Skip to content

Commit 21a12d8

Browse files
fix: network address of length zero are valid
Using the route command I replicated the original bug and observed the correct marshaling of the route message, confirming what was stated in 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.
1 parent 145b2d7 commit 21a12d8

File tree

2 files changed

+43
-37
lines changed

2 files changed

+43
-37
lines changed

route/address.go

+42-36
Original file line numberDiff line numberDiff line change
@@ -171,45 +171,55 @@ func (a *Inet6Addr) marshal(b []byte) (int, error) {
171171
// parseInetAddr parses b as an internet address for IPv4 or IPv6.
172172
func parseInetAddr(af int, b []byte) (Addr, error) {
173173
const (
174-
off4 = 4 // offset of in_addr
175-
off6 = 8 // offset of in6_addr
174+
off4 = 4 // offset of in_addr
175+
off6 = 8 // offset of in6_addr
176+
ipv4Len = 4 // length of IPv4 address in bytes
177+
ipv6Len = 16 // length of IPv6 address in bytes
176178
)
177179
switch af {
178180
case syscall.AF_INET:
179-
if len(b) < (off4+1) || len(b) < int(b[0]) || b[0] == 0 {
181+
if len(b) < (off4+1) || len(b) < int(b[0]) {
180182
return nil, errInvalidAddr
181183
}
182184
sockAddrLen := int(b[0])
183-
a := &Inet4Addr{}
184-
n := off4 + 4
185-
if sockAddrLen < n {
186-
n = sockAddrLen
185+
a := &Inet4Addr{IP: [ipv4Len]byte{}}
186+
// sockAddrLen of 0 is valid and represents 0.0.0.0
187+
if sockAddrLen != 0 {
188+
// Calculate how many bytes of the address to copy:
189+
// either full IPv4 length or the available length
190+
n := off4 + ipv4Len
191+
if sockAddrLen < n {
192+
n = sockAddrLen
193+
}
194+
copy(a.IP[:], b[off4:n])
187195
}
188-
copy(a.IP[:], b[off4:n])
189196
return a, nil
190197
case syscall.AF_INET6:
191-
if len(b) < (off6+1) || len(b) < int(b[0]) || b[0] == 0 {
198+
if len(b) < (off6+1) || len(b) < int(b[0]) {
192199
return nil, errInvalidAddr
193200
}
194201
sockAddrLen := int(b[0])
195-
n := off6 + 16
196-
if sockAddrLen < n {
197-
n = sockAddrLen
198-
}
199-
a := &Inet6Addr{}
200-
if sockAddrLen == sizeofSockaddrInet6 {
201-
a.ZoneID = int(nativeEndian.Uint32(b[24:28]))
202-
}
203-
copy(a.IP[:], b[off6:n])
204-
if a.IP[0] == 0xfe && a.IP[1]&0xc0 == 0x80 || a.IP[0] == 0xff && (a.IP[1]&0x0f == 0x01 || a.IP[1]&0x0f == 0x02) {
205-
// KAME based IPv6 protocol stack usually
206-
// embeds the interface index in the
207-
// interface-local or link-local address as
208-
// the kernel-internal form.
209-
id := int(bigEndian.Uint16(a.IP[2:4]))
210-
if id != 0 {
211-
a.ZoneID = id
212-
a.IP[2], a.IP[3] = 0, 0
202+
a := &Inet6Addr{IP: [ipv6Len]byte{}}
203+
// sockAddrLen of 0 is valid and represents ::
204+
if sockAddrLen != 0 {
205+
n := off6 + ipv6Len
206+
if sockAddrLen < n {
207+
n = sockAddrLen
208+
}
209+
if sockAddrLen == sizeofSockaddrInet6 {
210+
a.ZoneID = int(nativeEndian.Uint32(b[24:28]))
211+
}
212+
copy(a.IP[:], b[off6:n])
213+
if a.IP[0] == 0xfe && a.IP[1]&0xc0 == 0x80 || a.IP[0] == 0xff && (a.IP[1]&0x0f == 0x01 || a.IP[1]&0x0f == 0x02) {
214+
// KAME based IPv6 protocol stack usually
215+
// embeds the interface index in the
216+
// interface-local or link-local address as
217+
// the kernel-internal form.
218+
id := int(bigEndian.Uint16(a.IP[2:4]))
219+
if id != 0 {
220+
a.ZoneID = id
221+
a.IP[2], a.IP[3] = 0, 0
222+
}
213223
}
214224
}
215225
return a, nil
@@ -404,16 +414,12 @@ func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) (
404414
}
405415
b = b[l:]
406416
case syscall.AF_INET, syscall.AF_INET6:
407-
// #70528: if the sockaddrlen is 0, no address to parse inside,
408-
// skip over the record.
409-
if b[0] > 0 {
410-
af = int(b[1])
411-
a, err := parseInetAddr(af, b)
412-
if err != nil {
413-
return nil, err
414-
}
415-
as[i] = a
417+
af = int(b[1])
418+
a, err := parseInetAddr(af, b)
419+
if err != nil {
420+
return nil, err
416421
}
422+
as[i] = a
417423
l := roundup(int(b[0]))
418424
if len(b) < l {
419425
return nil, errMessageTooShort

route/address_darwin_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ var parseAddrsOnDarwinLittleEndianTests = []parseAddrsOnDarwinTest{
112112
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
113113
},
114114
[]Addr{
115-
nil,
115+
&Inet6Addr{IP: [16]byte{}},
116116
&Inet6Addr{IP: [16]byte{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x2f, 0x4b, 0xff, 0xfe, 0x09, 0x3b, 0xff}, ZoneID: 33},
117117
&Inet6Addr{IP: [16]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},
118118
nil,

0 commit comments

Comments
 (0)