├── .github └── workflows │ ├── ci.yml │ └── pkg.yml ├── .gitignore ├── .golangci.yml ├── Dockerfile ├── LICENSE ├── README.md ├── build ├── clean ├── cmd ├── genkeys │ └── main.go ├── yggdrasil │ └── main.go └── yggdrasilctl │ ├── cmd_line_env.go │ └── main.go ├── contrib ├── ansible │ └── genkeys.go ├── apparmor │ └── usr.bin.yggdrasil ├── busybox-init │ └── S42yggdrasil ├── deb │ └── generate.sh ├── docker │ ├── Dockerfile │ └── entrypoint.sh ├── freebsd │ └── yggdrasil ├── logo │ └── ygg-neilalexander.svg ├── macos │ ├── create-pkg.sh │ └── yggdrasil.plist ├── mobile │ ├── build │ ├── mobile.go │ ├── mobile_android.go │ ├── mobile_ios.go │ ├── mobile_other.go │ └── mobile_test.go ├── msi │ ├── build-msi.sh │ └── msversion.sh ├── openrc │ └── yggdrasil ├── semver │ ├── name.sh │ └── version.sh ├── systemd │ ├── yggdrasil-default-config.service │ └── yggdrasil.service └── yggdrasil-brute-simple │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── util.c │ ├── yggdrasil-brute-multi-curve25519.c │ ├── yggdrasil-brute-multi-ed25519.c │ └── yggdrasil-brute.h ├── go.mod ├── go.sum ├── misc ├── run-schannel-netns └── run-twolink-test └── src ├── autopeering ├── main.go ├── module.go ├── peers.go └── peers.txt ├── meshname └── module.go └── popura ├── config.go ├── module.go └── utils.go /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Yggdrasil 2 | 3 | on: 4 | push: 5 | pull_request: 6 | release: 7 | workflow_dispatch: 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | lint: 15 | name: Lint 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/setup-go@v3 19 | with: 20 | go-version: 1.19 21 | - uses: actions/checkout@v3 22 | - name: golangci-lint 23 | uses: golangci/golangci-lint-action@v3 24 | with: 25 | args: --issues-exit-code=1 26 | 27 | codeql: 28 | name: Analyse 29 | runs-on: ubuntu-latest 30 | permissions: 31 | actions: read 32 | contents: read 33 | security-events: write 34 | 35 | steps: 36 | - name: Checkout repository 37 | uses: actions/checkout@v3 38 | 39 | - name: Initialize CodeQL 40 | uses: github/codeql-action/init@v2 41 | with: 42 | languages: go 43 | 44 | - name: Autobuild 45 | uses: github/codeql-action/autobuild@v2 46 | 47 | - name: Perform CodeQL Analysis 48 | uses: github/codeql-action/analyze@v2 49 | 50 | build-linux: 51 | strategy: 52 | fail-fast: false 53 | matrix: 54 | goversion: ["1.17", "1.18", "1.19"] 55 | 56 | name: Build & Test (Linux, Go ${{ matrix.goversion }}) 57 | needs: [lint] 58 | 59 | runs-on: ubuntu-latest 60 | steps: 61 | - uses: actions/checkout@v3 62 | 63 | - name: Set up Go 64 | uses: actions/setup-go@v3 65 | with: 66 | go-version: ${{ matrix.goversion }} 67 | 68 | - name: Build Yggdrasil 69 | run: go build -v ./... 70 | 71 | - name: Unit tests 72 | run: go test -v ./... 73 | 74 | build-windows: 75 | strategy: 76 | fail-fast: false 77 | matrix: 78 | goversion: ["1.17", "1.18", "1.19"] 79 | 80 | name: Build & Test (Windows, Go ${{ matrix.goversion }}) 81 | needs: [lint] 82 | 83 | runs-on: windows-latest 84 | steps: 85 | - uses: actions/checkout@v3 86 | 87 | - name: Set up Go 88 | uses: actions/setup-go@v3 89 | with: 90 | go-version: ${{ matrix.goversion }} 91 | 92 | - name: Build Yggdrasil 93 | run: go build -v ./... 94 | 95 | - name: Unit tests 96 | run: go test -v ./... 97 | 98 | build-macos: 99 | strategy: 100 | fail-fast: false 101 | matrix: 102 | goversion: ["1.17", "1.18", "1.19"] 103 | 104 | name: Build & Test (macOS, Go ${{ matrix.goversion }}) 105 | needs: [lint] 106 | 107 | runs-on: macos-latest 108 | steps: 109 | - uses: actions/checkout@v3 110 | 111 | - name: Set up Go 112 | uses: actions/setup-go@v3 113 | with: 114 | go-version: ${{ matrix.goversion }} 115 | 116 | - name: Build Yggdrasil 117 | run: go build -v ./... 118 | 119 | - name: Unit tests 120 | run: go test -v ./... 121 | 122 | tests-ok: 123 | name: All tests passed 124 | needs: [lint, codeql, build-linux, build-windows, build-macos] 125 | runs-on: ubuntu-latest 126 | if: ${{ !cancelled() }} 127 | steps: 128 | - name: Check all tests passed 129 | uses: re-actors/alls-green@release/v1 130 | with: 131 | jobs: ${{ toJSON(needs) }} -------------------------------------------------------------------------------- /.github/workflows/pkg.yml: -------------------------------------------------------------------------------- 1 | name: Packages 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | concurrency: 7 | group: ${{ github.workflow }}-${{ github.ref }} 8 | cancel-in-progress: true 9 | 10 | jobs: 11 | build-packages-debian: 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | pkgarch: ["amd64", "i386", "mips", "mipsel", "armhf", "armel", "arm64"] 16 | 17 | name: Package (Debian, ${{ matrix.pkgarch }}) 18 | 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v3 22 | with: 23 | fetch-depth: 0 24 | 25 | - name: Set up Go 26 | uses: actions/setup-go@v3 27 | with: 28 | go-version: 1.19 29 | 30 | - name: Build package 31 | env: 32 | PKGARCH: ${{ matrix.pkgarch }} 33 | run: sh contrib/deb/generate.sh 34 | 35 | - name: Upload artifacts 36 | uses: actions/upload-artifact@v3 37 | with: 38 | name: Debian package (${{ matrix.pkgarch }}) 39 | path: "*.deb" 40 | if-no-files-found: error 41 | 42 | build-packages-macos: 43 | strategy: 44 | fail-fast: false 45 | matrix: 46 | pkgarch: ["amd64", "arm64"] 47 | 48 | name: Package (macOS, ${{ matrix.pkgarch }}) 49 | 50 | runs-on: macos-latest 51 | steps: 52 | - uses: actions/checkout@v3 53 | with: 54 | fetch-depth: 0 55 | 56 | - name: Set up Go 57 | uses: actions/setup-go@v3 58 | with: 59 | go-version: 1.19 60 | 61 | - name: Build package 62 | env: 63 | PKGARCH: ${{ matrix.pkgarch }} 64 | run: sh contrib/macos/create-pkg.sh 65 | 66 | - name: Upload artifacts 67 | uses: actions/upload-artifact@v3 68 | with: 69 | name: macOS package (${{ matrix.pkgarch }}) 70 | path: "*.pkg" 71 | if-no-files-found: error 72 | 73 | build-packages-windows: 74 | strategy: 75 | fail-fast: false 76 | matrix: 77 | pkgarch: ["x64", "x86", "arm", "arm64"] 78 | 79 | name: Package (Windows, ${{ matrix.pkgarch }}) 80 | 81 | runs-on: windows-latest 82 | steps: 83 | - uses: actions/checkout@v3 84 | with: 85 | fetch-depth: 0 86 | 87 | - name: Set up Go 88 | uses: actions/setup-go@v3 89 | with: 90 | go-version: 1.19 91 | 92 | - name: Build package 93 | run: sh contrib/msi/build-msi.sh ${{ matrix.pkgarch }} 94 | 95 | - name: Upload artifacts 96 | uses: actions/upload-artifact@v3 97 | with: 98 | name: Windows package (${{ matrix.pkgarch }}) 99 | path: "*.msi" 100 | if-no-files-found: error 101 | 102 | build-packages-router: 103 | strategy: 104 | fail-fast: false 105 | matrix: 106 | pkgarch: ["edgerouter-x", "edgerouter-lite", "vyos-amd64", "vyos-i386"] 107 | 108 | name: Package (Router, ${{ matrix.pkgarch }}) 109 | 110 | runs-on: ubuntu-latest 111 | steps: 112 | - uses: actions/checkout@v3 113 | with: 114 | fetch-depth: 0 115 | path: yggdrasil 116 | 117 | - uses: actions/checkout@v3 118 | with: 119 | repository: neilalexander/vyatta-yggdrasil 120 | path: vyatta-yggdrasil 121 | 122 | - name: Set up Go 123 | uses: actions/setup-go@v3 124 | with: 125 | go-version: 1.19 126 | 127 | - name: Build package 128 | env: 129 | BUILDDIR_YGG: /home/runner/work/yggdrasil-go/yggdrasil-go/yggdrasil 130 | run: cd /home/runner/work/yggdrasil-go/yggdrasil-go/vyatta-yggdrasil && ./build-${{ matrix.pkgarch }} 131 | 132 | - name: Upload artifacts 133 | uses: actions/upload-artifact@v3 134 | with: 135 | name: Router package (${{ matrix.pkgarch }}) 136 | path: "/home/runner/work/yggdrasil-go/yggdrasil-go/vyatta-yggdrasil/*.deb" 137 | if-no-files-found: error 138 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /yggdrasil 2 | /yggdrasil.exe 3 | /yggdrasilctl 4 | /yggdrasilctl.exe 5 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | run: 2 | build-tags: 3 | - lint 4 | issues-exit-code: 0 # TODO: change this to 1 when we want it to fail builds 5 | skip-dirs: 6 | - contrib/ 7 | - misc/ 8 | linters: 9 | disable: 10 | - gocyclo -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | contrib/docker/Dockerfile 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Popura ポプラ 2 | 3 | Popura, an alternative Yggdrasil network client 4 | 5 | *Yggdrasil Network* is a peer-to-peer IPv6 network with link-local peer discovery, 6 | automatic end-to-end encryption, distributed IP address allocation, and DHT-based routing information exchange. 7 | 8 | Popura uses the same Yggdrasil core API internally, but adds some useful 9 | experimental features which the original client lacks. 10 | 11 | By default, it works just like the original yggdrasil client, all features must be enabled manually. 12 | Popura adds new command line flags and config file sections to control those features. 13 | 14 | ## Features 15 | 16 | - [Autopeering](https://github.com/popura-network/Popura/wiki/Autopeering) over the Internet 17 | - Built-in decentralized DNS system [meshname](https://github.com/popura-network/Popura/wiki/Meshname) 18 | 19 | ## Installing 20 | 21 | - [Arch Linux](https://aur.archlinux.org/packages/popura-git/) 22 | - [Debian](https://github.com/popura-network/popura-debian-repo) 23 | - [Gentoo](https://yggdrasil-network.github.io/installation-linux-gentoo.html) 24 | - Just replace `net-p2p/yggdrasil-go` with `net-p2p/popura` 25 | - [OpenWRT](https://github.com/popura-network/hypermodem-packages) 26 | - [Windows](https://github.com/popura-network/Popura/releases) 27 | 28 | ## Building from source 29 | 30 | 1. Install Go 31 | 2. Clone this repository 32 | 3. Run `./build` 33 | 34 | ## Information 35 | 36 | [Wiki](https://github.com/popura-network/Popura/wiki) 37 | 38 | [Blog](https://popura-network.github.io) 39 | 40 | [Telegram channel](https://t.me/PopuraChan) 41 | 42 | [Yggdrasil documentation](https://yggdrasil-network.github.io/) 43 | -------------------------------------------------------------------------------- /build: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -ef 4 | 5 | PKGSRC=${PKGSRC:-github.com/yggdrasil-network/yggdrasil-go/src/version} 6 | PKGNAME=${PKGNAME:-$(sh contrib/semver/name.sh)} 7 | PKGVER=${PKGVER:-$(sh contrib/semver/version.sh --bare)} 8 | 9 | LDFLAGS="-X $PKGSRC.buildName=$PKGNAME -X $PKGSRC.buildVersion=$PKGVER" 10 | ARGS="-v" 11 | 12 | while getopts "utc:l:dro:p" option 13 | do 14 | case "$option" 15 | in 16 | u) UPX=true;; 17 | t) TABLES=true;; 18 | c) GCFLAGS="$GCFLAGS $OPTARG";; 19 | l) LDFLAGS="$LDFLAGS $OPTARG";; 20 | d) ARGS="$ARGS -tags debug" DEBUG=true;; 21 | r) ARGS="$ARGS -race";; 22 | o) ARGS="$ARGS -o $OPTARG";; 23 | p) ARGS="$ARGS -buildmode=pie";; 24 | esac 25 | done 26 | 27 | if [ -z $TABLES ] && [ -z $DEBUG ]; then 28 | LDFLAGS="$LDFLAGS -s -w" 29 | fi 30 | 31 | for CMD in yggdrasil yggdrasilctl ; do 32 | echo "Building: $CMD" 33 | go build $ARGS -ldflags="$LDFLAGS" -gcflags="$GCFLAGS" ./cmd/$CMD 34 | 35 | if [ $UPX ]; then 36 | upx --brute $CMD 37 | fi 38 | done 39 | -------------------------------------------------------------------------------- /clean: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | git clean -dxf 3 | -------------------------------------------------------------------------------- /cmd/genkeys/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | This file generates crypto keys. 4 | It prints out a new set of keys each time if finds a "better" one. 5 | By default, "better" means a higher NodeID (-> higher IP address). 6 | This is because the IP address format can compress leading 1s in the address, to increase the number of ID bits in the address. 7 | 8 | If run with the "-sig" flag, it generates signing keys instead. 9 | A "better" signing key means one with a higher TreeID. 10 | This only matters if it's high enough to make you the root of the tree. 11 | 12 | */ 13 | package main 14 | 15 | import ( 16 | "crypto/ed25519" 17 | "encoding/hex" 18 | "fmt" 19 | "net" 20 | "runtime" 21 | 22 | "github.com/yggdrasil-network/yggdrasil-go/src/address" 23 | ) 24 | 25 | type keySet struct { 26 | priv ed25519.PrivateKey 27 | pub ed25519.PublicKey 28 | } 29 | 30 | func main() { 31 | threads := runtime.GOMAXPROCS(0) 32 | var currentBest ed25519.PublicKey 33 | newKeys := make(chan keySet, threads) 34 | for i := 0; i < threads; i++ { 35 | go doKeys(newKeys) 36 | } 37 | for { 38 | newKey := <-newKeys 39 | if isBetter(currentBest, newKey.pub) || len(currentBest) == 0 { 40 | currentBest = newKey.pub 41 | fmt.Println("-----") 42 | fmt.Println("Priv:", hex.EncodeToString(newKey.priv)) 43 | fmt.Println("Pub:", hex.EncodeToString(newKey.pub)) 44 | addr := address.AddrForKey(newKey.pub) 45 | fmt.Println("IP:", net.IP(addr[:]).String()) 46 | } 47 | } 48 | } 49 | 50 | func isBetter(oldPub, newPub ed25519.PublicKey) bool { 51 | for idx := range oldPub { 52 | if newPub[idx] < oldPub[idx] { 53 | return true 54 | } 55 | if newPub[idx] > oldPub[idx] { 56 | break 57 | } 58 | } 59 | return false 60 | } 61 | 62 | func doKeys(out chan<- keySet) { 63 | bestKey := make(ed25519.PublicKey, ed25519.PublicKeySize) 64 | for idx := range bestKey { 65 | bestKey[idx] = 0xff 66 | } 67 | for { 68 | pub, priv, err := ed25519.GenerateKey(nil) 69 | if err != nil { 70 | panic(err) 71 | } 72 | if !isBetter(bestKey, pub) { 73 | continue 74 | } 75 | bestKey = pub 76 | out <- keySet{priv, pub} 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /cmd/yggdrasil/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "crypto/ed25519" 7 | "encoding/hex" 8 | "encoding/json" 9 | "flag" 10 | "fmt" 11 | "io" 12 | "net" 13 | "os" 14 | "os/signal" 15 | "regexp" 16 | "strings" 17 | "sync" 18 | "syscall" 19 | 20 | "golang.org/x/text/encoding/unicode" 21 | 22 | "github.com/gologme/log" 23 | gsyslog "github.com/hashicorp/go-syslog" 24 | "github.com/hjson/hjson-go" 25 | "github.com/kardianos/minwinsvc" 26 | "github.com/mitchellh/mapstructure" 27 | 28 | "github.com/yggdrasil-network/yggdrasil-go/src/address" 29 | "github.com/yggdrasil-network/yggdrasil-go/src/admin" 30 | "github.com/yggdrasil-network/yggdrasil-go/src/config" 31 | "github.com/yggdrasil-network/yggdrasil-go/src/defaults" 32 | "github.com/yggdrasil-network/yggdrasil-go/src/ipv6rwc" 33 | 34 | "github.com/yggdrasil-network/yggdrasil-go/src/core" 35 | "github.com/yggdrasil-network/yggdrasil-go/src/multicast" 36 | "github.com/yggdrasil-network/yggdrasil-go/src/tun" 37 | "github.com/yggdrasil-network/yggdrasil-go/src/version" 38 | 39 | "github.com/popura-network/Popura/src/autopeering" 40 | "github.com/popura-network/Popura/src/meshname" 41 | "github.com/popura-network/Popura/src/popura" 42 | ) 43 | 44 | type node struct { 45 | core *core.Core 46 | tun *tun.TunAdapter 47 | multicast *multicast.Multicast 48 | admin *admin.AdminSocket 49 | meshname popura.Module // meshname.MeshnameServer 50 | autopeering popura.Module // autopeering.AutoPeering 51 | } 52 | 53 | func readConfig(log *log.Logger, useconf bool, useconffile string, normaliseconf bool) *config.NodeConfig { 54 | // Use a configuration file. If -useconf, the configuration will be read 55 | // from stdin. If -useconffile, the configuration will be read from the 56 | // filesystem. 57 | var conf []byte 58 | var err error 59 | if useconffile != "" { 60 | // Read the file from the filesystem 61 | conf, err = os.ReadFile(useconffile) 62 | } else { 63 | // Read the file from stdin. 64 | conf, err = io.ReadAll(os.Stdin) 65 | } 66 | if err != nil { 67 | panic(err) 68 | } 69 | // If there's a byte order mark - which Windows 10 is now incredibly fond of 70 | // throwing everywhere when it's converting things into UTF-16 for the hell 71 | // of it - remove it and decode back down into UTF-8. This is necessary 72 | // because hjson doesn't know what to do with UTF-16 and will panic 73 | if bytes.Equal(conf[0:2], []byte{0xFF, 0xFE}) || 74 | bytes.Equal(conf[0:2], []byte{0xFE, 0xFF}) { 75 | utf := unicode.UTF16(unicode.BigEndian, unicode.UseBOM) 76 | decoder := utf.NewDecoder() 77 | conf, err = decoder.Bytes(conf) 78 | if err != nil { 79 | panic(err) 80 | } 81 | } 82 | // Generate a new configuration - this gives us a set of sane defaults - 83 | // then parse the configuration we loaded above on top of it. The effect 84 | // of this is that any configuration item that is missing from the provided 85 | // configuration will use a sane default. 86 | cfg := defaults.GenerateConfig() 87 | var dat map[string]interface{} 88 | if err := hjson.Unmarshal(conf, &dat); err != nil { 89 | panic(err) 90 | } 91 | // Sanitise the config 92 | confJson, err := json.Marshal(dat) 93 | if err != nil { 94 | panic(err) 95 | } 96 | if err := json.Unmarshal(confJson, &cfg); err != nil { 97 | panic(err) 98 | } 99 | // Overlay our newly mapped configuration onto the autoconf node config that 100 | // we generated above. 101 | if err = mapstructure.Decode(dat, &cfg); err != nil { 102 | panic(err) 103 | } 104 | return cfg 105 | } 106 | 107 | // Generates a new configuration and returns it in HJSON format. This is used 108 | // with -genconf. 109 | func doGenconf(isjson bool) string { 110 | cfg := defaults.GenerateConfig() 111 | var bs []byte 112 | var err error 113 | if isjson { 114 | bs, err = json.MarshalIndent(cfg, "", " ") 115 | } else { 116 | bs, err = hjson.Marshal(cfg) 117 | } 118 | if err != nil { 119 | panic(err) 120 | } 121 | return string(bs) 122 | } 123 | 124 | func setLogLevel(loglevel string, logger *log.Logger) { 125 | levels := [...]string{"error", "warn", "info", "debug", "trace"} 126 | loglevel = strings.ToLower(loglevel) 127 | 128 | contains := func() bool { 129 | for _, l := range levels { 130 | if l == loglevel { 131 | return true 132 | } 133 | } 134 | return false 135 | } 136 | 137 | if !contains() { // set default log level 138 | logger.Infoln("Loglevel parse failed. Set default level(info)") 139 | loglevel = "info" 140 | } 141 | 142 | for _, l := range levels { 143 | logger.EnableLevel(l) 144 | if l == loglevel { 145 | break 146 | } 147 | } 148 | } 149 | 150 | type yggArgs struct { 151 | genconf bool 152 | useconf bool 153 | normaliseconf bool 154 | confjson bool 155 | autoconf bool 156 | ver bool 157 | getaddr bool 158 | getsnet bool 159 | useconffile string 160 | logto string 161 | loglevel string 162 | autopeer bool 163 | meshnameenable bool 164 | meshnamelisten string 165 | } 166 | 167 | func getArgs() yggArgs { 168 | genconf := flag.Bool("genconf", false, "print a new config to stdout") 169 | useconf := flag.Bool("useconf", false, "read HJSON/JSON config from stdin") 170 | useconffile := flag.String("useconffile", "", "read HJSON/JSON config from specified file path") 171 | normaliseconf := flag.Bool("normaliseconf", false, "use in combination with either -useconf or -useconffile, outputs your configuration normalised") 172 | confjson := flag.Bool("json", false, "print configuration from -genconf or -normaliseconf as JSON instead of HJSON") 173 | autoconf := flag.Bool("autoconf", false, "automatic mode (dynamic IP, peer with IPv6 neighbors)") 174 | ver := flag.Bool("version", false, "prints the version of this build") 175 | logto := flag.String("logto", "stdout", "file path to log to, \"syslog\" or \"stdout\"") 176 | getaddr := flag.Bool("address", false, "returns the IPv6 address as derived from the supplied configuration") 177 | getsnet := flag.Bool("subnet", false, "returns the IPv6 subnet as derived from the supplied configuration") 178 | loglevel := flag.String("loglevel", "info", "loglevel to enable") 179 | autopeer := flag.Bool("autopeer", false, "automatic Internet peering (using peers from github.com/yggdrasil-network/public-peers)") 180 | meshnameenable := flag.Bool("meshname", false, "enable meshname resolver") 181 | meshnamelisten := flag.String("meshnamelisten", "[::1]:53535", "meshname resolver listen address") 182 | flag.Parse() 183 | return yggArgs{ 184 | genconf: *genconf, 185 | useconf: *useconf, 186 | useconffile: *useconffile, 187 | normaliseconf: *normaliseconf, 188 | confjson: *confjson, 189 | autoconf: *autoconf, 190 | ver: *ver, 191 | logto: *logto, 192 | getaddr: *getaddr, 193 | getsnet: *getsnet, 194 | loglevel: *loglevel, 195 | autopeer: *autopeer, 196 | meshnameenable: *meshnameenable, 197 | meshnamelisten: *meshnamelisten, 198 | } 199 | } 200 | 201 | // The main function is responsible for configuring and starting Yggdrasil. 202 | func run(args yggArgs, ctx context.Context) { 203 | // Create a new logger that logs output to stdout. 204 | var logger *log.Logger 205 | switch args.logto { 206 | case "stdout": 207 | logger = log.New(os.Stdout, "", log.Flags()) 208 | case "syslog": 209 | if syslogger, err := gsyslog.NewLogger(gsyslog.LOG_NOTICE, "DAEMON", version.BuildName()); err == nil { 210 | logger = log.New(syslogger, "", log.Flags()) 211 | } 212 | default: 213 | if logfd, err := os.OpenFile(args.logto, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err == nil { 214 | logger = log.New(logfd, "", log.Flags()) 215 | } 216 | } 217 | if logger == nil { 218 | logger = log.New(os.Stdout, "", log.Flags()) 219 | logger.Warnln("Logging defaulting to stdout") 220 | } 221 | 222 | if args.normaliseconf { 223 | setLogLevel("error", logger) 224 | } else { 225 | setLogLevel(args.loglevel, logger) 226 | } 227 | 228 | var cfg *config.NodeConfig 229 | popuraConfig := popura.GenerateConfig() 230 | var err error 231 | switch { 232 | case args.ver: 233 | fmt.Println("Build name:", version.BuildName()) 234 | fmt.Println("Build version:", version.BuildVersion()) 235 | return 236 | case args.autoconf: 237 | // Use an autoconf-generated config, this will give us random keys and 238 | // port numbers, and will use an automatically selected TUN interface. 239 | cfg = defaults.GenerateConfig() 240 | case args.useconffile != "" || args.useconf: 241 | // Read the configuration from either stdin or from the filesystem 242 | cfg = readConfig(logger, args.useconf, args.useconffile, args.normaliseconf) 243 | // If the -normaliseconf option was specified then remarshal the above 244 | // configuration and print it back to stdout. This lets the user update 245 | // their configuration file with newly mapped names (like above) or to 246 | // convert from plain JSON to commented HJSON. 247 | if args.normaliseconf { 248 | var bs []byte 249 | if args.confjson { 250 | bs, err = json.MarshalIndent(cfg, "", " ") 251 | } else { 252 | bs, err = hjson.Marshal(cfg) 253 | } 254 | if err != nil { 255 | panic(err) 256 | } 257 | fmt.Println(string(bs)) 258 | return 259 | } 260 | case args.genconf: 261 | // Generate a new configuration and print it to stdout. 262 | fmt.Println(doGenconf(args.confjson)) 263 | return 264 | default: 265 | // No flags were provided, therefore print the list of flags to stdout. 266 | flag.PrintDefaults() 267 | } 268 | // Have we got a working configuration? If we don't then it probably means 269 | // that neither -autoconf, -useconf or -useconffile were set above. Stop 270 | // if we don't. 271 | if cfg == nil { 272 | return 273 | } 274 | // Have we been asked for the node address yet? If so, print it and then stop. 275 | getNodeKey := func() ed25519.PublicKey { 276 | if pubkey, err := hex.DecodeString(cfg.PrivateKey); err == nil { 277 | return ed25519.PrivateKey(pubkey).Public().(ed25519.PublicKey) 278 | } 279 | return nil 280 | } 281 | switch { 282 | case args.getaddr: 283 | if key := getNodeKey(); key != nil { 284 | addr := address.AddrForKey(key) 285 | ip := net.IP(addr[:]) 286 | fmt.Println(ip.String()) 287 | } 288 | return 289 | case args.getsnet: 290 | if key := getNodeKey(); key != nil { 291 | snet := address.SubnetForKey(key) 292 | ipnet := net.IPNet{ 293 | IP: append(snet[:], 0, 0, 0, 0, 0, 0, 0, 0), 294 | Mask: net.CIDRMask(len(snet)*8, 128), 295 | } 296 | fmt.Println(ipnet.String()) 297 | } 298 | return 299 | } 300 | 301 | n := &node{} 302 | 303 | // Setup the Yggdrasil node itself. 304 | { 305 | sk, err := hex.DecodeString(cfg.PrivateKey) 306 | if err != nil { 307 | panic(err) 308 | } 309 | options := []core.SetupOption{ 310 | core.NodeInfo(cfg.NodeInfo), 311 | core.NodeInfoPrivacy(cfg.NodeInfoPrivacy), 312 | } 313 | for _, addr := range cfg.Listen { 314 | options = append(options, core.ListenAddress(addr)) 315 | } 316 | for _, peer := range cfg.Peers { 317 | options = append(options, core.Peer{URI: peer}) 318 | } 319 | for intf, peers := range cfg.InterfacePeers { 320 | for _, peer := range peers { 321 | options = append(options, core.Peer{URI: peer, SourceInterface: intf}) 322 | } 323 | } 324 | for _, allowed := range cfg.AllowedPublicKeys { 325 | k, err := hex.DecodeString(allowed) 326 | if err != nil { 327 | panic(err) 328 | } 329 | options = append(options, core.AllowedPublicKey(k[:])) 330 | } 331 | if n.core, err = core.New(sk[:], logger, options...); err != nil { 332 | panic(err) 333 | } 334 | } 335 | 336 | // Setup the admin socket. 337 | { 338 | options := []admin.SetupOption{ 339 | admin.ListenAddress(cfg.AdminListen), 340 | } 341 | if n.admin, err = admin.New(n.core, logger, options...); err != nil { 342 | panic(err) 343 | } 344 | if n.admin != nil { 345 | n.admin.SetupAdminHandlers() 346 | } 347 | } 348 | 349 | // Setup the multicast module. 350 | { 351 | options := []multicast.SetupOption{} 352 | for _, intf := range cfg.MulticastInterfaces { 353 | options = append(options, multicast.MulticastInterface{ 354 | Regex: regexp.MustCompile(intf.Regex), 355 | Beacon: intf.Beacon, 356 | Listen: intf.Listen, 357 | Port: intf.Port, 358 | Priority: intf.Priority, 359 | }) 360 | } 361 | if n.multicast, err = multicast.New(n.core, logger, options...); err != nil { 362 | panic(err) 363 | } 364 | if n.admin != nil && n.multicast != nil { 365 | n.multicast.SetupAdminHandlers(n.admin) 366 | } 367 | } 368 | 369 | // Setup the TUN module. 370 | { 371 | options := []tun.SetupOption{ 372 | tun.InterfaceName(cfg.IfName), 373 | tun.InterfaceMTU(cfg.IfMTU), 374 | } 375 | if n.tun, err = tun.New(ipv6rwc.NewReadWriteCloser(n.core), logger, options...); err != nil { 376 | panic(err) 377 | } 378 | if n.admin != nil && n.tun != nil { 379 | n.tun.SetupAdminHandlers(n.admin) 380 | } 381 | } 382 | 383 | // Setup Popura modules 384 | { 385 | n.meshname = &meshname.MeshnameServer{} 386 | n.autopeering = &autopeering.AutoPeering{} 387 | 388 | popuraConfig.Meshname.Enable = args.meshnameenable 389 | popuraConfig.Meshname.Listen = args.meshnamelisten 390 | _ = n.meshname.Init(n.core, cfg, popuraConfig, logger, nil) 391 | if err = n.meshname.Start(); err != nil { 392 | panic(err) 393 | } 394 | 395 | popuraConfig.Autopeering.Enable = args.autopeer 396 | _ = n.autopeering.Init(n.core, cfg, popuraConfig, logger, nil) 397 | if err = n.autopeering.Start(); err != nil { 398 | panic(err) 399 | } 400 | } 401 | 402 | // Make some nice output that tells us what our IPv6 address and subnet are. 403 | // This is just logged to stdout for the user. 404 | address := n.core.Address() 405 | subnet := n.core.Subnet() 406 | public := n.core.GetSelf().Key 407 | logger.Infof("Your public key is %s", hex.EncodeToString(public[:])) 408 | logger.Infof("Your IPv6 address is %s", address.String()) 409 | logger.Infof("Your IPv6 subnet is %s", subnet.String()) 410 | 411 | // Block until we are told to shut down. 412 | <-ctx.Done() 413 | 414 | // Shut down the node. 415 | _ = n.admin.Stop() 416 | _ = n.multicast.Stop() 417 | _ = n.tun.Stop() 418 | _ = n.autopeering.Stop() 419 | _ = n.meshname.Stop() 420 | n.core.Stop() 421 | } 422 | 423 | func main() { 424 | args := getArgs() 425 | 426 | // Catch interrupts from the operating system to exit gracefully. 427 | ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) 428 | 429 | // Capture the service being stopped on Windows. 430 | minwinsvc.SetOnExit(cancel) 431 | 432 | // Start the node, block and then wait for it to shut down. 433 | var wg sync.WaitGroup 434 | wg.Add(1) 435 | go func() { 436 | defer wg.Done() 437 | run(args, ctx) 438 | }() 439 | wg.Wait() 440 | } 441 | -------------------------------------------------------------------------------- /cmd/yggdrasilctl/cmd_line_env.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "flag" 6 | "fmt" 7 | "log" 8 | "os" 9 | 10 | "github.com/hjson/hjson-go" 11 | "golang.org/x/text/encoding/unicode" 12 | 13 | "github.com/yggdrasil-network/yggdrasil-go/src/defaults" 14 | ) 15 | 16 | type CmdLineEnv struct { 17 | args []string 18 | endpoint, server string 19 | injson, ver bool 20 | } 21 | 22 | func newCmdLineEnv() CmdLineEnv { 23 | var cmdLineEnv CmdLineEnv 24 | cmdLineEnv.endpoint = defaults.GetDefaults().DefaultAdminListen 25 | return cmdLineEnv 26 | } 27 | 28 | func (cmdLineEnv *CmdLineEnv) parseFlagsAndArgs() { 29 | flag.Usage = func() { 30 | fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] command [key=value] [key=value] ...\n\n", os.Args[0]) 31 | fmt.Println("Options:") 32 | flag.PrintDefaults() 33 | fmt.Println() 34 | fmt.Println("Please note that options must always specified BEFORE the command\non the command line or they will be ignored.") 35 | fmt.Println() 36 | fmt.Println("Commands:\n - Use \"list\" for a list of available commands") 37 | fmt.Println() 38 | fmt.Println("Examples:") 39 | fmt.Println(" - ", os.Args[0], "list") 40 | fmt.Println(" - ", os.Args[0], "getPeers") 41 | fmt.Println(" - ", os.Args[0], "-v getSelf") 42 | fmt.Println(" - ", os.Args[0], "setTunTap name=auto mtu=1500 tap_mode=false") 43 | fmt.Println(" - ", os.Args[0], "-endpoint=tcp://localhost:9001 getDHT") 44 | fmt.Println(" - ", os.Args[0], "-endpoint=unix:///var/run/ygg.sock getDHT") 45 | } 46 | 47 | server := flag.String("endpoint", cmdLineEnv.endpoint, "Admin socket endpoint") 48 | injson := flag.Bool("json", false, "Output in JSON format (as opposed to pretty-print)") 49 | ver := flag.Bool("version", false, "Prints the version of this build") 50 | 51 | flag.Parse() 52 | 53 | cmdLineEnv.args = flag.Args() 54 | cmdLineEnv.server = *server 55 | cmdLineEnv.injson = *injson 56 | cmdLineEnv.ver = *ver 57 | } 58 | 59 | func (cmdLineEnv *CmdLineEnv) setEndpoint(logger *log.Logger) { 60 | if cmdLineEnv.server == cmdLineEnv.endpoint { 61 | if config, err := os.ReadFile(defaults.GetDefaults().DefaultConfigFile); err == nil { 62 | if bytes.Equal(config[0:2], []byte{0xFF, 0xFE}) || 63 | bytes.Equal(config[0:2], []byte{0xFE, 0xFF}) { 64 | utf := unicode.UTF16(unicode.BigEndian, unicode.UseBOM) 65 | decoder := utf.NewDecoder() 66 | config, err = decoder.Bytes(config) 67 | if err != nil { 68 | panic(err) 69 | } 70 | } 71 | var dat map[string]interface{} 72 | if err := hjson.Unmarshal(config, &dat); err != nil { 73 | panic(err) 74 | } 75 | if ep, ok := dat["AdminListen"].(string); ok && (ep != "none" && ep != "") { 76 | cmdLineEnv.endpoint = ep 77 | logger.Println("Found platform default config file", defaults.GetDefaults().DefaultConfigFile) 78 | logger.Println("Using endpoint", cmdLineEnv.endpoint, "from AdminListen") 79 | } else { 80 | logger.Println("Configuration file doesn't contain appropriate AdminListen option") 81 | logger.Println("Falling back to platform default", defaults.GetDefaults().DefaultAdminListen) 82 | } 83 | } else { 84 | logger.Println("Can't open config file from default location", defaults.GetDefaults().DefaultConfigFile) 85 | logger.Println("Falling back to platform default", defaults.GetDefaults().DefaultAdminListen) 86 | } 87 | } else { 88 | cmdLineEnv.endpoint = cmdLineEnv.server 89 | logger.Println("Using endpoint", cmdLineEnv.endpoint, "from command line") 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /cmd/yggdrasilctl/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "errors" 7 | "flag" 8 | "fmt" 9 | "log" 10 | "net" 11 | "net/url" 12 | "os" 13 | "strings" 14 | "time" 15 | 16 | "github.com/olekukonko/tablewriter" 17 | "github.com/yggdrasil-network/yggdrasil-go/src/admin" 18 | "github.com/yggdrasil-network/yggdrasil-go/src/core" 19 | "github.com/yggdrasil-network/yggdrasil-go/src/multicast" 20 | "github.com/yggdrasil-network/yggdrasil-go/src/tun" 21 | "github.com/yggdrasil-network/yggdrasil-go/src/version" 22 | ) 23 | 24 | func main() { 25 | // makes sure we can use defer and still return an error code to the OS 26 | os.Exit(run()) 27 | } 28 | 29 | func run() int { 30 | logbuffer := &bytes.Buffer{} 31 | logger := log.New(logbuffer, "", log.Flags()) 32 | 33 | defer func() int { 34 | if r := recover(); r != nil { 35 | logger.Println("Fatal error:", r) 36 | fmt.Print(logbuffer) 37 | return 1 38 | } 39 | return 0 40 | }() 41 | 42 | cmdLineEnv := newCmdLineEnv() 43 | cmdLineEnv.parseFlagsAndArgs() 44 | 45 | if cmdLineEnv.ver { 46 | fmt.Println("Build name:", version.BuildName()) 47 | fmt.Println("Build version:", version.BuildVersion()) 48 | fmt.Println("To get the version number of the running Yggdrasil node, run", os.Args[0], "getSelf") 49 | return 0 50 | } 51 | 52 | if len(cmdLineEnv.args) == 0 { 53 | flag.Usage() 54 | return 0 55 | } 56 | 57 | cmdLineEnv.setEndpoint(logger) 58 | 59 | var conn net.Conn 60 | u, err := url.Parse(cmdLineEnv.endpoint) 61 | if err == nil { 62 | switch strings.ToLower(u.Scheme) { 63 | case "unix": 64 | logger.Println("Connecting to UNIX socket", cmdLineEnv.endpoint[7:]) 65 | conn, err = net.Dial("unix", cmdLineEnv.endpoint[7:]) 66 | case "tcp": 67 | logger.Println("Connecting to TCP socket", u.Host) 68 | conn, err = net.Dial("tcp", u.Host) 69 | default: 70 | logger.Println("Unknown protocol or malformed address - check your endpoint") 71 | err = errors.New("protocol not supported") 72 | } 73 | } else { 74 | logger.Println("Connecting to TCP socket", u.Host) 75 | conn, err = net.Dial("tcp", cmdLineEnv.endpoint) 76 | } 77 | if err != nil { 78 | panic(err) 79 | } 80 | 81 | logger.Println("Connected") 82 | defer conn.Close() 83 | 84 | decoder := json.NewDecoder(conn) 85 | encoder := json.NewEncoder(conn) 86 | send := &admin.AdminSocketRequest{} 87 | recv := &admin.AdminSocketResponse{} 88 | args := map[string]string{} 89 | for c, a := range cmdLineEnv.args { 90 | if c == 0 { 91 | if strings.HasPrefix(a, "-") { 92 | logger.Printf("Ignoring flag %s as it should be specified before other parameters\n", a) 93 | continue 94 | } 95 | logger.Printf("Sending request: %v\n", a) 96 | send.Name = a 97 | continue 98 | } 99 | tokens := strings.SplitN(a, "=", 2) 100 | switch { 101 | case len(tokens) == 1: 102 | logger.Println("Ignoring invalid argument:", a) 103 | default: 104 | args[tokens[0]] = tokens[1] 105 | } 106 | } 107 | if send.Arguments, err = json.Marshal(args); err != nil { 108 | panic(err) 109 | } 110 | if err := encoder.Encode(&send); err != nil { 111 | panic(err) 112 | } 113 | logger.Printf("Request sent") 114 | if err := decoder.Decode(&recv); err != nil { 115 | panic(err) 116 | } 117 | if recv.Status == "error" { 118 | if err := recv.Error; err != "" { 119 | fmt.Println("Admin socket returned an error:", err) 120 | } else { 121 | fmt.Println("Admin socket returned an error but didn't specify any error text") 122 | } 123 | return 1 124 | } 125 | if cmdLineEnv.injson { 126 | if json, err := json.MarshalIndent(recv.Response, "", " "); err == nil { 127 | fmt.Println(string(json)) 128 | } 129 | return 0 130 | } 131 | 132 | table := tablewriter.NewWriter(os.Stdout) 133 | table.SetAlignment(tablewriter.ALIGN_LEFT) 134 | table.SetAutoFormatHeaders(false) 135 | table.SetCenterSeparator("") 136 | table.SetColumnSeparator("") 137 | table.SetRowSeparator("") 138 | table.SetHeaderLine(false) 139 | table.SetBorder(false) 140 | table.SetTablePadding("\t") // pad with tabs 141 | table.SetNoWhiteSpace(true) 142 | table.SetAutoWrapText(false) 143 | 144 | switch strings.ToLower(send.Name) { 145 | case "list": 146 | var resp admin.ListResponse 147 | if err := json.Unmarshal(recv.Response, &resp); err != nil { 148 | panic(err) 149 | } 150 | table.SetHeader([]string{"Command", "Arguments", "Description"}) 151 | for _, entry := range resp.List { 152 | for i := range entry.Fields { 153 | entry.Fields[i] = entry.Fields[i] + "=..." 154 | } 155 | table.Append([]string{entry.Command, strings.Join(entry.Fields, ", "), entry.Description}) 156 | } 157 | table.Render() 158 | 159 | case "getself": 160 | var resp admin.GetSelfResponse 161 | if err := json.Unmarshal(recv.Response, &resp); err != nil { 162 | panic(err) 163 | } 164 | table.Append([]string{"Build name:", resp.BuildName}) 165 | table.Append([]string{"Build version:", resp.BuildVersion}) 166 | table.Append([]string{"IPv6 address:", resp.IPAddress}) 167 | table.Append([]string{"IPv6 subnet:", resp.Subnet}) 168 | table.Append([]string{"Coordinates:", fmt.Sprintf("%v", resp.Coords)}) 169 | table.Append([]string{"Public key:", resp.PublicKey}) 170 | table.Render() 171 | 172 | case "getpeers": 173 | var resp admin.GetPeersResponse 174 | if err := json.Unmarshal(recv.Response, &resp); err != nil { 175 | panic(err) 176 | } 177 | table.SetHeader([]string{"Port", "Public Key", "IP Address", "Uptime", "RX", "TX", "Pr", "URI"}) 178 | for _, peer := range resp.Peers { 179 | table.Append([]string{ 180 | fmt.Sprintf("%d", peer.Port), 181 | peer.PublicKey, 182 | peer.IPAddress, 183 | (time.Duration(peer.Uptime) * time.Second).String(), 184 | peer.RXBytes.String(), 185 | peer.TXBytes.String(), 186 | fmt.Sprintf("%d", peer.Priority), 187 | peer.Remote, 188 | }) 189 | } 190 | table.Render() 191 | 192 | case "getdht": 193 | var resp admin.GetDHTResponse 194 | if err := json.Unmarshal(recv.Response, &resp); err != nil { 195 | panic(err) 196 | } 197 | table.SetHeader([]string{"Public Key", "IP Address", "Port", "Rest"}) 198 | for _, dht := range resp.DHT { 199 | table.Append([]string{ 200 | dht.PublicKey, 201 | dht.IPAddress, 202 | fmt.Sprintf("%d", dht.Port), 203 | fmt.Sprintf("%d", dht.Rest), 204 | }) 205 | } 206 | table.Render() 207 | 208 | case "getpaths": 209 | var resp admin.GetPathsResponse 210 | if err := json.Unmarshal(recv.Response, &resp); err != nil { 211 | panic(err) 212 | } 213 | table.SetHeader([]string{"Public Key", "IP Address", "Path"}) 214 | for _, p := range resp.Paths { 215 | table.Append([]string{ 216 | p.PublicKey, 217 | p.IPAddress, 218 | fmt.Sprintf("%v", p.Path), 219 | }) 220 | } 221 | table.Render() 222 | 223 | case "getsessions": 224 | var resp admin.GetSessionsResponse 225 | if err := json.Unmarshal(recv.Response, &resp); err != nil { 226 | panic(err) 227 | } 228 | table.SetHeader([]string{"Public Key", "IP Address", "Uptime", "RX", "TX"}) 229 | for _, p := range resp.Sessions { 230 | table.Append([]string{ 231 | p.PublicKey, 232 | p.IPAddress, 233 | (time.Duration(p.Uptime) * time.Second).String(), 234 | p.RXBytes.String(), 235 | p.TXBytes.String(), 236 | }) 237 | } 238 | table.Render() 239 | 240 | case "getnodeinfo": 241 | var resp core.GetNodeInfoResponse 242 | if err := json.Unmarshal(recv.Response, &resp); err != nil { 243 | panic(err) 244 | } 245 | for _, v := range resp { 246 | fmt.Println(string(v)) 247 | break 248 | } 249 | 250 | case "getmulticastinterfaces": 251 | var resp multicast.GetMulticastInterfacesResponse 252 | if err := json.Unmarshal(recv.Response, &resp); err != nil { 253 | panic(err) 254 | } 255 | table.SetHeader([]string{"Interface"}) 256 | for _, p := range resp.Interfaces { 257 | table.Append([]string{p}) 258 | } 259 | table.Render() 260 | 261 | case "gettun": 262 | var resp tun.GetTUNResponse 263 | if err := json.Unmarshal(recv.Response, &resp); err != nil { 264 | panic(err) 265 | } 266 | table.Append([]string{"TUN enabled:", fmt.Sprintf("%#v", resp.Enabled)}) 267 | if resp.Enabled { 268 | table.Append([]string{"Interface name:", resp.Name}) 269 | table.Append([]string{"Interface MTU:", fmt.Sprintf("%d", resp.MTU)}) 270 | } 271 | table.Render() 272 | 273 | case "addpeer", "removepeer": 274 | 275 | default: 276 | fmt.Println(string(recv.Response)) 277 | } 278 | 279 | return 0 280 | } 281 | -------------------------------------------------------------------------------- /contrib/ansible/genkeys.go: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | This file generates crypto keys for [ansible-yggdrasil](https://github.com/jcgruenhage/ansible-yggdrasil/) 4 | 5 | */ 6 | package main 7 | 8 | import ( 9 | "crypto/ed25519" 10 | "encoding/hex" 11 | "flag" 12 | "fmt" 13 | "net" 14 | "os" 15 | 16 | "github.com/cheggaaa/pb/v3" 17 | "github.com/yggdrasil-network/yggdrasil-go/src/address" 18 | ) 19 | 20 | var numHosts = flag.Int("hosts", 1, "number of host vars to generate") 21 | var keyTries = flag.Int("tries", 1000, "number of tries before taking the best keys") 22 | 23 | type keySet struct { 24 | priv []byte 25 | pub []byte 26 | ip string 27 | } 28 | 29 | func main() { 30 | flag.Parse() 31 | 32 | bar := pb.StartNew(*keyTries*2 + *numHosts) 33 | 34 | if *numHosts > *keyTries { 35 | println("Can't generate less keys than hosts.") 36 | return 37 | } 38 | 39 | var keys []keySet 40 | for i := 0; i < *numHosts+1; i++ { 41 | keys = append(keys, newKey()) 42 | bar.Increment() 43 | } 44 | keys = sortKeySetArray(keys) 45 | for i := 0; i < *keyTries-*numHosts-1; i++ { 46 | keys[0] = newKey() 47 | keys = bubbleUpTo(keys, 0) 48 | bar.Increment() 49 | } 50 | 51 | os.MkdirAll("host_vars", 0755) 52 | 53 | for i := 1; i <= *numHosts; i++ { 54 | os.MkdirAll(fmt.Sprintf("host_vars/%x", i), 0755) 55 | file, err := os.Create(fmt.Sprintf("host_vars/%x/vars", i)) 56 | if err != nil { 57 | return 58 | } 59 | defer file.Close() 60 | file.WriteString(fmt.Sprintf("yggdrasil_public_key: %v\n", hex.EncodeToString(keys[i].pub))) 61 | file.WriteString("yggdrasil_private_key: \"{{ vault_yggdrasil_private_key }}\"\n") 62 | file.WriteString(fmt.Sprintf("ansible_host: %v\n", keys[i].ip)) 63 | 64 | file, err = os.Create(fmt.Sprintf("host_vars/%x/vault", i)) 65 | if err != nil { 66 | return 67 | } 68 | defer file.Close() 69 | file.WriteString(fmt.Sprintf("vault_yggdrasil_private_key: %v\n", hex.EncodeToString(keys[i].priv))) 70 | bar.Increment() 71 | } 72 | bar.Finish() 73 | } 74 | 75 | func newKey() keySet { 76 | pub, priv, err := ed25519.GenerateKey(nil) 77 | if err != nil { 78 | panic(err) 79 | } 80 | ip := net.IP(address.AddrForKey(pub)[:]).String() 81 | return keySet{priv[:], pub[:], ip} 82 | } 83 | 84 | func isBetter(oldID, newID []byte) bool { 85 | for idx := range oldID { 86 | if newID[idx] < oldID[idx] { 87 | return true 88 | } 89 | if newID[idx] > oldID[idx] { 90 | return false 91 | } 92 | } 93 | return false 94 | } 95 | 96 | func sortKeySetArray(sets []keySet) []keySet { 97 | for i := 0; i < len(sets); i++ { 98 | sets = bubbleUpTo(sets, i) 99 | } 100 | return sets 101 | } 102 | 103 | func bubbleUpTo(sets []keySet, num int) []keySet { 104 | for i := 0; i < len(sets)-num-1; i++ { 105 | if isBetter(sets[i+1].pub, sets[i].pub) { 106 | var tmp = sets[i] 107 | sets[i] = sets[i+1] 108 | sets[i+1] = tmp 109 | } else { 110 | break 111 | } 112 | } 113 | return sets 114 | } 115 | -------------------------------------------------------------------------------- /contrib/apparmor/usr.bin.yggdrasil: -------------------------------------------------------------------------------- 1 | # Last Modified: Fri Oct 30 11:33:31 2020 2 | #include 3 | 4 | /usr/bin/yggdrasil { 5 | #include 6 | #include 7 | 8 | capability net_admin, 9 | capability net_raw, 10 | 11 | /dev/net/tun rw, 12 | /proc/sys/net/core/somaxconn r, 13 | /sys/kernel/mm/transparent_hugepage/hpage_pmd_size r, 14 | 15 | /etc/yggdrasil.conf rw, 16 | /run/yggdrasil.sock rw, 17 | } 18 | -------------------------------------------------------------------------------- /contrib/busybox-init/S42yggdrasil: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | CONFFILE="/etc/yggdrasil.conf" 4 | 5 | genconf() { 6 | /usr/bin/yggdrasil -genconf > "$1" 7 | return $? 8 | } 9 | 10 | probetun() { 11 | modprobe tun 12 | return $? 13 | } 14 | 15 | start() { 16 | if [ ! -f "$CONFFILE" ]; then 17 | printf 'Generating configuration file: ' 18 | if genconf "$CONFFILE"; then 19 | echo "OK" 20 | else 21 | echo "FAIL" 22 | return 1 23 | fi 24 | fi 25 | 26 | if [ ! -e /dev/net/tun ]; then 27 | printf 'Inserting TUN module: ' 28 | if probetun; then 29 | echo "OK" 30 | else 31 | echo "FAIL" 32 | return 1 33 | fi 34 | fi 35 | 36 | printf 'Starting yggdrasil: ' 37 | if start-stop-daemon -S -q -b -x /usr/bin/yggdrasil \ 38 | -- -useconffile "$CONFFILE"; then 39 | echo "OK" 40 | else 41 | echo "FAIL" 42 | fi 43 | } 44 | 45 | stop() { 46 | printf "Stopping yggdrasil: " 47 | if start-stop-daemon -K -q -x /usr/bin/yggdrasil; then 48 | echo "OK" 49 | else 50 | echo "FAIL" 51 | fi 52 | } 53 | 54 | reload() { 55 | printf "Reloading yggdrasil: " 56 | if start-stop-daemon -K -q -s HUP -x /usr/bin/yggdrasil; then 57 | echo "OK" 58 | else 59 | echo "FAIL" 60 | start 61 | fi 62 | } 63 | 64 | restart() { 65 | stop 66 | start 67 | } 68 | 69 | case "$1" in 70 | start|stop|restart|reload) 71 | "$1";; 72 | *) 73 | echo "Usage: $0 {start|stop|restart|reload}" 74 | exit 1 75 | esac 76 | 77 | exit 0 78 | -------------------------------------------------------------------------------- /contrib/deb/generate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This is a lazy script to create a .deb for Debian/Ubuntu. It installs 4 | # yggdrasil and enables it in systemd. You can give it the PKGARCH= argument 5 | # i.e. PKGARCH=i386 sh contrib/deb/generate.sh 6 | 7 | if [ `pwd` != `git rev-parse --show-toplevel` ] 8 | then 9 | echo "You should run this script from the top-level directory of the git repo" 10 | exit 1 11 | fi 12 | 13 | PKGBRANCH=$(basename `git name-rev --name-only HEAD`) 14 | PKGNAME=$(sh contrib/semver/name.sh) 15 | PKGVERSION=$(sh contrib/semver/version.sh --bare) 16 | PKGARCH=${PKGARCH-amd64} 17 | PKGFILE=$PKGNAME-$PKGVERSION-$PKGARCH.deb 18 | PKGREPLACES=yggdrasil 19 | 20 | if [ $PKGBRANCH = "master" ]; then 21 | PKGREPLACES=yggdrasil-develop 22 | fi 23 | 24 | if [ $PKGARCH = "amd64" ]; then GOARCH=amd64 GOOS=linux ./build 25 | elif [ $PKGARCH = "i386" ]; then GOARCH=386 GOOS=linux ./build 26 | elif [ $PKGARCH = "mipsel" ]; then GOARCH=mipsle GOOS=linux ./build 27 | elif [ $PKGARCH = "mips" ]; then GOARCH=mips64 GOOS=linux ./build 28 | elif [ $PKGARCH = "armhf" ]; then GOARCH=arm GOOS=linux GOARM=6 ./build 29 | elif [ $PKGARCH = "arm64" ]; then GOARCH=arm64 GOOS=linux ./build 30 | elif [ $PKGARCH = "armel" ]; then GOARCH=arm GOOS=linux GOARM=5 ./build 31 | else 32 | echo "Specify PKGARCH=amd64,i386,mips,mipsel,armhf,arm64,armel" 33 | exit 1 34 | fi 35 | 36 | echo "Building $PKGFILE" 37 | 38 | mkdir -p /tmp/$PKGNAME/ 39 | mkdir -p /tmp/$PKGNAME/debian/ 40 | mkdir -p /tmp/$PKGNAME/usr/bin/ 41 | mkdir -p /tmp/$PKGNAME/etc/systemd/system/ 42 | 43 | cat > /tmp/$PKGNAME/debian/changelog << EOF 44 | Please see https://github.com/yggdrasil-network/yggdrasil-go/ 45 | EOF 46 | echo 9 > /tmp/$PKGNAME/debian/compat 47 | cat > /tmp/$PKGNAME/debian/control << EOF 48 | Package: $PKGNAME 49 | Version: $PKGVERSION 50 | Section: contrib/net 51 | Priority: extra 52 | Architecture: $PKGARCH 53 | Replaces: $PKGREPLACES 54 | Conflicts: $PKGREPLACES 55 | Maintainer: Neil Alexander 56 | Description: Yggdrasil Network 57 | Yggdrasil is an early-stage implementation of a fully end-to-end encrypted IPv6 58 | network. It is lightweight, self-arranging, supported on multiple platforms and 59 | allows pretty much any IPv6-capable application to communicate securely with 60 | other Yggdrasil nodes. 61 | EOF 62 | cat > /tmp/$PKGNAME/debian/copyright << EOF 63 | Please see https://github.com/yggdrasil-network/yggdrasil-go/ 64 | EOF 65 | cat > /tmp/$PKGNAME/debian/docs << EOF 66 | Please see https://github.com/yggdrasil-network/yggdrasil-go/ 67 | EOF 68 | cat > /tmp/$PKGNAME/debian/install << EOF 69 | usr/bin/yggdrasil usr/bin 70 | usr/bin/yggdrasilctl usr/bin 71 | etc/systemd/system/*.service etc/systemd/system 72 | EOF 73 | cat > /tmp/$PKGNAME/debian/postinst << EOF 74 | #!/bin/sh 75 | 76 | if ! getent group yggdrasil 2>&1 > /dev/null; then 77 | groupadd --system --force yggdrasil || echo "Failed to create group 'yggdrasil' - please create it manually and reinstall" 78 | fi 79 | 80 | if [ -f /etc/yggdrasil.conf ]; 81 | then 82 | mkdir -p /var/backups 83 | echo "Backing up configuration file to /var/backups/yggdrasil.conf.`date +%Y%m%d`" 84 | cp /etc/yggdrasil.conf /var/backups/yggdrasil.conf.`date +%Y%m%d` 85 | echo "Normalising and updating /etc/yggdrasil.conf" 86 | /usr/bin/yggdrasil -useconf -normaliseconf < /var/backups/yggdrasil.conf.`date +%Y%m%d` > /etc/yggdrasil.conf 87 | chgrp yggdrasil /etc/yggdrasil.conf 88 | 89 | if command -v systemctl >/dev/null; then 90 | systemctl daemon-reload >/dev/null || true 91 | systemctl enable yggdrasil || true 92 | systemctl start yggdrasil || true 93 | fi 94 | else 95 | echo "Generating initial configuration file /etc/yggdrasil.conf" 96 | echo "Please familiarise yourself with this file before starting Yggdrasil" 97 | sh -c 'umask 0027 && /usr/bin/yggdrasil -genconf > /etc/yggdrasil.conf' 98 | chgrp yggdrasil /etc/yggdrasil.conf 99 | fi 100 | EOF 101 | cat > /tmp/$PKGNAME/debian/prerm << EOF 102 | #!/bin/sh 103 | if command -v systemctl >/dev/null; then 104 | if systemctl is-active --quiet yggdrasil; then 105 | systemctl stop yggdrasil || true 106 | fi 107 | systemctl disable yggdrasil || true 108 | fi 109 | EOF 110 | 111 | cp yggdrasil /tmp/$PKGNAME/usr/bin/ 112 | cp yggdrasilctl /tmp/$PKGNAME/usr/bin/ 113 | cp contrib/systemd/*.service /tmp/$PKGNAME/etc/systemd/system/ 114 | 115 | tar -czvf /tmp/$PKGNAME/data.tar.gz -C /tmp/$PKGNAME/ \ 116 | usr/bin/yggdrasil usr/bin/yggdrasilctl \ 117 | etc/systemd/system/yggdrasil.service \ 118 | etc/systemd/system/yggdrasil-default-config.service 119 | tar -czvf /tmp/$PKGNAME/control.tar.gz -C /tmp/$PKGNAME/debian . 120 | echo 2.0 > /tmp/$PKGNAME/debian-binary 121 | 122 | ar -r $PKGFILE \ 123 | /tmp/$PKGNAME/debian-binary \ 124 | /tmp/$PKGNAME/control.tar.gz \ 125 | /tmp/$PKGNAME/data.tar.gz 126 | 127 | rm -rf /tmp/$PKGNAME 128 | -------------------------------------------------------------------------------- /contrib/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.io/golang:alpine as builder 2 | 3 | COPY . /src 4 | WORKDIR /src 5 | 6 | ENV CGO_ENABLED=0 7 | 8 | RUN apk add git && ./build && go build -o /src/genkeys cmd/genkeys/main.go 9 | 10 | FROM docker.io/alpine 11 | 12 | COPY --from=builder /src/yggdrasil /usr/bin/yggdrasil 13 | COPY --from=builder /src/yggdrasilctl /usr/bin/yggdrasilctl 14 | COPY --from=builder /src/genkeys /usr/bin/genkeys 15 | COPY contrib/docker/entrypoint.sh /usr/bin/entrypoint.sh 16 | 17 | # RUN addgroup -g 1000 -S yggdrasil-network \ 18 | # && adduser -u 1000 -S -g 1000 --home /etc/yggdrasil-network yggdrasil-network 19 | # 20 | # USER yggdrasil-network 21 | # TODO: Make running unprivileged work 22 | 23 | VOLUME [ "/etc/yggdrasil-network" ] 24 | 25 | ENTRYPOINT [ "/usr/bin/entrypoint.sh" ] 26 | -------------------------------------------------------------------------------- /contrib/docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | set -e 4 | 5 | CONF_DIR="/etc/yggdrasil-network" 6 | 7 | if [ ! -f "$CONF_DIR/config.conf" ]; then 8 | echo "generate $CONF_DIR/config.conf" 9 | yggdrasil --genconf > "$CONF_DIR/config.conf" 10 | fi 11 | 12 | yggdrasil --useconf < "$CONF_DIR/config.conf" 13 | exit $? 14 | -------------------------------------------------------------------------------- /contrib/freebsd/yggdrasil: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Put the yggdrasil and yggdrasilctl binaries into /usr/local/bin 4 | # Then copy this script into /etc/rc.d/yggdrasil 5 | # Finally, run: 6 | # 1. chmod +x /etc/rc.d/yggdrasil /usr/local/bin/{yggdrasil,yggdrasilctl} 7 | # 2. echo "yggdrasil_enable=yes" >> /etc/rc.d 8 | # 3. service yggdrasil start 9 | # 10 | # PROVIDE: yggdrasil 11 | # REQUIRE: networking 12 | # KEYWORD: 13 | 14 | . /etc/rc.subr 15 | 16 | name="yggdrasil" 17 | rcvar="yggdrasil_enable" 18 | 19 | start_cmd="${name}_start" 20 | stop_cmd="${name}_stop" 21 | 22 | pidfile="/var/run/yggdrasil/${name}.pid" 23 | command="/usr/sbin/daemon" 24 | command_args="-P ${pidfile} -r -f ${yggdrasil_command}" 25 | 26 | yggdrasil_start() 27 | { 28 | test ! -x /usr/local/bin/yggdrasil && ( 29 | logger -s -t yggdrasil "Warning: /usr/local/bin/yggdrasil is missing or not executable" 30 | logger -s -t yggdrasil "Copy the yggdrasil binary into /usr/local/bin and then chmod +x /usr/local/bin/yggdrasil" 31 | return 1 32 | ) 33 | 34 | test ! -f /etc/yggdrasil.conf && ( 35 | logger -s -t yggdrasil "Generating new configuration file into /etc/yggdrasil.conf" 36 | /usr/local/bin/yggdrasil -genconf > /etc/yggdrasil.conf 37 | ) 38 | 39 | tap_path="$(cat /etc/yggdrasil.conf | egrep -o '/dev/tap[0-9]{1,2}$')" 40 | tap_name="$(echo -n ${tap_path} | tr -d '/dev/')" 41 | 42 | /sbin/ifconfig ${tap_name} >/dev/null 2>&1 || ( 43 | logger -s -t yggdrasil "Creating ${tap_name} adapter" 44 | /sbin/ifconfig ${tap_name} create || logger -s -t yggdrasil "Failed to create ${tap_name} adapter" 45 | ) 46 | 47 | test ! -d /var/run/yggdrasil && mkdir -p /var/run/yggdrasil 48 | 49 | logger -s -t yggdrasil "Starting yggdrasil" 50 | ${command} ${command_args} /usr/local/bin/yggdrasil -useconffile /etc/yggdrasil.conf \ 51 | 1>/var/log/yggdrasil.stdout.log \ 52 | 2>/var/log/yggdrasil.stderr.log & 53 | } 54 | 55 | yggdrasil_stop() 56 | { 57 | logger -s -t yggdrasil "Stopping yggdrasil" 58 | test -f /var/run/yggdrasil/${name}.pid && kill -TERM $(cat /var/run/yggdrasil/${name}.pid) 59 | 60 | tap_path="$(cat /etc/yggdrasil.conf | grep /dev/tap | egrep -o '/dev/.*$')" 61 | tap_name="$(echo -n ${tap_path} | tr -d '/dev/')" 62 | 63 | /sbin/ifconfig ${tap_name} >/dev/null 2>&1 && ( 64 | logger -s -t yggdrasil "Destroying ${tap_name} adapter" 65 | /sbin/ifconfig ${tap_name} destroy || logger -s -t yggdrasil "Failed to destroy ${tap_name} adapter" 66 | ) 67 | } 68 | 69 | load_rc_config $name 70 | : ${yggdrasil_enable:=no} 71 | 72 | run_rc_command "$1" 73 | -------------------------------------------------------------------------------- /contrib/logo/ygg-neilalexander.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 43 | 45 | 46 | 48 | image/svg+xml 49 | 51 | 52 | 53 | 54 | 55 | 60 | 65 | 71 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /contrib/macos/create-pkg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Check if xar and mkbom are available 4 | command -v xar >/dev/null 2>&1 || ( 5 | echo "Building xar" 6 | sudo apt-get install libxml2-dev libssl1.0-dev zlib1g-dev -y 7 | mkdir -p /tmp/xar && cd /tmp/xar 8 | git clone https://github.com/mackyle/xar && cd xar/xar 9 | (sh autogen.sh && make && sudo make install) || (echo "Failed to build xar"; exit 1) 10 | ) 11 | command -v mkbom >/dev/null 2>&1 || ( 12 | echo "Building mkbom" 13 | mkdir -p /tmp/mkbom && cd /tmp/mkbom 14 | git clone https://github.com/hogliux/bomutils && cd bomutils 15 | sudo make install || (echo "Failed to build mkbom"; exit 1) 16 | ) 17 | 18 | # Build Yggdrasil 19 | echo "running GO111MODULE=on GOOS=darwin GOARCH=${PKGARCH-amd64} ./build" 20 | GO111MODULE=on GOOS=darwin GOARCH=${PKGARCH-amd64} ./build 21 | 22 | # Check if we can find the files we need - they should 23 | # exist if you are running this script from the root of 24 | # the yggdrasil-go repo and you have ran ./build 25 | test -f yggdrasil || (echo "yggdrasil binary not found"; exit 1) 26 | test -f yggdrasilctl || (echo "yggdrasilctl binary not found"; exit 1) 27 | test -f contrib/macos/yggdrasil.plist || (echo "contrib/macos/yggdrasil.plist not found"; exit 1) 28 | test -f contrib/semver/version.sh || (echo "contrib/semver/version.sh not found"; exit 1) 29 | 30 | # Delete the pkgbuild folder if it already exists 31 | test -d pkgbuild && rm -rf pkgbuild 32 | 33 | # Create our folder structure 34 | mkdir -p pkgbuild/scripts 35 | mkdir -p pkgbuild/flat/base.pkg 36 | mkdir -p pkgbuild/flat/Resources/en.lproj 37 | mkdir -p pkgbuild/root/usr/local/bin 38 | mkdir -p pkgbuild/root/Library/LaunchDaemons 39 | 40 | # Copy package contents into the pkgbuild root 41 | cp yggdrasil pkgbuild/root/usr/local/bin 42 | cp yggdrasilctl pkgbuild/root/usr/local/bin 43 | cp contrib/macos/yggdrasil.plist pkgbuild/root/Library/LaunchDaemons 44 | 45 | # Create the postinstall script 46 | cat > pkgbuild/scripts/postinstall << EOF 47 | #!/bin/sh 48 | 49 | # Normalise the config if it exists, generate it if it doesn't 50 | if [ -f /etc/yggdrasil.conf ]; 51 | then 52 | mkdir -p /Library/Preferences/Yggdrasil 53 | echo "Backing up configuration file to /Library/Preferences/Yggdrasil/yggdrasil.conf.`date +%Y%m%d`" 54 | cp /etc/yggdrasil.conf /Library/Preferences/Yggdrasil/yggdrasil.conf.`date +%Y%m%d` 55 | echo "Normalising /etc/yggdrasil.conf" 56 | /usr/local/bin/yggdrasil -useconffile /Library/Preferences/Yggdrasil/yggdrasil.conf.`date +%Y%m%d` -normaliseconf > /etc/yggdrasil.conf 57 | else 58 | /usr/local/bin/yggdrasil -genconf > /etc/yggdrasil.conf 59 | fi 60 | 61 | # Unload existing Yggdrasil launchd service, if possible 62 | test -f /Library/LaunchDaemons/yggdrasil.plist && (launchctl unload /Library/LaunchDaemons/yggdrasil.plist || true) 63 | 64 | # Load Yggdrasil launchd service and start Yggdrasil 65 | launchctl load /Library/LaunchDaemons/yggdrasil.plist 66 | EOF 67 | 68 | # Set execution permissions 69 | chmod +x pkgbuild/scripts/postinstall 70 | chmod +x pkgbuild/root/usr/local/bin/yggdrasil 71 | chmod +x pkgbuild/root/usr/local/bin/yggdrasilctl 72 | 73 | # Pack payload and scripts 74 | ( cd pkgbuild/scripts && find . | cpio -o --format odc --owner 0:80 | gzip -c ) > pkgbuild/flat/base.pkg/Scripts 75 | ( cd pkgbuild/root && find . | cpio -o --format odc --owner 0:80 | gzip -c ) > pkgbuild/flat/base.pkg/Payload 76 | 77 | # Work out metadata for the package info 78 | PKGNAME=$(sh contrib/semver/name.sh) 79 | PKGVERSION=$(sh contrib/semver/version.sh --bare) 80 | PKGARCH=${PKGARCH-amd64} 81 | PAYLOADSIZE=$(( $(wc -c pkgbuild/flat/base.pkg/Payload | awk '{ print $1 }') / 1024 )) 82 | [ "$PKGARCH" = "amd64" ] && PKGHOSTARCH="x86_64" || PKGHOSTARCH=${PKGARCH} 83 | 84 | # Create the PackageInfo file 85 | cat > pkgbuild/flat/base.pkg/PackageInfo << EOF 86 | 87 | 88 | 89 | 90 | 91 | 92 | EOF 93 | 94 | # Create the BOM 95 | ( cd pkgbuild && mkbom root flat/base.pkg/Bom ) 96 | 97 | # Create the Distribution file 98 | cat > pkgbuild/flat/Distribution << EOF 99 | 100 | 101 | Yggdrasil (${PKGNAME}-${PKGVERSION}) 102 | 103 | 104 | 105 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | #base.pkg 123 | 124 | EOF 125 | 126 | # Finally pack the .pkg 127 | ( cd pkgbuild/flat && xar --compression none -cf "../../${PKGNAME}-${PKGVERSION}-macos-${PKGARCH}.pkg" * ) 128 | -------------------------------------------------------------------------------- /contrib/macos/yggdrasil.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Label 6 | yggdrasil 7 | ProgramArguments 8 | 9 | sh 10 | -c 11 | /usr/local/bin/yggdrasil -useconffile /etc/yggdrasil.conf 12 | 13 | KeepAlive 14 | 15 | RunAtLoad 16 | 17 | ProcessType 18 | Interactive 19 | StandardOutPath 20 | /tmp/yggdrasil.stdout.log 21 | StandardErrorPath 22 | /tmp/yggdrasil.stderr.log 23 | 24 | 25 | -------------------------------------------------------------------------------- /contrib/mobile/build: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -ef 4 | 5 | [ ! -d contrib/mobile ] && (echo "Must run ./contrib/mobile/build [-i] [-a] from the repository top level folder"; exit 1) 6 | 7 | PKGSRC=${PKGSRC:-github.com/yggdrasil-network/yggdrasil-go/src/version} 8 | PKGNAME=${PKGNAME:-$(sh contrib/semver/name.sh)} 9 | PKGVER=${PKGVER:-$(sh contrib/semver/version.sh --bare)} 10 | 11 | LDFLAGS="-X $PKGSRC.buildName=$PKGNAME -X $PKGSRC.buildVersion=$PKGVER" 12 | ARGS="-v" 13 | 14 | while getopts "aitc:l:d" option 15 | do 16 | case "$option" 17 | in 18 | i) IOS=true;; 19 | a) ANDROID=true;; 20 | t) TABLES=true;; 21 | c) GCFLAGS="$GCFLAGS $OPTARG";; 22 | l) LDFLAGS="$LDFLAGS $OPTARG";; 23 | d) ARGS="$ARGS -tags debug" DEBUG=true;; 24 | esac 25 | done 26 | 27 | if [ -z $TABLES ] && [ -z $DEBUG ]; then 28 | LDFLAGS="$LDFLAGS -s -w" 29 | fi 30 | 31 | if [ ! $IOS ] && [ ! $ANDROID ]; then 32 | echo "Must specify -a (Android), -i (iOS) or both" 33 | exit 1 34 | fi 35 | 36 | if [ $IOS ]; then 37 | echo "Building framework for iOS" 38 | go get golang.org/x/mobile/bind 39 | gomobile bind \ 40 | -target ios -tags mobile -o Yggdrasil.xcframework \ 41 | -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" \ 42 | ./contrib/mobile ./src/config; 43 | fi 44 | 45 | if [ $ANDROID ]; then 46 | echo "Building aar for Android" 47 | go get golang.org/x/mobile/bind 48 | gomobile bind \ 49 | -target android -tags mobile -o yggdrasil.aar \ 50 | -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" \ 51 | ./contrib/mobile ./src/config; 52 | fi 53 | -------------------------------------------------------------------------------- /contrib/mobile/mobile.go: -------------------------------------------------------------------------------- 1 | package mobile 2 | 3 | import ( 4 | "encoding/hex" 5 | "encoding/json" 6 | "fmt" 7 | "net" 8 | "regexp" 9 | 10 | "github.com/gologme/log" 11 | 12 | "github.com/yggdrasil-network/yggdrasil-go/src/address" 13 | "github.com/yggdrasil-network/yggdrasil-go/src/config" 14 | "github.com/yggdrasil-network/yggdrasil-go/src/core" 15 | "github.com/yggdrasil-network/yggdrasil-go/src/defaults" 16 | "github.com/yggdrasil-network/yggdrasil-go/src/ipv6rwc" 17 | "github.com/yggdrasil-network/yggdrasil-go/src/multicast" 18 | "github.com/yggdrasil-network/yggdrasil-go/src/version" 19 | 20 | _ "golang.org/x/mobile/bind" 21 | ) 22 | 23 | // Yggdrasil mobile package is meant to "plug the gap" for mobile support, as 24 | // Gomobile will not create headers for Swift/Obj-C etc if they have complex 25 | // (non-native) types. Therefore for iOS we will expose some nice simple 26 | // functions. Note that in the case of iOS we handle reading/writing to/from TUN 27 | // in Swift therefore we use the "dummy" TUN interface instead. 28 | type Yggdrasil struct { 29 | core *core.Core 30 | iprwc *ipv6rwc.ReadWriteCloser 31 | config *config.NodeConfig 32 | multicast *multicast.Multicast 33 | log MobileLogger 34 | } 35 | 36 | // StartAutoconfigure starts a node with a randomly generated config 37 | func (m *Yggdrasil) StartAutoconfigure() error { 38 | return m.StartJSON([]byte("{}")) 39 | } 40 | 41 | // StartJSON starts a node with the given JSON config. You can get JSON config 42 | // (rather than HJSON) by using the GenerateConfigJSON() function 43 | func (m *Yggdrasil) StartJSON(configjson []byte) error { 44 | logger := log.New(m.log, "", 0) 45 | logger.EnableLevel("error") 46 | logger.EnableLevel("warn") 47 | logger.EnableLevel("info") 48 | m.config = defaults.GenerateConfig() 49 | if err := json.Unmarshal(configjson, &m.config); err != nil { 50 | return err 51 | } 52 | // Setup the Yggdrasil node itself. 53 | { 54 | sk, err := hex.DecodeString(m.config.PrivateKey) 55 | if err != nil { 56 | panic(err) 57 | } 58 | options := []core.SetupOption{} 59 | for _, peer := range m.config.Peers { 60 | options = append(options, core.Peer{URI: peer}) 61 | } 62 | for intf, peers := range m.config.InterfacePeers { 63 | for _, peer := range peers { 64 | options = append(options, core.Peer{URI: peer, SourceInterface: intf}) 65 | } 66 | } 67 | for _, allowed := range m.config.AllowedPublicKeys { 68 | k, err := hex.DecodeString(allowed) 69 | if err != nil { 70 | panic(err) 71 | } 72 | options = append(options, core.AllowedPublicKey(k[:])) 73 | } 74 | m.core, err = core.New(sk[:], logger, options...) 75 | if err != nil { 76 | panic(err) 77 | } 78 | } 79 | 80 | // Setup the multicast module. 81 | if len(m.config.MulticastInterfaces) > 0 { 82 | var err error 83 | options := []multicast.SetupOption{} 84 | for _, intf := range m.config.MulticastInterfaces { 85 | options = append(options, multicast.MulticastInterface{ 86 | Regex: regexp.MustCompile(intf.Regex), 87 | Beacon: intf.Beacon, 88 | Listen: intf.Listen, 89 | Port: intf.Port, 90 | Priority: intf.Priority, 91 | }) 92 | } 93 | m.multicast, err = multicast.New(m.core, logger, options...) 94 | if err != nil { 95 | logger.Errorln("An error occurred starting multicast:", err) 96 | } 97 | } 98 | 99 | mtu := m.config.IfMTU 100 | m.iprwc = ipv6rwc.NewReadWriteCloser(m.core) 101 | if m.iprwc.MaxMTU() < mtu { 102 | mtu = m.iprwc.MaxMTU() 103 | } 104 | m.iprwc.SetMTU(mtu) 105 | return nil 106 | } 107 | 108 | // Send sends a packet to Yggdrasil. It should be a fully formed 109 | // IPv6 packet 110 | func (m *Yggdrasil) Send(p []byte) error { 111 | if m.iprwc == nil { 112 | return nil 113 | } 114 | _, _ = m.iprwc.Write(p) 115 | return nil 116 | } 117 | 118 | // Recv waits for and reads a packet coming from Yggdrasil. It 119 | // will be a fully formed IPv6 packet 120 | func (m *Yggdrasil) Recv() ([]byte, error) { 121 | if m.iprwc == nil { 122 | return nil, nil 123 | } 124 | var buf [65535]byte 125 | n, _ := m.iprwc.Read(buf[:]) 126 | return buf[:n], nil 127 | } 128 | 129 | // Stop the mobile Yggdrasil instance 130 | func (m *Yggdrasil) Stop() error { 131 | logger := log.New(m.log, "", 0) 132 | logger.EnableLevel("info") 133 | logger.Infof("Stop the mobile Yggdrasil instance %s", "") 134 | if err := m.multicast.Stop(); err != nil { 135 | return err 136 | } 137 | m.core.Stop() 138 | return nil 139 | } 140 | 141 | // GenerateConfigJSON generates mobile-friendly configuration in JSON format 142 | func GenerateConfigJSON() []byte { 143 | nc := defaults.GenerateConfig() 144 | nc.IfName = "none" 145 | if json, err := json.Marshal(nc); err == nil { 146 | return json 147 | } 148 | return nil 149 | } 150 | 151 | // GetAddressString gets the node's IPv6 address 152 | func (m *Yggdrasil) GetAddressString() string { 153 | ip := m.core.Address() 154 | return ip.String() 155 | } 156 | 157 | // GetSubnetString gets the node's IPv6 subnet in CIDR notation 158 | func (m *Yggdrasil) GetSubnetString() string { 159 | subnet := m.core.Subnet() 160 | return subnet.String() 161 | } 162 | 163 | // GetPublicKeyString gets the node's public key in hex form 164 | func (m *Yggdrasil) GetPublicKeyString() string { 165 | return hex.EncodeToString(m.core.GetSelf().Key) 166 | } 167 | 168 | // GetCoordsString gets the node's coordinates 169 | func (m *Yggdrasil) GetCoordsString() string { 170 | return fmt.Sprintf("%v", m.core.GetSelf().Coords) 171 | } 172 | 173 | func (m *Yggdrasil) GetPeersJSON() (result string) { 174 | peers := []struct { 175 | core.PeerInfo 176 | IP string 177 | }{} 178 | for _, v := range m.core.GetPeers() { 179 | a := address.AddrForKey(v.Key) 180 | ip := net.IP(a[:]).String() 181 | peers = append(peers, struct { 182 | core.PeerInfo 183 | IP string 184 | }{ 185 | PeerInfo: v, 186 | IP: ip, 187 | }) 188 | } 189 | if res, err := json.Marshal(peers); err == nil { 190 | return string(res) 191 | } else { 192 | return "{}" 193 | } 194 | } 195 | 196 | func (m *Yggdrasil) GetDHTJSON() (result string) { 197 | if res, err := json.Marshal(m.core.GetDHT()); err == nil { 198 | return string(res) 199 | } else { 200 | return "{}" 201 | } 202 | } 203 | 204 | // GetMTU returns the configured node MTU. This must be called AFTER Start. 205 | func (m *Yggdrasil) GetMTU() int { 206 | return int(m.core.MTU()) 207 | } 208 | 209 | func GetVersion() string { 210 | return version.BuildVersion() 211 | } 212 | -------------------------------------------------------------------------------- /contrib/mobile/mobile_android.go: -------------------------------------------------------------------------------- 1 | //go:build android 2 | // +build android 3 | 4 | package mobile 5 | 6 | import "log" 7 | 8 | type MobileLogger struct{} 9 | 10 | func (nsl MobileLogger) Write(p []byte) (n int, err error) { 11 | log.Println(string(p)) 12 | return len(p), nil 13 | } 14 | -------------------------------------------------------------------------------- /contrib/mobile/mobile_ios.go: -------------------------------------------------------------------------------- 1 | //go:build ios 2 | // +build ios 3 | 4 | package mobile 5 | 6 | /* 7 | #cgo CFLAGS: -x objective-c 8 | #cgo LDFLAGS: -framework Foundation 9 | #import 10 | void Log(const char *text) { 11 | NSString *nss = [NSString stringWithUTF8String:text]; 12 | NSLog(@"%@", nss); 13 | } 14 | */ 15 | import "C" 16 | import ( 17 | "unsafe" 18 | ) 19 | 20 | type MobileLogger struct { 21 | } 22 | 23 | func (nsl MobileLogger) Write(p []byte) (n int, err error) { 24 | p = append(p, 0) 25 | cstr := (*C.char)(unsafe.Pointer(&p[0])) 26 | C.Log(cstr) 27 | return len(p), nil 28 | } 29 | -------------------------------------------------------------------------------- /contrib/mobile/mobile_other.go: -------------------------------------------------------------------------------- 1 | //go:build !android && !ios 2 | // +build !android,!ios 3 | 4 | package mobile 5 | 6 | import "fmt" 7 | 8 | type MobileLogger struct { 9 | } 10 | 11 | func (nsl MobileLogger) Write(p []byte) (n int, err error) { 12 | fmt.Print(string(p)) 13 | return len(p), nil 14 | } 15 | -------------------------------------------------------------------------------- /contrib/mobile/mobile_test.go: -------------------------------------------------------------------------------- 1 | package mobile 2 | 3 | import "testing" 4 | 5 | func TestStartYggdrasil(t *testing.T) { 6 | ygg := &Yggdrasil{} 7 | if err := ygg.StartAutoconfigure(); err != nil { 8 | t.Fatalf("Failed to start Yggdrasil: %s", err) 9 | } 10 | t.Log("Address:", ygg.GetAddressString()) 11 | t.Log("Subnet:", ygg.GetSubnetString()) 12 | t.Log("Coords:", ygg.GetCoordsString()) 13 | if err := ygg.Stop(); err != nil { 14 | t.Fatalf("Failed to stop Yggdrasil: %s", err) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /contrib/msi/build-msi.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script generates an MSI file for Yggdrasil for a given architecture. It 4 | # needs to run on Windows within MSYS2 and Go 1.17 or later must be installed on 5 | # the system and within the PATH. This is ran currently by GitHub Actions (see 6 | # the workflows in the repository). 7 | # 8 | # Author: Neil Alexander 9 | 10 | # Get arch from command line if given 11 | PKGARCH=$1 12 | if [ "${PKGARCH}" == "" ]; 13 | then 14 | echo "tell me the architecture: x86, x64, arm or arm64" 15 | exit 1 16 | fi 17 | 18 | # Download the wix tools! 19 | if [ ! -d wixbin ]; 20 | then 21 | curl -LO https://wixtoolset.org/downloads/v3.14.0.3910/wix314-binaries.zip 22 | if [ `md5sum wix314-binaries.zip | cut -f 1 -d " "` != "34f655cf108086838dd5a76d4318063b" ]; 23 | then 24 | echo "wix package didn't match expected checksum" 25 | exit 1 26 | fi 27 | mkdir -p wixbin 28 | unzip -o wix314-binaries.zip -d wixbin || ( 29 | echo "failed to unzip WiX" 30 | exit 1 31 | ) 32 | fi 33 | 34 | # Build Yggdrasil! 35 | [ "${PKGARCH}" == "x64" ] && GOOS=windows GOARCH=amd64 CGO_ENABLED=0 ./build 36 | [ "${PKGARCH}" == "x86" ] && GOOS=windows GOARCH=386 CGO_ENABLED=0 ./build 37 | [ "${PKGARCH}" == "arm" ] && GOOS=windows GOARCH=arm CGO_ENABLED=0 ./build 38 | [ "${PKGARCH}" == "arm64" ] && GOOS=windows GOARCH=arm64 CGO_ENABLED=0 ./build 39 | 40 | # Create the postinstall script 41 | cat > updateconfig.bat << EOF 42 | if not exist %ALLUSERSPROFILE%\\Yggdrasil ( 43 | mkdir %ALLUSERSPROFILE%\\Yggdrasil 44 | ) 45 | if not exist %ALLUSERSPROFILE%\\Yggdrasil\\yggdrasil.conf ( 46 | if exist yggdrasil.exe ( 47 | yggdrasil.exe -genconf > %ALLUSERSPROFILE%\\Yggdrasil\\yggdrasil.conf 48 | ) 49 | ) 50 | EOF 51 | 52 | # Work out metadata for the package info 53 | PKGNAME=$(sh contrib/semver/name.sh) 54 | PKGVERSION=$(sh contrib/msi/msversion.sh --bare) 55 | PKGVERSIONMS=$(echo $PKGVERSION | tr - .) 56 | ([ "${PKGARCH}" == "x64" ] || [ "${PKGARCH}" == "arm64" ]) && \ 57 | PKGGUID="77757838-1a23-40a5-a720-c3b43e0260cc" PKGINSTFOLDER="ProgramFiles64Folder" || \ 58 | PKGGUID="54a3294e-a441-4322-aefb-3bb40dd022bb" PKGINSTFOLDER="ProgramFilesFolder" 59 | 60 | # Download the Wintun driver 61 | if [ ! -d wintun ]; 62 | then 63 | curl -o wintun.zip https://www.wintun.net/builds/wintun-0.14.1.zip 64 | unzip wintun.zip 65 | fi 66 | if [ $PKGARCH = "x64" ]; then 67 | PKGWINTUNDLL=wintun/bin/amd64/wintun.dll 68 | elif [ $PKGARCH = "x86" ]; then 69 | PKGWINTUNDLL=wintun/bin/x86/wintun.dll 70 | elif [ $PKGARCH = "arm" ]; then 71 | PKGWINTUNDLL=wintun/bin/arm/wintun.dll 72 | elif [ $PKGARCH = "arm64" ]; then 73 | PKGWINTUNDLL=wintun/bin/arm64/wintun.dll 74 | else 75 | echo "wasn't sure which architecture to get wintun for" 76 | exit 1 77 | fi 78 | 79 | if [ $PKGNAME != "master" ]; then 80 | PKGDISPLAYNAME="Yggdrasil Network (${PKGNAME} branch)" 81 | else 82 | PKGDISPLAYNAME="Yggdrasil Network" 83 | fi 84 | 85 | # Generate the wix.xml file 86 | cat > wix.xml << EOF 87 | 88 | 89 | 97 | 98 | 109 | 110 | 112 | 113 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 130 | 131 | 136 | 137 | 149 | 150 | 156 | 157 | 158 | 159 | 165 | 166 | 167 | 168 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 192 | 193 | 194 | 197 | NOT Installed AND NOT REMOVE 198 | 199 | 200 | 201 | 202 | 203 | EOF 204 | 205 | # Generate the MSI 206 | CANDLEFLAGS="-nologo" 207 | LIGHTFLAGS="-nologo -spdb -sice:ICE71 -sice:ICE61" 208 | wixbin/candle $CANDLEFLAGS -out ${PKGNAME}-${PKGVERSION}-${PKGARCH}.wixobj -arch ${PKGARCH} wix.xml && \ 209 | wixbin/light $LIGHTFLAGS -ext WixUtilExtension.dll -out ${PKGNAME}-${PKGVERSION}-${PKGARCH}.msi ${PKGNAME}-${PKGVERSION}-${PKGARCH}.wixobj 210 | -------------------------------------------------------------------------------- /contrib/msi/msversion.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Get the last tag 4 | TAG=$(git describe --abbrev=0 --tags --match="v[0-9]*\.[0-9]*\.[0-9]*" 2>/dev/null) 5 | 6 | # Did getting the tag succeed? 7 | if [ $? != 0 ] || [ -z "$TAG" ]; then 8 | printf -- "unknown" 9 | exit 0 10 | fi 11 | 12 | # Get the current branch 13 | BRANCH=$(git symbolic-ref -q HEAD --short 2>/dev/null) 14 | 15 | # Did getting the branch succeed? 16 | if [ $? != 0 ] || [ -z "$BRANCH" ]; then 17 | BRANCH="master" 18 | fi 19 | 20 | # Split out into major, minor and patch numbers 21 | MAJOR=$(echo $TAG | cut -c 2- | cut -d "." -f 1) 22 | MINOR=$(echo $TAG | cut -c 2- | cut -d "." -f 2) 23 | PATCH=$(echo $TAG | cut -c 2- | cut -d "." -f 3 | awk -F"rc" '{print $1}') 24 | 25 | # Output in the desired format 26 | if [ $((PATCH)) -eq 0 ]; then 27 | printf '%s%d.%d' "$PREPEND" "$((MAJOR))" "$((MINOR))" 28 | else 29 | printf '%s%d.%d.%d' "$PREPEND" "$((MAJOR))" "$((MINOR))" "$((PATCH))" 30 | fi 31 | 32 | # Add the build tag on non-master branches 33 | if [ "$BRANCH" != "master" ]; then 34 | BUILD=$(git rev-list --count $TAG..HEAD 2>/dev/null) 35 | 36 | # Did getting the count of commits since the tag succeed? 37 | if [ $? != 0 ] || [ -z "$BUILD" ]; then 38 | printf -- "-unknown" 39 | exit 0 40 | fi 41 | 42 | # Is the build greater than zero? 43 | if [ $((BUILD)) -gt 0 ]; then 44 | printf -- "-%04d" "$((BUILD))" 45 | fi 46 | fi -------------------------------------------------------------------------------- /contrib/openrc/yggdrasil: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | 3 | description="An experiment in scalable routing as an encrypted IPv6 overlay network." 4 | 5 | CONFFILE="/etc/yggdrasil.conf" 6 | pidfile="/run/${RC_SVCNAME}.pid" 7 | 8 | command="/usr/bin/yggdrasil" 9 | extra_started_commands="reload" 10 | 11 | depend() { 12 | use net dns logger 13 | } 14 | 15 | start_pre() { 16 | if [ ! -f "${CONFFILE}" ]; then 17 | ebegin "Generating new configuration file into ${CONFFILE}" 18 | if ! eval ${command} -genconf > ${CONFFILE}; then 19 | eerror "Failed to generate configuration file" 20 | exit 1 21 | fi 22 | fi 23 | 24 | if [ ! -e /dev/net/tun ]; then 25 | ebegin "Inserting TUN module" 26 | if ! modprobe tun; then 27 | eerror "Failed to insert TUN kernel module" 28 | exit 1 29 | fi 30 | fi 31 | } 32 | 33 | start() { 34 | ebegin "Starting ${RC_SVCNAME}" 35 | start-stop-daemon --start --quiet \ 36 | --pidfile "${pidfile}" \ 37 | --make-pidfile \ 38 | --background \ 39 | --stdout /var/log/yggdrasil.stdout.log \ 40 | --stderr /var/log/yggdrasil.stderr.log \ 41 | --exec "${command}" -- -useconffile "${CONFFILE}" 42 | eend $? 43 | } 44 | 45 | reload() { 46 | ebegin "Reloading ${RC_SVCNAME}" 47 | start-stop-daemon --signal HUP --pidfile "${pidfile}" 48 | eend $? 49 | } 50 | 51 | stop() { 52 | ebegin "Stopping ${RC_SVCNAME}" 53 | start-stop-daemon --stop --pidfile "${pidfile}" --exec "${command}" 54 | eend $? 55 | } 56 | -------------------------------------------------------------------------------- /contrib/semver/name.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Get the current branch name 4 | BRANCH="$GITHUB_REF_NAME" 5 | if [ -z "$BRANCH" ]; then 6 | BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null) 7 | fi 8 | 9 | if [ $? != 0 ] || [ -z "$BRANCH" ]; then 10 | printf "yggdrasil" 11 | exit 0 12 | fi 13 | 14 | # Remove "/" characters from the branch name if present 15 | BRANCH=$(echo $BRANCH | tr -d "/") 16 | 17 | # Check if the branch name is not master 18 | if [ "$BRANCH" = "master" ]; then 19 | printf "yggdrasil" 20 | exit 0 21 | fi 22 | 23 | # If it is something other than master, append it 24 | printf "yggdrasil-%s" "$BRANCH" 25 | -------------------------------------------------------------------------------- /contrib/semver/version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | case "$*" in 4 | *--bare*) 5 | # Remove the "v" prefix 6 | git describe --tags --match="v[0-9]*\.[0-9]*\.[0-9]*" | cut -c 2- 7 | ;; 8 | *) 9 | git describe --tags --match="v[0-9]*\.[0-9]*\.[0-9]*" 10 | ;; 11 | esac 12 | -------------------------------------------------------------------------------- /contrib/systemd/yggdrasil-default-config.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=yggdrasil default config generator 3 | ConditionPathExists=|!/etc/yggdrasil.conf 4 | ConditionFileNotEmpty=|!/etc/yggdrasil.conf 5 | Wants=local-fs.target 6 | After=local-fs.target 7 | 8 | [Service] 9 | Type=oneshot 10 | Group=yggdrasil 11 | StandardOutput=file:/etc/yggdrasil.conf 12 | ExecStart=/usr/bin/yggdrasil -genconf 13 | ExecStartPost=/usr/bin/chmod 0640 /etc/yggdrasil.conf 14 | -------------------------------------------------------------------------------- /contrib/systemd/yggdrasil.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=yggdrasil 3 | Wants=network-online.target 4 | Wants=yggdrasil-default-config.service 5 | After=network-online.target 6 | After=yggdrasil-default-config.service 7 | 8 | [Service] 9 | Group=yggdrasil 10 | ProtectHome=true 11 | ProtectSystem=true 12 | SyslogIdentifier=yggdrasil 13 | CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE 14 | ExecStartPre=+-/sbin/modprobe tun 15 | ExecStart=/usr/bin/yggdrasil -useconffile /etc/yggdrasil.conf 16 | ExecReload=/bin/kill -HUP $MAINPID 17 | Restart=always 18 | TimeoutStopSec=5 19 | 20 | [Install] 21 | WantedBy=multi-user.target 22 | -------------------------------------------------------------------------------- /contrib/yggdrasil-brute-simple/LICENSE: -------------------------------------------------------------------------------- 1 | This software is released into the public domain. As such, it can be 2 | used under the Unlicense or CC0 public domain dedications. 3 | 4 | 5 | 6 | The Unlicense 7 | 8 | This is free and unencumbered software released into the public domain. 9 | 10 | Anyone is free to copy, modify, publish, use, compile, sell, or 11 | distribute this software, either in source code form or as a compiled 12 | binary, for any purpose, commercial or non-commercial, and by any 13 | means. 14 | 15 | In jurisdictions that recognize copyright laws, the author or authors 16 | of this software dedicate any and all copyright interest in the 17 | software to the public domain. We make this dedication for the benefit 18 | of the public at large and to the detriment of our heirs and 19 | successors. We intend this dedication to be an overt act of 20 | relinquishment in perpetuity of all present and future rights to this 21 | software under copyright law. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 26 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 27 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 28 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 29 | OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | For more information, please refer to 32 | 33 | 34 | 35 | CC0 1.0 Universal 36 | 37 | Statement of Purpose 38 | 39 | The laws of most jurisdictions throughout the world automatically confer 40 | exclusive Copyright and Related Rights (defined below) upon the creator and 41 | subsequent owner(s) (each and all, an "owner") of an original work of 42 | authorship and/or a database (each, a "Work"). 43 | 44 | Certain owners wish to permanently relinquish those rights to a Work for the 45 | purpose of contributing to a commons of creative, cultural and scientific 46 | works ("Commons") that the public can reliably and without fear of later 47 | claims of infringement build upon, modify, incorporate in other works, reuse 48 | and redistribute as freely as possible in any form whatsoever and for any 49 | purposes, including without limitation commercial purposes. These owners may 50 | contribute to the Commons to promote the ideal of a free culture and the 51 | further production of creative, cultural and scientific works, or to gain 52 | reputation or greater distribution for their Work in part through the use and 53 | efforts of others. 54 | 55 | For these and/or other purposes and motivations, and without any expectation 56 | of additional consideration or compensation, the person associating CC0 with a 57 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 58 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 59 | and publicly distribute the Work under its terms, with knowledge of his or her 60 | Copyright and Related Rights in the Work and the meaning and intended legal 61 | effect of CC0 on those rights. 62 | 63 | 1. Copyright and Related Rights. A Work made available under CC0 may be 64 | protected by copyright and related or neighboring rights ("Copyright and 65 | Related Rights"). Copyright and Related Rights include, but are not limited 66 | to, the following: 67 | 68 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 69 | and translate a Work; 70 | 71 | ii. moral rights retained by the original author(s) and/or performer(s); 72 | 73 | iii. publicity and privacy rights pertaining to a person's image or likeness 74 | depicted in a Work; 75 | 76 | iv. rights protecting against unfair competition in regards to a Work, 77 | subject to the limitations in paragraph 4(a), below; 78 | 79 | v. rights protecting the extraction, dissemination, use and reuse of data in 80 | a Work; 81 | 82 | vi. database rights (such as those arising under Directive 96/9/EC of the 83 | European Parliament and of the Council of 11 March 1996 on the legal 84 | protection of databases, and under any national implementation thereof, 85 | including any amended or successor version of such directive); and 86 | 87 | vii. other similar, equivalent or corresponding rights throughout the world 88 | based on applicable law or treaty, and any national implementations thereof. 89 | 90 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 91 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 92 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 93 | and Related Rights and associated claims and causes of action, whether now 94 | known or unknown (including existing as well as future claims and causes of 95 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 96 | duration provided by applicable law or treaty (including future time 97 | extensions), (iii) in any current or future medium and for any number of 98 | copies, and (iv) for any purpose whatsoever, including without limitation 99 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 100 | the Waiver for the benefit of each member of the public at large and to the 101 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 102 | shall not be subject to revocation, rescission, cancellation, termination, or 103 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 104 | by the public as contemplated by Affirmer's express Statement of Purpose. 105 | 106 | 3. Public License Fallback. Should any part of the Waiver for any reason be 107 | judged legally invalid or ineffective under applicable law, then the Waiver 108 | shall be preserved to the maximum extent permitted taking into account 109 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 110 | is so judged Affirmer hereby grants to each affected person a royalty-free, 111 | non transferable, non sublicensable, non exclusive, irrevocable and 112 | unconditional license to exercise Affirmer's Copyright and Related Rights in 113 | the Work (i) in all territories worldwide, (ii) for the maximum duration 114 | provided by applicable law or treaty (including future time extensions), (iii) 115 | in any current or future medium and for any number of copies, and (iv) for any 116 | purpose whatsoever, including without limitation commercial, advertising or 117 | promotional purposes (the "License"). The License shall be deemed effective as 118 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 119 | License for any reason be judged legally invalid or ineffective under 120 | applicable law, such partial invalidity or ineffectiveness shall not 121 | invalidate the remainder of the License, and in such case Affirmer hereby 122 | affirms that he or she will not (i) exercise any of his or her remaining 123 | Copyright and Related Rights in the Work or (ii) assert any associated claims 124 | and causes of action with respect to the Work, in either case contrary to 125 | Affirmer's express Statement of Purpose. 126 | 127 | 4. Limitations and Disclaimers. 128 | 129 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 130 | surrendered, licensed or otherwise affected by this document. 131 | 132 | b. Affirmer offers the Work as-is and makes no representations or warranties 133 | of any kind concerning the Work, express, implied, statutory or otherwise, 134 | including without limitation warranties of title, merchantability, fitness 135 | for a particular purpose, non infringement, or the absence of latent or 136 | other defects, accuracy, or the present or absence of errors, whether or not 137 | discoverable, all to the greatest extent permissible under applicable law. 138 | 139 | c. Affirmer disclaims responsibility for clearing rights of other persons 140 | that may apply to the Work or any use thereof, including without limitation 141 | any person's Copyright and Related Rights in the Work. Further, Affirmer 142 | disclaims responsibility for obtaining any necessary consents, permissions 143 | or other rights required for any use of the Work. 144 | 145 | d. Affirmer understands and acknowledges that Creative Commons is not a 146 | party to this document and has no duty or obligation with respect to this 147 | CC0 or use of the Work. 148 | 149 | For more information, please see 150 | 151 | -------------------------------------------------------------------------------- /contrib/yggdrasil-brute-simple/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | 3 | all: util yggdrasil-brute-multi-curve25519 yggdrasil-brute-multi-ed25519 4 | 5 | util: util.c 6 | gcc -Wall -std=c89 -O3 -c -o util.o util.c 7 | 8 | yggdrasil-brute-multi-ed25519: yggdrasil-brute-multi-ed25519.c util.o 9 | gcc -Wall -std=c89 -O3 -o yggdrasil-brute-multi-ed25519 -lsodium yggdrasil-brute-multi-ed25519.c util.o 10 | 11 | yggdrasil-brute-multi-curve25519: yggdrasil-brute-multi-curve25519.c util.o 12 | gcc -Wall -std=c89 -O3 -o yggdrasil-brute-multi-curve25519 -lsodium yggdrasil-brute-multi-curve25519.c util.o 13 | -------------------------------------------------------------------------------- /contrib/yggdrasil-brute-simple/README.md: -------------------------------------------------------------------------------- 1 | # yggdrasil-brute-simple 2 | 3 | Simple program for finding curve25519 and ed25519 public keys whose sha512 hash has many leading ones. 4 | Because ed25519 private keys consist of a seed that is hashed to find the secret part of the keypair, 5 | this program is near optimal for finding ed25519 keypairs. Curve25519 key generation, on the other hand, 6 | could be further optimized with elliptic curve magic. 7 | 8 | Depends on libsodium. 9 | -------------------------------------------------------------------------------- /contrib/yggdrasil-brute-simple/util.c: -------------------------------------------------------------------------------- 1 | #include "yggdrasil-brute.h" 2 | 3 | int find_where(unsigned char hash[64], unsigned char besthashlist[NUMKEYS][64]) { 4 | /* Where to insert hash into sorted hashlist */ 5 | int j; 6 | int where = -1; 7 | for (j = 0; j < NUMKEYS; ++j) { 8 | if (memcmp(hash, besthashlist[j], 64) > 0) ++where; 9 | else break; 10 | } 11 | return where; 12 | } 13 | 14 | void insert_64(unsigned char itemlist[NUMKEYS][64], unsigned char item[64], int where) { 15 | int j; 16 | for (j = 0; j < where; ++j) { 17 | memcpy(itemlist[j], itemlist[j+1], 64); 18 | } 19 | memcpy(itemlist[where], item, 64); 20 | } 21 | 22 | void insert_32(unsigned char itemlist[NUMKEYS][32], unsigned char item[32], int where) { 23 | int j; 24 | for (j = 0; j < where; ++j) { 25 | memcpy(itemlist[j], itemlist[j+1], 32); 26 | } 27 | memcpy(itemlist[where], item, 32); 28 | } 29 | 30 | void make_addr(unsigned char addr[32], unsigned char hash[64]) { 31 | /* Public key hash to yggdrasil ipv6 address */ 32 | int i; 33 | int offset; 34 | unsigned char mask; 35 | unsigned char c; 36 | int ones = 0; 37 | unsigned char br = 0; /* false */ 38 | for (i = 0; i < 64 && !br; ++i) { 39 | mask = 128; 40 | c = hash[i]; 41 | while (mask) { 42 | if (c & mask) { 43 | ++ones; 44 | } else { 45 | br = 1; /* true */ 46 | break; 47 | } 48 | mask >>= 1; 49 | } 50 | } 51 | 52 | addr[0] = 2; 53 | addr[1] = ones; 54 | 55 | offset = ones + 1; 56 | for (i = 0; i < 14; ++i) { 57 | c = hash[offset/8] << (offset%8); 58 | c |= hash[offset/8 + 1] >> (8 - offset%8); 59 | addr[i + 2] = c; 60 | offset += 8; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /contrib/yggdrasil-brute-simple/yggdrasil-brute-multi-curve25519.c: -------------------------------------------------------------------------------- 1 | /* 2 | sk: 32 random bytes 3 | sk[0] &= 248; 4 | sk[31] &= 127; 5 | sk[31] |= 64; 6 | 7 | increment sk 8 | pk = curve25519_scalarmult_base(mysecret) 9 | hash = sha512(pk) 10 | 11 | if besthash: 12 | bestsk = sk 13 | besthash = hash 14 | */ 15 | 16 | #include "yggdrasil-brute.h" 17 | 18 | 19 | void seed(unsigned char sk[32]) { 20 | randombytes_buf(sk, 32); 21 | sk[0] &= 248; 22 | sk[31] &= 127; 23 | sk[31] |= 64; 24 | } 25 | 26 | 27 | int main(int argc, char **argv) { 28 | int i; 29 | int j; 30 | unsigned char addr[16]; 31 | time_t starttime; 32 | time_t requestedtime; 33 | 34 | unsigned char bestsklist[NUMKEYS][32]; 35 | unsigned char bestpklist[NUMKEYS][32]; 36 | unsigned char besthashlist[NUMKEYS][64]; 37 | 38 | unsigned char sk[32]; 39 | unsigned char pk[32]; 40 | unsigned char hash[64]; 41 | 42 | unsigned int runs = 0; 43 | int where; 44 | 45 | if (argc != 2) { 46 | fprintf(stderr, "usage: ./yggdrasil-brute-multi-curve25519 \n"); 47 | return 1; 48 | } 49 | 50 | if (sodium_init() < 0) { 51 | /* panic! the library couldn't be initialized, it is not safe to use */ 52 | printf("sodium init failed!\n"); 53 | return 1; 54 | } 55 | 56 | starttime = time(NULL); 57 | requestedtime = atoi(argv[1]); 58 | 59 | if (requestedtime < 0) requestedtime = 0; 60 | fprintf(stderr, "Searching for yggdrasil curve25519 keys (this will take slightly longer than %ld seconds)\n", requestedtime); 61 | 62 | sodium_memzero(bestsklist, NUMKEYS * 32); 63 | sodium_memzero(bestpklist, NUMKEYS * 32); 64 | sodium_memzero(besthashlist, NUMKEYS * 64); 65 | seed(sk); 66 | 67 | do { 68 | /* generate pubkey, hash, compare, increment secret. 69 | * this loop should take 4 seconds on modern hardware */ 70 | for (i = 0; i < (1 << 16); ++i) { 71 | ++runs; 72 | if (crypto_scalarmult_curve25519_base(pk, sk) != 0) { 73 | printf("scalarmult to create pub failed!\n"); 74 | return 1; 75 | } 76 | crypto_hash_sha512(hash, pk, 32); 77 | 78 | where = find_where(hash, besthashlist); 79 | if (where >= 0) { 80 | insert_32(bestsklist, sk, where); 81 | insert_32(bestpklist, pk, where); 82 | insert_64(besthashlist, hash, where); 83 | 84 | seed(sk); 85 | } 86 | for (j = 1; j < 31; ++j) if (++sk[j]) break; 87 | } 88 | } while (time(NULL) - starttime < requestedtime || runs < NUMKEYS); 89 | 90 | fprintf(stderr, "--------------addr-------------- -----------------------------secret----------------------------- -----------------------------public-----------------------------\n"); 91 | for (i = 0; i < NUMKEYS; ++i) { 92 | make_addr(addr, besthashlist[i]); 93 | for (j = 0; j < 16; ++j) printf("%02x", addr[j]); 94 | printf(" "); 95 | for (j = 0; j < 32; ++j) printf("%02x", bestsklist[i][j]); 96 | printf(" "); 97 | for (j = 0; j < 32; ++j) printf("%02x", bestpklist[i][j]); 98 | printf("\n"); 99 | } 100 | 101 | sodium_memzero(bestsklist, NUMKEYS * 32); 102 | sodium_memzero(sk, 32); 103 | 104 | return 0; 105 | } 106 | -------------------------------------------------------------------------------- /contrib/yggdrasil-brute-simple/yggdrasil-brute-multi-ed25519.c: -------------------------------------------------------------------------------- 1 | /* 2 | seed: 32 random bytes 3 | sk: sha512(seed) 4 | sk[0] &= 248 5 | sk[31] &= 127 6 | sk[31] |= 64 7 | 8 | pk: scalarmult_ed25519_base(sk) 9 | 10 | 11 | increment seed 12 | generate sk 13 | generate pk 14 | hash = sha512(mypub) 15 | 16 | if besthash: 17 | bestseed = seed 18 | bestseckey = sk 19 | bestpubkey = pk 20 | besthash = hash 21 | */ 22 | 23 | #include "yggdrasil-brute.h" 24 | 25 | 26 | int main(int argc, char **argv) { 27 | int i; 28 | int j; 29 | time_t starttime; 30 | time_t requestedtime; 31 | 32 | unsigned char bestsklist[NUMKEYS][64]; /* sk contains pk */ 33 | unsigned char besthashlist[NUMKEYS][64]; 34 | 35 | unsigned char seed[32]; 36 | unsigned char sk[64]; 37 | unsigned char pk[32]; 38 | unsigned char hash[64]; 39 | 40 | unsigned int runs = 0; 41 | int where; 42 | 43 | if (argc != 2) { 44 | fprintf(stderr, "usage: ./yggdrasil-brute-multi-curve25519 \n"); 45 | return 1; 46 | } 47 | 48 | if (sodium_init() < 0) { 49 | /* panic! the library couldn't be initialized, it is not safe to use */ 50 | printf("sodium init failed!\n"); 51 | return 1; 52 | } 53 | 54 | starttime = time(NULL); 55 | requestedtime = atoi(argv[1]); 56 | 57 | if (requestedtime < 0) requestedtime = 0; 58 | fprintf(stderr, "Searching for yggdrasil ed25519 keys (this will take slightly longer than %ld seconds)\n", requestedtime); 59 | 60 | sodium_memzero(bestsklist, NUMKEYS * 64); 61 | sodium_memzero(besthashlist, NUMKEYS * 64); 62 | randombytes_buf(seed, 32); 63 | 64 | do { 65 | /* generate pubkey, hash, compare, increment secret. 66 | * this loop should take 4 seconds on modern hardware */ 67 | for (i = 0; i < (1 << 17); ++i) { 68 | ++runs; 69 | crypto_hash_sha512(sk, seed, 32); 70 | 71 | if (crypto_scalarmult_ed25519_base(pk, sk) != 0) { 72 | printf("scalarmult to create pub failed!\n"); 73 | return 1; 74 | } 75 | memcpy(sk + 32, pk, 32); 76 | 77 | crypto_hash_sha512(hash, pk, 32); 78 | 79 | /* insert into local list of good key */ 80 | where = find_where(hash, besthashlist); 81 | if (where >= 0) { 82 | insert_64(bestsklist, sk, where); 83 | insert_64(besthashlist, hash, where); 84 | randombytes_buf(seed, 32); 85 | } 86 | for (j = 1; j < 31; ++j) if (++seed[j]) break; 87 | } 88 | } while (time(NULL) - starttime < requestedtime || runs < NUMKEYS); 89 | 90 | fprintf(stderr, "!! Secret key is seed concatenated with public !!\n"); 91 | fprintf(stderr, "---hash--- ------------------------------seed------------------------------ -----------------------------public-----------------------------\n"); 92 | for (i = 0; i < NUMKEYS; ++i) { 93 | for (j = 0; j < 5; ++j) printf("%02x", besthashlist[i][j]); 94 | printf(" "); 95 | for (j = 0; j < 32; ++j) printf("%02x", bestsklist[i][j]); 96 | printf(" "); 97 | for (j = 32; j < 64; ++j) printf("%02x", bestsklist[i][j]); 98 | printf("\n"); 99 | } 100 | 101 | sodium_memzero(bestsklist, NUMKEYS * 64); 102 | sodium_memzero(sk, 64); 103 | sodium_memzero(seed, 32); 104 | 105 | return 0; 106 | } 107 | -------------------------------------------------------------------------------- /contrib/yggdrasil-brute-simple/yggdrasil-brute.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include /* printf */ 3 | #include /* memcpy */ 4 | #include /* atoi */ 5 | #include /* time */ 6 | 7 | 8 | #define NUMKEYS 10 9 | void make_addr(unsigned char addr[32], unsigned char hash[64]); 10 | int find_where(unsigned char hash[64], unsigned char besthashlist[NUMKEYS][64]); 11 | void insert_64(unsigned char itemlist[NUMKEYS][64], unsigned char item[64], int where); 12 | void insert_32(unsigned char itemlist[NUMKEYS][32], unsigned char item[32], int where); 13 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/popura-network/Popura 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/cheggaaa/pb/v3 v3.0.8 7 | github.com/gologme/log v1.2.0 8 | github.com/hashicorp/go-syslog v1.0.0 9 | github.com/hjson/hjson-go v3.1.0+incompatible 10 | github.com/kardianos/minwinsvc v1.0.2 11 | github.com/mitchellh/mapstructure v1.4.1 12 | github.com/olekukonko/tablewriter v0.0.5 13 | github.com/yggdrasil-network/yggdrasil-go v0.4.6 14 | github.com/zhoreeq/meshname v0.2.0 15 | golang.org/x/mobile v0.0.0-20221012134814-c746ac228303 16 | golang.org/x/text v0.3.8 17 | ) 18 | 19 | require ( 20 | github.com/Arceliar/ironwood v0.0.0-20221025225125-45b4281814c2 // indirect 21 | github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979 // indirect 22 | github.com/VividCortex/ewma v1.2.0 // indirect 23 | github.com/fatih/color v1.12.0 // indirect 24 | github.com/mattn/go-colorable v0.1.8 // indirect 25 | github.com/mattn/go-isatty v0.0.13 // indirect 26 | github.com/mattn/go-runewidth v0.0.13 // indirect 27 | github.com/miekg/dns v1.1.41 // indirect 28 | github.com/rivo/uniseg v0.2.0 // indirect 29 | github.com/vishvananda/netlink v1.1.0 // indirect 30 | github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect 31 | golang.org/x/crypto v0.0.0-20221012134737-56aed061732a // indirect 32 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect 33 | golang.org/x/net v0.0.0-20221014081412-f15817d10f9b // indirect 34 | golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 // indirect 35 | golang.org/x/tools v0.1.12 // indirect 36 | golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a // indirect 37 | golang.zx2c4.com/wireguard/windows v0.4.12 // indirect 38 | ) 39 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/Arceliar/ironwood v0.0.0-20221025225125-45b4281814c2 h1:Usab30pNT2i/vZvpXcN9uOr5IO1RZPcUqoGH0DIAPnU= 2 | github.com/Arceliar/ironwood v0.0.0-20221025225125-45b4281814c2/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk= 3 | github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979 h1:WndgpSW13S32VLQ3ugUxx2EnnWmgba1kCqPkd4Gk1yQ= 4 | github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979/go.mod h1:6Lkn+/zJilRMsKmbmG1RPoamiArC6HS73xbwRyp3UyI= 5 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 6 | github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= 7 | github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= 8 | github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= 9 | github.com/cheggaaa/pb/v3 v3.0.8 h1:bC8oemdChbke2FHIIGy9mn4DPJ2caZYQnfbRqwmdCoA= 10 | github.com/cheggaaa/pb/v3 v3.0.8/go.mod h1:UICbiLec/XO6Hw6k+BHEtHeQFzzBH4i2/qk/ow1EJTA= 11 | github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= 12 | github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= 13 | github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= 14 | github.com/gologme/log v1.2.0 h1:Ya5Ip/KD6FX7uH0S31QO87nCCSucKtF44TLbTtO7V4c= 15 | github.com/gologme/log v1.2.0/go.mod h1:gq31gQ8wEHkR+WekdWsqDuf8pXTUZA9BnnzTuPz1Y9U= 16 | github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= 17 | github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= 18 | github.com/hjson/hjson-go v3.1.0+incompatible h1:DY/9yE8ey8Zv22bY+mHV1uk2yRy0h8tKhZ77hEdi0Aw= 19 | github.com/hjson/hjson-go v3.1.0+incompatible/go.mod h1:qsetwF8NlsTsOTwZTApNlTCerV+b2GjYRRcIk4JMFio= 20 | github.com/kardianos/minwinsvc v1.0.2 h1:JmZKFJQrmTGa/WiW+vkJXKmfzdjabuEW4Tirj5lLdR0= 21 | github.com/kardianos/minwinsvc v1.0.2/go.mod h1:LUZNYhNmxujx2tR7FbdxqYJ9XDDoCd3MQcl1o//FWl4= 22 | github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ= 23 | github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk= 24 | github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= 25 | github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 26 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 27 | github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= 28 | github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 29 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 30 | github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= 31 | github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= 32 | github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 33 | github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= 34 | github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= 35 | github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= 36 | github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= 37 | github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 38 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= 39 | github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= 40 | github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 41 | github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= 42 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 43 | github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= 44 | github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= 45 | github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= 46 | github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA= 47 | github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= 48 | github.com/yggdrasil-network/yggdrasil-go v0.4.6 h1:GALUDV9QPz/5FVkbazpkTc9EABHufA556JwUJZr41j4= 49 | github.com/yggdrasil-network/yggdrasil-go v0.4.6/go.mod h1:PBMoAOvQjA9geNEeGyMXA9QgCS6Bu+9V+1VkWM84wpw= 50 | github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 51 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 52 | github.com/zhoreeq/meshname v0.2.0 h1:kRAHmemR/MpTmas2ZNoL8VJnYdbesZRwsGR2qEmzyDo= 53 | github.com/zhoreeq/meshname v0.2.0/go.mod h1:3I8MpFZ304bAYiD+e+ovlMDDZat8aKyUlqllUok4qm0= 54 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 55 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 56 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 57 | golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 58 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 59 | golang.org/x/crypto v0.0.0-20221012134737-56aed061732a h1:NmSIgad6KjE6VvHciPZuNRTKxGhlPfD6OA87W/PLkqg= 60 | golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 61 | golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= 62 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 63 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 64 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 65 | golang.org/x/mobile v0.0.0-20221012134814-c746ac228303 h1:K4fp1rDuJBz0FCPAWzIJwnzwNEM7S6yobdZzMrZ/Zws= 66 | golang.org/x/mobile v0.0.0-20221012134814-c746ac228303/go.mod h1:M32cGdzp91A8Ex9qQtyZinr19EYxzkFqDjW2oyHzTDQ= 67 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 68 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 69 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 70 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= 71 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 72 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 73 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 74 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 75 | golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 76 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 77 | golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 78 | golang.org/x/net v0.0.0-20210927181540-4e4d966f7476/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 79 | golang.org/x/net v0.0.0-20211011170408-caeb26a5c8c0/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 80 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 81 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 82 | golang.org/x/net v0.0.0-20221014081412-f15817d10f9b h1:tvrvnPFcdzp294diPnrdZZZ8XUt2Tyj7svb7X52iDuU= 83 | golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= 84 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 85 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 86 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 87 | golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde h1:ejfdSekXMDxDLbRrJMwUk6KnSLZ2McaUCVcIKM+N6jc= 88 | golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 89 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 90 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 91 | golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 92 | golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 93 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 94 | golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 95 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 96 | golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 97 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 98 | golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 99 | golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 100 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 101 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 102 | golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 103 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 104 | golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 105 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 106 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 107 | golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 108 | golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 h1:OK7RB6t2WQX54srQQYSXMW8dF5C6/8+oA/s5QBmmto4= 109 | golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 110 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 111 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 112 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 113 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 114 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 115 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 116 | golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= 117 | golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= 118 | golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= 119 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 120 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 121 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 122 | golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 123 | golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= 124 | golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= 125 | golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= 126 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 127 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 128 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 129 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 130 | golang.zx2c4.com/wireguard v0.0.0-20211012062646-82d2aa87aa62/go.mod h1:id8Oh3eCCmpj9uVGWVjsUAl6UPX5ysMLzu6QxJU2UOU= 131 | golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a h1:tTbyylK9/D3u/wEP26Vx7L700UpY48nhioJWZM1vhZw= 132 | golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a/go.mod h1:id8Oh3eCCmpj9uVGWVjsUAl6UPX5ysMLzu6QxJU2UOU= 133 | golang.zx2c4.com/wireguard/windows v0.4.12 h1:CUmbdWKVNzTSsVb4yUAiEwL3KsabdJkEPdDjCHxBlhA= 134 | golang.zx2c4.com/wireguard/windows v0.4.12/go.mod h1:PW4y+d9oY83XU9rRwRwrJDwEMuhVjMxu2gfD1cfzS7w= 135 | -------------------------------------------------------------------------------- /misc/run-schannel-netns: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Connects nodes in a network resembling an s-channel feynmann diagram. 4 | 5 | # 1 5 6 | # \ / 7 | # 3--4 8 | # / \ 9 | # 2 6 10 | 11 | # Bandwidth constraints are applied to 4<->5 and 4<->6. 12 | # The idea is to make sure that bottlenecks on one link don't affect the other. 13 | 14 | ip netns add node1 15 | ip netns add node2 16 | ip netns add node3 17 | ip netns add node4 18 | ip netns add node5 19 | ip netns add node6 20 | 21 | ip link add veth13 type veth peer name veth31 22 | ip link set veth13 netns node1 up 23 | ip link set veth31 netns node3 up 24 | 25 | ip link add veth23 type veth peer name veth32 26 | ip link set veth23 netns node2 up 27 | ip link set veth32 netns node3 up 28 | 29 | ip link add veth34 type veth peer name veth43 30 | ip link set veth34 netns node3 up 31 | ip link set veth43 netns node4 up 32 | 33 | ip link add veth45 type veth peer name veth54 34 | ip link set veth45 netns node4 up 35 | ip link set veth54 netns node5 up 36 | 37 | ip link add veth46 type veth peer name veth64 38 | ip link set veth46 netns node4 up 39 | ip link set veth64 netns node6 up 40 | 41 | ip netns exec node4 tc qdisc add dev veth45 root tbf rate 100mbit burst 8192 latency 1ms 42 | ip netns exec node5 tc qdisc add dev veth54 root tbf rate 100mbit burst 8192 latency 1ms 43 | 44 | ip netns exec node4 tc qdisc add dev veth46 root tbf rate 10mbit burst 8192 latency 1ms 45 | ip netns exec node6 tc qdisc add dev veth64 root tbf rate 10mbit burst 8192 latency 1ms 46 | 47 | ip netns exec node1 ip link set lo up 48 | ip netns exec node2 ip link set lo up 49 | ip netns exec node3 ip link set lo up 50 | ip netns exec node4 ip link set lo up 51 | ip netns exec node5 ip link set lo up 52 | ip netns exec node6 ip link set lo up 53 | 54 | echo '{AdminListen: "none"}' | ip netns exec node1 env PPROFLISTEN=localhost:6060 ./yggdrasil --useconf &> /dev/null & 55 | echo '{AdminListen: "none"}' | ip netns exec node2 env PPROFLISTEN=localhost:6060 ./yggdrasil --useconf &> /dev/null & 56 | echo '{AdminListen: "none"}' | ip netns exec node3 env PPROFLISTEN=localhost:6060 ./yggdrasil --useconf &> /dev/null & 57 | echo '{AdminListen: "none"}' | ip netns exec node4 env PPROFLISTEN=localhost:6060 ./yggdrasil --useconf &> /dev/null & 58 | echo '{AdminListen: "none"}' | ip netns exec node5 env PPROFLISTEN=localhost:6060 ./yggdrasil --useconf &> /dev/null & 59 | echo '{AdminListen: "none"}' | ip netns exec node6 env PPROFLISTEN=localhost:6060 ./yggdrasil --useconf &> /dev/null & 60 | 61 | echo "Started, to continue you should (possibly w/ sudo):" 62 | echo "kill" $(jobs -p) 63 | wait 64 | 65 | ip netns delete node1 66 | ip netns delete node2 67 | ip netns delete node3 68 | ip netns delete node4 69 | ip netns delete node5 70 | ip netns delete node6 71 | 72 | ip link delete veth13 73 | ip link delete veth23 74 | ip link delete veth34 75 | ip link delete veth45 76 | ip link delete veth46 77 | -------------------------------------------------------------------------------- /misc/run-twolink-test: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Connects nodes in two namespaces by two links with different bandwidth (10mbit and 100mbit) 4 | 5 | ip netns add node1 6 | ip netns add node2 7 | 8 | ip link add veth11 type veth peer name veth21 9 | ip link set veth11 netns node1 up 10 | ip link set veth21 netns node2 up 11 | 12 | ip link add veth12 type veth peer name veth22 13 | ip link set veth12 netns node1 up 14 | ip link set veth22 netns node2 up 15 | 16 | ip netns exec node1 tc qdisc add dev veth11 root tbf rate 10mbit burst 8192 latency 1ms 17 | ip netns exec node2 tc qdisc add dev veth21 root tbf rate 10mbit burst 8192 latency 1ms 18 | 19 | ip netns exec node1 tc qdisc add dev veth12 root tbf rate 100mbit burst 8192 latency 1ms 20 | ip netns exec node2 tc qdisc add dev veth22 root tbf rate 100mbit burst 8192 latency 1ms 21 | 22 | echo '{AdminListen: "unix://node1.sock"}' | ip netns exec node1 env PPROFLISTEN=localhost:6060 ./yggdrasil -logging "info,warn,error,debug" -useconf &> node1.log & 23 | echo '{AdminListen: "unix://node2.sock"}' | ip netns exec node2 env PPROFLISTEN=localhost:6060 ./yggdrasil -logging "info,warn,error,debug" -useconf &> node2.log & 24 | 25 | echo "Started, to continue you should (possibly w/ sudo):" 26 | echo "kill" $(jobs -p) 27 | wait 28 | 29 | ip netns delete node1 30 | ip netns delete node2 31 | 32 | ip link delete veth11 33 | ip link delete veth12 34 | -------------------------------------------------------------------------------- /src/autopeering/main.go: -------------------------------------------------------------------------------- 1 | package autopeering 2 | 3 | import ( 4 | "net" 5 | "net/url" 6 | "time" 7 | ) 8 | 9 | const defaultTimeout time.Duration = time.Duration(3) * time.Second 10 | 11 | type Peer struct { 12 | URL url.URL 13 | Online bool 14 | Latency time.Duration 15 | } 16 | 17 | func testPeers(peers []url.URL) []Peer { 18 | var res []Peer 19 | results := make(chan Peer) 20 | 21 | for _, p := range peers { 22 | go testPeer(p, results) 23 | } 24 | 25 | for i := 0; i < len(peers); i++ { 26 | res = append(res, <-results) 27 | } 28 | 29 | return res 30 | } 31 | 32 | func testPeer(peer url.URL, results chan Peer) { 33 | p := Peer{peer, false, 0.0} 34 | p.Online = false 35 | t0 := time.Now() 36 | 37 | var network string 38 | if peer.Scheme == "tcp" || peer.Scheme == "tls" { 39 | network = "tcp" 40 | } else { // skip, not supported yet 41 | results <- p 42 | return 43 | } 44 | 45 | conn, err := net.DialTimeout(network, peer.Host, defaultTimeout) 46 | if err == nil { 47 | t1 := time.Now() 48 | conn.Close() 49 | p.Online = true 50 | p.Latency = t1.Sub(t0) 51 | } 52 | results <- p 53 | } 54 | -------------------------------------------------------------------------------- /src/autopeering/module.go: -------------------------------------------------------------------------------- 1 | package autopeering 2 | 3 | import ( 4 | "net/url" 5 | "strings" 6 | "time" 7 | 8 | "github.com/gologme/log" 9 | 10 | "github.com/yggdrasil-network/yggdrasil-go/src/admin" 11 | "github.com/yggdrasil-network/yggdrasil-go/src/config" 12 | "github.com/yggdrasil-network/yggdrasil-go/src/core" 13 | 14 | "github.com/popura-network/Popura/src/popura" 15 | ) 16 | 17 | const ( 18 | linkLocalPrefix = "tls://[fe80" 19 | autopeerTimeout = 30 * time.Second 20 | peerCheckTimeout = 10 * time.Second 21 | ) 22 | 23 | type AutoPeering struct { 24 | core *core.Core 25 | log *log.Logger 26 | checkPeerTimer *time.Timer 27 | hadPeers time.Time 28 | peers []url.URL 29 | enabled bool 30 | } 31 | 32 | func (ap *AutoPeering) Init(yggcore *core.Core, yggConfig *config.NodeConfig, popConfig *popura.PopuraConfig, log *log.Logger, options interface{}) error { 33 | ap.core = yggcore 34 | ap.log = log 35 | ap.peers = GetPublicPeers() 36 | ap.enabled = popConfig.Autopeering.Enable 37 | return nil 38 | } 39 | 40 | func (ap *AutoPeering) Start() error { 41 | if ap.enabled { 42 | go ap.checkPeerLoop() 43 | } 44 | ap.log.Infoln("autopeering: module started") 45 | return nil 46 | } 47 | 48 | func (ap *AutoPeering) Stop() error { 49 | if ap.checkPeerTimer != nil { 50 | ap.checkPeerTimer.Stop() 51 | } 52 | return nil 53 | } 54 | 55 | func (ap *AutoPeering) checkPeerLoop() { 56 | havePeers := false 57 | 58 | for _, p := range ap.core.GetPeers() { 59 | if !strings.HasPrefix(p.Remote, linkLocalPrefix) { 60 | ap.log.Debugln("autopeering: remote peer is connected ", p.Remote) 61 | havePeers = true 62 | break 63 | } 64 | } 65 | 66 | if havePeers { 67 | ap.hadPeers = time.Now() 68 | } else if time.Since(ap.hadPeers) > autopeerTimeout { 69 | ap.log.Debugln("autopeering: adding a new peer") 70 | ap.hadPeers = time.Now() 71 | peers := RandomPick(GetClosestPeers(ap.peers, 10), 1) 72 | if len(peers) == 1 { 73 | peerUri := peers[0] 74 | 75 | ap.log.Infoln("autopeering: adding new peer", peerUri.String()) 76 | go func() { 77 | if err := ap.core.CallPeer(&peerUri, ""); err != nil { 78 | ap.log.Infoln("autopeering: peer connection failed:", err) 79 | } 80 | }() 81 | } 82 | } 83 | 84 | ap.checkPeerTimer = time.AfterFunc(peerCheckTimeout, func() { 85 | ap.checkPeerLoop() 86 | }) 87 | } 88 | 89 | func (ap *AutoPeering) UpdateConfig(yggConfig *config.NodeConfig, popConfig *popura.PopuraConfig) {} 90 | func (ap *AutoPeering) SetupAdminHandlers(a *admin.AdminSocket) {} 91 | func (ap *AutoPeering) IsStarted() bool { return false } 92 | -------------------------------------------------------------------------------- /src/autopeering/peers.go: -------------------------------------------------------------------------------- 1 | package autopeering 2 | 3 | import ( 4 | _ "embed" 5 | "math/rand" 6 | "net/url" 7 | "sort" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | //go:embed peers.txt 13 | var PublicPeers string 14 | 15 | // Get URLs of embedded public peers 16 | func GetPublicPeers() []url.URL { 17 | var result []url.URL 18 | 19 | for _, p := range strings.Split(PublicPeers, "\n") { 20 | if url, err := url.Parse(p); err == nil { 21 | result = append(result, *url) 22 | } else { 23 | panic(err) 24 | } 25 | } 26 | return result 27 | } 28 | 29 | // Get n online peers with best latency from a peer list 30 | func GetClosestPeers(peerList []url.URL, n int) []url.URL { 31 | var result []url.URL 32 | onlinePeers := testPeers(peerList) 33 | 34 | // Filter online peers 35 | x := 0 36 | for _, p := range onlinePeers { 37 | if p.Online { 38 | onlinePeers[x] = p 39 | x++ 40 | } 41 | } 42 | onlinePeers = onlinePeers[:x] 43 | 44 | sort.Slice(onlinePeers, func(i, j int) bool { 45 | return onlinePeers[i].Latency < onlinePeers[j].Latency 46 | }) 47 | 48 | for i := 0; i < len(onlinePeers); i++ { 49 | if len(result) == n { 50 | break 51 | } 52 | result = append(result, onlinePeers[i].URL) 53 | } 54 | 55 | return result 56 | } 57 | 58 | // Pick n random peers from a list 59 | func RandomPick(peerList []url.URL, n int) []url.URL { 60 | if len(peerList) <= n { 61 | return peerList 62 | } 63 | 64 | var res []url.URL 65 | r := rand.New(rand.NewSource(time.Now().UnixNano())) 66 | for _, i := range r.Perm(n) { 67 | res = append(res, peerList[i]) 68 | } 69 | 70 | return res 71 | } 72 | -------------------------------------------------------------------------------- /src/autopeering/peers.txt: -------------------------------------------------------------------------------- 1 | tcp://ipv6.campina-grande.paraiba.brazil.yggdrasil.iasylum.net:41000 2 | tcp://ipv4.campina-grande.paraiba.brazil.yggdrasil.iasylum.net:40000 3 | tls://ipv6.campina-grande.paraiba.brazil.yggdrasil.iasylum.net:51000 4 | tls://ipv4.campina-grande.paraiba.brazil.yggdrasil.iasylum.net:50000 5 | tls://192.99.145.61:58226 6 | tls://[2607:5300:201:3100::50a1]:58226 7 | tcp://kusoneko.moe:9002 8 | tls://ca1.servers.devices.cwinfo.net:58226 9 | tcp://[2a05:9403::8b]:7743 10 | tcp://195.123.245.146:7743 11 | tls://95.216.5.243:18836 12 | tls://[2a01:4f9:2a:60c::2]:18836 13 | tls://[2a01:4f9:c010:664d::1]:61995 14 | tls://aurora.devices.waren.io:18836 15 | tls://fi1.servers.devices.cwinfo.net:61995 16 | tls://65.21.57.122:61995 17 | tls://[2001:41d0:2:c44a:51:255:223:60]:54232 18 | tcp://62.210.85.80:39565 19 | tls://51.255.223.60:54232 20 | tcp://51.15.204.214:12345 21 | tls://51.15.204.214:54321 22 | tcp://[2001:470:1f13:e56::64]:39565 23 | tcp://s2.i2pd.xyz:39565 24 | tls://[2001:41d0:304:200::ace3]:23108 25 | tls://62.210.85.80:39575 26 | tls://[2001:470:1f13:e56::64]:39575 27 | tls://152.228.216.112:23108 28 | tls://s2.i2pd.xyz:39575 29 | tls://cloudberry.fr1.servers.devices.cwinfo.net:54232 30 | tls://fr2.servers.devices.cwinfo.net:23108 31 | tls://163.172.31.60:12221?key=060f2d49c6a1a2066357ea06e58f5cff8c76a5c0cc513ceb2dab75c900fe183b&sni=jorropo.net 32 | tls://jorropo.net:12221?key=060f2d49c6a1a2066357ea06e58f5cff8c76a5c0cc513ceb2dab75c900fe183b&sni=jorropo.net 33 | tcp://94.130.203.208:5999 34 | tls://yggdrasil.su:62586 35 | tcp://ygg.mkg20001.io:80 36 | tls://vpn.ltha.de:443?key=0000006149970f245e6cec43664bce203f2514b60a153e194f31e2b229a1339d 37 | tls://de-fsn-1.peer.v4.yggdrasil.chaz6.com:4444 38 | tcp://p2p-node.de:1337?key=000000d80a2d7b3126ea65c8c08fc751088c491a5cdd47eff11c86fa1e4644ae 39 | tcp://phrl42.ydns.eu:8842 40 | tcp://yggdrasil.su:62486 41 | tls://ygg.mkg20001.io:443 42 | tls://p2p-node.de:1338?key=000000d80a2d7b3126ea65c8c08fc751088c491a5cdd47eff11c86fa1e4644ae 43 | tcp://ygg1.mk16.de:1337?key=0000000087ee9949eeab56bd430ee8f324cad55abf3993ed9b9be63ce693e18a 44 | tls://ygg1.mk16.de:1338?key=0000000087ee9949eeab56bd430ee8f324cad55abf3993ed9b9be63ce693e18a 45 | tls://minecast.xyz:3785 46 | tls://45.147.198.155:6010 47 | tcp://ygg-nl.incognet.io:8883 48 | tcp://vpn.itrus.su:7991 49 | tls://ygg-nl.incognet.io:8884 50 | tls://109.107.173.235:9111 51 | tls://94.103.82.150:8080 52 | tls://aaoth.xyz:25565 53 | tcp://aaoth.xyz:7777 54 | tls://[2001:41d0:601:1100::cf2]:11129 55 | tls://54.37.137.221:11129 56 | tls://pl1.servers.devices.cwinfo.net:11129 57 | tcp://185.165.169.234:8880 58 | tls://185.165.169.234:8443 59 | tcp://188.225.9.167:18226 60 | tcp://92.124.136.131:30111 61 | tls://188.225.9.167:18227 62 | tcp://ygg.tomasgl.ru:61933?key=c5e0c28a600c2118e986196a0bbcbda4934d8e9278ceabea48838dc5d8fae576 63 | tls://[2a01:d0:ffff:4353::2]:6010 64 | tls://avevad.com:1337 65 | tcp://itcom.multed.com:7991 66 | tls://ygg.tomasgl.ru:61944?key=c5e0c28a600c2118e986196a0bbcbda4934d8e9278ceabea48838dc5d8fae576 67 | tcp://srv.itrus.su:7991 68 | tcp://box.paulll.cc:13337 69 | tcp://yggno.de:18226 70 | tls://yggno.de:18227 71 | tcp://ekb.itrus.su:7991 72 | tls://box.paulll.cc:13338 73 | tls://yggpvs.duckdns.org:8443 74 | tcp://158.101.229.219:17002 75 | tcp://[2603:c023:8001:1600:35e0:acde:2c6e:b27f]:17002 76 | tls://[2603:c023:8001:1600:35e0:acde:2c6e:b27f]:17001 77 | tls://158.101.229.219:17001 78 | tcp://sin.yuetau.net:6642 79 | tls://sin.yuetau.net:6643 80 | tcp://y.zbin.eu:7743 81 | tcp://[2a04:5b81:2010:5000:27d3:6343:a821:eb1c]:2000 82 | tls://[2a04:5b81:2010:5000:27d3:6343:a821:eb1c]:2001 83 | tls://[2a07:e01:105:444:c634:6bff:feb5:6e28]:7040 84 | tls://185.130.44.194:7040 85 | tls://ygg.ace.ctrl-c.liu.se:9999?key=5636b3af4738c3998284c4805d91209cab38921159c66a6f359f3f692af1c908 86 | tcp://ygg.ace.ctrl-c.liu.se:9998?key=5636b3af4738c3998284c4805d91209cab38921159c66a6f359f3f692af1c908 87 | tcp://212.154.86.134:8800 88 | tls://212.154.86.134:4433 89 | tcp://ip6-antalya.ddns.net:8800 90 | tls://ip6-antalya.ddns.net:4433 91 | tcp://193.111.114.28:8080 92 | tls://193.111.114.28:1443 93 | tls://91.224.254.114:18001 94 | tcp://78.27.153.163:33165 95 | tls://78.27.153.163:3784 96 | tls://78.27.153.163:179 97 | tls://78.27.153.163:3785 98 | tls://78.27.153.163:33166 99 | tls://51.38.64.12:28395 100 | tls://185.175.90.87:43006 101 | tls://[2a10:4740:40:0:2222:3f9c:b7cf:1]:43006 102 | tls://uk1.servers.devices.cwinfo.net:28395 103 | tcp://curiosity.tdjs.tech:30003 104 | tcp://50.236.201.218:56088 105 | tcp://longseason.1200bps.xyz:13121 106 | tcp://149.28.123.138:8008 107 | tcp://lancis.iscute.moe:49273 108 | tcp://zabugor.itrus.su:7991 109 | tcp://supergay.network:9002 110 | tls://108.175.10.127:61216 111 | tls://longseason.1200bps.xyz:13122 112 | tls://167.160.89.98:7040 113 | tls://supergay.network:9001 114 | tls://supergay.network:443 115 | tcp://tasty.chowder.land:9002 116 | tls://44.234.134.124:443 117 | tls://[2605:9f80:2000:64::2]:7040 118 | tls://bazari.sh:3725 119 | tls://tasty.chowder.land:9001 120 | tls://5.161.114.182:443 121 | tls://5.161.139.99:443 122 | tls://lancis.iscute.moe:49274 123 | -------------------------------------------------------------------------------- /src/meshname/module.go: -------------------------------------------------------------------------------- 1 | package meshname 2 | 3 | import ( 4 | "net" 5 | 6 | "github.com/gologme/log" 7 | 8 | "github.com/yggdrasil-network/yggdrasil-go/src/admin" 9 | "github.com/yggdrasil-network/yggdrasil-go/src/config" 10 | "github.com/yggdrasil-network/yggdrasil-go/src/core" 11 | 12 | _meshname "github.com/zhoreeq/meshname/pkg/meshname" 13 | 14 | "github.com/popura-network/Popura/src/popura" 15 | ) 16 | 17 | type MeshnameServer struct { 18 | server *_meshname.MeshnameServer 19 | log *log.Logger 20 | enable bool 21 | } 22 | 23 | func (s *MeshnameServer) Init(yggcore *core.Core, yggConfig *config.NodeConfig, popConfig *popura.PopuraConfig, log *log.Logger, options interface{}) error { 24 | s.log = log 25 | s.enable = popConfig.Meshname.Enable 26 | yggIPNet := &net.IPNet{IP: net.ParseIP("200::"), Mask: net.CIDRMask(7, 128)} 27 | s.server = _meshname.New( 28 | log, 29 | popConfig.Meshname.Listen, 30 | map[string]*net.IPNet{"ygg": yggIPNet, "meshname": yggIPNet, "popura": yggIPNet}, 31 | false, // enable meship protocol 32 | ) 33 | 34 | return nil 35 | } 36 | 37 | func (s *MeshnameServer) Start() error { 38 | if s.enable { 39 | return s.server.Start() 40 | } else { 41 | return nil 42 | } 43 | } 44 | 45 | func (s *MeshnameServer) Stop() error { 46 | s.server.Stop() 47 | return nil 48 | } 49 | 50 | func (s *MeshnameServer) UpdateConfig(yggConfig *config.NodeConfig, popConfig *popura.PopuraConfig) {} 51 | 52 | func (s *MeshnameServer) SetupAdminHandlers(a *admin.AdminSocket) {} 53 | 54 | func (s *MeshnameServer) IsStarted() bool { 55 | return s.server.IsStarted() 56 | } 57 | -------------------------------------------------------------------------------- /src/popura/config.go: -------------------------------------------------------------------------------- 1 | package popura 2 | 3 | type PopuraConfig struct { 4 | Autopeering AutopeeringConfig `comment:"Autopeering description"` 5 | Meshname MeshnameConfig `comment:"DNS server description"` 6 | } 7 | 8 | type AutopeeringConfig struct { 9 | Enable bool `comment:"Enable autopeering"` 10 | } 11 | 12 | type MeshnameConfig struct { 13 | Enable bool `comment:"Enable or disable the DNS server"` 14 | Listen string `comment:"Listen address for the DNS server"` 15 | } 16 | 17 | func GenerateConfig() *PopuraConfig { 18 | popConfig := PopuraConfig{} 19 | 20 | popConfig.Autopeering.Enable = false 21 | 22 | popConfig.Meshname.Enable = false 23 | popConfig.Meshname.Listen = "[::1]:53535" 24 | 25 | return &popConfig 26 | } 27 | -------------------------------------------------------------------------------- /src/popura/module.go: -------------------------------------------------------------------------------- 1 | package popura 2 | 3 | import ( 4 | "github.com/gologme/log" 5 | 6 | "github.com/yggdrasil-network/yggdrasil-go/src/admin" 7 | "github.com/yggdrasil-network/yggdrasil-go/src/config" 8 | "github.com/yggdrasil-network/yggdrasil-go/src/core" 9 | ) 10 | 11 | // Module is an interface that defines which functions must be supported by a 12 | // given Popura module. 13 | type Module interface { 14 | Init(yggcore *core.Core, yggConfig *config.NodeConfig, popuraConf *PopuraConfig, log *log.Logger, options interface{}) error 15 | Start() error 16 | Stop() error 17 | UpdateConfig(yggConf *config.NodeConfig, popuraConf *PopuraConfig) 18 | SetupAdminHandlers(a *admin.AdminSocket) 19 | IsStarted() bool 20 | } 21 | -------------------------------------------------------------------------------- /src/popura/utils.go: -------------------------------------------------------------------------------- 1 | package popura 2 | 3 | import ( 4 | "crypto/ed25519" 5 | "encoding/hex" 6 | "net" 7 | 8 | "github.com/yggdrasil-network/yggdrasil-go/src/address" 9 | ) 10 | 11 | func decodeKey(input string) ed25519.PublicKey { 12 | keyData, _ := hex.DecodeString(input) 13 | return ed25519.PrivateKey(keyData).Public().(ed25519.PublicKey) 14 | } 15 | 16 | // Get the subnet information from PublicKey 17 | func SubnetFromKey(inputString string) *net.IPNet { 18 | key := decodeKey(inputString) 19 | 20 | snet := address.SubnetForKey(key) 21 | ipnet := net.IPNet{ 22 | IP: append(snet[:], 0, 0, 0, 0, 0, 0, 0, 0), 23 | Mask: net.CIDRMask(len(snet)*8, 128), 24 | } 25 | 26 | return &ipnet 27 | } 28 | 29 | // Get the address information from PublicKey 30 | func AddressFromKey(inputString string) *net.IP { 31 | key := decodeKey(inputString) 32 | 33 | addr := address.AddrForKey(key) 34 | ip := net.IP(addr[:]) 35 | return &ip 36 | } 37 | --------------------------------------------------------------------------------