From 2bac716bd76510955ad4691d2a8303140dc979de Mon Sep 17 00:00:00 2001 From: bobo liu Date: Sat, 3 Jun 2023 16:50:21 +0800 Subject: [PATCH] improve: rootless trace on macOS --- trace/icmp_ipv4.go | 3 ++- trace/icmp_ipv6.go | 3 ++- trace/internal/icmp_darwin.go | 49 ++++++++++++++++++++++++++++++++++ trace/internal/icmp_darwin.s | 0 trace/internal/icmp_general.go | 9 +++++++ trace/trace.go | 2 +- 6 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 trace/internal/icmp_darwin.go create mode 100644 trace/internal/icmp_darwin.s create mode 100644 trace/internal/icmp_general.go diff --git a/trace/icmp_ipv4.go b/trace/icmp_ipv4.go index 901457c..4cd9235 100644 --- a/trace/icmp_ipv4.go +++ b/trace/icmp_ipv4.go @@ -12,6 +12,7 @@ import ( "sync" "time" + "github.com/xgadget-lab/nexttrace/trace/internal" "golang.org/x/net/context" "golang.org/x/net/icmp" "golang.org/x/net/ipv4" @@ -64,7 +65,7 @@ func (t *ICMPTracer) Execute() (*Result, error) { var err error - t.icmpListen, err = net.ListenPacket("ip4:1", t.SrcAddr) + t.icmpListen, err = internal.ListenICMP("ip4:1", t.SrcAddr) if err != nil { return &t.res, err } diff --git a/trace/icmp_ipv6.go b/trace/icmp_ipv6.go index 2f0ffe7..69bcf90 100644 --- a/trace/icmp_ipv6.go +++ b/trace/icmp_ipv6.go @@ -10,6 +10,7 @@ import ( "sync" "time" + "github.com/xgadget-lab/nexttrace/trace/internal" "golang.org/x/net/context" "golang.org/x/net/icmp" "golang.org/x/net/ipv6" @@ -65,7 +66,7 @@ func (t *ICMPTracerv6) Execute() (*Result, error) { var err error - t.icmpListen, err = net.ListenPacket("ip6:58", t.SrcAddr) + t.icmpListen, err = internal.ListenICMP("ip6:58", t.SrcAddr) if err != nil { return &t.res, err } diff --git a/trace/internal/icmp_darwin.go b/trace/internal/icmp_darwin.go new file mode 100644 index 0000000..dd2fbe6 --- /dev/null +++ b/trace/internal/icmp_darwin.go @@ -0,0 +1,49 @@ +//go:build darwin + +package internal + +import ( + "context" + "errors" + "net" + "os" + "syscall" + "unsafe" +) + +//go:linkname internetSocket net.internetSocket +func internetSocket(ctx context.Context, net string, laddr, raddr interface{}, sotype, proto int, mode string, ctrlCtxFn func(context.Context, string, string, syscall.RawConn) error) (fd unsafe.Pointer, err error) + +//go:linkname newIPConn net.newIPConn +func newIPConn(fd unsafe.Pointer) *net.IPConn + +var ( + errUnknownNetwork = errors.New("unknown network type") + + networkMap = map[string]string{ + "ip4:icmp": "udp4", + "ip4:1": "udp4", + "ip6:icmp": "udp6", + "ip6:58": "udp6", + } +) + +func ListenICMP(network string, laddr string) (net.PacketConn, error) { + if os.Getuid() == 0 { // root + return net.ListenPacket(network, laddr) + } else { + if nw, ok := networkMap[network]; ok { + proto := syscall.IPPROTO_ICMP + if nw == "udp6" { + proto = syscall.IPPROTO_ICMPV6 + } + isock, err := internetSocket(context.Background(), nw, nil, nil, syscall.SOCK_DGRAM, proto, "listen", nil) + if err != nil { + panic(err) + } + return newIPConn(isock), nil + } else { + return nil, errUnknownNetwork + } + } +} diff --git a/trace/internal/icmp_darwin.s b/trace/internal/icmp_darwin.s new file mode 100644 index 0000000..e69de29 diff --git a/trace/internal/icmp_general.go b/trace/internal/icmp_general.go new file mode 100644 index 0000000..89c1ce5 --- /dev/null +++ b/trace/internal/icmp_general.go @@ -0,0 +1,9 @@ +//go:build !darwin + +package internal + +import "net" + +func ListenICMP(network string, laddr string) (net.PacketConn, error) { + return net.ListenPacket(network, laddr) +} diff --git a/trace/trace.go b/trace/trace.go index ddf3050..13303ea 100644 --- a/trace/trace.go +++ b/trace/trace.go @@ -2,12 +2,12 @@ package trace import ( "errors" - "github.com/xgadget-lab/nexttrace/util" "net" "sync" "time" "github.com/xgadget-lab/nexttrace/ipgeo" + "github.com/xgadget-lab/nexttrace/util" ) var (