TUN-6654: Support ICMPv6 on Linux and Darwin

This commit is contained in:
cthuang
2022-09-06 13:46:21 +01:00
parent a65f8bce7f
commit bf3d70d1d2
7 changed files with 232 additions and 68 deletions

View File

@@ -8,6 +8,8 @@ import (
"github.com/rs/zerolog"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
"github.com/cloudflare/cloudflared/packet"
)
@@ -32,8 +34,65 @@ type ICMPProxy interface {
Request(pk *packet.ICMP, responder packet.FunnelUniPipe) error
}
func NewICMPProxy(listenIP netip.Addr, logger *zerolog.Logger) (ICMPProxy, error) {
return newICMPProxy(listenIP, logger, funnelIdleTimeout)
type icmpRouter struct {
ipv4Proxy ICMPProxy
ipv6Proxy ICMPProxy
}
// NewICMPProxy 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) {
// TODO: TUN-6741: don't bind to all interface
ipv4Proxy, ipv4Err := newICMPProxy(netip.IPv4Unspecified(), logger, funnelIdleTimeout)
ipv6Proxy, ipv6Err := newICMPProxy(netip.IPv6Unspecified(), logger, funnelIdleTimeout)
if ipv4Err != nil && ipv6Err != nil {
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")
ipv4Proxy = nil
}
if ipv6Err != nil {
logger.Warn().Err(ipv6Err).Msg("failed to create ICMPv6 proxy, only ICMPv4 proxy is created")
ipv6Proxy = nil
}
return &icmpRouter{
ipv4Proxy: ipv4Proxy,
ipv6Proxy: ipv6Proxy,
}, nil
}
func (ir *icmpRouter) Serve(ctx context.Context) error {
if ir.ipv4Proxy != nil && ir.ipv6Proxy != nil {
errC := make(chan error, 2)
go func() {
errC <- ir.ipv4Proxy.Serve(ctx)
}()
go func() {
errC <- ir.ipv6Proxy.Serve(ctx)
}()
return <-errC
}
if ir.ipv4Proxy != nil {
return ir.ipv4Proxy.Serve(ctx)
}
if ir.ipv6Proxy != nil {
return ir.ipv6Proxy.Serve(ctx)
}
return fmt.Errorf("ICMPv4 proxy and ICMPv6 proxy are both nil")
}
func (ir *icmpRouter) Request(pk *packet.ICMP, responder packet.FunnelUniPipe) error {
if pk.Dst.Is4() {
if ir.ipv4Proxy != nil {
return ir.ipv4Proxy.Request(pk, responder)
}
return fmt.Errorf("ICMPv4 proxy was not instantiated")
}
if ir.ipv6Proxy != nil {
return ir.ipv6Proxy.Request(pk, responder)
}
return fmt.Errorf("ICMPv6 proxy was not instantiated")
}
func getICMPEcho(msg *icmp.Message) (*icmp.Echo, error) {
@@ -43,3 +102,7 @@ func getICMPEcho(msg *icmp.Message) (*icmp.Echo, error) {
}
return echo, nil
}
func isEchoReply(msg *icmp.Message) bool {
return msg.Type == ipv4.ICMPTypeEchoReply || msg.Type == ipv6.ICMPTypeEchoReply
}