netbird/iface/tun_linux.go
Zoltan Papp 7ebe58f20a
Feature/permanent dns (#967)
* Add DNS list argument for mobile client

* Write testable code

Many places are checked the wgInterface != nil condition.
It is doing it just because to avoid the real wgInterface creation for tests.
Instead of this involve a wgInterface interface what is moc-able.

* Refactor the DNS server internal code structure

With the fake resolver has been involved several
if-else statement and generated some unused
variables to distinguish the listener and fake
resolver solutions at running time. With this
commit the fake resolver and listener based
solution has been moved into two separated
structure. Name of this layer is the 'service'.
With this modification the unit test looks
simpler and open the option to add new logic for
the permanent DNS service usage for mobile
systems.



* Remove is running check in test

We can not ensure the state well so remove this
check. The test will fail if the server is not
running well.
2023-07-14 21:56:22 +02:00

149 lines
3.0 KiB
Go

//go:build linux && !android
package iface
import (
"fmt"
"os"
log "github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
)
func (c *tunDevice) Create() error {
if WireGuardModuleIsLoaded() {
log.Infof("create tun interface with kernel WireGuard support: %s", c.DeviceName())
return c.createWithKernel()
}
if !tunModuleIsLoaded() {
return fmt.Errorf("couldn't check or load tun module")
}
log.Infof("create tun interface with userspace WireGuard support: %s", c.DeviceName())
var err error
c.netInterface, err = c.createWithUserspace()
if err != nil {
return err
}
return c.assignAddr()
}
// createWithKernel Creates a new WireGuard interface using kernel WireGuard module.
// Works for Linux and offers much better network performance
func (c *tunDevice) createWithKernel() error {
link := newWGLink(c.name)
// check if interface exists
l, err := netlink.LinkByName(c.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", c.name)
err = netlink.LinkAdd(link)
if os.IsExist(err) {
log.Infof("interface %s already exists. Will reuse.", c.name)
} else if err != nil {
return err
}
c.netInterface = link
err = c.assignAddr()
if err != nil {
return err
}
// todo do a discovery
log.Debugf("setting MTU: %d interface: %s", c.mtu, c.name)
err = netlink.LinkSetMTU(link, c.mtu)
if err != nil {
log.Errorf("error setting MTU on interface: %s", c.name)
return err
}
log.Debugf("bringing up interface: %s", c.name)
err = netlink.LinkSetUp(link)
if err != nil {
log.Errorf("error bringing up interface: %s", c.name)
return err
}
return nil
}
// assignAddr Adds IP address to the tunnel interface
func (c *tunDevice) assignAddr() error {
link := newWGLink(c.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", c.address.String(), c.name)
addr, _ := netlink.ParseAddr(c.address.String())
err = netlink.AddrAdd(link, addr)
if os.IsExist(err) {
log.Infof("interface %s already has the address: %s", c.name, c.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)
}