From 923cabda9aecb0652ade5000ca03a45da57ad962 Mon Sep 17 00:00:00 2001 From: braginini Date: Thu, 17 Jun 2021 14:27:33 +0200 Subject: [PATCH 01/14] feature: initial implementation of avoiding local proxy if peers are in the same net --- connection/connection.go | 14 ++++++++++++-- connection/wgproxy.go | 9 +++++++++ iface/iface.go | 3 +++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/connection/connection.go b/connection/connection.go index 67387571cfd..44161df54c3 100644 --- a/connection/connection.go +++ b/connection/connection.go @@ -5,6 +5,7 @@ import ( "fmt" ice "github.com/pion/ice/v2" log "github.com/sirupsen/logrus" + "github.com/wiretrustee/wiretrustee/iface" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" "sync" "time" @@ -144,10 +145,20 @@ func (conn *Connection) Open(timeout time.Duration) error { return err } - err = conn.wgProxy.Start(remoteConn) + pair, err := conn.agent.GetSelectedCandidatePair() if err != nil { return err } + // in case the remote peer is in the local network we don't need a Wireguard proxy, direct communication is possible. + if pair.Local.Type() == ice.CandidateTypeHost && pair.Remote.Type() == ice.CandidateTypeHost { + log.Debugf("remote peer %s is in the local network with an address %s", conn.Config.RemoteWgKey.String(), pair.Remote.Address()) + err = conn.wgProxy.StartLocal(fmt.Sprintf("%s:%d", pair.Remote.Address(), iface.WgPort)) + } else { + err = conn.wgProxy.Start(remoteConn) + if err != nil { + return err + } + } log.Infof("opened connection to peer %s", conn.Config.RemoteWgKey.String()) case <-time.After(timeout): @@ -298,7 +309,6 @@ func (conn *Connection) listenOnConnectionStateChanges() error { } log.Infof("will connect to peer %s via a selected connnection candidate pair %s", conn.Config.RemoteWgKey.String(), pair) } else if state == ice.ConnectionStateDisconnected || state == ice.ConnectionStateFailed { - // todo do we really wanna have a connection restart within connection itself? Think of moving it outside err := conn.Close() if err != nil { log.Warnf("error while closing connection to peer %s -> %s", conn.Config.RemoteWgKey.String(), err.Error()) diff --git a/connection/wgproxy.go b/connection/wgproxy.go index 8eae1d111b4..489b421cb66 100644 --- a/connection/wgproxy.go +++ b/connection/wgproxy.go @@ -42,6 +42,15 @@ func (p *WgProxy) Close() error { return nil } +func (p *WgProxy) StartLocal(host string) error { + err := iface.UpdatePeer(p.iface, p.remoteKey, p.allowedIps, DefaultWgKeepAlive, host) + if err != nil { + log.Errorf("error while configuring Wireguard peer [%s] %s", p.remoteKey, err.Error()) + return err + } + return nil +} + // Start starts a new proxy using the ICE connection func (p *WgProxy) Start(remoteConn *ice.Conn) error { diff --git a/iface/iface.go b/iface/iface.go index cb51e9ffdd3..5909aaeaf23 100644 --- a/iface/iface.go +++ b/iface/iface.go @@ -14,6 +14,7 @@ import ( const ( defaultMTU = 1280 + WgPort = 51820 ) // Saves tun device object - is it required? @@ -85,10 +86,12 @@ func Configure(iface string, privateKey string) error { return err } fwmark := 0 + p := WgPort cfg := wgtypes.Config{ PrivateKey: &key, ReplacePeers: false, FirewallMark: &fwmark, + ListenPort: &p, } err = wg.ConfigureDevice(iface, cfg) if err != nil { From e41fdedd5bfd92c7d4663d488b230da52804ddb3 Mon Sep 17 00:00:00 2001 From: braginini Date: Thu, 17 Jun 2021 21:31:53 +0200 Subject: [PATCH 02/14] feature: enable ice mDNS --- connection/connection.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/connection/connection.go b/connection/connection.go index 44161df54c3..69ff2a58a12 100644 --- a/connection/connection.go +++ b/connection/connection.go @@ -94,8 +94,9 @@ func (conn *Connection) Open(timeout time.Duration) error { // create an ice.Agent that will be responsible for negotiating and establishing actual peer-to-peer connection a, err := ice.NewAgent(&ice.AgentConfig{ - NetworkTypes: []ice.NetworkType{ice.NetworkTypeUDP4}, - Urls: conn.Config.StunTurnURLS, + MulticastDNSMode: ice.MulticastDNSModeQueryAndGather, + NetworkTypes: []ice.NetworkType{ice.NetworkTypeUDP4}, + Urls: conn.Config.StunTurnURLS, InterfaceFilter: func(s string) bool { if conn.Config.iFaceBlackList == nil { return true From aa854c58999be5b0d82bfb6b8112913ef174bc4a Mon Sep 17 00:00:00 2001 From: mlsmaycon Date: Fri, 18 Jun 2021 13:01:43 +0200 Subject: [PATCH 03/14] add linux native wg interface --- connection/connection.go | 6 +- iface/iface.go | 7 +- iface/iface_configuration.go | 207 +++++++++++++++++++++++++++++++++++ iface/iface_linux.go | 60 ++++++++-- 4 files changed, 262 insertions(+), 18 deletions(-) create mode 100644 iface/iface_configuration.go diff --git a/connection/connection.go b/connection/connection.go index 69ff2a58a12..d64131384a2 100644 --- a/connection/connection.go +++ b/connection/connection.go @@ -94,9 +94,9 @@ func (conn *Connection) Open(timeout time.Duration) error { // create an ice.Agent that will be responsible for negotiating and establishing actual peer-to-peer connection a, err := ice.NewAgent(&ice.AgentConfig{ - MulticastDNSMode: ice.MulticastDNSModeQueryAndGather, - NetworkTypes: []ice.NetworkType{ice.NetworkTypeUDP4}, - Urls: conn.Config.StunTurnURLS, + // MulticastDNSMode: ice.MulticastDNSModeQueryAndGather, + NetworkTypes: []ice.NetworkType{ice.NetworkTypeUDP4}, + Urls: conn.Config.StunTurnURLS, InterfaceFilter: func(s string) bool { if conn.Config.iFaceBlackList == nil { return true diff --git a/iface/iface.go b/iface/iface.go index 5909aaeaf23..d0d185f121f 100644 --- a/iface/iface.go +++ b/iface/iface.go @@ -1,15 +1,12 @@ +// +build !linux + package iface import ( - "net" - "time" - log "github.com/sirupsen/logrus" "golang.zx2c4.com/wireguard/conn" "golang.zx2c4.com/wireguard/device" "golang.zx2c4.com/wireguard/tun" - "golang.zx2c4.com/wireguard/wgctrl" - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) const ( diff --git a/iface/iface_configuration.go b/iface/iface_configuration.go new file mode 100644 index 00000000000..8f56bd4ced4 --- /dev/null +++ b/iface/iface_configuration.go @@ -0,0 +1,207 @@ +package iface + +import ( + "net" + "time" + + log "github.com/sirupsen/logrus" + "golang.zx2c4.com/wireguard/wgctrl" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" +) + +const ( + defaultMTU = 1280 +) + +// ConfigureWithKeyGen Extends the functionality of Configure(iface string, privateKey string) by generating a new Wireguard private key +func ConfigureWithKeyGen(iface string) (*wgtypes.Key, error) { + key, err := wgtypes.GeneratePrivateKey() + if err != nil { + return nil, err + } + return &key, Configure(iface, key.String()) +} + +// Configure configures a Wireguard interface +// The interface must exist before calling this method (e.g. call interface.Create() before) +func Configure(iface string, privateKey string) error { + + log.Debugf("configuring Wireguard interface %s", iface) + wg, err := wgctrl.New() + if err != nil { + return err + } + defer wg.Close() + + log.Debugf("adding Wireguard private key") + key, err := wgtypes.ParseKey(privateKey) + if err != nil { + return err + } + fwmark := 0 + cfg := wgtypes.Config{ + PrivateKey: &key, + ReplacePeers: false, + FirewallMark: &fwmark, + } + err = wg.ConfigureDevice(iface, cfg) + if err != nil { + return err + } + + return nil +} + +// GetListenPort returns the listening port of the Wireguard endpoint +func GetListenPort(iface string) (*int, error) { + log.Debugf("getting Wireguard listen port of interface %s", iface) + + //discover Wireguard current configuration + wg, err := wgctrl.New() + if err != nil { + return nil, err + } + defer wg.Close() + + d, err := wg.Device(iface) + if err != nil { + return nil, err + } + log.Debugf("got Wireguard device listen port %s, %d", iface, &d.ListenPort) + + return &d.ListenPort, nil +} + +// UpdateListenPort updates a Wireguard interface listen port +func UpdateListenPort(iface string, newPort int) error { + log.Debugf("updating Wireguard listen port of interface %s, new port %d", iface, newPort) + + //discover Wireguard current configuration + wg, err := wgctrl.New() + if err != nil { + return err + } + defer wg.Close() + + _, err = wg.Device(iface) + if err != nil { + return err + } + log.Debugf("got Wireguard device %s", iface) + + config := wgtypes.Config{ + ListenPort: &newPort, + ReplacePeers: false, + } + err = wg.ConfigureDevice(iface, config) + if err != nil { + return err + } + + log.Debugf("updated Wireguard listen port of interface %s, new port %d", iface, newPort) + + return nil +} + +// UpdatePeer updates existing Wireguard Peer or creates a new one if doesn't exist +// Endpoint is optional +func UpdatePeer(iface string, peerKey string, allowedIps string, keepAlive time.Duration, endpoint string) error { + + log.Debugf("updating interface %s peer %s: endpoint %s ", iface, peerKey, endpoint) + + wg, err := wgctrl.New() + if err != nil { + return err + } + defer wg.Close() + + _, err = wg.Device(iface) + if err != nil { + return err + } + log.Debugf("got Wireguard device %s", iface) + + //parse allowed ips + _, ipNet, err := net.ParseCIDR(allowedIps) + if err != nil { + return err + } + + peerKeyParsed, err := wgtypes.ParseKey(peerKey) + if err != nil { + return err + } + peers := make([]wgtypes.PeerConfig, 0) + peer := wgtypes.PeerConfig{ + PublicKey: peerKeyParsed, + ReplaceAllowedIPs: true, + AllowedIPs: []net.IPNet{*ipNet}, + PersistentKeepaliveInterval: &keepAlive, + } + peers = append(peers, peer) + + config := wgtypes.Config{ + ReplacePeers: false, + Peers: peers, + } + err = wg.ConfigureDevice(iface, config) + if err != nil { + return err + } + + if endpoint != "" { + return UpdatePeerEndpoint(iface, peerKey, endpoint) + } + + return nil +} + +// UpdatePeerEndpoint updates a Wireguard interface Peer with the new endpoint +// Used when NAT hole punching was successful and an update of the remote peer endpoint is required +func UpdatePeerEndpoint(iface string, peerKey string, newEndpoint string) error { + + log.Debugf("updating peer %s endpoint %s ", peerKey, newEndpoint) + + wg, err := wgctrl.New() + if err != nil { + return err + } + defer wg.Close() + + _, err = wg.Device(iface) + if err != nil { + return err + } + log.Debugf("got Wireguard device %s", iface) + + peerAddr, err := net.ResolveUDPAddr("udp4", newEndpoint) + if err != nil { + return err + } + + log.Debugf("parsed peer endpoint [%s]", peerAddr.String()) + + peerKeyParsed, err := wgtypes.ParseKey(peerKey) + if err != nil { + return err + } + peers := make([]wgtypes.PeerConfig, 0) + peer := wgtypes.PeerConfig{ + PublicKey: peerKeyParsed, + ReplaceAllowedIPs: false, + UpdateOnly: true, + Endpoint: peerAddr, + } + peers = append(peers, peer) + + config := wgtypes.Config{ + ReplacePeers: false, + Peers: peers, + } + err = wg.ConfigureDevice(iface, config) + if err != nil { + return err + } + + return nil +} diff --git a/iface/iface_linux.go b/iface/iface_linux.go index 346ac5a0a39..120d67954ff 100644 --- a/iface/iface_linux.go +++ b/iface/iface_linux.go @@ -3,24 +3,64 @@ package iface import ( log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" - "golang.zx2c4.com/wireguard/tun" - "os" ) -//const ( -// interfacePrefix = "wg" -//) - -// assignAddr Adds IP address to the tunnel interface -func assignAddr(address string, tunDevice tun.Device) error { - var err error +// 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 { attrs := netlink.NewLinkAttrs() - attrs.Name, err = tunDevice.Name() + attrs.Name = iface + + link := wgLink{ + attrs: &attrs, + } + + 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 + } + + log.Debugf("adding address %s to interface: %s", address, iface) + addr, _ := netlink.ParseAddr(address) + err = netlink.AddrAdd(&link, addr) + if os.IsExist(err) { + log.Infof("interface %s already has the address: %s", iface, address) + } else if err != nil { + return err + } + err = assignAddr(address, iface) if err != nil { return err } + // todo do a discovery + log.Debugf("setting MTU: %s", 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, } From 021092800be628100336e7d8313f9408033d37cf Mon Sep 17 00:00:00 2001 From: braginini Date: Fri, 18 Jun 2021 13:10:32 +0200 Subject: [PATCH 04/14] fix: extract constants from iface to iface_configuration --- iface/iface.go | 5 ----- iface/iface_configuration.go | 1 + 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/iface/iface.go b/iface/iface.go index d0d185f121f..b58f4629c8d 100644 --- a/iface/iface.go +++ b/iface/iface.go @@ -9,11 +9,6 @@ import ( "golang.zx2c4.com/wireguard/tun" ) -const ( - defaultMTU = 1280 - WgPort = 51820 -) - // Saves tun device object - is it required? var tunIface tun.Device diff --git a/iface/iface_configuration.go b/iface/iface_configuration.go index 8f56bd4ced4..c17d4662960 100644 --- a/iface/iface_configuration.go +++ b/iface/iface_configuration.go @@ -11,6 +11,7 @@ import ( const ( defaultMTU = 1280 + WgPort = 51820 ) // ConfigureWithKeyGen Extends the functionality of Configure(iface string, privateKey string) by generating a new Wireguard private key From 8dfccfc8006b4612747bc6017c16b7c191055d50 Mon Sep 17 00:00:00 2001 From: braginini Date: Fri, 18 Jun 2021 13:22:56 +0200 Subject: [PATCH 05/14] refactor: remove unused code --- iface/iface.go | 195 ----------------------------------- iface/iface_configuration.go | 2 + 2 files changed, 2 insertions(+), 195 deletions(-) diff --git a/iface/iface.go b/iface/iface.go index b58f4629c8d..d33a2a82989 100644 --- a/iface/iface.go +++ b/iface/iface.go @@ -51,198 +51,3 @@ func Create(iface string, address string) error { } return nil } - -// ConfigureWithKeyGen Extends the functionality of Configure(iface string, privateKey string) by generating a new Wireguard private key -func ConfigureWithKeyGen(iface string) (*wgtypes.Key, error) { - key, err := wgtypes.GeneratePrivateKey() - if err != nil { - return nil, err - } - return &key, Configure(iface, key.String()) -} - -// Configure configures a Wireguard interface -// The interface must exist before calling this method (e.g. call interface.Create() before) -func Configure(iface string, privateKey string) error { - - log.Debugf("configuring Wireguard interface %s", iface) - wg, err := wgctrl.New() - if err != nil { - return err - } - defer wg.Close() - - log.Debugf("adding Wireguard private key") - key, err := wgtypes.ParseKey(privateKey) - if err != nil { - return err - } - fwmark := 0 - p := WgPort - cfg := wgtypes.Config{ - PrivateKey: &key, - ReplacePeers: false, - FirewallMark: &fwmark, - ListenPort: &p, - } - err = wg.ConfigureDevice(iface, cfg) - if err != nil { - return err - } - - return nil -} - -// GetListenPort returns the listening port of the Wireguard endpoint -func GetListenPort(iface string) (*int, error) { - log.Debugf("getting Wireguard listen port of interface %s", iface) - - //discover Wireguard current configuration - wg, err := wgctrl.New() - if err != nil { - return nil, err - } - defer wg.Close() - - d, err := wg.Device(iface) - if err != nil { - return nil, err - } - log.Debugf("got Wireguard device listen port %s, %d", iface, &d.ListenPort) - - return &d.ListenPort, nil -} - -// UpdateListenPort updates a Wireguard interface listen port -func UpdateListenPort(iface string, newPort int) error { - log.Debugf("updating Wireguard listen port of interface %s, new port %d", iface, newPort) - - //discover Wireguard current configuration - wg, err := wgctrl.New() - if err != nil { - return err - } - defer wg.Close() - - _, err = wg.Device(iface) - if err != nil { - return err - } - log.Debugf("got Wireguard device %s", iface) - - config := wgtypes.Config{ - ListenPort: &newPort, - ReplacePeers: false, - } - err = wg.ConfigureDevice(iface, config) - if err != nil { - return err - } - - log.Debugf("updated Wireguard listen port of interface %s, new port %d", iface, newPort) - - return nil -} - -// UpdatePeer updates existing Wireguard Peer or creates a new one if doesn't exist -// Endpoint is optional -func UpdatePeer(iface string, peerKey string, allowedIps string, keepAlive time.Duration, endpoint string) error { - - log.Debugf("updating interface %s peer %s: endpoint %s ", iface, peerKey, endpoint) - - wg, err := wgctrl.New() - if err != nil { - return err - } - defer wg.Close() - - _, err = wg.Device(iface) - if err != nil { - return err - } - log.Debugf("got Wireguard device %s", iface) - - //parse allowed ips - _, ipNet, err := net.ParseCIDR(allowedIps) - if err != nil { - return err - } - - peerKeyParsed, err := wgtypes.ParseKey(peerKey) - if err != nil { - return err - } - peers := make([]wgtypes.PeerConfig, 0) - peer := wgtypes.PeerConfig{ - PublicKey: peerKeyParsed, - ReplaceAllowedIPs: true, - AllowedIPs: []net.IPNet{*ipNet}, - PersistentKeepaliveInterval: &keepAlive, - } - peers = append(peers, peer) - - config := wgtypes.Config{ - ReplacePeers: false, - Peers: peers, - } - err = wg.ConfigureDevice(iface, config) - if err != nil { - return err - } - - if endpoint != "" { - return UpdatePeerEndpoint(iface, peerKey, endpoint) - } - - return nil -} - -// UpdatePeerEndpoint updates a Wireguard interface Peer with the new endpoint -// Used when NAT hole punching was successful and an update of the remote peer endpoint is required -func UpdatePeerEndpoint(iface string, peerKey string, newEndpoint string) error { - - log.Debugf("updating peer %s endpoint %s ", peerKey, newEndpoint) - - wg, err := wgctrl.New() - if err != nil { - return err - } - defer wg.Close() - - _, err = wg.Device(iface) - if err != nil { - return err - } - log.Debugf("got Wireguard device %s", iface) - - peerAddr, err := net.ResolveUDPAddr("udp4", newEndpoint) - if err != nil { - return err - } - - log.Debugf("parsed peer endpoint [%s]", peerAddr.String()) - - peerKeyParsed, err := wgtypes.ParseKey(peerKey) - if err != nil { - return err - } - peers := make([]wgtypes.PeerConfig, 0) - peer := wgtypes.PeerConfig{ - PublicKey: peerKeyParsed, - ReplaceAllowedIPs: false, - UpdateOnly: true, - Endpoint: peerAddr, - } - peers = append(peers, peer) - - config := wgtypes.Config{ - ReplacePeers: false, - Peers: peers, - } - err = wg.ConfigureDevice(iface, config) - if err != nil { - return err - } - - return nil -} diff --git a/iface/iface_configuration.go b/iface/iface_configuration.go index c17d4662960..d83abb25b5e 100644 --- a/iface/iface_configuration.go +++ b/iface/iface_configuration.go @@ -40,10 +40,12 @@ func Configure(iface string, privateKey string) error { return err } fwmark := 0 + p := WgPort cfg := wgtypes.Config{ PrivateKey: &key, ReplacePeers: false, FirewallMark: &fwmark, + ListenPort: &p, } err = wg.ConfigureDevice(iface, cfg) if err != nil { From dd72a01ecfab62d94e108b4c1fc107c5a26e4373 Mon Sep 17 00:00:00 2001 From: braginini Date: Tue, 22 Jun 2021 14:38:28 +0200 Subject: [PATCH 06/14] feature: add check of Wireguard kernel module existence (Linux only) --- go.mod | 1 + iface/mod.go | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 iface/mod.go diff --git a/go.mod b/go.mod index 1b3a90f855f..50e4a32ca36 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/vishvananda/netlink v1.1.0 github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf + golang.org/x/sys v0.0.0-20210510120138-977fb7262007 golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210506160403-92e472f520a5 golang.zx2c4.com/wireguard/windows v0.3.14 diff --git a/iface/mod.go b/iface/mod.go new file mode 100644 index 00000000000..0b59f3d9a6f --- /dev/null +++ b/iface/mod.go @@ -0,0 +1,140 @@ +package iface + +// Holds logic to check existence of Wireguard kernel module +// Copied from https://github.com/paultag/go-modprobe + +import ( + "debug/elf" + "fmt" + "golang.org/x/sys/unix" + "os" + "path/filepath" + "strings" +) + +var ( + // get the root directory for the kernel modules. If this line panics, + // it's because getModuleRoot has failed to get the uname of the running + // kernel (likely a non-POSIX system, but maybe a broken kernel?) + moduleRoot = getModuleRoot() +) + +// Get the module root (/lib/modules/$(uname -r)/) +func getModuleRoot() string { + uname := unix.Utsname{} + if err := unix.Uname(&uname); err != nil { + panic(err) + } + + i := 0 + for ; uname.Release[i] != 0; i++ { + } + + return filepath.Join( + "/lib/modules", + string(uname.Release[:i]), + ) +} + +// Name will, given a file descriptor to a Kernel Module (.ko file), parse the +// binary to get the module name. For instance, given a handle to the file at +// `kernel/drivers/usb/gadget/legacy/g_ether.ko`, return `g_ether`. +func Name(file *os.File) (string, error) { + f, err := elf.NewFile(file) + if err != nil { + return "", err + } + + syms, err := f.Symbols() + if err != nil { + return "", err + } + + for _, sym := range syms { + if strings.Compare(sym.Name, "__this_module") == 0 { + section := f.Sections[sym.Section] + data, err := section.Data() + if err != nil { + return "", err + } + + if len(data) < 25 { + return "", fmt.Errorf("modprobe: data is short, __this_module is '%s'", data) + } + + data = data[24:] + i := 0 + for ; data[i] != 0x00; i++ { + } + return string(data[:i]), nil + } + } + + return "", fmt.Errorf("No name found. Is this a .ko or just an ELF?") +} + +// Open every single kernel module under the root, and parse the ELF headers to +// extract the module name. +func elfMap(root string) (map[string]string, error) { + ret := map[string]string{} + + err := filepath.Walk( + root, + func(path string, info os.FileInfo, err error) error { + if !info.Mode().IsRegular() { + return nil + } + fd, err := os.Open(path) + if err != nil { + return err + } + defer fd.Close() + name, err := Name(fd) + if err != nil { + /* For now, let's just ignore that and avoid adding to it */ + return nil + } + + ret[name] = path + return nil + }) + + if err != nil { + return nil, err + } + + return ret, nil +} + +// Open every single kernel module under the kernel module directory +// (/lib/modules/$(uname -r)/), and parse the ELF headers to extract the +// module name. +func generateMap() (map[string]string, error) { + return elfMap(moduleRoot) +} + +// WireguardModExists returns true if Wireguard kernel module exists. +func WireguardModExists() bool { + _, err := resolveModName("wireguard") + if err != nil { + return false + } + + return true +} + +// resolveModName will, given a module name (such as `wireguard`) return an absolute +// path to the .ko that provides that module. +func resolveModName(name string) (string, error) { + paths, err := generateMap() + if err != nil { + return "", err + } + + fsPath := paths[name] + if !strings.HasPrefix(fsPath, moduleRoot) { + return "", fmt.Errorf("module isn't in the module directory") + } + + return fsPath, nil +} From 4216cd2986b4cd88e1f9514ec83324af6e17df5f Mon Sep 17 00:00:00 2001 From: braginini Date: Wed, 23 Jun 2021 16:11:54 +0200 Subject: [PATCH 07/14] feature: add feature to determine when to run wireguard userspace implementation or native one (linux) --- iface/iface.go | 46 +-------------------- iface/iface_configuration.go | 46 +++++++++++++++++++++ iface/iface_darwin.go | 4 +- iface/iface_linux.go | 80 +++++++++++++++++++----------------- iface/iface_windows.go | 4 +- 5 files changed, 93 insertions(+), 87 deletions(-) diff --git a/iface/iface.go b/iface/iface.go index d33a2a82989..38beba6faca 100644 --- a/iface/iface.go +++ b/iface/iface.go @@ -2,52 +2,8 @@ package iface -import ( - log "github.com/sirupsen/logrus" - "golang.zx2c4.com/wireguard/conn" - "golang.zx2c4.com/wireguard/device" - "golang.zx2c4.com/wireguard/tun" -) - -// Saves tun device object - is it required? -var tunIface tun.Device - // 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 { - var err error - tunIface, err = tun.CreateTUN(iface, defaultMTU) - if err != nil { - return err - } - - // We need to create a wireguard-go device and listen to configuration requests - tunDevice := device.NewDevice(tunIface, conn.NewDefaultBind(), device.NewLogger(device.LogLevelSilent, "[wiretrustee] ")) - err = tunDevice.Up() - if err != nil { - return err - } - uapi, err := getUAPI(iface) - if err != nil { - return err - } - - go func() { - for { - uapiConn, err := uapi.Accept() - if err != nil { - log.Debugln(err) - return - } - go tunDevice.IpcHandle(uapiConn) - } - }() - - log.Debugln("UAPI listener started") - - err = assignAddr(address, tunIface) - if err != nil { - return err - } - return nil + return CreateInUserspace(iface, address) } diff --git a/iface/iface_configuration.go b/iface/iface_configuration.go index d83abb25b5e..f611a855366 100644 --- a/iface/iface_configuration.go +++ b/iface/iface_configuration.go @@ -1,6 +1,9 @@ package iface import ( + "golang.zx2c4.com/wireguard/conn" + "golang.zx2c4.com/wireguard/device" + "golang.zx2c4.com/wireguard/tun" "net" "time" @@ -23,6 +26,49 @@ func ConfigureWithKeyGen(iface string) (*wgtypes.Key, error) { return &key, Configure(iface, key.String()) } +// CreateInUserspace Creates a new Wireguard interface, using wireguard-go userspace implementation +func CreateInUserspace(iface string, address string) error { + var err error + tunIface, err := tun.CreateTUN(iface, defaultMTU) + if err != nil { + return err + } + + // We need to create a wireguard-go device and listen to configuration requests + tunDevice := device.NewDevice(tunIface, conn.NewDefaultBind(), device.NewLogger(device.LogLevelSilent, "[wiretrustee] ")) + err = tunDevice.Up() + if err != nil { + return err + } + uapi, err := getUAPI(iface) + if err != nil { + return err + } + + go func() { + for { + uapiConn, err := uapi.Accept() + if err != nil { + log.Debugln(err) + return + } + go tunDevice.IpcHandle(uapiConn) + } + }() + + log.Debugln("UAPI listener started") + + ifaceName, err := tunIface.Name() + if err != nil { + return err + } + err = assignAddr(address, ifaceName) + if err != nil { + return err + } + return nil +} + // Configure configures a Wireguard interface // The interface must exist before calling this method (e.g. call interface.Create() before) func Configure(iface string, privateKey string) error { diff --git a/iface/iface_darwin.go b/iface/iface_darwin.go index aa963e25e56..0d07bff8907 100644 --- a/iface/iface_darwin.go +++ b/iface/iface_darwin.go @@ -2,7 +2,6 @@ package iface import ( log "github.com/sirupsen/logrus" - "golang.zx2c4.com/wireguard/tun" "net" "os/exec" "strings" @@ -13,8 +12,7 @@ import ( //) // assignAddr Adds IP address to the tunnel interface and network route based on the range provided -func assignAddr(address string, tunDevice tun.Device) error { - ifaceName, err := tunDevice.Name() +func assignAddr(address string, ifaceName string) error { ip := strings.Split(address, "/") cmd := exec.Command("ifconfig", ifaceName, "inet", address, ip[0]) if out, err := cmd.CombinedOutput(); err != nil { diff --git a/iface/iface_linux.go b/iface/iface_linux.go index 120d67954ff..283ec250526 100644 --- a/iface/iface_linux.go +++ b/iface/iface_linux.go @@ -9,50 +9,56 @@ import ( // 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 { - attrs := netlink.NewLinkAttrs() - attrs.Name = iface - link := wgLink{ - attrs: &attrs, - } + if WireguardModExists() { + attrs := netlink.NewLinkAttrs() + attrs.Name = iface - 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 - } + link := wgLink{ + attrs: &attrs, + } - log.Debugf("adding address %s to interface: %s", address, iface) - addr, _ := netlink.ParseAddr(address) - err = netlink.AddrAdd(&link, addr) - if os.IsExist(err) { - log.Infof("interface %s already has the address: %s", iface, address) - } else if err != nil { - return err - } - err = assignAddr(address, iface) - 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 + } - // todo do a discovery - log.Debugf("setting MTU: %s", iface) - err = netlink.LinkSetMTU(&link, defaultMTU) - if err != nil { - log.Errorf("error setting MTU on interface: %s", iface) - return err - } + log.Debugf("adding address %s to interface: %s", address, iface) + addr, _ := netlink.ParseAddr(address) + err = netlink.AddrAdd(&link, addr) + if os.IsExist(err) { + log.Infof("interface %s already has the address: %s", iface, address) + } else if err != nil { + return err + } + err = assignAddr(address, iface) + if err != nil { + 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 + // todo do a discovery + log.Debugf("setting MTU: %s", 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 + } else { + return CreateInUserspace(iface, address) } - return nil } // assignAddr Adds IP address to the tunnel interface diff --git a/iface/iface_windows.go b/iface/iface_windows.go index 9ce7aeafebb..601ecfa4a7a 100644 --- a/iface/iface_windows.go +++ b/iface/iface_windows.go @@ -9,8 +9,8 @@ import ( ) // assignAddr Adds IP address to the tunnel interface and network route based on the range provided -func assignAddr(address string, tunDevice tun.Device) error { - ifaceName, err := tunDevice.Name() +func assignAddr(address string, ifaceName string) error { + nativeTunDevice := tunDevice.(*tun.NativeTun) luid := winipcfg.LUID(nativeTunDevice.LUID()) From 0e313eec24b7124f4e6f7d4b97cb835977cf4f6a Mon Sep 17 00:00:00 2001 From: braginini Date: Wed, 23 Jun 2021 16:16:48 +0200 Subject: [PATCH 08/14] fix: mod.go build only for linux --- iface/mod.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iface/mod.go b/iface/mod.go index 0b59f3d9a6f..f020c3e13f3 100644 --- a/iface/mod.go +++ b/iface/mod.go @@ -1,3 +1,5 @@ +// +build linux + package iface // Holds logic to check existence of Wireguard kernel module From 561bd681d922767e814bdf0624895f734a648071 Mon Sep 17 00:00:00 2001 From: braginini Date: Thu, 24 Jun 2021 10:55:05 +0200 Subject: [PATCH 09/14] fix: golint errors --- connection/connection.go | 3 +++ iface/mod.go | 12 +++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/connection/connection.go b/connection/connection.go index d64131384a2..7a95c766dd5 100644 --- a/connection/connection.go +++ b/connection/connection.go @@ -154,6 +154,9 @@ func (conn *Connection) Open(timeout time.Duration) error { if pair.Local.Type() == ice.CandidateTypeHost && pair.Remote.Type() == ice.CandidateTypeHost { log.Debugf("remote peer %s is in the local network with an address %s", conn.Config.RemoteWgKey.String(), pair.Remote.Address()) err = conn.wgProxy.StartLocal(fmt.Sprintf("%s:%d", pair.Remote.Address(), iface.WgPort)) + if err != nil { + return err + } } else { err = conn.wgProxy.Start(remoteConn) if err != nil { diff --git a/iface/mod.go b/iface/mod.go index f020c3e13f3..dd3239daee6 100644 --- a/iface/mod.go +++ b/iface/mod.go @@ -83,6 +83,12 @@ func elfMap(root string) (map[string]string, error) { err := filepath.Walk( root, func(path string, info os.FileInfo, err error) error { + + if err != nil { + // skip broken files + return nil + } + if !info.Mode().IsRegular() { return nil } @@ -118,11 +124,7 @@ func generateMap() (map[string]string, error) { // WireguardModExists returns true if Wireguard kernel module exists. func WireguardModExists() bool { _, err := resolveModName("wireguard") - if err != nil { - return false - } - - return true + return err == nil } // resolveModName will, given a module name (such as `wireguard`) return an absolute From 729b16e599fbc500840588b0f32b8f0b63dd61e8 Mon Sep 17 00:00:00 2001 From: braginini Date: Thu, 24 Jun 2021 10:59:41 +0200 Subject: [PATCH 10/14] fix: windows iface build --- iface/iface_windows.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iface/iface_windows.go b/iface/iface_windows.go index 601ecfa4a7a..9c7ff25cd53 100644 --- a/iface/iface_windows.go +++ b/iface/iface_windows.go @@ -17,7 +17,7 @@ func assignAddr(address string, ifaceName string) error { ip, ipnet, _ := net.ParseCIDR(address) log.Debugf("adding address %s to interface: %s", address, ifaceName) - err = luid.SetIPAddresses([]net.IPNet{{ip, ipnet.Mask}}) + err := luid.SetIPAddresses([]net.IPNet{{ip, ipnet.Mask}}) if err != nil { return err } From f2ca2fc7c1a0ee39825e5a995a9a40a3f3029397 Mon Sep 17 00:00:00 2001 From: braginini Date: Thu, 24 Jun 2021 11:02:40 +0200 Subject: [PATCH 11/14] refactort: extract method to create Wireguard interface using kernel module --- iface/iface.go | 2 +- iface/iface_configuration.go | 4 +- iface/iface_linux.go | 96 +++++++++++++++++++----------------- 3 files changed, 54 insertions(+), 48 deletions(-) diff --git a/iface/iface.go b/iface/iface.go index 38beba6faca..830a2ae5236 100644 --- a/iface/iface.go +++ b/iface/iface.go @@ -5,5 +5,5 @@ package iface // 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 { - return CreateInUserspace(iface, address) + return CreateWithUserspace(iface, address) } diff --git a/iface/iface_configuration.go b/iface/iface_configuration.go index f611a855366..cb2a95ebf53 100644 --- a/iface/iface_configuration.go +++ b/iface/iface_configuration.go @@ -26,8 +26,8 @@ func ConfigureWithKeyGen(iface string) (*wgtypes.Key, error) { return &key, Configure(iface, key.String()) } -// CreateInUserspace Creates a new Wireguard interface, using wireguard-go userspace implementation -func CreateInUserspace(iface string, address string) error { +// CreateWithUserspace Creates a new Wireguard interface, using wireguard-go userspace implementation +func CreateWithUserspace(iface string, address string) error { var err error tunIface, err := tun.CreateTUN(iface, defaultMTU) if err != nil { diff --git a/iface/iface_linux.go b/iface/iface_linux.go index 283ec250526..5d63695fceb 100644 --- a/iface/iface_linux.go +++ b/iface/iface_linux.go @@ -11,56 +11,62 @@ import ( func Create(iface string, address string) error { if WireguardModExists() { - attrs := netlink.NewLinkAttrs() - attrs.Name = iface - - link := wgLink{ - attrs: &attrs, - } - - 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 - } - - log.Debugf("adding address %s to interface: %s", address, iface) - addr, _ := netlink.ParseAddr(address) - err = netlink.AddrAdd(&link, addr) - if os.IsExist(err) { - log.Infof("interface %s already has the address: %s", iface, address) - } else if err != nil { - return err - } - err = assignAddr(address, iface) - if err != nil { - return err - } - - // todo do a discovery - log.Debugf("setting MTU: %s", 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 + return CreateWithKernel(iface, address) } else { - return CreateInUserspace(iface, address) + 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, + } + + 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 + } + + log.Debugf("adding address %s to interface: %s", address, iface) + addr, _ := netlink.ParseAddr(address) + err = netlink.AddrAdd(&link, addr) + if os.IsExist(err) { + log.Infof("interface %s already has the address: %s", iface, address) + } else if err != nil { + return err + } + err = assignAddr(address, iface) + if err != nil { + return err + } + + // todo do a discovery + log.Debugf("setting MTU: %s", 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 From a40669270a2f60add2fce1e3dc8c1967542467bd Mon Sep 17 00:00:00 2001 From: braginini Date: Thu, 24 Jun 2021 11:46:33 +0200 Subject: [PATCH 12/14] refactor: rearrange iface package --- iface/iface.go | 256 ++++++++++++++++++++++++++++++++++- iface/iface_configuration.go | 256 ----------------------------------- iface/iface_darwin.go | 7 +- iface/iface_linux.go | 1 - iface/iface_windows.go | 7 +- 5 files changed, 260 insertions(+), 267 deletions(-) delete mode 100644 iface/iface_configuration.go diff --git a/iface/iface.go b/iface/iface.go index 830a2ae5236..5534cd6e4de 100644 --- a/iface/iface.go +++ b/iface/iface.go @@ -1,9 +1,253 @@ -// +build !linux - package iface -// 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 { - return CreateWithUserspace(iface, address) +import ( + log "github.com/sirupsen/logrus" + "golang.zx2c4.com/wireguard/conn" + "golang.zx2c4.com/wireguard/device" + "golang.zx2c4.com/wireguard/tun" + "golang.zx2c4.com/wireguard/wgctrl" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + "net" + "time" +) + +const ( + defaultMTU = 1280 + WgPort = 51820 +) + +var tunIface tun.Device + +// CreateWithUserspace Creates a new Wireguard interface, using wireguard-go userspace implementation +func CreateWithUserspace(iface string, address string) error { + var err error + tunIface, err = tun.CreateTUN(iface, defaultMTU) + if err != nil { + return err + } + + // We need to create a wireguard-go device and listen to configuration requests + tunDevice := device.NewDevice(tunIface, conn.NewDefaultBind(), device.NewLogger(device.LogLevelSilent, "[wiretrustee] ")) + err = tunDevice.Up() + if err != nil { + return err + } + uapi, err := getUAPI(iface) + if err != nil { + return err + } + + go func() { + for { + uapiConn, err := uapi.Accept() + if err != nil { + log.Debugln(err) + return + } + go tunDevice.IpcHandle(uapiConn) + } + }() + + log.Debugln("UAPI listener started") + + err = assignAddr(address, iface) + if err != nil { + return err + } + return nil +} + +// ConfigureWithKeyGen Extends the functionality of Configure(iface string, privateKey string) by generating a new Wireguard private key +func ConfigureWithKeyGen(iface string) (*wgtypes.Key, error) { + key, err := wgtypes.GeneratePrivateKey() + if err != nil { + return nil, err + } + return &key, Configure(iface, key.String()) +} + +// Configure configures a Wireguard interface +// The interface must exist before calling this method (e.g. call interface.Create() before) +func Configure(iface string, privateKey string) error { + + log.Debugf("configuring Wireguard interface %s", iface) + wg, err := wgctrl.New() + if err != nil { + return err + } + defer wg.Close() + + log.Debugf("adding Wireguard private key") + key, err := wgtypes.ParseKey(privateKey) + if err != nil { + return err + } + fwmark := 0 + p := WgPort + cfg := wgtypes.Config{ + PrivateKey: &key, + ReplacePeers: false, + FirewallMark: &fwmark, + ListenPort: &p, + } + err = wg.ConfigureDevice(iface, cfg) + if err != nil { + return err + } + + return nil +} + +// GetListenPort returns the listening port of the Wireguard endpoint +func GetListenPort(iface string) (*int, error) { + log.Debugf("getting Wireguard listen port of interface %s", iface) + + //discover Wireguard current configuration + wg, err := wgctrl.New() + if err != nil { + return nil, err + } + defer wg.Close() + + d, err := wg.Device(iface) + if err != nil { + return nil, err + } + log.Debugf("got Wireguard device listen port %s, %d", iface, &d.ListenPort) + + return &d.ListenPort, nil +} + +// UpdateListenPort updates a Wireguard interface listen port +func UpdateListenPort(iface string, newPort int) error { + log.Debugf("updating Wireguard listen port of interface %s, new port %d", iface, newPort) + + //discover Wireguard current configuration + wg, err := wgctrl.New() + if err != nil { + return err + } + defer wg.Close() + + _, err = wg.Device(iface) + if err != nil { + return err + } + log.Debugf("got Wireguard device %s", iface) + + config := wgtypes.Config{ + ListenPort: &newPort, + ReplacePeers: false, + } + err = wg.ConfigureDevice(iface, config) + if err != nil { + return err + } + + log.Debugf("updated Wireguard listen port of interface %s, new port %d", iface, newPort) + + return nil +} + +// UpdatePeer updates existing Wireguard Peer or creates a new one if doesn't exist +// Endpoint is optional +func UpdatePeer(iface string, peerKey string, allowedIps string, keepAlive time.Duration, endpoint string) error { + + log.Debugf("updating interface %s peer %s: endpoint %s ", iface, peerKey, endpoint) + + wg, err := wgctrl.New() + if err != nil { + return err + } + defer wg.Close() + + _, err = wg.Device(iface) + if err != nil { + return err + } + log.Debugf("got Wireguard device %s", iface) + + //parse allowed ips + _, ipNet, err := net.ParseCIDR(allowedIps) + if err != nil { + return err + } + + peerKeyParsed, err := wgtypes.ParseKey(peerKey) + if err != nil { + return err + } + peers := make([]wgtypes.PeerConfig, 0) + peer := wgtypes.PeerConfig{ + PublicKey: peerKeyParsed, + ReplaceAllowedIPs: true, + AllowedIPs: []net.IPNet{*ipNet}, + PersistentKeepaliveInterval: &keepAlive, + } + peers = append(peers, peer) + + config := wgtypes.Config{ + ReplacePeers: false, + Peers: peers, + } + err = wg.ConfigureDevice(iface, config) + if err != nil { + return err + } + + if endpoint != "" { + return UpdatePeerEndpoint(iface, peerKey, endpoint) + } + + return nil +} + +// UpdatePeerEndpoint updates a Wireguard interface Peer with the new endpoint +// Used when NAT hole punching was successful and an update of the remote peer endpoint is required +func UpdatePeerEndpoint(iface string, peerKey string, newEndpoint string) error { + + log.Debugf("updating peer %s endpoint %s ", peerKey, newEndpoint) + + wg, err := wgctrl.New() + if err != nil { + return err + } + defer wg.Close() + + _, err = wg.Device(iface) + if err != nil { + return err + } + log.Debugf("got Wireguard device %s", iface) + + peerAddr, err := net.ResolveUDPAddr("udp4", newEndpoint) + if err != nil { + return err + } + + log.Debugf("parsed peer endpoint [%s]", peerAddr.String()) + + peerKeyParsed, err := wgtypes.ParseKey(peerKey) + if err != nil { + return err + } + peers := make([]wgtypes.PeerConfig, 0) + peer := wgtypes.PeerConfig{ + PublicKey: peerKeyParsed, + ReplaceAllowedIPs: false, + UpdateOnly: true, + Endpoint: peerAddr, + } + peers = append(peers, peer) + + config := wgtypes.Config{ + ReplacePeers: false, + Peers: peers, + } + err = wg.ConfigureDevice(iface, config) + if err != nil { + return err + } + + return nil } diff --git a/iface/iface_configuration.go b/iface/iface_configuration.go deleted file mode 100644 index cb2a95ebf53..00000000000 --- a/iface/iface_configuration.go +++ /dev/null @@ -1,256 +0,0 @@ -package iface - -import ( - "golang.zx2c4.com/wireguard/conn" - "golang.zx2c4.com/wireguard/device" - "golang.zx2c4.com/wireguard/tun" - "net" - "time" - - log "github.com/sirupsen/logrus" - "golang.zx2c4.com/wireguard/wgctrl" - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" -) - -const ( - defaultMTU = 1280 - WgPort = 51820 -) - -// ConfigureWithKeyGen Extends the functionality of Configure(iface string, privateKey string) by generating a new Wireguard private key -func ConfigureWithKeyGen(iface string) (*wgtypes.Key, error) { - key, err := wgtypes.GeneratePrivateKey() - if err != nil { - return nil, err - } - return &key, Configure(iface, key.String()) -} - -// CreateWithUserspace Creates a new Wireguard interface, using wireguard-go userspace implementation -func CreateWithUserspace(iface string, address string) error { - var err error - tunIface, err := tun.CreateTUN(iface, defaultMTU) - if err != nil { - return err - } - - // We need to create a wireguard-go device and listen to configuration requests - tunDevice := device.NewDevice(tunIface, conn.NewDefaultBind(), device.NewLogger(device.LogLevelSilent, "[wiretrustee] ")) - err = tunDevice.Up() - if err != nil { - return err - } - uapi, err := getUAPI(iface) - if err != nil { - return err - } - - go func() { - for { - uapiConn, err := uapi.Accept() - if err != nil { - log.Debugln(err) - return - } - go tunDevice.IpcHandle(uapiConn) - } - }() - - log.Debugln("UAPI listener started") - - ifaceName, err := tunIface.Name() - if err != nil { - return err - } - err = assignAddr(address, ifaceName) - if err != nil { - return err - } - return nil -} - -// Configure configures a Wireguard interface -// The interface must exist before calling this method (e.g. call interface.Create() before) -func Configure(iface string, privateKey string) error { - - log.Debugf("configuring Wireguard interface %s", iface) - wg, err := wgctrl.New() - if err != nil { - return err - } - defer wg.Close() - - log.Debugf("adding Wireguard private key") - key, err := wgtypes.ParseKey(privateKey) - if err != nil { - return err - } - fwmark := 0 - p := WgPort - cfg := wgtypes.Config{ - PrivateKey: &key, - ReplacePeers: false, - FirewallMark: &fwmark, - ListenPort: &p, - } - err = wg.ConfigureDevice(iface, cfg) - if err != nil { - return err - } - - return nil -} - -// GetListenPort returns the listening port of the Wireguard endpoint -func GetListenPort(iface string) (*int, error) { - log.Debugf("getting Wireguard listen port of interface %s", iface) - - //discover Wireguard current configuration - wg, err := wgctrl.New() - if err != nil { - return nil, err - } - defer wg.Close() - - d, err := wg.Device(iface) - if err != nil { - return nil, err - } - log.Debugf("got Wireguard device listen port %s, %d", iface, &d.ListenPort) - - return &d.ListenPort, nil -} - -// UpdateListenPort updates a Wireguard interface listen port -func UpdateListenPort(iface string, newPort int) error { - log.Debugf("updating Wireguard listen port of interface %s, new port %d", iface, newPort) - - //discover Wireguard current configuration - wg, err := wgctrl.New() - if err != nil { - return err - } - defer wg.Close() - - _, err = wg.Device(iface) - if err != nil { - return err - } - log.Debugf("got Wireguard device %s", iface) - - config := wgtypes.Config{ - ListenPort: &newPort, - ReplacePeers: false, - } - err = wg.ConfigureDevice(iface, config) - if err != nil { - return err - } - - log.Debugf("updated Wireguard listen port of interface %s, new port %d", iface, newPort) - - return nil -} - -// UpdatePeer updates existing Wireguard Peer or creates a new one if doesn't exist -// Endpoint is optional -func UpdatePeer(iface string, peerKey string, allowedIps string, keepAlive time.Duration, endpoint string) error { - - log.Debugf("updating interface %s peer %s: endpoint %s ", iface, peerKey, endpoint) - - wg, err := wgctrl.New() - if err != nil { - return err - } - defer wg.Close() - - _, err = wg.Device(iface) - if err != nil { - return err - } - log.Debugf("got Wireguard device %s", iface) - - //parse allowed ips - _, ipNet, err := net.ParseCIDR(allowedIps) - if err != nil { - return err - } - - peerKeyParsed, err := wgtypes.ParseKey(peerKey) - if err != nil { - return err - } - peers := make([]wgtypes.PeerConfig, 0) - peer := wgtypes.PeerConfig{ - PublicKey: peerKeyParsed, - ReplaceAllowedIPs: true, - AllowedIPs: []net.IPNet{*ipNet}, - PersistentKeepaliveInterval: &keepAlive, - } - peers = append(peers, peer) - - config := wgtypes.Config{ - ReplacePeers: false, - Peers: peers, - } - err = wg.ConfigureDevice(iface, config) - if err != nil { - return err - } - - if endpoint != "" { - return UpdatePeerEndpoint(iface, peerKey, endpoint) - } - - return nil -} - -// UpdatePeerEndpoint updates a Wireguard interface Peer with the new endpoint -// Used when NAT hole punching was successful and an update of the remote peer endpoint is required -func UpdatePeerEndpoint(iface string, peerKey string, newEndpoint string) error { - - log.Debugf("updating peer %s endpoint %s ", peerKey, newEndpoint) - - wg, err := wgctrl.New() - if err != nil { - return err - } - defer wg.Close() - - _, err = wg.Device(iface) - if err != nil { - return err - } - log.Debugf("got Wireguard device %s", iface) - - peerAddr, err := net.ResolveUDPAddr("udp4", newEndpoint) - if err != nil { - return err - } - - log.Debugf("parsed peer endpoint [%s]", peerAddr.String()) - - peerKeyParsed, err := wgtypes.ParseKey(peerKey) - if err != nil { - return err - } - peers := make([]wgtypes.PeerConfig, 0) - peer := wgtypes.PeerConfig{ - PublicKey: peerKeyParsed, - ReplaceAllowedIPs: false, - UpdateOnly: true, - Endpoint: peerAddr, - } - peers = append(peers, peer) - - config := wgtypes.Config{ - ReplacePeers: false, - Peers: peers, - } - err = wg.ConfigureDevice(iface, config) - if err != nil { - return err - } - - return nil -} diff --git a/iface/iface_darwin.go b/iface/iface_darwin.go index 0d07bff8907..c3c86050b5f 100644 --- a/iface/iface_darwin.go +++ b/iface/iface_darwin.go @@ -7,9 +7,10 @@ import ( "strings" ) -//const ( -// interfacePrefix = "utun" -//) +// Create Creates a new Wireguard interface, sets a given IP and brings it up. +func Create(iface string, address string) error { + return CreateWithUserspace(iface, address) +} // assignAddr Adds IP address to the tunnel interface and network route based on the range provided func assignAddr(address string, ifaceName string) error { diff --git a/iface/iface_linux.go b/iface/iface_linux.go index 5d63695fceb..fd39aee459a 100644 --- a/iface/iface_linux.go +++ b/iface/iface_linux.go @@ -15,7 +15,6 @@ func Create(iface string, address string) error { } else { return CreateWithUserspace(iface, address) } - } // CreateWithKernel Creates a new Wireguard interface using kernel Wireguard module. diff --git a/iface/iface_windows.go b/iface/iface_windows.go index 9c7ff25cd53..46966b23d63 100644 --- a/iface/iface_windows.go +++ b/iface/iface_windows.go @@ -8,10 +8,15 @@ import ( "net" ) +// Create Creates a new Wireguard interface, sets a given IP and brings it up. +func Create(iface string, address string) error { + return CreateWithUserspace(iface, address) +} + // assignAddr Adds IP address to the tunnel interface and network route based on the range provided func assignAddr(address string, ifaceName string) error { - nativeTunDevice := tunDevice.(*tun.NativeTun) + nativeTunDevice := tunIface.(*tun.NativeTun) luid := winipcfg.LUID(nativeTunDevice.LUID()) ip, ipnet, _ := net.ParseCIDR(address) From dac865c61fea274a8e7f5776238bc55093698f23 Mon Sep 17 00:00:00 2001 From: braginini Date: Thu, 24 Jun 2021 12:49:14 +0200 Subject: [PATCH 13/14] chore: add log to detect a usage of the Wireguard kernel module --- iface/iface_linux.go | 1 + 1 file changed, 1 insertion(+) diff --git a/iface/iface_linux.go b/iface/iface_linux.go index fd39aee459a..86c670785b6 100644 --- a/iface/iface_linux.go +++ b/iface/iface_linux.go @@ -11,6 +11,7 @@ import ( func Create(iface string, address string) error { if WireguardModExists() { + log.Debug("using kernel Wireguard module") return CreateWithKernel(iface, address) } else { return CreateWithUserspace(iface, address) From 61a7f3013b21259c95af3ec7e4e9a9dce56965fb Mon Sep 17 00:00:00 2001 From: mlsmaycon Date: Thu, 24 Jun 2021 23:16:09 +0200 Subject: [PATCH 14/14] Rename Name function --- iface/mod.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iface/mod.go b/iface/mod.go index dd3239daee6..d3195b8085c 100644 --- a/iface/mod.go +++ b/iface/mod.go @@ -38,10 +38,10 @@ func getModuleRoot() string { ) } -// Name will, given a file descriptor to a Kernel Module (.ko file), parse the +// modName will, given a file descriptor to a Kernel Module (.ko file), parse the // binary to get the module name. For instance, given a handle to the file at // `kernel/drivers/usb/gadget/legacy/g_ether.ko`, return `g_ether`. -func Name(file *os.File) (string, error) { +func modName(file *os.File) (string, error) { f, err := elf.NewFile(file) if err != nil { return "", err @@ -97,7 +97,7 @@ func elfMap(root string) (map[string]string, error) { return err } defer fd.Close() - name, err := Name(fd) + name, err := modName(fd) if err != nil { /* For now, let's just ignore that and avoid adding to it */ return nil