mirror of
https://github.com/netbirdio/netbird.git
synced 2025-03-05 02:11:13 +01:00
Netstack poc
This commit is contained in:
parent
2d1dfa3ae7
commit
cec4232860
2
go.mod
2
go.mod
@ -109,6 +109,7 @@ require (
|
|||||||
github.com/go-stack/stack v1.8.0 // indirect
|
github.com/go-stack/stack v1.8.0 // indirect
|
||||||
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff // indirect
|
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
|
github.com/google/btree v1.0.1 // indirect
|
||||||
github.com/google/s2a-go v0.1.4 // indirect
|
github.com/google/s2a-go v0.1.4 // indirect
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
|
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
|
||||||
github.com/googleapis/gax-go/v2 v2.10.0 // indirect
|
github.com/googleapis/gax-go/v2 v2.10.0 // indirect
|
||||||
@ -154,6 +155,7 @@ require (
|
|||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||||
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 // indirect
|
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
gvisor.dev/gvisor v0.0.0-20221203005347-703fd9b7fbc0 // indirect
|
||||||
honnef.co/go/tools v0.2.2 // indirect
|
honnef.co/go/tools v0.2.2 // indirect
|
||||||
k8s.io/apimachinery v0.23.5 // indirect
|
k8s.io/apimachinery v0.23.5 // indirect
|
||||||
)
|
)
|
||||||
|
@ -20,10 +20,10 @@ func NewWGIFace(iFaceName string, address string, mtu int, tunAdapter TunAdapter
|
|||||||
return wgIFace, err
|
return wgIFace, err
|
||||||
}
|
}
|
||||||
|
|
||||||
wgIFace.tun = newTunDevice(iFaceName, wgAddress, mtu, transportNet)
|
tun := newTunDevice(iFaceName, wgAddress, mtu, transportNet)
|
||||||
|
wgIFace.tun = tun
|
||||||
wgIFace.configurer = newWGConfigurer(iFaceName)
|
wgIFace.configurer = newWGConfigurer(tun)
|
||||||
wgIFace.userspaceBind = !WireGuardModuleIsLoaded()
|
wgIFace.userspaceBind = true
|
||||||
return wgIFace, nil
|
return wgIFace, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
package iface
|
package iface
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@ -11,14 +10,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (c *tunDevice) Create() error {
|
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())
|
log.Infof("create tun interface with userspace WireGuard support: %s", c.DeviceName())
|
||||||
var err error
|
var err error
|
||||||
c.netInterface, err = c.createWithUserspace()
|
c.netInterface, err = c.createWithUserspace()
|
||||||
@ -27,7 +18,6 @@ func (c *tunDevice) Create() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return c.assignAddr()
|
return c.assignAddr()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// createWithKernel Creates a new WireGuard interface using kernel WireGuard module.
|
// createWithKernel Creates a new WireGuard interface using kernel WireGuard module.
|
||||||
@ -90,34 +80,7 @@ func (c *tunDevice) createWithKernel() error {
|
|||||||
|
|
||||||
// assignAddr Adds IP address to the tunnel interface
|
// assignAddr Adds IP address to the tunnel interface
|
||||||
func (c *tunDevice) assignAddr() error {
|
func (c *tunDevice) assignAddr() error {
|
||||||
link := newWGLink(c.name)
|
return nil
|
||||||
|
|
||||||
//delete existing addresses
|
|
||||||
list, err := netlink.AddrList(link, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if len(list) > 0 {
|
|
||||||
for _, a := range list {
|
|
||||||
addr := a
|
|
||||||
err = netlink.AddrDel(link, &addr)
|
|
||||||
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 {
|
type wgLink struct {
|
||||||
|
@ -4,16 +4,17 @@ package iface
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/pion/transport/v2"
|
"github.com/pion/transport/v2"
|
||||||
"golang.zx2c4.com/wireguard/ipc"
|
"golang.zx2c4.com/wireguard/ipc"
|
||||||
|
"golang.zx2c4.com/wireguard/tun/netstack"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/iface/bind"
|
"github.com/netbirdio/netbird/iface/bind"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"golang.zx2c4.com/wireguard/device"
|
"golang.zx2c4.com/wireguard/device"
|
||||||
"golang.zx2c4.com/wireguard/tun"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type tunDevice struct {
|
type tunDevice struct {
|
||||||
@ -25,6 +26,7 @@ type tunDevice struct {
|
|||||||
uapi net.Listener
|
uapi net.Listener
|
||||||
wrapper *DeviceWrapper
|
wrapper *DeviceWrapper
|
||||||
close chan struct{}
|
close chan struct{}
|
||||||
|
tunDevice *device.Device
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTunDevice(name string, address WGAddress, mtu int, transportNet transport.Net) *tunDevice {
|
func newTunDevice(name string, address WGAddress, mtu int, transportNet transport.Net) *tunDevice {
|
||||||
@ -46,6 +48,10 @@ func (c *tunDevice) WgAddress() WGAddress {
|
|||||||
return c.address
|
return c.address
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *tunDevice) Device() *device.Device {
|
||||||
|
return t.tunDevice
|
||||||
|
}
|
||||||
|
|
||||||
func (c *tunDevice) DeviceName() string {
|
func (c *tunDevice) DeviceName() string {
|
||||||
return c.name
|
return c.name
|
||||||
}
|
}
|
||||||
@ -87,8 +93,12 @@ func (c *tunDevice) Close() error {
|
|||||||
|
|
||||||
// createWithUserspace Creates a new Wireguard interface, using wireguard-go userspace implementation
|
// createWithUserspace Creates a new Wireguard interface, using wireguard-go userspace implementation
|
||||||
func (c *tunDevice) createWithUserspace() (NetInterface, error) {
|
func (c *tunDevice) createWithUserspace() (NetInterface, error) {
|
||||||
tunIface, err := tun.CreateTUN(c.name, c.mtu)
|
tunIface, _, err := netstack.CreateNetTUN(
|
||||||
|
[]netip.Addr{netip.MustParseAddr(c.address.IP.String())},
|
||||||
|
[]netip.Addr{netip.MustParseAddr("8.8.8.8")},
|
||||||
|
1420)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Debugf("createWithUserspace failed with error: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.wrapper = newDeviceWrapper(tunIface)
|
c.wrapper = newDeviceWrapper(tunIface)
|
||||||
@ -101,37 +111,12 @@ func (c *tunDevice) createWithUserspace() (NetInterface, error) {
|
|||||||
)
|
)
|
||||||
err = tunDev.Up()
|
err = tunDev.Up()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Debugf("tunDev.Up() failed with error: %v", err)
|
||||||
_ = tunIface.Close()
|
_ = tunIface.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.uapi, err = c.getUAPI(c.name)
|
c.tunDevice = tunDev
|
||||||
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
|
return tunIface, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,205 +0,0 @@
|
|||||||
//go:build !android
|
|
||||||
|
|
||||||
package iface
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
"golang.zx2c4.com/wireguard/wgctrl"
|
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
|
||||||
)
|
|
||||||
|
|
||||||
type wGConfigurer struct {
|
|
||||||
deviceName string
|
|
||||||
}
|
|
||||||
|
|
||||||
func newWGConfigurer(deviceName string) wGConfigurer {
|
|
||||||
return wGConfigurer{
|
|
||||||
deviceName: deviceName,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *wGConfigurer) configureInterface(privateKey string, port int) error {
|
|
||||||
log.Debugf("adding Wireguard private key")
|
|
||||||
key, err := wgtypes.ParseKey(privateKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fwmark := 0
|
|
||||||
config := wgtypes.Config{
|
|
||||||
PrivateKey: &key,
|
|
||||||
ReplacePeers: true,
|
|
||||||
FirewallMark: &fwmark,
|
|
||||||
ListenPort: &port,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = c.configure(config)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf(`received error "%w" while configuring interface %s with port %d`, err, c.deviceName, port)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *wGConfigurer) updatePeer(peerKey string, allowedIps string, keepAlive time.Duration, endpoint *net.UDPAddr, preSharedKey *wgtypes.Key) error {
|
|
||||||
//parse allowed ips
|
|
||||||
_, ipNet, err := net.ParseCIDR(allowedIps)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
peerKeyParsed, err := wgtypes.ParseKey(peerKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
peer := wgtypes.PeerConfig{
|
|
||||||
PublicKey: peerKeyParsed,
|
|
||||||
ReplaceAllowedIPs: true,
|
|
||||||
AllowedIPs: []net.IPNet{*ipNet},
|
|
||||||
PersistentKeepaliveInterval: &keepAlive,
|
|
||||||
PresharedKey: preSharedKey,
|
|
||||||
Endpoint: endpoint,
|
|
||||||
}
|
|
||||||
|
|
||||||
config := wgtypes.Config{
|
|
||||||
Peers: []wgtypes.PeerConfig{peer},
|
|
||||||
}
|
|
||||||
err = c.configure(config)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf(`received error "%w" while updating peer on interface %s with settings: allowed ips %s, endpoint %s`, err, c.deviceName, allowedIps, endpoint.String())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *wGConfigurer) removePeer(peerKey string) error {
|
|
||||||
peerKeyParsed, err := wgtypes.ParseKey(peerKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
peer := wgtypes.PeerConfig{
|
|
||||||
PublicKey: peerKeyParsed,
|
|
||||||
Remove: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
config := wgtypes.Config{
|
|
||||||
Peers: []wgtypes.PeerConfig{peer},
|
|
||||||
}
|
|
||||||
err = c.configure(config)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf(`received error "%w" while removing peer %s from interface %s`, err, peerKey, c.deviceName)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *wGConfigurer) addAllowedIP(peerKey string, allowedIP string) error {
|
|
||||||
_, ipNet, err := net.ParseCIDR(allowedIP)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
peerKeyParsed, err := wgtypes.ParseKey(peerKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
peer := wgtypes.PeerConfig{
|
|
||||||
PublicKey: peerKeyParsed,
|
|
||||||
UpdateOnly: true,
|
|
||||||
ReplaceAllowedIPs: false,
|
|
||||||
AllowedIPs: []net.IPNet{*ipNet},
|
|
||||||
}
|
|
||||||
|
|
||||||
config := wgtypes.Config{
|
|
||||||
Peers: []wgtypes.PeerConfig{peer},
|
|
||||||
}
|
|
||||||
err = c.configure(config)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf(`received error "%w" while adding allowed Ip to peer on interface %s with settings: allowed ips %s`, err, c.deviceName, allowedIP)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *wGConfigurer) removeAllowedIP(peerKey string, allowedIP string) error {
|
|
||||||
_, ipNet, err := net.ParseCIDR(allowedIP)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
peerKeyParsed, err := wgtypes.ParseKey(peerKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
existingPeer, err := c.getPeer(c.deviceName, peerKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
newAllowedIPs := existingPeer.AllowedIPs
|
|
||||||
|
|
||||||
for i, existingAllowedIP := range existingPeer.AllowedIPs {
|
|
||||||
if existingAllowedIP.String() == ipNet.String() {
|
|
||||||
newAllowedIPs = append(existingPeer.AllowedIPs[:i], existingPeer.AllowedIPs[i+1:]...) //nolint:gocritic
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
peer := wgtypes.PeerConfig{
|
|
||||||
PublicKey: peerKeyParsed,
|
|
||||||
UpdateOnly: true,
|
|
||||||
ReplaceAllowedIPs: true,
|
|
||||||
AllowedIPs: newAllowedIPs,
|
|
||||||
}
|
|
||||||
|
|
||||||
config := wgtypes.Config{
|
|
||||||
Peers: []wgtypes.PeerConfig{peer},
|
|
||||||
}
|
|
||||||
err = c.configure(config)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf(`received error "%w" while removing allowed IP from peer on interface %s with settings: allowed ips %s`, err, c.deviceName, allowedIP)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *wGConfigurer) getPeer(ifaceName, peerPubKey string) (wgtypes.Peer, error) {
|
|
||||||
wg, err := wgctrl.New()
|
|
||||||
if err != nil {
|
|
||||||
return wgtypes.Peer{}, err
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
err = wg.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("got error while closing wgctl: %v", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
wgDevice, err := wg.Device(ifaceName)
|
|
||||||
if err != nil {
|
|
||||||
return wgtypes.Peer{}, err
|
|
||||||
}
|
|
||||||
for _, peer := range wgDevice.Peers {
|
|
||||||
if peer.PublicKey.String() == peerPubKey {
|
|
||||||
return peer, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return wgtypes.Peer{}, fmt.Errorf("peer not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *wGConfigurer) configure(config wgtypes.Config) error {
|
|
||||||
wg, err := wgctrl.New()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer wg.Close()
|
|
||||||
|
|
||||||
// validate if device with name exists
|
|
||||||
_, err = wg.Device(c.deviceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Tracef("got Wireguard device %s", c.deviceName)
|
|
||||||
|
|
||||||
return wg.ConfigureDevice(c.deviceName, config)
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user