// Detect and return host-side network configuration. func getNetConfig() (config *netConfig, err error) { eth0, err := netlink.LinkByName("eth0") if err != nil { return nil, fmt.Errorf("LinkByName(eth0): %v", err) } eth0Addrs, err := netlink.AddrList(eth0, syscall.AF_INET) if err != nil { return nil, fmt.Errorf("AddrList(eth0): %v", err) } if len(eth0Addrs) != 1 { return nil, fmt.Errorf("eth0: Expected single IPv4 address") } // TODO Is there a better way than relying on "8.8.8.8" being past // the default router? defaultroute, err := netlink.RouteGet(net.ParseIP("8.8.8.8")) if len(defaultroute) != 1 { return nil, fmt.Errorf("Could not determine single default route (got %v)", len(defaultroute)) } eth0Attrs := eth0.Attrs() dns := dnsReadConfig("/etc/resolv.conf") hostname, _ := os.Hostname() config = &netConfig{ hostname, eth0Addrs[0].IPNet.String(), defaultroute[0].Gw.String(), eth0Attrs.HardwareAddr.String(), dns.servers, dns.search, } return }
func programGateway(path string, gw net.IP) error { runtime.LockOSThread() defer runtime.UnlockOSThread() origns, err := netns.Get() if err != nil { return err } defer origns.Close() f, err := os.OpenFile(path, os.O_RDONLY, 0) if err != nil { return fmt.Errorf("failed get network namespace %q: %v", path, err) } defer f.Close() nsFD := f.Fd() if err = netns.Set(netns.NsHandle(nsFD)); err != nil { return err } defer netns.Set(origns) gwRoutes, err := netlink.RouteGet(gw) if err != nil { return fmt.Errorf("route for the gateway could not be found: %v", err) } return netlink.RouteAdd(&netlink.Route{ Scope: netlink.SCOPE_UNIVERSE, LinkIndex: gwRoutes[0].LinkIndex, Gw: gw, }) }
// Add a route from the global namespace func programRoute(dest *net.IPNet, nh net.IP) error { gwRoutes, err := netlink.RouteGet(nh) if err != nil { return fmt.Errorf("route for the next hop %s could not be found: %v", nh, err) } return netlink.RouteAdd(&netlink.Route{ Scope: netlink.SCOPE_UNIVERSE, LinkIndex: gwRoutes[0].LinkIndex, Gw: gwRoutes[0].Gw, Dst: dest, }) }
// Delete a route from the namespace routing table. func removeRoute(path string, dest *net.IPNet, nh net.IP) error { return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error { gwRoutes, err := netlink.RouteGet(nh) if err != nil { return fmt.Errorf("route for the next hop could not be found: %v", err) } return netlink.RouteDel(&netlink.Route{ Scope: netlink.SCOPE_UNIVERSE, LinkIndex: gwRoutes[0].LinkIndex, Gw: gwRoutes[0].Gw, Dst: dest, }) }) }
func programGateway(path string, gw net.IP, isAdd bool) error { return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error { gwRoutes, err := netlink.RouteGet(gw) if err != nil { return fmt.Errorf("route for the gateway could not be found: %v", err) } if isAdd { return netlink.RouteAdd(&netlink.Route{ Scope: netlink.SCOPE_UNIVERSE, LinkIndex: gwRoutes[0].LinkIndex, Gw: gw, }) } return netlink.RouteDel(&netlink.Route{ Scope: netlink.SCOPE_UNIVERSE, LinkIndex: gwRoutes[0].LinkIndex, Gw: gw, }) }) }
func processRoute(ru *exportRoute, s net.Addr) error { src := s.(*net.TCPAddr).IP _, err := netlink.AddrList(nil, netlink.FAMILY_ALL) if err != nil { log.Error("Failed to get addresses") log.Error(err) return err } switch { case ru.Type == syscall.RTM_NEWROUTE: r := &netlink.Route{ Dst: ru.Dst, Gw: src, Priority: ru.Priority + 100, } err := netlink.RouteAdd(r) if err != nil { log.Errorf("Failed to add route: %v", r) log.Error(err) return err } case ru.Type == syscall.RTM_DELROUTE: routes, err := netlink.RouteGet(ru.Dst.IP) if err != nil { log.Error("Failed to get routes") log.Error(err) return err } for _, r := range routes { if r.Gw.Equal(src) { netlink.RouteDel(&r) } } } return nil }