From df63086c54071ecf3369142a0ed04197eb30091e Mon Sep 17 00:00:00 2001 From: Carlos Hernandez Date: Tue, 4 Feb 2025 09:17:26 -0700 Subject: [PATCH] fix: network address of length zero are valid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Chapter 18 of UNIX® Network Programming Volume 1, Third Edition: The Sockets Networking API: The socket address structures are variable-length, but this code assumes that each has an sa_len field specifying its length. There are two complications that must be handled. First, the two masks, the network mask and the cloning mask, can be returned in a socket address structure with an sa_len of 0, but this really occupies the size of an unsigned long. (Chapter 19 of TCPv2 discusses the cloning feature of the 4.4BSD routing table). This value represents a mask of all zero bits, which we printed as 0.0.0.0 for the network mask of the default route in our earlier example. There are other references in the book which also state sa_len of 0 is valid. fixes #70528 --- route/address.go | 74 +++++++++++++++++++----------------- route/address_darwin_test.go | 2 +- 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/route/address.go b/route/address.go index b649f43141..d0e9f415fe 100644 --- a/route/address.go +++ b/route/address.go @@ -171,45 +171,55 @@ 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 + off4 = 4 // offset of in_addr + off6 = 8 // offset of in6_addr + ipv4Len = 4 // length of IPv4 address in bytes + ipv6Len = 16 // length of IPv6 address in bytes ) switch af { case syscall.AF_INET: - if len(b) < (off4+1) || len(b) < int(b[0]) || b[0] == 0 { + if len(b) < (off4+1) || len(b) < int(b[0]) { return nil, errInvalidAddr } sockAddrLen := int(b[0]) a := &Inet4Addr{} - n := off4 + 4 - if sockAddrLen < n { - n = sockAddrLen + // sockAddrLen of 0 is valid and represents 0.0.0.0 + if sockAddrLen != 0 { + // Calculate how many bytes of the address to copy: + // either full IPv4 length or the available length. + n := off4 + ipv4Len + if sockAddrLen < n { + n = sockAddrLen + } + copy(a.IP[:], b[off4:n]) } - copy(a.IP[:], b[off4:n]) return a, nil case syscall.AF_INET6: - if len(b) < (off6+1) || len(b) < int(b[0]) || b[0] == 0 { + if len(b) < (off6+1) || len(b) < int(b[0]) { return nil, errInvalidAddr } 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 - // interface-local or link-local address as - // the kernel-internal form. - id := int(bigEndian.Uint16(a.IP[2:4])) - if id != 0 { - a.ZoneID = id - a.IP[2], a.IP[3] = 0, 0 + // sockAddrLen of 0 is valid and represents :: + if sockAddrLen != 0 { + n := off6 + ipv6Len + if sockAddrLen < n { + n = sockAddrLen + } + 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 + // interface-local or link-local address as + // the kernel-internal form. + id := int(bigEndian.Uint16(a.IP[2:4])) + if id != 0 { + a.ZoneID = id + a.IP[2], a.IP[3] = 0, 0 + } } } return a, nil @@ -404,16 +414,12 @@ func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) ( } b = b[l:] case syscall.AF_INET, syscall.AF_INET6: - // #70528: if the sockaddrlen is 0, no address to parse inside, - // skip over the record. - if b[0] > 0 { - af = int(b[1]) - a, err := parseInetAddr(af, b) - if err != nil { - return nil, err - } - as[i] = a + af = int(b[1]) + a, err := parseInetAddr(af, b) + if err != nil { + return nil, err } + as[i] = a l := roundup(int(b[0])) if len(b) < l { return nil, errMessageTooShort diff --git a/route/address_darwin_test.go b/route/address_darwin_test.go index add72e37ec..55accff9d8 100644 --- a/route/address_darwin_test.go +++ b/route/address_darwin_test.go @@ -112,7 +112,7 @@ var parseAddrsOnDarwinLittleEndianTests = []parseAddrsOnDarwinTest{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, }, []Addr{ - nil, + &Inet6Addr{IP: [16]byte{}}, &Inet6Addr{IP: [16]byte{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x2f, 0x4b, 0xff, 0xfe, 0x09, 0x3b, 0xff}, ZoneID: 33}, &Inet6Addr{IP: [16]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, nil,