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
This commit is contained in:
Fabricio Voznika
2018-07-03 11:39:17 -07:00
committed by Shentubot
parent c1b4c1ffee
commit 0ef6066167
5 changed files with 48 additions and 33 deletions
+31 -20
View File
@@ -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)
+1 -2
View File
@@ -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()
+11 -5
View File
@@ -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)
+1 -1
View File
@@ -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
}
+4 -5
View File
@@ -134,11 +134,10 @@ func (n *Network) CreateLinksAndRoutes(args *CreateLinksAndRoutesArgs, _ *struct
}
linkEP := fdbased.New(&fdbased.Options{
FD: newFD,
MTU: uint32(link.MTU),
ChecksumOffload: false,
EthernetHeader: true,
Address: tcpip.LinkAddress(generateRndMac()),
FD: newFD,
MTU: uint32(link.MTU),
EthernetHeader: true,
Address: tcpip.LinkAddress(generateRndMac()),
})
log.Infof("Enabling interface %q with id %d on addresses %+v", link.Name, nicID, link.Addresses)