github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/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/SagerNet/gvisor/pkg/tcpip" 19 "github.com/SagerNet/gvisor/pkg/tcpip/stack" 20 "github.com/SagerNet/gvisor/pkg/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(id stack.TransportEndpointID, pkt *stack.PacketBuffer) bool { 47 f.handler(&ForwarderRequest{ 48 stack: f.stack, 49 id: id, 50 pkt: pkt, 51 }) 52 53 return true 54 } 55 56 // ForwarderRequest represents a session request received by the forwarder and 57 // passed to the client. Clients may optionally create an endpoint to represent 58 // it via CreateEndpoint. 59 type ForwarderRequest struct { 60 stack *stack.Stack 61 id stack.TransportEndpointID 62 pkt *stack.PacketBuffer 63 } 64 65 // ID returns the 4-tuple (src address, src port, dst address, dst port) that 66 // represents the session request. 67 func (r *ForwarderRequest) ID() stack.TransportEndpointID { 68 return r.id 69 } 70 71 // CreateEndpoint creates a connected UDP endpoint for the session request. 72 func (r *ForwarderRequest) CreateEndpoint(queue *waiter.Queue) (tcpip.Endpoint, tcpip.Error) { 73 netHdr := r.pkt.Network() 74 route, err := r.stack.FindRoute(r.pkt.NICID, netHdr.DestinationAddress(), netHdr.SourceAddress(), r.pkt.NetworkProtocolNumber, false /* multicastLoop */) 75 if err != nil { 76 return nil, err 77 } 78 79 ep := newEndpoint(r.stack, r.pkt.NetworkProtocolNumber, queue) 80 if err := r.stack.RegisterTransportEndpoint([]tcpip.NetworkProtocolNumber{r.pkt.NetworkProtocolNumber}, ProtocolNumber, r.id, ep, ep.portFlags, tcpip.NICID(ep.ops.GetBindToDevice())); err != nil { 81 ep.Close() 82 route.Release() 83 return nil, err 84 } 85 86 ep.ID = r.id 87 ep.route = route 88 ep.dstPort = r.id.RemotePort 89 ep.effectiveNetProtos = []tcpip.NetworkProtocolNumber{r.pkt.NetworkProtocolNumber} 90 ep.RegisterNICID = r.pkt.NICID 91 ep.boundPortFlags = ep.portFlags 92 93 ep.state = uint32(StateConnected) 94 95 ep.rcvMu.Lock() 96 ep.rcvReady = true 97 ep.rcvMu.Unlock() 98 99 ep.HandlePacket(r.id, r.pkt) 100 101 return ep, nil 102 }