Skip to content

Commit 8a53c1a

Browse files
committed
TUN-6592: Decrement TTL and return ICMP time exceed if it's 0
1 parent f5f3e6a commit 8a53c1a

18 files changed

+515
-106
lines changed

connection/quic.go

Lines changed: 21 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ type QUICConnection struct {
5151
sessionManager datagramsession.Manager
5252
// datagramMuxer mux/demux datagrams from quic connection
5353
datagramMuxer quicpogs.BaseDatagramMuxer
54-
packetRouter *packetRouter
54+
packetRouter *packet.Router
5555
controlStreamHandler ControlStreamHandler
5656
connOptions *tunnelpogs.ConnectionOptions
5757
}
@@ -65,7 +65,7 @@ func NewQUICConnection(
6565
connOptions *tunnelpogs.ConnectionOptions,
6666
controlStreamHandler ControlStreamHandler,
6767
logger *zerolog.Logger,
68-
icmpProxy ingress.ICMPProxy,
68+
icmpRouter packet.ICMPRouter,
6969
) (*QUICConnection, error) {
7070
session, err := quic.DialAddr(edgeAddr.String(), tlsConfig, quicConfig)
7171
if err != nil {
@@ -75,15 +75,12 @@ func NewQUICConnection(
7575
sessionDemuxChan := make(chan *packet.Session, demuxChanCapacity)
7676
var (
7777
datagramMuxer quicpogs.BaseDatagramMuxer
78-
pr *packetRouter
78+
pr *packet.Router
7979
)
80-
if icmpProxy != nil {
81-
pr = &packetRouter{
82-
muxer: quicpogs.NewDatagramMuxerV2(session, logger, sessionDemuxChan),
83-
icmpProxy: icmpProxy,
84-
logger: logger,
85-
}
86-
datagramMuxer = pr.muxer
80+
if icmpRouter != nil {
81+
datagramMuxerV2 := quicpogs.NewDatagramMuxerV2(session, logger, sessionDemuxChan)
82+
pr = packet.NewRouter(datagramMuxerV2, &returnPipe{muxer: datagramMuxerV2}, icmpRouter, logger)
83+
datagramMuxer = datagramMuxerV2
8784
} else {
8885
datagramMuxer = quicpogs.NewDatagramMuxer(session, logger, sessionDemuxChan)
8986
}
@@ -139,7 +136,7 @@ func (q *QUICConnection) Serve(ctx context.Context) error {
139136
if q.packetRouter != nil {
140137
errGroup.Go(func() error {
141138
defer cancel()
142-
return q.packetRouter.serve(ctx)
139+
return q.packetRouter.Serve(ctx)
143140
})
144141
}
145142

@@ -348,50 +345,6 @@ func (q *QUICConnection) UpdateConfiguration(ctx context.Context, version int32,
348345
return q.orchestrator.UpdateConfig(version, config)
349346
}
350347

351-
type packetRouter struct {
352-
muxer *quicpogs.DatagramMuxerV2
353-
icmpProxy ingress.ICMPProxy
354-
logger *zerolog.Logger
355-
}
356-
357-
func (pr *packetRouter) serve(ctx context.Context) error {
358-
icmpDecoder := packet.NewICMPDecoder()
359-
for {
360-
pk, err := pr.muxer.ReceivePacket(ctx)
361-
if err != nil {
362-
return err
363-
}
364-
icmpPacket, err := icmpDecoder.Decode(pk)
365-
if err != nil {
366-
pr.logger.Err(err).Msg("Failed to decode ICMP packet from quic datagram")
367-
continue
368-
}
369-
370-
flowPipe := muxerResponder{muxer: pr.muxer}
371-
if err := pr.icmpProxy.Request(icmpPacket, &flowPipe); err != nil {
372-
pr.logger.Err(err).
373-
Str("src", icmpPacket.Src.String()).
374-
Str("dst", icmpPacket.Dst.String()).
375-
Interface("type", icmpPacket.Type).
376-
Msg("Failed to send ICMP packet")
377-
continue
378-
}
379-
}
380-
}
381-
382-
// muxerResponder wraps DatagramMuxerV2 to satisfy the packet.FunnelUniPipe interface
383-
type muxerResponder struct {
384-
muxer *quicpogs.DatagramMuxerV2
385-
}
386-
387-
func (mr *muxerResponder) SendPacket(dst netip.Addr, pk packet.RawPacket) error {
388-
return mr.muxer.SendPacket(pk)
389-
}
390-
391-
func (mr *muxerResponder) Close() error {
392-
return nil
393-
}
394-
395348
// streamReadWriteAcker is a light wrapper over QUIC streams with a callback to send response back to
396349
// the client.
397350
type streamReadWriteAcker struct {
@@ -538,3 +491,16 @@ func (np *nopCloserReadWriter) Close() error {
538491

539492
return nil
540493
}
494+
495+
// returnPipe wraps DatagramMuxerV2 to satisfy the packet.FunnelUniPipe interface
496+
type returnPipe struct {
497+
muxer *quicpogs.DatagramMuxerV2
498+
}
499+
500+
func (rp *returnPipe) SendPacket(dst netip.Addr, pk packet.RawPacket) error {
501+
return rp.muxer.SendPacket(pk)
502+
}
503+
504+
func (rp *returnPipe) Close() error {
505+
return nil
506+
}

ingress/icmp_darwin.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ func (snf echoFunnelID) String() string {
115115
return strconv.FormatUint(uint64(snf), 10)
116116
}
117117

118-
func newICMPProxy(listenIP netip.Addr, logger *zerolog.Logger, idleTimeout time.Duration) (ICMPProxy, error) {
118+
func newICMPProxy(listenIP netip.Addr, logger *zerolog.Logger, idleTimeout time.Duration) (*icmpProxy, error) {
119119
conn, err := newICMPConn(listenIP)
120120
if err != nil {
121121
return nil, err

ingress/icmp_generic.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,29 @@
33
package ingress
44

55
import (
6+
"context"
67
"fmt"
78
"net/netip"
89
"runtime"
910
"time"
1011

1112
"github.com/rs/zerolog"
13+
14+
"github.com/cloudflare/cloudflared/packet"
1215
)
1316

14-
func newICMPProxy(listenIP netip.Addr, logger *zerolog.Logger, idleTimeout time.Duration) (ICMPProxy, error) {
15-
return nil, fmt.Errorf("ICMP proxy is not implemented on %s", runtime.GOOS)
17+
var errICMPProxyNotImplemented = fmt.Errorf("ICMP proxy is not implemented on %s", runtime.GOOS)
18+
19+
type icmpProxy struct{}
20+
21+
func (ip icmpProxy) Request(pk *packet.ICMP, responder packet.FunnelUniPipe) error {
22+
return errICMPProxyNotImplemented
23+
}
24+
25+
func (ip *icmpProxy) Serve(ctx context.Context) error {
26+
return errICMPProxyNotImplemented
27+
}
28+
29+
func newICMPProxy(listenIP netip.Addr, logger *zerolog.Logger, idleTimeout time.Duration) (*icmpProxy, error) {
30+
return nil, errICMPProxyNotImplemented
1631
}

ingress/icmp_linux.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ type icmpProxy struct {
2828
idleTimeout time.Duration
2929
}
3030

31-
func newICMPProxy(listenIP netip.Addr, logger *zerolog.Logger, idleTimeout time.Duration) (ICMPProxy, error) {
31+
func newICMPProxy(listenIP netip.Addr, logger *zerolog.Logger, idleTimeout time.Duration) (*icmpProxy, error) {
3232
if err := testPermission(listenIP); err != nil {
3333
return nil, err
3434
}

ingress/icmp_posix.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ func (ief *icmpEchoFlow) returnToSrc(reply *echoReply) error {
9696
Src: reply.from,
9797
Dst: ief.Src,
9898
Protocol: layers.IPProtocol(reply.msg.Type.Protocol()),
99+
TTL: packet.DefaultTTL,
99100
},
100101
Message: reply.msg,
101102
}

ingress/icmp_windows.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ type icmpProxy struct {
224224
encoderPool sync.Pool
225225
}
226226

227-
func newICMPProxy(listenIP netip.Addr, logger *zerolog.Logger, idleTimeout time.Duration) (ICMPProxy, error) {
227+
func newICMPProxy(listenIP netip.Addr, logger *zerolog.Logger, idleTimeout time.Duration) (*icmpProxy, error) {
228228
var (
229229
srcSocketAddr *sockAddrIn6
230230
handle uintptr
@@ -302,6 +302,7 @@ func (ip *icmpProxy) handleEchoReply(request *packet.ICMP, echoReq *icmp.Echo, d
302302
Src: request.Dst,
303303
Dst: request.Src,
304304
Protocol: layers.IPProtocol(request.Type.Protocol()),
305+
TTL: packet.DefaultTTL,
305306
},
306307
Message: &icmp.Message{
307308
Type: replyType,

ingress/icmp_windows_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ func TestSendEchoErrors(t *testing.T) {
134134
func testSendEchoErrors(t *testing.T, listenIP netip.Addr) {
135135
proxy, err := newICMPProxy(listenIP, &noopLogger, time.Second)
136136
require.NoError(t, err)
137-
winProxy := proxy.(*icmpProxy)
138137

139138
echo := icmp.Echo{
140139
ID: 6193,
@@ -145,7 +144,7 @@ func testSendEchoErrors(t *testing.T, listenIP netip.Addr) {
145144
if listenIP.Is6() {
146145
documentIP = netip.MustParseAddr("2001:db8::1")
147146
}
148-
resp, err := winProxy.icmpEchoRoundtrip(documentIP, &echo)
147+
resp, err := proxy.icmpEchoRoundtrip(documentIP, &echo)
149148
require.Error(t, err)
150149
require.Nil(t, resp)
151150
}

ingress/origin_icmp_proxy.go

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,34 +26,26 @@ var (
2626
errPacketNil = fmt.Errorf("packet is nil")
2727
)
2828

29-
// ICMPProxy sends ICMP messages and listens for their responses
30-
type ICMPProxy interface {
31-
// Serve starts listening for responses to the requests until context is done
32-
Serve(ctx context.Context) error
33-
// Request sends an ICMP message
34-
Request(pk *packet.ICMP, responder packet.FunnelUniPipe) error
35-
}
36-
3729
type icmpRouter struct {
38-
ipv4Proxy ICMPProxy
39-
ipv6Proxy ICMPProxy
30+
ipv4Proxy *icmpProxy
31+
ipv6Proxy *icmpProxy
4032
}
4133

42-
// NewICMPProxy doesn't return an error if either ipv4 proxy or ipv6 proxy can be created. The machine might only
34+
// NewICMPRouter doesn't return an error if either ipv4 proxy or ipv6 proxy can be created. The machine might only
4335
// support one of them
44-
func NewICMPProxy(logger *zerolog.Logger) (ICMPProxy, error) {
36+
func NewICMPRouter(logger *zerolog.Logger) (*icmpRouter, error) {
4537
// TODO: TUN-6741: don't bind to all interface
4638
ipv4Proxy, ipv4Err := newICMPProxy(netip.IPv4Unspecified(), logger, funnelIdleTimeout)
4739
ipv6Proxy, ipv6Err := newICMPProxy(netip.IPv6Unspecified(), logger, funnelIdleTimeout)
4840
if ipv4Err != nil && ipv6Err != nil {
4941
return nil, fmt.Errorf("cannot create ICMPv4 proxy: %v nor ICMPv6 proxy: %v", ipv4Err, ipv6Err)
5042
}
5143
if ipv4Err != nil {
52-
logger.Warn().Err(ipv4Err).Msg("failed to create ICMPv4 proxy, only ICMPv6 proxy is created")
44+
logger.Debug().Err(ipv4Err).Msg("failed to create ICMPv4 proxy, only ICMPv6 proxy is created")
5345
ipv4Proxy = nil
5446
}
5547
if ipv6Err != nil {
56-
logger.Warn().Err(ipv6Err).Msg("failed to create ICMPv6 proxy, only ICMPv4 proxy is created")
48+
logger.Debug().Err(ipv6Err).Msg("failed to create ICMPv6 proxy, only ICMPv4 proxy is created")
5749
ipv6Proxy = nil
5850
}
5951
return &icmpRouter{

ingress/origin_icmp_proxy_test.go

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,24 @@ var (
3030
// Note: if this test fails on your device under Linux, then most likely you need to make sure that your user
3131
// is allowed in ping_group_range. See the following gist for how to do that:
3232
// https://github.com/ValentinBELYN/icmplib/blob/main/docs/6-use-icmplib-without-privileges.md
33-
func TestICMPProxyEcho(t *testing.T) {
34-
testICMPProxyEcho(t, true)
35-
testICMPProxyEcho(t, false)
33+
func TestICMPRouterEcho(t *testing.T) {
34+
testICMPRouterEcho(t, true)
35+
testICMPRouterEcho(t, false)
3636
}
3737

38-
func testICMPProxyEcho(t *testing.T, sendIPv4 bool) {
38+
func testICMPRouterEcho(t *testing.T, sendIPv4 bool) {
3939
const (
4040
echoID = 36571
4141
endSeq = 20
4242
)
4343

44-
proxy, err := NewICMPProxy(&noopLogger)
44+
router, err := NewICMPRouter(&noopLogger)
4545
require.NoError(t, err)
4646

4747
proxyDone := make(chan struct{})
4848
ctx, cancel := context.WithCancel(context.Background())
4949
go func() {
50-
proxy.Serve(ctx)
50+
router.Serve(ctx)
5151
close(proxyDone)
5252
}()
5353

@@ -67,6 +67,7 @@ func testICMPProxyEcho(t *testing.T, sendIPv4 bool) {
6767
Src: localIP,
6868
Dst: localIP,
6969
Protocol: protocol,
70+
TTL: packet.DefaultTTL,
7071
}
7172
}
7273

@@ -88,7 +89,7 @@ func testICMPProxyEcho(t *testing.T, sendIPv4 bool) {
8889
},
8990
},
9091
}
91-
require.NoError(t, proxy.Request(&pk, &responder))
92+
require.NoError(t, router.Request(&pk, &responder))
9293
responder.validate(t, &pk)
9394
}
9495
}
@@ -97,7 +98,7 @@ func testICMPProxyEcho(t *testing.T, sendIPv4 bool) {
9798
}
9899

99100
// TestICMPProxyRejectNotEcho makes sure it rejects messages other than echo
100-
func TestICMPProxyRejectNotEcho(t *testing.T) {
101+
func TestICMPRouterRejectNotEcho(t *testing.T) {
101102
msgs := []icmp.Message{
102103
{
103104
Type: ipv4.ICMPTypeDestinationUnreachable,
@@ -122,7 +123,7 @@ func TestICMPProxyRejectNotEcho(t *testing.T) {
122123
},
123124
},
124125
}
125-
testICMPProxyRejectNotEcho(t, localhostIP, msgs)
126+
testICMPRouterRejectNotEcho(t, localhostIP, msgs)
126127
msgsV6 := []icmp.Message{
127128
{
128129
Type: ipv6.ICMPTypeDestinationUnreachable,
@@ -147,11 +148,11 @@ func TestICMPProxyRejectNotEcho(t *testing.T) {
147148
},
148149
},
149150
}
150-
testICMPProxyRejectNotEcho(t, localhostIPv6, msgsV6)
151+
testICMPRouterRejectNotEcho(t, localhostIPv6, msgsV6)
151152
}
152153

153-
func testICMPProxyRejectNotEcho(t *testing.T, srcDstIP netip.Addr, msgs []icmp.Message) {
154-
proxy, err := NewICMPProxy(&noopLogger)
154+
func testICMPRouterRejectNotEcho(t *testing.T, srcDstIP netip.Addr, msgs []icmp.Message) {
155+
router, err := NewICMPRouter(&noopLogger)
155156
require.NoError(t, err)
156157

157158
responder := echoFlowResponder{
@@ -168,10 +169,11 @@ func testICMPProxyRejectNotEcho(t *testing.T, srcDstIP netip.Addr, msgs []icmp.M
168169
Src: srcDstIP,
169170
Dst: srcDstIP,
170171
Protocol: protocol,
172+
TTL: packet.DefaultTTL,
171173
},
172174
Message: &m,
173175
}
174-
require.Error(t, proxy.Request(&pk, &responder))
176+
require.Error(t, router.Request(&pk, &responder))
175177
}
176178
}
177179

packet/decoder.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ func FindProtocol(p []byte) (layers.IPProtocol, error) {
1616
}
1717
switch version {
1818
case 4:
19-
if len(p) < ipv4HeaderLen {
20-
return 0, fmt.Errorf("IPv4 packet should have at least %d bytes, got %d bytes", ipv4HeaderLen, len(p))
19+
if len(p) < ipv4MinHeaderLen {
20+
return 0, fmt.Errorf("IPv4 packet should have at least %d bytes, got %d bytes", ipv4MinHeaderLen, len(p))
2121
}
2222
// Protocol is in the 10th byte of IPv4 header
2323
return layers.IPProtocol(p[9]), nil

0 commit comments

Comments
 (0)