mirror of
https://github.com/netbirdio/netbird.git
synced 2024-11-25 09:33:24 +01:00
Refactor Interface package and update windows driver (#192)
* script to generate syso files * test wireguard-windows driver package * set int log * add windows test * add windows test * verbose bash * use cd * move checkout * exit 0 * removed tty flag * artifact path * fix tags and add cache * fix cache * fix cache * test dir * restore artifacts in the root * try dll file * try dll file * copy dll * typo in copy dll * compile test * checkout first * updated cicd * fix add address issue and gen GUID * psexec typo * accept eula * mod tidy before tests * regular test exec and verbose test with psexec * test all * return WGInterface Interface * use WgIfaceName and timeout after 30 seconds * different ports and validate connect 2 peers * Use time.After for timeout and close interface * Use time.After for testing connect peers * WG Interface struct * Update engine and parse address * refactor Linux create and assignAddress * NewWGIface and configuration methods * Update proxy with interface methods * update up command test * resolve lint warnings * remove psexec test * close copied files * add goos before build * run tests on mac,windows and linux * cache by testing os * run on push * fix indentation * adjust test timeouts * remove parallel flag * mod tidy before test * ignore syso files * removed functions and renamed vars * different IPs for connect peers test * Generate syso with DLL * Single Close method * use port from test constant * test: remove wireguard interfaces after finishing engine test * use load_wgnt_from_rsrc Co-authored-by: braginini <bangvalo@gmail.com>
This commit is contained in:
parent
afb302d5e7
commit
64f2d295a8
12
.github/workflows/golang-test-build.yml
vendored
12
.github/workflows/golang-test-build.yml
vendored
@ -1,9 +1,5 @@
|
|||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
name: Test Build On Platforms
|
name: Test Build On Platforms
|
||||||
|
on: push
|
||||||
jobs:
|
jobs:
|
||||||
test_build:
|
test_build:
|
||||||
strategy:
|
strategy:
|
||||||
@ -21,15 +17,15 @@ jobs:
|
|||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
|
|
||||||
- name: Cache Go modules
|
- name: Cache Go modules
|
||||||
uses: actions/cache@v1
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: ~/go/pkg/mod
|
path: ~/go/pkg/mod
|
||||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
key: ${{ runner.os }}-go-test-${{ matrix.os }}-${{ hashFiles('**/go.sum') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-go-
|
${{ runner.os }}-go-
|
||||||
|
|
||||||
- name: Install modules
|
- name: Install modules
|
||||||
run: go mod tidy
|
run: GOOS=${{ matrix.os }} go mod tidy
|
||||||
|
|
||||||
- name: run build client
|
- name: run build client
|
||||||
run: GOOS=${{ matrix.os }} go build .
|
run: GOOS=${{ matrix.os }} go build .
|
||||||
|
29
.github/workflows/golang-test-darwin.yml
vendored
Normal file
29
.github/workflows/golang-test-darwin.yml
vendored
Normal file
@ -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 ./...
|
@ -1,9 +1,5 @@
|
|||||||
on:
|
name: Test Code Linux
|
||||||
push:
|
on: push
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
name: Test Code
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
strategy:
|
strategy:
|
||||||
@ -27,7 +23,20 @@ jobs:
|
|||||||
$(whoami) soft nofile 65535
|
$(whoami) soft nofile 65535
|
||||||
$(whoami) hard nofile 65535
|
$(whoami) hard nofile 65535
|
||||||
EOF
|
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
|
- name: Checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install modules
|
||||||
|
run: go mod tidy
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: GOBIN=$(which go) && sudo --preserve-env=GOROOT $GOBIN test -p 1 ./...
|
run: GOBIN=$(which go) && sudo --preserve-env=GOROOT $GOBIN test ./...
|
51
.github/workflows/golang-test-windows.yml
vendored
Normal file
51
.github/workflows/golang-test-windows.yml
vendored
Normal file
@ -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 ./...
|
6
.github/workflows/golangci-lint.yml
vendored
6
.github/workflows/golangci-lint.yml
vendored
@ -1,9 +1,5 @@
|
|||||||
name: golangci-lint
|
name: golangci-lint
|
||||||
on:
|
on: push
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
jobs:
|
jobs:
|
||||||
golangci:
|
golangci:
|
||||||
name: lint
|
name: lint
|
||||||
|
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@ -14,6 +14,10 @@ jobs:
|
|||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # It is required for GoReleaser to work properly
|
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
|
name: Set up Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -5,4 +5,5 @@ dist/
|
|||||||
conf.json
|
conf.json
|
||||||
http-cmds.sh
|
http-cmds.sh
|
||||||
infrastructure_files/management.json
|
infrastructure_files/management.json
|
||||||
infrastructure_files/docker-compose.yml
|
infrastructure_files/docker-compose.yml
|
||||||
|
*.syso
|
@ -26,7 +26,7 @@ builds:
|
|||||||
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser
|
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser
|
||||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||||
tags:
|
tags:
|
||||||
- load_wintun_from_rsrc
|
- load_wgnt_from_rsrc
|
||||||
|
|
||||||
- id: wiretrustee-mgmt
|
- id: wiretrustee-mgmt
|
||||||
dir: management
|
dir: management
|
||||||
|
@ -60,7 +60,7 @@ func TestLogin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if actualConf.WgIface != iface.WgInterfaceDefault {
|
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 {
|
if len(actualConf.PrivateKey) == 0 {
|
||||||
|
@ -64,7 +64,7 @@ func createEngineConfig(key wgtypes.Key, config *internal.Config, peerConfig *mg
|
|||||||
}
|
}
|
||||||
|
|
||||||
engineConf := &internal.EngineConfig{
|
engineConf := &internal.EngineConfig{
|
||||||
WgIface: config.WgIface,
|
WgIfaceName: config.WgIface,
|
||||||
WgAddr: peerConfig.Address,
|
WgAddr: peerConfig.Address,
|
||||||
IFaceBlackList: iFaceBlackList,
|
IFaceBlackList: iFaceBlackList,
|
||||||
WgPrivateKey: key,
|
WgPrivateKey: key,
|
||||||
|
@ -36,7 +36,7 @@ func TestUp_Start(t *testing.T) {
|
|||||||
|
|
||||||
func TestUp(t *testing.T) {
|
func TestUp(t *testing.T) {
|
||||||
|
|
||||||
defer iface.Close("wt0")
|
//defer iface.Close("wt0")
|
||||||
|
|
||||||
tempDir := t.TempDir()
|
tempDir := t.TempDir()
|
||||||
confPath := tempDir + "/config.json"
|
confPath := tempDir + "/config.json"
|
||||||
@ -53,6 +53,8 @@ func TestUp(t *testing.T) {
|
|||||||
"A2C8E62B-38F5-4553-B31E-DD66C696CEBB",
|
"A2C8E62B-38F5-4553-B31E-DD66C696CEBB",
|
||||||
"--management-url",
|
"--management-url",
|
||||||
mgmtURL.String(),
|
mgmtURL.String(),
|
||||||
|
"--log-level",
|
||||||
|
"debug",
|
||||||
"--log-file",
|
"--log-file",
|
||||||
"console",
|
"console",
|
||||||
})
|
})
|
||||||
@ -63,20 +65,23 @@ func TestUp(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
exists := false
|
timeout := 15 * time.Second
|
||||||
for start := time.Now(); time.Since(start) < 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)
|
e, err := iface.Exists(iface.WgInterfaceDefault)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if *e {
|
if *e {
|
||||||
exists = true
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if !exists {
|
|
||||||
t.Errorf("expected wireguard interface %s to be created", iface.WgInterfaceDefault)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
// PeerConnectionTimeoutMax is a timeout of an initial connection attempt to a remote peer.
|
// 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.
|
// 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 PeerConnectionTimeoutMax = 45000 //ms
|
||||||
const PeerConnectionTimeoutMin = 30000 //ms
|
const PeerConnectionTimeoutMin = 30000 //ms
|
||||||
|
|
||||||
@ -28,8 +29,8 @@ const WgPort = 51820
|
|||||||
|
|
||||||
// EngineConfig is a config for the Engine
|
// EngineConfig is a config for the Engine
|
||||||
type EngineConfig struct {
|
type EngineConfig struct {
|
||||||
WgPort int
|
WgPort int
|
||||||
WgIface string
|
WgIfaceName string
|
||||||
// WgAddr is a Wireguard local address (Wiretrustee Network IP)
|
// WgAddr is a Wireguard local address (Wiretrustee Network IP)
|
||||||
WgAddr string
|
WgAddr string
|
||||||
// WgPrivateKey is a Wireguard private key of our peer (it MUST never leave the machine)
|
// 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
|
cancel context.CancelFunc
|
||||||
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
|
||||||
|
wgInterface iface.WGIface
|
||||||
}
|
}
|
||||||
|
|
||||||
// Peer is an instance of the Connection Peer
|
// Peer is an instance of the Connection Peer
|
||||||
@ -93,11 +96,13 @@ func (e *Engine) Stop() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("removing Wiretrustee interface %s", e.config.WgIface)
|
log.Debugf("removing Wiretrustee interface %s", e.config.WgIfaceName)
|
||||||
err = iface.Close(e.config.WgIface)
|
if e.wgInterface.Interface != nil {
|
||||||
if err != nil {
|
err = e.wgInterface.Close()
|
||||||
log.Errorf("failed closing Wiretrustee interface %s %v", e.config.WgIface, err)
|
if err != nil {
|
||||||
return err
|
log.Errorf("failed closing Wiretrustee interface %s %v", e.config.WgIfaceName, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("stopped Wiretrustee Engine")
|
log.Infof("stopped Wiretrustee Engine")
|
||||||
@ -112,19 +117,26 @@ func (e *Engine) Start() error {
|
|||||||
e.syncMsgMux.Lock()
|
e.syncMsgMux.Lock()
|
||||||
defer e.syncMsgMux.Unlock()
|
defer e.syncMsgMux.Unlock()
|
||||||
|
|
||||||
wgIface := e.config.WgIface
|
wgIfaceName := e.config.WgIfaceName
|
||||||
wgAddr := e.config.WgAddr
|
wgAddr := e.config.WgAddr
|
||||||
myPrivateKey := e.config.WgPrivateKey
|
myPrivateKey := e.config.WgPrivateKey
|
||||||
|
var err error
|
||||||
|
|
||||||
err := iface.Create(wgIface, wgAddr)
|
e.wgInterface, err = iface.NewWGIface(wgIfaceName, wgAddr, iface.DefaultMTU)
|
||||||
if err != nil {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = iface.Configure(wgIface, myPrivateKey.String(), e.config.WgPort)
|
err = e.wgInterface.Create()
|
||||||
if err != nil {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,7 +411,7 @@ func (e Engine) createPeerConn(pubKey string, allowedIPs string) (*peer.Conn, er
|
|||||||
proxyConfig := proxy.Config{
|
proxyConfig := proxy.Config{
|
||||||
RemoteKey: pubKey,
|
RemoteKey: pubKey,
|
||||||
WgListenAddr: fmt.Sprintf("127.0.0.1:%d", e.config.WgPort),
|
WgListenAddr: fmt.Sprintf("127.0.0.1:%d", e.config.WgPort),
|
||||||
WgInterface: e.config.WgIface,
|
WgInterface: e.wgInterface,
|
||||||
AllowedIps: allowedIPs,
|
AllowedIps: allowedIPs,
|
||||||
PreSharedKey: e.config.PreSharedKey,
|
PreSharedKey: e.config.PreSharedKey,
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,11 @@ func TestEngine_MultiplePeers(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer func() {
|
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())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
@ -102,25 +106,43 @@ func TestEngine_MultiplePeers(t *testing.T) {
|
|||||||
|
|
||||||
// wait until all have been created and started
|
// wait until all have been created and started
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
// check whether all the peer have expected peers connected
|
// check whether all the peer have expected peers connected
|
||||||
|
|
||||||
expectedConnected := numPeers * (numPeers - 1)
|
expectedConnected := numPeers * (numPeers - 1)
|
||||||
|
// adjust according to timeouts
|
||||||
|
timeout := 50 * time.Second
|
||||||
|
timeoutChan := time.After(timeout)
|
||||||
for {
|
for {
|
||||||
|
select {
|
||||||
|
case <-timeoutChan:
|
||||||
|
t.Fatalf("waiting for expected connections timeout after %s", timeout.String())
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
totalConnected := 0
|
totalConnected := 0
|
||||||
for _, engine := range engines {
|
for _, engine := range engines {
|
||||||
totalConnected = totalConnected + len(engine.GetConnectedPeers())
|
totalConnected = totalConnected + len(engine.GetConnectedPeers())
|
||||||
}
|
}
|
||||||
if totalConnected == expectedConnected {
|
if totalConnected == expectedConnected {
|
||||||
|
log.Debugf("total connected=%d", totalConnected)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
log.Infof("total connected=%d", totalConnected)
|
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) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -151,7 +173,7 @@ func createEngine(ctx context.Context, cancel context.CancelFunc, setupKey strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
conf := &EngineConfig{
|
conf := &EngineConfig{
|
||||||
WgIface: ifaceName,
|
WgIfaceName: ifaceName,
|
||||||
WgAddr: resp.PeerConfig.Address,
|
WgAddr: resp.PeerConfig.Address,
|
||||||
WgPrivateKey: key,
|
WgPrivateKey: key,
|
||||||
WgPort: 33100 + i,
|
WgPort: 33100 + i,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package proxy
|
package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/wiretrustee/wiretrustee/iface"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@ -12,7 +13,7 @@ const DefaultWgKeepAlive = 25 * time.Second
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
WgListenAddr string
|
WgListenAddr string
|
||||||
RemoteKey string
|
RemoteKey string
|
||||||
WgInterface string
|
WgInterface iface.WGIface
|
||||||
AllowedIps string
|
AllowedIps string
|
||||||
PreSharedKey *wgtypes.Key
|
PreSharedKey *wgtypes.Key
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package proxy
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/wiretrustee/wiretrustee/iface"
|
|
||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -25,9 +24,13 @@ func NewWireguardProxy(config Config) *WireguardProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *WireguardProxy) updateEndpoint() error {
|
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
|
// add local proxy connection as a Wireguard peer
|
||||||
err := iface.UpdatePeer(p.config.WgInterface, p.config.RemoteKey, p.config.AllowedIps, DefaultWgKeepAlive,
|
err = p.config.WgInterface.UpdatePeer(p.config.RemoteKey, p.config.AllowedIps, DefaultWgKeepAlive,
|
||||||
p.localConn.LocalAddr().String(), p.config.PreSharedKey)
|
udpAddr, p.config.PreSharedKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -65,7 +68,7 @@ func (p *WireguardProxy) Close() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err := iface.RemovePeer(p.config.WgInterface, p.config.RemoteKey)
|
err := p.config.WgInterface.RemovePeer(p.config.RemoteKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -5,5 +5,5 @@
|
|||||||
#define STRINGIZE(x) #x
|
#define STRINGIZE(x) #x
|
||||||
#define EXPAND(x) STRINGIZE(x)
|
#define EXPAND(x) STRINGIZE(x)
|
||||||
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST manifest.xml
|
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST manifest.xml
|
||||||
wintun.dll RCDATA wintun.dll
|
7 ICON ui/wiretrustee.ico
|
||||||
|
wireguard.dll RCDATA wireguard.dll
|
||||||
|
Binary file not shown.
27
client/wireguard_nt.sh
Normal file
27
client/wireguard_nt.sh
Normal file
@ -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
|
122
iface/configuration.go
Normal file
122
iface/configuration.go
Normal file
@ -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)
|
||||||
|
}
|
238
iface/iface.go
238
iface/iface.go
@ -1,78 +1,51 @@
|
|||||||
package iface
|
package iface
|
||||||
|
|
||||||
import (
|
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"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"os"
|
||||||
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultMTU = 1280
|
DefaultMTU = 1280
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// WGIface represents a interface instance
|
||||||
tunIface tun.Device
|
type WGIface struct {
|
||||||
)
|
Name string
|
||||||
|
Port int
|
||||||
// CreateWithUserspace Creates a new Wireguard interface, using wireguard-go userspace implementation
|
MTU int
|
||||||
func CreateWithUserspace(iface string, address string) error {
|
Address WGAddress
|
||||||
var err error
|
Interface NetInterface
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// configure peer for the wireguard device
|
// WGAddress Wireguard parsed address
|
||||||
func configureDevice(iface string, config wgtypes.Config) error {
|
type WGAddress struct {
|
||||||
wg, err := wgctrl.New()
|
IP net.IP
|
||||||
if err != nil {
|
Network *net.IPNet
|
||||||
return err
|
}
|
||||||
}
|
|
||||||
defer wg.Close()
|
|
||||||
|
|
||||||
_, err = wg.Device(iface)
|
// NetInterface represents a generic network tunnel interface
|
||||||
if err != nil {
|
type NetInterface interface {
|
||||||
return err
|
Close() error
|
||||||
}
|
}
|
||||||
log.Debugf("got Wireguard device %s", iface)
|
|
||||||
|
|
||||||
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
|
// Exists checks whether specified Wireguard device exists or not
|
||||||
@ -99,140 +72,35 @@ func Exists(iface string) (*bool, error) {
|
|||||||
return &exists, nil
|
return &exists, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure configures a Wireguard interface
|
// parseAddress parse a string ("1.2.3.4/24") address to WG Address
|
||||||
// The interface must exist before calling this method (e.g. call interface.Create() before)
|
func parseAddress(address string) (WGAddress, error) {
|
||||||
func Configure(iface string, privateKey string, port int) error {
|
ip, network, err := net.ParseCIDR(address)
|
||||||
|
|
||||||
log.Debugf("configuring Wireguard interface %s", iface)
|
|
||||||
|
|
||||||
log.Debugf("adding Wireguard private key")
|
|
||||||
key, err := wgtypes.ParseKey(privateKey)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return WGAddress{}, err
|
||||||
}
|
}
|
||||||
fwmark := 0
|
return WGAddress{
|
||||||
config := wgtypes.Config{
|
IP: ip,
|
||||||
PrivateKey: &key,
|
Network: network,
|
||||||
ReplacePeers: false,
|
}, nil
|
||||||
FirewallMark: &fwmark,
|
|
||||||
ListenPort: &port,
|
|
||||||
}
|
|
||||||
|
|
||||||
return configureDevice(iface, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListenPort returns the listening port of the Wireguard endpoint
|
// Closes the tunnel interface
|
||||||
func GetListenPort(iface string) (*int, error) {
|
func (w *WGIface) Close() error {
|
||||||
log.Debugf("getting Wireguard listen port of interface %s", iface)
|
|
||||||
|
|
||||||
//discover Wireguard current configuration
|
err := w.Interface.Close()
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
peerKeyParsed, err := wgtypes.ParseKey(peerKey)
|
if runtime.GOOS == "darwin" {
|
||||||
if err != nil {
|
sockPath := "/var/run/wireguard/" + w.Name + ".sock"
|
||||||
return err
|
if _, statErr := os.Stat(sockPath); statErr == nil {
|
||||||
}
|
statErr = os.Remove(sockPath)
|
||||||
peer := wgtypes.PeerConfig{
|
if statErr != nil {
|
||||||
PublicKey: peerKeyParsed,
|
return statErr
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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()
|
|
||||||
}
|
|
||||||
|
@ -2,62 +2,31 @@ package iface
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create Creates a new Wireguard interface, sets a given IP and brings it up.
|
// Create Creates a new Wireguard interface, sets a given IP and brings it up.
|
||||||
func Create(iface string, address string) error {
|
func (w *WGIface) Create() error {
|
||||||
return CreateWithUserspace(iface, address)
|
return w.CreateWithUserspace()
|
||||||
}
|
}
|
||||||
|
|
||||||
// assignAddr Adds IP address to the tunnel interface and network route based on the range provided
|
// 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() error {
|
||||||
ip := strings.Split(address, "/")
|
//mask,_ := w.Address.Network.Mask.Size()
|
||||||
cmd := exec.Command("ifconfig", ifaceName, "inet", address, ip[0])
|
//
|
||||||
|
//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 {
|
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
|
return err
|
||||||
}
|
}
|
||||||
_, resolvedNet, err := net.ParseCIDR(address)
|
|
||||||
err = addRoute(ifaceName, resolvedNet)
|
routeCmd := exec.Command("route", "add", "-net", w.Address.Network.String(), "-interface", w.Name)
|
||||||
if err != nil {
|
if out, err := routeCmd.CombinedOutput(); err != nil {
|
||||||
log.Infoln("Adding route failed with error:", err)
|
log.Printf("adding route command \"%v\" failed with output %s and error: ", routeCmd.String(), out)
|
||||||
}
|
return 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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,35 +1,36 @@
|
|||||||
package iface
|
package iface
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type NativeLink struct {
|
||||||
|
Link *netlink.Link
|
||||||
|
}
|
||||||
|
|
||||||
// Create Creates a new Wireguard interface, sets a given IP and brings it up.
|
// Create Creates a new Wireguard interface, sets a given IP and brings it up.
|
||||||
// Will reuse an existing one.
|
// Will reuse an existing one.
|
||||||
func Create(iface string, address string) error {
|
func (w *WGIface) Create() error {
|
||||||
|
|
||||||
if WireguardModExists() {
|
if WireguardModExists() {
|
||||||
log.Debug("using kernel Wireguard module")
|
log.Debug("using kernel Wireguard module")
|
||||||
return CreateWithKernel(iface, address)
|
return w.CreateWithKernel()
|
||||||
} else {
|
} else {
|
||||||
return CreateWithUserspace(iface, address)
|
return w.CreateWithUserspace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateWithKernel Creates a new Wireguard interface using kernel Wireguard module.
|
// CreateWithKernel Creates a new Wireguard interface using kernel Wireguard module.
|
||||||
// Works for Linux and offers much better network performance
|
// Works for Linux and offers much better network performance
|
||||||
func CreateWithKernel(iface string, address string) error {
|
func (w *WGIface) CreateWithKernel() error {
|
||||||
attrs := netlink.NewLinkAttrs()
|
|
||||||
attrs.Name = iface
|
|
||||||
|
|
||||||
link := wgLink{
|
link := newWGLink(w.Name)
|
||||||
attrs: &attrs,
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if interface exists
|
// check if interface exists
|
||||||
l, err := netlink.LinkByName(iface)
|
l, err := netlink.LinkByName(w.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch err.(type) {
|
switch err.(type) {
|
||||||
case netlink.LinkNotFoundError:
|
case netlink.LinkNotFoundError:
|
||||||
@ -41,37 +42,39 @@ func CreateWithKernel(iface string, address string) error {
|
|||||||
|
|
||||||
// remove if interface exists
|
// remove if interface exists
|
||||||
if l != nil {
|
if l != nil {
|
||||||
err = netlink.LinkDel(&link)
|
err = netlink.LinkDel(link)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("adding device: %s", iface)
|
log.Debugf("adding device: %s", w.Name)
|
||||||
err = netlink.LinkAdd(&link)
|
err = netlink.LinkAdd(link)
|
||||||
if os.IsExist(err) {
|
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 {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = assignAddr(address, iface)
|
w.Interface = link
|
||||||
|
|
||||||
|
err = w.assignAddr()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo do a discovery
|
// todo do a discovery
|
||||||
log.Debugf("setting MTU: %d interface: %s", defaultMTU, iface)
|
log.Debugf("setting MTU: %d interface: %s", w.MTU, w.Name)
|
||||||
err = netlink.LinkSetMTU(&link, defaultMTU)
|
err = netlink.LinkSetMTU(link, w.MTU)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error setting MTU on interface: %s", iface)
|
log.Errorf("error setting MTU on interface: %s", w.Name)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("bringing up interface: %s", iface)
|
log.Debugf("bringing up interface: %s", w.Name)
|
||||||
err = netlink.LinkSetUp(&link)
|
err = netlink.LinkSetUp(link)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error bringing up interface: %s", iface)
|
log.Errorf("error bringing up interface: %s", w.Name)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,39 +82,37 @@ func CreateWithKernel(iface string, address string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// assignAddr Adds IP address to the tunnel interface
|
// assignAddr Adds IP address to the tunnel interface
|
||||||
func assignAddr(address, name string) error {
|
func (w *WGIface) assignAddr() error {
|
||||||
var err error
|
|
||||||
attrs := netlink.NewLinkAttrs()
|
|
||||||
attrs.Name = name
|
|
||||||
|
|
||||||
link := wgLink{
|
mask, _ := w.Address.Network.Mask.Size()
|
||||||
attrs: &attrs,
|
address := fmt.Sprintf("%s/%d", w.Address.IP.String(), mask)
|
||||||
}
|
|
||||||
|
link := newWGLink(w.Name)
|
||||||
|
|
||||||
//delete existing addresses
|
//delete existing addresses
|
||||||
list, err := netlink.AddrList(&link, 0)
|
list, err := netlink.AddrList(link, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(list) > 0 {
|
if len(list) > 0 {
|
||||||
for _, a := range list {
|
for _, a := range list {
|
||||||
err = netlink.AddrDel(&link, &a)
|
err = netlink.AddrDel(link, &a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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)
|
addr, _ := netlink.ParseAddr(address)
|
||||||
err = netlink.AddrAdd(&link, addr)
|
err = netlink.AddrAdd(link, addr)
|
||||||
if os.IsExist(err) {
|
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 {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// On linux, the link must be brought up
|
// On linux, the link must be brought up
|
||||||
err = netlink.LinkSetUp(&link)
|
err = netlink.LinkSetUp(link)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,28 +120,26 @@ type wgLink struct {
|
|||||||
attrs *netlink.LinkAttrs
|
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
|
// Attrs returns the Wireguard's default attributes
|
||||||
func (w *wgLink) Attrs() *netlink.LinkAttrs {
|
func (l *wgLink) Attrs() *netlink.LinkAttrs {
|
||||||
return w.attrs
|
return l.attrs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type returns the interface type
|
// Type returns the interface type
|
||||||
func (w *wgLink) Type() string {
|
func (l *wgLink) Type() string {
|
||||||
return "wireguard"
|
return "wireguard"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the tunnel interface
|
// Close deletes the link interface
|
||||||
func Close(iFace string) error {
|
func (l *wgLink) Close() error {
|
||||||
|
return netlink.LinkDel(l)
|
||||||
if tunIface != nil {
|
|
||||||
return CloseWithUserspace()
|
|
||||||
} else {
|
|
||||||
attrs := netlink.NewLinkAttrs()
|
|
||||||
attrs.Name = iFace
|
|
||||||
|
|
||||||
link := wgLink{
|
|
||||||
attrs: &attrs,
|
|
||||||
}
|
|
||||||
return netlink.LinkDel(&link)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -12,25 +12,36 @@ import (
|
|||||||
|
|
||||||
// keep darwin compability
|
// keep darwin compability
|
||||||
const (
|
const (
|
||||||
key = "0PMI6OkB5JmB+Jj/iWWHekuQRx+bipZirWCWKFXexHc="
|
WgPort = 51000
|
||||||
peerPubKey = "Ok0mC0qlJyXEPKh2UFIpsI2jG0L7LRpC3sLAusSJ5CQ="
|
)
|
||||||
WgPort = 51820
|
|
||||||
|
var (
|
||||||
|
key string
|
||||||
|
peerPubKey string
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
log.SetLevel(log.DebugLevel)
|
log.SetLevel(log.DebugLevel)
|
||||||
|
privateKey, _ := wgtypes.GeneratePrivateKey()
|
||||||
|
key = privateKey.String()
|
||||||
|
peerPrivateKey, _ := wgtypes.GeneratePrivateKey()
|
||||||
|
peerPubKey = peerPrivateKey.PublicKey().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
func Test_CreateInterface(t *testing.T) {
|
func Test_CreateInterface(t *testing.T) {
|
||||||
ifaceName := "utun999"
|
ifaceName := "utun999"
|
||||||
wgIP := "10.99.99.1/24"
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
err = Close(ifaceName)
|
err = iface.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -46,21 +57,54 @@ func Test_CreateInterface(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
func Test_ConfigureInterface(t *testing.T) {
|
|
||||||
ifaceName := "utun1000"
|
func Test_Close(t *testing.T) {
|
||||||
wgIP := "10.99.99.10/24"
|
ifaceName := "utun1004"
|
||||||
err := Create(ifaceName, wgIP)
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
err = Close(ifaceName)
|
err = wg.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -88,28 +132,35 @@ func Test_ConfigureInterface(t *testing.T) {
|
|||||||
func Test_UpdatePeer(t *testing.T) {
|
func Test_UpdatePeer(t *testing.T) {
|
||||||
ifaceName := "utun1001"
|
ifaceName := "utun1001"
|
||||||
wgIP := "10.99.99.20/24"
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
err = Close(ifaceName)
|
err = iface.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
err = Configure(ifaceName, key, WgPort)
|
err = iface.Configure(key, WgPort+2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
keepAlive := 15 * time.Second
|
keepAlive := 15 * time.Second
|
||||||
allowedIP := "10.99.99.2/32"
|
allowedIP := "10.99.99.2/32"
|
||||||
endpoint := "127.0.0.1:9900"
|
endpoint, err := net.ResolveUDPAddr("udp", "127.0.0.1:9900")
|
||||||
err = UpdatePeer(ifaceName, peerPubKey, allowedIP, keepAlive, endpoint, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -117,11 +168,7 @@ func Test_UpdatePeer(t *testing.T) {
|
|||||||
t.Fatal("configured peer with mismatched keepalive interval value")
|
t.Fatal("configured peer with mismatched keepalive interval value")
|
||||||
}
|
}
|
||||||
|
|
||||||
resolvedEndpoint, err := net.ResolveUDPAddr("udp", endpoint)
|
if peer.Endpoint.String() != endpoint.String() {
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if peer.Endpoint.String() != resolvedEndpoint.String() {
|
|
||||||
t.Fatal("configured peer with mismatched endpoint")
|
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) {
|
func Test_RemovePeer(t *testing.T) {
|
||||||
ifaceName := "utun1003"
|
ifaceName := "utun1003"
|
||||||
wgIP := "10.99.99.40/24"
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
err = Close(ifaceName)
|
err = iface.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
err = Configure(ifaceName, key, WgPort)
|
err = iface.Configure(key, WgPort+3)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
keepAlive := 15 * time.Second
|
keepAlive := 15 * time.Second
|
||||||
allowedIP := "10.99.99.2/32"
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = RemovePeer(ifaceName, peerPubKey)
|
err = iface.RemovePeer(peerPubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
_, err = getPeer(ifaceName, t)
|
_, err = getPeer(ifaceName, peerPubKey, t)
|
||||||
if err.Error() != "peer not found" {
|
if err.Error() != "peer not found" {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func Test_Close(t *testing.T) {
|
|
||||||
ifaceName := "utun1004"
|
func Test_ConnectPeers(t *testing.T) {
|
||||||
wgIP := "10.99.99.50/24"
|
peer1ifaceName := fmt.Sprintf("utun%d", 400)
|
||||||
err := Create(ifaceName, wgIP)
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
err = wg.Close()
|
err = iface1.Close()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
err = iface2.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
err = iface1.Configure(peer1Key.String(), peer1Port)
|
||||||
err = Close(ifaceName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
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{}
|
emptyPeer := wgtypes.Peer{}
|
||||||
wg, err := wgctrl.New()
|
wg, err := wgctrl.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1,12 +1,58 @@
|
|||||||
|
//go:build linux || darwin
|
||||||
// +build linux darwin
|
// +build linux darwin
|
||||||
|
|
||||||
package iface
|
package iface
|
||||||
|
|
||||||
import (
|
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/ipc"
|
||||||
|
"golang.zx2c4.com/wireguard/tun"
|
||||||
"net"
|
"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
|
// getUAPI returns a Listener
|
||||||
func getUAPI(iface string) (net.Listener, error) {
|
func getUAPI(iface string) (net.Listener, error) {
|
||||||
tunSock, err := ipc.UAPIOpen(iface)
|
tunSock, err := ipc.UAPIOpen(iface)
|
||||||
|
@ -1,46 +1,47 @@
|
|||||||
package iface
|
package iface
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"golang.zx2c4.com/wireguard/ipc"
|
"golang.org/x/sys/windows"
|
||||||
"golang.zx2c4.com/wireguard/tun"
|
"golang.zx2c4.com/wireguard/windows/driver"
|
||||||
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create Creates a new Wireguard interface, sets a given IP and brings it up.
|
// Create Creates a new Wireguard interface, sets a given IP and brings it up.
|
||||||
func Create(iface string, address string) error {
|
func (w *WGIface) Create() error {
|
||||||
return CreateWithUserspace(iface, address)
|
|
||||||
|
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
|
// 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)
|
log.Debugf("adding address %s to interface: %s", w.Address.IP, w.Name)
|
||||||
luid := winipcfg.LUID(nativeTunDevice.LUID())
|
err := luid.SetIPAddresses([]net.IPNet{{w.Address.IP, w.Address.Network.Mask}})
|
||||||
|
|
||||||
ip, ipnet, _ := net.ParseCIDR(address)
|
|
||||||
|
|
||||||
log.Debugf("adding address %s to interface: %s", address, ifaceName)
|
|
||||||
err := luid.SetIPAddresses([]net.IPNet{{ip, ipnet.Mask}})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
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()
|
|
||||||
}
|
|
||||||
|
@ -93,6 +93,12 @@ var _ = Describe("Client", func() {
|
|||||||
_, err = io.Copy(hashDst, dstFile)
|
_, err = io.Copy(hashDst, dstFile)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
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])))
|
Expect(hex.EncodeToString(hashSrc.Sum(nil)[:16])).To(BeEquivalentTo(hex.EncodeToString(hashDst.Sum(nil)[:16])))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user