From 47698be2ede7f93d496d6dd0487a03a5e285a6db Mon Sep 17 00:00:00 2001 From: bobo liu Date: Sat, 11 Nov 2023 21:36:48 +0800 Subject: [PATCH 1/2] add source ip support for macOS rootless solution do you guys not have macos devices? --- trace/icmp_ipv4.go | 4 ++- trace/icmp_ipv6.go | 4 ++- trace/internal/icmp_darwin.go | 47 ++++++++++++++++++++++++++++++++--- 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/trace/icmp_ipv4.go b/trace/icmp_ipv4.go index c5bc170c..54340725 100644 --- a/trace/icmp_ipv4.go +++ b/trace/icmp_ipv4.go @@ -15,6 +15,8 @@ import ( "golang.org/x/net/context" "golang.org/x/net/icmp" "golang.org/x/net/ipv4" + + "github.com/nxtrace/NTrace-core/trace/internal" ) type ICMPTracer struct { @@ -67,7 +69,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 3dc26ba0..7202788e 100644 --- a/trace/icmp_ipv6.go +++ b/trace/icmp_ipv6.go @@ -13,6 +13,8 @@ import ( "golang.org/x/net/context" "golang.org/x/net/icmp" "golang.org/x/net/ipv6" + + "github.com/nxtrace/NTrace-core/trace/internal" ) type ICMPTracerv6 struct { @@ -65,7 +67,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 index 1ae6649e..e919bc12 100644 --- a/trace/internal/icmp_darwin.go +++ b/trace/internal/icmp_darwin.go @@ -12,13 +12,14 @@ import ( ) //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) +func internetSocket(ctx context.Context, net string, laddr, raddr any, 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") + errUnknownIface = errors.New("unknown network interface") networkMap = map[string]string{ "ip4:icmp": "udp4", @@ -28,7 +29,6 @@ var ( } ) -// ListenICMP 会造成指定出口IP功能不可使用 func ListenICMP(network string, laddr string) (net.PacketConn, error) { if os.Getuid() == 0 { // root return net.ListenPacket(network, laddr) @@ -38,7 +38,48 @@ func ListenICMP(network string, laddr string) (net.PacketConn, error) { if nw == "udp6" { proto = syscall.IPPROTO_ICMPV6 } - isock, err := internetSocket(context.Background(), nw, nil, nil, syscall.SOCK_DGRAM, proto, "listen", nil) + + var ifIndex int = -1 + if laddr != "" { + la := net.ParseIP(laddr) + if ifaces, err := net.Interfaces(); err == nil { + for _, iface := range ifaces { + addrs, err := iface.Addrs() + if err != nil { + continue + } + for _, addr := range addrs { + if ipnet, ok := addr.(*net.IPNet); ok { + if ipnet.IP.Equal(la) { + ifIndex = iface.Index + break + } + } + } + } + if ifIndex == -1 { + return nil, errUnknownIface + } + } else { + return nil, err + } + } + + isock, err := internetSocket(context.Background(), nw, nil, nil, syscall.SOCK_DGRAM, proto, "listen", + func(ctx context.Context, network, address string, c syscall.RawConn) error { + if ifIndex != -1 { + if proto == syscall.IPPROTO_ICMP { + return c.Control(func(fd uintptr) { + syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BOUND_IF, ifIndex) + }) + } else { + return c.Control(func(fd uintptr) { + syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BOUND_IF, ifIndex) + }) + } + } + return nil + }) if err != nil { panic(err) } From e4626c4f8262e294c96d6aa1fb0741c077612a87 Mon Sep 17 00:00:00 2001 From: bobo liu Date: Sun, 12 Nov 2023 00:11:11 +0800 Subject: [PATCH 2/2] notice silver-bullet of permission issue --- trace/trace.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/trace/trace.go b/trace/trace.go index d58f3a1c..f8d48913 100644 --- a/trace/trace.go +++ b/trace/trace.go @@ -7,6 +7,7 @@ import ( "strconv" "strings" "sync" + "syscall" "time" "github.com/nxtrace/NTrace-core/ipgeo" @@ -92,7 +93,11 @@ func Traceroute(method Method, config Config) (*Result, error) { default: return &Result{}, ErrInvalidMethod } - return tracer.Execute() + result, err := tracer.Execute() + if err != nil && errors.Is(err, syscall.EPERM) { + err = fmt.Errorf("%w, please run as root", err) + } + return result, err } type Result struct {