Skip to content

Commit 6123ccd

Browse files
fvoznikashentubot
authored andcommitted
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
1 parent f93980b commit 6123ccd

File tree

5 files changed

+48
-33
lines changed

5 files changed

+48
-33
lines changed

pkg/tcpip/link/fdbased/endpoint.go

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,14 @@ type endpoint struct {
4545
// its end of the communication pipe.
4646
closed func(*tcpip.Error)
4747

48-
vv *buffer.VectorisedView
49-
iovecs []syscall.Iovec
50-
views []buffer.View
51-
attached bool
48+
vv *buffer.VectorisedView
49+
iovecs []syscall.Iovec
50+
views []buffer.View
51+
dispatcher stack.NetworkDispatcher
52+
53+
// egressLocal indicates whether packets destined to itself should be
54+
// forwarded to the FD endpoint (true) or be sent back to netstack (false).
55+
egressLocal bool
5256
}
5357

5458
// Options specify the details about the fd-based endpoint to be created.
@@ -59,6 +63,7 @@ type Options struct {
5963
ChecksumOffload bool
6064
ClosedFunc func(*tcpip.Error)
6165
Address tcpip.LinkAddress
66+
EgressLocal bool
6267
}
6368

6469
// New creates a new fd-based endpoint.
@@ -80,14 +85,15 @@ func New(opts *Options) tcpip.LinkEndpointID {
8085
}
8186

8287
e := &endpoint{
83-
fd: opts.FD,
84-
mtu: opts.MTU,
85-
caps: caps,
86-
closed: opts.ClosedFunc,
87-
addr: opts.Address,
88-
hdrSize: hdrSize,
89-
views: make([]buffer.View, len(BufConfig)),
90-
iovecs: make([]syscall.Iovec, len(BufConfig)),
88+
fd: opts.FD,
89+
mtu: opts.MTU,
90+
caps: caps,
91+
closed: opts.ClosedFunc,
92+
addr: opts.Address,
93+
hdrSize: hdrSize,
94+
views: make([]buffer.View, len(BufConfig)),
95+
iovecs: make([]syscall.Iovec, len(BufConfig)),
96+
egressLocal: opts.EgressLocal,
9197
}
9298
vv := buffer.NewVectorisedView(0, e.views)
9399
e.vv = &vv
@@ -97,13 +103,13 @@ func New(opts *Options) tcpip.LinkEndpointID {
97103
// Attach launches the goroutine that reads packets from the file descriptor and
98104
// dispatches them via the provided dispatcher.
99105
func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) {
100-
e.attached = true
101-
go e.dispatchLoop(dispatcher) // S/R-FIXME
106+
e.dispatcher = dispatcher
107+
go e.dispatchLoop() // S/R-FIXME
102108
}
103109

104110
// IsAttached implements stack.LinkEndpoint.IsAttached.
105111
func (e *endpoint) IsAttached() bool {
106-
return e.attached
112+
return e.dispatcher != nil
107113
}
108114

