mirror of
https://github.com/yggdrasil-network/yggdrasil-go.git
synced 2025-08-27 04:00:21 +00:00
Compare commits
39 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0b9c8bd020 | ||
![]() |
0b9469100c | ||
![]() |
a6429390da | ||
![]() |
1ee61dcefa | ||
![]() |
81e345c1ae | ||
![]() |
a038a6a8ef | ||
![]() |
01e73792fe | ||
![]() |
d22dc9ecc9 | ||
![]() |
874083da79 | ||
![]() |
ccda1075c0 | ||
![]() |
6d5243bd9a | ||
![]() |
377bc664c9 | ||
![]() |
d1b849588f | ||
![]() |
d6fd305f12 | ||
![]() |
98a6fdb4f2 | ||
![]() |
c00779c7d3 | ||
![]() |
43a1a3de64 | ||
![]() |
b8ab843a98 | ||
![]() |
e138fa679c | ||
![]() |
361b9fd6fc | ||
![]() |
5461bb380e | ||
![]() |
34f087de1c | ||
![]() |
c4b29b735c | ||
![]() |
947b6ad7aa | ||
![]() |
340cedbe14 | ||
![]() |
b1283e15f6 | ||
![]() |
ef989bef63 | ||
![]() |
af9ff34995 | ||
![]() |
63cd757525 | ||
![]() |
5e5de3a343 | ||
![]() |
edf179ed26 | ||
![]() |
9950d1225d | ||
![]() |
4fbdeb4e3f | ||
![]() |
5ea16e63a1 | ||
![]() |
da7ebde828 | ||
![]() |
02d92ff81c | ||
![]() |
04c0acf71b | ||
![]() |
8ecc402d7c | ||
![]() |
c505097be0 |
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@@ -17,10 +17,10 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/setup-go@v5
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.21
|
go-version: stable
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v3
|
uses: golangci/golangci-lint-action@v6
|
||||||
with:
|
with:
|
||||||
args: --issues-exit-code=1
|
args: --issues-exit-code=1
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
goversion: ["1.21", "1.22"]
|
goversion: ["1.21", "1.22", "1.23"]
|
||||||
|
|
||||||
name: Build & Test (Linux, Go ${{ matrix.goversion }})
|
name: Build & Test (Linux, Go ${{ matrix.goversion }})
|
||||||
needs: [lint]
|
needs: [lint]
|
||||||
@@ -75,7 +75,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
goversion: ["1.21", "1.22"]
|
goversion: ["1.21", "1.22", "1.23"]
|
||||||
|
|
||||||
name: Build & Test (Windows, Go ${{ matrix.goversion }})
|
name: Build & Test (Windows, Go ${{ matrix.goversion }})
|
||||||
needs: [lint]
|
needs: [lint]
|
||||||
@@ -99,7 +99,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
goversion: ["1.21", "1.22"]
|
goversion: ["1.21", "1.22", "1.23"]
|
||||||
|
|
||||||
name: Build & Test (macOS, Go ${{ matrix.goversion }})
|
name: Build & Test (macOS, Go ${{ matrix.goversion }})
|
||||||
needs: [lint]
|
needs: [lint]
|
||||||
@@ -123,7 +123,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
goversion: ["1.21", "1.22"]
|
goversion: ["1.21", "1.22", "1.23"]
|
||||||
goos:
|
goos:
|
||||||
- freebsd
|
- freebsd
|
||||||
- openbsd
|
- openbsd
|
||||||
|
@@ -2,9 +2,10 @@ run:
|
|||||||
build-tags:
|
build-tags:
|
||||||
- lint
|
- lint
|
||||||
issues-exit-code: 0 # TODO: change this to 1 when we want it to fail builds
|
issues-exit-code: 0 # TODO: change this to 1 when we want it to fail builds
|
||||||
skip-dirs:
|
issues:
|
||||||
|
exclude-dirs:
|
||||||
- contrib/
|
- contrib/
|
||||||
- misc/
|
- misc/
|
||||||
linters:
|
linters:
|
||||||
disable:
|
disable:
|
||||||
- gocyclo
|
- gocyclo
|
||||||
|
51
CHANGELOG.md
51
CHANGELOG.md
@@ -26,6 +26,57 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||||||
- in case of vulnerabilities.
|
- in case of vulnerabilities.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
## [0.5.9] - 2024-10-19
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* New command line option `-user` for changing the process UID/GID
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
* The routing algorithm has been updated with RTT-aware link costing, which should prefer lower latency links over higher latency links where possible
|
||||||
|
* The calculated cost is an average of the link RTT, but newly established links are costed higher to begin with, such that unstable peerings can be avoided
|
||||||
|
* Link costs are only used where multiple next-hops are available and will be ignored if there is only one loop-free path to the destination
|
||||||
|
* This is protocol-compatible with existing v0.5.x nodes but will have the best results when peering with nodes that are also running the latest version
|
||||||
|
* The `getPeers` endpoint will now report the calculated link cost for each given peer
|
||||||
|
* Upgrade dependencies
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Multicast discovery should now work again when building Yggdrasil as an Android framework
|
||||||
|
* Multicast discovery will now correctly ignore interfaces that are not marked as running
|
||||||
|
* Ephemeral links, such as those added by multicast, will no longer try to reconnect in a fast loop, fixing a high CPU issue
|
||||||
|
* The TUN interface will no longer stop working when hitting a segment read error from vectorised reads
|
||||||
|
* The `AllowedPublicKeys` option will once again no longer apply to multicast peerings, as was originally intended
|
||||||
|
* A potential panic when shutting down peering links has been fixed
|
||||||
|
* A redundant system call for setting MTU on OpenBSD has been removed
|
||||||
|
|
||||||
|
## [0.5.8] - 2024-08-12
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* A bug which caused startup problems on Windows and FreeBSD should be fixed
|
||||||
|
* Resolved some minor link state and listener management bugs during shutdown
|
||||||
|
|
||||||
|
## [0.5.7] - 2024-08-05
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* WebSocket support for peerings, by using the new `ws://` scheme in `Listen` and `Peers`
|
||||||
|
* Additionally, the `wss://` scheme can be used to connect to a WebSocket peer behind a HTTPS reverse proxy
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
* On Linux, the TUN adapter now uses vectorised reads/writes where possible, which should reduce the amount of CPU time spent on syscalls and potentially improve throughput
|
||||||
|
* Link error handling has been improved and various link error messages have been rewritten to be clearer
|
||||||
|
* Upgrade dependencies
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Multiple multicast connections to the same remote machine should now work correctly
|
||||||
|
* You may get two connections in some cases, one inbound and one outbound, this is known and will not cause problems
|
||||||
|
* Running as a Windows service should be more reliable with service startup and shutdown bugs fixed
|
||||||
|
|
||||||
## [0.5.6] - 2024-05-30
|
## [0.5.6] - 2024-05-30
|
||||||
|
|
||||||
* Go 1.21 is now required to build Yggdrasil
|
* Go 1.21 is now required to build Yggdrasil
|
||||||
|
10
cmd/yggdrasil/chuser_other.go
Normal file
10
cmd/yggdrasil/chuser_other.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris
|
||||||
|
// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
func chuser(user string) error {
|
||||||
|
return errors.New("setting uid/gid is not supported on this platform")
|
||||||
|
}
|
87
cmd/yggdrasil/chuser_unix.go
Normal file
87
cmd/yggdrasil/chuser_unix.go
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
||||||
|
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
osuser "os/user"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func chuser(user string) error {
|
||||||
|
group := ""
|
||||||
|
if i := strings.IndexByte(user, ':'); i >= 0 {
|
||||||
|
user, group = user[:i], user[i+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
u := (*osuser.User)(nil)
|
||||||
|
g := (*osuser.Group)(nil)
|
||||||
|
|
||||||
|
if user != "" {
|
||||||
|
if _, err := strconv.ParseUint(user, 10, 32); err == nil {
|
||||||
|
u, err = osuser.LookupId(user)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to lookup user by id %q: %v", user, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
u, err = osuser.Lookup(user)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to lookup user by name %q: %v", user, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if group != "" {
|
||||||
|
if _, err := strconv.ParseUint(group, 10, 32); err == nil {
|
||||||
|
g, err = osuser.LookupGroupId(group)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to lookup group by id %q: %v", user, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g, err = osuser.LookupGroup(group)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to lookup group by name %q: %v", user, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if g != nil {
|
||||||
|
gid, _ := strconv.ParseUint(g.Gid, 10, 32)
|
||||||
|
var err error
|
||||||
|
if gid < math.MaxInt {
|
||||||
|
err = syscall.Setgid(int(gid))
|
||||||
|
} else {
|
||||||
|
err = errors.New("gid too big")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to setgid %d: %v", gid, err)
|
||||||
|
}
|
||||||
|
} else if u != nil {
|
||||||
|
gid, _ := strconv.ParseUint(u.Gid, 10, 32)
|
||||||
|
err := syscall.Setgid(int(uint32(gid)))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to setgid %d: %v", gid, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if u != nil {
|
||||||
|
uid, _ := strconv.ParseUint(u.Uid, 10, 32)
|
||||||
|
var err error
|
||||||
|
if uid < math.MaxInt {
|
||||||
|
err = syscall.Setuid(int(uid))
|
||||||
|
} else {
|
||||||
|
err = errors.New("uid too big")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to setuid %d: %v", uid, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@@ -52,14 +52,15 @@ func main() {
|
|||||||
getsnet := flag.Bool("subnet", false, "use in combination with either -useconf or -useconffile, outputs your IPv6 subnet")
|
getsnet := flag.Bool("subnet", false, "use in combination with either -useconf or -useconffile, outputs your IPv6 subnet")
|
||||||
getpkey := flag.Bool("publickey", false, "use in combination with either -useconf or -useconffile, outputs your public key")
|
getpkey := flag.Bool("publickey", false, "use in combination with either -useconf or -useconffile, outputs your public key")
|
||||||
loglevel := flag.String("loglevel", "info", "loglevel to enable")
|
loglevel := flag.String("loglevel", "info", "loglevel to enable")
|
||||||
|
chuserto := flag.String("user", "", "user (and, optionally, group) to set UID/GID to")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
defer close(done)
|
||||||
|
|
||||||
// Catch interrupts from the operating system to exit gracefully.
|
// Catch interrupts from the operating system to exit gracefully.
|
||||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||||
|
|
||||||
// Capture the service being stopped on Windows.
|
|
||||||
minwinsvc.SetOnExit(cancel)
|
|
||||||
|
|
||||||
// Create a new logger that logs output to stdout.
|
// Create a new logger that logs output to stdout.
|
||||||
var logger *log.Logger
|
var logger *log.Logger
|
||||||
switch *logto {
|
switch *logto {
|
||||||
@@ -272,6 +273,22 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Windows service shutdown
|
||||||
|
minwinsvc.SetOnExit(func() {
|
||||||
|
logger.Infof("Shutting down service ...")
|
||||||
|
cancel()
|
||||||
|
// Wait for all parts to shutdown properly
|
||||||
|
<-done
|
||||||
|
})
|
||||||
|
|
||||||
|
// Change user if requested
|
||||||
|
if *chuserto != "" {
|
||||||
|
err = chuser(*chuserto)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Block until we are told to shut down.
|
// Block until we are told to shut down.
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
|
|
||||||
|
@@ -38,7 +38,6 @@ func (cmdLineEnv *CmdLineEnv) parseFlagsAndArgs() {
|
|||||||
fmt.Println("Examples:")
|
fmt.Println("Examples:")
|
||||||
fmt.Println(" - ", os.Args[0], "list")
|
fmt.Println(" - ", os.Args[0], "list")
|
||||||
fmt.Println(" - ", os.Args[0], "getPeers")
|
fmt.Println(" - ", os.Args[0], "getPeers")
|
||||||
fmt.Println(" - ", os.Args[0], "setTunTap name=auto mtu=1500 tap_mode=false")
|
|
||||||
fmt.Println(" - ", os.Args[0], "-endpoint=tcp://localhost:9001 getPeers")
|
fmt.Println(" - ", os.Args[0], "-endpoint=tcp://localhost:9001 getPeers")
|
||||||
fmt.Println(" - ", os.Args[0], "-endpoint=unix:///var/run/ygg.sock getPeers")
|
fmt.Println(" - ", os.Args[0], "-endpoint=unix:///var/run/ygg.sock getPeers")
|
||||||
}
|
}
|
||||||
|
@@ -174,7 +174,7 @@ func run() int {
|
|||||||
if err := json.Unmarshal(recv.Response, &resp); err != nil {
|
if err := json.Unmarshal(recv.Response, &resp); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
table.SetHeader([]string{"URI", "State", "Dir", "IP Address", "Uptime", "RTT", "RX", "TX", "Pr", "Last Error"})
|
table.SetHeader([]string{"URI", "State", "Dir", "IP Address", "Uptime", "RTT", "RX", "TX", "Pr", "Cost", "Last Error"})
|
||||||
for _, peer := range resp.Peers {
|
for _, peer := range resp.Peers {
|
||||||
state, lasterr, dir, rtt := "Up", "-", "Out", "-"
|
state, lasterr, dir, rtt := "Up", "-", "Out", "-"
|
||||||
if !peer.Up {
|
if !peer.Up {
|
||||||
@@ -200,6 +200,7 @@ func run() int {
|
|||||||
peer.RXBytes.String(),
|
peer.RXBytes.String(),
|
||||||
peer.TXBytes.String(),
|
peer.TXBytes.String(),
|
||||||
fmt.Sprintf("%d", peer.Priority),
|
fmt.Sprintf("%d", peer.Priority),
|
||||||
|
fmt.Sprintf("%d", peer.Cost),
|
||||||
lasterr,
|
lasterr,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,7 @@ set -ef
|
|||||||
PKGSRC=${PKGSRC:-github.com/yggdrasil-network/yggdrasil-go/src/version}
|
PKGSRC=${PKGSRC:-github.com/yggdrasil-network/yggdrasil-go/src/version}
|
||||||
PKGNAME=${PKGNAME:-$(sh contrib/semver/name.sh)}
|
PKGNAME=${PKGNAME:-$(sh contrib/semver/name.sh)}
|
||||||
PKGVER=${PKGVER:-$(sh contrib/semver/version.sh --bare)}
|
PKGVER=${PKGVER:-$(sh contrib/semver/version.sh --bare)}
|
||||||
|
GOVER=$(go version | { read _ _ version _; echo ${version#go}; })
|
||||||
|
|
||||||
LDFLAGS="-X $PKGSRC.buildName=$PKGNAME -X $PKGSRC.buildVersion=$PKGVER"
|
LDFLAGS="-X $PKGSRC.buildName=$PKGNAME -X $PKGSRC.buildVersion=$PKGVER"
|
||||||
ARGS="-v"
|
ARGS="-v"
|
||||||
@@ -33,6 +34,15 @@ if [ ! $IOS ] && [ ! $ANDROID ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
ver_le() {
|
||||||
|
printf "$1\n$2\n" | sort -VC
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $ANDROID ] && ver_le 1.23.0 $GOVER ; then
|
||||||
|
# github.com/wlynxg/anet library relies on //go:linkname
|
||||||
|
LDFLAGS="$LDFLAGS -checklinkname=0"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ $IOS ]; then
|
if [ $IOS ]; then
|
||||||
echo "Building framework for iOS"
|
echo "Building framework for iOS"
|
||||||
go get golang.org/x/mobile/bind
|
go get golang.org/x/mobile/bind
|
||||||
|
@@ -15,8 +15,6 @@ import (
|
|||||||
"github.com/yggdrasil-network/yggdrasil-go/src/multicast"
|
"github.com/yggdrasil-network/yggdrasil-go/src/multicast"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/tun"
|
"github.com/yggdrasil-network/yggdrasil-go/src/tun"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/version"
|
"github.com/yggdrasil-network/yggdrasil-go/src/version"
|
||||||
|
|
||||||
_ "golang.org/x/mobile/bind"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Yggdrasil mobile package is meant to "plug the gap" for mobile support, as
|
// Yggdrasil mobile package is meant to "plug the gap" for mobile support, as
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
//go:build ios
|
//go:build ios || darwin
|
||||||
// +build ios
|
// +build ios darwin
|
||||||
|
|
||||||
package mobile
|
package mobile
|
||||||
|
|
@@ -1,5 +1,5 @@
|
|||||||
//go:build !android && !ios
|
//go:build !android && !ios && !darwin
|
||||||
// +build !android,!ios
|
// +build !android,!ios,!darwin
|
||||||
|
|
||||||
package mobile
|
package mobile
|
||||||
|
|
||||||
|
35
go.mod
35
go.mod
@@ -3,21 +3,23 @@ module github.com/yggdrasil-network/yggdrasil-go
|
|||||||
go 1.21
|
go 1.21
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Arceliar/ironwood v0.0.0-20240529054413-b8e59574e2b2
|
github.com/Arceliar/ironwood v0.0.0-20241016082300-f6fb9da97a17
|
||||||
github.com/Arceliar/phony v0.0.0-20220903101357-530938a4b13d
|
github.com/Arceliar/phony v0.0.0-20220903101357-530938a4b13d
|
||||||
github.com/cheggaaa/pb/v3 v3.1.4
|
github.com/cheggaaa/pb/v3 v3.1.5
|
||||||
|
github.com/coder/websocket v1.8.12
|
||||||
github.com/gologme/log v1.3.0
|
github.com/gologme/log v1.3.0
|
||||||
github.com/hashicorp/go-syslog v1.0.0
|
github.com/hashicorp/go-syslog v1.0.0
|
||||||
github.com/hjson/hjson-go/v4 v4.4.0
|
github.com/hjson/hjson-go/v4 v4.4.0
|
||||||
github.com/kardianos/minwinsvc v1.0.2
|
github.com/kardianos/minwinsvc v1.0.2
|
||||||
github.com/quic-go/quic-go v0.44.0
|
github.com/quic-go/quic-go v0.46.0
|
||||||
github.com/vishvananda/netlink v1.1.0
|
github.com/vishvananda/netlink v1.3.0
|
||||||
golang.org/x/crypto v0.23.0
|
github.com/wlynxg/anet v0.0.5
|
||||||
golang.org/x/mobile v0.0.0-20240520174638-fa72addaaa1b
|
golang.org/x/crypto v0.28.0
|
||||||
golang.org/x/net v0.25.0
|
golang.org/x/net v0.30.0
|
||||||
golang.org/x/sys v0.20.0
|
golang.org/x/sys v0.26.0
|
||||||
golang.org/x/text v0.15.0
|
golang.org/x/text v0.19.0
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20230223181233-21636207a675
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2
|
||||||
|
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
|
||||||
golang.zx2c4.com/wireguard/windows v0.5.3
|
golang.zx2c4.com/wireguard/windows v0.5.3
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,18 +32,17 @@ require (
|
|||||||
github.com/onsi/ginkgo/v2 v2.9.5 // indirect
|
github.com/onsi/ginkgo/v2 v2.9.5 // indirect
|
||||||
github.com/rivo/uniseg v0.2.0 // indirect
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
go.uber.org/mock v0.4.0 // indirect
|
go.uber.org/mock v0.4.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||||
golang.org/x/mod v0.17.0 // indirect
|
golang.org/x/mod v0.19.0 // indirect
|
||||||
golang.org/x/sync v0.7.0 // indirect
|
golang.org/x/sync v0.8.0 // indirect
|
||||||
golang.org/x/tools v0.21.0 // indirect
|
golang.org/x/tools v0.23.0 // indirect
|
||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||||
github.com/fatih/color v1.15.0 // indirect
|
github.com/fatih/color v1.15.0 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||||
github.com/olekukonko/tablewriter v0.0.5
|
github.com/olekukonko/tablewriter v0.0.5
|
||||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect
|
github.com/vishvananda/netns v0.0.4 // indirect
|
||||||
)
|
)
|
||||||
|
76
go.sum
76
go.sum
@@ -1,5 +1,5 @@
|
|||||||
github.com/Arceliar/ironwood v0.0.0-20240529054413-b8e59574e2b2 h1:SBdYBKeXYUUFef5wi2CMhYmXFVGiYaRpTvbki0Bu+JQ=
|
github.com/Arceliar/ironwood v0.0.0-20241016082300-f6fb9da97a17 h1:uOvHqPwu09ndYZQDUL6QvyDcz0M9kwooKYa/PEfLwIU=
|
||||||
github.com/Arceliar/ironwood v0.0.0-20240529054413-b8e59574e2b2/go.mod h1:6WP4799FX0OuWdENGQAh+0RXp9FLh0y7NZ7tM9cJyXk=
|
github.com/Arceliar/ironwood v0.0.0-20241016082300-f6fb9da97a17/go.mod h1:6WP4799FX0OuWdENGQAh+0RXp9FLh0y7NZ7tM9cJyXk=
|
||||||
github.com/Arceliar/phony v0.0.0-20220903101357-530938a4b13d h1:UK9fsWbWqwIQkMCz1CP+v5pGbsGoWAw6g4AyvMpm1EM=
|
github.com/Arceliar/phony v0.0.0-20220903101357-530938a4b13d h1:UK9fsWbWqwIQkMCz1CP+v5pGbsGoWAw6g4AyvMpm1EM=
|
||||||
github.com/Arceliar/phony v0.0.0-20220903101357-530938a4b13d/go.mod h1:BCnxhRf47C/dy/e/D2pmB8NkB3dQVIrkD98b220rx5Q=
|
github.com/Arceliar/phony v0.0.0-20220903101357-530938a4b13d/go.mod h1:BCnxhRf47C/dy/e/D2pmB8NkB3dQVIrkD98b220rx5Q=
|
||||||
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
|
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
|
||||||
@@ -9,11 +9,13 @@ github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJR
|
|||||||
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||||
github.com/bits-and-blooms/bloom/v3 v3.7.0 h1:VfknkqV4xI+PsaDIsoHueyxVDZrfvMn56jeWUzvzdls=
|
github.com/bits-and-blooms/bloom/v3 v3.7.0 h1:VfknkqV4xI+PsaDIsoHueyxVDZrfvMn56jeWUzvzdls=
|
||||||
github.com/bits-and-blooms/bloom/v3 v3.7.0/go.mod h1:VKlUSvp0lFIYqxJjzdnSsZEw4iHb1kOL2tfHTgyJBHg=
|
github.com/bits-and-blooms/bloom/v3 v3.7.0/go.mod h1:VKlUSvp0lFIYqxJjzdnSsZEw4iHb1kOL2tfHTgyJBHg=
|
||||||
github.com/cheggaaa/pb/v3 v3.1.4 h1:DN8j4TVVdKu3WxVwcRKu0sG00IIU6FewoABZzXbRQeo=
|
github.com/cheggaaa/pb/v3 v3.1.5 h1:QuuUzeM2WsAqG2gMqtzaWithDJv0i+i6UlnwSCI4QLk=
|
||||||
github.com/cheggaaa/pb/v3 v3.1.4/go.mod h1:6wVjILNBaXMs8c21qRiaUM8BR82erfgau1DQ4iUXmSA=
|
github.com/cheggaaa/pb/v3 v3.1.5/go.mod h1:CrxkeghYTXi1lQBEI7jSn+3svI3cuc19haAj6jM60XI=
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
|
github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo=
|
||||||
|
github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -27,6 +29,8 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg
|
|||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/gologme/log v1.3.0 h1:l781G4dE+pbigClDSDzSaaYKtiueHCILUa/qSDsmHAo=
|
github.com/gologme/log v1.3.0 h1:l781G4dE+pbigClDSDzSaaYKtiueHCILUa/qSDsmHAo=
|
||||||
github.com/gologme/log v1.3.0/go.mod h1:yKT+DvIPdDdDoPtqFrFxheooyVmoqi0BAsw+erN3wA4=
|
github.com/gologme/log v1.3.0/go.mod h1:yKT+DvIPdDdDoPtqFrFxheooyVmoqi0BAsw+erN3wA4=
|
||||||
|
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
||||||
|
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
||||||
@@ -44,8 +48,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
|
|||||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||||
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
|
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
|
||||||
@@ -54,8 +58,8 @@ github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
|
|||||||
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
|
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0=
|
github.com/quic-go/quic-go v0.46.0 h1:uuwLClEEyk1DNvchH8uCByQVjo3yKL9opKulExNDs7Y=
|
||||||
github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek=
|
github.com/quic-go/quic-go v0.46.0/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI=
|
||||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
@@ -63,55 +67,56 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd
|
|||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg=
|
github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg=
|
||||||
github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
|
github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
|
||||||
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
|
github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk=
|
||||||
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs=
|
||||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
|
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
||||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA=
|
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU=
|
||||||
|
github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
|
||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
|
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||||
golang.org/x/mobile v0.0.0-20240520174638-fa72addaaa1b h1:WX7nnnLfCEXg+FmdYZPai2XuP3VqCP1HZVMST0n9DF0=
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||||
golang.org/x/mobile v0.0.0-20240520174638-fa72addaaa1b/go.mod h1:EiXZlVfUTaAyySFVJb9rsODuiO+WXu8HrUuySb7nYFw=
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
|
||||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||||
|
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
@@ -124,26 +129,29 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
|
||||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||||
|
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
|
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
|
||||||
golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
|
||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20230223181233-21636207a675 h1:/J/RVnr7ng4fWPRH3xa4WtBJ1Jp+Auu4YNLmGiPv5QU=
|
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20230223181233-21636207a675/go.mod h1:whfbyDBt09xhCYQWtO2+3UVjlaq6/9hDZrjg2ZE6SyA=
|
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
|
||||||
golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE=
|
golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE=
|
||||||
golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI=
|
golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI=
|
||||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259 h1:TbRPT0HtzFP3Cno1zZo7yPzEEnfu8EjLfl6IU9VfqkQ=
|
||||||
|
gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259/go.mod h1:AVgIgHMwK63XvmAzWG9vLQ41YnVHN0du0tEC46fI7yY=
|
||||||
|
@@ -12,7 +12,7 @@ type AddPeerRequest struct {
|
|||||||
|
|
||||||
type AddPeerResponse struct{}
|
type AddPeerResponse struct{}
|
||||||
|
|
||||||
func (a *AdminSocket) addPeerHandler(req *AddPeerRequest, res *AddPeerResponse) error {
|
func (a *AdminSocket) addPeerHandler(req *AddPeerRequest, _ *AddPeerResponse) error {
|
||||||
u, err := url.Parse(req.Uri)
|
u, err := url.Parse(req.Uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to parse peering URI: %w", err)
|
return fmt.Errorf("unable to parse peering URI: %w", err)
|
||||||
|
@@ -201,10 +201,6 @@ func (a *AdminSocket) SetupAdminHandlers() {
|
|||||||
return res, nil
|
return res, nil
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
//_ = a.AddHandler("getNodeInfo", []string{"key"}, t.proto.nodeinfo.nodeInfoAdminHandler)
|
|
||||||
//_ = a.AddHandler("debug_remoteGetSelf", []string{"key"}, t.proto.getSelfHandler)
|
|
||||||
//_ = a.AddHandler("debug_remoteGetPeers", []string{"key"}, t.proto.getPeersHandler)
|
|
||||||
//_ = a.AddHandler("debug_remoteGetDHT", []string{"key"}, t.proto.getDHTHandler)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsStarted returns true if the module has been started.
|
// IsStarted returns true if the module has been started.
|
||||||
@@ -242,34 +238,33 @@ func (a *AdminSocket) listen() {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
switch strings.ToLower(u.Scheme) {
|
switch strings.ToLower(u.Scheme) {
|
||||||
case "unix":
|
case "unix":
|
||||||
if _, err := os.Stat(listenaddr[7:]); err == nil {
|
if _, err := os.Stat(u.Path); err == nil {
|
||||||
a.log.Debugln("Admin socket", listenaddr[7:], "already exists, trying to clean up")
|
a.log.Debugln("Admin socket", u.Path, "already exists, trying to clean up")
|
||||||
if _, err := net.DialTimeout("unix", listenaddr[7:], time.Second*2); err == nil || err.(net.Error).Timeout() {
|
if _, err := net.DialTimeout("unix", u.Path, time.Second*2); err == nil || err.(net.Error).Timeout() {
|
||||||
a.log.Errorln("Admin socket", listenaddr[7:], "already exists and is in use by another process")
|
a.log.Errorln("Admin socket", u.Path, "already exists and is in use by another process")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
} else {
|
} else {
|
||||||
if err := os.Remove(listenaddr[7:]); err == nil {
|
if err := os.Remove(u.Path); err == nil {
|
||||||
a.log.Debugln(listenaddr[7:], "was cleaned up")
|
a.log.Debugln(u.Path, "was cleaned up")
|
||||||
} else {
|
} else {
|
||||||
a.log.Errorln(listenaddr[7:], "already exists and was not cleaned up:", err)
|
a.log.Errorln(u.Path, "already exists and was not cleaned up:", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
a.listener, err = net.Listen("unix", listenaddr[7:])
|
a.listener, err = net.Listen("unix", u.Path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
switch listenaddr[7:8] {
|
switch u.Path[:1] {
|
||||||
case "@": // maybe abstract namespace
|
case "@": // maybe abstract namespace
|
||||||
default:
|
default:
|
||||||
if err := os.Chmod(listenaddr[7:], 0660); err != nil {
|
if err := os.Chmod(u.Path, 0660); err != nil {
|
||||||
a.log.Warnln("WARNING:", listenaddr[:7], "may have unsafe permissions!")
|
a.log.Warnln("WARNING:", u.Path, "may have unsafe permissions!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "tcp":
|
case "tcp":
|
||||||
a.listener, err = net.Listen("tcp", u.Host)
|
a.listener, err = net.Listen("tcp", u.Host)
|
||||||
default:
|
default:
|
||||||
// err = errors.New(fmt.Sprint("protocol not supported: ", u.Scheme))
|
|
||||||
a.listener, err = net.Listen("tcp", listenaddr)
|
a.listener, err = net.Listen("tcp", listenaddr)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -309,23 +304,6 @@ func (a *AdminSocket) handleRequest(conn net.Conn) {
|
|||||||
|
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
/*
|
|
||||||
defer func() {
|
|
||||||
r := recover()
|
|
||||||
if r != nil {
|
|
||||||
fmt.Println("ERROR:", r)
|
|
||||||
a.log.Debugln("Admin socket error:", r)
|
|
||||||
if err := encoder.Encode(&ErrorResponse{
|
|
||||||
Error: "Check your syntax and input types",
|
|
||||||
}); err != nil {
|
|
||||||
fmt.Println("ERROR 2:", err)
|
|
||||||
a.log.Debugln("Admin socket JSON encode error:", err)
|
|
||||||
}
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
*/
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
var err error
|
var err error
|
||||||
var buf json.RawMessage
|
var buf json.RawMessage
|
||||||
|
@@ -3,7 +3,7 @@ package admin
|
|||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"net"
|
"net"
|
||||||
"sort"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
@@ -23,7 +23,7 @@ type PathEntry struct {
|
|||||||
Sequence uint64 `json:"sequence"`
|
Sequence uint64 `json:"sequence"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AdminSocket) getPathsHandler(req *GetPathsRequest, res *GetPathsResponse) error {
|
func (a *AdminSocket) getPathsHandler(_ *GetPathsRequest, res *GetPathsResponse) error {
|
||||||
paths := a.core.GetPaths()
|
paths := a.core.GetPaths()
|
||||||
res.Paths = make([]PathEntry, 0, len(paths))
|
res.Paths = make([]PathEntry, 0, len(paths))
|
||||||
for _, p := range paths {
|
for _, p := range paths {
|
||||||
@@ -35,8 +35,8 @@ func (a *AdminSocket) getPathsHandler(req *GetPathsRequest, res *GetPathsRespons
|
|||||||
Sequence: p.Sequence,
|
Sequence: p.Sequence,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
sort.SliceStable(res.Paths, func(i, j int) bool {
|
slices.SortStableFunc(res.Paths, func(a, b PathEntry) int {
|
||||||
return strings.Compare(res.Paths[i].PublicKey, res.Paths[j].PublicKey) < 0
|
return strings.Compare(a.PublicKey, b.PublicKey)
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,8 @@ package admin
|
|||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"net"
|
"net"
|
||||||
"sort"
|
"slices"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
@@ -24,6 +25,7 @@ type PeerEntry struct {
|
|||||||
PublicKey string `json:"key"`
|
PublicKey string `json:"key"`
|
||||||
Port uint64 `json:"port"`
|
Port uint64 `json:"port"`
|
||||||
Priority uint64 `json:"priority"`
|
Priority uint64 `json:"priority"`
|
||||||
|
Cost uint64 `json:"cost"`
|
||||||
RXBytes DataUnit `json:"bytes_recvd,omitempty"`
|
RXBytes DataUnit `json:"bytes_recvd,omitempty"`
|
||||||
TXBytes DataUnit `json:"bytes_sent,omitempty"`
|
TXBytes DataUnit `json:"bytes_sent,omitempty"`
|
||||||
Uptime float64 `json:"uptime,omitempty"`
|
Uptime float64 `json:"uptime,omitempty"`
|
||||||
@@ -32,7 +34,7 @@ type PeerEntry struct {
|
|||||||
LastError string `json:"last_error,omitempty"`
|
LastError string `json:"last_error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AdminSocket) getPeersHandler(req *GetPeersRequest, res *GetPeersResponse) error {
|
func (a *AdminSocket) getPeersHandler(_ *GetPeersRequest, res *GetPeersResponse) error {
|
||||||
peers := a.core.GetPeers()
|
peers := a.core.GetPeers()
|
||||||
res.Peers = make([]PeerEntry, 0, len(peers))
|
res.Peers = make([]PeerEntry, 0, len(peers))
|
||||||
for _, p := range peers {
|
for _, p := range peers {
|
||||||
@@ -41,6 +43,7 @@ func (a *AdminSocket) getPeersHandler(req *GetPeersRequest, res *GetPeersRespons
|
|||||||
Up: p.Up,
|
Up: p.Up,
|
||||||
Inbound: p.Inbound,
|
Inbound: p.Inbound,
|
||||||
Priority: uint64(p.Priority), // can't be uint8 thanks to gobind
|
Priority: uint64(p.Priority), // can't be uint8 thanks to gobind
|
||||||
|
Cost: p.Cost,
|
||||||
URI: p.URI,
|
URI: p.URI,
|
||||||
RXBytes: DataUnit(p.RXBytes),
|
RXBytes: DataUnit(p.RXBytes),
|
||||||
TXBytes: DataUnit(p.TXBytes),
|
TXBytes: DataUnit(p.TXBytes),
|
||||||
@@ -59,17 +62,26 @@ func (a *AdminSocket) getPeersHandler(req *GetPeersRequest, res *GetPeersRespons
|
|||||||
}
|
}
|
||||||
res.Peers = append(res.Peers, peer)
|
res.Peers = append(res.Peers, peer)
|
||||||
}
|
}
|
||||||
sort.Slice(res.Peers, func(i, j int) bool {
|
slices.SortStableFunc(res.Peers, func(a, b PeerEntry) int {
|
||||||
if res.Peers[i].Inbound == res.Peers[j].Inbound {
|
if !a.Inbound && b.Inbound {
|
||||||
if res.Peers[i].PublicKey == res.Peers[j].PublicKey {
|
return -1
|
||||||
if res.Peers[i].Priority == res.Peers[j].Priority {
|
|
||||||
return res.Peers[i].Uptime > res.Peers[j].Uptime
|
|
||||||
}
|
|
||||||
return res.Peers[i].Priority < res.Peers[j].Priority
|
|
||||||
}
|
|
||||||
return res.Peers[i].PublicKey < res.Peers[j].PublicKey
|
|
||||||
}
|
}
|
||||||
return !res.Peers[i].Inbound && res.Peers[j].Inbound
|
if a.Inbound && !b.Inbound {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if d := strings.Compare(a.PublicKey, b.PublicKey); d != 0 {
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
if d := a.Priority - b.Priority; d != 0 {
|
||||||
|
return int(d)
|
||||||
|
}
|
||||||
|
if d := a.Cost - b.Cost; d != 0 {
|
||||||
|
return int(d)
|
||||||
|
}
|
||||||
|
if d := a.Uptime - b.Uptime; d != 0 {
|
||||||
|
return int(d)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,7 @@ type GetSelfResponse struct {
|
|||||||
Subnet string `json:"subnet"`
|
Subnet string `json:"subnet"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AdminSocket) getSelfHandler(req *GetSelfRequest, res *GetSelfResponse) error {
|
func (a *AdminSocket) getSelfHandler(_ *GetSelfRequest, res *GetSelfResponse) error {
|
||||||
self := a.core.GetSelf()
|
self := a.core.GetSelf()
|
||||||
snet := a.core.Subnet()
|
snet := a.core.Subnet()
|
||||||
res.BuildName = version.BuildName()
|
res.BuildName = version.BuildName()
|
||||||
|
@@ -3,7 +3,7 @@ package admin
|
|||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"net"
|
"net"
|
||||||
"sort"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
@@ -23,7 +23,7 @@ type SessionEntry struct {
|
|||||||
Uptime float64 `json:"uptime"`
|
Uptime float64 `json:"uptime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AdminSocket) getSessionsHandler(req *GetSessionsRequest, res *GetSessionsResponse) error {
|
func (a *AdminSocket) getSessionsHandler(_ *GetSessionsRequest, res *GetSessionsResponse) error {
|
||||||
sessions := a.core.GetSessions()
|
sessions := a.core.GetSessions()
|
||||||
res.Sessions = make([]SessionEntry, 0, len(sessions))
|
res.Sessions = make([]SessionEntry, 0, len(sessions))
|
||||||
for _, s := range sessions {
|
for _, s := range sessions {
|
||||||
@@ -36,8 +36,8 @@ func (a *AdminSocket) getSessionsHandler(req *GetSessionsRequest, res *GetSessio
|
|||||||
Uptime: s.Uptime.Seconds(),
|
Uptime: s.Uptime.Seconds(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
sort.SliceStable(res.Sessions, func(i, j int) bool {
|
slices.SortStableFunc(res.Sessions, func(a, b SessionEntry) int {
|
||||||
return strings.Compare(res.Sessions[i].PublicKey, res.Sessions[j].PublicKey) < 0
|
return strings.Compare(a.PublicKey, b.PublicKey)
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,7 @@ package admin
|
|||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"net"
|
"net"
|
||||||
"sort"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
@@ -20,11 +20,9 @@ type TreeEntry struct {
|
|||||||
PublicKey string `json:"key"`
|
PublicKey string `json:"key"`
|
||||||
Parent string `json:"parent"`
|
Parent string `json:"parent"`
|
||||||
Sequence uint64 `json:"sequence"`
|
Sequence uint64 `json:"sequence"`
|
||||||
//Port uint64 `json:"port"`
|
|
||||||
//Rest uint64 `json:"rest"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AdminSocket) getTreeHandler(req *GetTreeRequest, res *GetTreeResponse) error {
|
func (a *AdminSocket) getTreeHandler(_ *GetTreeRequest, res *GetTreeResponse) error {
|
||||||
tree := a.core.GetTree()
|
tree := a.core.GetTree()
|
||||||
res.Tree = make([]TreeEntry, 0, len(tree))
|
res.Tree = make([]TreeEntry, 0, len(tree))
|
||||||
for _, d := range tree {
|
for _, d := range tree {
|
||||||
@@ -34,12 +32,10 @@ func (a *AdminSocket) getTreeHandler(req *GetTreeRequest, res *GetTreeResponse)
|
|||||||
PublicKey: hex.EncodeToString(d.Key[:]),
|
PublicKey: hex.EncodeToString(d.Key[:]),
|
||||||
Parent: hex.EncodeToString(d.Parent[:]),
|
Parent: hex.EncodeToString(d.Parent[:]),
|
||||||
Sequence: d.Sequence,
|
Sequence: d.Sequence,
|
||||||
//Port: d.Port,
|
|
||||||
//Rest: d.Rest,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
sort.SliceStable(res.Tree, func(i, j int) bool {
|
slices.SortStableFunc(res.Tree, func(a, b TreeEntry) int {
|
||||||
return strings.Compare(res.Tree[i].PublicKey, res.Tree[j].PublicKey) < 0
|
return strings.Compare(a.PublicKey, b.PublicKey)
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,7 @@ type RemovePeerRequest struct {
|
|||||||
|
|
||||||
type RemovePeerResponse struct{}
|
type RemovePeerResponse struct{}
|
||||||
|
|
||||||
func (a *AdminSocket) removePeerHandler(req *RemovePeerRequest, res *RemovePeerResponse) error {
|
func (a *AdminSocket) removePeerHandler(req *RemovePeerRequest, _ *RemovePeerResponse) error {
|
||||||
u, err := url.Parse(req.Uri)
|
u, err := url.Parse(req.Uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to parse peering URI: %w", err)
|
return fmt.Errorf("unable to parse peering URI: %w", err)
|
||||||
|
@@ -30,6 +30,7 @@ type PeerInfo struct {
|
|||||||
Coords []uint64
|
Coords []uint64
|
||||||
Port uint64
|
Port uint64
|
||||||
Priority uint8
|
Priority uint8
|
||||||
|
Cost uint64
|
||||||
RXBytes uint64
|
RXBytes uint64
|
||||||
TXBytes uint64
|
TXBytes uint64
|
||||||
Uptime time.Duration
|
Uptime time.Duration
|
||||||
@@ -94,6 +95,7 @@ func (c *Core) GetPeers() []PeerInfo {
|
|||||||
peerinfo.Port = p.Port
|
peerinfo.Port = p.Port
|
||||||
peerinfo.Priority = p.Priority
|
peerinfo.Priority = p.Priority
|
||||||
peerinfo.Latency = p.Latency
|
peerinfo.Latency = p.Latency
|
||||||
|
peerinfo.Cost = p.Cost
|
||||||
}
|
}
|
||||||
peers = append(peers, peerinfo)
|
peers = append(peers, peerinfo)
|
||||||
}
|
}
|
||||||
@@ -148,7 +150,14 @@ func (c *Core) GetSessions() []SessionInfo {
|
|||||||
// parsed from a string of the form e.g. "tcp://a.b.c.d:e". In the case of a
|
// parsed from a string of the form e.g. "tcp://a.b.c.d:e". In the case of a
|
||||||
// link-local address, the interface should be provided as the second argument.
|
// link-local address, the interface should be provided as the second argument.
|
||||||
func (c *Core) Listen(u *url.URL, sintf string) (*Listener, error) {
|
func (c *Core) Listen(u *url.URL, sintf string) (*Listener, error) {
|
||||||
return c.links.listen(u, sintf)
|
return c.links.listen(u, sintf, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListenLocal starts a listener, like the Listen function, but is used for
|
||||||
|
// more trustworthy situations where you want to ignore AllowedPublicKeys, i.e.
|
||||||
|
// with multicast listeners.
|
||||||
|
func (c *Core) ListenLocal(u *url.URL, sintf string) (*Listener, error) {
|
||||||
|
return c.links.listen(u, sintf, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Address gets the IPv6 address of the Yggdrasil node. This is always a /128
|
// Address gets the IPv6 address of the Yggdrasil node. This is always a /128
|
||||||
|
@@ -127,7 +127,7 @@ func New(cert *tls.Certificate, logger Logger, opts ...SetupOption) (*Core, erro
|
|||||||
c.log.Errorf("Invalid listener URI %q specified, ignoring\n", listenaddr)
|
c.log.Errorf("Invalid listener URI %q specified, ignoring\n", listenaddr)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, err = c.links.listen(u, ""); err != nil {
|
if _, err = c.links.listen(u, "", false); err != nil {
|
||||||
c.log.Errorf("Failed to start listener %q: %s\n", listenaddr, err)
|
c.log.Errorf("Failed to start listener %q: %s\n", listenaddr, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,6 +25,27 @@ func GetLoggerWithPrefix(prefix string, verbose bool) *log.Logger {
|
|||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func require_NoError(t *testing.T, err error) {
|
||||||
|
t.Helper()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func require_Equal[T comparable](t *testing.T, a, b T) {
|
||||||
|
t.Helper()
|
||||||
|
if a != b {
|
||||||
|
t.Fatalf("%v != %v", a, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func require_True(t *testing.T, a bool) {
|
||||||
|
t.Helper()
|
||||||
|
if !a {
|
||||||
|
t.Fatal("expected true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CreateAndConnectTwo creates two nodes. nodeB connects to nodeA.
|
// CreateAndConnectTwo creates two nodes. nodeB connects to nodeA.
|
||||||
// Verbosity flag is passed to logger.
|
// Verbosity flag is passed to logger.
|
||||||
func CreateAndConnectTwo(t testing.TB, verbose bool) (nodeA *Core, nodeB *Core) {
|
func CreateAndConnectTwo(t testing.TB, verbose bool) (nodeA *Core, nodeB *Core) {
|
||||||
@@ -201,3 +222,69 @@ func BenchmarkCore_Start_Transfer(b *testing.B) {
|
|||||||
}
|
}
|
||||||
<-done
|
<-done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAllowedPublicKeys(t *testing.T) {
|
||||||
|
logger := GetLoggerWithPrefix("", false)
|
||||||
|
cfgA, cfgB := config.GenerateConfig(), config.GenerateConfig()
|
||||||
|
require_NoError(t, cfgA.GenerateSelfSignedCertificate())
|
||||||
|
require_NoError(t, cfgB.GenerateSelfSignedCertificate())
|
||||||
|
|
||||||
|
nodeA, err := New(cfgA.Certificate, logger, AllowedPublicKey("abcdef"))
|
||||||
|
require_NoError(t, err)
|
||||||
|
defer nodeA.Stop()
|
||||||
|
|
||||||
|
nodeB, err := New(cfgB.Certificate, logger)
|
||||||
|
require_NoError(t, err)
|
||||||
|
defer nodeB.Stop()
|
||||||
|
|
||||||
|
u, err := url.Parse("tcp://localhost:0")
|
||||||
|
require_NoError(t, err)
|
||||||
|
|
||||||
|
l, err := nodeA.Listen(u, "")
|
||||||
|
require_NoError(t, err)
|
||||||
|
|
||||||
|
u, err = url.Parse("tcp://" + l.Addr().String())
|
||||||
|
require_NoError(t, err)
|
||||||
|
|
||||||
|
require_NoError(t, nodeB.AddPeer(u, ""))
|
||||||
|
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
|
peers := nodeB.GetPeers()
|
||||||
|
require_Equal(t, len(peers), 1)
|
||||||
|
require_True(t, !peers[0].Up)
|
||||||
|
require_True(t, peers[0].LastError != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAllowedPublicKeysLocal(t *testing.T) {
|
||||||
|
logger := GetLoggerWithPrefix("", false)
|
||||||
|
cfgA, cfgB := config.GenerateConfig(), config.GenerateConfig()
|
||||||
|
require_NoError(t, cfgA.GenerateSelfSignedCertificate())
|
||||||
|
require_NoError(t, cfgB.GenerateSelfSignedCertificate())
|
||||||
|
|
||||||
|
nodeA, err := New(cfgA.Certificate, logger, AllowedPublicKey("abcdef"))
|
||||||
|
require_NoError(t, err)
|
||||||
|
defer nodeA.Stop()
|
||||||
|
|
||||||
|
nodeB, err := New(cfgB.Certificate, logger)
|
||||||
|
require_NoError(t, err)
|
||||||
|
defer nodeB.Stop()
|
||||||
|
|
||||||
|
u, err := url.Parse("tcp://localhost:0")
|
||||||
|
require_NoError(t, err)
|
||||||
|
|
||||||
|
l, err := nodeA.ListenLocal(u, "")
|
||||||
|
require_NoError(t, err)
|
||||||
|
|
||||||
|
u, err = url.Parse("tcp://" + l.Addr().String())
|
||||||
|
require_NoError(t, err)
|
||||||
|
|
||||||
|
require_NoError(t, nodeB.AddPeer(u, ""))
|
||||||
|
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
|
peers := nodeB.GetPeers()
|
||||||
|
require_Equal(t, len(peers), 1)
|
||||||
|
require_True(t, peers[0].Up)
|
||||||
|
require_True(t, peers[0].LastError == nil)
|
||||||
|
}
|
||||||
|
145
src/core/link.go
145
src/core/link.go
@@ -4,10 +4,10 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -38,8 +38,11 @@ type links struct {
|
|||||||
unix *linkUNIX // UNIX interface support
|
unix *linkUNIX // UNIX interface support
|
||||||
socks *linkSOCKS // SOCKS interface support
|
socks *linkSOCKS // SOCKS interface support
|
||||||
quic *linkQUIC // QUIC interface support
|
quic *linkQUIC // QUIC interface support
|
||||||
|
ws *linkWS // WS interface support
|
||||||
|
wss *linkWSS // WSS interface support
|
||||||
// _links can only be modified safely from within the links actor
|
// _links can only be modified safely from within the links actor
|
||||||
_links map[linkInfo]*link // *link is nil if connection in progress
|
_links map[linkInfo]*link // *link is nil if connection in progress
|
||||||
|
_listeners map[*Listener]context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
type linkProtocol interface {
|
type linkProtocol interface {
|
||||||
@@ -84,13 +87,6 @@ func (l *Listener) Addr() net.Addr {
|
|||||||
return l.listener.Addr()
|
return l.listener.Addr()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Listener) Close() error {
|
|
||||||
l.Cancel()
|
|
||||||
err := l.listener.Close()
|
|
||||||
<-l.ctx.Done()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *links) init(c *Core) error {
|
func (l *links) init(c *Core) error {
|
||||||
l.core = c
|
l.core = c
|
||||||
l.tcp = l.newLinkTCP()
|
l.tcp = l.newLinkTCP()
|
||||||
@@ -98,33 +94,23 @@ func (l *links) init(c *Core) error {
|
|||||||
l.unix = l.newLinkUNIX()
|
l.unix = l.newLinkUNIX()
|
||||||
l.socks = l.newLinkSOCKS()
|
l.socks = l.newLinkSOCKS()
|
||||||
l.quic = l.newLinkQUIC()
|
l.quic = l.newLinkQUIC()
|
||||||
|
l.ws = l.newLinkWS()
|
||||||
|
l.wss = l.newLinkWSS()
|
||||||
l._links = make(map[linkInfo]*link)
|
l._links = make(map[linkInfo]*link)
|
||||||
|
l._listeners = make(map[*Listener]context.CancelFunc)
|
||||||
var listeners []ListenAddress
|
|
||||||
phony.Block(c, func() {
|
|
||||||
listeners = make([]ListenAddress, 0, len(c.config._listeners))
|
|
||||||
for listener := range c.config._listeners {
|
|
||||||
listeners = append(listeners, listener)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *links) shutdown() {
|
func (l *links) shutdown() {
|
||||||
phony.Block(l.tcp, func() {
|
phony.Block(l, func() {
|
||||||
for l := range l.tcp._listeners {
|
for listener := range l._listeners {
|
||||||
_ = l.Close()
|
_ = listener.listener.Close()
|
||||||
}
|
}
|
||||||
})
|
for _, link := range l._links {
|
||||||
phony.Block(l.tls, func() {
|
if link._conn != nil {
|
||||||
for l := range l.tls._listeners {
|
_ = link._conn.Close()
|
||||||
_ = l.Close()
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
phony.Block(l.unix, func() {
|
|
||||||
for l := range l.unix._listeners {
|
|
||||||
_ = l.Close()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -137,7 +123,7 @@ const ErrLinkAlreadyConfigured = linkError("peer is already configured")
|
|||||||
const ErrLinkNotConfigured = linkError("peer is not configured")
|
const ErrLinkNotConfigured = linkError("peer is not configured")
|
||||||
const ErrLinkPriorityInvalid = linkError("priority value is invalid")
|
const ErrLinkPriorityInvalid = linkError("priority value is invalid")
|
||||||
const ErrLinkPinnedKeyInvalid = linkError("pinned public key is invalid")
|
const ErrLinkPinnedKeyInvalid = linkError("pinned public key is invalid")
|
||||||
const ErrLinkPasswordInvalid = linkError("password is invalid")
|
const ErrLinkPasswordInvalid = linkError("invalid password supplied")
|
||||||
const ErrLinkUnrecognisedSchema = linkError("link schema unknown")
|
const ErrLinkUnrecognisedSchema = linkError("link schema unknown")
|
||||||
const ErrLinkMaxBackoffInvalid = linkError("max backoff duration invalid")
|
const ErrLinkMaxBackoffInvalid = linkError("max backoff duration invalid")
|
||||||
|
|
||||||
@@ -350,7 +336,7 @@ func (l *links) add(u *url.URL, sintf string, linkType linkType) error {
|
|||||||
|
|
||||||
// Give the connection to the handler. The handler will block
|
// Give the connection to the handler. The handler will block
|
||||||
// for the lifetime of the connection.
|
// for the lifetime of the connection.
|
||||||
if err = l.handler(linkType, options, lc, resetBackoff); err != nil && err != io.EOF {
|
if err = l.handler(linkType, options, lc, resetBackoff, false); err != nil && err != io.EOF {
|
||||||
l.core.log.Debugf("Link %s error: %s\n", info.uri, err)
|
l.core.log.Debugf("Link %s error: %s\n", info.uri, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,9 +346,11 @@ func (l *links) add(u *url.URL, sintf string, linkType linkType) error {
|
|||||||
_ = lc.Close()
|
_ = lc.Close()
|
||||||
phony.Block(l, func() {
|
phony.Block(l, func() {
|
||||||
state._conn = nil
|
state._conn = nil
|
||||||
if state._err = err; state._err != nil {
|
if err == nil {
|
||||||
state._errtime = time.Now()
|
err = fmt.Errorf("remote side closed the connection")
|
||||||
}
|
}
|
||||||
|
state._err = err
|
||||||
|
state._errtime = time.Now()
|
||||||
})
|
})
|
||||||
|
|
||||||
// If the link is persistently configured, back off if needed
|
// If the link is persistently configured, back off if needed
|
||||||
@@ -371,15 +359,16 @@ func (l *links) add(u *url.URL, sintf string, linkType linkType) error {
|
|||||||
if backoffNow() {
|
if backoffNow() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
// Ephemeral or incoming connections don't reconnect.
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
})
|
})
|
||||||
return retErr
|
return retErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *links) remove(u *url.URL, sintf string, linkType linkType) error {
|
func (l *links) remove(u *url.URL, sintf string, _ linkType) error {
|
||||||
var retErr error
|
var retErr error
|
||||||
phony.Block(l, func() {
|
phony.Block(l, func() {
|
||||||
// Generate the link info and see whether we think we already
|
// Generate the link info and see whether we think we already
|
||||||
@@ -406,7 +395,7 @@ func (l *links) remove(u *url.URL, sintf string, linkType linkType) error {
|
|||||||
return retErr
|
return retErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *links) listen(u *url.URL, sintf string) (*Listener, error) {
|
func (l *links) listen(u *url.URL, sintf string, local bool) (*Listener, error) {
|
||||||
ctx, cancel := context.WithCancel(l.core.ctx)
|
ctx, cancel := context.WithCancel(l.core.ctx)
|
||||||
var protocol linkProtocol
|
var protocol linkProtocol
|
||||||
switch strings.ToLower(u.Scheme) {
|
switch strings.ToLower(u.Scheme) {
|
||||||
@@ -418,6 +407,10 @@ func (l *links) listen(u *url.URL, sintf string) (*Listener, error) {
|
|||||||
protocol = l.unix
|
protocol = l.unix
|
||||||
case "quic":
|
case "quic":
|
||||||
protocol = l.quic
|
protocol = l.quic
|
||||||
|
case "ws":
|
||||||
|
protocol = l.ws
|
||||||
|
case "wss":
|
||||||
|
protocol = l.wss
|
||||||
default:
|
default:
|
||||||
cancel()
|
cancel()
|
||||||
return nil, ErrLinkUnrecognisedSchema
|
return nil, ErrLinkUnrecognisedSchema
|
||||||
@@ -430,7 +423,10 @@ func (l *links) listen(u *url.URL, sintf string) (*Listener, error) {
|
|||||||
li := &Listener{
|
li := &Listener{
|
||||||
listener: listener,
|
listener: listener,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
Cancel: cancel,
|
Cancel: func() {
|
||||||
|
cancel()
|
||||||
|
_ = listener.Close()
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var options linkOptions
|
var options linkOptions
|
||||||
@@ -448,11 +444,18 @@ func (l *links) listen(u *url.URL, sintf string) (*Listener, error) {
|
|||||||
options.password = []byte(p)
|
options.password = []byte(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
phony.Block(l, func() {
|
||||||
|
l._listeners[li] = cancel
|
||||||
|
})
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
l.core.log.Infof("%s listener started on %s", strings.ToUpper(u.Scheme), listener.Addr())
|
l.core.log.Infof("%s listener started on %s", strings.ToUpper(u.Scheme), li.listener.Addr())
|
||||||
defer l.core.log.Infof("%s listener stopped on %s", strings.ToUpper(u.Scheme), listener.Addr())
|
defer l.core.log.Infof("%s listener stopped on %s", strings.ToUpper(u.Scheme), li.listener.Addr())
|
||||||
|
defer phony.Block(l, func() {
|
||||||
|
delete(l._listeners, li)
|
||||||
|
})
|
||||||
for {
|
for {
|
||||||
conn, err := listener.Accept()
|
conn, err := li.listener.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -508,13 +511,22 @@ func (l *links) listen(u *url.URL, sintf string) (*Listener, error) {
|
|||||||
// Store the state of the link so that it can be queried later.
|
// Store the state of the link so that it can be queried later.
|
||||||
l._links[info] = state
|
l._links[info] = state
|
||||||
})
|
})
|
||||||
|
defer phony.Block(l, func() {
|
||||||
|
if l._links[info] == state {
|
||||||
|
delete(l._links, info)
|
||||||
|
}
|
||||||
|
})
|
||||||
if lc == nil {
|
if lc == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give the connection to the handler. The handler will block
|
// Give the connection to the handler. The handler will block
|
||||||
// for the lifetime of the connection.
|
// for the lifetime of the connection.
|
||||||
if err = l.handler(linkTypeIncoming, options, lc, nil); err != nil && err != io.EOF {
|
switch err = l.handler(linkTypeIncoming, options, lc, nil, local); {
|
||||||
|
case err == nil:
|
||||||
|
case errors.Is(err, io.EOF):
|
||||||
|
case errors.Is(err, net.ErrClosed):
|
||||||
|
default:
|
||||||
l.core.log.Debugf("Link %s error: %s\n", u.Host, err)
|
l.core.log.Debugf("Link %s error: %s\n", u.Host, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,11 +534,6 @@ func (l *links) listen(u *url.URL, sintf string) (*Listener, error) {
|
|||||||
// try to close the underlying socket just in case and then
|
// try to close the underlying socket just in case and then
|
||||||
// drop the link state.
|
// drop the link state.
|
||||||
_ = lc.Close()
|
_ = lc.Close()
|
||||||
phony.Block(l, func() {
|
|
||||||
if l._links[info] == state {
|
|
||||||
delete(l._links, info)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}(conn)
|
}(conn)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -546,13 +553,17 @@ func (l *links) connect(ctx context.Context, u *url.URL, info linkInfo, options
|
|||||||
dialer = l.unix
|
dialer = l.unix
|
||||||
case "quic":
|
case "quic":
|
||||||
dialer = l.quic
|
dialer = l.quic
|
||||||
|
case "ws":
|
||||||
|
dialer = l.ws
|
||||||
|
case "wss":
|
||||||
|
dialer = l.wss
|
||||||
default:
|
default:
|
||||||
return nil, ErrLinkUnrecognisedSchema
|
return nil, ErrLinkUnrecognisedSchema
|
||||||
}
|
}
|
||||||
return dialer.dial(ctx, u, info, options)
|
return dialer.dial(ctx, u, info, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *links) handler(linkType linkType, options linkOptions, conn net.Conn, success func()) error {
|
func (l *links) handler(linkType linkType, options linkOptions, conn net.Conn, success func(), local bool) error {
|
||||||
meta := version_getBaseMetadata()
|
meta := version_getBaseMetadata()
|
||||||
meta.publicKey = l.core.public
|
meta.publicKey = l.core.public
|
||||||
meta.priority = options.priority
|
meta.priority = options.priority
|
||||||
@@ -567,7 +578,7 @@ func (l *links) handler(linkType linkType, options linkOptions, conn net.Conn, s
|
|||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
return fmt.Errorf("write handshake: %w", err)
|
return fmt.Errorf("write handshake: %w", err)
|
||||||
case err == nil && n != len(metaBytes):
|
case n != len(metaBytes):
|
||||||
return fmt.Errorf("incomplete handshake send")
|
return fmt.Errorf("incomplete handshake send")
|
||||||
}
|
}
|
||||||
meta = version_metadata{}
|
meta = version_metadata{}
|
||||||
@@ -595,19 +606,21 @@ func (l *links) handler(linkType linkType, options linkOptions, conn net.Conn, s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check if we're authorized to connect to this key / IP
|
// Check if we're authorized to connect to this key / IP
|
||||||
var allowed map[[32]byte]struct{}
|
if !local {
|
||||||
phony.Block(l.core, func() {
|
var allowed map[[32]byte]struct{}
|
||||||
allowed = l.core.config._allowedPublicKeys
|
phony.Block(l.core, func() {
|
||||||
})
|
allowed = l.core.config._allowedPublicKeys
|
||||||
isallowed := len(allowed) == 0
|
})
|
||||||
for k := range allowed {
|
isallowed := len(allowed) == 0
|
||||||
if bytes.Equal(k[:], meta.publicKey) {
|
for k := range allowed {
|
||||||
isallowed = true
|
if bytes.Equal(k[:], meta.publicKey) {
|
||||||
break
|
isallowed = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if linkType == linkTypeIncoming && !isallowed {
|
||||||
|
return fmt.Errorf("node public key %q is not in AllowedPublicKeys", hex.EncodeToString(meta.publicKey))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if linkType == linkTypeIncoming && !isallowed {
|
|
||||||
return fmt.Errorf("node public key %q is not in AllowedPublicKeys", hex.EncodeToString(meta.publicKey))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dir := "outbound"
|
dir := "outbound"
|
||||||
@@ -636,21 +649,11 @@ func (l *links) handler(linkType linkType, options linkOptions, conn net.Conn, s
|
|||||||
l.core.log.Infof("Disconnected %s: %s, source %s; error: %s",
|
l.core.log.Infof("Disconnected %s: %s, source %s; error: %s",
|
||||||
dir, remoteStr, localStr, err)
|
dir, remoteStr, localStr, err)
|
||||||
}
|
}
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func urlForLinkInfo(u url.URL) url.URL {
|
func urlForLinkInfo(u url.URL) url.URL {
|
||||||
u.RawQuery = ""
|
u.RawQuery = ""
|
||||||
if host, _, err := net.SplitHostPort(u.Host); err == nil {
|
|
||||||
if addr, err := netip.ParseAddr(host); err == nil {
|
|
||||||
// For peers that look like multicast peers (i.e.
|
|
||||||
// link-local addresses), we will ignore the port number,
|
|
||||||
// otherwise we might open multiple connections to them.
|
|
||||||
if addr.IsLinkLocalUnicast() {
|
|
||||||
u.Host = fmt.Sprintf("[%s]", addr.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -15,7 +15,6 @@ type linkTCP struct {
|
|||||||
phony.Inbox
|
phony.Inbox
|
||||||
*links
|
*links
|
||||||
listenconfig *net.ListenConfig
|
listenconfig *net.ListenConfig
|
||||||
_listeners map[*Listener]context.CancelFunc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *links) newLinkTCP() *linkTCP {
|
func (l *links) newLinkTCP() *linkTCP {
|
||||||
@@ -24,7 +23,6 @@ func (l *links) newLinkTCP() *linkTCP {
|
|||||||
listenconfig: &net.ListenConfig{
|
listenconfig: &net.ListenConfig{
|
||||||
KeepAlive: -1,
|
KeepAlive: -1,
|
||||||
},
|
},
|
||||||
_listeners: map[*Listener]context.CancelFunc{},
|
|
||||||
}
|
}
|
||||||
lt.listenconfig.Control = lt.tcpContext
|
lt.listenconfig.Control = lt.tcpContext
|
||||||
return lt
|
return lt
|
||||||
|
@@ -28,6 +28,6 @@ func (t *linkTCP) tcpContext(network, address string, c syscall.RawConn) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *linkTCP) getControl(sintf string) func(string, string, syscall.RawConn) error {
|
func (t *linkTCP) getControl(_ string) func(string, string, syscall.RawConn) error {
|
||||||
return t.tcpContext
|
return t.tcpContext
|
||||||
}
|
}
|
||||||
|
@@ -13,10 +13,9 @@ import (
|
|||||||
type linkTLS struct {
|
type linkTLS struct {
|
||||||
phony.Inbox
|
phony.Inbox
|
||||||
*links
|
*links
|
||||||
tcp *linkTCP
|
tcp *linkTCP
|
||||||
listener *net.ListenConfig
|
listener *net.ListenConfig
|
||||||
config *tls.Config
|
config *tls.Config
|
||||||
_listeners map[*Listener]context.CancelFunc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *links) newLinkTLS(tcp *linkTCP) *linkTLS {
|
func (l *links) newLinkTLS(tcp *linkTCP) *linkTLS {
|
||||||
@@ -27,8 +26,7 @@ func (l *links) newLinkTLS(tcp *linkTCP) *linkTLS {
|
|||||||
Control: tcp.tcpContext,
|
Control: tcp.tcpContext,
|
||||||
KeepAlive: -1,
|
KeepAlive: -1,
|
||||||
},
|
},
|
||||||
config: l.core.config.tls.Clone(),
|
config: l.core.config.tls.Clone(),
|
||||||
_listeners: map[*Listener]context.CancelFunc{},
|
|
||||||
}
|
}
|
||||||
return lt
|
return lt
|
||||||
}
|
}
|
||||||
|
@@ -12,9 +12,8 @@ import (
|
|||||||
type linkUNIX struct {
|
type linkUNIX struct {
|
||||||
phony.Inbox
|
phony.Inbox
|
||||||
*links
|
*links
|
||||||
dialer *net.Dialer
|
dialer *net.Dialer
|
||||||
listener *net.ListenConfig
|
listener *net.ListenConfig
|
||||||
_listeners map[*Listener]context.CancelFunc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *links) newLinkUNIX() *linkUNIX {
|
func (l *links) newLinkUNIX() *linkUNIX {
|
||||||
@@ -27,7 +26,6 @@ func (l *links) newLinkUNIX() *linkUNIX {
|
|||||||
listener: &net.ListenConfig{
|
listener: &net.ListenConfig{
|
||||||
KeepAlive: -1,
|
KeepAlive: -1,
|
||||||
},
|
},
|
||||||
_listeners: map[*Listener]context.CancelFunc{},
|
|
||||||
}
|
}
|
||||||
return lt
|
return lt
|
||||||
}
|
}
|
||||||
|
127
src/core/link_ws.go
Normal file
127
src/core/link_ws.go
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Arceliar/phony"
|
||||||
|
"github.com/coder/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
type linkWS struct {
|
||||||
|
phony.Inbox
|
||||||
|
*links
|
||||||
|
listenconfig *net.ListenConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type linkWSConn struct {
|
||||||
|
net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
type linkWSListener struct {
|
||||||
|
ch chan *linkWSConn
|
||||||
|
ctx context.Context
|
||||||
|
httpServer *http.Server
|
||||||
|
listener net.Listener
|
||||||
|
}
|
||||||
|
|
||||||
|
type wsServer struct {
|
||||||
|
ch chan *linkWSConn
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *linkWSListener) Accept() (net.Conn, error) {
|
||||||
|
qs := <-l.ch
|
||||||
|
if qs == nil {
|
||||||
|
return nil, context.Canceled
|
||||||
|
}
|
||||||
|
return qs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *linkWSListener) Addr() net.Addr {
|
||||||
|
return l.listener.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *linkWSListener) Close() error {
|
||||||
|
if err := l.httpServer.Shutdown(l.ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return l.listener.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *wsServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.URL.Path == "/health" || r.URL.Path == "/healthz" {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
_, _ = w.Write([]byte("OK"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := websocket.Accept(w, r, &websocket.AcceptOptions{
|
||||||
|
Subprotocols: []string{"ygg-ws"},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Subprotocol() != "ygg-ws" {
|
||||||
|
c.Close(websocket.StatusPolicyViolation, "client must speak the ygg-ws subprotocol")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.ch <- &linkWSConn{
|
||||||
|
Conn: websocket.NetConn(s.ctx, c, websocket.MessageBinary),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *links) newLinkWS() *linkWS {
|
||||||
|
lt := &linkWS{
|
||||||
|
links: l,
|
||||||
|
listenconfig: &net.ListenConfig{
|
||||||
|
KeepAlive: -1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return lt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *linkWS) dial(ctx context.Context, url *url.URL, info linkInfo, options linkOptions) (net.Conn, error) {
|
||||||
|
wsconn, _, err := websocket.Dial(ctx, url.String(), &websocket.DialOptions{
|
||||||
|
Subprotocols: []string{"ygg-ws"},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &linkWSConn{
|
||||||
|
Conn: websocket.NetConn(ctx, wsconn, websocket.MessageBinary),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *linkWS) listen(ctx context.Context, url *url.URL, _ string) (net.Listener, error) {
|
||||||
|
nl, err := l.listenconfig.Listen(ctx, "tcp", url.Host)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ch := make(chan *linkWSConn)
|
||||||
|
|
||||||
|
httpServer := &http.Server{
|
||||||
|
Handler: &wsServer{
|
||||||
|
ch: ch,
|
||||||
|
ctx: ctx,
|
||||||
|
},
|
||||||
|
BaseContext: func(_ net.Listener) context.Context { return ctx },
|
||||||
|
ReadTimeout: time.Second * 10,
|
||||||
|
WriteTimeout: time.Second * 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
lwl := &linkWSListener{
|
||||||
|
ch: ch,
|
||||||
|
ctx: ctx,
|
||||||
|
httpServer: httpServer,
|
||||||
|
listener: nl,
|
||||||
|
}
|
||||||
|
go lwl.httpServer.Serve(nl) // nolint:errcheck
|
||||||
|
return lwl, nil
|
||||||
|
}
|
43
src/core/link_wss.go
Normal file
43
src/core/link_wss.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/Arceliar/phony"
|
||||||
|
"github.com/coder/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
type linkWSS struct {
|
||||||
|
phony.Inbox
|
||||||
|
*links
|
||||||
|
}
|
||||||
|
|
||||||
|
type linkWSSConn struct {
|
||||||
|
net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *links) newLinkWSS() *linkWSS {
|
||||||
|
lwss := &linkWSS{
|
||||||
|
links: l,
|
||||||
|
}
|
||||||
|
return lwss
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *linkWSS) dial(ctx context.Context, url *url.URL, info linkInfo, options linkOptions) (net.Conn, error) {
|
||||||
|
wsconn, _, err := websocket.Dial(ctx, url.String(), &websocket.DialOptions{
|
||||||
|
Subprotocols: []string{"ygg-ws"},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &linkWSSConn{
|
||||||
|
Conn: websocket.NetConn(ctx, wsconn, websocket.MessageBinary),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *linkWSS) listen(ctx context.Context, url *url.URL, _ string) (net.Listener, error) {
|
||||||
|
return nil, fmt.Errorf("WSS listener not supported, use WS listener behind reverse proxy instead")
|
||||||
|
}
|
@@ -8,7 +8,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"golang.org/x/crypto/blake2b"
|
"golang.org/x/crypto/blake2b"
|
||||||
@@ -38,6 +37,16 @@ const (
|
|||||||
metaPriority // uint8
|
metaPriority // uint8
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type handshakeError string
|
||||||
|
|
||||||
|
func (e handshakeError) Error() string { return string(e) }
|
||||||
|
|
||||||
|
const ErrHandshakeInvalidPreamble = handshakeError("invalid handshake, remote side is not Yggdrasil")
|
||||||
|
const ErrHandshakeInvalidLength = handshakeError("invalid handshake length, possible version mismatch")
|
||||||
|
const ErrHandshakeInvalidPassword = handshakeError("invalid password supplied, check your config")
|
||||||
|
const ErrHandshakeHashFailure = handshakeError("invalid hash length")
|
||||||
|
const ErrHandshakeIncorrectPassword = handshakeError("password does not match remote side")
|
||||||
|
|
||||||
// Gets a base metadata with no keys set, but with the correct version numbers.
|
// Gets a base metadata with no keys set, but with the correct version numbers.
|
||||||
func version_getBaseMetadata() version_metadata {
|
func version_getBaseMetadata() version_metadata {
|
||||||
return version_metadata{
|
return version_metadata{
|
||||||
@@ -77,7 +86,7 @@ func (m *version_metadata) encode(privateKey ed25519.PrivateKey, password []byte
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if n != ed25519.PublicKeySize {
|
if n != ed25519.PublicKeySize {
|
||||||
return nil, fmt.Errorf("hash writer only wrote %d bytes", n)
|
return nil, ErrHandshakeHashFailure
|
||||||
}
|
}
|
||||||
hash := hasher.Sum(nil)
|
hash := hasher.Sum(nil)
|
||||||
bs = append(bs, ed25519.Sign(privateKey, hash)...)
|
bs = append(bs, ed25519.Sign(privateKey, hash)...)
|
||||||
@@ -94,11 +103,11 @@ func (m *version_metadata) decode(r io.Reader, password []byte) error {
|
|||||||
}
|
}
|
||||||
meta := [4]byte{'m', 'e', 't', 'a'}
|
meta := [4]byte{'m', 'e', 't', 'a'}
|
||||||
if !bytes.Equal(bh[:4], meta[:]) {
|
if !bytes.Equal(bh[:4], meta[:]) {
|
||||||
return fmt.Errorf("invalid handshake preamble")
|
return ErrHandshakeInvalidPreamble
|
||||||
}
|
}
|
||||||
hl := binary.BigEndian.Uint16(bh[4:6])
|
hl := binary.BigEndian.Uint16(bh[4:6])
|
||||||
if hl < ed25519.SignatureSize {
|
if hl < ed25519.SignatureSize {
|
||||||
return fmt.Errorf("invalid handshake length")
|
return ErrHandshakeInvalidLength
|
||||||
}
|
}
|
||||||
bs := make([]byte, hl)
|
bs := make([]byte, hl)
|
||||||
if _, err := io.ReadFull(r, bs); err != nil {
|
if _, err := io.ReadFull(r, bs); err != nil {
|
||||||
@@ -132,15 +141,15 @@ func (m *version_metadata) decode(r io.Reader, password []byte) error {
|
|||||||
|
|
||||||
hasher, err := blake2b.New512(password)
|
hasher, err := blake2b.New512(password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid password supplied")
|
return ErrHandshakeInvalidPassword
|
||||||
}
|
}
|
||||||
n, err := hasher.Write(m.publicKey)
|
n, err := hasher.Write(m.publicKey)
|
||||||
if err != nil || n != ed25519.PublicKeySize {
|
if err != nil || n != ed25519.PublicKeySize {
|
||||||
return fmt.Errorf("failed to generate hash")
|
return ErrHandshakeHashFailure
|
||||||
}
|
}
|
||||||
hash := hasher.Sum(nil)
|
hash := hasher.Sum(nil)
|
||||||
if !ed25519.Verify(m.publicKey, hash, sig) {
|
if !ed25519.Verify(m.publicKey, hash, sig) {
|
||||||
return fmt.Errorf("password is incorrect")
|
return ErrHandshakeIncorrectPassword
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,7 @@ type GetMulticastInterfacesResponse struct {
|
|||||||
Interfaces []string `json:"multicast_interfaces"`
|
Interfaces []string `json:"multicast_interfaces"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Multicast) getMulticastInterfacesHandler(req *GetMulticastInterfacesRequest, res *GetMulticastInterfacesResponse) error {
|
func (m *Multicast) getMulticastInterfacesHandler(_ *GetMulticastInterfacesRequest, res *GetMulticastInterfacesResponse) error {
|
||||||
res.Interfaces = []string{}
|
res.Interfaces = []string{}
|
||||||
for _, v := range m.Interfaces() {
|
for _, v := range m.Interfaces() {
|
||||||
res.Interfaces = append(res.Interfaces, v.Name)
|
res.Interfaces = append(res.Interfaces, v.Name)
|
||||||
|
@@ -9,10 +9,12 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Arceliar/phony"
|
"github.com/Arceliar/phony"
|
||||||
"github.com/gologme/log"
|
"github.com/gologme/log"
|
||||||
|
"github.com/wlynxg/anet"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/core"
|
"github.com/yggdrasil-network/yggdrasil-go/src/core"
|
||||||
"golang.org/x/crypto/blake2b"
|
"golang.org/x/crypto/blake2b"
|
||||||
@@ -28,7 +30,7 @@ type Multicast struct {
|
|||||||
core *core.Core
|
core *core.Core
|
||||||
log *log.Logger
|
log *log.Logger
|
||||||
sock *ipv6.PacketConn
|
sock *ipv6.PacketConn
|
||||||
_isOpen bool
|
running atomic.Bool
|
||||||
_listeners map[string]*listenerInfo
|
_listeners map[string]*listenerInfo
|
||||||
_interfaces map[string]*interfaceInfo
|
_interfaces map[string]*interfaceInfo
|
||||||
_timer *time.Timer
|
_timer *time.Timer
|
||||||
@@ -79,7 +81,7 @@ func New(core *core.Core, log *log.Logger, opts ...SetupOption) (*Multicast, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Multicast) _start() error {
|
func (m *Multicast) _start() error {
|
||||||
if m._isOpen {
|
if !m.running.CompareAndSwap(false, true) {
|
||||||
return fmt.Errorf("multicast module is already started")
|
return fmt.Errorf("multicast module is already started")
|
||||||
}
|
}
|
||||||
var anyEnabled bool
|
var anyEnabled bool
|
||||||
@@ -87,12 +89,14 @@ func (m *Multicast) _start() error {
|
|||||||
anyEnabled = anyEnabled || intf.Beacon || intf.Listen
|
anyEnabled = anyEnabled || intf.Beacon || intf.Listen
|
||||||
}
|
}
|
||||||
if !anyEnabled {
|
if !anyEnabled {
|
||||||
|
m.running.Store(false)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
m.log.Debugln("Starting multicast module")
|
m.log.Debugln("Starting multicast module")
|
||||||
defer m.log.Debugln("Started multicast module")
|
defer m.log.Debugln("Started multicast module")
|
||||||
addr, err := net.ResolveUDPAddr("udp", string(m.config._groupAddr))
|
addr, err := net.ResolveUDPAddr("udp", string(m.config._groupAddr))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
m.running.Store(false)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
listenString := fmt.Sprintf("[::]:%v", addr.Port)
|
listenString := fmt.Sprintf("[::]:%v", addr.Port)
|
||||||
@@ -101,6 +105,7 @@ func (m *Multicast) _start() error {
|
|||||||
}
|
}
|
||||||
conn, err := lc.ListenPacket(context.Background(), "udp6", listenString)
|
conn, err := lc.ListenPacket(context.Background(), "udp6", listenString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
m.running.Store(false)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
m.sock = ipv6.NewPacketConn(conn)
|
m.sock = ipv6.NewPacketConn(conn)
|
||||||
@@ -108,7 +113,6 @@ func (m *Multicast) _start() error {
|
|||||||
// Windows can't set this flag, so we need to handle it in other ways
|
// Windows can't set this flag, so we need to handle it in other ways
|
||||||
}
|
}
|
||||||
|
|
||||||
m._isOpen = true
|
|
||||||
go m.listen()
|
go m.listen()
|
||||||
m.Act(nil, m._multicastStarted)
|
m.Act(nil, m._multicastStarted)
|
||||||
m.Act(nil, m._announce)
|
m.Act(nil, m._announce)
|
||||||
@@ -118,11 +122,7 @@ func (m *Multicast) _start() error {
|
|||||||
|
|
||||||
// IsStarted returns true if the module has been started.
|
// IsStarted returns true if the module has been started.
|
||||||
func (m *Multicast) IsStarted() bool {
|
func (m *Multicast) IsStarted() bool {
|
||||||
var isOpen bool
|
return m.running.Load()
|
||||||
phony.Block(m, func() {
|
|
||||||
isOpen = m._isOpen
|
|
||||||
})
|
|
||||||
return isOpen
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop stops the multicast module.
|
// Stop stops the multicast module.
|
||||||
@@ -136,8 +136,10 @@ func (m *Multicast) Stop() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Multicast) _stop() error {
|
func (m *Multicast) _stop() error {
|
||||||
|
if !m.running.CompareAndSwap(true, false) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
m.log.Infoln("Stopping multicast module")
|
m.log.Infoln("Stopping multicast module")
|
||||||
m._isOpen = false
|
|
||||||
if m.sock != nil {
|
if m.sock != nil {
|
||||||
m.sock.Close()
|
m.sock.Close()
|
||||||
}
|
}
|
||||||
@@ -147,7 +149,8 @@ func (m *Multicast) _stop() error {
|
|||||||
func (m *Multicast) _updateInterfaces() {
|
func (m *Multicast) _updateInterfaces() {
|
||||||
interfaces := m._getAllowedInterfaces()
|
interfaces := m._getAllowedInterfaces()
|
||||||
for name, info := range interfaces {
|
for name, info := range interfaces {
|
||||||
addrs, err := info.iface.Addrs()
|
// 'anet' package is used here to avoid https://github.com/golang/go/issues/40569
|
||||||
|
addrs, err := anet.InterfaceAddrsByInterface(&info.iface)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.log.Warnf("Failed up get addresses for interface %s: %s", name, err)
|
m.log.Warnf("Failed up get addresses for interface %s: %s", name, err)
|
||||||
delete(interfaces, name)
|
delete(interfaces, name)
|
||||||
@@ -155,6 +158,7 @@ func (m *Multicast) _updateInterfaces() {
|
|||||||
}
|
}
|
||||||
info.addrs = addrs
|
info.addrs = addrs
|
||||||
interfaces[name] = info
|
interfaces[name] = info
|
||||||
|
m.log.Debugf("Discovered addresses for interface %s: %s", name, addrs)
|
||||||
}
|
}
|
||||||
m._interfaces = interfaces
|
m._interfaces = interfaces
|
||||||
}
|
}
|
||||||
@@ -173,10 +177,11 @@ func (m *Multicast) Interfaces() map[string]net.Interface {
|
|||||||
func (m *Multicast) _getAllowedInterfaces() map[string]*interfaceInfo {
|
func (m *Multicast) _getAllowedInterfaces() map[string]*interfaceInfo {
|
||||||
interfaces := make(map[string]*interfaceInfo)
|
interfaces := make(map[string]*interfaceInfo)
|
||||||
// Ask the system for network interfaces
|
// Ask the system for network interfaces
|
||||||
allifaces, err := net.Interfaces()
|
// 'anet' package is used here to avoid https://github.com/golang/go/issues/40569
|
||||||
|
allifaces, err := anet.Interfaces()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Don't panic, since this may be from e.g. too many open files (from too much connection spam)
|
// Don't panic, since this may be from e.g. too many open files (from too much connection spam)
|
||||||
// TODO? log something
|
m.log.Debugf("Failed to get interfaces: %s", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Work out which interfaces to announce on
|
// Work out which interfaces to announce on
|
||||||
@@ -185,6 +190,8 @@ func (m *Multicast) _getAllowedInterfaces() map[string]*interfaceInfo {
|
|||||||
switch {
|
switch {
|
||||||
case iface.Flags&net.FlagUp == 0:
|
case iface.Flags&net.FlagUp == 0:
|
||||||
continue // Ignore interfaces that are down
|
continue // Ignore interfaces that are down
|
||||||
|
case iface.Flags&net.FlagRunning == 0:
|
||||||
|
continue // Ignore interfaces that are not running
|
||||||
case iface.Flags&net.FlagMulticast == 0:
|
case iface.Flags&net.FlagMulticast == 0:
|
||||||
continue // Ignore non-multicast interfaces
|
continue // Ignore non-multicast interfaces
|
||||||
case iface.Flags&net.FlagPointToPoint != 0:
|
case iface.Flags&net.FlagPointToPoint != 0:
|
||||||
@@ -233,7 +240,7 @@ func (m *Multicast) AnnounceNow() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Multicast) _announce() {
|
func (m *Multicast) _announce() {
|
||||||
if !m._isOpen {
|
if !m.running.Load() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
m._updateInterfaces()
|
m._updateInterfaces()
|
||||||
@@ -250,7 +257,7 @@ func (m *Multicast) _announce() {
|
|||||||
for name, info := range m._listeners {
|
for name, info := range m._listeners {
|
||||||
// Prepare our stop function!
|
// Prepare our stop function!
|
||||||
stop := func() {
|
stop := func() {
|
||||||
info.listener.Close()
|
info.listener.Cancel()
|
||||||
delete(m._listeners, name)
|
delete(m._listeners, name)
|
||||||
m.log.Debugln("No longer multicasting on", name)
|
m.log.Debugln("No longer multicasting on", name)
|
||||||
}
|
}
|
||||||
@@ -320,7 +327,7 @@ func (m *Multicast) _announce() {
|
|||||||
Host: net.JoinHostPort(addrIP.String(), fmt.Sprintf("%d", info.port)),
|
Host: net.JoinHostPort(addrIP.String(), fmt.Sprintf("%d", info.port)),
|
||||||
RawQuery: v.Encode(),
|
RawQuery: v.Encode(),
|
||||||
}
|
}
|
||||||
if li, err := m.core.Listen(u, iface.Name); err == nil {
|
if li, err := m.core.ListenLocal(u, iface.Name); err == nil {
|
||||||
m.log.Debugln("Started multicasting on", iface.Name)
|
m.log.Debugln("Started multicasting on", iface.Name)
|
||||||
// Store the listener so that we can stop it later if needed
|
// Store the listener so that we can stop it later if needed
|
||||||
linfo = &listenerInfo{listener: li, time: time.Now(), port: info.port}
|
linfo = &listenerInfo{listener: li, time: time.Now(), port: info.port}
|
||||||
@@ -376,6 +383,9 @@ func (m *Multicast) listen() {
|
|||||||
bs := make([]byte, 2048)
|
bs := make([]byte, 2048)
|
||||||
hb := make([]byte, 0, blake2b.Size) // Reused to reduce hash allocations
|
hb := make([]byte, 0, blake2b.Size) // Reused to reduce hash allocations
|
||||||
for {
|
for {
|
||||||
|
if !m.running.Load() {
|
||||||
|
return
|
||||||
|
}
|
||||||
n, rcm, fromAddr, err := m.sock.ReadFrom(bs)
|
n, rcm, fromAddr, err := m.sock.ReadFrom(bs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !m.IsStarted() {
|
if !m.IsStarted() {
|
||||||
|
@@ -31,7 +31,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (m *Multicast) _multicastStarted() {
|
func (m *Multicast) _multicastStarted() {
|
||||||
if !m._isOpen {
|
if !m.running.Load() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
C.StopAWDLBrowsing()
|
C.StopAWDLBrowsing()
|
||||||
|
@@ -1,42 +1,70 @@
|
|||||||
package tun
|
package tun
|
||||||
|
|
||||||
const TUN_OFFSET_BYTES = 4
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
wgtun "golang.zx2c4.com/wireguard/tun"
|
||||||
|
)
|
||||||
|
|
||||||
|
const TUN_OFFSET_BYTES = 80 // sizeof(virtio_net_hdr)
|
||||||
|
|
||||||
func (tun *TunAdapter) read() {
|
func (tun *TunAdapter) read() {
|
||||||
var buf [TUN_OFFSET_BYTES + 65535]byte
|
vs := tun.iface.BatchSize()
|
||||||
|
bufs := make([][]byte, vs)
|
||||||
|
sizes := make([]int, vs)
|
||||||
|
for i := range bufs {
|
||||||
|
bufs[i] = make([]byte, TUN_OFFSET_BYTES+65535)
|
||||||
|
}
|
||||||
for {
|
for {
|
||||||
n, err := tun.iface.Read(buf[:], TUN_OFFSET_BYTES)
|
n, err := tun.iface.Read(bufs, sizes, TUN_OFFSET_BYTES)
|
||||||
if n <= TUN_OFFSET_BYTES || err != nil {
|
if err != nil {
|
||||||
tun.log.Errorln("Error reading TUN:", err)
|
if errors.Is(err, wgtun.ErrTooManySegments) {
|
||||||
ferr := tun.iface.Flush()
|
tun.log.Debugln("TUN segments dropped: %v", err)
|
||||||
if ferr != nil {
|
continue
|
||||||
tun.log.Errorln("Unable to flush packets:", ferr)
|
|
||||||
}
|
}
|
||||||
|
tun.log.Errorln("Error reading TUN:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
begin := TUN_OFFSET_BYTES
|
for i, b := range bufs[:n] {
|
||||||
end := begin + n
|
if _, err := tun.rwc.Write(b[TUN_OFFSET_BYTES : TUN_OFFSET_BYTES+sizes[i]]); err != nil {
|
||||||
bs := buf[begin:end]
|
tun.log.Debugln("Unable to send packet:", err)
|
||||||
if _, err := tun.rwc.Write(bs); err != nil {
|
}
|
||||||
tun.log.Debugln("Unable to send packet:", err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tun *TunAdapter) write() {
|
func (tun *TunAdapter) queue() {
|
||||||
var buf [TUN_OFFSET_BYTES + 65535]byte
|
|
||||||
for {
|
for {
|
||||||
bs := buf[TUN_OFFSET_BYTES:]
|
p := bufPool.Get().([]byte)[:bufPoolSize]
|
||||||
n, err := tun.rwc.Read(bs)
|
n, err := tun.rwc.Read(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tun.log.Errorln("Exiting TUN writer due to core read error:", err)
|
tun.log.Errorln("Exiting TUN writer due to core read error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
tun.ch <- p[:n]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tun *TunAdapter) write() {
|
||||||
|
vs := cap(tun.ch)
|
||||||
|
bufs := make([][]byte, vs)
|
||||||
|
for i := range bufs {
|
||||||
|
bufs[i] = make([]byte, TUN_OFFSET_BYTES+65535)
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
n := len(tun.ch)
|
||||||
|
if n == 0 {
|
||||||
|
n = 1 // Nothing queued up yet, wait for it instead
|
||||||
|
}
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
msg := <-tun.ch
|
||||||
|
bufs[i] = append(bufs[i][:TUN_OFFSET_BYTES], msg...)
|
||||||
|
bufPool.Put(msg) // nolint:staticcheck
|
||||||
|
}
|
||||||
if !tun.isEnabled {
|
if !tun.isEnabled {
|
||||||
continue // Nothing to do, the tun isn't enabled
|
continue // Nothing to do, the tun isn't enabled
|
||||||
}
|
}
|
||||||
bs = buf[:TUN_OFFSET_BYTES+n]
|
if _, err := tun.iface.Write(bufs[:n], TUN_OFFSET_BYTES); err != nil {
|
||||||
if _, err = tun.iface.Write(bs, TUN_OFFSET_BYTES); err != nil {
|
|
||||||
tun.Act(nil, func() {
|
tun.Act(nil, func() {
|
||||||
if !tun.isOpen {
|
if !tun.isOpen {
|
||||||
tun.log.Errorln("TUN iface write error:", err)
|
tun.log.Errorln("TUN iface write error:", err)
|
||||||
|
@@ -10,9 +10,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/Arceliar/phony"
|
"github.com/Arceliar/phony"
|
||||||
"golang.zx2c4.com/wireguard/tun"
|
wgtun "golang.zx2c4.com/wireguard/tun"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||||
@@ -39,7 +40,7 @@ type TunAdapter struct {
|
|||||||
addr address.Address
|
addr address.Address
|
||||||
subnet address.Subnet
|
subnet address.Subnet
|
||||||
mtu uint64
|
mtu uint64
|
||||||
iface tun.Device
|
iface wgtun.Device
|
||||||
phony.Inbox // Currently only used for _handlePacket from the reader, TODO: all the stuff that currently needs a mutex below
|
phony.Inbox // Currently only used for _handlePacket from the reader, TODO: all the stuff that currently needs a mutex below
|
||||||
isOpen bool
|
isOpen bool
|
||||||
isEnabled bool // Used by the writer to drop sessionTraffic if not enabled
|
isEnabled bool // Used by the writer to drop sessionTraffic if not enabled
|
||||||
@@ -48,6 +49,7 @@ type TunAdapter struct {
|
|||||||
name InterfaceName
|
name InterfaceName
|
||||||
mtu InterfaceMTU
|
mtu InterfaceMTU
|
||||||
}
|
}
|
||||||
|
ch chan []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the maximum supported MTU for the platform based on the defaults in
|
// Gets the maximum supported MTU for the platform based on the defaults in
|
||||||
@@ -145,6 +147,8 @@ func (tun *TunAdapter) _start() error {
|
|||||||
tun.rwc.SetMTU(tun.MTU())
|
tun.rwc.SetMTU(tun.MTU())
|
||||||
tun.isOpen = true
|
tun.isOpen = true
|
||||||
tun.isEnabled = true
|
tun.isEnabled = true
|
||||||
|
tun.ch = make(chan []byte, tun.iface.BatchSize())
|
||||||
|
go tun.queue()
|
||||||
go tun.read()
|
go tun.read()
|
||||||
go tun.write()
|
go tun.write()
|
||||||
return nil
|
return nil
|
||||||
@@ -178,3 +182,12 @@ func (tun *TunAdapter) _stop() error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bufPoolSize = TUN_OFFSET_BYTES + 65535
|
||||||
|
|
||||||
|
var bufPool = sync.Pool{
|
||||||
|
New: func() any {
|
||||||
|
b := [bufPoolSize]byte{}
|
||||||
|
return b[:]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
//go:build openbsd || freebsd
|
//go:build freebsd
|
||||||
// +build openbsd freebsd
|
// +build freebsd
|
||||||
|
|
||||||
package tun
|
package tun
|
||||||
|
|
||||||
@@ -54,11 +54,6 @@ struct in6_ifreq {
|
|||||||
290 };
|
290 };
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type in6_ifreq_mtu struct {
|
|
||||||
ifr_name [syscall.IFNAMSIZ]byte
|
|
||||||
ifru_mtu int
|
|
||||||
}
|
|
||||||
|
|
||||||
type in6_ifreq_addr struct {
|
type in6_ifreq_addr struct {
|
||||||
ifr_name [syscall.IFNAMSIZ]byte
|
ifr_name [syscall.IFNAMSIZ]byte
|
||||||
ifru_addr sockaddr_in6
|
ifru_addr sockaddr_in6
|
||||||
@@ -112,26 +107,6 @@ func (tun *TunAdapter) setupAddress(addr string) error {
|
|||||||
tun.log.Infof("Interface IPv6: %s", addr)
|
tun.log.Infof("Interface IPv6: %s", addr)
|
||||||
tun.log.Infof("Interface MTU: %d", tun.mtu)
|
tun.log.Infof("Interface MTU: %d", tun.mtu)
|
||||||
|
|
||||||
// Create the MTU request
|
|
||||||
var ir in6_ifreq_mtu
|
|
||||||
copy(ir.ifr_name[:], tun.Name())
|
|
||||||
ir.ifru_mtu = int(tun.mtu)
|
|
||||||
|
|
||||||
// Set the MTU
|
|
||||||
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(sfd), uintptr(syscall.SIOCSIFMTU), uintptr(unsafe.Pointer(&ir))); errno != 0 {
|
|
||||||
err = errno
|
|
||||||
tun.log.Errorf("Error in SIOCSIFMTU: %v", errno)
|
|
||||||
|
|
||||||
// Fall back to ifconfig to set the MTU
|
|
||||||
cmd := exec.Command("ifconfig", tun.Name(), "mtu", string(tun.mtu))
|
|
||||||
tun.log.Warnf("Using ifconfig as fallback: %v", strings.Join(cmd.Args, " "))
|
|
||||||
output, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
tun.log.Errorf("SIOCSIFMTU fallback failed: %v.", err)
|
|
||||||
tun.log.Traceln(string(output))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the address request
|
// Create the address request
|
||||||
// FIXME: I don't work!
|
// FIXME: I don't work!
|
||||||
var ar in6_ifreq_addr
|
var ar in6_ifreq_addr
|
122
src/tun/tun_openbsd.go
Normal file
122
src/tun/tun_openbsd.go
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
//go:build openbsd
|
||||||
|
// +build openbsd
|
||||||
|
|
||||||
|
package tun
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
wgtun "golang.zx2c4.com/wireguard/tun"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SIOCAIFADDR_IN6 = 0x8080691a
|
||||||
|
ND6_INFINITE_LIFETIME = 0xffffffff
|
||||||
|
)
|
||||||
|
|
||||||
|
type in6_addrlifetime struct {
|
||||||
|
ia6t_expire int64
|
||||||
|
ia6t_preferred int64
|
||||||
|
ia6t_vltime uint32
|
||||||
|
ia6t_pltime uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match types from the net package, effectively being [16]byte for IPv6 addresses.
|
||||||
|
type in6_addr [16]uint8
|
||||||
|
|
||||||
|
type sockaddr_in6 struct {
|
||||||
|
sin6_len uint8
|
||||||
|
sin6_family uint8
|
||||||
|
sin6_port uint16
|
||||||
|
sin6_flowinfo uint32
|
||||||
|
sin6_addr in6_addr
|
||||||
|
sin6_scope_id uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sa6 *sockaddr_in6) setSockaddr(addr [/*16*/]byte /* net.IP or net.IPMask */) {
|
||||||
|
sa6.sin6_len = uint8(unsafe.Sizeof(*sa6))
|
||||||
|
sa6.sin6_family = unix.AF_INET6
|
||||||
|
|
||||||
|
for i := range sa6.sin6_addr {
|
||||||
|
sa6.sin6_addr[i] = addr[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type in6_aliasreq struct {
|
||||||
|
ifra_name [syscall.IFNAMSIZ]byte
|
||||||
|
ifra_addr sockaddr_in6
|
||||||
|
ifra_dstaddr sockaddr_in6
|
||||||
|
ifra_prefixmask sockaddr_in6
|
||||||
|
ifra_flags int32
|
||||||
|
ifra_lifetime in6_addrlifetime
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configures the TUN adapter with the correct IPv6 address and MTU.
|
||||||
|
func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error {
|
||||||
|
iface, err := wgtun.CreateTUN(ifname, int(mtu))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create TUN: %w", err)
|
||||||
|
}
|
||||||
|
tun.iface = iface
|
||||||
|
if mtu, err := iface.MTU(); err == nil {
|
||||||
|
tun.mtu = getSupportedMTU(uint64(mtu))
|
||||||
|
} else {
|
||||||
|
tun.mtu = 0
|
||||||
|
}
|
||||||
|
if addr != "" {
|
||||||
|
return tun.setupAddress(addr)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configures the "utun" adapter from an existing file descriptor.
|
||||||
|
func (tun *TunAdapter) setupFD(fd int32, addr string, mtu uint64) error {
|
||||||
|
return fmt.Errorf("setup via FD not supported on this platform")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tun *TunAdapter) setupAddress(addr string) error {
|
||||||
|
var sfd int
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ip, prefix, err := net.ParseCIDR(addr)
|
||||||
|
if err != nil {
|
||||||
|
tun.log.Errorf("Error in ParseCIDR: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create system socket
|
||||||
|
if sfd, err = unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, 0); err != nil {
|
||||||
|
tun.log.Printf("Create AF_INET6 socket failed: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Friendly output
|
||||||
|
tun.log.Infof("Interface name: %s", tun.Name())
|
||||||
|
tun.log.Infof("Interface IPv6: %s", addr)
|
||||||
|
tun.log.Infof("Interface MTU: %d", tun.mtu)
|
||||||
|
|
||||||
|
// Create the address request
|
||||||
|
var ar in6_aliasreq
|
||||||
|
copy(ar.ifra_name[:], tun.Name())
|
||||||
|
|
||||||
|
ar.ifra_addr.setSockaddr(ip)
|
||||||
|
|
||||||
|
prefixmask := net.CIDRMask(prefix.Mask.Size())
|
||||||
|
ar.ifra_prefixmask.setSockaddr(prefixmask)
|
||||||
|
|
||||||
|
ar.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME
|
||||||
|
ar.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME
|
||||||
|
|
||||||
|
// Set the interface address
|
||||||
|
if err = unix.IoctlSetInt(sfd, SIOCAIFADDR_IN6, int(uintptr(unsafe.Pointer(&ar)))); err != nil {
|
||||||
|
tun.log.Errorf("Error in SIOCAIFADDR_IN6: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@@ -8,10 +8,12 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
|
|
||||||
|
"golang.zx2c4.com/wintun"
|
||||||
wgtun "golang.zx2c4.com/wireguard/tun"
|
wgtun "golang.zx2c4.com/wireguard/tun"
|
||||||
"golang.zx2c4.com/wireguard/windows/elevate"
|
"golang.zx2c4.com/wireguard/windows/elevate"
|
||||||
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||||
@@ -31,11 +33,23 @@ func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error {
|
|||||||
if guid, err = windows.GUIDFromString("{8f59971a-7872-4aa6-b2eb-061fc4e9d0a7}"); err != nil {
|
if guid, err = windows.GUIDFromString("{8f59971a-7872-4aa6-b2eb-061fc4e9d0a7}"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if iface, err = wgtun.CreateTUNWithRequestedGUID(ifname, &guid, int(mtu)); err != nil {
|
iface, err = wgtun.CreateTUNWithRequestedGUID(ifname, &guid, int(mtu))
|
||||||
return err
|
if err != nil {
|
||||||
|
// Very rare condition, it will purge the old device and create new
|
||||||
|
tun.log.Printf("Error creating TUN: '%s'", err)
|
||||||
|
wintun.Uninstall()
|
||||||
|
time.Sleep(3 * time.Second)
|
||||||
|
tun.log.Printf("Trying again")
|
||||||
|
iface, err = wgtun.CreateTUNWithRequestedGUID(ifname, &guid, int(mtu))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
tun.log.Printf("Waiting for TUN to come up")
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
tun.iface = iface
|
tun.iface = iface
|
||||||
if addr != "" {
|
if addr != "" {
|
||||||
|
tun.log.Printf("Setting up address")
|
||||||
if err = tun.setupAddress(addr); err != nil {
|
if err = tun.setupAddress(addr); err != nil {
|
||||||
tun.log.Errorln("Failed to set up TUN address:", err)
|
tun.log.Errorln("Failed to set up TUN address:", err)
|
||||||
return err
|
return err
|
||||||
@@ -48,6 +62,7 @@ func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error {
|
|||||||
if mtu, err := iface.MTU(); err == nil {
|
if mtu, err := iface.MTU(); err == nil {
|
||||||
tun.mtu = uint64(mtu)
|
tun.mtu = uint64(mtu)
|
||||||
}
|
}
|
||||||
|
tun.log.Printf("TUN is set up successfully")
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user