github.com/google/netstack@v0.0.0-20191123085552-55fcc16cd0eb/tcpip/transport/udp/forwarder.go (about) 1 // Copyright 2019 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package udp 16 17 import ( 18 "github.com/google/netstack/tcpip" 19 "github.com/google/netstack/tcpip/stack" 20 "github.com/google/netstack/waiter" 21 ) 22 23 // Forwarder is a session request forwarder, which allows clients to decide 24 // what to do with a session request, for example: ignore it, or process it. 25 // 26 // The canonical way of using it is to pass the Forwarder.HandlePacket function 27 // to stack.SetTransportProtocolHandler. 28 type Forwarder struct { 29 handler func(*ForwarderRequest) 30 31 stack *stack.Stack 32 } 33 34 // NewForwarder allocates and initializes a new forwarder. 35 func NewForwarder(s *stack.Stack, handler func(*ForwarderRequest)) *Forwarder { 36 return &Forwarder{ 37 stack: s, 38 handler: handler, 39 } 40 } 41 42 // HandlePacket handles all packets. 43 // 44 // This function is expected to be passed as an argument to the 45 // stack.SetTransportProtocolHandler function. 46 func (f *Forwarder) HandlePacket(r *stack.Route, id stack.TransportEndpointID, pkt tcpip.PacketBuffer) bool { 47 f.handler(&ForwarderRequest{ 48 stack: f.stack, 49 route: r, 50 id: id, 51 pkt: pkt, 52 }) 53 54 return true 55 } 56 57 // ForwarderRequest represents a session request received by the forwarder and 58 // passed to the client. Clients may optionally create an endpoint to represent 59 // it via CreateEndpoint. 60 type ForwarderRequest struct { 61 stack *stack.Stack 62 route *stack.Route 63 id stack.TransportEndpointID 64 pkt tcpip.PacketBuffer 65 } 66 67 // ID returns the 4-tuple (src address, src port, dst address, dst port) that 68 // represents the session request. 69 func (r *ForwarderRequest) ID() stack.TransportEndpointID { 70 return r.id 71 } 72 73 // CreateEndpoint creates a connected UDP endpoint for the session request. 74 func (r *ForwarderRequest) CreateEndpoint(queue *waiter.Queue) (tcpip.Endpoint, *tcpip.Error) { 75 ep := newEndpoint(r.stack, r.route.NetProto, queue) 76 if err := r.stack.RegisterTransportEndpoint(r.route.NICID(), []tcpip.NetworkProtocolNumber{r.route.NetProto}, ProtocolNumber, r.id, ep, ep.reusePort, ep.bindToDevice); err != nil { 77 ep.Close() 78 return nil, err 79 } 80 81 ep.ID = r.id 82 ep.route = r.route.Clone() 83 ep.dstPort = r.id.RemotePort 84 ep.RegisterNICID = r.route.NICID() 85 86 ep.state = StateConnected 87 88 ep.rcvMu.Lock() 89 ep.rcvReady = true 90 ep.rcvMu.Unlock() 91 92 ep.HandlePacket(r.route, r.id, r.pkt) 93 94 return ep, nil 95 }