109115
// MTU implements stack.LinkEndpoint.MTU. It returns the value initialized
@@ -130,6 +136,12 @@ func (e *endpoint) LinkAddress() tcpip.LinkAddress {
130136
// WritePacket writes outbound packets to the file descriptor. If it is not
131137
// currently writable, the packet is dropped.
132138
func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload buffer.View, protocol tcpip.NetworkProtocolNumber) *tcpip.Error {
139+
if !e.egressLocal && r.LocalAddress != "" && r.LocalAddress == r.RemoteAddress {
140+
hdrView := hdr.View()
141+
vv := buffer.NewVectorisedView(len(hdrView)+len(payload), []buffer.View{hdrView, payload})
142+
e.dispatcher.DeliverNetworkPacket(e, r.RemoteLinkAddress, protocol, &vv)
143+
return nil
144+
}
133145
if e.hdrSize > 0 {
134146
// Add ethernet header if needed.
135147
eth := header.Ethernet(hdr.Prepend(header.EthernetMinimumSize))
@@ -142,7 +154,6 @@ func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload
142154

143155
if len(payload) == 0 {
144156
return rawfile.NonBlockingWrite(e.fd, hdr.UsedBytes())
145-
146157
}
147158

148159
return rawfile.NonBlockingWrite2(e.fd, hdr.UsedBytes(), payload)
@@ -175,7 +186,7 @@ func (e *endpoint) allocateViews(bufConfig []int) {
175186
}
176187

177188
// dispatch reads one packet from the file descriptor and dispatches it.
178-
func (e *endpoint) dispatch(d stack.NetworkDispatcher, largeV buffer.View) (bool, *tcpip.Error) {
189+
func (e *endpoint) dispatch(largeV buffer.View) (bool, *tcpip.Error) {
179190
e.allocateViews(BufConfig)
180191

181192
n, err := rawfile.BlockingReadv(e.fd, e.iovecs)
@@ -211,7 +222,7 @@ func (e *endpoint) dispatch(d stack.NetworkDispatcher, largeV buffer.View) (bool
211222
e.vv.SetSize(n)
212223
e.vv.TrimFront(e.hdrSize)
213224

214-
d.DeliverNetworkPacket(e, addr, p, e.vv)
225+
e.dispatcher.DeliverNetworkPacket(e, addr, p, e.vv)
215226

216227
// Prepare e.views for another packet: release used views.
217228
for i := 0; i < used; i++ {
@@ -223,10 +234,10 @@ func (e *endpoint) dispatch(d stack.NetworkDispatcher, largeV buffer.View) (bool
223234

224235
// dispatchLoop reads packets from the file descriptor in a loop and dispatches
225236
// them to the network stack.
226-
func (e *endpoint) dispatchLoop(d stack.NetworkDispatcher) *tcpip.Error {
237+
func (e *endpoint) dispatchLoop() *tcpip.Error {
227238
v := buffer.NewView(header.MaxIPPacketSize)
228239
for {
229-
cont, err := e.dispatch(d, v)
240+
cont, err := e.dispatch(v)
230241
if err != nil || !cont {
231242
if e.closed != nil {
232243
e.closed(err)

pkg/tcpip/stack/nic.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,7 @@ func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remoteLinkAddr tcpip.Lin
317317
return
318318
}
319319

320-
r := makeRoute(protocol, dst, src, ref)
321-
r.LocalLinkAddress = linkEP.LinkAddress()
320+
r := makeRoute(protocol, dst, src, linkEP.LinkAddress(), ref)
322321
r.RemoteLinkAddress = remoteLinkAddr
323322
ref.ep.HandlePacket(&r, vv)
324323
ref.decRef()

pkg/tcpip/stack/route.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,13 @@ type Route struct {
4040

4141
// makeRoute initializes a new route. It takes ownership of the provided
4242
// reference to a network endpoint.
43-
func makeRoute(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr tcpip.Address, ref *referencedNetworkEndpoint) Route {
43+
func makeRoute(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr tcpip.Address, localLinkAddr tcpip.LinkAddress, ref *referencedNetworkEndpoint) Route {
4444
return Route{
45-
NetProto: netProto,
46-
LocalAddress: localAddr,
47-
RemoteAddress: remoteAddr,
48-
ref: ref,
45+
NetProto: netProto,
46+
LocalAddress: localAddr,
47+
LocalLinkAddress: localLinkAddr,
48+
RemoteAddress: remoteAddr,
49+
ref: ref,
4950
}
5051
}
5152

@@ -82,6 +83,11 @@ func (r *Route) Resolve(waker *sleep.Waker) *tcpip.Error {
8283

8384
nextAddr := r.NextHop
8485
if nextAddr == "" {
86+
// Local link address is already known.
87+
if r.RemoteAddress == r.LocalAddress {
88+
r.RemoteLinkAddress = r.LocalLinkAddress
89+
return nil
90+
}
8591
nextAddr = r.RemoteAddress
8692
}
8793
linkAddr, err := r.ref.linkCache.GetLinkAddress(r.ref.nic.ID(), nextAddr, r.LocalAddress, r.NetProto, waker)

pkg/tcpip/stack/stack.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, n
647647
remoteAddr = ref.ep.ID().LocalAddress
648648
}
649649

650-
r := makeRoute(netProto, ref.ep.ID().LocalAddress, remoteAddr, ref)
650+
r := makeRoute(netProto, ref.ep.ID().LocalAddress, remoteAddr, nic.linkEP.LinkAddress(), ref)
651651
r.NextHop = s.routeTable[i].Gateway
652652
return r, nil
653653
}

runsc/boot/network.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,10 @@ func (n *Network) CreateLinksAndRoutes(args *CreateLinksAndRoutesArgs, _ *struct
134134
}
135135

136136
linkEP := fdbased.New(&fdbased.Options{
137-
FD: newFD,
138-
MTU: uint32(link.MTU),
139-
ChecksumOffload: false,
140-
EthernetHeader: true,
141-
Address: tcpip.LinkAddress(generateRndMac()),
137+
FD: newFD,
138+
MTU: uint32(link.MTU),
139+
EthernetHeader: true,
140+
Address: tcpip.LinkAddress(generateRndMac()),
142141
})
143142

144143
log.Infof("Enabling interface %q with id %d on addresses %+v", link.Name, nicID, link.Addresses)

0 commit comments

Comments
 (0)