From ea1e39a314d3a248d8b682a9f63e686530597d61 Mon Sep 17 00:00:00 2001 From: Fabricio Voznika Date: Wed, 8 Aug 2018 22:02:09 -0700 Subject: Resend packets back to netstack if destined to itself Add option to redirect packet back to netstack if it's destined to itself. This fixes the problem where connecting to the local NIC address would not work, e.g.: echo bar | nc -l -p 8080 & echo foo | nc 192.168.0.2 8080 PiperOrigin-RevId: 207995083 Change-Id: I17adc2a04df48bfea711011a5df206326a1fb8ef --- pkg/tcpip/link/fdbased/endpoint.go | 52 +++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 20 deletions(-) (limited to 'pkg/tcpip/link/fdbased') diff --git a/pkg/tcpip/link/fdbased/endpoint.go b/pkg/tcpip/link/fdbased/endpoint.go index 4e20cfbf8..152d8f0b2 100644 --- a/pkg/tcpip/link/fdbased/endpoint.go +++ b/pkg/tcpip/link/fdbased/endpoint.go @@ -55,10 +55,15 @@ type endpoint struct { // its end of the communication pipe. closed func(*tcpip.Error) - vv *buffer.VectorisedView - iovecs []syscall.Iovec - views []buffer.View - attached bool + vv *buffer.VectorisedView + iovecs []syscall.Iovec + views []buffer.View + dispatcher stack.NetworkDispatcher + + // handleLocal indicates whether packets destined to itself should be + // handled by the netstack internally (true) or be forwarded to the FD + // endpoint (false). + handleLocal bool } // Options specify the details about the fd-based endpoint to be created. @@ -71,6 +76,7 @@ type Options struct { Address tcpip.LinkAddress SaveRestore bool DisconnectOk bool + HandleLocal bool } // New creates a new fd-based endpoint. @@ -100,14 +106,15 @@ func New(opts *Options) tcpip.LinkEndpointID { } e := &endpoint{ - fd: opts.FD, - mtu: opts.MTU, - caps: caps, - closed: opts.ClosedFunc, - addr: opts.Address, - hdrSize: hdrSize, - views: make([]buffer.View, len(BufConfig)), - iovecs: make([]syscall.Iovec, len(BufConfig)), + fd: opts.FD, + mtu: opts.MTU, + caps: caps, + closed: opts.ClosedFunc, + addr: opts.Address, + hdrSize: hdrSize, + views: make([]buffer.View, len(BufConfig)), + iovecs: make([]syscall.Iovec, len(BufConfig)), + handleLocal: opts.HandleLocal, } vv := buffer.NewVectorisedView(0, e.views) e.vv = &vv @@ -117,16 +124,16 @@ func New(opts *Options) tcpip.LinkEndpointID { // Attach launches the goroutine that reads packets from the file descriptor and // dispatches them via the provided dispatcher. func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) { - e.attached = true + e.dispatcher = dispatcher // Link endpoints are not savable. When transportation endpoints are // saved, they stop sending outgoing packets and all incoming packets // are rejected. - go e.dispatchLoop(dispatcher) // S/R-SAFE: See above. + go e.dispatchLoop() // S/R-SAFE: See above. } // IsAttached implements stack.LinkEndpoint.IsAttached. func (e *endpoint) IsAttached() bool { - return e.attached + return e.dispatcher != nil } // MTU implements stack.LinkEndpoint.MTU. It returns the value initialized @@ -153,6 +160,12 @@ func (e *endpoint) LinkAddress() tcpip.LinkAddress { // WritePacket writes outbound packets to the file descriptor. If it is not // currently writable, the packet is dropped. func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload buffer.View, protocol tcpip.NetworkProtocolNumber) *tcpip.Error { + if e.handleLocal && r.LocalAddress != "" && r.LocalAddress == r.RemoteAddress { + hdrView := hdr.View() + vv := buffer.NewVectorisedView(len(hdrView)+len(payload), []buffer.View{hdrView, payload}) + e.dispatcher.DeliverNetworkPacket(e, r.RemoteLinkAddress, protocol, &vv) + return nil + } if e.hdrSize > 0 { // Add ethernet header if needed. eth := header.Ethernet(hdr.Prepend(header.EthernetMinimumSize)) @@ -165,7 +178,6 @@ func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload if len(payload) == 0 { return rawfile.NonBlockingWrite(e.fd, hdr.UsedBytes()) - } return rawfile.NonBlockingWrite2(e.fd, hdr.UsedBytes(), payload) @@ -198,7 +210,7 @@ func (e *endpoint) allocateViews(bufConfig []int) { } // dispatch reads one packet from the file descriptor and dispatches it. -func (e *endpoint) dispatch(d stack.NetworkDispatcher, largeV buffer.View) (bool, *tcpip.Error) { +func (e *endpoint) dispatch(largeV buffer.View) (bool, *tcpip.Error) { e.allocateViews(BufConfig) n, err := rawfile.BlockingReadv(e.fd, e.iovecs) @@ -234,7 +246,7 @@ func (e *endpoint) dispatch(d stack.NetworkDispatcher, largeV buffer.View) (bool e.vv.SetSize(n) e.vv.TrimFront(e.hdrSize) - d.DeliverNetworkPacket(e, addr, p, e.vv) + e.dispatcher.DeliverNetworkPacket(e, addr, p, e.vv) // Prepare e.views for another packet: release used views. for i := 0; i < used; i++ { @@ -246,10 +258,10 @@ func (e *endpoint) dispatch(d stack.NetworkDispatcher, largeV buffer.View) (bool // dispatchLoop reads packets from the file descriptor in a loop and dispatches // them to the network stack. -func (e *endpoint) dispatchLoop(d stack.NetworkDispatcher) *tcpip.Error { +func (e *endpoint) dispatchLoop() *tcpip.Error { v := buffer.NewView(header.MaxIPPacketSize) for { - cont, err := e.dispatch(d, v) + cont, err := e.dispatch(v) if err != nil || !cont { if e.closed != nil { e.closed(err) -- cgit v1.2.3