diff --git a/.github/workflows/golang-test-build.yml b/.github/workflows/golang-test-build.yml index 680346ce9..f03da0d01 100644 --- a/.github/workflows/golang-test-build.yml +++ b/.github/workflows/golang-test-build.yml @@ -1,9 +1,5 @@ -on: - push: - branches: - - main - pull_request: name: Test Build On Platforms +on: push jobs: test_build: strategy: @@ -21,15 +17,15 @@ jobs: go-version: ${{ matrix.go-version }} - name: Cache Go modules - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + key: ${{ runner.os }}-go-test-${{ matrix.os }}-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - name: Install modules - run: go mod tidy + run: GOOS=${{ matrix.os }} go mod tidy - name: run build client run: GOOS=${{ matrix.os }} go build . diff --git a/.github/workflows/golang-test-darwin.yml b/.github/workflows/golang-test-darwin.yml new file mode 100644 index 000000000..d582c5e53 --- /dev/null +++ b/.github/workflows/golang-test-darwin.yml @@ -0,0 +1,29 @@ +name: Test Code Darwin +on: push +jobs: + test: + strategy: + matrix: + go-version: [1.17.x] + runs-on: macos-latest + steps: + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + - name: Checkout code + uses: actions/checkout@v2 + + - name: Cache Go modules + uses: actions/cache@v2 + with: + path: ~/go/pkg/mod + key: macos-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + macos-go- + + - name: Install modules + run: go mod tidy + + - name: Test + run: GOBIN=$(which go) && sudo --preserve-env=GOROOT $GOBIN test ./... \ No newline at end of file diff --git a/.github/workflows/golang-test.yml b/.github/workflows/golang-test-linux.yml similarity index 72% rename from .github/workflows/golang-test.yml rename to .github/workflows/golang-test-linux.yml index 6ddb7f12b..6351b307b 100644 --- a/.github/workflows/golang-test.yml +++ b/.github/workflows/golang-test-linux.yml @@ -1,9 +1,5 @@ -on: - push: - branches: - - main - pull_request: -name: Test Code +name: Test Code Linux +on: push jobs: test: strategy: @@ -27,7 +23,20 @@ jobs: $(whoami) soft nofile 65535 $(whoami) hard nofile 65535 EOF + + - name: Cache Go modules + uses: actions/cache@v2 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + - name: Checkout code uses: actions/checkout@v2 + + - name: Install modules + run: go mod tidy + - name: Test - run: GOBIN=$(which go) && sudo --preserve-env=GOROOT $GOBIN test -p 1 ./... \ No newline at end of file + run: GOBIN=$(which go) && sudo --preserve-env=GOROOT $GOBIN test ./... \ No newline at end of file diff --git a/.github/workflows/golang-test-windows.yml b/.github/workflows/golang-test-windows.yml new file mode 100644 index 000000000..39542b27b --- /dev/null +++ b/.github/workflows/golang-test-windows.yml @@ -0,0 +1,51 @@ +name: Test Code Windows +on: push +jobs: + pre: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - run: bash -x wireguard_nt.sh + working-directory: client + + - uses: actions/upload-artifact@v2 + with: + name: syso + path: client/*.syso + retention-days: 1 + + test: + needs: pre + strategy: + matrix: + go-version: [1.17.x] + runs-on: windows-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + + - uses: actions/cache@v2 + with: + path: | + %LocalAppData%\go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - uses: actions/download-artifact@v2 + with: + name: syso + path: iface\ + + - name: Install modules + run: go mod tidy + + - name: Test build + run: go test -tags=load_wgnt_from_rsrc ./... diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index d302dc89f..c242080ef 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -1,9 +1,5 @@ name: golangci-lint -on: - push: - branches: - - main - pull_request: +on: push jobs: golangci: name: lint diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0a5f7dc41..442f3a4df 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,6 +14,10 @@ jobs: uses: actions/checkout@v2 with: fetch-depth: 0 # It is required for GoReleaser to work properly + + - name: Generate syso with DLL + run: bash -x wireguard_nt.sh + working-directory: client - name: Set up Go uses: actions/setup-go@v2 diff --git a/.gitignore b/.gitignore index 53a8f902b..e94ed3084 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ dist/ conf.json http-cmds.sh infrastructure_files/management.json -infrastructure_files/docker-compose.yml \ No newline at end of file +infrastructure_files/docker-compose.yml +*.syso \ No newline at end of file diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 49faae1f4..054311520 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -26,7 +26,7 @@ builds: - -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser mod_timestamp: '{{ .CommitTimestamp }}' tags: - - load_wintun_from_rsrc + - load_wgnt_from_rsrc - id: wiretrustee-mgmt dir: management diff --git a/client/cmd/login_test.go b/client/cmd/login_test.go index c951a880f..0016f568c 100644 --- a/client/cmd/login_test.go +++ b/client/cmd/login_test.go @@ -60,7 +60,7 @@ func TestLogin(t *testing.T) { } if actualConf.WgIface != iface.WgInterfaceDefault { - t.Errorf("expected WgIface %s got %s", iface.WgInterfaceDefault, actualConf.WgIface) + t.Errorf("expected WgIfaceName %s got %s", iface.WgInterfaceDefault, actualConf.WgIface) } if len(actualConf.PrivateKey) == 0 { diff --git a/client/cmd/up.go b/client/cmd/up.go index c9fc95f33..b1e6d27de 100644 --- a/client/cmd/up.go +++ b/client/cmd/up.go @@ -64,7 +64,7 @@ func createEngineConfig(key wgtypes.Key, config *internal.Config, peerConfig *mg } engineConf := &internal.EngineConfig{ - WgIface: config.WgIface, + WgIfaceName: config.WgIface, WgAddr: peerConfig.Address, IFaceBlackList: iFaceBlackList, WgPrivateKey: key, diff --git a/client/cmd/up_test.go b/client/cmd/up_test.go index 4ecb030a3..97543599d 100644 --- a/client/cmd/up_test.go +++ b/client/cmd/up_test.go @@ -36,7 +36,7 @@ func TestUp_Start(t *testing.T) { func TestUp(t *testing.T) { - defer iface.Close("wt0") + //defer iface.Close("wt0") tempDir := t.TempDir() confPath := tempDir + "/config.json" @@ -53,6 +53,8 @@ func TestUp(t *testing.T) { "A2C8E62B-38F5-4553-B31E-DD66C696CEBB", "--management-url", mgmtURL.String(), + "--log-level", + "debug", "--log-file", "console", }) @@ -63,20 +65,23 @@ func TestUp(t *testing.T) { } }() - exists := false - for start := time.Now(); time.Since(start) < 15*time.Second; { + timeout := 15 * time.Second + timeoutChannel := time.After(timeout) + for { + select { + case <-timeoutChannel: + t.Fatalf("expected wireguard interface %s to be created before %s", iface.WgInterfaceDefault, timeout.String()) + default: + } e, err := iface.Exists(iface.WgInterfaceDefault) if err != nil { continue } + if err != nil { + continue + } if *e { - exists = true break } - - } - - if !exists { - t.Errorf("expected wireguard interface %s to be created", iface.WgInterfaceDefault) } } diff --git a/client/internal/engine.go b/client/internal/engine.go index 603eb4481..4b10f51b5 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -21,6 +21,7 @@ import ( // PeerConnectionTimeoutMax is a timeout of an initial connection attempt to a remote peer. // E.g. this peer will wait PeerConnectionTimeoutMax for the remote peer to respond, if not successful then it will retry the connection attempt. +// Todo pass timeout at EnginConfig const PeerConnectionTimeoutMax = 45000 //ms const PeerConnectionTimeoutMin = 30000 //ms @@ -28,8 +29,8 @@ const WgPort = 51820 // EngineConfig is a config for the Engine type EngineConfig struct { - WgPort int - WgIface string + WgPort int + WgIfaceName string // WgAddr is a Wireguard local address (Wiretrustee Network IP) WgAddr string // WgPrivateKey is a Wireguard private key of our peer (it MUST never leave the machine) @@ -61,6 +62,8 @@ type Engine struct { cancel context.CancelFunc ctx context.Context + + wgInterface iface.WGIface } // Peer is an instance of the Connection Peer @@ -93,11 +96,13 @@ func (e *Engine) Stop() error { return err } - log.Debugf("removing Wiretrustee interface %s", e.config.WgIface) - err = iface.Close(e.config.WgIface) - if err != nil { - log.Errorf("failed closing Wiretrustee interface %s %v", e.config.WgIface, err) - return err + log.Debugf("removing Wiretrustee interface %s", e.config.WgIfaceName) + if e.wgInterface.Interface != nil { + err = e.wgInterface.Close() + if err != nil { + log.Errorf("failed closing Wiretrustee interface %s %v", e.config.WgIfaceName, err) + return err + } } log.Infof("stopped Wiretrustee Engine") @@ -112,19 +117,26 @@ func (e *Engine) Start() error { e.syncMsgMux.Lock() defer e.syncMsgMux.Unlock() - wgIface := e.config.WgIface + wgIfaceName := e.config.WgIfaceName wgAddr := e.config.WgAddr myPrivateKey := e.config.WgPrivateKey + var err error - err := iface.Create(wgIface, wgAddr) + e.wgInterface, err = iface.NewWGIface(wgIfaceName, wgAddr, iface.DefaultMTU) if err != nil { - log.Errorf("failed creating interface %s: [%s]", wgIface, err.Error()) + log.Errorf("failed creating wireguard interface instance %s: [%s]", wgIfaceName, err.Error()) return err } - err = iface.Configure(wgIface, myPrivateKey.String(), e.config.WgPort) + err = e.wgInterface.Create() if err != nil { - log.Errorf("failed configuring Wireguard interface [%s]: %s", wgIface, err.Error()) + log.Errorf("failed creating tunnel interface %s: [%s]", wgIfaceName, err.Error()) + return err + } + + err = e.wgInterface.Configure(myPrivateKey.String(), e.config.WgPort) + if err != nil { + log.Errorf("failed configuring Wireguard interface [%s]: %s", wgIfaceName, err.Error()) return err } @@ -399,7 +411,7 @@ func (e Engine) createPeerConn(pubKey string, allowedIPs string) (*peer.Conn, er proxyConfig := proxy.Config{ RemoteKey: pubKey, WgListenAddr: fmt.Sprintf("127.0.0.1:%d", e.config.WgPort), - WgInterface: e.config.WgIface, + WgInterface: e.wgInterface, AllowedIps: allowedIPs, PreSharedKey: e.config.PreSharedKey, } diff --git a/client/internal/engine_test.go b/client/internal/engine_test.go index 7ceb284e3..dae0e4851 100644 --- a/client/internal/engine_test.go +++ b/client/internal/engine_test.go @@ -48,7 +48,11 @@ func TestEngine_MultiplePeers(t *testing.T) { t.Fatal(err) } defer func() { - os.Remove(filepath.Join(dir, "store.json")) //nolint + err = os.Remove(filepath.Join(dir, "store.json")) //nolint + if err != nil { + t.Fatal(err) + return + } }() ctx, cancel := context.WithCancel(context.Background()) @@ -102,25 +106,43 @@ func TestEngine_MultiplePeers(t *testing.T) { // wait until all have been created and started wg.Wait() - // check whether all the peer have expected peers connected + expectedConnected := numPeers * (numPeers - 1) + // adjust according to timeouts + timeout := 50 * time.Second + timeoutChan := time.After(timeout) for { + select { + case <-timeoutChan: + t.Fatalf("waiting for expected connections timeout after %s", timeout.String()) + return + default: + } time.Sleep(time.Second) totalConnected := 0 for _, engine := range engines { totalConnected = totalConnected + len(engine.GetConnectedPeers()) } if totalConnected == expectedConnected { + log.Debugf("total connected=%d", totalConnected) break } log.Infof("total connected=%d", totalConnected) } + + // cleanup test + for _, peerEngine := range engines { + errStop := peerEngine.Stop() + if errStop != nil { + log.Infoln("got error trying to close testing peers engine: ", errStop) + } + } } func createEngine(ctx context.Context, cancel context.CancelFunc, setupKey string, i int) (*Engine, error) { - key, err := wgtypes.GenerateKey() + key, err := wgtypes.GeneratePrivateKey() if err != nil { return nil, err } @@ -151,7 +173,7 @@ func createEngine(ctx context.Context, cancel context.CancelFunc, setupKey strin } conf := &EngineConfig{ - WgIface: ifaceName, + WgIfaceName: ifaceName, WgAddr: resp.PeerConfig.Address, WgPrivateKey: key, WgPort: 33100 + i, diff --git a/client/internal/proxy/proxy.go b/client/internal/proxy/proxy.go index 5ab892faa..5bf07927d 100644 --- a/client/internal/proxy/proxy.go +++ b/client/internal/proxy/proxy.go @@ -1,6 +1,7 @@ package proxy import ( + "github.com/wiretrustee/wiretrustee/iface" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" "io" "net" @@ -12,7 +13,7 @@ const DefaultWgKeepAlive = 25 * time.Second type Config struct { WgListenAddr string RemoteKey string - WgInterface string + WgInterface iface.WGIface AllowedIps string PreSharedKey *wgtypes.Key } diff --git a/client/internal/proxy/wireguard.go b/client/internal/proxy/wireguard.go index b4fa67600..c7325a71f 100644 --- a/client/internal/proxy/wireguard.go +++ b/client/internal/proxy/wireguard.go @@ -3,7 +3,6 @@ package proxy import ( "context" log "github.com/sirupsen/logrus" - "github.com/wiretrustee/wiretrustee/iface" "net" ) @@ -25,9 +24,13 @@ func NewWireguardProxy(config Config) *WireguardProxy { } func (p *WireguardProxy) updateEndpoint() error { + udpAddr, err := net.ResolveUDPAddr(p.localConn.LocalAddr().Network(), p.localConn.LocalAddr().String()) + if err != nil { + return err + } // add local proxy connection as a Wireguard peer - err := iface.UpdatePeer(p.config.WgInterface, p.config.RemoteKey, p.config.AllowedIps, DefaultWgKeepAlive, - p.localConn.LocalAddr().String(), p.config.PreSharedKey) + err = p.config.WgInterface.UpdatePeer(p.config.RemoteKey, p.config.AllowedIps, DefaultWgKeepAlive, + udpAddr, p.config.PreSharedKey) if err != nil { return err } @@ -65,7 +68,7 @@ func (p *WireguardProxy) Close() error { return err } } - err := iface.RemovePeer(p.config.WgInterface, p.config.RemoteKey) + err := p.config.WgInterface.RemovePeer(p.config.RemoteKey) if err != nil { return err } diff --git a/client/resources.rc b/client/resources.rc index 5ffef3cff..8459d85c0 100644 --- a/client/resources.rc +++ b/client/resources.rc @@ -5,5 +5,5 @@ #define STRINGIZE(x) #x #define EXPAND(x) STRINGIZE(x) CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST manifest.xml -wintun.dll RCDATA wintun.dll - +7 ICON ui/wiretrustee.ico +wireguard.dll RCDATA wireguard.dll diff --git a/client/resources_windows_amd64.syso b/client/resources_windows_amd64.syso deleted file mode 100644 index 64d593543..000000000 Binary files a/client/resources_windows_amd64.syso and /dev/null differ diff --git a/client/wireguard_nt.sh b/client/wireguard_nt.sh new file mode 100644 index 000000000..9f381fd97 --- /dev/null +++ b/client/wireguard_nt.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +ldir=$PWD +tmp_dir_path=$ldir/.distfiles +winnt=wireguard-nt.zip +download_file_path=$tmp_dir_path/$winnt +download_url=https://download.wireguard.com/wireguard-nt/wireguard-nt-0.10.1.zip +download_sha=772c0b1463d8d2212716f43f06f4594d880dea4f735165bd68e388fc41b81605 + +function resources_windows(){ + cmd=$1 + arch=$2 + out=$3 + docker run -i --rm -v $PWD:$PWD -w $PWD mstorsjo/llvm-mingw:latest $cmd -O coff -c 65001 -I $tmp_dir_path/wireguard-nt/bin/$arch -i resources.rc -o $out +} + +mkdir -p $tmp_dir_path +curl -L#o $download_file_path.unverified $download_url +echo "$download_sha $download_file_path.unverified" | sha256sum -c +mv $download_file_path.unverified $download_file_path + +mkdir -p .deps +unzip $download_file_path -d $tmp_dir_path + +resources_windows i686-w64-mingw32-windres x86 resources_windows_386.syso +resources_windows aarch64-w64-mingw32-windres arm64 resources_windows_arm64.syso +resources_windows x86_64-w64-mingw32-windres amd64 resources_windows_amd64.syso \ No newline at end of file diff --git a/iface/configuration.go b/iface/configuration.go new file mode 100644 index 000000000..f7944f980 --- /dev/null +++ b/iface/configuration.go @@ -0,0 +1,122 @@ +package iface + +import ( + log "github.com/sirupsen/logrus" + "golang.zx2c4.com/wireguard/wgctrl" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + "net" + "time" +) + +// configureDevice configures the wireguard device +func (w *WGIface) configureDevice(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(w.Name) + if err != nil { + return err + } + log.Debugf("got Wireguard device %s", w.Name) + + return wg.ConfigureDevice(w.Name, config) +} + +// Configure configures a Wireguard interface +// The interface must exist before calling this method (e.g. call interface.Create() before) +func (w *WGIface) Configure(privateKey string, port int) error { + + log.Debugf("configuring Wireguard interface %s", w.Name) + + 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, + } + + return w.configureDevice(config) +} + +// GetListenPort returns the listening port of the Wireguard endpoint +func (w *WGIface) GetListenPort() (*int, error) { + log.Debugf("getting Wireguard listen port of interface %s", w.Name) + + //discover Wireguard current configuration + wg, err := wgctrl.New() + if err != nil { + return nil, err + } + defer wg.Close() + + d, err := wg.Device(w.Name) + if err != nil { + return nil, err + } + log.Debugf("got Wireguard device listen port %s, %d", w.Name, d.ListenPort) + + return &d.ListenPort, nil +} + +// UpdatePeer updates existing Wireguard Peer or creates a new one if doesn't exist +// Endpoint is optional +func (w *WGIface) UpdatePeer(peerKey string, allowedIps string, keepAlive time.Duration, endpoint *net.UDPAddr, preSharedKey *wgtypes.Key) error { + + log.Debugf("updating interface %s peer %s: endpoint %s ", w.Name, peerKey, endpoint) + + //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}, + } + + return w.configureDevice(config) +} + +// RemovePeer removes a Wireguard Peer from the interface iface +func (w *WGIface) RemovePeer(peerKey string) error { + log.Debugf("Removing peer %s from interface %s ", peerKey, w.Name) + + peerKeyParsed, err := wgtypes.ParseKey(peerKey) + if err != nil { + return err + } + + peer := wgtypes.PeerConfig{ + PublicKey: peerKeyParsed, + Remove: true, + } + + config := wgtypes.Config{ + Peers: []wgtypes.PeerConfig{peer}, + } + + return w.configureDevice(config) +} diff --git a/iface/iface.go b/iface/iface.go index 0f2db4e67..1ba5b1813 100644 --- a/iface/iface.go +++ b/iface/iface.go @@ -1,78 +1,51 @@ package iface 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" + "os" + "runtime" ) const ( - defaultMTU = 1280 + DefaultMTU = 1280 ) -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("uapi Accept failed with error: ", err) - continue - } - go tunDevice.IpcHandle(uapiConn) - } - }() - - log.Debugln("UAPI listener started") - - err = assignAddr(address, iface) - if err != nil { - return err - } - return nil +// WGIface represents a interface instance +type WGIface struct { + Name string + Port int + MTU int + Address WGAddress + Interface NetInterface } -// configure peer for the wireguard device -func configureDevice(iface string, config wgtypes.Config) error { - wg, err := wgctrl.New() - if err != nil { - return err - } - defer wg.Close() +// WGAddress Wireguard parsed address +type WGAddress struct { + IP net.IP + Network *net.IPNet +} - _, err = wg.Device(iface) - if err != nil { - return err - } - log.Debugf("got Wireguard device %s", iface) +// NetInterface represents a generic network tunnel interface +type NetInterface interface { + Close() error +} - return wg.ConfigureDevice(iface, config) +// NewWGIface Creates a new Wireguard interface instance +func NewWGIface(iface string, address string, mtu int) (WGIface, error) { + wgIface := WGIface{ + Name: iface, + MTU: mtu, + } + + wgAddress, err := parseAddress(address) + if err != nil { + return wgIface, err + } + + wgIface.Address = wgAddress + + return wgIface, nil } // Exists checks whether specified Wireguard device exists or not @@ -99,140 +72,35 @@ func Exists(iface string) (*bool, error) { return &exists, 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, port int) error { - - log.Debugf("configuring Wireguard interface %s", iface) - - log.Debugf("adding Wireguard private key") - key, err := wgtypes.ParseKey(privateKey) +// parseAddress parse a string ("1.2.3.4/24") address to WG Address +func parseAddress(address string) (WGAddress, error) { + ip, network, err := net.ParseCIDR(address) if err != nil { - return err + return WGAddress{}, err } - fwmark := 0 - config := wgtypes.Config{ - PrivateKey: &key, - ReplacePeers: false, - FirewallMark: &fwmark, - ListenPort: &port, - } - - return configureDevice(iface, config) + return WGAddress{ + IP: ip, + Network: network, + }, 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) +// Closes the tunnel interface +func (w *WGIface) Close() error { - //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 -} - -// 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, preSharedKey *wgtypes.Key) error { - - log.Debugf("updating interface %s peer %s: endpoint %s ", iface, peerKey, endpoint) - - //parse allowed ips - _, ipNet, err := net.ParseCIDR(allowedIps) + err := w.Interface.Close() 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, - } - - config := wgtypes.Config{ - Peers: []wgtypes.PeerConfig{peer}, - } - - err = configureDevice(iface, config) - if err != nil { - return err - } - - if endpoint != "" { - return UpdatePeerEndpoint(iface, peerKey, endpoint) + if runtime.GOOS == "darwin" { + sockPath := "/var/run/wireguard/" + w.Name + ".sock" + if _, statErr := os.Stat(sockPath); statErr == nil { + statErr = os.Remove(sockPath) + if statErr != nil { + return statErr + } + } } 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) - - 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 - } - - peer := wgtypes.PeerConfig{ - PublicKey: peerKeyParsed, - ReplaceAllowedIPs: false, - UpdateOnly: true, - Endpoint: peerAddr, - } - config := wgtypes.Config{ - Peers: []wgtypes.PeerConfig{peer}, - } - return configureDevice(iface, config) -} - -// RemovePeer removes a Wireguard Peer from the interface iface -func RemovePeer(iface string, peerKey string) error { - log.Debugf("Removing peer %s from interface %s ", peerKey, iface) - - peerKeyParsed, err := wgtypes.ParseKey(peerKey) - if err != nil { - return err - } - - peer := wgtypes.PeerConfig{ - PublicKey: peerKeyParsed, - Remove: true, - } - - config := wgtypes.Config{ - Peers: []wgtypes.PeerConfig{peer}, - } - - return configureDevice(iface, config) -} - -// CloseWithUserspace closes the User Space tunnel interface -func CloseWithUserspace() error { - return tunIface.Close() -} diff --git a/iface/iface_darwin.go b/iface/iface_darwin.go index d8d5ae57e..aba4ff7c7 100644 --- a/iface/iface_darwin.go +++ b/iface/iface_darwin.go @@ -2,62 +2,31 @@ package iface import ( log "github.com/sirupsen/logrus" - "net" - "os" "os/exec" - "strings" ) // 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) +func (w *WGIface) Create() error { + return w.CreateWithUserspace() } // assignAddr Adds IP address to the tunnel interface and network route based on the range provided -func assignAddr(address string, ifaceName string) error { - ip := strings.Split(address, "/") - cmd := exec.Command("ifconfig", ifaceName, "inet", address, ip[0]) +func (w *WGIface) assignAddr() error { + //mask,_ := w.Address.Network.Mask.Size() + // + //address := fmt.Sprintf("%s/%d",w.Address.IP.String() , mask) + + cmd := exec.Command("ifconfig", w.Name, "inet", w.Address.IP.String(), w.Address.IP.String()) if out, err := cmd.CombinedOutput(); err != nil { - log.Infof("Command: %v failed with output %s and error: ", cmd.String(), out) + log.Infof("adding addreess command \"%v\" failed with output %s and error: ", cmd.String(), out) return err } - _, resolvedNet, err := net.ParseCIDR(address) - err = addRoute(ifaceName, resolvedNet) - if err != nil { - log.Infoln("Adding route failed with error:", err) - } - return nil -} - -// addRoute Adds network route based on the range provided -func addRoute(iface string, ipNet *net.IPNet) error { - cmd := exec.Command("route", "add", "-net", ipNet.String(), "-interface", iface) - if out, err := cmd.CombinedOutput(); err != nil { - log.Printf("Command: %v failed with output %s and error: ", cmd.String(), out) - return err - } - return nil -} - -// Closes the tunnel interface -func Close(iFace string) error { - name, err := tunIface.Name() - if err != nil { - return err - } - - sockPath := "/var/run/wireguard/" + name + ".sock" - - err = CloseWithUserspace() - if err != nil { - return err - } - - if _, err := os.Stat(sockPath); err == nil { - err = os.Remove(sockPath) - if err != nil { - return err - } + + routeCmd := exec.Command("route", "add", "-net", w.Address.Network.String(), "-interface", w.Name) + if out, err := routeCmd.CombinedOutput(); err != nil { + log.Printf("adding route command \"%v\" failed with output %s and error: ", routeCmd.String(), out) + return err } + return nil } diff --git a/iface/iface_linux.go b/iface/iface_linux.go index 09367e562..0aa6b4b2f 100644 --- a/iface/iface_linux.go +++ b/iface/iface_linux.go @@ -1,35 +1,36 @@ 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 Create(iface string, address string) error { +func (w *WGIface) Create() error { if WireguardModExists() { log.Debug("using kernel Wireguard module") - return CreateWithKernel(iface, address) + return w.CreateWithKernel() } else { - return CreateWithUserspace(iface, address) + return w.CreateWithUserspace() } } // 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 +func (w *WGIface) CreateWithKernel() error { - link := wgLink{ - attrs: &attrs, - } + link := newWGLink(w.Name) // check if interface exists - l, err := netlink.LinkByName(iface) + l, err := netlink.LinkByName(w.Name) if err != nil { switch err.(type) { case netlink.LinkNotFoundError: @@ -41,37 +42,39 @@ func CreateWithKernel(iface string, address string) error { // remove if interface exists if l != nil { - err = netlink.LinkDel(&link) + err = netlink.LinkDel(link) if err != nil { return err } } - log.Debugf("adding device: %s", iface) - err = netlink.LinkAdd(&link) + log.Debugf("adding device: %s", w.Name) + err = netlink.LinkAdd(link) if os.IsExist(err) { - log.Infof("interface %s already exists. Will reuse.", iface) + log.Infof("interface %s already exists. Will reuse.", w.Name) } else if err != nil { return err } - err = assignAddr(address, iface) + w.Interface = link + + err = w.assignAddr() if err != nil { return err } // todo do a discovery - log.Debugf("setting MTU: %d interface: %s", defaultMTU, iface) - err = netlink.LinkSetMTU(&link, defaultMTU) + 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", iface) + log.Errorf("error setting MTU on interface: %s", w.Name) return err } - log.Debugf("bringing up interface: %s", iface) - err = netlink.LinkSetUp(&link) + log.Debugf("bringing up interface: %s", w.Name) + err = netlink.LinkSetUp(link) if err != nil { - log.Errorf("error bringing up interface: %s", iface) + log.Errorf("error bringing up interface: %s", w.Name) return err } @@ -79,39 +82,37 @@ func CreateWithKernel(iface string, address string) error { } // assignAddr Adds IP address to the tunnel interface -func assignAddr(address, name string) error { - var err error - attrs := netlink.NewLinkAttrs() - attrs.Name = name +func (w *WGIface) assignAddr() error { - link := wgLink{ - attrs: &attrs, - } + mask, _ := w.Address.Network.Mask.Size() + address := fmt.Sprintf("%s/%d", w.Address.IP.String(), mask) + + link := newWGLink(w.Name) //delete existing addresses - list, err := netlink.AddrList(&link, 0) + list, err := netlink.AddrList(link, 0) if err != nil { return err } if len(list) > 0 { for _, a := range list { - err = netlink.AddrDel(&link, &a) + err = netlink.AddrDel(link, &a) if err != nil { return err } } } - log.Debugf("adding address %s to interface: %s", address, attrs.Name) + log.Debugf("adding address %s to interface: %s", address, w.Name) addr, _ := netlink.ParseAddr(address) - err = netlink.AddrAdd(&link, addr) + err = netlink.AddrAdd(link, addr) if os.IsExist(err) { - log.Infof("interface %s already has the address: %s", attrs.Name, address) + log.Infof("interface %s already has the address: %s", w.Name, address) } else if err != nil { return err } // On linux, the link must be brought up - err = netlink.LinkSetUp(&link) + err = netlink.LinkSetUp(link) return err } @@ -119,28 +120,26 @@ 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 (w *wgLink) Attrs() *netlink.LinkAttrs { - return w.attrs +func (l *wgLink) Attrs() *netlink.LinkAttrs { + return l.attrs } // Type returns the interface type -func (w *wgLink) Type() string { +func (l *wgLink) Type() string { return "wireguard" } -// Close closes the tunnel interface -func Close(iFace string) error { - - if tunIface != nil { - return CloseWithUserspace() - } else { - attrs := netlink.NewLinkAttrs() - attrs.Name = iFace - - link := wgLink{ - attrs: &attrs, - } - return netlink.LinkDel(&link) - } +// Close deletes the link interface +func (l *wgLink) Close() error { + return netlink.LinkDel(l) } diff --git a/iface/iface_test.go b/iface/iface_test.go index f4cfe927d..dec097522 100644 --- a/iface/iface_test.go +++ b/iface/iface_test.go @@ -12,25 +12,36 @@ import ( // keep darwin compability const ( - key = "0PMI6OkB5JmB+Jj/iWWHekuQRx+bipZirWCWKFXexHc=" - peerPubKey = "Ok0mC0qlJyXEPKh2UFIpsI2jG0L7LRpC3sLAusSJ5CQ=" - WgPort = 51820 + WgPort = 51000 +) + +var ( + key string + peerPubKey string ) func init() { log.SetLevel(log.DebugLevel) + privateKey, _ := wgtypes.GeneratePrivateKey() + key = privateKey.String() + peerPrivateKey, _ := wgtypes.GeneratePrivateKey() + peerPubKey = peerPrivateKey.PublicKey().String() } // func Test_CreateInterface(t *testing.T) { ifaceName := "utun999" wgIP := "10.99.99.1/24" - err := Create(ifaceName, wgIP) + iface, err := NewWGIface(ifaceName, wgIP, DefaultMTU) + if err != nil { + t.Fatal(err) + } + err = iface.Create() if err != nil { t.Fatal(err) } defer func() { - err = Close(ifaceName) + err = iface.Close() if err != nil { t.Error(err) } @@ -46,21 +57,54 @@ func Test_CreateInterface(t *testing.T) { } }() } -func Test_ConfigureInterface(t *testing.T) { - ifaceName := "utun1000" - wgIP := "10.99.99.10/24" - err := Create(ifaceName, wgIP) + +func Test_Close(t *testing.T) { + ifaceName := "utun1004" + wgIP := "10.99.99.50/24" + iface, err := NewWGIface(ifaceName, wgIP, DefaultMTU) + if err != nil { + t.Fatal(err) + } + err = iface.Create() + if err != nil { + t.Fatal(err) + } + wg, err := wgctrl.New() if err != nil { t.Fatal(err) } defer func() { - err = Close(ifaceName) + err = wg.Close() if err != nil { t.Error(err) } }() - err = Configure(ifaceName, key, WgPort) + err = iface.Close() + if err != nil { + t.Fatal(err) + } +} + +func Test_ConfigureInterface(t *testing.T) { + ifaceName := "utun1000" + wgIP := "10.99.99.10/24" + iface, err := NewWGIface(ifaceName, wgIP, DefaultMTU) + if err != nil { + t.Fatal(err) + } + err = iface.Create() + if err != nil { + t.Fatal(err) + } + defer func() { + err = iface.Close() + if err != nil { + t.Error(err) + } + }() + + err = iface.Configure(key, WgPort+1) if err != nil { t.Fatal(err) } @@ -88,28 +132,35 @@ func Test_ConfigureInterface(t *testing.T) { func Test_UpdatePeer(t *testing.T) { ifaceName := "utun1001" wgIP := "10.99.99.20/24" - err := Create(ifaceName, wgIP) + iface, err := NewWGIface(ifaceName, wgIP, DefaultMTU) + if err != nil { + t.Fatal(err) + } + err = iface.Create() if err != nil { t.Fatal(err) } defer func() { - err = Close(ifaceName) + err = iface.Close() if err != nil { t.Error(err) } }() - err = Configure(ifaceName, key, WgPort) + err = iface.Configure(key, WgPort+2) if err != nil { t.Fatal(err) } keepAlive := 15 * time.Second allowedIP := "10.99.99.2/32" - endpoint := "127.0.0.1:9900" - err = UpdatePeer(ifaceName, peerPubKey, allowedIP, keepAlive, endpoint, nil) + endpoint, err := net.ResolveUDPAddr("udp", "127.0.0.1:9900") if err != nil { t.Fatal(err) } - peer, err := getPeer(ifaceName, t) + err = iface.UpdatePeer(peerPubKey, allowedIP, keepAlive, endpoint, nil) + if err != nil { + t.Fatal(err) + } + peer, err := getPeer(ifaceName, peerPubKey, t) if err != nil { t.Fatal(err) } @@ -117,11 +168,7 @@ func Test_UpdatePeer(t *testing.T) { t.Fatal("configured peer with mismatched keepalive interval value") } - resolvedEndpoint, err := net.ResolveUDPAddr("udp", endpoint) - if err != nil { - t.Fatal(err) - } - if peer.Endpoint.String() != resolvedEndpoint.String() { + if peer.Endpoint.String() != endpoint.String() { t.Fatal("configured peer with mismatched endpoint") } @@ -137,104 +184,132 @@ func Test_UpdatePeer(t *testing.T) { } } -func Test_UpdatePeerEndpoint(t *testing.T) { - ifaceName := "utun1002" - wgIP := "10.99.99.30/24" - err := Create(ifaceName, wgIP) - if err != nil { - t.Fatal(err) - } - defer func() { - err = Close(ifaceName) - if err != nil { - t.Error(err) - } - }() - err = Configure(ifaceName, key, WgPort) - if err != nil { - t.Fatal(err) - } - keepAlive := 15 * time.Second - allowedIP := "10.99.99.2/32" - endpoint := "127.0.0.1:9900" - err = UpdatePeer(ifaceName, peerPubKey, allowedIP, keepAlive, endpoint, nil) - if err != nil { - t.Fatal(err) - } - - newEndpoint := "127.0.0.1:9999" - err = UpdatePeerEndpoint(ifaceName, peerPubKey, newEndpoint) - if err != nil { - t.Fatal(err) - } - - peer, err := getPeer(ifaceName, t) - if err != nil { - t.Fatal(err) - } - - if peer.Endpoint.String() != newEndpoint { - t.Fatal("configured peer with mismatched endpoint") - } -} - func Test_RemovePeer(t *testing.T) { ifaceName := "utun1003" wgIP := "10.99.99.40/24" - err := Create(ifaceName, wgIP) + iface, err := NewWGIface(ifaceName, wgIP, DefaultMTU) + if err != nil { + t.Fatal(err) + } + err = iface.Create() if err != nil { t.Fatal(err) } defer func() { - err = Close(ifaceName) + err = iface.Close() if err != nil { t.Error(err) } }() - err = Configure(ifaceName, key, WgPort) + err = iface.Configure(key, WgPort+3) if err != nil { t.Fatal(err) } keepAlive := 15 * time.Second allowedIP := "10.99.99.2/32" - endpoint := "127.0.0.1:9900" - err = UpdatePeer(ifaceName, peerPubKey, allowedIP, keepAlive, endpoint, nil) + + err = iface.UpdatePeer(peerPubKey, allowedIP, keepAlive, nil, nil) if err != nil { t.Fatal(err) } - err = RemovePeer(ifaceName, peerPubKey) + err = iface.RemovePeer(peerPubKey) if err != nil { t.Fatal(err) } - _, err = getPeer(ifaceName, t) + _, err = getPeer(ifaceName, peerPubKey, t) if err.Error() != "peer not found" { t.Fatal(err) } } -func Test_Close(t *testing.T) { - ifaceName := "utun1004" - wgIP := "10.99.99.50/24" - err := Create(ifaceName, wgIP) + +func Test_ConnectPeers(t *testing.T) { + peer1ifaceName := fmt.Sprintf("utun%d", 400) + peer1wgIP := "10.99.99.100/24" + peer1Key, _ := wgtypes.GeneratePrivateKey() + peer1Port := WgPort + 4 + + peer1endpoint, err := net.ResolveUDPAddr("udp", fmt.Sprintf("127.0.0.1:%d", peer1Port)) if err != nil { t.Fatal(err) } - wg, err := wgctrl.New() + + peer2ifaceName := fmt.Sprintf("utun%d", 500) + peer2wgIP := "10.99.99.200/24" + peer2Key, _ := wgtypes.GeneratePrivateKey() + peer2Port := WgPort + 5 + + peer2endpoint, err := net.ResolveUDPAddr("udp", fmt.Sprintf("127.0.0.1:%d", peer2Port)) + if err != nil { + t.Fatal(err) + } + + keepAlive := 1 * time.Second + + iface1, err := NewWGIface(peer1ifaceName, peer1wgIP, DefaultMTU) + if err != nil { + t.Fatal(err) + } + err = iface1.Create() + if err != nil { + t.Fatal(err) + } + iface2, err := NewWGIface(peer2ifaceName, peer2wgIP, DefaultMTU) + if err != nil { + t.Fatal(err) + } + err = iface2.Create() if err != nil { t.Fatal(err) } defer func() { - err = wg.Close() + err = iface1.Close() + if err != nil { + t.Error(err) + } + err = iface2.Close() if err != nil { t.Error(err) } }() - - err = Close(ifaceName) + err = iface1.Configure(peer1Key.String(), peer1Port) if err != nil { t.Fatal(err) } + err = iface2.Configure(peer2Key.String(), peer2Port) + if err != nil { + t.Fatal(err) + } + + err = iface1.UpdatePeer(peer2Key.PublicKey().String(), peer2wgIP, keepAlive, peer2endpoint, nil) + if err != nil { + t.Fatal(err) + } + err = iface2.UpdatePeer(peer1Key.PublicKey().String(), peer1wgIP, keepAlive, peer1endpoint, nil) + if err != nil { + t.Fatal(err) + } + + timeout := 10 * time.Second + timeoutChannel := time.After(timeout) + for { + select { + case <-timeoutChannel: + t.Fatalf("waiting for peer handshake timeout after %s", timeout.String()) + default: + } + peer, gpErr := getPeer(peer1ifaceName, peer2Key.PublicKey().String(), t) + if gpErr != nil { + t.Fatal(gpErr) + } + if !peer.LastHandshakeTime.IsZero() { + t.Log("peers successfully handshake") + break + } + } + } -func getPeer(ifaceName string, t *testing.T) (wgtypes.Peer, error) { + +func getPeer(ifaceName, peerPubKey string, t *testing.T) (wgtypes.Peer, error) { emptyPeer := wgtypes.Peer{} wg, err := wgctrl.New() if err != nil { diff --git a/iface/iface_unix.go b/iface/iface_unix.go index ccdfa69cf..54bd635cf 100644 --- a/iface/iface_unix.go +++ b/iface/iface_unix.go @@ -1,12 +1,58 @@ +//go:build linux || darwin // +build linux darwin package iface import ( + log "github.com/sirupsen/logrus" + "golang.zx2c4.com/wireguard/conn" + "golang.zx2c4.com/wireguard/device" "golang.zx2c4.com/wireguard/ipc" + "golang.zx2c4.com/wireguard/tun" "net" ) +// CreateWithUserspace Creates a new Wireguard interface, using wireguard-go userspace implementation +func (w *WGIface) CreateWithUserspace() error { + + tunIface, err := tun.CreateTUN(w.Name, w.MTU) + if err != nil { + return err + } + + w.Interface = tunIface + + // 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(w.Name) + if err != nil { + return err + } + + go func() { + for { + uapiConn, uapiErr := uapi.Accept() + if uapiErr != nil { + log.Traceln("uapi Accept failed with error: ", uapiErr) + continue + } + go tunDevice.IpcHandle(uapiConn) + } + }() + + log.Debugln("UAPI listener started") + + err = w.assignAddr() + if err != nil { + return err + } + return nil +} + // getUAPI returns a Listener func getUAPI(iface string) (net.Listener, error) { tunSock, err := ipc.UAPIOpen(iface) diff --git a/iface/iface_windows.go b/iface/iface_windows.go index a85e062cf..42b07e441 100644 --- a/iface/iface_windows.go +++ b/iface/iface_windows.go @@ -1,46 +1,47 @@ package iface import ( + "fmt" log "github.com/sirupsen/logrus" - "golang.zx2c4.com/wireguard/ipc" - "golang.zx2c4.com/wireguard/tun" + "golang.org/x/sys/windows" + "golang.zx2c4.com/wireguard/windows/driver" "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg" "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) +func (w *WGIface) Create() error { + + WintunStaticRequestedGUID, _ := windows.GenerateGUID() + adapter, err := driver.CreateAdapter(w.Name, "WireGuard", &WintunStaticRequestedGUID) + if err != nil { + err = fmt.Errorf("error creating adapter: %w", err) + return err + } + w.Interface = adapter + luid := adapter.LUID() + err = adapter.SetLogging(driver.AdapterLogOn) + if err != nil { + err = fmt.Errorf("Error enabling adapter logging: %w", err) + return err + } + err = adapter.SetAdapterState(driver.AdapterStateUp) + if err != nil { + return err + } + state, _ := luid.GUID() + log.Debugln("device guid: ", state.String()) + return w.assignAddr(luid) } // assignAddr Adds IP address to the tunnel interface and network route based on the range provided -func assignAddr(address string, ifaceName string) error { +func (w *WGIface) assignAddr(luid winipcfg.LUID) error { - nativeTunDevice := tunIface.(*tun.NativeTun) - luid := winipcfg.LUID(nativeTunDevice.LUID()) - - ip, ipnet, _ := net.ParseCIDR(address) - - log.Debugf("adding address %s to interface: %s", address, ifaceName) - err := luid.SetIPAddresses([]net.IPNet{{ip, ipnet.Mask}}) + log.Debugf("adding address %s to interface: %s", w.Address.IP, w.Name) + err := luid.SetIPAddresses([]net.IPNet{{w.Address.IP, w.Address.Network.Mask}}) if err != nil { return err } - log.Debugf("adding Routes to interface: %s", ifaceName) - err = luid.SetRoutes([]*winipcfg.RouteData{{*ipnet, ipnet.IP, 0}}) - if err != nil { - return err - } return nil } - -// getUAPI returns a Listener -func getUAPI(iface string) (net.Listener, error) { - return ipc.UAPIListen(iface) -} - -// Closes the tunnel interface -func Close(iFace string) error { - return CloseWithUserspace() -} diff --git a/util/file_test.go b/util/file_test.go index 2c4d3209e..c502285d0 100644 --- a/util/file_test.go +++ b/util/file_test.go @@ -93,6 +93,12 @@ var _ = Describe("Client", func() { _, err = io.Copy(hashDst, dstFile) Expect(err).NotTo(HaveOccurred()) + err = srcFile.Close() + Expect(err).NotTo(HaveOccurred()) + + err = dstFile.Close() + Expect(err).NotTo(HaveOccurred()) + Expect(hex.EncodeToString(hashSrc.Sum(nil)[:16])).To(BeEquivalentTo(hex.EncodeToString(hashDst.Sum(nil)[:16]))) }) })