diff options
author | Fabricio Voznika <fvoznika@google.com> | 2018-07-03 11:38:08 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2018-07-03 11:39:17 -0700 |
commit | 0ef606616732e1daf9d424658c31e5fed8f1ee4a (patch) | |
tree | deb3d6808e14e8f37b61a50a8bec1ebbecc6b2c6 /pkg | |
parent | c1b4c1ffee850aea2880f5f91a1e48e840933c71 (diff) |
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: 203157739
Change-Id: I31c9f7c501e3f55007f25e1852c27893a16ac6c4
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/tcpip/link/fdbased/endpoint.go | 51 | ||||
-rw-r--r-- | pkg/tcpip/stack/nic.go | 3 | ||||
-rw-r--r-- | pkg/tcpip/stack/route.go | 16 | ||||
-rw-r--r-- | pkg/tcpip/stack/stack.go | 2 |
4 files changed, 44 insertions, 28 deletions
diff --git a/pkg/tcpip/link/fdbased/endpoint.go b/pkg/tcpip/link/fdbased/endpoint.go index 668514454..0c844c05b 100644 --- a/pkg/tcpip/link/fdbased/endpoint.go +++ b/pkg/tcpip/link/fdbased/endpoint.go @@ -45,10 +45,14 @@ 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 + + // egressLocal indicates whether packets destined to itself should be + // forwarded to the FD endpoint (true) or be sent back to netstack (false). + egressLocal bool } // Options specify the details about the fd-based endpoint to be created. @@ -59,6 +63,7 @@ type Options struct { ChecksumOffload bool ClosedFunc func(*tcpip.Error) Address tcpip.LinkAddress + EgressLocal bool } // New creates a new fd-based endpoint. @@ -80,14 +85,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)), + egressLocal: opts.EgressLocal, } vv := buffer.NewVectorisedView(0, e.views) e.vv = &vv @@ -97,13 +103,13 @@ 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 - go e.dispatchLoop(dispatcher) // S/R-FIXME + e.dispatcher = dispatcher + go e.dispatchLoop() // S/R-FIXME } // 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 @@ -130,6 +136,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.egressLocal && 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)) @@ -142,7 +154,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) @@ -175,7 +186,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) @@ -211,7 +222,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++ { @@ -223,10 +234,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) diff --git a/pkg/tcpip/stack/nic.go b/pkg/tcpip/stack/nic.go index 8ff4310d5..06bb5abc5 100644 --- a/pkg/tcpip/stack/nic.go +++ b/pkg/tcpip/stack/nic.go @@ -317,8 +317,7 @@ func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remoteLinkAddr tcpip.Lin return } - r := makeRoute(protocol, dst, src, ref) - r.LocalLinkAddress = linkEP.LinkAddress() + r := makeRoute(protocol, dst, src, linkEP.LinkAddress(), ref) r.RemoteLinkAddress = remoteLinkAddr ref.ep.HandlePacket(&r, vv) ref.decRef() diff --git a/pkg/tcpip/stack/route.go b/pkg/tcpip/stack/route.go index 12f5efba5..e4f10cfa1 100644 --- a/pkg/tcpip/stack/route.go +++ b/pkg/tcpip/stack/route.go @@ -40,12 +40,13 @@ type Route struct { // makeRoute initializes a new route. It takes ownership of the provided // reference to a network endpoint. -func makeRoute(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr tcpip.Address, ref *referencedNetworkEndpoint) Route { +func makeRoute(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr tcpip.Address, localLinkAddr tcpip.LinkAddress, ref *referencedNetworkEndpoint) Route { return Route{ - NetProto: netProto, - LocalAddress: localAddr, - RemoteAddress: remoteAddr, - ref: ref, + NetProto: netProto, + LocalAddress: localAddr, + LocalLinkAddress: localLinkAddr, + RemoteAddress: remoteAddr, + ref: ref, } } @@ -82,6 +83,11 @@ func (r *Route) Resolve(waker *sleep.Waker) *tcpip.Error { nextAddr := r.NextHop if nextAddr == "" { + // Local link address is already known. + if r.RemoteAddress == r.LocalAddress { + r.RemoteLinkAddress = r.LocalLinkAddress + return nil + } nextAddr = r.RemoteAddress } linkAddr, err := r.ref.linkCache.GetLinkAddress(r.ref.nic.ID(), nextAddr, r.LocalAddress, r.NetProto, waker) diff --git a/pkg/tcpip/stack/stack.go b/pkg/tcpip/stack/stack.go index 3976f585c..d1d762a8e 100644 --- a/pkg/tcpip/stack/stack.go +++ b/pkg/tcpip/stack/stack.go @@ -647,7 +647,7 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, n remoteAddr = ref.ep.ID().LocalAddress } - r := makeRoute(netProto, ref.ep.ID().LocalAddress, remoteAddr, ref) + r := makeRoute(netProto, ref.ep.ID().LocalAddress, remoteAddr, nic.linkEP.LinkAddress(), ref) r.NextHop = s.routeTable[i].Gateway return r, nil } |