// If the ifindex is zero, interfaceTable returns mappings of all // network interfaces. Otheriwse it returns a mapping of a specific // interface. func interfaceTable(ifindex int) ([]Interface, error) { tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC) if err != nil { return nil, os.NewSyscallError("netlink rib", err) } msgs, err := syscall.ParseNetlinkMessage(tab) if err != nil { return nil, os.NewSyscallError("netlink message", err) } var ift []Interface for _, m := range msgs { switch m.Header.Type { case syscall.NLMSG_DONE: goto done case syscall.RTM_NEWLINK: ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0])) if ifindex == 0 || ifindex == int(ifim.Index) { attrs, err := syscall.ParseNetlinkRouteAttr(&m) if err != nil { return nil, os.NewSyscallError("netlink routeattr", err) } ifi := newLink(ifim, attrs) ift = append(ift, ifi) } } } done: return ift, nil }
func GetDefaultHost() (string, error) { rmsg, rerr := getDefaultRoute() if rerr != nil { return "", rerr } host, oif, err := parsePREFSRC(rmsg) if err != nil { return "", err } if host != "" { return host, nil } // prefsrc not detected, fall back to getting address from iface ifmsg, ierr := getIface(oif) if ierr != nil { return "", ierr } attrs, aerr := syscall.ParseNetlinkRouteAttr(ifmsg) if aerr != nil { return "", aerr } for _, attr := range attrs { if attr.Attr.Type == syscall.RTA_SRC { return net.IP(attr.Value).String(), nil } } return "", errNoDefaultRoute }
func GetDefaultInterface() (string, error) { rmsg, rerr := getDefaultRoute() if rerr != nil { return "", rerr } _, oif, err := parsePREFSRC(rmsg) if err != nil { return "", err } ifmsg, ierr := getIface(oif) if ierr != nil { return "", ierr } attrs, aerr := syscall.ParseNetlinkRouteAttr(ifmsg) if aerr != nil { return "", aerr } for _, attr := range attrs { if attr.Attr.Type == syscall.IFLA_IFNAME { return string(attr.Value[:len(attr.Value)-1]), nil } } return "", errNoDefaultInterface }
func addrTable(ift []Interface, ifi *Interface, msgs []syscall.NetlinkMessage) ([]Addr, error) { var ifat []Addr loop: for _, m := range msgs { switch m.Header.Type { case syscall.NLMSG_DONE: break loop case syscall.RTM_NEWADDR: ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0])) if len(ift) != 0 || ifi.Index == int(ifam.Index) { if len(ift) != 0 { var err error ifi, err = interfaceByIndex(ift, int(ifam.Index)) if err != nil { return nil, err } } attrs, err := syscall.ParseNetlinkRouteAttr(&m) if err != nil { return nil, os.NewSyscallError("parsenetlinkrouteattr", err) } ifa := newAddr(ifi, ifam, attrs) if ifa != nil { ifat = append(ifat, ifa) } } } } return ifat, nil }
// If the ifindex is zero, interfaceTable returns mappings of all // network interfaces. Otherwise it returns a mapping of a specific // interface. func interfaceTable(ifindex int) ([]Interface, error) { // 如果ifindex为0,返回所有网络接口 tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC) // 获得netlink rib if err != nil { return nil, os.NewSyscallError("netlinkrib", err) } msgs, err := syscall.ParseNetlinkMessage(tab) // 解析netlink信息 if err != nil { return nil, os.NewSyscallError("parsenetlinkmessage", err) } var ift []Interface loop: for _, m := range msgs { // 遍历获取的netlink信息 switch m.Header.Type { case syscall.NLMSG_DONE: break loop case syscall.RTM_NEWLINK: ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0])) if ifindex == 0 || ifindex == int(ifim.Index) { attrs, err := syscall.ParseNetlinkRouteAttr(&m) if err != nil { return nil, os.NewSyscallError("parsenetlinkrouteattr", err) } ift = append(ift, *newLink(ifim, attrs)) // 加入到Interface Slice中 if ifindex == int(ifim.Index) { break loop } } } } return ift, nil }
func GetDefaultHost() (string, error) { rmsg, rerr := getDefaultRoute() if rerr != nil { return "", rerr } attrs, aerr := syscall.ParseNetlinkRouteAttr(rmsg) if aerr != nil { return "", aerr } oif := uint32(0) for _, attr := range attrs { if attr.Attr.Type == syscall.RTA_PREFSRC { return net.IP(attr.Value).String(), nil } if attr.Attr.Type == syscall.RTA_OIF { oif = binary.LittleEndian.Uint32(attr.Value) } } if oif == 0 { return "", errNoDefaultRoute } // prefsrc not detected, fall back to getting address from iface ifmsg, ierr := getIface(oif) if ierr != nil { return "", ierr } attrs, aerr = syscall.ParseNetlinkRouteAttr(ifmsg) if aerr != nil { return "", aerr } for _, attr := range attrs { if attr.Attr.Type == syscall.RTA_SRC { return net.IP(attr.Value).String(), nil } } return "", errNoDefaultRoute }
func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, error) { var ifat []Addr for _, m := range msgs { switch m.Header.Type { case syscall.NLMSG_DONE: goto done case syscall.RTM_NEWADDR: ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0])) if ifindex == 0 || ifindex == int(ifam.Index) { attrs, err := syscall.ParseNetlinkRouteAttr(&m) if err != nil { return nil, os.NewSyscallError("netlink routeattr", err) } ifat = append(ifat, newAddr(attrs, int(ifam.Family), int(ifam.Prefixlen))) } } } done: return ifat, nil }
func matchIfName(ifaceName string) func(m syscall.NetlinkMessage) (bool, error) { return func(m syscall.NetlinkMessage) (bool, error) { switch m.Header.Type { case syscall.RTM_NEWLINK: // receive this type for link 'up' ifmsg := nl.DeserializeIfInfomsg(m.Data) attrs, err := syscall.ParseNetlinkRouteAttr(&m) if err != nil { return true, err } name := "" for _, attr := range attrs { if attr.Attr.Type == syscall.IFA_LABEL { name = string(attr.Value[:len(attr.Value)-1]) } } if ifaceName == name && ifmsg.Flags&syscall.IFF_UP != 0 { return true, nil } } return false, nil } }
func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, error) { var ifat []Addr loop: for _, m := range msgs { switch m.Header.Type { case syscall.NLMSG_DONE: break loop case syscall.RTM_NEWADDR: ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0])) ifi, err := InterfaceByIndex(int(ifam.Index)) if err != nil { return nil, err } if ifindex == 0 || ifindex == int(ifam.Index) { attrs, err := syscall.ParseNetlinkRouteAttr(&m) if err != nil { return nil, os.NewSyscallError("netlink routeattr", err) } ifat = append(ifat, newAddr(attrs, ifi, ifam)) } } } return ifat, nil }
// parsePREFSRC returns preferred source address and output interface index (RTA_OIF). func parsePREFSRC(m *syscall.NetlinkMessage) (host string, oif uint32, err error) { var attrs []syscall.NetlinkRouteAttr attrs, err = syscall.ParseNetlinkRouteAttr(m) if err != nil { return "", 0, err } for _, attr := range attrs { if attr.Attr.Type == syscall.RTA_PREFSRC { host = net.IP(attr.Value).String() } if attr.Attr.Type == syscall.RTA_OIF { oif = binary.LittleEndian.Uint32(attr.Value) } if host != "" && oif != uint32(0) { break } } if oif == 0 { err = errNoDefaultRoute } return }
// Returns an array of IPNet for all the currently routed subnets on ipv4 // This is similar to the first column of "ip route" output func NetworkGetRoutes() ([]Route, error) { native := nativeEndian() s, err := getNetlinkSocket() if err != nil { return nil, err } defer s.Close() wb := newNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP) msg := newIfInfomsg(syscall.AF_UNSPEC) wb.AddData(msg) if err := s.Send(wb); err != nil { return nil, err } pid, err := s.GetPid() if err != nil { return nil, err } res := make([]Route, 0) done: for { msgs, err := s.Receive() if err != nil { return nil, err } for _, m := range msgs { if m.Header.Seq != wb.Seq { return nil, fmt.Errorf("Wrong Seq nr %d, expected 1", m.Header.Seq) } if m.Header.Pid != pid { return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid) } if m.Header.Type == syscall.NLMSG_DONE { break done } if m.Header.Type == syscall.NLMSG_ERROR { error := int32(native.Uint32(m.Data[0:4])) if error == 0 { break done } return nil, syscall.Errno(-error) } if m.Header.Type != syscall.RTM_NEWROUTE { continue } var r Route msg := (*RtMsg)(unsafe.Pointer(&m.Data[0:syscall.SizeofRtMsg][0])) if msg.Flags&syscall.RTM_F_CLONED != 0 { // Ignore cloned routes continue } if msg.Table != syscall.RT_TABLE_MAIN { // Ignore non-main tables continue } if msg.Family != syscall.AF_INET { // Ignore non-ipv4 routes continue } if msg.Dst_len == 0 { // Default routes r.Default = true } attrs, err := syscall.ParseNetlinkRouteAttr(&m) if err != nil { return nil, err } for _, attr := range attrs { switch attr.Attr.Type { case syscall.RTA_DST: ip := attr.Value r.IPNet = &net.IPNet{ IP: ip, Mask: net.CIDRMask(int(msg.Dst_len), 8*len(ip)), } case syscall.RTA_OIF: index := int(native.Uint32(attr.Value[0:4])) r.Iface, _ = net.InterfaceByIndex(index) } } if r.Default || r.IPNet != nil { res = append(res, r) } } } return res, nil }
func find_gateway(ip_mask *net.IPNet) (ip net.IP, dev string, err error) { buf, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_INET) if err != nil { log.Println("Failed to open netlink:", err) return } msgs, err := syscall.ParseNetlinkMessage(buf) if err != nil { log.Println("Failed to parse nl msg:", err) return } var def route set := false var once sync.Once loop: for _, m := range msgs { switch m.Header.Type { case syscall.NLMSG_DONE: break loop case syscall.RTM_NEWROUTE: // a route enrty var r route rtmsg := (*syscall.RtMsg)(unsafe.Pointer(&m.Data[0])) attrs, err := syscall.ParseNetlinkRouteAttr(&m) if err != nil { // err is shadowed log.Println("Failed to parse nl rtattr:", err) return ip, dev, err } // parse a route entry for _, a := range attrs { switch a.Attr.Type { case syscall.RTA_DST: addr := a.Value _, r.dst, err = net.ParseCIDR(fmt.Sprintf("%d.%d.%d.%d/%d", addr[0], addr[1], addr[2], addr[3], rtmsg.Dst_len)) if err != nil { log.Println("Failed to parse ip addr:", err) return ip, dev, err } case syscall.RTA_GATEWAY: addr := a.Value r.gateway = net.IPv4(addr[0], addr[1], addr[2], addr[3]) case syscall.RTA_OIF: r.if_index = int(a.Value[0]) } } if r.dst == nil { once.Do(func() { def = r set = true }) } else { if r.dst.Contains(ip_mask.IP) { ifce, err := net.InterfaceByIndex(r.if_index) if err != nil { log.Println("Failed to get interface by index:", err) return ip, dev, err } return r.gateway, ifce.Name, nil } } } } if set { ifce, err := net.InterfaceByIndex(def.if_index) if err != nil { log.Println("Failed to get interface by index:", err) return ip, dev, err } return def.gateway, ifce.Name, nil } err = fmt.Errorf("Route not found.") return }
// New creates a new router object. The router returned by New currently does // not update its routes after construction... care should be taken for // long-running programs to call New() regularly to take into account any // changes to the routing table which have occurred since the last New() call. func New() (Router, error) { rtr := &router{} tab, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_UNSPEC) if err != nil { return nil, err } msgs, err := syscall.ParseNetlinkMessage(tab) if err != nil { return nil, err } loop: for _, m := range msgs { switch m.Header.Type { case syscall.NLMSG_DONE: break loop case syscall.RTM_NEWROUTE: rt := (*routeInfoInMemory)(unsafe.Pointer(&m.Data[0])) routeInfo := rtInfo{} attrs, err := syscall.ParseNetlinkRouteAttr(&m) if err != nil { return nil, err } switch rt.Family { case syscall.AF_INET: rtr.v4 = append(rtr.v4, &routeInfo) case syscall.AF_INET6: rtr.v6 = append(rtr.v6, &routeInfo) default: continue loop } for _, attr := range attrs { switch attr.Attr.Type { case syscall.RTA_DST: routeInfo.Dst = &net.IPNet{ IP: net.IP(attr.Value), Mask: net.CIDRMask(int(rt.DstLen), len(attr.Value)*8), } case syscall.RTA_SRC: routeInfo.Src = &net.IPNet{ IP: net.IP(attr.Value), Mask: net.CIDRMask(int(rt.SrcLen), len(attr.Value)*8), } case syscall.RTA_GATEWAY: routeInfo.Gateway = net.IP(attr.Value) case syscall.RTA_PREFSRC: routeInfo.PrefSrc = net.IP(attr.Value) case syscall.RTA_IIF: routeInfo.InputIface = *(*uint32)(unsafe.Pointer(&attr.Value[0])) case syscall.RTA_OIF: routeInfo.OutputIface = *(*uint32)(unsafe.Pointer(&attr.Value[0])) case syscall.RTA_PRIORITY: routeInfo.Priority = *(*uint32)(unsafe.Pointer(&attr.Value[0])) } } } } sort.Sort(rtr.v4) sort.Sort(rtr.v6) ifaces, err := net.Interfaces() if err != nil { return nil, err } for i, iface := range ifaces { if i != iface.Index-1 { return nil, fmt.Errorf("out of order iface %d = %v", i, iface) } rtr.ifaces = append(rtr.ifaces, iface) var addrs ipAddrs ifaceAddrs, err := iface.Addrs() if err != nil { return nil, err } for _, addr := range ifaceAddrs { if inet, ok := addr.(*net.IPNet); ok { // Go has a nasty habit of giving you IPv4s as ::ffff:1.2.3.4 instead of 1.2.3.4. // We want to use mapped v4 addresses as v4 preferred addresses, never as v6 // preferred addresses. if v4 := inet.IP.To4(); v4 != nil { if addrs.v4 == nil { addrs.v4 = v4 } } else if addrs.v6 == nil { addrs.v6 = inet.IP } } } rtr.addrs = append(rtr.addrs, addrs) } return rtr, nil }
// List all available routes on the system. func Routes() ([]*Route, error) { var routes []*Route rib, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_UNSPEC) if err != nil { return nil, fmt.Errorf("Could not retrieve RIB: %s", err) } msgs, err := syscall.ParseNetlinkMessage(rib) if err != nil { return nil, fmt.Errorf("Could not parse messages: %s") } for _, m := range msgs { if m.Header.Type == syscall.NLMSG_DONE { break } if m.Header.Type != syscall.RTM_NEWROUTE { continue } route := &Route{Default: true} rtmsg := (*rtmsg)(unsafe.Pointer(&m.Data[0])) attrs, err := syscall.ParseNetlinkRouteAttr(&m) if err != nil { return nil, fmt.Errorf("Could not parse attr: %s", err) } for _, a := range attrs { switch a.Attr.Type { case syscall.RTA_SRC: route.SrcNet = &net.IPNet{ IP: net.IP(a.Value), Mask: net.CIDRMask( int(rtmsg.src_len), len(a.Value)*8, ), } case syscall.RTA_DST: route.DstNet = &net.IPNet{ IP: net.IP(a.Value), Mask: net.CIDRMask( int(rtmsg.dst_len), len(a.Value)*8, ), } route.Default = false case syscall.RTA_GATEWAY: route.Gateway = net.IP(a.Value) case syscall.RTA_OIF: oif := *(*uint32)(unsafe.Pointer(&a.Value[0])) iface, err := net.InterfaceByIndex(int(oif)) if err != nil { } route.Iface = iface case syscall.RTA_PRIORITY: } } routes = append(routes, route) } return routes, nil }