netconfig: added GetIPRoutes(defaultOnly bool) and IsDefaultIPRoute() that works for
BSD, Mac, and Linux.
Change-Id: Ic46435045948ab9db756dec82ae3bb9c5a37c7d0
diff --git a/lib/netconfig/ipaux_linux.go b/lib/netconfig/ipaux_linux.go
index c598da3..49945d1 100644
--- a/lib/netconfig/ipaux_linux.go
+++ b/lib/netconfig/ipaux_linux.go
@@ -369,3 +369,72 @@
}
w.Unlock()
}
+func toIP(a []byte) (net.IP, error) {
+ switch len(a) {
+ case 4:
+ return net.IPv4(a[0], a[1], a[2], a[3]), nil
+ case 16:
+ return net.IP(a), nil
+ }
+ return net.IPv6unspecified, errors.New("unknown ip address len")
+}
+
+// IPRoutes returns all kernel known routes. If defaultOnly is set, only default routes
+// are returned.
+func GetIPRoutes(defaultOnly bool) []*IPRoute {
+ var x []*IPRoute
+ rib, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_UNSPEC)
+ if err != nil {
+ vlog.Infof("Couldn't read: %s", err)
+ return x
+ }
+ msgs, err := syscall.ParseNetlinkMessage(rib)
+ if err != nil {
+ vlog.Infof("Couldn't parse: %s", err)
+ return x
+ }
+L:
+ for _, m := range msgs {
+ if m.Header.Type != syscall.RTM_NEWROUTE {
+ continue
+ }
+ attrs, err := syscall.ParseNetlinkRouteAttr(&m)
+ if err != nil {
+ continue
+ }
+ r := new(IPRoute)
+ r.Net.IP = net.IPv4zero
+ for _, a := range attrs {
+ switch a.Attr.Type {
+ case syscall.RTA_DST:
+ if r.Net.IP, err = toIP(a.Value[:]); err != nil {
+ continue L
+ }
+ case syscall.RTA_GATEWAY:
+ if r.Gateway, err = toIP(a.Value[:]); err != nil {
+ continue L
+ }
+ case syscall.RTA_OIF:
+ r.IfcIndex = int(a.Value[0])
+ case syscall.RTA_PREFSRC:
+ if r.PreferredSource, err = toIP(a.Value[:]); err != nil {
+ continue L
+ }
+ }
+ }
+ b := m.Data[:syscall.SizeofRtMsg]
+ a := (*syscall.RtMsg)(unsafe.Pointer(&b[0]))
+ len := 128
+ if r.Net.IP.To4() != nil {
+ len = 32
+ }
+ if int(a.Dst_len) > len {
+ continue
+ }
+ r.Net.Mask = net.CIDRMask(int(a.Dst_len), len)
+ if !defaultOnly || IsDefaultIPRoute(r) {
+ x = append(x, r)
+ }
+ }
+ return x
+}