Compare commits

..

39 commits

Author SHA1 Message Date
Vasyl Gello
8ad1962f64 Implement error checking on listeners
Some checks failed
Trunk / release build / Build Windows/Linux-static/MacOS/*BSD-static/Android (push) Has been cancelled
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2025-02-08 13:26:54 +00:00
Neil Alexander
83bc9a2eec
Update to Yggdrasil 0.5.12 2024-12-18 22:39:27 +00:00
Neil Alexander
696625c14f
Update to Yggdrasil 0.5.10 2024-11-24 14:33:28 +00:00
Vasyl Gello
763e4db047 Bump yggdrasil to 0.5.9
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-10-19 19:39:53 +00:00
Vasyl Gello
c65f79d01a Bump yggdrasil-go and gvisor
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-08-13 09:27:06 +00:00
Vasyl Gello
58b3efd2da Trigger CI builds on pull requests
... but upload only tags or pyshes to develop branch

Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-08-06 13:12:14 +00:00
Vasyl Gello
bfc106637a Fix UDP port forward not working with Yggdrasil client
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-08-06 13:12:14 +00:00
Vasyl Gello
08f51fded2 Canonicalize DNS example in readme
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-08-06 06:44:44 +03:00
Vasyl Gello
7a72fe25ab Edit README.md
* Go needed version is 1.22 now thx to gvisor
  * Add external DNS nameserver usage example

[skip CI] skip CI

Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-08-06 06:38:45 +03:00
Vasyl Gello
873b19b7c6 Fix release upload
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-08-05 22:47:56 +03:00
Vasyl Gello
98b1a1c79d Add caching Go setup step
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-08-05 22:19:11 +03:00
Vasyl Gello
b132d6af16 Make CI run on branch or tag push
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-08-05 22:15:59 +03:00
Vasyl Gello
4844607750 Bump dependencies
* ygdrasil-go 0.5.7

Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-08-05 22:13:02 +03:00
Vasyl Gello
9395ddbfa2 Expand trunk builds for tags
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-08-05 21:57:38 +03:00
Vasyl Gello
5a87e43f9a Try building only static executables for Linux/*BSD
It appears Go toolchain silently uses netgo+osusergo+static
if cross-compiling but provides dynamicaly-linked executable
for native arch. Keeping track of all Linux and *BSD sysroots
is impractical so lets ship static executables where possible.
They may bot honor system DNS resolver but at least they work
everywhere.

Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-07-26 11:54:55 +03:00
Vasyl Gello
fef083ae4a Declare *bsd builds are static and drop CGO_ENABLED for ststic build
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-07-26 11:35:36 +03:00
Vasyl Gello
95a41a3e8f Use golang:1.21-buster for glibc stuff
From Matrix Yggdrasil developer room:

The only problem is on Ubuntu 20.04:
yggstack-linux-amd64: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by ./yggstack-linux-amd64)
yggstack-linux-amd64: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found (required by ./yggstack-linux-amd64)

We do not need latest Ubuntu as we dont use external linking in static binaries.

Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-07-26 07:14:29 +03:00
Vasyl Gello
3be03c793f Try publishing static binaries as distroless containers
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-07-25 11:22:28 +03:00
Vasyl Gello
b534d1205e Try building static linux binaries without external linking 2024-07-25 07:12:59 +03:00
Vasyl Gello
1eb9a94d2c Try to use netgo,osusergo,static for static builds
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-07-25 07:02:14 +03:00
Vasyl Gello
9da884697a
Fix gvisor changes
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-07-24 18:37:35 +03:00
Vasyl Gello
f0eecd21d4
Bump yggdrasil-go and gvisor
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-07-24 18:16:56 +03:00
Vasyl Gello
8a6c67475c
Switch back to glibc for static builds
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-07-24 17:55:45 +03:00
Vasyl Gello
2c09a1d7b2
Fix .pk.ygg resolver after refactoring
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-07-23 22:44:14 +03:00
Vasyl Gello
5008a4ea2d Do not leak sessions
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-07-22 07:23:16 +03:00
Vasyl Gello
457b1d99c5 Build Linux static executables with musl-cross
(except ppc64, ppc64le)

Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-07-19 14:49:16 +03:00
Vasyl Gello
f529064aa0 Refactor UDP port forwarding and document usage 2024-07-19 12:07:56 +03:00
Vasyl Gello
0783b429fd [WIP] Introduce TCP/UDP local/remote port forwarding
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-07-19 05:50:53 +03:00
Vasyl Gello
30d51ba566 Try to fix #4
... by catching TCP RST packets in WritePackets and sending them
during the next WritePackets call where no RST packet is being sent

Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-07-19 05:50:52 +03:00
Vasyl Gello
b160b3f66d
Add UDP port exposure
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-07-18 18:01:11 +03:00
Vasyl Gello
582fe511fa Fix unix domain socket creation/cleanup logic
* If there is another instance still listening on the same
    Unix domain socket, bail out

  * If there is a leftover from crashed yggstack etc,
    clean the socket file and proceed

Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-07-16 07:32:07 +03:00
Artem Andreenko
dcc0284e3b Implemented UNIX socket support for SOCKS5 server in yggstack command and updated README.md with usage instructions. 2024-07-15 10:19:15 +00:00
Neil Alexander
174bb7026d
Update to Yggdrasil v0.5.6 2024-06-01 16:15:03 +01:00
Vasyl Gello
edbaa72445 Do notvtry to open admin socket in autoconf too
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-03-24 19:44:52 +02:00
Vasyl Gello
7b5300a476 Try to fix gh upload 2024-01-28 14:10:18 +02:00
Neil Alexander
5520ef03bf
Update to Yggdrasil v0.5.5 2024-01-28 11:11:02 +00:00
Vasyl Gello
f465d71770 [skip CI] Add information about downloads
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-01-14 06:55:07 +02:00
Vasyl Gello
8f21eaa31a [skip ci] Overwrite trunk build artifacts in release
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-01-07 17:49:30 +02:00
Vasyl Gello
3fa4809cd1 [Skip CI] Fix badge
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-01-07 17:37:54 +02:00
12 changed files with 1180 additions and 308 deletions

View file

@ -1,8 +1,17 @@
name: Trunk build name: Trunk / release build
on: on:
pull_request:
paths-ignore:
- "README.md"
push: 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: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
@ -10,69 +19,246 @@ concurrency:
permissions: permissions:
contents: write contents: write
packages: write
jobs: jobs:
build: build:
strategy: strategy:
fail-fast: false fail-fast: false
name: Build Windows/Linux/MacOS/FreeBSD/Android name: Build Windows/Linux-static/MacOS/*BSD-static/Android
runs-on: ubuntu-20.04 runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Set up Go - uses: actions/setup-go@v5
uses: actions/setup-go@v3
with: with:
go-version: "1.21" go-version: '1.22'
- name: Build static executables - name: Check if commit needs a release upload
run: | run: |
GOOS=windows GOARCH=arm GOARM=7 ./build -o yggstack-windows-armv7.exe if [ "${{ github.ref_type }}" = "tag" ]; then
GOOS=windows GOARCH=arm64 ./build -o yggstack-windows-arm64.exe echo "RELEASENAME=${{ github.ref_name }}" >> "$GITHUB_ENV"
GOOS=windows GOARCH=386 ./build -o yggstack-windows-i386.exe 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=windows GOARCH=amd64 ./build -o yggstack-windows-amd64.exe
GOOS=linux GOARCH=386 ./build -o yggstack-linux-i386 echo "::endgroup::"
GOOS=linux GOARCH=amd64 ./build -o yggstack-linux-amd64 #
GOOS=linux GOARCH=arm GOARM=6 ./build -o yggstack-linux-armv6 echo "::group::yggstack-windows-arm64.exe"
GOOS=linux GOARCH=arm GOARM=7 ./build -o yggstack-linux-armv7 GOOS=windows GOARCH=arm64 ./build -o yggstack-windows-arm64.exe
GOOS=linux GOARCH=arm64 ./build -o yggstack-linux-arm64 echo "::endgroup::"
GOOS=linux GOARCH=mips GOMIPS=softfloat ./build -o yggstack-linux-mips-sf #
GOOS=linux GOARCH=mipsle GOMIPS=softfloat ./build -o yggstack-linux-mipsle-sf echo "::group::yggstack-windows-armv7.exe"
GOOS=linux GOARCH=mips64 ./build -o yggstack-linux-mips64 GOOS=windows GOARCH=arm GOARM=7 ./build -o yggstack-windows-armv7.exe
GOOS=linux GOARCH=mips64le ./build -o yggstack-linux-mips64le echo "::endgroup::"
GOOS=linux GOARCH=ppc64 ./build -o yggstack-linux-ppc64 #
GOOS=linux GOARCH=ppc64le ./build -o yggstack-linux-ppc64le echo "::group::yggstack-windows-i386.exe"
GOOS=linux GOARCH=riscv64 ./build -o yggstack-linux-riscv64 GOOS=windows GOARCH=386 ./build -o yggstack-windows-i386.exe
GOOS=linux GOARCH=s390x ./build -o yggstack-linux-s390x GOOS=windows GOARCH=386 ./build -o yggstack-windows-386.exe
GOOS=darwin GOARCH=arm64 ./build -o yggstack-darwin-arm64 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=darwin GOARCH=amd64 ./build -o yggstack-darwin-amd64
GOOS=freebsd GOARCH=arm64 ./build -o yggstack-freebsd-arm64 echo "::endgroup::"
GOOS=freebsd GOARCH=amd64 ./build -o yggstack-freebsd-amd64 #
GOOS=freebsd GOARCH=arm GOARM=6 ./build -o yggstack-freebsd-armv6 echo "::group::yggstack-darwin-arm64"
GOOS=freebsd GOARCH=arm GOARM=7 ./build -o yggstack-freebsd-armv7 GOOS=darwin GOARCH=arm64 ./build -o yggstack-darwin-arm64
GOOS=freebsd GOARCH=386 ./build -o yggstack-freebsd-i386 echo "::endgroup::"
GOOS=openbsd GOARCH=arm64 ./build -o yggstack-openbsd-arm64 #
GOOS=openbsd GOARCH=amd64 ./build -o yggstack-openbsd-amd64 echo "::group::yggstack-freebsd-amd64-static"
GOOS=openbsd GOARCH=arm GOARM=6 ./build -o yggstack-openbsd-armv6 GOOS=freebsd GOARCH=amd64 ./build -o yggstack-freebsd-amd64-static
GOOS=openbsd GOARCH=arm GOARM=7 ./build -o yggstack-openbsd-armv7 echo "::endgroup::"
GOOS=openbsd GOARCH=386 ./build -o yggstack-openbsd-i386 #
GOOS=netbsd GOARCH=arm64 ./build -o yggstack-netbsd-arm64 echo "::group::yggstack-freebsd-arm64-static"
GOOS=netbsd GOARCH=amd64 ./build -o yggstack-netbsd-amd64 GOOS=freebsd GOARCH=arm64 ./build -o yggstack-freebsd-arm64-static
GOOS=netbsd GOARCH=arm GOARM=6 ./build -o yggstack-netbsd-armv6 echo "::endgroup::"
GOOS=netbsd GOARCH=arm GOARM=7 ./build -o yggstack-netbsd-armv7 #
GOOS=netbsd GOARCH=386 ./build -o yggstack-netbsd-i386 echo "::group::yggstack-freebsd-armv6-static"
CC="$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang" GOOS=android GOARCH=arm64 ./build -o yggstack-android-arm64 GOOS=freebsd GOARCH=arm GOARM=6 ./build -o yggstack-freebsd-armv6-static
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::"
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 "::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 #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 #GOOS=ios GOARCH=amd64 CC=$(go env GOROOT)/misc/ios/clangwrap.sh ./build -o yggstack-ios-amd64
#echo "::endgroup::"
- name: Publish release - name: Publish release
if: ${{ env.SKIP_UPLOAD == '' }}
run: | 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: env:
GH_TOKEN: ${{ github.token }} 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
View 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" ]

View file

@ -1,6 +1,6 @@
# Yggstack - Yggdrasil as SOCKS proxy / port forwarder # Yggstack - Yggdrasil as SOCKS proxy / port forwarder
[![Build status](https://github.com/yggdrasil-network/yggstack/actions/workflows/ci.yml/badge.svg)](https://github.com/yggdrasil-network/yggstack/actions/workflows/ci.yml) [![Build status](https://github.com/yggdrasil-network/yggstack/actions/workflows/trunk.yml/badge.svg)](https://github.com/yggdrasil-network/yggstack/actions/workflows/trunk.yml)
## Introduction ## 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 page for more information. You may also find other platform-specific wrappers, scripts
or tools in the `contrib` folder. 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 ## Building
If you want to build from source, as opposed to installing one of the pre-built If you want to build from source, as opposed to installing one of the pre-built
packages: 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. Clone this repository
2. Run `./build` 2. Run `./build`
@ -66,17 +72,48 @@ other configuration such as listen addresses or multicast addresses, etc.
### Run Yggstack ### 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 ./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 To run SOCKS proxy server listening on UNIX socket file `/tmp/yggstack.sock`:
network address at port 80:
``` ```
./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: 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 You can even run several Yggstack instances with different configurations
on the same OS and user! 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 ### pk.ygg DNS resolver
One unique feature of Yggstack is built-in DNS resolver functionality using 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`) For example, HowToYgg website (whose public key is `d40d4a7153cf288ea28f1865f6cfe95143a478b5c8c9e7cb002a0633d10a53eb`)
can be accessed by any Web browser supporting SOCKS servers 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: You can even use cURL with Yggstack:

3
build
View file

@ -9,7 +9,7 @@ PKGVER=${PKGVER:-$(sh contrib/semver/version.sh --bare)}
LDFLAGS="-X $PKGSRC.buildName=$PKGNAME -X $PKGSRC.buildVersion=$PKGVER" LDFLAGS="-X $PKGSRC.buildName=$PKGNAME -X $PKGSRC.buildVersion=$PKGVER"
ARGS="-v" ARGS="-v"
while getopts "utc:l:dro:p" option while getopts "utc:l:dro:ps" option
do do
case "$option" case "$option"
in in
@ -21,6 +21,7 @@ do
r) ARGS="$ARGS -race";; r) ARGS="$ARGS -race";;
o) ARGS="$ARGS -o $OPTARG";; o) ARGS="$ARGS -o $OPTARG";;
p) ARGS="$ARGS -buildmode=pie";; p) ARGS="$ARGS -buildmode=pie";;
s) ARGS="$ARGS -tags netgo,osusersgo,static" LDFLAGS="$LDFLAGS -extldflags '-static'" CGO_ENABLED=0;;
esac esac
done done

View file

@ -5,13 +5,16 @@ import (
"crypto/ed25519" "crypto/ed25519"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors"
"flag" "flag"
"fmt" "fmt"
"net" "net"
"os" "os"
"os/signal" "os/signal"
"regexp" "regexp"
"runtime"
"strings" "strings"
"sync"
"syscall" "syscall"
"github.com/gologme/log" "github.com/gologme/log"
@ -28,17 +31,29 @@ import (
"github.com/yggdrasil-network/yggstack/src/netstack" "github.com/yggdrasil-network/yggstack/src/netstack"
"github.com/yggdrasil-network/yggstack/src/types" "github.com/yggdrasil-network/yggstack/src/types"
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
) )
type node struct { type node struct {
core *core.Core core *core.Core
multicast *multicast.Multicast multicast *multicast.Multicast
admin *admin.AdminSocket 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. // The main function is responsible for configuring and starting Yggdrasil.
func main() { 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") genconf := flag.Bool("genconf", false, "print a new config to stdout")
useconf := flag.Bool("useconf", false, "read HJSON/JSON config from stdin") useconf := flag.Bool("useconf", false, "read HJSON/JSON config from stdin")
useconffile := flag.String("useconffile", "", "read HJSON/JSON config from specified file path") 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") 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")
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") 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() flag.Parse()
// Catch interrupts from the operating system to exit gracefully. // Catch interrupts from the operating system to exit gracefully.
@ -95,6 +113,8 @@ func main() {
return return
case *autoconf: case *autoconf:
// Force AdminListen to none in yggstack
cfg.AdminListen = "none"
// Use an autoconf-generated config, this will give us random keys and // Use an autoconf-generated config, this will give us random keys and
// port numbers, and will use an automatically selected TUN interface. // port numbers, and will use an automatically selected TUN interface.
@ -114,6 +134,7 @@ func main() {
_ = f.Close() _ = f.Close()
case *genconf: case *genconf:
// Force AdminListen to none in yggstack
cfg.AdminListen = "none" cfg.AdminListen = "none"
var bs []byte var bs []byte
if *confjson { if *confjson {
@ -268,29 +289,164 @@ func main() {
// Create SOCKS server // Create SOCKS server
{ {
if socks != nil && nameserver != nil && *socks != "" { if socks != nil && *socks != "" {
resolver := types.NewNameResolver(s, *nameserver)
socksOptions := []socks5.Option{ socksOptions := []socks5.Option{
socks5.WithDial(s.DialContext), 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") { if logger.GetLevel("debug") {
socksOptions = append(socksOptions, socks5.WithLogger(logger)) socksOptions = append(socksOptions, socks5.WithLogger(logger))
} }
server := socks5.NewServer(socksOptions...) 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) { go func(mapping types.TCPMapping) {
listener, err := s.ListenTCP(mapping.Listen) listener, err := s.ListenTCP(mapping.Listen)
if err != nil { if err != nil {
panic(err) 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 { for {
c, err := listener.Accept() c, err := listener.Accept()
if err != nil { 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. // Block until we are told to shut down.
<-ctx.Done() <-ctx.Done()
// Shut down the node. // Shut down the node.
_ = n.admin.Stop() _ = n.admin.Stop()
_ = n.multicast.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() 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) { func setLogLevel(loglevel string, logger *log.Logger) {
levels := [...]string{"error", "warn", "info", "debug", "trace"} levels := [...]string{"error", "warn", "info", "debug", "trace"}
loglevel = strings.ToLower(loglevel) loglevel = strings.ToLower(loglevel)

48
go.mod
View file

@ -1,34 +1,38 @@
module github.com/yggdrasil-network/yggstack module github.com/yggdrasil-network/yggstack
go 1.21.4 go 1.22.0
toolchain go1.22.5
require ( require (
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/things-go/go-socks5 v0.0.4 github.com/things-go/go-socks5 v0.0.5
github.com/yggdrasil-network/yggdrasil-go v0.5.4 github.com/yggdrasil-network/yggdrasil-go v0.5.12
gvisor.dev/gvisor v0.0.0-20240103195848-a9a6a6819b00 gvisor.dev/gvisor v0.0.0-20240810013311-326fe0f2a77f
) )
require ( 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/Arceliar/phony v0.0.0-20220903101357-530938a4b13d // indirect
github.com/bits-and-blooms/bitset v1.13.0 // indirect github.com/bits-and-blooms/bitset v1.14.3 // indirect
github.com/bits-and-blooms/bloom/v3 v3.6.0 // indirect github.com/bits-and-blooms/bloom/v3 v3.7.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/coder/websocket v1.8.12 // indirect
github.com/google/btree v1.1.2 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42 // indirect github.com/google/btree v1.1.3 // indirect
github.com/onsi/ginkgo/v2 v2.13.2 // indirect github.com/google/pprof v0.0.0-20241017200806-017d972448fc // indirect
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect github.com/onsi/ginkgo/v2 v2.20.2 // indirect
github.com/quic-go/quic-go v0.40.1 // indirect github.com/quic-go/quic-go v0.48.2 // indirect
go.uber.org/mock v0.4.0 // indirect github.com/wlynxg/anet v0.0.5 // indirect
golang.org/x/crypto v0.17.0 // indirect go.uber.org/mock v0.5.0 // indirect
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect golang.org/x/crypto v0.31.0 // indirect
golang.org/x/mod v0.14.0 // indirect golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
golang.org/x/net v0.19.0 // indirect golang.org/x/mod v0.21.0 // indirect
golang.org/x/sys v0.16.0 // indirect golang.org/x/net v0.32.0 // indirect
golang.org/x/text v0.14.0 // indirect golang.org/x/sync v0.10.0 // indirect
golang.org/x/time v0.5.0 // indirect golang.org/x/sys v0.28.0 // indirect
golang.org/x/tools v0.16.1 // 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
View file

@ -1,179 +1,73 @@
github.com/Arceliar/ironwood v0.0.0-20231126105342-ad38416a77c8 h1:qyXiPZClVoe6QsbsiDP23g0Ze/MNXiHIAL/nVNfauH0= github.com/Arceliar/ironwood v0.0.0-20241213013129-743fe2fccbd3 h1:d8N0z+udAnbU5PdjpLSNPTWlqeU/nnYsQ42B6+879aw=
github.com/Arceliar/ironwood v0.0.0-20231126105342-ad38416a77c8/go.mod h1:5x7fWW0mshe9WQ1lvSMmmHBYC3BeHH9gpwW5tz7cbfw= github.com/Arceliar/ironwood v0.0.0-20241213013129-743fe2fccbd3/go.mod h1:SrrElc3FFMpYCODSr11jWbLFeOM8WsY+DbDY/l2AXF0=
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/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/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.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.14.3 h1:Gd2c8lSNf9pKXom5JtD7AaKO8o7fGQ2LtFj1436qilA=
github.com/bits-and-blooms/bitset v1.11.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bits-and-blooms/bitset v1.14.3/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= github.com/bits-and-blooms/bloom/v3 v3.7.0 h1:VfknkqV4xI+PsaDIsoHueyxVDZrfvMn56jeWUzvzdls=
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bits-and-blooms/bloom/v3 v3.7.0/go.mod h1:VKlUSvp0lFIYqxJjzdnSsZEw4iHb1kOL2tfHTgyJBHg=
github.com/bits-and-blooms/bloom/v3 v3.3.1 h1:K2+A19bXT8gJR5mU7y+1yW6hsKfNCjcP2uNfLFKncjQ= github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo=
github.com/bits-and-blooms/bloom/v3 v3.3.1/go.mod h1:bhUUknWd5khVbTe4UgMCSiOOVJzr3tMoijSK3WwvW90= github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
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/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=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
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/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.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.5.9/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-20241017200806-017d972448fc h1:NGyrhhFhwvRAZg02jnYVg3GBQy0qGBKmFQJwaPmpmxs=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20241017200806-017d972448fc/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
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/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= 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 h1:D/NPvqOCH6/eisTb5/ztuIS8GUvmpHaLOcNk1Bjr298=
github.com/hjson/hjson-go/v4 v4.4.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E= 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.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
github.com/onsi/ginkgo/v2 v2.13.1 h1:LNGfMbR2OVGBfXjvRZIZ2YCTQdGKtPLvuI1rMCCj3OU= github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
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/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/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE=
github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/quic-go/quic-go v0.39.3 h1:o3YB6t2SR+HU/pgwF29kJ6g4jJIJEwEZ8CKia1h1TKg= github.com/things-go/go-socks5 v0.0.5 h1:qvKaGcBkfDrUL33SchHN93srAmYGzb4CxSM2DPYufe8=
github.com/quic-go/quic-go v0.39.3/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q= github.com/things-go/go-socks5 v0.0.5/go.mod h1:mtzInf8v5xmsBpHZVbIw2YQYhc4K0jRwzfsH64Uh0IQ=
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/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/yggdrasil-network/yggdrasil-go v0.5.3 h1:tfAajYmaiS1L9XevdEC1VUpScpgFfCW7/oEEWxdv5aM= github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU=
github.com/yggdrasil-network/yggdrasil-go v0.5.3/go.mod h1:qRzHB8bKEIpd1pQVYoZ+SedJJTBG0X9sbyctWxQDDGA= github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
github.com/yggdrasil-network/yggdrasil-go v0.5.4 h1:A7ZFmxkkbZhtqJgQXBVDw5sHsi25aUawLlJCCHnNsAs= github.com/yggdrasil-network/yggdrasil-go v0.5.12 h1:SaQ8d59JP+uFy+nOWXTx1ETM5r2uCfe1Gt/d+IodHJw=
github.com/yggdrasil-network/yggdrasil-go v0.5.4/go.mod h1:TLmU4X0nfzCY9t5xABtFQ6GLoOtCae8xVatC9JwjD5I= github.com/yggdrasil-network/yggdrasil-go v0.5.12/go.mod h1:u4DU6dpTfWmVs8r0WjW1T3UpGyeUh9vRrS8zngvncwM=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM= golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
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=
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-20231125084359-4b4191b8cad1 h1:J9340hJZ+P01JeVPK8GatP/6Bk7j2dyLUiKct5k7IBA= gvisor.dev/gvisor v0.0.0-20240810013311-326fe0f2a77f h1:llng6MGz63x02Xs1Ft71riYTfau4zS8OAZKv5jgPX6M=
gvisor.dev/gvisor v0.0.0-20231125084359-4b4191b8cad1/go.mod h1:10sU+Uh5KKNv1+2x2A0Gvzt8FjD3ASIhorV3YsauXhk= gvisor.dev/gvisor v0.0.0-20240810013311-326fe0f2a77f/go.mod h1:sxc3Uvk/vHcd3tj7/DHVBoR5wvWT/MmRq2pj7HRJnwU=
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=

View file

@ -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) fa, pn, _ := convertToFullAddr(addr.IP, addr.Port)
return gonet.DialTCP(s.stack, fa, pn) 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) fa, pn, _ := convertToFullAddr(addr.IP, addr.Port)
return gonet.DialUDP(s.stack, nil, &fa, pn) 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) 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) fa, pn, _ := convertToFullAddr(addr.IP, addr.Port)
return gonet.DialUDP(s.stack, &fa, nil, pn) return gonet.DialUDP(s.stack, &fa, nil, pn)
} }

View file

@ -12,6 +12,7 @@ import (
"gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6" "gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
"gvisor.dev/gvisor/pkg/tcpip/stack" "gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
) )
type YggdrasilNIC struct { type YggdrasilNIC struct {
@ -20,15 +21,17 @@ type YggdrasilNIC struct {
dispatcher stack.NetworkDispatcher dispatcher stack.NetworkDispatcher
readBuf []byte readBuf []byte
writeBuf []byte writeBuf []byte
rstPackets chan *stack.PacketBuffer
} }
func (s *YggdrasilNetstack) NewYggdrasilNIC(ygg *core.Core) tcpip.Error { func (s *YggdrasilNetstack) NewYggdrasilNIC(ygg *core.Core) tcpip.Error {
rwc := ipv6rwc.NewReadWriteCloser(ygg) rwc := ipv6rwc.NewReadWriteCloser(ygg)
mtu := rwc.MTU() mtu := rwc.MTU()
nic := &YggdrasilNIC{ nic := &YggdrasilNIC{
ipv6rwc: rwc, ipv6rwc: rwc,
readBuf: make([]byte, mtu), readBuf: make([]byte, mtu),
writeBuf: make([]byte, mtu), writeBuf: make([]byte, mtu),
rstPackets: make(chan *stack.PacketBuffer, 100),
} }
if err := s.stack.CreateNIC(1, nic); err != nil { if err := s.stack.CreateNIC(1, nic); err != nil {
return err return err
@ -48,6 +51,15 @@ func (s *YggdrasilNetstack) NewYggdrasilNIC(ygg *core.Core) tcpip.Error {
nic.dispatcher.DeliverNetworkPacket(ipv6.ProtocolNumber, pkb) 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") _, snet, err := net.ParseCIDR("0200::/7")
if err != nil { if err != nil {
return &tcpip.ErrBadAddress{} 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) MTU() uint32 { return uint32(e.ipv6rwc.MTU()) }
func (e *YggdrasilNIC) SetMTU(uint32) {}
func (*YggdrasilNIC) Capabilities() stack.LinkEndpointCapabilities { return stack.CapabilityNone } func (*YggdrasilNIC) Capabilities() stack.LinkEndpointCapabilities { return stack.CapabilityNone }
func (*YggdrasilNIC) MaxHeaderLength() uint16 { return 40 } func (*YggdrasilNIC) MaxHeaderLength() uint16 { return 40 }
func (*YggdrasilNIC) LinkAddress() tcpip.LinkAddress { return "" } func (*YggdrasilNIC) LinkAddress() tcpip.LinkAddress { return "" }
func (*YggdrasilNIC) SetLinkAddress(tcpip.LinkAddress) {}
func (*YggdrasilNIC) Wait() {} 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( func (e *YggdrasilNIC) WritePackets(
list stack.PacketBufferList, list stack.PacketBufferList,
) (int, tcpip.Error) { ) (int, tcpip.Error) {
var i int = 0 var i int = 0
var err tcpip.Error = nil
for i, pkt := range list.AsSlice() { for i, pkt := range list.AsSlice() {
vv := pkt.ToView() if pkt.Data().Size() == 0 {
n, err := vv.Read(e.writeBuf) if pkt.Network().TransportProtocol() == tcp.ProtocolNumber {
if err != nil { tcpHeader := header.TCP(pkt.TransportHeader().Slice())
log.Println(err) if (tcpHeader.Flags() & header.TCPFlagRst) == header.TCPFlagRst {
return i - 1, &tcpip.ErrAborted{} e.rstPackets <- pkt
continue
}
}
} }
_, err = e.ipv6rwc.Write(e.writeBuf[:n]) err = e.writePacket(pkt)
if err != nil { if err != nil {
log.Println(err) 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 return true
} }
func (e *YggdrasilNIC) Close() error { func (e *YggdrasilNIC) Close() {
e.stack.stack.RemoveNIC(1) e.stack.stack.RemoveNIC(1)
e.dispatcher = nil e.dispatcher = nil
return nil
} }
func (e *YggdrasilNIC) SetOnCloseAction(func()) {}

View file

@ -7,62 +7,381 @@ import (
"strings" "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 { type TCPMapping struct {
Listen *net.TCPAddr Listen *net.TCPAddr
Mapped *net.TCPAddr Mapped *net.TCPAddr
} }
type TCPMappings []TCPMapping type TCPLocalMappings []TCPMapping
func (m *TCPMappings) String() string { func (m *TCPLocalMappings) String() string {
return "" return ""
} }
func (m *TCPMappings) Set(value string) error { func (m *TCPLocalMappings) Set(value string) error {
tokens := strings.Split(value, ":") first_address, first_port, second_address, second_port, err :=
if len(tokens) > 2 { parseMappingString(value)
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])
if err != nil { 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{ mapping := TCPMapping{
Listen: &net.TCPAddr{ Listen: &net.TCPAddr{
Port: listenport, Port: first_port,
}, },
Mapped: &net.TCPAddr{ Mapped: &net.TCPAddr{
IP: net.IPv6loopback, IP: net.IPv6loopback,
Port: listenport, Port: second_port,
}, },
} }
tokens = tokens[1:]
if len(tokens) > 0 { if first_address != "" {
mappedaddr := net.ParseIP(tokens[0]) 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 { 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 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) *m = append(*m, mapping)
return nil return nil
} }

View file

@ -3,26 +3,108 @@ package types
import "testing" import "testing"
func TestEndpointMappings(t *testing.T) { func TestEndpointMappings(t *testing.T) {
var mappings TCPMappings var tcpMappings TCPMappings
if err := mappings.Set("1234"); err != nil { if err := tcpMappings.Set("1234"); err != nil {
t.Fatal(err) 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) 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) 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) 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") 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") 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") t.Fatal("'a' should be an invalid mapped port")
} }
} }

22
src/types/udpproxy.go Normal file
View 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
}