TUN-6592: Decrement TTL and return ICMP time exceed if it's 0

This commit is contained in:
cthuang
2022-09-13 14:00:54 +01:00
parent f5f3e6a453
commit 8a53c1aa1d
18 changed files with 515 additions and 106 deletions

View File

@@ -115,7 +115,7 @@ func (snf echoFunnelID) String() string {
return strconv.FormatUint(uint64(snf), 10)
}
func newICMPProxy(listenIP netip.Addr, logger *zerolog.Logger, idleTimeout time.Duration) (ICMPProxy, error) {
func newICMPProxy(listenIP netip.Addr, logger *zerolog.Logger, idleTimeout time.Duration) (*icmpProxy, error) {
conn, err := newICMPConn(listenIP)
if err != nil {
return nil, err

View File

@@ -3,14 +3,29 @@
package ingress
import (
"context"
"fmt"
"net/netip"
"runtime"
"time"
"github.com/rs/zerolog"
"github.com/cloudflare/cloudflared/packet"
)
func newICMPProxy(listenIP netip.Addr, logger *zerolog.Logger, idleTimeout time.Duration) (ICMPProxy, error) {
return nil, fmt.Errorf("ICMP proxy is not implemented on %s", runtime.GOOS)
var errICMPProxyNotImplemented = fmt.Errorf("ICMP proxy is not implemented on %s", runtime.GOOS)
type icmpProxy struct{}
func (ip icmpProxy) Request(pk *packet.ICMP, responder packet.FunnelUniPipe) error {
return errICMPProxyNotImplemented
}
func (ip *icmpProxy) Serve(ctx context.Context) error {
return errICMPProxyNotImplemented
}
func newICMPProxy(listenIP netip.Addr, logger *zerolog.Logger, idleTimeout time.Duration) (*icmpProxy, error) {
return nil, errICMPProxyNotImplemented
}

View File

@@ -28,7 +28,7 @@ type icmpProxy struct {
idleTimeout time.Duration
}
func newICMPProxy(listenIP netip.Addr, logger *zerolog.Logger, idleTimeout time.Duration) (ICMPProxy, error) {
func newICMPProxy(listenIP netip.Addr, logger *zerolog.Logger, idleTimeout time.Duration) (*icmpProxy, error) {
if err := testPermission(listenIP); err != nil {
return nil, err
}

View File

@@ -96,6 +96,7 @@ func (ief *icmpEchoFlow) returnToSrc(reply *echoReply) error {
Src: reply.from,
Dst: ief.Src,
Protocol: layers.IPProtocol(reply.msg.Type.Protocol()),
TTL: packet.DefaultTTL,
},
Message: reply.msg,
}

View File

@@ -224,7 +224,7 @@ type icmpProxy struct {
encoderPool sync.Pool
}
func newICMPProxy(listenIP netip.Addr, logger *zerolog.Logger, idleTimeout time.Duration) (ICMPProxy, error) {
func newICMPProxy(listenIP netip.Addr, logger *zerolog.Logger, idleTimeout time.Duration) (*icmpProxy, error) {
var (
srcSocketAddr *sockAddrIn6
handle uintptr
@@ -302,6 +302,7 @@ func (ip *icmpProxy) handleEchoReply(request *packet.ICMP, echoReq *icmp.Echo, d
Src: request.Dst,
Dst: request.Src,
Protocol: layers.IPProtocol(request.Type.Protocol()),
TTL: packet.DefaultTTL,
},
Message: &icmp.Message{
Type: replyType,

View File

@@ -134,7 +134,6 @@ func TestSendEchoErrors(t *testing.T) {
func testSendEchoErrors(t *testing.T, listenIP netip.Addr) {
proxy, err := newICMPProxy(listenIP, &noopLogger, time.Second)
require.NoError(t, err)
winProxy := proxy.(*icmpProxy)
echo := icmp.Echo{
ID: 6193,
@@ -145,7 +144,7 @@ func testSendEchoErrors(t *testing.T, listenIP netip.Addr) {
if listenIP.Is6() {
documentIP = netip.MustParseAddr("2001:db8::1")
}
resp, err := winProxy.icmpEchoRoundtrip(documentIP, &echo)
resp, err := proxy.icmpEchoRoundtrip(documentIP, &echo)
require.Error(t, err)
require.Nil(t, resp)
}

View File

@@ -26,22 +26,14 @@ var (
errPacketNil = fmt.Errorf("packet is nil")
)
// ICMPProxy sends ICMP messages and listens for their responses
type ICMPProxy interface {
// Serve starts listening for responses to the requests until context is done
Serve(ctx context.Context) error
// Request sends an ICMP message
Request(pk *packet.ICMP, responder packet.FunnelUniPipe) error
}
type icmpRouter struct {
ipv4Proxy ICMPProxy
ipv6Proxy ICMPProxy
ipv4Proxy *icmpProxy
ipv6Proxy *icmpProxy
}
// NewICMPProxy doesn't return an error if either ipv4 proxy or ipv6 proxy can be created. The machine might only
// NewICMPRouter doesn't return an error if either ipv4 proxy or ipv6 proxy can be created. The machine might only
// support one of them
func NewICMPProxy(logger *zerolog.Logger) (ICMPProxy, error) {
func NewICMPRouter(logger *zerolog.Logger) (*icmpRouter, error) {
// TODO: TUN-6741: don't bind to all interface
ipv4Proxy, ipv4Err := newICMPProxy(netip.IPv4Unspecified(), logger, funnelIdleTimeout)
ipv6Proxy, ipv6Err := newICMPProxy(netip.IPv6Unspecified(), logger, funnelIdleTimeout)
@@ -49,11 +41,11 @@ func NewICMPProxy(logger *zerolog.Logger) (ICMPProxy, error) {
return nil, fmt.Errorf("cannot create ICMPv4 proxy: %v nor ICMPv6 proxy: %v", ipv4Err, ipv6Err)
}
if ipv4Err != nil {
logger.Warn().Err(ipv4Err).Msg("failed to create ICMPv4 proxy, only ICMPv6 proxy is created")
logger.Debug().Err(ipv4Err).Msg("failed to create ICMPv4 proxy, only ICMPv6 proxy is created")
ipv4Proxy = nil
}
if ipv6Err != nil {
logger.Warn().Err(ipv6Err).Msg("failed to create ICMPv6 proxy, only ICMPv4 proxy is created")
logger.Debug().Err(ipv6Err).Msg("failed to create ICMPv6 proxy, only ICMPv4 proxy is created")
ipv6Proxy = nil
}
return &icmpRouter{

View File

@@ -30,24 +30,24 @@ var (
// Note: if this test fails on your device under Linux, then most likely you need to make sure that your user
// is allowed in ping_group_range. See the following gist for how to do that:
// https://github.com/ValentinBELYN/icmplib/blob/main/docs/6-use-icmplib-without-privileges.md
func TestICMPProxyEcho(t *testing.T) {
testICMPProxyEcho(t, true)
testICMPProxyEcho(t, false)
func TestICMPRouterEcho(t *testing.T) {
testICMPRouterEcho(t, true)
testICMPRouterEcho(t, false)
}
func testICMPProxyEcho(t *testing.T, sendIPv4 bool) {
func testICMPRouterEcho(t *testing.T, sendIPv4 bool) {
const (
echoID = 36571
endSeq = 20
)
proxy, err := NewICMPProxy(&noopLogger)
router, err := NewICMPRouter(&noopLogger)
require.NoError(t, err)
proxyDone := make(chan struct{})
ctx, cancel := context.WithCancel(context.Background())
go func() {
proxy.Serve(ctx)
router.Serve(ctx)
close(proxyDone)
}()
@@ -67,6 +67,7 @@ func testICMPProxyEcho(t *testing.T, sendIPv4 bool) {
Src: localIP,
Dst: localIP,
Protocol: protocol,
TTL: packet.DefaultTTL,
}
}
@@ -88,7 +89,7 @@ func testICMPProxyEcho(t *testing.T, sendIPv4 bool) {
},
},
}
require.NoError(t, proxy.Request(&pk, &responder))
require.NoError(t, router.Request(&pk, &responder))
responder.validate(t, &pk)
}
}
@@ -97,7 +98,7 @@ func testICMPProxyEcho(t *testing.T, sendIPv4 bool) {
}
// TestICMPProxyRejectNotEcho makes sure it rejects messages other than echo
func TestICMPProxyRejectNotEcho(t *testing.T) {
func TestICMPRouterRejectNotEcho(t *testing.T) {
msgs := []icmp.Message{
{
Type: ipv4.ICMPTypeDestinationUnreachable,
@@ -122,7 +123,7 @@ func TestICMPProxyRejectNotEcho(t *testing.T) {
},
},
}
testICMPProxyRejectNotEcho(t, localhostIP, msgs)
testICMPRouterRejectNotEcho(t, localhostIP, msgs)
msgsV6 := []icmp.Message{
{
Type: ipv6.ICMPTypeDestinationUnreachable,
@@ -147,11 +148,11 @@ func TestICMPProxyRejectNotEcho(t *testing.T) {
},
},
}
testICMPProxyRejectNotEcho(t, localhostIPv6, msgsV6)
testICMPRouterRejectNotEcho(t, localhostIPv6, msgsV6)
}
func testICMPProxyRejectNotEcho(t *testing.T, srcDstIP netip.Addr, msgs []icmp.Message) {
proxy, err := NewICMPProxy(&noopLogger)
func testICMPRouterRejectNotEcho(t *testing.T, srcDstIP netip.Addr, msgs []icmp.Message) {
router, err := NewICMPRouter(&noopLogger)
require.NoError(t, err)
responder := echoFlowResponder{
@@ -168,10 +169,11 @@ func testICMPProxyRejectNotEcho(t *testing.T, srcDstIP netip.Addr, msgs []icmp.M
Src: srcDstIP,
Dst: srcDstIP,
Protocol: protocol,
TTL: packet.DefaultTTL,
},
Message: &m,
}
require.Error(t, proxy.Request(&pk, &responder))
require.Error(t, router.Request(&pk, &responder))
}
}