예제 #1
0
// 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
}
예제 #2
0
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
}
예제 #3
0
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
}
예제 #4
0
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
}
예제 #5
0
// 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
}
예제 #6
0
파일: routes_linux.go 프로젝트: nhr/origin
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
}
예제 #7
0
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
}
예제 #8
0
파일: if.go 프로젝트: narry/weave
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
	}
}
예제 #9
0
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
}
예제 #10
0
// 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
}
예제 #11
0
// 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
}
예제 #12
0
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
}
예제 #13
0
파일: routing.go 프로젝트: nplanel/gopacket
// 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
}
예제 #14
0
// 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
}