diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 9584ee7..0000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,232 +0,0 @@ -# Golang CircleCI 2.0 configuration file -# -# Check https://circleci.com/docs/2.0/language-go/ for more details -version: 2.1 -jobs: - lint: - docker: - - image: circleci/golang:1.17 - - steps: - - checkout - - - run: - name: Run golangci-lint - command: | - go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.31.0 - golangci-lint run - - - run: - name: Run Go tests - command: | - go test ./... - - build-linux: - docker: - - image: circleci/golang:1.17 - - steps: - - checkout - - - run: - name: Create artifact upload directory and set variables - command: | - mkdir /tmp/upload - echo 'export CINAME=$(sh contrib/semver/name.sh)' >> $BASH_ENV - echo 'export CIVERSION=$(sh contrib/semver/version.sh --bare)' >> $BASH_ENV - echo 'export CIVERSIONRPM=$(sh contrib/semver/version.sh --bare | tr "-" ".")' >> $BASH_ENV - echo 'export CIBRANCH=$(echo $CIRCLE_BRANCH | tr -d "/")' >> $BASH_ENV - case "$CINAME" in \ - "yggdrasil") (echo 'export CICONFLICTS=yggdrasil-develop' >> $BASH_ENV) ;; \ - "yggdrasil-develop") (echo 'export CICONFLICTS=yggdrasil' >> $BASH_ENV) ;; \ - *) (echo 'export CICONFLICTS="yggdrasil yggdrasil-develop"' >> $BASH_ENV) ;; \ - esac - git config --global user.email "$(git log --format='%ae' HEAD -1)"; - git config --global user.name "$(git log --format='%an' HEAD -1)"; - - - run: - name: Install RPM utilities - command: | - sudo apt-get update - sudo apt-get install -y rpm file - mkdir -p ~/rpmbuild/BUILD ~/rpmbuild/RPMS ~/rpmbuild/SOURCES ~/rpmbuild/SPECS ~/rpmbuild/SRPMS - - - run: - name: Test debug builds - command: | - ./build -d - test -f yggdrasil && test -f yggdrasilctl - - - run: - name: Build for Linux (including Debian packages) - command: | - rm -f {yggdrasil,yggdrasilctl} - PKGARCH=amd64 sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-amd64 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-linux-amd64; - PKGARCH=i386 sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-i386 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-linux-i386; - PKGARCH=mipsel sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-mipsel && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-linux-mipsel; - PKGARCH=mips sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-mips && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-linux-mips; - PKGARCH=armhf sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-armhf && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-linux-armhf; - PKGARCH=armel sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-armel && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-linux-armel; - PKGARCH=arm64 sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-arm64 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-linux-arm64; - mv *.deb /tmp/upload/ - - - run: - name: Build for Linux (RPM packages) - command: | - git clone https://github.com/yggdrasil-network/yggdrasil-package-rpm ~/rpmbuild/SPECS - cd ../ && tar -czvf ~/rpmbuild/SOURCES/v$CIVERSIONRPM --transform "s/project/yggdrasil-go-$CIBRANCH-$CIVERSIONRPM/" project - sed -i "s/yggdrasil-go/yggdrasil-go-$CIBRANCH/" ~/rpmbuild/SPECS/yggdrasil.spec - sed -i "s/^PKGNAME=yggdrasil/PKGNAME=yggdrasil-$CIBRANCH/" ~/rpmbuild/SPECS/yggdrasil.spec - sed -i "s/^Name\:.*/Name\: $CINAME/" ~/rpmbuild/SPECS/yggdrasil.spec - sed -i "s/^Version\:.*/Version\: $CIVERSIONRPM/" ~/rpmbuild/SPECS/yggdrasil.spec - sed -i "s/^Conflicts\:.*/Conflicts\: $CICONFLICTS/" ~/rpmbuild/SPECS/yggdrasil.spec - cat ~/rpmbuild/SPECS/yggdrasil.spec - GOARCH=amd64 rpmbuild -v --nodeps --target=x86_64 -ba ~/rpmbuild/SPECS/yggdrasil.spec - #GOARCH=386 rpmbuild -v --nodeps --target=i386 -bb ~/rpmbuild/SPECS/yggdrasil.spec - find ~/rpmbuild/RPMS/ -name '*.rpm' -exec mv {} /tmp/upload \; - find ~/rpmbuild/SRPMS/ -name '*.rpm' -exec mv {} /tmp/upload \; - - - run: - name: Build for EdgeRouter and VyOS - command: | - rm -f {yggdrasil,yggdrasilctl} - git clone https://github.com/neilalexander/vyatta-yggdrasil /tmp/vyatta-yggdrasil; - cd /tmp/vyatta-yggdrasil; - BUILDDIR_YGG=$CIRCLE_WORKING_DIRECTORY ./build-edgerouter-x $CIRCLE_BRANCH; - BUILDDIR_YGG=$CIRCLE_WORKING_DIRECTORY ./build-edgerouter-lite $CIRCLE_BRANCH; - BUILDDIR_YGG=$CIRCLE_WORKING_DIRECTORY ./build-vyos-i386 $CIRCLE_BRANCH - BUILDDIR_YGG=$CIRCLE_WORKING_DIRECTORY ./build-vyos-amd64 $CIRCLE_BRANCH - mv *.deb /tmp/upload; - - - persist_to_workspace: - root: /tmp - paths: - - upload - - build-macos: - macos: - xcode: "13.0.0" - - working_directory: ~/go/src/github.com/yggdrasil-network/yggdrasil-go - - steps: - - checkout - - - run: - name: Create artifact upload directory and set variables - command: | - mkdir /tmp/upload - echo 'export CINAME=$(sh contrib/semver/name.sh)' >> $BASH_ENV - echo 'export CIVERSION=$(sh contrib/semver/version.sh --bare)' >> $BASH_ENV - echo 'export PATH=$PATH:/usr/local/go/bin:~/go/bin' >> $BASH_ENV - git config --global user.email "$(git log --format='%ae' HEAD -1)"; - git config --global user.name "$(git log --format='%an' HEAD -1)"; - echo -e "Host *\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config - - - run: - name: Install Go 1.17 - command: | - cd /tmp - curl -LO https://dl.google.com/go/go1.17.darwin-amd64.pkg - sudo installer -pkg /tmp/go1.17.darwin-amd64.pkg -target / - - #- run: - # name: Install Gomobile - # command: | - # GO111MODULE=off go get golang.org/x/mobile/cmd/gomobile - # gomobile init - - - run: - name: Build for macOS - command: | - GO111MODULE=on GOOS=darwin GOARCH=amd64 ./build - cp yggdrasil /tmp/upload/$CINAME-$CIVERSION-darwin-amd64 - cp yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-darwin-amd64; - GO111MODULE=on GOOS=darwin GOARCH=arm64 ./build - cp yggdrasil /tmp/upload/$CINAME-$CIVERSION-darwin-arm64 - cp yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-darwin-arm64; - - - run: - name: Build for macOS (.pkg format) - command: | - PKGARCH=amd64 sh contrib/macos/create-pkg.sh - PKGARCH=arm64 sh contrib/macos/create-pkg.sh - mv *.pkg /tmp/upload/ - - #- run: - # name: Build framework for iOS (.framework format) - # command: | - # sudo GO111MODULE=off go get -v github.com/yggdrasil-network/yggdrasil-go/cmd/... - # sudo GO111MODULE=off go get -v github.com/yggdrasil-network/yggdrasil-go/src/... - # GO111MODULE=off ./build -i - # mv *.framework /tmp/upload - - - persist_to_workspace: - root: /tmp - paths: - - upload - - build-other: - docker: - - image: circleci/golang:1.17 - - steps: - - checkout - - - run: - name: Create artifact upload directory and set variables - command: | - mkdir /tmp/upload - echo 'export CINAME=$(sh contrib/semver/name.sh)' >> $BASH_ENV - echo 'export CIVERSION=$(sh contrib/semver/version.sh --bare)' >> $BASH_ENV - git config --global user.email "$(git log --format='%ae' HEAD -1)"; - git config --global user.name "$(git log --format='%an' HEAD -1)"; - - - run: - name: Build for OpenBSD - command: | - rm -f {yggdrasil,yggdrasilctl} - GOOS=openbsd GOARCH=amd64 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-openbsd-amd64 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-openbsd-amd64; - GOOS=openbsd GOARCH=386 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-openbsd-i386 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-openbsd-i386; - - - run: - name: Build for FreeBSD - command: | - rm -f {yggdrasil,yggdrasilctl} - GOOS=freebsd GOARCH=amd64 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-freebsd-amd64 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-freebsd-amd64; - GOOS=freebsd GOARCH=386 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-freebsd-i386 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-freebsd-i386; - - - run: - name: Build for Windows - command: | - rm -f {yggdrasil,yggdrasilctl} - GOOS=windows GOARCH=amd64 ./build && mv yggdrasil.exe /tmp/upload/$CINAME-$CIVERSION-windows-amd64.exe && mv yggdrasilctl.exe /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-windows-amd64.exe; - GOOS=windows GOARCH=386 ./build && mv yggdrasil.exe /tmp/upload/$CINAME-$CIVERSION-windows-i386.exe && mv yggdrasilctl.exe /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-windows-i386.exe; - - - persist_to_workspace: - root: /tmp - paths: - - upload - - upload: - machine: true - - steps: - - attach_workspace: - at: /tmp - - - store_artifacts: - path: /tmp/upload - destination: / - -workflows: - version: 2.1 - build: - jobs: - - lint - - build-linux - - build-other - - upload: - requires: - - build-linux - - build-other diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..0c99ac0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,131 @@ +name: Yggdrasil + +on: + push: + pull_request: + release: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - uses: actions/setup-go@v3 + with: + go-version: 1.19 + - uses: actions/checkout@v3 + - name: golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + args: --issues-exit-code=1 + + codeql: + name: Analyse + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: go + + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + + build-linux: + strategy: + fail-fast: false + matrix: + goversion: ["1.17", "1.18", "1.19"] + + name: Build & Test (Linux, Go ${{ matrix.goversion }}) + needs: [lint] + + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: ${{ matrix.goversion }} + + - name: Build Yggdrasil + run: go build -v ./... + + - name: Unit tests + run: go test -v ./... + + build-windows: + strategy: + fail-fast: false + matrix: + goversion: ["1.17", "1.18", "1.19"] + + name: Build & Test (Windows, Go ${{ matrix.goversion }}) + needs: [lint] + + runs-on: windows-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: ${{ matrix.goversion }} + + - name: Build Yggdrasil + run: go build -v ./... + + - name: Unit tests + run: go test -v ./... + + build-macos: + strategy: + fail-fast: false + matrix: + goversion: ["1.17", "1.18", "1.19"] + + name: Build & Test (macOS, Go ${{ matrix.goversion }}) + needs: [lint] + + runs-on: macos-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: ${{ matrix.goversion }} + + - name: Build Yggdrasil + run: go build -v ./... + + - name: Unit tests + run: go test -v ./... + + tests-ok: + name: All tests passed + needs: [lint, codeql, build-linux, build-windows, build-macos] + runs-on: ubuntu-latest + if: ${{ !cancelled() }} + steps: + - name: Check all tests passed + uses: re-actors/alls-green@release/v1 + with: + jobs: ${{ toJSON(needs) }} \ No newline at end of file diff --git a/.github/workflows/pkg.yml b/.github/workflows/pkg.yml new file mode 100644 index 0000000..f282cc2 --- /dev/null +++ b/.github/workflows/pkg.yml @@ -0,0 +1,137 @@ +name: Packages + +on: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-packages-debian: + strategy: + fail-fast: false + matrix: + pkgarch: ["amd64", "i386", "mips", "mipsel", "armhf", "armel", "arm64"] + + name: Package (Debian, ${{ matrix.pkgarch }}) + + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.19 + + - name: Build package + env: + PKGARCH: ${{ matrix.pkgarch }} + run: sh contrib/deb/generate.sh + + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: Debian package (${{ matrix.pkgarch }}) + path: "*.deb" + if-no-files-found: error + + build-packages-macos: + strategy: + fail-fast: false + matrix: + pkgarch: ["amd64", "arm64"] + + name: Package (macOS, ${{ matrix.pkgarch }}) + + runs-on: macos-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.19 + + - name: Build package + env: + PKGARCH: ${{ matrix.pkgarch }} + run: sh contrib/macos/create-pkg.sh + + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: macOS package (${{ matrix.pkgarch }}) + path: "*.pkg" + if-no-files-found: error + + build-packages-windows: + strategy: + fail-fast: false + matrix: + pkgarch: ["x64", "x86", "arm", "arm64"] + + name: Package (Windows, ${{ matrix.pkgarch }}) + + runs-on: windows-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.19 + + - name: Build package + run: sh contrib/msi/build-msi.sh ${{ matrix.pkgarch }} + + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: Windows package (${{ matrix.pkgarch }}) + path: "*.msi" + if-no-files-found: error + + build-packages-router: + strategy: + fail-fast: false + matrix: + pkgarch: ["edgerouter-x", "edgerouter-lite", "vyos-amd64", "vyos-i386"] + + name: Package (Router, ${{ matrix.pkgarch }}) + + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + path: yggdrasil + + - uses: actions/checkout@v3 + with: + repository: neilalexander/vyatta-yggdrasil + path: vyatta-yggdrasil + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.19 + + - name: Build package + env: + BUILDDIR_YGG: /home/runner/work/yggdrasil-go/yggdrasil-go/yggdrasil + run: cd /home/runner/work/yggdrasil-go/yggdrasil-go/vyatta-yggdrasil && ./build-${{ matrix.pkgarch }} + + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: Router package (${{ matrix.pkgarch }}) + path: "/home/runner/work/yggdrasil-go/yggdrasil-go/vyatta-yggdrasil/*.deb" + if-no-files-found: error diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 27ff7fb..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,23 +0,0 @@ -version: '{build}' -pull_requests: - do_not_increment_build_number: true -os: Visual Studio 2019 -shallow_clone: false - -environment: - MSYS2_PATH_TYPE: inherit - CHERE_INVOKING: enabled_from_arguments - -build_script: -- cmd: cd %APPVEYOR_BUILD_FOLDER% -- curl -o C:\projects\golang.zip https://dl.google.com/go/go1.17.5.windows-amd64.zip -- 7z x C:\projects\golang.zip -oC:\projects\ -- cmd: set PATH=C:\projects\go\bin;%PATH% -- cmd: set GOROOT=C:\projects\go -- c:\msys64\usr\bin\bash -lc "./contrib/msi/build-msi.sh x64" -- c:\msys64\usr\bin\bash -lc "./contrib/msi/build-msi.sh x86" - -test: off - -artifacts: -- path: '*.msi' diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index db2c099..a00c0ad 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -8,11 +8,13 @@ import ( "encoding/json" "flag" "fmt" - "io/ioutil" + "io" "net" "os" "os/signal" + "regexp" "strings" + "sync" "syscall" "golang.org/x/text/encoding/unicode" @@ -27,11 +29,11 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/admin" "github.com/yggdrasil-network/yggdrasil-go/src/config" "github.com/yggdrasil-network/yggdrasil-go/src/defaults" + "github.com/yggdrasil-network/yggdrasil-go/src/ipv6rwc" "github.com/yggdrasil-network/yggdrasil-go/src/core" - "github.com/yggdrasil-network/yggdrasil-go/src/ipv6rwc" "github.com/yggdrasil-network/yggdrasil-go/src/multicast" - "github.com/yggdrasil-network/yggdrasil-go/src/tuntap" + "github.com/yggdrasil-network/yggdrasil-go/src/tun" "github.com/yggdrasil-network/yggdrasil-go/src/version" "github.com/popura-network/Popura/src/autopeering" @@ -40,11 +42,10 @@ import ( ) type node struct { - core core.Core - config *config.NodeConfig - tuntap *tuntap.TunAdapter - multicast *multicast.Multicast - admin *admin.AdminSocket + core *core.Core + tun *tun.TunAdapter + multicast *multicast.Multicast + admin *admin.AdminSocket meshname popura.Module // meshname.MeshnameServer autopeering popura.Module // autopeering.AutoPeering } @@ -57,10 +58,10 @@ func readConfig(log *log.Logger, useconf bool, useconffile string, normaliseconf var err error if useconffile != "" { // Read the file from the filesystem - conf, err = ioutil.ReadFile(useconffile) + conf, err = os.ReadFile(useconffile) } else { // Read the file from stdin. - conf, err = ioutil.ReadAll(os.Stdin) + conf, err = io.ReadAll(os.Stdin) } if err != nil { panic(err) @@ -87,48 +88,6 @@ func readConfig(log *log.Logger, useconf bool, useconffile string, normaliseconf if err := hjson.Unmarshal(conf, &dat); err != nil { panic(err) } - // Check if we have old field names - if _, ok := dat["TunnelRouting"]; ok { - log.Warnln("WARNING: Tunnel routing is no longer supported") - } - if old, ok := dat["SigningPrivateKey"]; ok { - log.Warnln("WARNING: The \"SigningPrivateKey\" configuration option has been renamed to \"PrivateKey\"") - if _, ok := dat["PrivateKey"]; !ok { - if privstr, err := hex.DecodeString(old.(string)); err == nil { - priv := ed25519.PrivateKey(privstr) - pub := priv.Public().(ed25519.PublicKey) - dat["PrivateKey"] = hex.EncodeToString(priv[:]) - dat["PublicKey"] = hex.EncodeToString(pub[:]) - } else { - log.Warnln("WARNING: The \"SigningPrivateKey\" configuration option contains an invalid value and will be ignored") - } - } - } - if oldmc, ok := dat["MulticastInterfaces"]; ok { - if oldmcvals, ok := oldmc.([]interface{}); ok { - var newmc []config.MulticastInterfaceConfig - for _, oldmcval := range oldmcvals { - if str, ok := oldmcval.(string); ok { - newmc = append(newmc, config.MulticastInterfaceConfig{ - Regex: str, - Beacon: true, - Listen: true, - }) - } - } - if newmc != nil { - if oldport, ok := dat["LinkLocalTCPPort"]; ok { - // numbers parse to float64 by default - if port, ok := oldport.(float64); ok { - for idx := range newmc { - newmc[idx].Port = uint16(port) - } - } - } - dat["MulticastInterfaces"] = newmc - } - } - } // Sanitise the config confJson, err := json.Marshal(dat) if err != nil { @@ -189,20 +148,20 @@ func setLogLevel(loglevel string, logger *log.Logger) { } type yggArgs struct { - genconf bool - useconf bool - normaliseconf bool - confjson bool - autoconf bool - ver bool - getaddr bool - getsnet bool - useconffile string - logto string - loglevel string - autopeer bool - meshnameenable bool - meshnamelisten string + genconf bool + useconf bool + normaliseconf bool + confjson bool + autoconf bool + ver bool + getaddr bool + getsnet bool + useconffile string + logto string + loglevel string + autopeer bool + meshnameenable bool + meshnamelisten string } func getArgs() yggArgs { @@ -212,36 +171,35 @@ func getArgs() yggArgs { normaliseconf := flag.Bool("normaliseconf", false, "use in combination with either -useconf or -useconffile, outputs your configuration normalised") confjson := flag.Bool("json", false, "print configuration from -genconf or -normaliseconf as JSON instead of HJSON") autoconf := flag.Bool("autoconf", false, "automatic mode (dynamic IP, peer with IPv6 neighbors)") - autopeer := flag.Bool("autopeer", false, "automatic Internet peering (using peers from github.com/yggdrasil-network/public-peers)") ver := flag.Bool("version", false, "prints the version of this build") logto := flag.String("logto", "stdout", "file path to log to, \"syslog\" or \"stdout\"") - meshnameenable := flag.Bool("meshname", false, "enable meshname resolver") - meshnamelisten := flag.String("meshnamelisten", "[::1]:53535", "meshname resolver listen address") getaddr := flag.Bool("address", false, "returns the IPv6 address as derived from the supplied configuration") getsnet := flag.Bool("subnet", false, "returns the IPv6 subnet as derived from the supplied configuration") loglevel := flag.String("loglevel", "info", "loglevel to enable") + autopeer := flag.Bool("autopeer", false, "automatic Internet peering (using peers from github.com/yggdrasil-network/public-peers)") + meshnameenable := flag.Bool("meshname", false, "enable meshname resolver") + meshnamelisten := flag.String("meshnamelisten", "[::1]:53535", "meshname resolver listen address") flag.Parse() return yggArgs{ - genconf: *genconf, - useconf: *useconf, - useconffile: *useconffile, - normaliseconf: *normaliseconf, - confjson: *confjson, - autoconf: *autoconf, - autopeer: *autopeer, - ver: *ver, - logto: *logto, - getaddr: *getaddr, - getsnet: *getsnet, - loglevel: *loglevel, - meshnameenable: *meshnameenable, - meshnamelisten: *meshnamelisten, + genconf: *genconf, + useconf: *useconf, + useconffile: *useconffile, + normaliseconf: *normaliseconf, + confjson: *confjson, + autoconf: *autoconf, + ver: *ver, + logto: *logto, + getaddr: *getaddr, + getsnet: *getsnet, + loglevel: *loglevel, + autopeer: *autopeer, + meshnameenable: *meshnameenable, + meshnamelisten: *meshnamelisten, } } // The main function is responsible for configuring and starting Yggdrasil. -func run(args yggArgs, ctx context.Context, done chan struct{}) { - defer close(done) +func run(args yggArgs, ctx context.Context) { // Create a new logger that logs output to stdout. var logger *log.Logger switch args.logto { @@ -277,7 +235,7 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) { return case args.autoconf: // Use an autoconf-generated config, this will give us random keys and - // port numbers, and will use an automatically selected TUN/TAP interface. + // port numbers, and will use an automatically selected TUN interface. cfg = defaults.GenerateConfig() case args.useconffile != "" || args.useconf: // Read the configuration from either stdin or from the filesystem @@ -338,56 +296,104 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) { fmt.Println(ipnet.String()) } return - default: } - // Setup the Yggdrasil node itself. The node{} type includes a Core, so we - // don't need to create this manually. - n := node{config: cfg} - // Now start Yggdrasil - this starts the DHT, router, switch and other core - // components needed for Yggdrasil to operate - if err = n.core.Start(cfg, logger); err != nil { - logger.Errorln("An error occurred during startup") - panic(err) - } - // Register the session firewall gatekeeper function - // Allocate our modules - n.admin = &admin.AdminSocket{} - n.multicast = &multicast.Multicast{} - n.tuntap = &tuntap.TunAdapter{} - n.meshname = &meshname.MeshnameServer{} - n.autopeering = &autopeering.AutoPeering{} - // Start the admin socket - if err := n.admin.Init(&n.core, cfg, logger, nil); err != nil { - logger.Errorln("An error occurred initialising admin socket:", err) - } else if err := n.admin.Start(); err != nil { - logger.Errorln("An error occurred starting admin socket:", err) - } - n.admin.SetupAdminHandlers(n.admin) - // Start the multicast interface - if err := n.multicast.Init(&n.core, cfg, logger, nil); err != nil { - logger.Errorln("An error occurred initialising multicast:", err) - } else if err := n.multicast.Start(); err != nil { - logger.Errorln("An error occurred starting multicast:", err) - } - n.multicast.SetupAdminHandlers(n.admin) - // Start the TUN/TAP interface - rwc := ipv6rwc.NewReadWriteCloser(&n.core) - if err := n.tuntap.Init(rwc, cfg, logger, nil); err != nil { - logger.Errorln("An error occurred initialising TUN/TAP:", err) - } else if err := n.tuntap.Start(); err != nil { - logger.Errorln("An error occurred starting TUN/TAP:", err) - } - n.tuntap.SetupAdminHandlers(n.admin) - // Start the DNS server - popuraConfig.Meshname.Enable = args.meshnameenable - popuraConfig.Meshname.Listen = args.meshnamelisten - n.meshname.Init(&n.core, cfg, popuraConfig, logger, nil) - n.meshname.Start() + n := &node{} - popuraConfig.Autopeering.Enable = args.autopeer - n.autopeering.Init(&n.core, cfg, popuraConfig, logger, nil) - n.autopeering.Start() + // Setup the Yggdrasil node itself. + { + sk, err := hex.DecodeString(cfg.PrivateKey) + if err != nil { + panic(err) + } + options := []core.SetupOption{ + core.NodeInfo(cfg.NodeInfo), + core.NodeInfoPrivacy(cfg.NodeInfoPrivacy), + } + for _, addr := range cfg.Listen { + options = append(options, core.ListenAddress(addr)) + } + for _, peer := range cfg.Peers { + options = append(options, core.Peer{URI: peer}) + } + for intf, peers := range cfg.InterfacePeers { + for _, peer := range peers { + options = append(options, core.Peer{URI: peer, SourceInterface: intf}) + } + } + for _, allowed := range cfg.AllowedPublicKeys { + k, err := hex.DecodeString(allowed) + if err != nil { + panic(err) + } + options = append(options, core.AllowedPublicKey(k[:])) + } + if n.core, err = core.New(sk[:], logger, options...); err != nil { + panic(err) + } + } + + // Setup the admin socket. + { + options := []admin.SetupOption{ + admin.ListenAddress(cfg.AdminListen), + } + if n.admin, err = admin.New(n.core, logger, options...); err != nil { + panic(err) + } + if n.admin != nil { + n.admin.SetupAdminHandlers() + } + } + + // Setup the multicast module. + { + options := []multicast.SetupOption{} + for _, intf := range cfg.MulticastInterfaces { + options = append(options, multicast.MulticastInterface{ + Regex: regexp.MustCompile(intf.Regex), + Beacon: intf.Beacon, + Listen: intf.Listen, + Port: intf.Port, + Priority: intf.Priority, + }) + } + if n.multicast, err = multicast.New(n.core, logger, options...); err != nil { + panic(err) + } + if n.admin != nil && n.multicast != nil { + n.multicast.SetupAdminHandlers(n.admin) + } + } + + // Setup the TUN module. + { + options := []tun.SetupOption{ + tun.InterfaceName(cfg.IfName), + tun.InterfaceMTU(cfg.IfMTU), + } + if n.tun, err = tun.New(ipv6rwc.NewReadWriteCloser(n.core), logger, options...); err != nil { + panic(err) + } + if n.admin != nil && n.tun != nil { + n.tun.SetupAdminHandlers(n.admin) + } + } + + // Setup Popura modules + { + n.meshname = &meshname.MeshnameServer{} + n.autopeering = &autopeering.AutoPeering{} + + popuraConfig.Meshname.Enable = args.meshnameenable + popuraConfig.Meshname.Listen = args.meshnamelisten + n.meshname.Init(n.core, cfg, popuraConfig, logger, nil) + n.meshname.Start() + + popuraConfig.Autopeering.Enable = args.autopeer + n.autopeering.Init(n.core, cfg, popuraConfig, logger, nil) + n.autopeering.Start() + } // Make some nice output that tells us what our IPv6 address and subnet are. // This is just logged to stdout for the user. @@ -397,42 +403,34 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) { logger.Infof("Your public key is %s", hex.EncodeToString(public[:])) logger.Infof("Your IPv6 address is %s", address.String()) logger.Infof("Your IPv6 subnet is %s", subnet.String()) - // Catch interrupts from the operating system to exit gracefully. - <-ctx.Done() - // Capture the service being stopped on Windows. - minwinsvc.SetOnExit(n.shutdown) - n.shutdown() -} -func (n *node) shutdown() { - _ = n.autopeering.Stop() - _ = n.meshname.Stop() + // Block until we are told to shut down. + <-ctx.Done() + + // Shut down the node. _ = n.admin.Stop() _ = n.multicast.Stop() - _ = n.tuntap.Stop() + _ = n.tun.Stop() + _ = n.autopeering.Stop() + _ = n.meshname.Stop() n.core.Stop() } func main() { args := getArgs() - hup := make(chan os.Signal, 1) - //signal.Notify(hup, os.Interrupt, syscall.SIGHUP) - term := make(chan os.Signal, 1) - signal.Notify(term, os.Interrupt, syscall.SIGTERM) - for { - done := make(chan struct{}) - ctx, cancel := context.WithCancel(context.Background()) - go run(args, ctx, done) - select { - case <-hup: - cancel() - <-done - case <-term: - cancel() - <-done - return - case <-done: - return - } - } + + // Catch interrupts from the operating system to exit gracefully. + ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) + + // Capture the service being stopped on Windows. + minwinsvc.SetOnExit(cancel) + + // Start the node, block and then wait for it to shut down. + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + run(args, ctx) + }() + wg.Wait() } diff --git a/cmd/yggdrasilctl/cmd_line_env.go b/cmd/yggdrasilctl/cmd_line_env.go index bd6df8f..9fcabad 100644 --- a/cmd/yggdrasilctl/cmd_line_env.go +++ b/cmd/yggdrasilctl/cmd_line_env.go @@ -4,7 +4,6 @@ import ( "bytes" "flag" "fmt" - "io/ioutil" "log" "os" @@ -15,9 +14,9 @@ import ( ) type CmdLineEnv struct { - args []string - endpoint, server string - injson, verbose, ver bool + args []string + endpoint, server string + injson, ver bool } func newCmdLineEnv() CmdLineEnv { @@ -47,7 +46,6 @@ func (cmdLineEnv *CmdLineEnv) parseFlagsAndArgs() { server := flag.String("endpoint", cmdLineEnv.endpoint, "Admin socket endpoint") injson := flag.Bool("json", false, "Output in JSON format (as opposed to pretty-print)") - verbose := flag.Bool("v", false, "Verbose output (includes public keys)") ver := flag.Bool("version", false, "Prints the version of this build") flag.Parse() @@ -55,13 +53,12 @@ func (cmdLineEnv *CmdLineEnv) parseFlagsAndArgs() { cmdLineEnv.args = flag.Args() cmdLineEnv.server = *server cmdLineEnv.injson = *injson - cmdLineEnv.verbose = *verbose cmdLineEnv.ver = *ver } func (cmdLineEnv *CmdLineEnv) setEndpoint(logger *log.Logger) { if cmdLineEnv.server == cmdLineEnv.endpoint { - if config, err := ioutil.ReadFile(defaults.GetDefaults().DefaultConfigFile); err == nil { + if config, err := os.ReadFile(defaults.GetDefaults().DefaultConfigFile); err == nil { if bytes.Equal(config[0:2], []byte{0xFF, 0xFE}) || bytes.Equal(config[0:2], []byte{0xFE, 0xFF}) { utf := unicode.UTF16(unicode.BigEndian, unicode.UseBOM) diff --git a/cmd/yggdrasilctl/main.go b/cmd/yggdrasilctl/main.go index 788b4f1..c9b1522 100644 --- a/cmd/yggdrasilctl/main.go +++ b/cmd/yggdrasilctl/main.go @@ -10,15 +10,17 @@ import ( "net" "net/url" "os" - "sort" - "strconv" "strings" + "time" + "github.com/olekukonko/tablewriter" + "github.com/yggdrasil-network/yggdrasil-go/src/admin" + "github.com/yggdrasil-network/yggdrasil-go/src/core" + "github.com/yggdrasil-network/yggdrasil-go/src/multicast" + "github.com/yggdrasil-network/yggdrasil-go/src/tun" "github.com/yggdrasil-network/yggdrasil-go/src/version" ) -type admin_info map[string]interface{} - func main() { // makes sure we can use defer and still return an error code to the OS os.Exit(run()) @@ -54,103 +56,13 @@ func run() int { cmdLineEnv.setEndpoint(logger) - conn := connect(cmdLineEnv.endpoint, logger) - logger.Println("Connected") - defer conn.Close() - - decoder := json.NewDecoder(conn) - encoder := json.NewEncoder(conn) - send := make(admin_info) - recv := make(admin_info) - - for c, a := range cmdLineEnv.args { - if c == 0 { - if strings.HasPrefix(a, "-") { - logger.Printf("Ignoring flag %s as it should be specified before other parameters\n", a) - continue - } - logger.Printf("Sending request: %v\n", a) - send["request"] = a - continue - } - tokens := strings.Split(a, "=") - if len(tokens) == 1 { - send[tokens[0]] = true - } else if len(tokens) > 2 { - send[tokens[0]] = strings.Join(tokens[1:], "=") - } else if len(tokens) == 2 { - if i, err := strconv.Atoi(tokens[1]); err == nil { - logger.Printf("Sending parameter %s: %d\n", tokens[0], i) - send[tokens[0]] = i - } else { - switch strings.ToLower(tokens[1]) { - case "true": - send[tokens[0]] = true - case "false": - send[tokens[0]] = false - default: - send[tokens[0]] = tokens[1] - } - logger.Printf("Sending parameter %s: %v\n", tokens[0], send[tokens[0]]) - } - } - } - - if err := encoder.Encode(&send); err != nil { - panic(err) - } - - logger.Printf("Request sent") - - if err := decoder.Decode(&recv); err == nil { - logger.Printf("Response received") - if recv["status"] == "error" { - if err, ok := recv["error"]; ok { - fmt.Println("Admin socket returned an error:", err) - } else { - fmt.Println("Admin socket returned an error but didn't specify any error text") - } - return 1 - } - if _, ok := recv["request"]; !ok { - fmt.Println("Missing request in response (malformed response?)") - return 1 - } - if _, ok := recv["response"]; !ok { - fmt.Println("Missing response body (malformed response?)") - return 1 - } - res := recv["response"].(map[string]interface{}) - - if cmdLineEnv.injson { - if json, err := json.MarshalIndent(res, "", " "); err == nil { - fmt.Println(string(json)) - } - return 0 - } - - handleAll(recv, cmdLineEnv.verbose) - } else { - logger.Println("Error receiving response:", err) - } - - if v, ok := recv["status"]; ok && v != "success" { - return 1 - } - - return 0 -} - -func connect(endpoint string, logger *log.Logger) net.Conn { var conn net.Conn - - u, err := url.Parse(endpoint) - + u, err := url.Parse(cmdLineEnv.endpoint) if err == nil { switch strings.ToLower(u.Scheme) { case "unix": - logger.Println("Connecting to UNIX socket", endpoint[7:]) - conn, err = net.Dial("unix", endpoint[7:]) + logger.Println("Connecting to UNIX socket", cmdLineEnv.endpoint[7:]) + conn, err = net.Dial("unix", cmdLineEnv.endpoint[7:]) case "tcp": logger.Println("Connecting to TCP socket", u.Host) conn, err = net.Dial("tcp", u.Host) @@ -160,298 +72,209 @@ func connect(endpoint string, logger *log.Logger) net.Conn { } } else { logger.Println("Connecting to TCP socket", u.Host) - conn, err = net.Dial("tcp", endpoint) + conn, err = net.Dial("tcp", cmdLineEnv.endpoint) } - if err != nil { panic(err) } - return conn -} + logger.Println("Connected") + defer conn.Close() -func handleAll(recv map[string]interface{}, verbose bool) { - req := recv["request"].(map[string]interface{}) - res := recv["response"].(map[string]interface{}) - - switch strings.ToLower(req["request"].(string)) { - case "dot": - handleDot(res) - case "list", "getpeers", "getswitchpeers", "getdht", "getsessions", "dhtping": - handleVariousInfo(res, verbose) - case "gettuntap", "settuntap": - handleGetAndSetTunTap(res) - case "getself": - handleGetSelf(res, verbose) - case "getswitchqueues": - handleGetSwitchQueues(res) - case "addpeer", "removepeer", "addallowedencryptionpublickey", "removeallowedencryptionpublickey", "addsourcesubnet", "addroute", "removesourcesubnet", "removeroute": - handleAddsAndRemoves(res) - case "getallowedencryptionpublickeys": - handleGetAllowedEncryptionPublicKeys(res) - case "getmulticastinterfaces": - handleGetMulticastInterfaces(res) - case "getsourcesubnets": - handleGetSourceSubnets(res) - case "getroutes": - handleGetRoutes(res) - case "settunnelrouting": - fallthrough - case "gettunnelrouting": - handleGetTunnelRouting(res) - default: - if json, err := json.MarshalIndent(recv["response"], "", " "); err == nil { + decoder := json.NewDecoder(conn) + encoder := json.NewEncoder(conn) + send := &admin.AdminSocketRequest{} + recv := &admin.AdminSocketResponse{} + args := map[string]string{} + for c, a := range cmdLineEnv.args { + if c == 0 { + if strings.HasPrefix(a, "-") { + logger.Printf("Ignoring flag %s as it should be specified before other parameters\n", a) + continue + } + logger.Printf("Sending request: %v\n", a) + send.Name = a + continue + } + tokens := strings.SplitN(a, "=", 2) + switch { + case len(tokens) == 1: + logger.Println("Ignoring invalid argument:", a) + default: + args[tokens[0]] = tokens[1] + } + } + if send.Arguments, err = json.Marshal(args); err != nil { + panic(err) + } + if err := encoder.Encode(&send); err != nil { + panic(err) + } + logger.Printf("Request sent") + if err := decoder.Decode(&recv); err != nil { + panic(err) + } + if recv.Status == "error" { + if err := recv.Error; err != "" { + fmt.Println("Admin socket returned an error:", err) + } else { + fmt.Println("Admin socket returned an error but didn't specify any error text") + } + return 1 + } + if cmdLineEnv.injson { + if json, err := json.MarshalIndent(recv.Response, "", " "); err == nil { fmt.Println(string(json)) } + return 0 } -} -func handleDot(res map[string]interface{}) { - fmt.Println(res["dot"]) -} + table := tablewriter.NewWriter(os.Stdout) + table.SetAlignment(tablewriter.ALIGN_LEFT) + table.SetAutoFormatHeaders(false) + table.SetCenterSeparator("") + table.SetColumnSeparator("") + table.SetRowSeparator("") + table.SetHeaderLine(false) + table.SetBorder(false) + table.SetTablePadding("\t") // pad with tabs + table.SetNoWhiteSpace(true) + table.SetAutoWrapText(false) -func handleVariousInfo(res map[string]interface{}, verbose bool) { - maxWidths := make(map[string]int) - var keyOrder []string - keysOrdered := false - - for _, tlv := range res { - for slk, slv := range tlv.(map[string]interface{}) { - if !keysOrdered { - for k := range slv.(map[string]interface{}) { - if !verbose { - if k == "box_pub_key" || k == "box_sig_key" || k == "nodeinfo" || k == "was_mtu_fixed" { - continue - } - } - keyOrder = append(keyOrder, fmt.Sprint(k)) - } - sort.Strings(keyOrder) - keysOrdered = true - } - for k, v := range slv.(map[string]interface{}) { - if len(fmt.Sprint(slk)) > maxWidths["key"] { - maxWidths["key"] = len(fmt.Sprint(slk)) - } - if len(fmt.Sprint(v)) > maxWidths[k] { - maxWidths[k] = len(fmt.Sprint(v)) - if maxWidths[k] < len(k) { - maxWidths[k] = len(k) - } - } + switch strings.ToLower(send.Name) { + case "list": + var resp admin.ListResponse + if err := json.Unmarshal(recv.Response, &resp); err != nil { + panic(err) + } + table.SetHeader([]string{"Command", "Arguments", "Description"}) + for _, entry := range resp.List { + for i := range entry.Fields { + entry.Fields[i] = entry.Fields[i] + "=..." } + table.Append([]string{entry.Command, strings.Join(entry.Fields, ", "), entry.Description}) + } + table.Render() + + case "getself": + var resp admin.GetSelfResponse + if err := json.Unmarshal(recv.Response, &resp); err != nil { + panic(err) + } + table.Append([]string{"Build name:", resp.BuildName}) + table.Append([]string{"Build version:", resp.BuildVersion}) + table.Append([]string{"IPv6 address:", resp.IPAddress}) + table.Append([]string{"IPv6 subnet:", resp.Subnet}) + table.Append([]string{"Coordinates:", fmt.Sprintf("%v", resp.Coords)}) + table.Append([]string{"Public key:", resp.PublicKey}) + table.Render() + + case "getpeers": + var resp admin.GetPeersResponse + if err := json.Unmarshal(recv.Response, &resp); err != nil { + panic(err) + } + table.SetHeader([]string{"Port", "Public Key", "IP Address", "Uptime", "RX", "TX", "Pr", "URI"}) + for _, peer := range resp.Peers { + table.Append([]string{ + fmt.Sprintf("%d", peer.Port), + peer.PublicKey, + peer.IPAddress, + (time.Duration(peer.Uptime) * time.Second).String(), + peer.RXBytes.String(), + peer.TXBytes.String(), + fmt.Sprintf("%d", peer.Priority), + peer.Remote, + }) + } + table.Render() + + case "getdht": + var resp admin.GetDHTResponse + if err := json.Unmarshal(recv.Response, &resp); err != nil { + panic(err) + } + table.SetHeader([]string{"Public Key", "IP Address", "Port", "Rest"}) + for _, dht := range resp.DHT { + table.Append([]string{ + dht.PublicKey, + dht.IPAddress, + fmt.Sprintf("%d", dht.Port), + fmt.Sprintf("%d", dht.Rest), + }) + } + table.Render() + + case "getpaths": + var resp admin.GetPathsResponse + if err := json.Unmarshal(recv.Response, &resp); err != nil { + panic(err) + } + table.SetHeader([]string{"Public Key", "IP Address", "Path"}) + for _, p := range resp.Paths { + table.Append([]string{ + p.PublicKey, + p.IPAddress, + fmt.Sprintf("%v", p.Path), + }) + } + table.Render() + + case "getsessions": + var resp admin.GetSessionsResponse + if err := json.Unmarshal(recv.Response, &resp); err != nil { + panic(err) + } + table.SetHeader([]string{"Public Key", "IP Address", "Uptime", "RX", "TX"}) + for _, p := range resp.Sessions { + table.Append([]string{ + p.PublicKey, + p.IPAddress, + (time.Duration(p.Uptime) * time.Second).String(), + p.RXBytes.String(), + p.TXBytes.String(), + }) + } + table.Render() + + case "getnodeinfo": + var resp core.GetNodeInfoResponse + if err := json.Unmarshal(recv.Response, &resp); err != nil { + panic(err) + } + for _, v := range resp { + fmt.Println(string(v)) + break } - if len(keyOrder) > 0 { - fmt.Printf("%-"+fmt.Sprint(maxWidths["key"])+"s ", "") - for _, v := range keyOrder { - fmt.Printf("%-"+fmt.Sprint(maxWidths[v])+"s ", v) - } - fmt.Println() + case "getmulticastinterfaces": + var resp multicast.GetMulticastInterfacesResponse + if err := json.Unmarshal(recv.Response, &resp); err != nil { + panic(err) } + table.SetHeader([]string{"Interface"}) + for _, p := range resp.Interfaces { + table.Append([]string{p}) + } + table.Render() - for slk, slv := range tlv.(map[string]interface{}) { - fmt.Printf("%-"+fmt.Sprint(maxWidths["key"])+"s ", slk) - for _, k := range keyOrder { - preformatted := slv.(map[string]interface{})[k] - var formatted string - switch k { - case "bytes_sent", "bytes_recvd": - formatted = fmt.Sprintf("%d", uint(preformatted.(float64))) - case "uptime", "last_seen": - seconds := uint(preformatted.(float64)) % 60 - minutes := uint(preformatted.(float64)/60) % 60 - hours := uint(preformatted.(float64) / 60 / 60) - formatted = fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds) - default: - formatted = fmt.Sprint(preformatted) - } - fmt.Printf("%-"+fmt.Sprint(maxWidths[k])+"s ", formatted) - } - fmt.Println() + case "gettun": + var resp tun.GetTUNResponse + if err := json.Unmarshal(recv.Response, &resp); err != nil { + panic(err) } + table.Append([]string{"TUN enabled:", fmt.Sprintf("%#v", resp.Enabled)}) + if resp.Enabled { + table.Append([]string{"Interface name:", resp.Name}) + table.Append([]string{"Interface MTU:", fmt.Sprintf("%d", resp.MTU)}) + } + table.Render() + + case "addpeer", "removepeer": + + default: + fmt.Println(string(recv.Response)) } -} - -func handleGetAndSetTunTap(res map[string]interface{}) { - for k, v := range res { - fmt.Println("Interface name:", k) - if mtu, ok := v.(map[string]interface{})["mtu"].(float64); ok { - fmt.Println("Interface MTU:", mtu) - } - if tap_mode, ok := v.(map[string]interface{})["tap_mode"].(bool); ok { - fmt.Println("TAP mode:", tap_mode) - } - } -} - -func handleGetSelf(res map[string]interface{}, verbose bool) { - for k, v := range res["self"].(map[string]interface{}) { - if buildname, ok := v.(map[string]interface{})["build_name"].(string); ok && buildname != "unknown" { - fmt.Println("Build name:", buildname) - } - if buildversion, ok := v.(map[string]interface{})["build_version"].(string); ok && buildversion != "unknown" { - fmt.Println("Build version:", buildversion) - } - fmt.Println("IPv6 address:", k) - if subnet, ok := v.(map[string]interface{})["subnet"].(string); ok { - fmt.Println("IPv6 subnet:", subnet) - } - if boxSigKey, ok := v.(map[string]interface{})["key"].(string); ok { - fmt.Println("Public key:", boxSigKey) - } - if coords, ok := v.(map[string]interface{})["coords"].(string); ok { - fmt.Println("Coords:", coords) - } - if verbose { - if nodeID, ok := v.(map[string]interface{})["node_id"].(string); ok { - fmt.Println("Node ID:", nodeID) - } - if boxPubKey, ok := v.(map[string]interface{})["box_pub_key"].(string); ok { - fmt.Println("Public encryption key:", boxPubKey) - } - if boxSigKey, ok := v.(map[string]interface{})["box_sig_key"].(string); ok { - fmt.Println("Public signing key:", boxSigKey) - } - } - } -} - -func handleGetSwitchQueues(res map[string]interface{}) { - maximumqueuesize := float64(4194304) - portqueues := make(map[float64]float64) - portqueuesize := make(map[float64]float64) - portqueuepackets := make(map[float64]float64) - v := res["switchqueues"].(map[string]interface{}) - if queuecount, ok := v["queues_count"].(float64); ok { - fmt.Printf("Active queue count: %d queues\n", uint(queuecount)) - } - if queuesize, ok := v["queues_size"].(float64); ok { - fmt.Printf("Active queue size: %d bytes\n", uint(queuesize)) - } - if highestqueuecount, ok := v["highest_queues_count"].(float64); ok { - fmt.Printf("Highest queue count: %d queues\n", uint(highestqueuecount)) - } - if highestqueuesize, ok := v["highest_queues_size"].(float64); ok { - fmt.Printf("Highest queue size: %d bytes\n", uint(highestqueuesize)) - } - if m, ok := v["maximum_queues_size"].(float64); ok { - maximumqueuesize = m - fmt.Printf("Maximum queue size: %d bytes\n", uint(maximumqueuesize)) - } - if queues, ok := v["queues"].([]interface{}); ok { - if len(queues) != 0 { - fmt.Println("Active queues:") - for _, v := range queues { - queueport := v.(map[string]interface{})["queue_port"].(float64) - queuesize := v.(map[string]interface{})["queue_size"].(float64) - queuepackets := v.(map[string]interface{})["queue_packets"].(float64) - queueid := v.(map[string]interface{})["queue_id"].(string) - portqueues[queueport]++ - portqueuesize[queueport] += queuesize - portqueuepackets[queueport] += queuepackets - queuesizepercent := (100 / maximumqueuesize) * queuesize - fmt.Printf("- Switch port %d, Stream ID: %v, size: %d bytes (%d%% full), %d packets\n", - uint(queueport), []byte(queueid), uint(queuesize), - uint(queuesizepercent), uint(queuepackets)) - } - } - } - if len(portqueuesize) > 0 && len(portqueuepackets) > 0 { - fmt.Println("Aggregated statistics by switchport:") - for k, v := range portqueuesize { - queuesizepercent := (100 / (portqueues[k] * maximumqueuesize)) * v - fmt.Printf("- Switch port %d, size: %d bytes (%d%% full), %d packets\n", - uint(k), uint(v), uint(queuesizepercent), uint(portqueuepackets[k])) - } - } -} - -func handleAddsAndRemoves(res map[string]interface{}) { - if _, ok := res["added"]; ok { - for _, v := range res["added"].([]interface{}) { - fmt.Println("Added:", fmt.Sprint(v)) - } - } - if _, ok := res["not_added"]; ok { - for _, v := range res["not_added"].([]interface{}) { - fmt.Println("Not added:", fmt.Sprint(v)) - } - } - if _, ok := res["removed"]; ok { - for _, v := range res["removed"].([]interface{}) { - fmt.Println("Removed:", fmt.Sprint(v)) - } - } - if _, ok := res["not_removed"]; ok { - for _, v := range res["not_removed"].([]interface{}) { - fmt.Println("Not removed:", fmt.Sprint(v)) - } - } -} - -func handleGetAllowedEncryptionPublicKeys(res map[string]interface{}) { - if _, ok := res["allowed_box_pubs"]; !ok { - fmt.Println("All connections are allowed") - } else if res["allowed_box_pubs"] == nil { - fmt.Println("All connections are allowed") - } else { - fmt.Println("Connections are allowed only from the following public box keys:") - for _, v := range res["allowed_box_pubs"].([]interface{}) { - fmt.Println("-", v) - } - } -} - -func handleGetMulticastInterfaces(res map[string]interface{}) { - if _, ok := res["multicast_interfaces"]; !ok { - fmt.Println("No multicast interfaces found") - } else if res["multicast_interfaces"] == nil { - fmt.Println("No multicast interfaces found") - } else { - fmt.Println("Multicast peer discovery is active on:") - for _, v := range res["multicast_interfaces"].([]interface{}) { - fmt.Println("-", v) - } - } -} - -func handleGetSourceSubnets(res map[string]interface{}) { - if _, ok := res["source_subnets"]; !ok { - fmt.Println("No source subnets found") - } else if res["source_subnets"] == nil { - fmt.Println("No source subnets found") - } else { - fmt.Println("Source subnets:") - for _, v := range res["source_subnets"].([]interface{}) { - fmt.Println("-", v) - } - } -} - -func handleGetRoutes(res map[string]interface{}) { - if routes, ok := res["routes"].(map[string]interface{}); !ok { - fmt.Println("No routes found") - } else { - if res["routes"] == nil || len(routes) == 0 { - fmt.Println("No routes found") - } else { - fmt.Println("Routes:") - for k, v := range routes { - if pv, ok := v.(string); ok { - fmt.Println("-", k, " via ", pv) - } - } - } - } -} - -func handleGetTunnelRouting(res map[string]interface{}) { - if enabled, ok := res["enabled"].(bool); !ok { - fmt.Println("Tunnel routing is disabled") - } else if !enabled { - fmt.Println("Tunnel routing is disabled") - } else { - fmt.Println("Tunnel routing is enabled") - } + + return 0 } diff --git a/contrib/mobile/mobile.go b/contrib/mobile/mobile.go index ba7cfdf..78a3f50 100644 --- a/contrib/mobile/mobile.go +++ b/contrib/mobile/mobile.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "net" + "regexp" "github.com/gologme/log" @@ -25,10 +26,10 @@ import ( // functions. Note that in the case of iOS we handle reading/writing to/from TUN // in Swift therefore we use the "dummy" TUN interface instead. type Yggdrasil struct { - core core.Core + core *core.Core iprwc *ipv6rwc.ReadWriteCloser config *config.NodeConfig - multicast multicast.Multicast + multicast *multicast.Multicast log MobileLogger } @@ -48,27 +49,59 @@ func (m *Yggdrasil) StartJSON(configjson []byte) error { if err := json.Unmarshal(configjson, &m.config); err != nil { return err } - m.config.IfName = "none" - if err := m.core.Start(m.config, logger); err != nil { - logger.Errorln("An error occured starting Yggdrasil:", err) - return err + // Setup the Yggdrasil node itself. + { + sk, err := hex.DecodeString(m.config.PrivateKey) + if err != nil { + panic(err) + } + options := []core.SetupOption{} + for _, peer := range m.config.Peers { + options = append(options, core.Peer{URI: peer}) + } + for intf, peers := range m.config.InterfacePeers { + for _, peer := range peers { + options = append(options, core.Peer{URI: peer, SourceInterface: intf}) + } + } + for _, allowed := range m.config.AllowedPublicKeys { + k, err := hex.DecodeString(allowed) + if err != nil { + panic(err) + } + options = append(options, core.AllowedPublicKey(k[:])) + } + m.core, err = core.New(sk[:], logger, options...) + if err != nil { + panic(err) + } } + + // Setup the multicast module. + if len(m.config.MulticastInterfaces) > 0 { + var err error + options := []multicast.SetupOption{} + for _, intf := range m.config.MulticastInterfaces { + options = append(options, multicast.MulticastInterface{ + Regex: regexp.MustCompile(intf.Regex), + Beacon: intf.Beacon, + Listen: intf.Listen, + Port: intf.Port, + Priority: intf.Priority, + }) + } + m.multicast, err = multicast.New(m.core, logger, options...) + if err != nil { + logger.Errorln("An error occurred starting multicast:", err) + } + } + mtu := m.config.IfMTU - m.iprwc = ipv6rwc.NewReadWriteCloser(&m.core) + m.iprwc = ipv6rwc.NewReadWriteCloser(m.core) if m.iprwc.MaxMTU() < mtu { mtu = m.iprwc.MaxMTU() } m.iprwc.SetMTU(mtu) - if len(m.config.MulticastInterfaces) > 0 { - if err := m.multicast.Init(&m.core, m.config, logger, nil); err != nil { - logger.Errorln("An error occurred initialising multicast:", err) - return err - } - if err := m.multicast.Start(); err != nil { - logger.Errorln("An error occurred starting multicast:", err) - return err - } - } return nil } @@ -139,18 +172,18 @@ func (m *Yggdrasil) GetCoordsString() string { func (m *Yggdrasil) GetPeersJSON() (result string) { peers := []struct { - core.Peer + core.PeerInfo IP string }{} for _, v := range m.core.GetPeers() { a := address.AddrForKey(v.Key) ip := net.IP(a[:]).String() peers = append(peers, struct { - core.Peer + core.PeerInfo IP string }{ - Peer: v, - IP: ip, + PeerInfo: v, + IP: ip, }) } if res, err := json.Marshal(peers); err == nil { diff --git a/contrib/mobile/mobile_android.go b/contrib/mobile/mobile_android.go index f3206ac..39bebec 100644 --- a/contrib/mobile/mobile_android.go +++ b/contrib/mobile/mobile_android.go @@ -1,3 +1,4 @@ +//go:build android // +build android package mobile diff --git a/contrib/mobile/mobile_ios.go b/contrib/mobile/mobile_ios.go index 253bbc0..fedee2d 100644 --- a/contrib/mobile/mobile_ios.go +++ b/contrib/mobile/mobile_ios.go @@ -1,3 +1,4 @@ +//go:build ios // +build ios package mobile diff --git a/contrib/mobile/mobile_other.go b/contrib/mobile/mobile_other.go index 7b7ed74..aceeb7e 100644 --- a/contrib/mobile/mobile_other.go +++ b/contrib/mobile/mobile_other.go @@ -1,3 +1,4 @@ +//go:build !android && !ios // +build !android,!ios package mobile diff --git a/contrib/msi/build-msi.sh b/contrib/msi/build-msi.sh index 765af5c..38b9b81 100644 --- a/contrib/msi/build-msi.sh +++ b/contrib/msi/build-msi.sh @@ -1,9 +1,9 @@ #!/bin/sh # This script generates an MSI file for Yggdrasil for a given architecture. It -# needs to run on Windows within MSYS2 and Go 1.13 or later must be installed on -# the system and within the PATH. This is ran currently by Appveyor (see -# appveyor.yml in the repository root) for both x86 and x64. +# needs to run on Windows within MSYS2 and Go 1.17 or later must be installed on +# the system and within the PATH. This is ran currently by GitHub Actions (see +# the workflows in the repository). # # Author: Neil Alexander @@ -11,37 +11,21 @@ PKGARCH=$1 if [ "${PKGARCH}" == "" ]; then - echo "tell me the architecture: x86, x64 or arm" + echo "tell me the architecture: x86, x64, arm or arm64" exit 1 fi -# Get the rest of the repository history. This is needed within Appveyor because -# otherwise we don't get all of the branch histories and therefore the semver -# scripts don't work properly. -if [ "${APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH}" != "" ]; -then - git fetch --all -# git checkout ${APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH} -elif [ "${APPVEYOR_REPO_BRANCH}" != "" ]; -then - git fetch --all - git checkout ${APPVEYOR_REPO_BRANCH} -fi - -# Install prerequisites within MSYS2 -pacman -S --needed --noconfirm unzip git curl - # Download the wix tools! if [ ! -d wixbin ]; then - curl -LO https://github.com/wixtoolset/wix3/releases/download/wix3112rtm/wix311-binaries.zip - if [ `md5sum wix311-binaries.zip | cut -f 1 -d " "` != "47a506f8ab6666ee3cc502fb07d0ee2a" ]; + curl -LO https://wixtoolset.org/downloads/v3.14.0.3910/wix314-binaries.zip + if [ `md5sum wix314-binaries.zip | cut -f 1 -d " "` != "34f655cf108086838dd5a76d4318063b" ]; then echo "wix package didn't match expected checksum" exit 1 fi mkdir -p wixbin - unzip -o wix311-binaries.zip -d wixbin || ( + unzip -o wix314-binaries.zip -d wixbin || ( echo "failed to unzip WiX" exit 1 ) @@ -51,7 +35,7 @@ fi [ "${PKGARCH}" == "x64" ] && GOOS=windows GOARCH=amd64 CGO_ENABLED=0 ./build [ "${PKGARCH}" == "x86" ] && GOOS=windows GOARCH=386 CGO_ENABLED=0 ./build [ "${PKGARCH}" == "arm" ] && GOOS=windows GOARCH=arm CGO_ENABLED=0 ./build -#[ "${PKGARCH}" == "arm64" ] && GOOS=windows GOARCH=arm64 CGO_ENABLED=0 ./build +[ "${PKGARCH}" == "arm64" ] && GOOS=windows GOARCH=arm64 CGO_ENABLED=0 ./build # Create the postinstall script cat > updateconfig.bat << EOF @@ -67,9 +51,9 @@ EOF # Work out metadata for the package info PKGNAME=$(sh contrib/semver/name.sh) -PKGVERSION=$(sh contrib/msi/msversion.sh --bare | cut -d "+" -f 1) +PKGVERSION=$(sh contrib/msi/msversion.sh --bare) PKGVERSIONMS=$(echo $PKGVERSION | tr - .) -[ "${PKGARCH}" == "x64" ] && \ +([ "${PKGARCH}" == "x64" ] || [ "${PKGARCH}" == "arm64" ]) && \ PKGGUID="77757838-1a23-40a5-a720-c3b43e0260cc" PKGINSTFOLDER="ProgramFiles64Folder" || \ PKGGUID="54a3294e-a441-4322-aefb-3bb40dd022bb" PKGINSTFOLDER="ProgramFilesFolder" @@ -85,8 +69,8 @@ elif [ $PKGARCH = "x86" ]; then PKGWINTUNDLL=wintun/bin/x86/wintun.dll elif [ $PKGARCH = "arm" ]; then PKGWINTUNDLL=wintun/bin/arm/wintun.dll -#elif [ $PKGARCH = "arm64" ]; then -# PKGWINTUNDLL=wintun/bin/arm64/wintun.dll +elif [ $PKGARCH = "arm64" ]; then + PKGWINTUNDLL=wintun/bin/arm64/wintun.dll else echo "wasn't sure which architecture to get wintun for" exit 1 diff --git a/contrib/msi/msversion.sh b/contrib/msi/msversion.sh index b37e4df..61f221d 100644 --- a/contrib/msi/msversion.sh +++ b/contrib/msi/msversion.sh @@ -23,7 +23,11 @@ MINOR=$(echo $TAG | cut -c 2- | cut -d "." -f 2) PATCH=$(echo $TAG | cut -c 2- | cut -d "." -f 3 | awk -F"rc" '{print $1}') # Output in the desired format -printf '%s%d.%d.%s' "$PREPEND" "$((MAJOR))" "$((MINOR))" "$PATCH" +if [ $((PATCH)) -eq 0 ]; then + printf '%s%d.%d' "$PREPEND" "$((MAJOR))" "$((MINOR))" +else + printf '%s%d.%d.%d' "$PREPEND" "$((MAJOR))" "$((MINOR))" "$((PATCH))" +fi # Add the build tag on non-master branches if [ "$BRANCH" != "master" ]; then @@ -39,4 +43,4 @@ if [ "$BRANCH" != "master" ]; then if [ $((BUILD)) -gt 0 ]; then printf -- "-%04d" "$((BUILD))" fi -fi +fi \ No newline at end of file diff --git a/contrib/semver/name.sh b/contrib/semver/name.sh index 53f56d5..6294f89 100644 --- a/contrib/semver/name.sh +++ b/contrib/semver/name.sh @@ -1,13 +1,12 @@ #!/bin/sh # Get the current branch name -BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null) +BRANCH="$GITHUB_REF_NAME" +if [ -z "$BRANCH" ]; then + BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null) +fi -if [ -n "$APPVEYOR_PULL_REQUEST_NUMBER" ]; then - printf "yggdrasil-pr%s" "$APPVEYOR_PULL_REQUEST_NUMBER" - exit 0 -# Complain if the git history is not available -elif [ $? != 0 ] || [ -z "$BRANCH" ]; then +if [ $? != 0 ] || [ -z "$BRANCH" ]; then printf "yggdrasil" exit 0 fi diff --git a/go.mod b/go.mod index b304b0e..7b2be88 100644 --- a/go.mod +++ b/go.mod @@ -1,16 +1,38 @@ module github.com/popura-network/Popura -go 1.16 +go 1.17 require ( github.com/cheggaaa/pb/v3 v3.0.8 github.com/gologme/log v1.2.0 github.com/hashicorp/go-syslog v1.0.0 github.com/hjson/hjson-go v3.1.0+incompatible - github.com/kardianos/minwinsvc v1.0.0 - github.com/miekg/dns v1.1.41 // indirect + github.com/kardianos/minwinsvc v1.0.2 github.com/mitchellh/mapstructure v1.4.1 - github.com/yggdrasil-network/yggdrasil-go v0.4.3 + github.com/olekukonko/tablewriter v0.0.5 + github.com/yggdrasil-network/yggdrasil-go v0.4.6 github.com/zhoreeq/meshname v0.2.0 - golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b + golang.org/x/mobile v0.0.0-20221012134814-c746ac228303 + golang.org/x/text v0.3.8 +) + +require ( + github.com/Arceliar/ironwood v0.0.0-20221025225125-45b4281814c2 // indirect + github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979 // indirect + github.com/VividCortex/ewma v1.2.0 // indirect + github.com/fatih/color v1.12.0 // indirect + github.com/mattn/go-colorable v0.1.8 // indirect + github.com/mattn/go-isatty v0.0.13 // indirect + github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/miekg/dns v1.1.41 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/vishvananda/netlink v1.1.0 // indirect + github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect + golang.org/x/crypto v0.0.0-20221012134737-56aed061732a // indirect + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/net v0.0.0-20221014081412-f15817d10f9b // indirect + golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 // indirect + golang.org/x/tools v0.1.12 // indirect + golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a // indirect + golang.zx2c4.com/wireguard/windows v0.4.12 // indirect ) diff --git a/go.sum b/go.sum index ef0053d..ca8e119 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/Arceliar/ironwood v0.0.0-20211125050254-8951369625d0 h1:QUqcb7BOcBU2p7Nax7pESOb8hrZYtI0Ts6j4v4mvcQo= -github.com/Arceliar/ironwood v0.0.0-20211125050254-8951369625d0/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk= +github.com/Arceliar/ironwood v0.0.0-20221025225125-45b4281814c2 h1:Usab30pNT2i/vZvpXcN9uOr5IO1RZPcUqoGH0DIAPnU= +github.com/Arceliar/ironwood v0.0.0-20221025225125-45b4281814c2/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk= github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979 h1:WndgpSW13S32VLQ3ugUxx2EnnWmgba1kCqPkd4Gk1yQ= github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979/go.mod h1:6Lkn+/zJilRMsKmbmG1RPoamiArC6HS73xbwRyp3UyI= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -17,8 +17,8 @@ github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwM github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hjson/hjson-go v3.1.0+incompatible h1:DY/9yE8ey8Zv22bY+mHV1uk2yRy0h8tKhZ77hEdi0Aw= github.com/hjson/hjson-go v3.1.0+incompatible/go.mod h1:qsetwF8NlsTsOTwZTApNlTCerV+b2GjYRRcIk4JMFio= -github.com/kardianos/minwinsvc v1.0.0 h1:+JfAi8IBJna0jY2dJGZqi7o15z13JelFIklJCAENALA= -github.com/kardianos/minwinsvc v1.0.0/go.mod h1:Bgd0oc+D0Qo3bBytmNtyRKVlp85dAloLKhfxanPFFRc= +github.com/kardianos/minwinsvc v1.0.2 h1:JmZKFJQrmTGa/WiW+vkJXKmfzdjabuEW4Tirj5lLdR0= +github.com/kardianos/minwinsvc v1.0.2/go.mod h1:LUZNYhNmxujx2tR7FbdxqYJ9XDDoCd3MQcl1o//FWl4= github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ= github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= @@ -26,6 +26,7 @@ github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= @@ -34,6 +35,8 @@ github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -42,25 +45,30 @@ github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYp github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/yggdrasil-network/yggdrasil-go v0.4.3 h1:LNS7kNpKzFlxQ9xmD5tfmMEvzwa+utBoD6pV9t2a8q4= -github.com/yggdrasil-network/yggdrasil-go v0.4.3/go.mod h1:A1/8kOQT7vzBxlkQtLf1KzJR0cbfL/2zjOCiYOAdjjo= +github.com/yggdrasil-network/yggdrasil-go v0.4.6 h1:GALUDV9QPz/5FVkbazpkTc9EABHufA556JwUJZr41j4= +github.com/yggdrasil-network/yggdrasil-go v0.4.6/go.mod h1:PBMoAOvQjA9geNEeGyMXA9QgCS6Bu+9V+1VkWM84wpw= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zhoreeq/meshname v0.2.0 h1:kRAHmemR/MpTmas2ZNoL8VJnYdbesZRwsGR2qEmzyDo= github.com/zhoreeq/meshname v0.2.0/go.mod h1:3I8MpFZ304bAYiD+e+ovlMDDZat8aKyUlqllUok4qm0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20221012134737-56aed061732a h1:NmSIgad6KjE6VvHciPZuNRTKxGhlPfD6OA87W/PLkqg= +golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20220112015953-858099ff7816/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ= +golang.org/x/mobile v0.0.0-20221012134814-c746ac228303 h1:K4fp1rDuJBz0FCPAWzIJwnzwNEM7S6yobdZzMrZ/Zws= +golang.org/x/mobile v0.0.0-20221012134814-c746ac228303/go.mod h1:M32cGdzp91A8Ex9qQtyZinr19EYxzkFqDjW2oyHzTDQ= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -69,11 +77,15 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210927181540-4e4d966f7476/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211011170408-caeb26a5c8c0/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211101193420-4a448f8816b3 h1:VrJZAjbekhoRn7n5FBujY31gboH+iB3pdLxn3gE9FjU= -golang.org/x/net v0.0.0-20211101193420-4a448f8816b3/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b h1:tvrvnPFcdzp294diPnrdZZZ8XUt2Tyj7svb7X52iDuU= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde h1:ejfdSekXMDxDLbRrJMwUk6KnSLZ2McaUCVcIKM+N6jc= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -81,7 +93,6 @@ golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -91,20 +102,28 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211102192858-4dd72447c267 h1:7zYaz3tjChtpayGDzu6H0hDAUM5zIGA2XW7kRNgQ0jc= -golang.org/x/sys v0.0.0-20211102192858-4dd72447c267/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 h1:OK7RB6t2WQX54srQQYSXMW8dF5C6/8+oA/s5QBmmto4= +golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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/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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b h1:NXqSWXSRUSCaFuvitrWtU169I3876zRTalMRbfd6LL0= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= +golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/misc/run-schannel-netns b/misc/run-schannel-netns new file mode 100755 index 0000000..74a0294 --- /dev/null +++ b/misc/run-schannel-netns @@ -0,0 +1,76 @@ +#!/bin/bash + +# Connects nodes in a network resembling an s-channel feynmann diagram. + +# 1 5 +# \ / +# 3--4 +# / \ +# 2 6 + +# Bandwidth constraints are applied to 4<->5 and 4<->6. +# The idea is to make sure that bottlenecks on one link don't affect the other. + +ip netns add node1 +ip netns add node2 +ip netns add node3 +ip netns add node4 +ip netns add node5 +ip netns add node6 + +ip link add veth13 type veth peer name veth31 +ip link set veth13 netns node1 up +ip link set veth31 netns node3 up + +ip link add veth23 type veth peer name veth32 +ip link set veth23 netns node2 up +ip link set veth32 netns node3 up + +ip link add veth34 type veth peer name veth43 +ip link set veth34 netns node3 up +ip link set veth43 netns node4 up + +ip link add veth45 type veth peer name veth54 +ip link set veth45 netns node4 up +ip link set veth54 netns node5 up + +ip link add veth46 type veth peer name veth64 +ip link set veth46 netns node4 up +ip link set veth64 netns node6 up + +ip netns exec node4 tc qdisc add dev veth45 root tbf rate 100mbit burst 8192 latency 1ms +ip netns exec node5 tc qdisc add dev veth54 root tbf rate 100mbit burst 8192 latency 1ms + +ip netns exec node4 tc qdisc add dev veth46 root tbf rate 10mbit burst 8192 latency 1ms +ip netns exec node6 tc qdisc add dev veth64 root tbf rate 10mbit burst 8192 latency 1ms + +ip netns exec node1 ip link set lo up +ip netns exec node2 ip link set lo up +ip netns exec node3 ip link set lo up +ip netns exec node4 ip link set lo up +ip netns exec node5 ip link set lo up +ip netns exec node6 ip link set lo up + +echo '{AdminListen: "none"}' | ip netns exec node1 env PPROFLISTEN=localhost:6060 ./yggdrasil --useconf &> /dev/null & +echo '{AdminListen: "none"}' | ip netns exec node2 env PPROFLISTEN=localhost:6060 ./yggdrasil --useconf &> /dev/null & +echo '{AdminListen: "none"}' | ip netns exec node3 env PPROFLISTEN=localhost:6060 ./yggdrasil --useconf &> /dev/null & +echo '{AdminListen: "none"}' | ip netns exec node4 env PPROFLISTEN=localhost:6060 ./yggdrasil --useconf &> /dev/null & +echo '{AdminListen: "none"}' | ip netns exec node5 env PPROFLISTEN=localhost:6060 ./yggdrasil --useconf &> /dev/null & +echo '{AdminListen: "none"}' | ip netns exec node6 env PPROFLISTEN=localhost:6060 ./yggdrasil --useconf &> /dev/null & + +echo "Started, to continue you should (possibly w/ sudo):" +echo "kill" $(jobs -p) +wait + +ip netns delete node1 +ip netns delete node2 +ip netns delete node3 +ip netns delete node4 +ip netns delete node5 +ip netns delete node6 + +ip link delete veth13 +ip link delete veth23 +ip link delete veth34 +ip link delete veth45 +ip link delete veth46 diff --git a/misc/run-twolink-test b/misc/run-twolink-test new file mode 100755 index 0000000..987b6de --- /dev/null +++ b/misc/run-twolink-test @@ -0,0 +1,33 @@ +#!/bin/bash + +# Connects nodes in two namespaces by two links with different bandwidth (10mbit and 100mbit) + +ip netns add node1 +ip netns add node2 + +ip link add veth11 type veth peer name veth21 +ip link set veth11 netns node1 up +ip link set veth21 netns node2 up + +ip link add veth12 type veth peer name veth22 +ip link set veth12 netns node1 up +ip link set veth22 netns node2 up + +ip netns exec node1 tc qdisc add dev veth11 root tbf rate 10mbit burst 8192 latency 1ms +ip netns exec node2 tc qdisc add dev veth21 root tbf rate 10mbit burst 8192 latency 1ms + +ip netns exec node1 tc qdisc add dev veth12 root tbf rate 100mbit burst 8192 latency 1ms +ip netns exec node2 tc qdisc add dev veth22 root tbf rate 100mbit burst 8192 latency 1ms + +echo '{AdminListen: "unix://node1.sock"}' | ip netns exec node1 env PPROFLISTEN=localhost:6060 ./yggdrasil -logging "info,warn,error,debug" -useconf &> node1.log & +echo '{AdminListen: "unix://node2.sock"}' | ip netns exec node2 env PPROFLISTEN=localhost:6060 ./yggdrasil -logging "info,warn,error,debug" -useconf &> node2.log & + +echo "Started, to continue you should (possibly w/ sudo):" +echo "kill" $(jobs -p) +wait + +ip netns delete node1 +ip netns delete node2 + +ip link delete veth11 +ip link delete veth12 diff --git a/src/autopeering/peers.txt b/src/autopeering/peers.txt index 8c3ef16..6ecfe42 100644 --- a/src/autopeering/peers.txt +++ b/src/autopeering/peers.txt @@ -1,141 +1,122 @@ -tcp://yggby.ddns.net:7991 -tls://yggby.ddns.net:7992 -tcp://45.231.133.188:58301 -tcp://[2804:49fc::ffff:ffff:5b5:e8be]:58301 -tcp://kusoneko.moe:9002 +tcp://ipv6.campina-grande.paraiba.brazil.yggdrasil.iasylum.net:41000 +tcp://ipv4.campina-grande.paraiba.brazil.yggdrasil.iasylum.net:40000 +tls://ipv6.campina-grande.paraiba.brazil.yggdrasil.iasylum.net:51000 +tls://ipv4.campina-grande.paraiba.brazil.yggdrasil.iasylum.net:50000 tls://192.99.145.61:58226 tls://[2607:5300:201:3100::50a1]:58226 +tcp://kusoneko.moe:9002 tls://ca1.servers.devices.cwinfo.net:58226 -tcp://195.123.245.146:7743 -tcp://37.205.14.171:46370 -tcp://[2a03:3b40:fe:ab::1]:46370 tcp://[2a05:9403::8b]:7743 -tcp://ygg-fin.incognet.io:8883 -tls://65.21.57.122:61995 +tcp://195.123.245.146:7743 tls://95.216.5.243:18836 tls://[2a01:4f9:2a:60c::2]:18836 tls://[2a01:4f9:c010:664d::1]:61995 tls://aurora.devices.waren.io:18836 tls://fi1.servers.devices.cwinfo.net:61995 -tls://ygg-fin.incognet.io:8884 -tcp://51.15.204.214:12345 +tls://65.21.57.122:61995 +tls://[2001:41d0:2:c44a:51:255:223:60]:54232 tcp://62.210.85.80:39565 +tls://51.255.223.60:54232 +tcp://51.15.204.214:12345 +tls://51.15.204.214:54321 tcp://[2001:470:1f13:e56::64]:39565 tcp://s2.i2pd.xyz:39565 -tls://152.228.216.112:23108 -tls://51.15.204.214:54321 -tls://51.255.223.60:54232 -tls://62.210.85.80:39575 -tls://[2001:41d0:2:c44a:51:255:223:60]:54232 tls://[2001:41d0:304:200::ace3]:23108 +tls://62.210.85.80:39575 tls://[2001:470:1f13:e56::64]:39575 +tls://152.228.216.112:23108 +tls://s2.i2pd.xyz:39575 tls://cloudberry.fr1.servers.devices.cwinfo.net:54232 tls://fr2.servers.devices.cwinfo.net:23108 -tls://s2.i2pd.xyz:39575 -tcp://01.ffm.deu.ygg.yt:80 -tcp://130.61.94.233:13338 +tls://163.172.31.60:12221?key=060f2d49c6a1a2066357ea06e58f5cff8c76a5c0cc513ceb2dab75c900fe183b&sni=jorropo.net +tls://jorropo.net:12221?key=060f2d49c6a1a2066357ea06e58f5cff8c76a5c0cc513ceb2dab75c900fe183b&sni=jorropo.net tcp://94.130.203.208:5999 -tcp://bunkertreff.ddns.net:5454 -tcp://phrl42.ydns.eu:8842 +tls://yggdrasil.su:62586 tcp://ygg.mkg20001.io:80 -tls://01.ffm.deu.ygg.yt:443 +tls://vpn.ltha.de:443?key=0000006149970f245e6cec43664bce203f2514b60a153e194f31e2b229a1339d +tls://de-fsn-1.peer.v4.yggdrasil.chaz6.com:4444 +tcp://p2p-node.de:1337?key=000000d80a2d7b3126ea65c8c08fc751088c491a5cdd47eff11c86fa1e4644ae +tcp://phrl42.ydns.eu:8842 +tcp://yggdrasil.su:62486 tls://ygg.mkg20001.io:443 -tcp://01.rkv.isl.ygg.yt:80 -tls://01.rkv.isl.ygg.yt:443 -tcp://01.blr.ind.ygg.yt:80 -tls://01.blr.ind.ygg.yt:443 -tcp://01.tky.jpn.ygg.yt:80 -tls://01.tky.jpn.ygg.yt:443 +tls://p2p-node.de:1338?key=000000d80a2d7b3126ea65c8c08fc751088c491a5cdd47eff11c86fa1e4644ae +tcp://ygg1.mk16.de:1337?key=0000000087ee9949eeab56bd430ee8f324cad55abf3993ed9b9be63ce693e18a +tls://ygg1.mk16.de:1338?key=0000000087ee9949eeab56bd430ee8f324cad55abf3993ed9b9be63ce693e18a tls://minecast.xyz:3785 -tcp://jeff.loki:5000 -tcp://yes.loki:5000 -tcp://104.244.79.104:58935 -tcp://01.mxc.mex.ygg.yt:80 -tls://01.mxc.mex.ygg.yt:443 -tcp://01.hrl.nld.ygg.yt:80 -tcp://51.15.118.10:62486 -tcp://[2001:bc8:1820:192f::1]:62486 -tcp://ygg-nl.incognet.io:8883 -tls://01.hrl.nld.ygg.yt:443 tls://45.147.198.155:6010 -tls://77.249.167.165:8084 -tls://94.103.82.150:8080 +tcp://ygg-nl.incognet.io:8883 +tcp://vpn.itrus.su:7991 tls://ygg-nl.incognet.io:8884 -tls://54.37.137.221:11129 +tls://109.107.173.235:9111 +tls://94.103.82.150:8080 +tls://aaoth.xyz:25565 +tcp://aaoth.xyz:7777 tls://[2001:41d0:601:1100::cf2]:11129 +tls://54.37.137.221:11129 tls://pl1.servers.devices.cwinfo.net:11129 tcp://185.165.169.234:8880 tls://185.165.169.234:8443 -tcp://188.120.228.75:7991 tcp://188.225.9.167:18226 tcp://92.124.136.131:30111 -tcp://95.165.99.73:5353 -tcp://box.paulll.cc:13337 -tcp://srv.itrus.su:7991 -tcp://ygg.loskiq.dev:17313 -tcp://ygg.tomasgl.ru:61933?key=c5e0c28a600c2118e986196a0bbcbda4934d8e9278ceabea48838dc5d8fae576 -tcp://ygg0.ezdomain.ru:11129 -tcp://yggno.de:18226 -tls://188.120.228.75:7992 tls://188.225.9.167:18227 +tcp://ygg.tomasgl.ru:61933?key=c5e0c28a600c2118e986196a0bbcbda4934d8e9278ceabea48838dc5d8fae576 tls://[2a01:d0:ffff:4353::2]:6010 -tls://box.paulll.cc:13338 -tls://cluster.h3xco.de:7040 -tls://ygg.loskiq.dev:17314 +tls://avevad.com:1337 +tcp://itcom.multed.com:7991 tls://ygg.tomasgl.ru:61944?key=c5e0c28a600c2118e986196a0bbcbda4934d8e9278ceabea48838dc5d8fae576 -tls://ygg0.ezdomain.ru:11130 +tcp://srv.itrus.su:7991 +tcp://box.paulll.cc:13337 +tcp://yggno.de:18226 tls://yggno.de:18227 -tls://150.230.51.87:17001 -tls://[2603:c023:8001:1600:1::]:17001 +tcp://ekb.itrus.su:7991 +tls://box.paulll.cc:13338 +tls://yggpvs.duckdns.org:8443 +tcp://158.101.229.219:17002 +tcp://[2603:c023:8001:1600:35e0:acde:2c6e:b27f]:17002 tls://[2603:c023:8001:1600:35e0:acde:2c6e:b27f]:17001 -tls://[2603:c023:8001:1600::1:3]:17001 -tcp://01.sgp.sgp.ygg.yt:80 -tls://01.sgp.sgp.ygg.yt:443 +tls://158.101.229.219:17001 +tcp://sin.yuetau.net:6642 +tls://sin.yuetau.net:6643 tcp://y.zbin.eu:7743 -tcp://[2a04:5b81:2010::90]:2000 -tcp://01.sel.kor.ygg.yt:80 -tls://01.sel.kor.ygg.yt:443 -tcp://ygg.ace.ctrl-c.liu.se:9998?key=5636b3af4738c3998284c4805d91209cab38921159c66a6f359f3f692af1c908 -tls://185.130.44.194:7040 +tcp://[2a04:5b81:2010:5000:27d3:6343:a821:eb1c]:2000 +tls://[2a04:5b81:2010:5000:27d3:6343:a821:eb1c]:2001 tls://[2a07:e01:105:444:c634:6bff:feb5:6e28]:7040 +tls://185.130.44.194:7040 tls://ygg.ace.ctrl-c.liu.se:9999?key=5636b3af4738c3998284c4805d91209cab38921159c66a6f359f3f692af1c908 -tcp://140.238.168.104:17117 -tls://140.238.168.104:17121 +tcp://ygg.ace.ctrl-c.liu.se:9998?key=5636b3af4738c3998284c4805d91209cab38921159c66a6f359f3f692af1c908 +tcp://212.154.86.134:8800 +tls://212.154.86.134:4433 +tcp://ip6-antalya.ddns.net:8800 +tls://ip6-antalya.ddns.net:4433 tcp://193.111.114.28:8080 -tcp://78.27.153.163:33165 -tcp://ygg-ukr.incognet.io:8883 tls://193.111.114.28:1443 -tls://78.27.153.163:179 -tls://78.27.153.163:33166 +tls://91.224.254.114:18001 +tcp://78.27.153.163:33165 tls://78.27.153.163:3784 +tls://78.27.153.163:179 tls://78.27.153.163:3785 -tls://ygg-ukr.incognet.io:8884 -tcp://01.lon.gbr.ygg.yt:80 -tcp://curiosity.tdjs.tech:30003 -tls://01.lon.gbr.ygg.yt:443 -tls://185.175.90.87:43006 +tls://78.27.153.163:33166 tls://51.38.64.12:28395 -tls://[2001:41d0:801:2000::233f]:28395 +tls://185.175.90.87:43006 tls://[2a10:4740:40:0:2222:3f9c:b7cf:1]:43006 tls://uk1.servers.devices.cwinfo.net:28395 -tcp://01.scv.usa.ygg.yt:80 +tcp://curiosity.tdjs.tech:30003 tcp://50.236.201.218:56088 -tcp://51.81.46.170:5000 -tcp://[2001:470:c177:2:216:3eff:fe8f:264f]:13121 -tcp://lancis.iscute.moe:49273 tcp://longseason.1200bps.xyz:13121 -tcp://ygg-nv-us.incognet.io:8883 -tcp://ygg-ny-us.incognet.io:8883 -tcp://ygg-tx-us.incognet.io:8883 -tls://01.scv.usa.ygg.yt:443 +tcp://149.28.123.138:8008 +tcp://lancis.iscute.moe:49273 +tcp://zabugor.itrus.su:7991 +tcp://supergay.network:9002 tls://108.175.10.127:61216 +tls://longseason.1200bps.xyz:13122 tls://167.160.89.98:7040 -tls://[2001:470:c177:2:216:3eff:fe8f:264f]:13122 +tls://supergay.network:9001 +tls://supergay.network:443 +tcp://tasty.chowder.land:9002 +tls://44.234.134.124:443 tls://[2605:9f80:2000:64::2]:7040 tls://bazari.sh:3725 +tls://tasty.chowder.land:9001 +tls://5.161.114.182:443 +tls://5.161.139.99:443 tls://lancis.iscute.moe:49274 -tls://longseason.1200bps.xyz:13122 -tls://supergay.network:9001 -tls://ygg-nv-us.incognet.io:8884 -tls://ygg-ny-us.incognet.io:8884 -tls://ygg-tx-us.incognet.io:8884