Skip to content

Commit ebd23f8

Browse files
hurricanehrndzgopherbot
authored andcommitted
route: fix parsing network address of length zero
sa_len of 0 should be valid, for Chapter 18 of UNIX® Network Programming Volume 1, Third Edition: The Sockets Networking API, states: 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 golang/go#70528 Change-Id: I9205a674f9cdf8091b1cc8b8a56609cd1cf4c670 GitHub-Last-Rev: df63086 GitHub-Pull-Request: #230 Reviewed-on: https://go-review.googlesource.com/c/net/+/646555 Auto-Submit: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Reviewed-by: Damien Neil <dneil@google.com>
1 parent 938a9fb commit ebd23f8

File tree

2 files changed

+41
-35
lines changed

2 files changed

+41
-35
lines changed

route/address.go

+40-34
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])
183185
a := &Inet4Addr{}
184-
n := off4 + 4
185-
if sockAddrLen < n {
186-
n = sockAddrLen
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-
}
199202
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
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)