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  }