mirror of
https://github.com/yggdrasil-network/yggstack.git
synced 2025-07-07 00:15:08 +03:00
Compare commits
39 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8ad1962f64 | ||
![]() |
83bc9a2eec | ||
![]() |
696625c14f | ||
![]() |
763e4db047 | ||
![]() |
c65f79d01a | ||
![]() |
58b3efd2da | ||
![]() |
bfc106637a | ||
![]() |
08f51fded2 | ||
![]() |
7a72fe25ab | ||
![]() |
873b19b7c6 | ||
![]() |
98b1a1c79d | ||
![]() |
b132d6af16 | ||
![]() |
4844607750 | ||
![]() |
9395ddbfa2 | ||
![]() |
5a87e43f9a | ||
![]() |
fef083ae4a | ||
![]() |
95a41a3e8f | ||
![]() |
3be03c793f | ||
![]() |
b534d1205e | ||
![]() |
1eb9a94d2c | ||
![]() |
9da884697a | ||
![]() |
f0eecd21d4 | ||
![]() |
8a6c67475c | ||
![]() |
2c09a1d7b2 | ||
![]() |
5008a4ea2d | ||
![]() |
457b1d99c5 | ||
![]() |
f529064aa0 | ||
![]() |
0783b429fd | ||
![]() |
30d51ba566 | ||
![]() |
b160b3f66d | ||
![]() |
582fe511fa | ||
![]() |
dcc0284e3b | ||
![]() |
174bb7026d | ||
![]() |
edbaa72445 | ||
![]() |
7b5300a476 | ||
![]() |
5520ef03bf | ||
![]() |
f465d71770 | ||
![]() |
8f21eaa31a | ||
![]() |
3fa4809cd1 |
12 changed files with 1180 additions and 308 deletions
278
.github/workflows/trunk.yml
vendored
278
.github/workflows/trunk.yml
vendored
|
@ -1,8 +1,17 @@
|
|||
name: Trunk build
|
||||
name: Trunk / release build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "README.md"
|
||||
push:
|
||||
branch: develop
|
||||
branches:
|
||||
- develop
|
||||
tags:
|
||||
- 'v[0-9]+.[0-9]+.[0-9]+'
|
||||
- '[0-9]+.[0-9]+.[0-9]+'
|
||||
- 'v[0-9]+.[0-9]+.[0-9]+-[0-9]+'
|
||||
- '[0-9]+.[0-9]+.[0-9]+-[0-9]+'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
@ -10,69 +19,246 @@ concurrency:
|
|||
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
name: Build Windows/Linux/MacOS/FreeBSD/Android
|
||||
runs-on: ubuntu-20.04
|
||||
name: Build Windows/Linux-static/MacOS/*BSD-static/Android
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.21"
|
||||
go-version: '1.22'
|
||||
|
||||
- name: Build static executables
|
||||
- name: Check if commit needs a release upload
|
||||
run: |
|
||||
GOOS=windows GOARCH=arm GOARM=7 ./build -o yggstack-windows-armv7.exe
|
||||
GOOS=windows GOARCH=arm64 ./build -o yggstack-windows-arm64.exe
|
||||
GOOS=windows GOARCH=386 ./build -o yggstack-windows-i386.exe
|
||||
if [ "${{ github.ref_type }}" = "tag" ]; then
|
||||
echo "RELEASENAME=${{ github.ref_name }}" >> "$GITHUB_ENV"
|
||||
elif [ "${{ github.event_name }}" = "push" ] && [ "${{ github.ref }}" = "refs/heads/develop" ]; then
|
||||
echo "PRERELEASE=--prerelease" >> "$GITHUB_ENV"
|
||||
echo "RELEASENAME=trunk" >> "$GITHUB_ENV"
|
||||
else
|
||||
echo "Not a tag or push to develop branch, skipping upload"
|
||||
echo "SKIP_UPLOAD=1" >> "$GITHUB_ENV"
|
||||
fi
|
||||
|
||||
- name: Build yggstack executables
|
||||
run: |
|
||||
set -e
|
||||
echo "::group::yggstack-windows-amd64.exe"
|
||||
GOOS=windows GOARCH=amd64 ./build -o yggstack-windows-amd64.exe
|
||||
GOOS=linux GOARCH=386 ./build -o yggstack-linux-i386
|
||||
GOOS=linux GOARCH=amd64 ./build -o yggstack-linux-amd64
|
||||
GOOS=linux GOARCH=arm GOARM=6 ./build -o yggstack-linux-armv6
|
||||
GOOS=linux GOARCH=arm GOARM=7 ./build -o yggstack-linux-armv7
|
||||
GOOS=linux GOARCH=arm64 ./build -o yggstack-linux-arm64
|
||||
GOOS=linux GOARCH=mips GOMIPS=softfloat ./build -o yggstack-linux-mips-sf
|
||||
GOOS=linux GOARCH=mipsle GOMIPS=softfloat ./build -o yggstack-linux-mipsle-sf
|
||||
GOOS=linux GOARCH=mips64 ./build -o yggstack-linux-mips64
|
||||
GOOS=linux GOARCH=mips64le ./build -o yggstack-linux-mips64le
|
||||
GOOS=linux GOARCH=ppc64 ./build -o yggstack-linux-ppc64
|
||||
GOOS=linux GOARCH=ppc64le ./build -o yggstack-linux-ppc64le
|
||||
GOOS=linux GOARCH=riscv64 ./build -o yggstack-linux-riscv64
|
||||
GOOS=linux GOARCH=s390x ./build -o yggstack-linux-s390x
|
||||
GOOS=darwin GOARCH=arm64 ./build -o yggstack-darwin-arm64
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-windows-arm64.exe"
|
||||
GOOS=windows GOARCH=arm64 ./build -o yggstack-windows-arm64.exe
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-windows-armv7.exe"
|
||||
GOOS=windows GOARCH=arm GOARM=7 ./build -o yggstack-windows-armv7.exe
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-windows-i386.exe"
|
||||
GOOS=windows GOARCH=386 ./build -o yggstack-windows-i386.exe
|
||||
GOOS=windows GOARCH=386 ./build -o yggstack-windows-386.exe
|
||||
echo "::endgroup::"
|
||||
#
|
||||
# NOTE: Go toolchain does produce dynamically linked binaries
|
||||
# for native-architecture Linux/*BSD. Since we are building on amd64,
|
||||
# request this buid to be fully static like the othe builds
|
||||
echo "::group::yggstack-linux-amd64-static"
|
||||
GOOS=linux GOARCH=amd64 ./build -s -o yggstack-linux-amd64-static
|
||||
! ldd yggstack-linux-amd64-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-linux-arm64-static"
|
||||
GOOS=linux GOARCH=arm64 ./build -o yggstack-linux-arm64-static
|
||||
! ldd yggstack-linux-arm64-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-linux-armv6-static"
|
||||
GOOS=linux GOARCH=arm GOARM=6 ./build -o yggstack-linux-armv6-static
|
||||
! ldd yggstack-linux-armv6-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-linux-armv7-static"
|
||||
GOOS=linux GOARCH=arm GOARM=7 ./build -o yggstack-linux-armv7-static
|
||||
! ldd yggstack-linux-armv7-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-linux-i386-static"
|
||||
GOOS=linux GOARCH=386 ./build -o yggstack-linux-i386-static
|
||||
GOOS=linux GOARCH=386 ./build -o yggstack-linux-386-static
|
||||
! ldd yggstack-linux-i386-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-linux-mips-sf-static"
|
||||
GOOS=linux GOARCH=mips GOMIPS=softfloat ./build -o yggstack-linux-mips-sf-static
|
||||
! ldd yggstack-linux-mips-sf-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-linux-mipsle-sf-static"
|
||||
GOOS=linux GOARCH=mipsle GOMIPS=softfloat ./build -o yggstack-linux-mipsle-sf-static
|
||||
! ldd yggstack-linux-mipsle-sf-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-linux-mips64-static"
|
||||
GOOS=linux GOARCH=mips64 ./build -o yggstack-linux-mips64-static
|
||||
! ldd yggstack-linux-mips64-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-linux-mips64le-static"
|
||||
GOOS=linux GOARCH=mips64le ./build -o yggstack-linux-mips64le-static
|
||||
! ldd yggstack-linux-mips64le-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-linux-ppc64-static"
|
||||
GOOS=linux GOARCH=ppc64 ./build -o yggstack-linux-ppc64-static
|
||||
! ldd yggstack-linux-ppc64-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-linux-ppc64le-static"
|
||||
GOOS=linux GOARCH=ppc64le ./build -o yggstack-linux-ppc64le-static
|
||||
! ldd yggstack-linux-ppc64le-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-linux-riscv64-static"
|
||||
GOOS=linux GOARCH=riscv64 ./build -o yggstack-linux-riscv64-static
|
||||
! ldd yggstack-linux-riscv64-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-linux-s390x-static"
|
||||
GOOS=linux GOARCH=s390x ./build -o yggstack-linux-s390x-static
|
||||
! ldd yggstack-linux-s390x-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-darwin-amd64"
|
||||
GOOS=darwin GOARCH=amd64 ./build -o yggstack-darwin-amd64
|
||||
GOOS=freebsd GOARCH=arm64 ./build -o yggstack-freebsd-arm64
|
||||
GOOS=freebsd GOARCH=amd64 ./build -o yggstack-freebsd-amd64
|
||||
GOOS=freebsd GOARCH=arm GOARM=6 ./build -o yggstack-freebsd-armv6
|
||||
GOOS=freebsd GOARCH=arm GOARM=7 ./build -o yggstack-freebsd-armv7
|
||||
GOOS=freebsd GOARCH=386 ./build -o yggstack-freebsd-i386
|
||||
GOOS=openbsd GOARCH=arm64 ./build -o yggstack-openbsd-arm64
|
||||
GOOS=openbsd GOARCH=amd64 ./build -o yggstack-openbsd-amd64
|
||||
GOOS=openbsd GOARCH=arm GOARM=6 ./build -o yggstack-openbsd-armv6
|
||||
GOOS=openbsd GOARCH=arm GOARM=7 ./build -o yggstack-openbsd-armv7
|
||||
GOOS=openbsd GOARCH=386 ./build -o yggstack-openbsd-i386
|
||||
GOOS=netbsd GOARCH=arm64 ./build -o yggstack-netbsd-arm64
|
||||
GOOS=netbsd GOARCH=amd64 ./build -o yggstack-netbsd-amd64
|
||||
GOOS=netbsd GOARCH=arm GOARM=6 ./build -o yggstack-netbsd-armv6
|
||||
GOOS=netbsd GOARCH=arm GOARM=7 ./build -o yggstack-netbsd-armv7
|
||||
GOOS=netbsd GOARCH=386 ./build -o yggstack-netbsd-i386
|
||||
CC="$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang" GOOS=android GOARCH=arm64 ./build -o yggstack-android-arm64
|
||||
CC="$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android21-clang" GOOS=android GOARCH=amd64 ./build -o yggstack-android-amd64
|
||||
CC="$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi21-clang" GOOS=android GOARCH=arm GOARM=7 ./build -o yggstack-android-armv7
|
||||
CC="$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/i686-linux-android21-clang" GOOS=android GOARCH=386 ./build -o yggstack-android-i386
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-darwin-arm64"
|
||||
GOOS=darwin GOARCH=arm64 ./build -o yggstack-darwin-arm64
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-freebsd-amd64-static"
|
||||
GOOS=freebsd GOARCH=amd64 ./build -o yggstack-freebsd-amd64-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-freebsd-arm64-static"
|
||||
GOOS=freebsd GOARCH=arm64 ./build -o yggstack-freebsd-arm64-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-freebsd-armv6-static"
|
||||
GOOS=freebsd GOARCH=arm GOARM=6 ./build -o yggstack-freebsd-armv6-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-freebsd-armv7-static"
|
||||
GOOS=freebsd GOARCH=arm GOARM=7 ./build -o yggstack-freebsd-armv7-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-freebsd-i386-static"
|
||||
GOOS=freebsd GOARCH=386 ./build -o yggstack-freebsd-i386-static
|
||||
GOOS=freebsd GOARCH=386 ./build -o yggstack-freebsd-386-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-openbsd-amd64-static"
|
||||
GOOS=openbsd GOARCH=amd64 ./build -o yggstack-openbsd-amd64-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-openbsd-arm64-static"
|
||||
GOOS=openbsd GOARCH=arm64 ./build -o yggstack-openbsd-arm64-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-openbsd-armv6-static"
|
||||
GOOS=openbsd GOARCH=arm GOARM=6 ./build -o yggstack-openbsd-armv6-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-openbsd-armv7-static"
|
||||
GOOS=openbsd GOARCH=arm GOARM=7 ./build -o yggstack-openbsd-armv7-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-openbsd-i386-static"
|
||||
GOOS=openbsd GOARCH=386 ./build -o yggstack-openbsd-i386-static
|
||||
GOOS=openbsd GOARCH=386 ./build -o yggstack-openbsd-386-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-netbsd-amd64-static"
|
||||
GOOS=netbsd GOARCH=amd64 ./build -o yggstack-netbsd-amd64-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-netbsd-arm64-static"
|
||||
GOOS=netbsd GOARCH=arm64 ./build -o yggstack-netbsd-arm64-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-netbsd-armv6-static"
|
||||
GOOS=netbsd GOARCH=arm GOARM=6 ./build -o yggstack-netbsd-armv6-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-netbsd-armv7-static"
|
||||
GOOS=netbsd GOARCH=arm GOARM=7 ./build -o yggstack-netbsd-armv7-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-netbsd-i386-static"
|
||||
GOOS=netbsd GOARCH=386 ./build -o yggstack-netbsd-i386-static
|
||||
GOOS=netbsd GOARCH=386 ./build -o yggstack-netbsd-386-static
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-android-amd64"
|
||||
CGO_ENABLED=1 CC="$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android21-clang" GOOS=android GOARCH=amd64 ./build -o yggstack-android-amd64
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-android-arm64"
|
||||
CGO_ENABLED=1 CC="$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang" GOOS=android GOARCH=arm64 ./build -o yggstack-android-arm64
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-android-armv7"
|
||||
CGO_ENABLED=1 CC="$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi21-clang" GOOS=android GOARCH=arm GOARM=7 ./build -o yggstack-android-armv7
|
||||
echo "::endgroup::"
|
||||
#
|
||||
echo "::group::yggstack-android-i386"
|
||||
CGO_ENABLED=1 CC="$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/i686-linux-android21-clang" GOOS=android GOARCH=386 ./build -o yggstack-android-i386
|
||||
CGO_ENABLED=1 CC="$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/i686-linux-android21-clang" GOOS=android GOARCH=386 ./build -o yggstack-android-386
|
||||
echo "::endgroup::"
|
||||
#
|
||||
#echo "::group::yggstack-ios-arm64"
|
||||
#GOOS=ios GOARCH=arm64 CC=$(go env GOROOT)/misc/ios/clangwrap.sh ./build -o yggstack-ios-arm64
|
||||
#echo "::endgroup::"
|
||||
#
|
||||
#echo "::group::yggstack-ios-amd64"
|
||||
#GOOS=ios GOARCH=amd64 CC=$(go env GOROOT)/misc/ios/clangwrap.sh ./build -o yggstack-ios-amd64
|
||||
#echo "::endgroup::"
|
||||
|
||||
- name: Publish release
|
||||
if: ${{ env.SKIP_UPLOAD == '' }}
|
||||
run: |
|
||||
gh release create trunk --prerelease yggstack-* || gh release upload trunk yggstack-*
|
||||
gh release create "${{ env.RELEASENAME }}" ${{ env.PRERELEASE }} yggstack-* || gh release upload "${{ env.RELEASENAME }}" yggstack-* --clobber
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
if: ${{ env.SKIP_UPLOAD != '1' }}
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
if: ${{ env.SKIP_UPLOAD == '' }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push yggstack container image
|
||||
if: ${{ env.SKIP_UPLOAD == '' }}
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.static
|
||||
platforms: linux/386, linux/amd64, linux/arm/v6, linux/arm/v7, linux/arm64, linux/ppc64le, linux/riscv64, linux/s390x
|
||||
push: true
|
||||
tags: ghcr.io/yggdrasil-network/yggstack:${{ env.RELEASENAME }}
|
||||
|
|
9
Dockerfile.static
Normal file
9
Dockerfile.static
Normal file
|
@ -0,0 +1,9 @@
|
|||
FROM --platform=linux/amd64 gcr.io/distroless/static
|
||||
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
ARG TARGETVARIANT
|
||||
|
||||
COPY --chown=0:0 --chmod=0755 yggstack-${TARGETOS}-${TARGETARCH}${TARGETVARIANT}-static /bin/yggstack
|
||||
|
||||
ENTRYPOINT [ "/bin/yggstack" ]
|
76
README.md
76
README.md
|
@ -1,6 +1,6 @@
|
|||
# Yggstack - Yggdrasil as SOCKS proxy / port forwarder
|
||||
|
||||
[](https://github.com/yggdrasil-network/yggstack/actions/workflows/ci.yml)
|
||||
[](https://github.com/yggdrasil-network/yggstack/actions/workflows/trunk.yml)
|
||||
|
||||
## Introduction
|
||||
|
||||
|
@ -30,12 +30,18 @@ Please see our [Installation](https://yggdrasil-network.github.io/installation.h
|
|||
page for more information. You may also find other platform-specific wrappers, scripts
|
||||
or tools in the `contrib` folder.
|
||||
|
||||
## Downloading
|
||||
|
||||
Bleeding-edge binaries can be downloaded via [trunk release](https://github.com/yggdrasil-network/yggstack/releases/tag/trunk)
|
||||
|
||||
Tagged releases provide packages similar to Yggdrasil.
|
||||
|
||||
## Building
|
||||
|
||||
If you want to build from source, as opposed to installing one of the pre-built
|
||||
packages:
|
||||
|
||||
1. Install [Go](https://golang.org) (requires Go 1.17 or later)
|
||||
1. Install [Go](https://golang.org) (requires Go 1.22 or later)
|
||||
2. Clone this repository
|
||||
2. Run `./build`
|
||||
|
||||
|
@ -66,17 +72,48 @@ other configuration such as listen addresses or multicast addresses, etc.
|
|||
|
||||
### Run Yggstack
|
||||
|
||||
To run SOCKS proxy server listening on local port 1080 using generated configuration:
|
||||
To run SOCKS proxy server listening on local port 1080 using generated
|
||||
configuration (like `ssh -D`):
|
||||
|
||||
```
|
||||
./yggstack -useconffile /path/to/yggdrasil.conf -socks 127.0.0.1:1080
|
||||
```
|
||||
|
||||
To expose network services (like a Web server) listening on local port 8080 to Yggdrasil
|
||||
network address at port 80:
|
||||
To run SOCKS proxy server listening on UNIX socket file `/tmp/yggstack.sock`:
|
||||
|
||||
```
|
||||
./yggstack -useconffile /path/to/yggdrasil.conf -exposetcp 80:127.0.0.1:8080
|
||||
./yggstack -useconffile /path/to/yggdrasil.conf -socks /tmp/yggstack.sock
|
||||
```
|
||||
|
||||
To expose network services (like a Web server) listening on local port 8080
|
||||
to Yggdrasil network address at port 80 (like `ssh -R`):
|
||||
|
||||
TCP:
|
||||
|
||||
```
|
||||
./yggstack -useconffile /path/to/yggdrasil.conf -remote-tcp 80:127.0.0.1:8080
|
||||
```
|
||||
|
||||
UDP:
|
||||
|
||||
```
|
||||
./yggstack -useconffile /path/to/yggdrasil.conf -remote-udp 53:127.0.0.1:53
|
||||
```
|
||||
|
||||
To forward remote port on some other Yggdrasil node to local machine (like `ssh -L`):
|
||||
|
||||
TCP:
|
||||
|
||||
```
|
||||
./yggstack -useconffile /path/to/yggdrasil.conf -local-tcp 127.0.0.1:8080:<remote-yggdrasil-ipv6>:8080
|
||||
./yggstack -useconffile /path/to/yggdrasil.conf -local-tcp [::1]:8080:<remote-yggdrasil-ipv6>:8080
|
||||
```
|
||||
|
||||
UDP:
|
||||
|
||||
```
|
||||
./yggstack -useconffile /path/to/yggdrasil.conf -local-udp 127.0.0.1:5353:<remote-yggdrasil-ipv6>:53
|
||||
./yggstack -useconffile /path/to/yggdrasil.conf -local-udp [::1]:5353:<remote-yggdrasil-ipv6>:53
|
||||
```
|
||||
|
||||
To run as a standalone node without SOCKS server or TCP port forwarding:
|
||||
|
@ -95,14 +132,37 @@ Unlike mainline Yggdrasil, Yggstack does NOT require privileged access.
|
|||
You can even run several Yggstack instances with different configurations
|
||||
on the same OS and user!
|
||||
|
||||
### External DNS nameservers
|
||||
|
||||
If a client tool like `curl` fails to resolve `.ygg` domain, and yggstack prints
|
||||
the following warning on start-up:
|
||||
|
||||
```
|
||||
2024/08/06 03:27:20 DNS nameserver is not set!
|
||||
2024/08/06 03:27:20 SOCKS server will not be able to resolve hostnames other than .pk.ygg !
|
||||
```
|
||||
|
||||
start yggstack pointing to a [DNS server](https://yggdrasil-network.github.io/services.html#dns),
|
||||
for example:
|
||||
|
||||
```
|
||||
yggstack -useconffile /path/to/yggdrasil.conf -nameserver '[324:71e:281a:9ed3::53]:53' -socks 127.0.0.1:1080
|
||||
```
|
||||
|
||||
and test if resolver works:
|
||||
|
||||
```
|
||||
curl -x socks5h://127.0.0.1:1080 http://web.mc.ygg
|
||||
```
|
||||
|
||||
### pk.ygg DNS resolver
|
||||
|
||||
One unique feature of Yggstack is built-in DNS resolver functionality using
|
||||
`<publickey>.pk.ygg` format.
|
||||
`<publickey>.pk.ygg` format without the need for external DNS nameservers.
|
||||
|
||||
For example, HowToYgg website (whose public key is `d40d4a7153cf288ea28f1865f6cfe95143a478b5c8c9e7cb002a0633d10a53eb`)
|
||||
can be accessed by any Web browser supporting SOCKS servers
|
||||
via `http://d40d4a7153cf288ea28f1865f6cfe95143a478b5c8c9e7cb002a0633d10a53eb.pk.ygg`
|
||||
via `http://d40d4a7153cf288ea28f1865f6cfe95143a478b5c8c9e7cb002a0633d10a53eb.pk.ygg`
|
||||
|
||||
You can even use cURL with Yggstack:
|
||||
|
||||
|
|
3
build
3
build
|
@ -9,7 +9,7 @@ PKGVER=${PKGVER:-$(sh contrib/semver/version.sh --bare)}
|
|||
LDFLAGS="-X $PKGSRC.buildName=$PKGNAME -X $PKGSRC.buildVersion=$PKGVER"
|
||||
ARGS="-v"
|
||||
|
||||
while getopts "utc:l:dro:p" option
|
||||
while getopts "utc:l:dro:ps" option
|
||||
do
|
||||
case "$option"
|
||||
in
|
||||
|
@ -21,6 +21,7 @@ do
|
|||
r) ARGS="$ARGS -race";;
|
||||
o) ARGS="$ARGS -o $OPTARG";;
|
||||
p) ARGS="$ARGS -buildmode=pie";;
|
||||
s) ARGS="$ARGS -tags netgo,osusersgo,static" LDFLAGS="$LDFLAGS -extldflags '-static'" CGO_ENABLED=0;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
|
|
@ -5,13 +5,16 @@ import (
|
|||
"crypto/ed25519"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/gologme/log"
|
||||
|
@ -28,17 +31,29 @@ import (
|
|||
|
||||
"github.com/yggdrasil-network/yggstack/src/netstack"
|
||||
"github.com/yggdrasil-network/yggstack/src/types"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
|
||||
)
|
||||
|
||||
type node struct {
|
||||
core *core.Core
|
||||
multicast *multicast.Multicast
|
||||
admin *admin.AdminSocket
|
||||
core *core.Core
|
||||
multicast *multicast.Multicast
|
||||
admin *admin.AdminSocket
|
||||
socks5Tcp net.Listener
|
||||
socks5Unix net.Listener
|
||||
}
|
||||
|
||||
type UDPSession struct {
|
||||
conn interface{}
|
||||
remoteAddr net.Addr
|
||||
}
|
||||
|
||||
// The main function is responsible for configuring and starting Yggdrasil.
|
||||
func main() {
|
||||
var expose types.TCPMappings
|
||||
var localtcp types.TCPLocalMappings
|
||||
var localudp types.UDPLocalMappings
|
||||
var remotetcp types.TCPRemoteMappings
|
||||
var remoteudp types.UDPRemoteMappings
|
||||
genconf := flag.Bool("genconf", false, "print a new config to stdout")
|
||||
useconf := flag.Bool("useconf", false, "read HJSON/JSON config from stdin")
|
||||
useconffile := flag.String("useconffile", "", "read HJSON/JSON config from specified file path")
|
||||
|
@ -52,9 +67,12 @@ func main() {
|
|||
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")
|
||||
loglevel := flag.String("loglevel", "info", "loglevel to enable")
|
||||
socks := flag.String("socks", "", "address to listen on for SOCKS, i.e. :1080")
|
||||
socks := flag.String("socks", "", "address to listen on for SOCKS, i.e. :1080; or UNIX socket file path, i.e. /tmp/yggstack.sock")
|
||||
nameserver := flag.String("nameserver", "", "the Yggdrasil IPv6 address to use as a DNS server for SOCKS")
|
||||
flag.Var(&expose, "exposetcp", "TCP ports to expose to the network, e.g. 22, 2022:22, 22:192.168.1.1:2022")
|
||||
flag.Var(&localtcp, "local-tcp", "TCP ports to forward to the remote Yggdradil node, e.g. 22:[a:b:c:d]:22, 127.0.0.1:22:[a:b:c:d]:22")
|
||||
flag.Var(&localudp, "local-udp", "UDP ports to forward to the remote Yggdrasil node, e.g. 22:[a:b:c:d]:2022, 127.0.0.1:[a:b:c:d]:22")
|
||||
flag.Var(&remotetcp, "remote-tcp", "TCP ports to expose to the network, e.g. 22, 2022:22, 22:192.168.1.1:2022")
|
||||
flag.Var(&remoteudp, "remote-udp", "UDP ports to expose to the network, e.g. 22, 2022:22, 22:192.168.1.1:2022")
|
||||
flag.Parse()
|
||||
|
||||
// Catch interrupts from the operating system to exit gracefully.
|
||||
|
@ -95,6 +113,8 @@ func main() {
|
|||
return
|
||||
|
||||
case *autoconf:
|
||||
// Force AdminListen to none in yggstack
|
||||
cfg.AdminListen = "none"
|
||||
// Use an autoconf-generated config, this will give us random keys and
|
||||
// port numbers, and will use an automatically selected TUN interface.
|
||||
|
||||
|
@ -114,6 +134,7 @@ func main() {
|
|||
_ = f.Close()
|
||||
|
||||
case *genconf:
|
||||
// Force AdminListen to none in yggstack
|
||||
cfg.AdminListen = "none"
|
||||
var bs []byte
|
||||
if *confjson {
|
||||
|
@ -268,29 +289,164 @@ func main() {
|
|||
|
||||
// Create SOCKS server
|
||||
{
|
||||
if socks != nil && nameserver != nil && *socks != "" {
|
||||
resolver := types.NewNameResolver(s, *nameserver)
|
||||
if socks != nil && *socks != "" {
|
||||
socksOptions := []socks5.Option{
|
||||
socks5.WithDial(s.DialContext),
|
||||
socks5.WithResolver(resolver),
|
||||
}
|
||||
if nameserver != nil {
|
||||
if *nameserver == "" {
|
||||
logger.Infof("DNS nameserver is not set!")
|
||||
logger.Infof("SOCKS server will not be able to resolve hostnames other than .pk.ygg !")
|
||||
}
|
||||
resolver := types.NewNameResolver(s, *nameserver)
|
||||
socksOptions = append(socksOptions, socks5.WithResolver(resolver))
|
||||
}
|
||||
if logger.GetLevel("debug") {
|
||||
socksOptions = append(socksOptions, socks5.WithLogger(logger))
|
||||
}
|
||||
server := socks5.NewServer(socksOptions...)
|
||||
go server.ListenAndServe("tcp", *socks) // nolint:errcheck
|
||||
if strings.Contains(*socks, ":") {
|
||||
logger.Infof("Starting SOCKS server on %s", *socks)
|
||||
n.socks5Tcp, err = net.Listen("tcp", *socks)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
go func() {
|
||||
err := server.Serve(n.socks5Tcp)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
logger.Infof("Starting SOCKS server with socket file %s", *socks)
|
||||
n.socks5Unix, err = net.Listen("unix", *socks)
|
||||
if err != nil {
|
||||
// If address in use, try connecting to
|
||||
// the socket to see if other yggstack
|
||||
// instance is listening on it
|
||||
|
||||
if isErrorAddressAlreadyInUse(err) {
|
||||
_, err = net.Dial("unix", *socks)
|
||||
if err != nil {
|
||||
// Unlink dead socket if not connected
|
||||
err = os.RemoveAll(*socks)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
panic(fmt.Errorf("Another yggstack instance is listening on socket '%s'", *socks))
|
||||
}
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
go func() {
|
||||
err := server.Serve(n.socks5Unix)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create TCP mappings
|
||||
// Create local TCP mappings (forwarding connections from local port
|
||||
// to remote Yggdrasil node)
|
||||
{
|
||||
for _, mapping := range expose {
|
||||
for _, mapping := range localtcp {
|
||||
go func(mapping types.TCPMapping) {
|
||||
listener, err := net.ListenTCP("tcp", mapping.Listen)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
logger.Infof("Mapping local TCP port %d to Yggdrasil %s", mapping.Listen.Port, mapping.Mapped)
|
||||
for {
|
||||
c, err := listener.Accept()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
r, err := s.DialTCP(mapping.Mapped)
|
||||
if err != nil {
|
||||
logger.Errorf("Failed to connect to %s: %s", mapping.Mapped, err)
|
||||
_ = c.Close()
|
||||
continue
|
||||
}
|
||||
go types.ProxyTCP(n.core.MTU(), c, r)
|
||||
}
|
||||
}(mapping)
|
||||
}
|
||||
}
|
||||
|
||||
// Create local UDP mappings (forwarding connections from local port
|
||||
// to remote Yggdrasil node)
|
||||
{
|
||||
for _, mapping := range localudp {
|
||||
go func(mapping types.UDPMapping) {
|
||||
mtu := n.core.MTU()
|
||||
udpListenConn, err := net.ListenUDP("udp", mapping.Listen)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
logger.Infof("Mapping local UDP port %d to Yggdrasil %s", mapping.Listen.Port, mapping.Mapped)
|
||||
localUdpConnections := new(sync.Map)
|
||||
udpBuffer := make([]byte, mtu)
|
||||
for {
|
||||
bytesRead, remoteUdpAddr, err := udpListenConn.ReadFrom(udpBuffer)
|
||||
if err != nil {
|
||||
if bytesRead == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
remoteUdpAddrStr := remoteUdpAddr.String()
|
||||
|
||||
connVal, ok := localUdpConnections.Load(remoteUdpAddrStr)
|
||||
|
||||
if !ok {
|
||||
logger.Debugf("Creating new session for %s", remoteUdpAddr.String())
|
||||
udpFwdConn, err := s.DialUDP(mapping.Mapped)
|
||||
if err != nil {
|
||||
logger.Errorf("Failed to connect to %s: %s", mapping.Mapped, err)
|
||||
continue
|
||||
}
|
||||
udpSession := &UDPSession{
|
||||
conn: udpFwdConn,
|
||||
remoteAddr: remoteUdpAddr,
|
||||
}
|
||||
localUdpConnections.Store(remoteUdpAddrStr, udpSession)
|
||||
go types.ReverseProxyUDP(mtu, udpListenConn, remoteUdpAddr, udpFwdConn)
|
||||
}
|
||||
|
||||
udpSession, ok := connVal.(*UDPSession)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
udpFwdConnPtr := udpSession.conn.(*gonet.UDPConn)
|
||||
udpFwdConn := *udpFwdConnPtr
|
||||
|
||||
_, err = udpFwdConn.Write(udpBuffer[:bytesRead])
|
||||
if err != nil {
|
||||
logger.Debugf("Cannot write from yggdrasil to udp listener: %q", err)
|
||||
udpFwdConn.Close()
|
||||
localUdpConnections.Delete(remoteUdpAddrStr)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}(mapping)
|
||||
}
|
||||
}
|
||||
|
||||
// Create remote TCP mappings (forwarding connections from Yggdrasil
|
||||
// node to local port)
|
||||
{
|
||||
for _, mapping := range remotetcp {
|
||||
go func(mapping types.TCPMapping) {
|
||||
listener, err := s.ListenTCP(mapping.Listen)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
logger.Infof("Mapping Yggdrasil port %d to %s", mapping.Listen.Port, mapping.Mapped)
|
||||
logger.Infof("Mapping Yggdrasil TCP port %d to %s", mapping.Listen.Port, mapping.Mapped)
|
||||
for {
|
||||
c, err := listener.Accept()
|
||||
if err != nil {
|
||||
|
@ -308,15 +464,110 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
// Create remote UDP mappings (forwarding connections from Yggdrasil
|
||||
// node to local port)
|
||||
{
|
||||
for _, mapping := range remoteudp {
|
||||
go func(mapping types.UDPMapping) {
|
||||
mtu := n.core.MTU()
|
||||
udpListenConn, err := s.ListenUDP(mapping.Listen)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
logger.Infof("Mapping Yggdrasil UDP port %d to %s", mapping.Listen.Port, mapping.Mapped)
|
||||
remoteUdpConnections := new(sync.Map)
|
||||
udpBuffer := make([]byte, mtu)
|
||||
for {
|
||||
bytesRead, remoteUdpAddr, err := udpListenConn.ReadFrom(udpBuffer)
|
||||
if err != nil {
|
||||
logger.Debugf("udp readFrom error: %v", err)
|
||||
}
|
||||
if bytesRead == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
remoteUdpAddrStr := remoteUdpAddr.String()
|
||||
|
||||
var udpSession *UDPSession = nil
|
||||
|
||||
connVal, ok := remoteUdpConnections.Load(remoteUdpAddrStr)
|
||||
|
||||
if !ok {
|
||||
logger.Debugf("Creating new session for %s", remoteUdpAddr.String())
|
||||
udpFwdConn, err := net.DialUDP("udp", nil, mapping.Mapped)
|
||||
if err != nil {
|
||||
logger.Errorf("Failed to connect to %s: %s", mapping.Mapped, err)
|
||||
continue
|
||||
}
|
||||
udpSession = &UDPSession{
|
||||
conn: udpFwdConn,
|
||||
remoteAddr: remoteUdpAddr,
|
||||
}
|
||||
remoteUdpConnections.Store(remoteUdpAddrStr, udpSession)
|
||||
go types.ReverseProxyUDP(mtu, udpListenConn, remoteUdpAddr, udpFwdConn)
|
||||
} else {
|
||||
udpSession, ok = connVal.(*UDPSession)
|
||||
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
udpFwdConnPtr := udpSession.conn.(*net.UDPConn)
|
||||
udpFwdConn := *udpFwdConnPtr
|
||||
|
||||
_, err = udpFwdConn.Write(udpBuffer[:bytesRead])
|
||||
if err != nil {
|
||||
logger.Debugf("Cannot write from yggdrasil to udp listener: %q", err)
|
||||
udpFwdConn.Close()
|
||||
remoteUdpConnections.Delete(remoteUdpAddrStr)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}(mapping)
|
||||
}
|
||||
}
|
||||
|
||||
// Block until we are told to shut down.
|
||||
<-ctx.Done()
|
||||
|
||||
// Shut down the node.
|
||||
_ = n.admin.Stop()
|
||||
_ = n.multicast.Stop()
|
||||
if n.socks5Unix != nil {
|
||||
_ = n.socks5Unix.Close()
|
||||
_ = os.RemoveAll(*socks)
|
||||
logger.Infof("Stopped SOCKS5 UNIX socket listener")
|
||||
}
|
||||
if n.socks5Tcp != nil {
|
||||
_ = n.socks5Tcp.Close()
|
||||
logger.Infof("Stopped SOCKS5 TCP listener")
|
||||
}
|
||||
n.core.Stop()
|
||||
}
|
||||
|
||||
// Helper to detect if socket address is in use
|
||||
// https://stackoverflow.com/a/52152912
|
||||
func isErrorAddressAlreadyInUse(err error) bool {
|
||||
var eOsSyscall *os.SyscallError
|
||||
if !errors.As(err, &eOsSyscall) {
|
||||
return false
|
||||
}
|
||||
var errErrno syscall.Errno // doesn't need a "*" (ptr) because it's already a ptr (uintptr)
|
||||
if !errors.As(eOsSyscall, &errErrno) {
|
||||
return false
|
||||
}
|
||||
if errors.Is(errErrno, syscall.EADDRINUSE) {
|
||||
return true
|
||||
}
|
||||
const WSAEADDRINUSE = 10048
|
||||
if runtime.GOOS == "windows" && errErrno == WSAEADDRINUSE {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Helper to set logging level
|
||||
func setLogLevel(loglevel string, logger *log.Logger) {
|
||||
levels := [...]string{"error", "warn", "info", "debug", "trace"}
|
||||
loglevel = strings.ToLower(loglevel)
|
||||
|
|
48
go.mod
48
go.mod
|
@ -1,34 +1,38 @@
|
|||
module github.com/yggdrasil-network/yggstack
|
||||
|
||||
go 1.21.4
|
||||
go 1.22.0
|
||||
|
||||
toolchain go1.22.5
|
||||
|
||||
require (
|
||||
github.com/gologme/log v1.3.0
|
||||
github.com/hashicorp/go-syslog v1.0.0
|
||||
github.com/hjson/hjson-go/v4 v4.4.0
|
||||
github.com/things-go/go-socks5 v0.0.4
|
||||
github.com/yggdrasil-network/yggdrasil-go v0.5.4
|
||||
gvisor.dev/gvisor v0.0.0-20240103195848-a9a6a6819b00
|
||||
github.com/things-go/go-socks5 v0.0.5
|
||||
github.com/yggdrasil-network/yggdrasil-go v0.5.12
|
||||
gvisor.dev/gvisor v0.0.0-20240810013311-326fe0f2a77f
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Arceliar/ironwood v0.0.0-20231127131626-465b82dfb5bd // indirect
|
||||
github.com/Arceliar/ironwood v0.0.0-20241213013129-743fe2fccbd3 // indirect
|
||||
github.com/Arceliar/phony v0.0.0-20220903101357-530938a4b13d // indirect
|
||||
github.com/bits-and-blooms/bitset v1.13.0 // indirect
|
||||
github.com/bits-and-blooms/bloom/v3 v3.6.0 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.13.2 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
|
||||
github.com/quic-go/quic-go v0.40.1 // indirect
|
||||
go.uber.org/mock v0.4.0 // indirect
|
||||
golang.org/x/crypto v0.17.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/net v0.19.0 // indirect
|
||||
golang.org/x/sys v0.16.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.16.1 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.14.3 // indirect
|
||||
github.com/bits-and-blooms/bloom/v3 v3.7.0 // indirect
|
||||
github.com/coder/websocket v1.8.12 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/pprof v0.0.0-20241017200806-017d972448fc // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.20.2 // indirect
|
||||
github.com/quic-go/quic-go v0.48.2 // indirect
|
||||
github.com/wlynxg/anet v0.0.5 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
golang.org/x/crypto v0.31.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
|
||||
golang.org/x/mod v0.21.0 // indirect
|
||||
golang.org/x/net v0.32.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/time v0.7.0 // indirect
|
||||
golang.org/x/tools v0.26.0 // indirect
|
||||
)
|
||||
|
|
218
go.sum
218
go.sum
|
@ -1,179 +1,73 @@
|
|||
github.com/Arceliar/ironwood v0.0.0-20231126105342-ad38416a77c8 h1:qyXiPZClVoe6QsbsiDP23g0Ze/MNXiHIAL/nVNfauH0=
|
||||
github.com/Arceliar/ironwood v0.0.0-20231126105342-ad38416a77c8/go.mod h1:5x7fWW0mshe9WQ1lvSMmmHBYC3BeHH9gpwW5tz7cbfw=
|
||||
github.com/Arceliar/ironwood v0.0.0-20231127131626-465b82dfb5bd h1:458tnmZ4zM2gbLtefdYbaxyAJevDNEWu6tLKEqbK4wg=
|
||||
github.com/Arceliar/ironwood v0.0.0-20231127131626-465b82dfb5bd/go.mod h1:5x7fWW0mshe9WQ1lvSMmmHBYC3BeHH9gpwW5tz7cbfw=
|
||||
github.com/Arceliar/ironwood v0.0.0-20241213013129-743fe2fccbd3 h1:d8N0z+udAnbU5PdjpLSNPTWlqeU/nnYsQ42B6+879aw=
|
||||
github.com/Arceliar/ironwood v0.0.0-20241213013129-743fe2fccbd3/go.mod h1:SrrElc3FFMpYCODSr11jWbLFeOM8WsY+DbDY/l2AXF0=
|
||||
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/bits-and-blooms/bitset v1.3.1/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||
github.com/bits-and-blooms/bitset v1.5.0 h1:NpE8frKRLGHIcEzkR+gZhiioW1+WbYV6fKwD6ZIpQT8=
|
||||
github.com/bits-and-blooms/bitset v1.5.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||
github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/bits-and-blooms/bitset v1.11.0 h1:RMyy2mBBShArUAhfVRZJ2xyBO58KCBCtZFShw3umo6k=
|
||||
github.com/bits-and-blooms/bitset v1.11.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
|
||||
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/bits-and-blooms/bloom/v3 v3.3.1 h1:K2+A19bXT8gJR5mU7y+1yW6hsKfNCjcP2uNfLFKncjQ=
|
||||
github.com/bits-and-blooms/bloom/v3 v3.3.1/go.mod h1:bhUUknWd5khVbTe4UgMCSiOOVJzr3tMoijSK3WwvW90=
|
||||
github.com/bits-and-blooms/bloom/v3 v3.6.0 h1:dTU0OVLJSoOhz9m68FTXMFfA39nR8U/nTCs1zb26mOI=
|
||||
github.com/bits-and-blooms/bloom/v3 v3.6.0/go.mod h1:VKlUSvp0lFIYqxJjzdnSsZEw4iHb1kOL2tfHTgyJBHg=
|
||||
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/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/bits-and-blooms/bitset v1.14.3 h1:Gd2c8lSNf9pKXom5JtD7AaKO8o7fGQ2LtFj1436qilA=
|
||||
github.com/bits-and-blooms/bitset v1.14.3/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/go.mod h1:VKlUSvp0lFIYqxJjzdnSsZEw4iHb1kOL2tfHTgyJBHg=
|
||||
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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
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/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
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/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
||||
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/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/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5XqmmYsTLzJp/TO9Lhy39gkverk=
|
||||
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42 h1:dHLYa5D8/Ta0aLR2XcPsrkpAgGeFs6thhMcQK0oQ0n8=
|
||||
github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
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/pprof v0.0.0-20241017200806-017d972448fc h1:NGyrhhFhwvRAZg02jnYVg3GBQy0qGBKmFQJwaPmpmxs=
|
||||
github.com/google/pprof v0.0.0-20241017200806-017d972448fc/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hjson/hjson-go/v4 v4.3.0 h1:dyrzJdqqFGhHt+FSrs5n9s6b0fPM8oSJdWo+oS3YnJw=
|
||||
github.com/hjson/hjson-go/v4 v4.3.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E=
|
||||
github.com/hjson/hjson-go/v4 v4.3.1 h1:wfmDwHGxjzmYKXRFL0Qr9nonY/Xxe5y7IalwjlY7ekA=
|
||||
github.com/hjson/hjson-go/v4 v4.3.1/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E=
|
||||
github.com/hjson/hjson-go/v4 v4.4.0 h1:D/NPvqOCH6/eisTb5/ztuIS8GUvmpHaLOcNk1Bjr298=
|
||||
github.com/hjson/hjson-go/v4 v4.4.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
|
||||
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
|
||||
github.com/onsi/ginkgo/v2 v2.13.1 h1:LNGfMbR2OVGBfXjvRZIZ2YCTQdGKtPLvuI1rMCCj3OU=
|
||||
github.com/onsi/ginkgo/v2 v2.13.1/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM=
|
||||
github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs=
|
||||
github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM=
|
||||
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/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
|
||||
github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
|
||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
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/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/quic-go/quic-go v0.39.3 h1:o3YB6t2SR+HU/pgwF29kJ6g4jJIJEwEZ8CKia1h1TKg=
|
||||
github.com/quic-go/quic-go v0.39.3/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q=
|
||||
github.com/quic-go/quic-go v0.40.0 h1:GYd1iznlKm7dpHD7pOVpUvItgMPo/jrMgDWZhMCecqw=
|
||||
github.com/quic-go/quic-go v0.40.0/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c=
|
||||
github.com/quic-go/quic-go v0.40.1 h1:X3AGzUNFs0jVuO3esAGnTfvdgvL4fq655WaOi1snv1Q=
|
||||
github.com/quic-go/quic-go v0.40.1/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/things-go/go-socks5 v0.0.4 h1:jMQjIc+qhD4z9cITOMnBiwo9dDmpGuXmBlkRFrl/qD0=
|
||||
github.com/things-go/go-socks5 v0.0.4/go.mod h1:sh4K6WHrmHZpjxLTCHyYtXYH8OUuD+yZun41NomR1IQ=
|
||||
github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE=
|
||||
github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/things-go/go-socks5 v0.0.5 h1:qvKaGcBkfDrUL33SchHN93srAmYGzb4CxSM2DPYufe8=
|
||||
github.com/things-go/go-socks5 v0.0.5/go.mod h1:mtzInf8v5xmsBpHZVbIw2YQYhc4K0jRwzfsH64Uh0IQ=
|
||||
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/yggdrasil-network/yggdrasil-go v0.5.3 h1:tfAajYmaiS1L9XevdEC1VUpScpgFfCW7/oEEWxdv5aM=
|
||||
github.com/yggdrasil-network/yggdrasil-go v0.5.3/go.mod h1:qRzHB8bKEIpd1pQVYoZ+SedJJTBG0X9sbyctWxQDDGA=
|
||||
github.com/yggdrasil-network/yggdrasil-go v0.5.4 h1:A7ZFmxkkbZhtqJgQXBVDw5sHsi25aUawLlJCCHnNsAs=
|
||||
github.com/yggdrasil-network/yggdrasil-go v0.5.4/go.mod h1:TLmU4X0nfzCY9t5xABtFQ6GLoOtCae8xVatC9JwjD5I=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
|
||||
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
|
||||
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY=
|
||||
golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
|
||||
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM=
|
||||
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||
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.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
|
||||
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||
golang.org/x/mod v0.14.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-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.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
|
||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
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.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/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-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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.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-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.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
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.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY=
|
||||
golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
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/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.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.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
|
||||
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
|
||||
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
|
||||
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
|
||||
golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
|
||||
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
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=
|
||||
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/yggdrasil-network/yggdrasil-go v0.5.12 h1:SaQ8d59JP+uFy+nOWXTx1ETM5r2uCfe1Gt/d+IodHJw=
|
||||
github.com/yggdrasil-network/yggdrasil-go v0.5.12/go.mod h1:u4DU6dpTfWmVs8r0WjW1T3UpGyeUh9vRrS8zngvncwM=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
|
||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
|
||||
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gvisor.dev/gvisor v0.0.0-20231125084359-4b4191b8cad1 h1:J9340hJZ+P01JeVPK8GatP/6Bk7j2dyLUiKct5k7IBA=
|
||||
gvisor.dev/gvisor v0.0.0-20231125084359-4b4191b8cad1/go.mod h1:10sU+Uh5KKNv1+2x2A0Gvzt8FjD3ASIhorV3YsauXhk=
|
||||
gvisor.dev/gvisor v0.0.0-20240103195848-a9a6a6819b00 h1:CaYh1ABhmDNrDvY7Xs8y4/TqK67I4r3Jb1du+J4PG60=
|
||||
gvisor.dev/gvisor v0.0.0-20240103195848-a9a6a6819b00/go.mod h1:10sU+Uh5KKNv1+2x2A0Gvzt8FjD3ASIhorV3YsauXhk=
|
||||
gvisor.dev/gvisor v0.0.0-20240104232245-1e61310ce61e h1:KNBb7yeP1HRByrH54W1Bw2LCrKualEWp8oQtCJarK00=
|
||||
gvisor.dev/gvisor v0.0.0-20240104232245-1e61310ce61e/go.mod h1:10sU+Uh5KKNv1+2x2A0Gvzt8FjD3ASIhorV3YsauXhk=
|
||||
gvisor.dev/gvisor v0.0.0-20240810013311-326fe0f2a77f h1:llng6MGz63x02Xs1Ft71riYTfau4zS8OAZKv5jgPX6M=
|
||||
gvisor.dev/gvisor v0.0.0-20240810013311-326fe0f2a77f/go.mod h1:sxc3Uvk/vHcd3tj7/DHVBoR5wvWT/MmRq2pj7HRJnwU=
|
||||
|
|
|
@ -86,12 +86,12 @@ func (s *YggdrasilNetstack) DialContext(ctx context.Context, network, address st
|
|||
}
|
||||
}
|
||||
|
||||
func (s *YggdrasilNetstack) DialTCP(addr *net.TCPAddr) (net.Conn, error) {
|
||||
func (s *YggdrasilNetstack) DialTCP(addr *net.TCPAddr) (*gonet.TCPConn, error) {
|
||||
fa, pn, _ := convertToFullAddr(addr.IP, addr.Port)
|
||||
return gonet.DialTCP(s.stack, fa, pn)
|
||||
}
|
||||
|
||||
func (s *YggdrasilNetstack) DialUDP(addr *net.UDPAddr) (net.PacketConn, error) {
|
||||
func (s *YggdrasilNetstack) DialUDP(addr *net.UDPAddr) (*gonet.UDPConn, error) {
|
||||
fa, pn, _ := convertToFullAddr(addr.IP, addr.Port)
|
||||
return gonet.DialUDP(s.stack, nil, &fa, pn)
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ func (s *YggdrasilNetstack) ListenTCP(addr *net.TCPAddr) (net.Listener, error) {
|
|||
return gonet.ListenTCP(s.stack, fa, pn)
|
||||
}
|
||||
|
||||
func (s *YggdrasilNetstack) ListenUDP(addr *net.UDPAddr) (net.PacketConn, error) {
|
||||
func (s *YggdrasilNetstack) ListenUDP(addr *net.UDPAddr) (*gonet.UDPConn, error) {
|
||||
fa, pn, _ := convertToFullAddr(addr.IP, addr.Port)
|
||||
return gonet.DialUDP(s.stack, &fa, nil, pn)
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
|
||||
)
|
||||
|
||||
type YggdrasilNIC struct {
|
||||
|
@ -20,15 +21,17 @@ type YggdrasilNIC struct {
|
|||
dispatcher stack.NetworkDispatcher
|
||||
readBuf []byte
|
||||
writeBuf []byte
|
||||
rstPackets chan *stack.PacketBuffer
|
||||
}
|
||||
|
||||
func (s *YggdrasilNetstack) NewYggdrasilNIC(ygg *core.Core) tcpip.Error {
|
||||
rwc := ipv6rwc.NewReadWriteCloser(ygg)
|
||||
mtu := rwc.MTU()
|
||||
nic := &YggdrasilNIC{
|
||||
ipv6rwc: rwc,
|
||||
readBuf: make([]byte, mtu),
|
||||
writeBuf: make([]byte, mtu),
|
||||
ipv6rwc: rwc,
|
||||
readBuf: make([]byte, mtu),
|
||||
writeBuf: make([]byte, mtu),
|
||||
rstPackets: make(chan *stack.PacketBuffer, 100),
|
||||
}
|
||||
if err := s.stack.CreateNIC(1, nic); err != nil {
|
||||
return err
|
||||
|
@ -48,6 +51,15 @@ func (s *YggdrasilNetstack) NewYggdrasilNIC(ygg *core.Core) tcpip.Error {
|
|||
nic.dispatcher.DeliverNetworkPacket(ipv6.ProtocolNumber, pkb)
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
for {
|
||||
pkt := <- nic.rstPackets
|
||||
if pkt == nil {
|
||||
continue
|
||||
}
|
||||
_ = nic.writePacket(pkt)
|
||||
}
|
||||
}()
|
||||
_, snet, err := net.ParseCIDR("0200::/7")
|
||||
if err != nil {
|
||||
return &tcpip.ErrBadAddress{}
|
||||
|
@ -85,29 +97,60 @@ func (e *YggdrasilNIC) IsAttached() bool { return e.dispatcher != nil }
|
|||
|
||||
func (e *YggdrasilNIC) MTU() uint32 { return uint32(e.ipv6rwc.MTU()) }
|
||||
|
||||
func (e *YggdrasilNIC) SetMTU(uint32) {}
|
||||
|
||||
func (*YggdrasilNIC) Capabilities() stack.LinkEndpointCapabilities { return stack.CapabilityNone }
|
||||
|
||||
func (*YggdrasilNIC) MaxHeaderLength() uint16 { return 40 }
|
||||
|
||||
func (*YggdrasilNIC) LinkAddress() tcpip.LinkAddress { return "" }
|
||||
|
||||
func (*YggdrasilNIC) SetLinkAddress(tcpip.LinkAddress) {}
|
||||
|
||||
func (*YggdrasilNIC) Wait() {}
|
||||
|
||||
func (e *YggdrasilNIC) writePacket(
|
||||
pkt *stack.PacketBuffer,
|
||||
) tcpip.Error {
|
||||
// We need to recover from panic() here because
|
||||
// parser in ToView() gets confused on some packets
|
||||
// without payload and panics
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r != nil {
|
||||
}
|
||||
}()
|
||||
vv := pkt.ToView()
|
||||
n, err := vv.Read(e.writeBuf)
|
||||
if err != nil {
|
||||
return &tcpip.ErrAborted{}
|
||||
}
|
||||
_, err = e.ipv6rwc.Write(e.writeBuf[:n])
|
||||
if err != nil {
|
||||
return &tcpip.ErrAborted{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *YggdrasilNIC) WritePackets(
|
||||
list stack.PacketBufferList,
|
||||
) (int, tcpip.Error) {
|
||||
var i int = 0
|
||||
var err tcpip.Error = nil
|
||||
for i, pkt := range list.AsSlice() {
|
||||
vv := pkt.ToView()
|
||||
n, err := vv.Read(e.writeBuf)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return i - 1, &tcpip.ErrAborted{}
|
||||
if pkt.Data().Size() == 0 {
|
||||
if pkt.Network().TransportProtocol() == tcp.ProtocolNumber {
|
||||
tcpHeader := header.TCP(pkt.TransportHeader().Slice())
|
||||
if (tcpHeader.Flags() & header.TCPFlagRst) == header.TCPFlagRst {
|
||||
e.rstPackets <- pkt
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
_, err = e.ipv6rwc.Write(e.writeBuf[:n])
|
||||
err = e.writePacket(pkt)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return i - 1, &tcpip.ErrAborted{}
|
||||
return i - 1, err
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,8 +172,9 @@ func (e *YggdrasilNIC) ParseHeader(*stack.PacketBuffer) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (e *YggdrasilNIC) Close() error {
|
||||
func (e *YggdrasilNIC) Close() {
|
||||
e.stack.stack.RemoveNIC(1)
|
||||
e.dispatcher = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *YggdrasilNIC) SetOnCloseAction(func()) {}
|
||||
|
|
|
@ -7,62 +7,381 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
func parseMappingString(value string) (first_address string, first_port int, second_address string, second_port int, err error) {
|
||||
var first_port_string string = ""
|
||||
var second_port_string string = ""
|
||||
|
||||
tokens := strings.Split(value, ":")
|
||||
tokens_len := len(tokens)
|
||||
|
||||
// If token count is 1, then it is first and second port the same
|
||||
|
||||
if tokens_len == 1 {
|
||||
first_port, err = strconv.Atoi(tokens[0])
|
||||
if err != nil {
|
||||
return "", 0, "", 0, fmt.Errorf("Malformed mapping spec '%s'", value)
|
||||
}
|
||||
second_port = first_port
|
||||
}
|
||||
|
||||
// If token count is 2, then it is <first-port>:<second-port>
|
||||
|
||||
if tokens_len == 2 {
|
||||
first_port, err = strconv.Atoi(tokens[0])
|
||||
if err != nil {
|
||||
return "", 0, "", 0, fmt.Errorf("Malformed mapping spec '%s'", value)
|
||||
}
|
||||
second_port, err = strconv.Atoi(tokens[1])
|
||||
if err != nil {
|
||||
return "", 0, "", 0, fmt.Errorf("Malformed mapping spec '%s'", value)
|
||||
}
|
||||
}
|
||||
|
||||
// If token count is 3, parse it as
|
||||
// <first-port>:<second-address>:<second-port>
|
||||
|
||||
if tokens_len == 3 {
|
||||
first_port, err = strconv.Atoi(tokens[0])
|
||||
if err != nil {
|
||||
return "", 0, "", 0, fmt.Errorf("Malformed mapping spec '%s'", value)
|
||||
}
|
||||
second_address, second_port_string, err = net.SplitHostPort(
|
||||
tokens[1] + ":" + tokens[2])
|
||||
if err != nil {
|
||||
return "", 0, "", 0, fmt.Errorf("Malformed mapping spec '%s'", value)
|
||||
}
|
||||
second_port, err = strconv.Atoi(second_port_string)
|
||||
if err != nil {
|
||||
return "", 0, "", 0, fmt.Errorf("Malformed mapping spec '%s'", value)
|
||||
}
|
||||
}
|
||||
|
||||
// If token count is 4, parse it as
|
||||
// <first-address>:<first-port>:<second-address>:<second-port>
|
||||
|
||||
if tokens_len == 4 {
|
||||
first_address, first_port_string, err = net.SplitHostPort(
|
||||
tokens[0] + ":" + tokens[1])
|
||||
if err != nil {
|
||||
return "", 0, "", 0, fmt.Errorf("Malformed mapping spec '%s'", value)
|
||||
}
|
||||
second_address, second_port_string, err = net.SplitHostPort(
|
||||
tokens[0] + ":" + tokens[1])
|
||||
if err != nil {
|
||||
return "", 0, "", 0, fmt.Errorf("Malformed mapping spec '%s'", value)
|
||||
}
|
||||
first_port, err = strconv.Atoi(first_port_string)
|
||||
if err != nil {
|
||||
return "", 0, "", 0, fmt.Errorf("Malformed mapping spec '%s'", value)
|
||||
}
|
||||
second_port, err = strconv.Atoi(second_port_string)
|
||||
if err != nil {
|
||||
return "", 0, "", 0, fmt.Errorf("Malformed mapping spec '%s'", value)
|
||||
}
|
||||
}
|
||||
|
||||
if tokens_len > 4 {
|
||||
// Last token needs to be the second_port
|
||||
|
||||
second_port, err = strconv.Atoi(tokens[tokens_len-1])
|
||||
if err != nil {
|
||||
return "", 0, "", 0, fmt.Errorf("Malformed mapping spec '%s'", value)
|
||||
}
|
||||
|
||||
// Cut seen tokens
|
||||
|
||||
tokens = tokens[:tokens_len-1]
|
||||
tokens_len = len(tokens)
|
||||
|
||||
if strings.HasSuffix(tokens[tokens_len-1], "]") {
|
||||
// Reverse-walk over tokens to find the end of
|
||||
// numeric ipv6 address
|
||||
|
||||
for i := tokens_len - 1; i >= 0; i-- {
|
||||
if strings.HasPrefix(tokens[i], "[") {
|
||||
// Store second address
|
||||
second_address = strings.Join(tokens[i:], ":")
|
||||
second_address, _ = strings.CutPrefix(second_address, "[")
|
||||
second_address, _ = strings.CutSuffix(second_address, "]")
|
||||
// Cut seen tokens
|
||||
tokens = tokens[:i]
|
||||
// break from loop
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// next is second address in non-numerical-ipv6 form
|
||||
second_address = tokens[tokens_len-1]
|
||||
tokens = tokens[:tokens_len-1]
|
||||
}
|
||||
|
||||
tokens_len = len(tokens)
|
||||
|
||||
if tokens_len < 1 {
|
||||
return "", 0, "", 0, fmt.Errorf("Malformed mapping spec '%s'", value)
|
||||
}
|
||||
|
||||
// Last token needs to be the first_port
|
||||
|
||||
first_port, err = strconv.Atoi(tokens[tokens_len-1])
|
||||
if err != nil {
|
||||
return "", 0, "", 0, fmt.Errorf("Malformed mapping spec '%s'", value)
|
||||
}
|
||||
|
||||
// Cut seen tokens
|
||||
|
||||
tokens = tokens[:tokens_len-1]
|
||||
tokens_len = len(tokens)
|
||||
|
||||
if tokens_len > 0 {
|
||||
if strings.HasSuffix(tokens[tokens_len-1], "]") {
|
||||
// Reverse-walk over tokens to find the end of
|
||||
// numeric ipv6 address
|
||||
|
||||
for i := tokens_len - 1; i >= 0; i-- {
|
||||
if strings.HasPrefix(tokens[i], "[") {
|
||||
// Store first address
|
||||
first_address = strings.Join(tokens[i:], ":")
|
||||
first_address, _ = strings.CutPrefix(first_address, "[")
|
||||
first_address, _ = strings.CutSuffix(first_address, "]")
|
||||
// break from loop
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// next is first address in non-numerical-ipv6 form
|
||||
first_address = tokens[tokens_len-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if first_port == 0 || second_port == 0 {
|
||||
return "", 0, "", 0, fmt.Errorf("Ports must not be zero")
|
||||
}
|
||||
|
||||
return first_address, first_port, second_address, second_port, nil
|
||||
}
|
||||
|
||||
type TCPMapping struct {
|
||||
Listen *net.TCPAddr
|
||||
Mapped *net.TCPAddr
|
||||
}
|
||||
|
||||
type TCPMappings []TCPMapping
|
||||
type TCPLocalMappings []TCPMapping
|
||||
|
||||
func (m *TCPMappings) String() string {
|
||||
func (m *TCPLocalMappings) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *TCPMappings) Set(value string) error {
|
||||
tokens := strings.Split(value, ":")
|
||||
if len(tokens) > 2 {
|
||||
tokens = strings.SplitN(value, ":", 2)
|
||||
host, port, err := net.SplitHostPort(tokens[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to split host and port: %w", err)
|
||||
}
|
||||
tokens = append(tokens[:1], host, port)
|
||||
}
|
||||
listenport, err := strconv.Atoi(tokens[0])
|
||||
func (m *TCPLocalMappings) Set(value string) error {
|
||||
first_address, first_port, second_address, second_port, err :=
|
||||
parseMappingString(value)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("listen port is invalid: %w", err)
|
||||
return err
|
||||
}
|
||||
if listenport == 0 {
|
||||
return fmt.Errorf("listen port must not be zero")
|
||||
|
||||
// First address can be ipv4/ipv6
|
||||
// Second address can be only Yggdrasil ipv6
|
||||
|
||||
if !strings.Contains(second_address, ":") {
|
||||
return fmt.Errorf("Yggdrasil listening address can be only IPv6")
|
||||
}
|
||||
|
||||
// Create mapping
|
||||
|
||||
mapping := TCPMapping{
|
||||
Listen: &net.TCPAddr{
|
||||
Port: listenport,
|
||||
Port: first_port,
|
||||
},
|
||||
Mapped: &net.TCPAddr{
|
||||
IP: net.IPv6loopback,
|
||||
Port: listenport,
|
||||
Port: second_port,
|
||||
},
|
||||
}
|
||||
tokens = tokens[1:]
|
||||
if len(tokens) > 0 {
|
||||
mappedaddr := net.ParseIP(tokens[0])
|
||||
|
||||
if first_address != "" {
|
||||
listenaddr := net.ParseIP(first_address)
|
||||
if listenaddr == nil {
|
||||
return fmt.Errorf("invalid listen address %q", first_address)
|
||||
}
|
||||
mapping.Listen.IP = listenaddr
|
||||
}
|
||||
|
||||
if second_address != "" {
|
||||
mappedaddr := net.ParseIP(second_address)
|
||||
if mappedaddr == nil {
|
||||
return fmt.Errorf("invalid mapped address %q", tokens[0])
|
||||
return fmt.Errorf("invalid mapped address %q", second_address)
|
||||
}
|
||||
// TODO: Filter Yggdrasil IPs here
|
||||
mapping.Mapped.IP = mappedaddr
|
||||
tokens = tokens[1:]
|
||||
}
|
||||
if len(tokens) > 0 {
|
||||
mappedport, err := strconv.Atoi(tokens[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("mapped port is invalid: %w", err)
|
||||
}
|
||||
if mappedport == 0 {
|
||||
return fmt.Errorf("mapped port must not be zero")
|
||||
}
|
||||
mapping.Mapped.Port = mappedport
|
||||
}
|
||||
|
||||
*m = append(*m, mapping)
|
||||
return nil
|
||||
}
|
||||
|
||||
type TCPRemoteMappings []TCPMapping
|
||||
|
||||
func (m *TCPRemoteMappings) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *TCPRemoteMappings) Set(value string) error {
|
||||
first_address, first_port, second_address, second_port, err :=
|
||||
parseMappingString(value)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// First address must be empty
|
||||
// Second address can be ipv4/ipv6
|
||||
|
||||
if first_address != "" {
|
||||
return fmt.Errorf("Yggdrasil listening must be empty")
|
||||
}
|
||||
|
||||
// Create mapping
|
||||
|
||||
mapping := TCPMapping{
|
||||
Listen: &net.TCPAddr{
|
||||
Port: first_port,
|
||||
},
|
||||
Mapped: &net.TCPAddr{
|
||||
IP: net.IPv6loopback,
|
||||
Port: second_port,
|
||||
},
|
||||
}
|
||||
|
||||
if first_address != "" {
|
||||
listenaddr := net.ParseIP(first_address)
|
||||
if listenaddr == nil {
|
||||
return fmt.Errorf("invalid listen address %q", first_address)
|
||||
}
|
||||
mapping.Listen.IP = listenaddr
|
||||
}
|
||||
|
||||
if second_address != "" {
|
||||
mappedaddr := net.ParseIP(second_address)
|
||||
if mappedaddr == nil {
|
||||
return fmt.Errorf("invalid mapped address %q", second_address)
|
||||
}
|
||||
mapping.Mapped.IP = mappedaddr
|
||||
}
|
||||
|
||||
*m = append(*m, mapping)
|
||||
return nil
|
||||
}
|
||||
|
||||
type UDPMapping struct {
|
||||
Listen *net.UDPAddr
|
||||
Mapped *net.UDPAddr
|
||||
}
|
||||
|
||||
type UDPLocalMappings []UDPMapping
|
||||
|
||||
func (m *UDPLocalMappings) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *UDPLocalMappings) Set(value string) error {
|
||||
first_address, first_port, second_address, second_port, err :=
|
||||
parseMappingString(value)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// First address can be ipv4/ipv6
|
||||
// Second address can be only Yggdrasil ipv6
|
||||
|
||||
if !strings.Contains(second_address, ":") {
|
||||
return fmt.Errorf("Yggdrasil listening address can be only IPv6")
|
||||
}
|
||||
|
||||
// Create mapping
|
||||
|
||||
mapping := UDPMapping{
|
||||
Listen: &net.UDPAddr{
|
||||
Port: first_port,
|
||||
},
|
||||
Mapped: &net.UDPAddr{
|
||||
IP: net.IPv6loopback,
|
||||
Port: second_port,
|
||||
},
|
||||
}
|
||||
|
||||
if first_address != "" {
|
||||
listenaddr := net.ParseIP(first_address)
|
||||
if listenaddr == nil {
|
||||
return fmt.Errorf("invalid listen address %q", first_address)
|
||||
}
|
||||
mapping.Listen.IP = listenaddr
|
||||
}
|
||||
|
||||
if second_address != "" {
|
||||
mappedaddr := net.ParseIP(second_address)
|
||||
if mappedaddr == nil {
|
||||
return fmt.Errorf("invalid mapped address %q", second_address)
|
||||
}
|
||||
// TODO: Filter Yggdrasil IPs here
|
||||
mapping.Mapped.IP = mappedaddr
|
||||
}
|
||||
|
||||
*m = append(*m, mapping)
|
||||
return nil
|
||||
}
|
||||
|
||||
type UDPRemoteMappings []UDPMapping
|
||||
|
||||
func (m *UDPRemoteMappings) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *UDPRemoteMappings) Set(value string) error {
|
||||
first_address, first_port, second_address, second_port, err :=
|
||||
parseMappingString(value)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// First address must be empty
|
||||
// Second address can be ipv4/ipv6
|
||||
|
||||
if first_address != "" {
|
||||
return fmt.Errorf("Yggdrasil listening must be empty")
|
||||
}
|
||||
|
||||
// Create mapping
|
||||
|
||||
mapping := UDPMapping{
|
||||
Listen: &net.UDPAddr{
|
||||
Port: first_port,
|
||||
},
|
||||
Mapped: &net.UDPAddr{
|
||||
IP: net.IPv6loopback,
|
||||
Port: second_port,
|
||||
},
|
||||
}
|
||||
|
||||
if first_address != "" {
|
||||
listenaddr := net.ParseIP(first_address)
|
||||
if listenaddr == nil {
|
||||
return fmt.Errorf("invalid listen address %q", first_address)
|
||||
}
|
||||
mapping.Listen.IP = listenaddr
|
||||
}
|
||||
|
||||
if second_address != "" {
|
||||
mappedaddr := net.ParseIP(second_address)
|
||||
if mappedaddr == nil {
|
||||
return fmt.Errorf("invalid mapped address %q", second_address)
|
||||
}
|
||||
mapping.Mapped.IP = mappedaddr
|
||||
}
|
||||
|
||||
*m = append(*m, mapping)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -3,26 +3,108 @@ package types
|
|||
import "testing"
|
||||
|
||||
func TestEndpointMappings(t *testing.T) {
|
||||
var mappings TCPMappings
|
||||
if err := mappings.Set("1234"); err != nil {
|
||||
var tcpMappings TCPMappings
|
||||
if err := tcpMappings.Set("1234"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := mappings.Set("1234:192.168.1.1"); err != nil {
|
||||
if err := tcpMappings.Set("1234:192.168.1.1"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := mappings.Set("1234:192.168.1.1:4321"); err != nil {
|
||||
if err := tcpMappings.Set("1234:192.168.1.1:4321"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := mappings.Set("1234:[2000::1]:4321"); err != nil {
|
||||
if err := tcpMappings.Set("192.168.1.2:1234:192.168.1.1:4321"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := mappings.Set("a"); err == nil {
|
||||
if err := tcpMappings.Set("1234:[2000::1]:4321"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := tcpMappings.Set("[2001:1]:1234:[2000::1]:4321"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := tcpMappings.Set("a"); err == nil {
|
||||
t.Fatal("'a' should be an invalid exposed port")
|
||||
}
|
||||
if err := mappings.Set("1234:localhost"); err == nil {
|
||||
if err := tcpMappings.Set("1234:localhost"); err == nil {
|
||||
t.Fatal("mapped address must be an IP literal")
|
||||
}
|
||||
if err := mappings.Set("1234:localhost:a"); err == nil {
|
||||
if err := tcpMappings.Set("127.0.0.1:1234:localhost"); err == nil {
|
||||
t.Fatal("mapped address must be an IP literal")
|
||||
}
|
||||
if err := tcpMappings.Set("[2000:1]:1234:localhost"); err == nil {
|
||||
t.Fatal("mapped address must be an IP literal")
|
||||
}
|
||||
if err := tcpMappings.Set("localhost:1234:127.0.0.1"); err == nil {
|
||||
t.Fatal("listen address must be an IP literal")
|
||||
}
|
||||
if err := tcpMappings.Set("localhost:1234:127.0.0.1"); err == nil {
|
||||
t.Fatal("listen address must be an IP literal")
|
||||
}
|
||||
if err := tcpMappings.Set("localhost:1234:[2000:1]"); err == nil {
|
||||
t.Fatal("listen address must be an IP literal")
|
||||
}
|
||||
if err := tcpMappings.Set("localhost:1234:[2000:1]"); err == nil {
|
||||
t.Fatal("listen address must be an IP literal")
|
||||
}
|
||||
if err := tcpMappings.Set("1234:localhost:a"); err == nil {
|
||||
t.Fatal("'a' should be an invalid mapped port")
|
||||
}
|
||||
if err := tcpMappings.Set("127.0.0.1:1234:127.0.0.1:a"); err == nil {
|
||||
t.Fatal("'a' should be an invalid mapped port")
|
||||
}
|
||||
if err := tcpMappings.Set("[2000::1]:1234:[2000::1]:a"); err == nil {
|
||||
t.Fatal("'a' should be an invalid mapped port")
|
||||
}
|
||||
var udpMappings UDPMappings
|
||||
if err := udpMappings.Set("1234"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := udpMappings.Set("1234:192.168.1.1"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := udpMappings.Set("1234:192.168.1.1:4321"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := udpMappings.Set("192.168.1.2:1234:192.168.1.1:4321"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := udpMappings.Set("1234:[2000::1]:4321"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := udpMappings.Set("[2001:1]:1234:[2000::1]:4321"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := udpMappings.Set("a"); err == nil {
|
||||
t.Fatal("'a' should be an invalid exposed port")
|
||||
}
|
||||
if err := udpMappings.Set("1234:localhost"); err == nil {
|
||||
t.Fatal("mapped address must be an IP literal")
|
||||
}
|
||||
if err := udpMappings.Set("127.0.0.1:1234:localhost"); err == nil {
|
||||
t.Fatal("mapped address must be an IP literal")
|
||||
}
|
||||
if err := udpMappings.Set("[2000:1]:1234:localhost"); err == nil {
|
||||
t.Fatal("mapped address must be an IP literal")
|
||||
}
|
||||
if err := udpMappings.Set("localhost:1234:127.0.0.1"); err == nil {
|
||||
t.Fatal("listen address must be an IP literal")
|
||||
}
|
||||
if err := udpMappings.Set("localhost:1234:127.0.0.1"); err == nil {
|
||||
t.Fatal("listen address must be an IP literal")
|
||||
}
|
||||
if err := udpMappings.Set("localhost:1234:[2000:1]"); err == nil {
|
||||
t.Fatal("listen address must be an IP literal")
|
||||
}
|
||||
if err := udpMappings.Set("localhost:1234:[2000:1]"); err == nil {
|
||||
t.Fatal("listen address must be an IP literal")
|
||||
}
|
||||
if err := udpMappings.Set("1234:localhost:a"); err == nil {
|
||||
t.Fatal("'a' should be an invalid mapped port")
|
||||
}
|
||||
if err := udpMappings.Set("127.0.0.1:1234:127.0.0.1:a"); err == nil {
|
||||
t.Fatal("'a' should be an invalid mapped port")
|
||||
}
|
||||
if err := udpMappings.Set("[2000::1]:1234:[2000::1]:a"); err == nil {
|
||||
t.Fatal("'a' should be an invalid mapped port")
|
||||
}
|
||||
}
|
||||
|
|
22
src/types/udpproxy.go
Normal file
22
src/types/udpproxy.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func ReverseProxyUDP(mtu uint64, dst net.PacketConn, dstAddr net.Addr, src net.Conn) error {
|
||||
buf := make([]byte, mtu)
|
||||
for {
|
||||
n, err := src.Read(buf[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n > 0 {
|
||||
n, err = dst.WriteTo(buf[:n], dstAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue