package iface import ( "fmt" log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" "golang.zx2c4.com/wireguard/wgctrl" "os" ) // Create Creates a new Wireguard interface, sets a given IP and brings it up. // Will reuse an existing one. func Create(iface string, address string) error { if WireguardModExists() { log.Debug("using kernel Wireguard module") return CreateWithKernel(iface, address) } else { return CreateWithUserspace(iface, address) } } // CreateWithKernel Creates a new Wireguard interface using kernel Wireguard module. // Works for Linux and offers much better network performance func CreateWithKernel(iface string, address string) error { attrs := netlink.NewLinkAttrs() attrs.Name = iface link := wgLink{ attrs: &attrs, } // check if interface exists l, err := netlink.LinkByName(iface) if err != nil { switch err.(type) { case netlink.LinkNotFoundError: break default: return err } } // remove if interface exists if l != nil { err = netlink.LinkDel(&link) if err != nil { return err } } log.Debugf("adding device: %s", iface) err = netlink.LinkAdd(&link) if os.IsExist(err) { log.Infof("interface %s already exists. Will reuse.", iface) } else if err != nil { return err } err = assignAddr(address, iface) if err != nil { return err } // todo do a discovery log.Debugf("setting MTU: %d interface: %s", defaultMTU, iface) err = netlink.LinkSetMTU(&link, defaultMTU) if err != nil { log.Errorf("error setting MTU on interface: %s", iface) return err } log.Debugf("bringing up interface: %s", iface) err = netlink.LinkSetUp(&link) if err != nil { log.Errorf("error bringing up interface: %s", iface) return err } return nil } // assignAddr Adds IP address to the tunnel interface func assignAddr(address, name string) error { var err error attrs := netlink.NewLinkAttrs() attrs.Name = name link := wgLink{ attrs: &attrs, } //delete existing addresses list, err := netlink.AddrList(&link, 0) if err != nil { return err } if len(list) > 0 { for _, a := range list { err = netlink.AddrDel(&link, &a) if err != nil { return err } } } log.Debugf("adding address %s to interface: %s", address, attrs.Name) addr, _ := netlink.ParseAddr(address) err = netlink.AddrAdd(&link, addr) if os.IsExist(err) { log.Infof("interface %s already has the address: %s", attrs.Name, address) } else if err != nil { return err } // On linux, the link must be brought up err = netlink.LinkSetUp(&link) return err } type wgLink struct { attrs *netlink.LinkAttrs } // Attrs returns the Wireguard's default attributes func (w *wgLink) Attrs() *netlink.LinkAttrs { return w.attrs } // Type returns the interface type func (w *wgLink) Type() string { return "wireguard" } // Closes the tunnel interface func Close() error { if tunIface != nil { return CloseWithUserspace() } else { var iface = "" wg, err := wgctrl.New() if err != nil { return err } defer wg.Close() devList, err := wg.Devices() if err != nil { return err } for _, wgDev := range devList { // todo check after move the WgPort constant to the client if wgDev.ListenPort == WgPort { iface = wgDev.Name break } } if iface == "" { return fmt.Errorf("Wireguard Interface not found") } attrs := netlink.NewLinkAttrs() attrs.Name = iface link := wgLink{ attrs: &attrs, } return netlink.LinkDel(&link) } }