netbird/iface/iface_linux.go

168 lines
3.4 KiB
Go

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(WgInterfaceDefault)
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 {
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)
}
}