netlink: add func AddrSubscribe on darwin

This commit is contained in:
rkonfj
2024-07-18 22:12:48 +08:00
parent a9063a8ba8
commit 074c53fb2b
2 changed files with 92 additions and 0 deletions

9
netlink/addr.go Normal file
View File

@@ -0,0 +1,9 @@
package netlink
import "net"
type AddrUpdate struct {
New bool
Addr net.IPNet
LinkIndex int
}

83
netlink/addr_darwin.go Normal file
View File

@@ -0,0 +1,83 @@
package netlink
import (
"context"
"encoding/hex"
"fmt"
"log/slog"
"net"
"os"
"slices"
"syscall"
"golang.org/x/net/route"
)
func AddrSubscribe(ctx context.Context, ch chan<- AddrUpdate) error {
fd, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC)
if err != nil {
return fmt.Errorf("syscall socket: %w", err)
}
go func() {
err := runAddrMsgReadLoop(fd, ch)
if err != nil {
slog.Error("AddrSubscribe", "err", fmt.Errorf("msg read loop exited: %w", err))
}
}()
go func() {
<-ctx.Done()
syscall.Close(fd)
close(ch)
}()
return nil
}
func runAddrMsgReadLoop(fd int, ch chan<- AddrUpdate) error {
buf := make([]byte, os.Getpagesize())
for {
n, err := syscall.Read(fd, buf)
if err != nil {
return fmt.Errorf("syscall read: %w", err)
}
buf[0] = 254
msgs, err := route.ParseRIB(route.RIBTypeRoute, buf[:254])
if err != nil {
slog.Warn("RouteParseRIB", "err", err, "msglen", n, "msg", hex.EncodeToString(buf[:n]))
continue
}
for _, msg := range msgs {
m, ok := msg.(*route.InterfaceAddrMessage)
if !ok {
continue
}
if !slices.Contains([]int{syscall.RTM_NEWADDR, syscall.RTM_DELADDR}, m.Type) {
continue
}
ipnet := net.IPNet{}
for _, addr := range m.Addrs {
var ip []byte
switch v := addr.(type) {
case *route.Inet4Addr:
ip = v.IP[:]
case *route.Inet6Addr:
ip = v.IP[:]
default:
continue
}
if ipnet.Mask == nil {
ipnet.Mask = ip
continue
}
if ipnet.IP == nil {
ipnet.IP = ip
break
}
}
ch <- AddrUpdate{
New: m.Type == syscall.RTM_NEWADDR,
Addr: ipnet,
LinkIndex: m.Index,
}
}
}
}