netbird/iface/iface_linux.go
Maycon Santos e4ad6174ca
Improve module load (#470)
* Add additional check for needed kernel modules

* Check if wireguard and tun modules are loaded

If modules are loaded return true, otherwise attempt to load them

* fix state check

* Add module function tests

* Add test execution in container

* run client package tests on docker

* add package comment to new file

* force entrypoint

* add --privileged flag

* clean only if tables where created

* run from within the directories
2022-09-15 01:26:11 +05:00

148 lines
3.0 KiB
Go

package iface
import (
"fmt"
log "github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
"os"
)
type NativeLink struct {
Link *netlink.Link
}
// Create creates a new Wireguard interface, sets a given IP and brings it up.
// Will reuse an existing one.
func (w *WGIface) Create() error {
w.mu.Lock()
defer w.mu.Unlock()
if WireguardModuleIsLoaded() {
log.Info("using kernel WireGuard")
return w.createWithKernel()
} else {
if !tunModuleIsLoaded() {
return fmt.Errorf("couldn't check or load tun module")
}
log.Info("using userspace WireGuard")
return w.createWithUserspace()
}
}
// createWithKernel Creates a new Wireguard interface using kernel Wireguard module.
// Works for Linux and offers much better network performance
func (w *WGIface) createWithKernel() error {
link := newWGLink(w.Name)
// check if interface exists
l, err := netlink.LinkByName(w.Name)
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", w.Name)
err = netlink.LinkAdd(link)
if os.IsExist(err) {
log.Infof("interface %s already exists. Will reuse.", w.Name)
} else if err != nil {
return err
}
w.Interface = link
err = w.assignAddr()
if err != nil {
return err
}
// todo do a discovery
log.Debugf("setting MTU: %d interface: %s", w.MTU, w.Name)
err = netlink.LinkSetMTU(link, w.MTU)
if err != nil {
log.Errorf("error setting MTU on interface: %s", w.Name)
return err
}
log.Debugf("bringing up interface: %s", w.Name)
err = netlink.LinkSetUp(link)
if err != nil {
log.Errorf("error bringing up interface: %s", w.Name)
return err
}
return nil
}
// assignAddr Adds IP address to the tunnel interface
func (w *WGIface) assignAddr() error {
link := newWGLink(w.Name)
//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", w.Address.String(), w.Name)
addr, _ := netlink.ParseAddr(w.Address.String())
err = netlink.AddrAdd(link, addr)
if os.IsExist(err) {
log.Infof("interface %s already has the address: %s", w.Name, w.Address.String())
} 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
}
func newWGLink(name string) *wgLink {
attrs := netlink.NewLinkAttrs()
attrs.Name = name
return &wgLink{
attrs: &attrs,
}
}
// Attrs returns the Wireguard's default attributes
func (l *wgLink) Attrs() *netlink.LinkAttrs {
return l.attrs
}
// Type returns the interface type
func (l *wgLink) Type() string {
return "wireguard"
}
// Close deletes the link interface
func (l *wgLink) Close() error {
return netlink.LinkDel(l)
}