mirror of
https://github.com/golang/net.git
synced 2026-03-31 10:27:08 +09:00
route: fix RTM_GET netmask parsing on Darwin
On Darwin, the AF_FAMILY byte of a sockaddr for a netmask or genmask
can be ignored if unreasonable. In such cases, it is the family of the
DST address that should instead be used.
Additionally, fixing faulty test data. 192.168.86.0 is a Class C network
address, that should have a subnet mask of 255.255.255.0. What's more is
the data can also be flag as incorrect considering structure padding
rules alone.
Further more, you can validate that `route get` will never actually return a
netmask for a host query, even though it should be 255.255.255.255.
You can run the following to check:
route -n get -host 127.0.0.1
You will note the reply has no mention of netmask.
Depends on CL 646556 - https://go.dev/cl/646556
Fixes golang/go#71578.
Change-Id: Id95669b649a416a380d26c5cdba0e3d1c4bc1ffb
GitHub-Last-Rev: 20064b2797
GitHub-Pull-Request: golang/net#232
Reviewed-on: https://go-review.googlesource.com/c/net/+/647176
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Commit-Queue: Ian Lance Taylor <iant@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
This commit is contained in:
committed by
Gopher Robot
parent
df97a48b7b
commit
cd9d6616c0
@@ -396,13 +396,19 @@ func marshalAddrs(b []byte, as []Addr) (uint, error) {
|
||||
func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) ([]Addr, error) {
|
||||
var as [syscall.RTAX_MAX]Addr
|
||||
af := int(syscall.AF_UNSPEC)
|
||||
isInet := func(fam int) bool {
|
||||
return fam == syscall.AF_INET || fam == syscall.AF_INET6
|
||||
}
|
||||
isMask := func(addrType uint) bool {
|
||||
return addrType == syscall.RTAX_NETMASK || addrType == syscall.RTAX_GENMASK
|
||||
}
|
||||
for i := uint(0); i < syscall.RTAX_MAX && len(b) >= roundup(0); i++ {
|
||||
if attrs&(1<<i) == 0 {
|
||||
continue
|
||||
}
|
||||
if i <= syscall.RTAX_BRD {
|
||||
switch b[1] {
|
||||
case syscall.AF_LINK:
|
||||
switch {
|
||||
case b[1] == syscall.AF_LINK:
|
||||
a, err := parseLinkAddr(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -413,8 +419,10 @@ func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) (
|
||||
return nil, errMessageTooShort
|
||||
}
|
||||
b = b[l:]
|
||||
case syscall.AF_INET, syscall.AF_INET6:
|
||||
af = int(b[1])
|
||||
case isInet(int(b[1])) || (isMask(i) && isInet(af)):
|
||||
if isInet(int(b[1])) {
|
||||
af = int(b[1])
|
||||
}
|
||||
a, err := parseInetAddr(af, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -29,12 +29,12 @@ var parseAddrsOnDarwinLittleEndianTests = []parseAddrsOnDarwinTest{
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0,
|
||||
|
||||
0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0,
|
||||
},
|
||||
[]Addr{
|
||||
&Inet4Addr{IP: [4]byte{192, 168, 86, 0}},
|
||||
&LinkAddr{Index: 4},
|
||||
&Inet4Addr{IP: [4]byte{255, 255, 255, 255}},
|
||||
&Inet4Addr{IP: [4]byte{255, 255, 255, 0}},
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
|
||||
70
route/example_darwin_test.go
Normal file
70
route/example_darwin_test.go
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package route_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/net/route"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// This example demonstrates how to parse a response to RTM_GET request.
|
||||
func ExampleParseRIB() {
|
||||
fd, err := unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer unix.Close(fd)
|
||||
|
||||
// Create a RouteMessage with RTM_GET type
|
||||
rtm := &route.RouteMessage{
|
||||
Version: syscall.RTM_VERSION,
|
||||
Type: unix.RTM_GET,
|
||||
ID: uintptr(os.Getpid()),
|
||||
Seq: 0,
|
||||
Addrs: []route.Addr{
|
||||
&route.Inet4Addr{IP: [4]byte{127, 0, 0, 0}},
|
||||
},
|
||||
}
|
||||
|
||||
// Marshal the message into bytes
|
||||
msgBytes, err := rtm.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Send the message over the routing socket
|
||||
_, err = unix.Write(fd, msgBytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Read the response from the routing socket
|
||||
var buf [2 << 10]byte
|
||||
n, err := unix.Read(fd, buf[:])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Parse the response messages
|
||||
msgs, err := route.ParseRIB(route.RIBTypeRoute, buf[:n])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
routeMsg, ok := msgs[0].(*route.RouteMessage)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
netmask, ok := routeMsg.Addrs[2].(*route.Inet4Addr)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
fmt.Println(netip.AddrFrom4(netmask.IP))
|
||||
// Output: 255.0.0.0
|
||||
}
|
||||
Reference in New Issue
Block a user