mirror of
https://github.com/netbirdio/netbird.git
synced 2024-11-25 17:43:38 +01:00
2eeed55c18
This PR adds supports for the WireGuard userspace implementation using Bind interface from wireguard-go. The newly introduced ICEBind struct implements Bind with UDPMux-based structs from pion/ice to handle hole punching using ICE. The core implementation was taken from StdBind of wireguard-go. The result is a single WireGuard port that is used for host and server reflexive candidates. Relay candidates are still handled separately and will be integrated in the following PRs. ICEBind checks the incoming packets for being STUN or WireGuard ones and routes them to UDPMux (to handle hole punching) or to WireGuard respectively.
152 lines
3.2 KiB
Go
152 lines
3.2 KiB
Go
package iface
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
|
|
"github.com/pion/transport/v2"
|
|
log "github.com/sirupsen/logrus"
|
|
"golang.zx2c4.com/wireguard/device"
|
|
"golang.zx2c4.com/wireguard/ipc"
|
|
"golang.zx2c4.com/wireguard/tun"
|
|
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
|
|
|
"github.com/netbirdio/netbird/iface/bind"
|
|
)
|
|
|
|
type tunDevice struct {
|
|
name string
|
|
address WGAddress
|
|
netInterface NetInterface
|
|
iceBind *bind.ICEBind
|
|
mtu int
|
|
uapi net.Listener
|
|
close chan struct{}
|
|
}
|
|
|
|
func newTunDevice(name string, address WGAddress, mtu int, transportNet transport.Net) *tunDevice {
|
|
return &tunDevice{
|
|
name: name,
|
|
address: address,
|
|
mtu: mtu,
|
|
iceBind: bind.NewICEBind(transportNet),
|
|
close: make(chan struct{}),
|
|
}
|
|
}
|
|
|
|
func (c *tunDevice) Create() error {
|
|
var err error
|
|
c.netInterface, err = c.createWithUserspace()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return c.assignAddr()
|
|
}
|
|
|
|
// createWithUserspace Creates a new Wireguard interface, using wireguard-go userspace implementation
|
|
func (c *tunDevice) createWithUserspace() (NetInterface, error) {
|
|
tunIface, err := tun.CreateTUN(c.name, c.mtu)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// We need to create a wireguard-go device and listen to configuration requests
|
|
tunDev := device.NewDevice(tunIface, c.iceBind, device.NewLogger(device.LogLevelSilent, "[netbird] "))
|
|
err = tunDev.Up()
|
|
if err != nil {
|
|
_ = tunIface.Close()
|
|
return nil, err
|
|
}
|
|
|
|
c.uapi, err = c.getUAPI(c.name)
|
|
if err != nil {
|
|
_ = tunIface.Close()
|
|
return nil, err
|
|
}
|
|
|
|
go func() {
|
|
for {
|
|
select {
|
|
case <-c.close:
|
|
log.Debugf("exit uapi.Accept()")
|
|
return
|
|
default:
|
|
}
|
|
uapiConn, uapiErr := c.uapi.Accept()
|
|
if uapiErr != nil {
|
|
log.Traceln("uapi Accept failed with error: ", uapiErr)
|
|
continue
|
|
}
|
|
go func() {
|
|
tunDev.IpcHandle(uapiConn)
|
|
log.Debugf("exit tunDevice.IpcHandle")
|
|
}()
|
|
}
|
|
}()
|
|
|
|
log.Debugln("UAPI listener started")
|
|
return tunIface, nil
|
|
}
|
|
|
|
func (c *tunDevice) UpdateAddr(address WGAddress) error {
|
|
c.address = address
|
|
return c.assignAddr()
|
|
}
|
|
|
|
func (c *tunDevice) WgAddress() WGAddress {
|
|
return c.address
|
|
}
|
|
|
|
func (c *tunDevice) DeviceName() string {
|
|
return c.name
|
|
}
|
|
|
|
func (c *tunDevice) Close() error {
|
|
select {
|
|
case c.close <- struct{}{}:
|
|
default:
|
|
}
|
|
|
|
var err1, err2 error
|
|
if c.netInterface != nil {
|
|
err1 = c.netInterface.Close()
|
|
}
|
|
|
|
if c.uapi != nil {
|
|
err2 = c.uapi.Close()
|
|
}
|
|
|
|
if err1 != nil {
|
|
return err1
|
|
}
|
|
|
|
return err2
|
|
}
|
|
|
|
func (c *tunDevice) getInterfaceGUIDString() (string, error) {
|
|
if c.netInterface == nil {
|
|
return "", fmt.Errorf("interface has not been initialized yet")
|
|
}
|
|
windowsDevice := c.netInterface.(*tun.NativeTun)
|
|
luid := winipcfg.LUID(windowsDevice.LUID())
|
|
guid, err := luid.GUID()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return guid.String(), nil
|
|
}
|
|
|
|
// assignAddr Adds IP address to the tunnel interface and network route based on the range provided
|
|
func (c *tunDevice) assignAddr() error {
|
|
tunDev := c.netInterface.(*tun.NativeTun)
|
|
luid := winipcfg.LUID(tunDev.LUID())
|
|
log.Debugf("adding address %s to interface: %s", c.address.IP, c.name)
|
|
return luid.SetIPAddresses([]net.IPNet{{c.address.IP, c.address.Network.Mask}})
|
|
}
|
|
|
|
// getUAPI returns a Listener
|
|
func (c *tunDevice) getUAPI(iface string) (net.Listener, error) {
|
|
return ipc.UAPIListen(iface)
|
|
}
|