From 34e7bf9e3962639b5539ab7fcb34d5e094a3a11e Mon Sep 17 00:00:00 2001 From: Carlos Hernandez Date: Thu, 29 Aug 2024 11:50:59 -0600 Subject: [PATCH] route: fix address parsing of messages on Darwin partial fix golang/go#44740 sizeofSockaddrInet is 16, but first byte of sockaddr specifies the size of the address. 16 works for most cases, except Netmasks addresses, on Darwin where only the significant bits are in the msg. Take this route message as an example ``` 88 00 05 01 00 00 00 00 41 08 00 00 07 00 00 00 92 7b 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 DST 10 02 00 00 64 71 00 00 00 00 00 00 00 00 00 00 // 100.113.0.0 GW 14 12 21 00 01 08 00 00 75 74 75 6e 34 33 31 39 00 00 00 00 // !utun4319 MASK 06 02 00 00 ff ff // 255.255.0.0 NULL 00 00 ``` i.e. ipv4 ``` 06 02 00 00 ff ff ``` The above byte sequence is for a sockaddr that is 6 bytes long representing an ipv4 for address that is 255.255.0.0. i.e. ipv6 netmask ``` 0e 1e 00 00 00 00 00 00 ff ff ff ff ff ff 00 00 ``` The above is /48 netmask that should also be parsed using b[0] of the sockaddr that contains the lenght. Confirmed by using `route monitor`. sources: https://github.com/apple/darwin-xnu/blob/main/bsd/net/route.h https://github.com/apple/darwin-xnu/blob/main/bsd/sys/socket.h#L603 --- route/address.go | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/route/address.go b/route/address.go index 5443d67223..bae63003f0 100644 --- a/route/address.go +++ b/route/address.go @@ -170,20 +170,37 @@ func (a *Inet6Addr) marshal(b []byte) (int, error) { // parseInetAddr parses b as an internet address for IPv4 or IPv6. func parseInetAddr(af int, b []byte) (Addr, error) { + const ( + off4 = 4 // offset of in_addr + off6 = 8 // offset of in6_addr + ) switch af { case syscall.AF_INET: - if len(b) < sizeofSockaddrInet { + if len(b) < (off4+1) || len(b) < int(b[0]) { return nil, errInvalidAddr } + sockAddrLen := int(b[0]) a := &Inet4Addr{} - copy(a.IP[:], b[4:8]) + n := off4 + 4 + if sockAddrLen < n { + n = sockAddrLen + } + copy(a.IP[:], b[off4:n]) return a, nil case syscall.AF_INET6: - if len(b) < sizeofSockaddrInet6 { + if len(b) < (off6+1) || len(b) < int(b[0]) { return nil, errInvalidAddr } - a := &Inet6Addr{ZoneID: int(nativeEndian.Uint32(b[24:28]))} - copy(a.IP[:], b[8:24]) + sockAddrLen := int(b[0]) + n := off6 + 16 + if sockAddrLen < n { + n = sockAddrLen + } + a := &Inet6Addr{} + if sockAddrLen == sizeofSockaddrInet6 { + a.ZoneID = int(nativeEndian.Uint32(b[24:28])) + } + copy(a.IP[:], b[off6:n]) if a.IP[0] == 0xfe && a.IP[1]&0xc0 == 0x80 || a.IP[0] == 0xff && (a.IP[1]&0x0f == 0x01 || a.IP[1]&0x0f == 0x02) { // KAME based IPv6 protocol stack usually // embeds the interface index in the