package vip import ( "errors" "net" "sync" "github.com/vishvananda/netlink" ) var ErrNoDefaultInterface = errors.New("no default interface found") func DefaultInterface() (iface string, err error) { routes, err := netlink.RouteGet(net.IPv4bcast) if err != nil { return } if len(routes) >= 1 { link, err := netlink.LinkByIndex(routes[0].LinkIndex) if err != nil { return "", err } return link.Attrs().Name, nil } err = ErrNoDefaultInterface return } type Network struct { sync.Mutex m map[string]struct{} iface string label string link netlink.Link } func NewNetwork(iface string) (n *Network, err error) { return NewNetworkWithLabel(iface, "") } func NewNetworkWithLabel(iface, label string) (n *Network, err error) { if iface == "" { iface, err = DefaultInterface() if err != nil { return } } link, err := netlink.LinkByName(iface) if err != nil { return } n = &Network{ m: make(map[string]struct{}), iface: iface, label: label, link: link, } return } func (n *Network) Interface() string { return n.iface } func (n *Network) HasIP(a *netlink.Addr) bool { addrs, err := netlink.AddrList(n.link, 0) if err != nil { return false } for _, addr := range addrs { if addr.Equal(*a) { return true } } return false } func (n *Network) AddIP(cidr string) error { n.Lock() defer n.Unlock() addr, err := netlink.ParseAddr(cidr) if err != nil { return err } if n.HasIP(addr) { return nil } if n.label != "" { addr.Label = n.iface + ":" + n.label } err = netlink.AddrReplace(n.link, addr) if err != nil { return err } n.m[cidr] = struct{}{} return ARPSendGratuitous(cidr, n.iface) } func (n *Network) DeleteIP(cidr string) error { n.Lock() defer n.Unlock() addr, err := netlink.ParseAddr(cidr) if err != nil { return err } if !n.HasIP(addr) { return nil } err = netlink.AddrDel(n.link, addr) if err != nil { return err } delete(n.m, cidr) return nil } func (n *Network) GetIPs() (cidrs []string) { n.Lock() defer n.Unlock() cidrs = make([]string, len(n.m)) c := 0 for k := range n.m { cidrs[c] = k c++ } return }