From ff44417decc3e7f9ad702b2c67b1cfa6d4739785 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 1 Jul 2021 08:04:01 -0500 Subject: [PATCH 001/345] listen for SIGHUP, restart node (reload config file, listen for stdin again, etc) if we receive one --- cmd/yggdrasil/main.go | 112 +++++++++++++++++++++++++++++++++--------- 1 file changed, 89 insertions(+), 23 deletions(-) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 55e6b261..84b0b11e 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "context" "crypto/ed25519" "encoding/hex" "encoding/json" @@ -41,15 +42,15 @@ type node struct { admin *admin.AdminSocket } -func readConfig(log *log.Logger, useconf *bool, useconffile *string, normaliseconf *bool) *config.NodeConfig { +func readConfig(log *log.Logger, useconf bool, useconffile string, normaliseconf bool) *config.NodeConfig { // Use a configuration file. If -useconf, the configuration will be read // from stdin. If -useconffile, the configuration will be read from the // filesystem. var conf []byte var err error - if *useconffile != "" { + if useconffile != "" { // Read the file from the filesystem - conf, err = ioutil.ReadFile(*useconffile) + conf, err = ioutil.ReadFile(useconffile) } else { // Read the file from stdin. conf, err = ioutil.ReadAll(os.Stdin) @@ -180,9 +181,21 @@ func setLogLevel(loglevel string, logger *log.Logger) { } } -// The main function is responsible for configuring and starting Yggdrasil. -func main() { - // Configure the command line parameters. +type yggArgs struct { + genconf bool + useconf bool + useconffile string + normaliseconf bool + confjson bool + autoconf bool + ver bool + logto string + getaddr bool + getsnet bool + loglevel string +} + +func getArgs() yggArgs { genconf := flag.Bool("genconf", false, "print a new config to stdout") useconf := flag.Bool("useconf", false, "read HJSON/JSON config from stdin") useconffile := flag.String("useconffile", "", "read HJSON/JSON config from specified file path") @@ -195,10 +208,43 @@ func main() { getsnet := flag.Bool("subnet", false, "returns the IPv6 subnet as derived from the supplied configuration") loglevel := flag.String("loglevel", "info", "loglevel to enable") flag.Parse() + return yggArgs{ + genconf: *genconf, + useconf: *useconf, + useconffile: *useconffile, + normaliseconf: *normaliseconf, + confjson: *confjson, + autoconf: *autoconf, + ver: *ver, + logto: *logto, + getaddr: *getaddr, + getsnet: *getsnet, + loglevel: *loglevel, + } +} + +// The main function is responsible for configuring and starting Yggdrasil. +func run(args yggArgs, ctx context.Context, done chan struct{}) { + defer close(done) + // Configure the command line parameters. + /* + genconf := flag.Bool("genconf", false, "print a new config to stdout") + useconf := flag.Bool("useconf", false, "read HJSON/JSON config from stdin") + useconffile := flag.String("useconffile", "", "read HJSON/JSON config from specified file path") + normaliseconf := flag.Bool("normaliseconf", false, "use in combination with either -useconf or -useconffile, outputs your configuration normalised") + confjson := flag.Bool("json", false, "print configuration from -genconf or -normaliseconf as JSON instead of HJSON") + autoconf := flag.Bool("autoconf", false, "automatic mode (dynamic IP, peer with IPv6 neighbors)") + ver := flag.Bool("version", false, "prints the version of this build") + logto := flag.String("logto", "stdout", "file path to log to, \"syslog\" or \"stdout\"") + getaddr := flag.Bool("address", false, "returns the IPv6 address as derived from the supplied configuration") + getsnet := flag.Bool("subnet", false, "returns the IPv6 subnet as derived from the supplied configuration") + loglevel := flag.String("loglevel", "info", "loglevel to enable") + flag.Parse() + */ // Create a new logger that logs output to stdout. var logger *log.Logger - switch *logto { + switch args.logto { case "stdout": logger = log.New(os.Stdout, "", log.Flags()) case "syslog": @@ -206,7 +252,7 @@ func main() { logger = log.New(syslogger, "", log.Flags()) } default: - if logfd, err := os.OpenFile(*logto, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err == nil { + if logfd, err := os.OpenFile(args.logto, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err == nil { logger = log.New(logfd, "", log.Flags()) } } @@ -215,33 +261,33 @@ func main() { logger.Warnln("Logging defaulting to stdout") } - if *normaliseconf { + if args.normaliseconf { setLogLevel("error", logger) } else { - setLogLevel(*loglevel, logger) + setLogLevel(args.loglevel, logger) } var cfg *config.NodeConfig var err error switch { - case *ver: + case args.ver: fmt.Println("Build name:", version.BuildName()) fmt.Println("Build version:", version.BuildVersion()) return - case *autoconf: + case args.autoconf: // Use an autoconf-generated config, this will give us random keys and // port numbers, and will use an automatically selected TUN/TAP interface. cfg = defaults.GenerateConfig() - case *useconffile != "" || *useconf: + case args.useconffile != "" || args.useconf: // Read the configuration from either stdin or from the filesystem - cfg = readConfig(logger, useconf, useconffile, normaliseconf) + cfg = readConfig(logger, args.useconf, args.useconffile, args.normaliseconf) // If the -normaliseconf option was specified then remarshal the above // configuration and print it back to stdout. This lets the user update // their configuration file with newly mapped names (like above) or to // convert from plain JSON to commented HJSON. - if *normaliseconf { + if args.normaliseconf { var bs []byte - if *confjson { + if args.confjson { bs, err = json.MarshalIndent(cfg, "", " ") } else { bs, err = hjson.Marshal(cfg) @@ -252,9 +298,9 @@ func main() { fmt.Println(string(bs)) return } - case *genconf: + case args.genconf: // Generate a new configuration and print it to stdout. - fmt.Println(doGenconf(*confjson)) + fmt.Println(doGenconf(args.confjson)) default: // No flags were provided, therefore print the list of flags to stdout. flag.PrintDefaults() @@ -273,14 +319,14 @@ func main() { return nil } switch { - case *getaddr: + case args.getaddr: if key := getNodeKey(); key != nil { addr := address.AddrForKey(key) ip := net.IP(addr[:]) fmt.Println(ip.String()) } return - case *getsnet: + case args.getsnet: if key := getNodeKey(); key != nil { snet := address.SubnetForKey(key) ipnet := net.IPNet{ @@ -337,10 +383,8 @@ func main() { logger.Infof("Your IPv6 address is %s", address.String()) logger.Infof("Your IPv6 subnet is %s", subnet.String()) // Catch interrupts from the operating system to exit gracefully. - c := make(chan os.Signal, 1) - signal.Notify(c, os.Interrupt, syscall.SIGTERM) + <-ctx.Done() // Capture the service being stopped on Windows. - <-c minwinsvc.SetOnExit(n.shutdown) n.shutdown() } @@ -351,3 +395,25 @@ func (n *node) shutdown() { _ = n.tuntap.Stop() n.core.Stop() } + +func main() { + args := getArgs() + hup := make(chan os.Signal, 1) + signal.Notify(hup, os.Interrupt, syscall.SIGHUP) + term := make(chan os.Signal, 1) + signal.Notify(term, os.Interrupt, syscall.SIGTERM) + for { + done := make(chan struct{}) + ctx, cancel := context.WithCancel(context.Background()) + go run(args, ctx, done) + select { + case <-hup: + cancel() + <-done + case <-term: + cancel() + <-done + return + } + } +} From df44b0227b743ef2fbfed01a2b32340843565f52 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 1 Jul 2021 08:54:14 -0500 Subject: [PATCH 002/345] disable SIGHUP handling for now --- cmd/yggdrasil/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 84b0b11e..c8165175 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -399,7 +399,7 @@ func (n *node) shutdown() { func main() { args := getArgs() hup := make(chan os.Signal, 1) - signal.Notify(hup, os.Interrupt, syscall.SIGHUP) + //signal.Notify(hup, os.Interrupt, syscall.SIGHUP) term := make(chan os.Signal, 1) signal.Notify(term, os.Interrupt, syscall.SIGTERM) for { From b07caa1e0ac7208be2a4b93c5a219e90caac77e5 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 1 Jul 2021 19:32:55 -0500 Subject: [PATCH 003/345] add first draft of changelog --- CHANGELOG.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 856f1cea..50f91dd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,32 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - in case of vulnerabilities. --> +## [0.4.0] - 2021-07-04 +### Added +- Connections to TLS peers will now pin the public ed25519 key used in the TLS handshake, or check that the handshake key matches the existing pinned key for that peer (if a key was pinned) + +### Changed +- This version is backwards incompatible with previous versions of Yggdrasil. The wire protocol version number, exchanged as part of the peer setup handshake, has been increased to 0.4. Nodes running this version will **not** be able to peer with earlier versions of Yggdrasil. Please note that **the network may be temporarily unstable** while infrastructure is being upgraded to the new release. Please also note that nodes may be removed from the public peers repository if they do not upgrade within some reasonable amount of time (think days or weeks, not months), and a large fraction of nodes on the public peers list may be unusable (offline or running an old and incompatible version) until that cleanup happens +- IP addresses are derived from ed25519 public (signing) keys. Previously, addresses were derived from a hash of X25519 (Diffie-Hellman) keys. Note that this means **all node addresses have changed with respect to previous releases**, so any existing services will be hosted at new addresses. The services page of the main repo has been updated to only list services in the new v0.4 network. Service operators are encouraged to submit a PR if they wish to be (re-)added to the list +- Link-local peers from multicast peer discovery will now connect over TLS. This is part of a general effort to encourage peering over TLS by default. Note that traffic is encrypted end-to-end regardless of how peer connections are established +- Multicast peer discovery is now more configurable. There are separate configuration options to control if beacons are sent, what port to listen on for incoming connections (if sending beacons), and whether or not to listen for beacons from other nodes (and open connections when receiving a beacon). Each configuration entry in the list specifies a regular expression to match against interface names. If an interface matches multiple regex in the list, it will use the settings for the first entry in the list that it matches with +- `socks://` peers now expect the destination endpoint to be a `tls://` listener +- The configuration file format has been updated. Among other things, there is now a single `PublicKey` and `PrivateKey` pair, both corresponding to ed25519 keys (since nodes no longer have a permanent X25519 key pair) +- Many of the admin functions available over `yggdrasilctl` have been changed or removed as part of rewrites to the code. The list of available functions will likely be expanded in future releases +- The session and routing code has been redesigned and rewritten as a [standalone library](https://github.com/Arceliar/ironwood). We expect to see reduced bandwidth use and improved reliability with the new design, especially in mobile networks. This is still an early work-in-progress, so the code hasn't been as well tested or optimized as the old code base. Please bear with us for these next few releases as we work through any bugs or issues +- Cryptographic sessions no longer use a single shared (ephemeral) secret for the entire life of the session. Keys are now rotated regularly for ongoing sessions (both nodes will rotate keys at least once per round trip exchange of traffic, which is arguably *too* aggressive, we may throttle this somehow in a future release) +- Source routing has been added. Under normal circumstances, this is what is used to forward session traffic (e.g. the user's IPv6 traffic) +- DHT-based routing has been added. This is used when the sender does not know a source route to the destination. Forwarding through the DHT is less efficient, but the only information that it requires the sender to know is the destination node's (static) key. This is primarily used during the key exchange at session setup, or as a temporary fallback when a source route fails due to changes in the network +- The greedy routing scheme, used to forward all traffic in previous releases, is now only used for protocol traffic (i.e. DHT setup and source route discovery) + +### Removed +- TunnelRouting (aka cryptokey routing) has been removed. We recommend tunneling an existing standard over Yggdrasil instead (e.g. `ip6gre` and `ip6gretap`) +- SessionFirewall has been removed. This was never a true firewall, it was simply a way to prevent a node from being flooded with unwanted sessions. The new code base needs to address that problem in other ways. Users who want a firewall or other packet filter should configure something supported by their OS (e.g. `ip6tables`) +- SIGHUP handling has been removed. SIGHUP will be handled normally (by exiting) instead of attempting to reload (parts of) the config file +- The whitepaper (and the rest of the doc folder) has been removed. This documentation was outdated since the routing code as been rewritten. New documentation will likely appear in a future release +- `cmd/yggrasilsim` has been removed. Since the routing code is now a separate library, it probably makes more sense to rewrite this as part of the library test code (or otherwise keep it separate from this repo) +- DHT lookups have been removed. This means there's nothing in the protocol that inherently makes it possible to crawl through the network. That said, `yggdrasilctl` exposes several remote `debug` functions, which make it possible to continue crawling the network. These will also be removed in a future release, if/when we're reasonably confident that things are working as intended + ## [0.3.16] - 2021-03-18 ### Added - New simulation code under `cmd/yggdrasilsim` (work-in-progress) From 9239ed70e472a8d7fc3bda279fd65e7be98dcf3b Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 1 Jul 2021 20:06:05 -0500 Subject: [PATCH 004/345] changelog revisions --- CHANGELOG.md | 68 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50f91dd9..c4c82d3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,29 +27,59 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [0.4.0] - 2021-07-04 ### Added -- Connections to TLS peers will now pin the public ed25519 key used in the TLS handshake, or check that the handshake key matches the existing pinned key for that peer (if a key was pinned) +- TLS connections now use public key pinning + - If no public key was already pinned, then the public key received as part of the TLS handshake is pinned to the connection + - The public key received as part of the handshake is checked against the pinned keys, and if no match is found, the connection is rejected ### Changed -- This version is backwards incompatible with previous versions of Yggdrasil. The wire protocol version number, exchanged as part of the peer setup handshake, has been increased to 0.4. Nodes running this version will **not** be able to peer with earlier versions of Yggdrasil. Please note that **the network may be temporarily unstable** while infrastructure is being upgraded to the new release. Please also note that nodes may be removed from the public peers repository if they do not upgrade within some reasonable amount of time (think days or weeks, not months), and a large fraction of nodes on the public peers list may be unusable (offline or running an old and incompatible version) until that cleanup happens -- IP addresses are derived from ed25519 public (signing) keys. Previously, addresses were derived from a hash of X25519 (Diffie-Hellman) keys. Note that this means **all node addresses have changed with respect to previous releases**, so any existing services will be hosted at new addresses. The services page of the main repo has been updated to only list services in the new v0.4 network. Service operators are encouraged to submit a PR if they wish to be (re-)added to the list -- Link-local peers from multicast peer discovery will now connect over TLS. This is part of a general effort to encourage peering over TLS by default. Note that traffic is encrypted end-to-end regardless of how peer connections are established -- Multicast peer discovery is now more configurable. There are separate configuration options to control if beacons are sent, what port to listen on for incoming connections (if sending beacons), and whether or not to listen for beacons from other nodes (and open connections when receiving a beacon). Each configuration entry in the list specifies a regular expression to match against interface names. If an interface matches multiple regex in the list, it will use the settings for the first entry in the list that it matches with -- `socks://` peers now expect the destination endpoint to be a `tls://` listener -- The configuration file format has been updated. Among other things, there is now a single `PublicKey` and `PrivateKey` pair, both corresponding to ed25519 keys (since nodes no longer have a permanent X25519 key pair) -- Many of the admin functions available over `yggdrasilctl` have been changed or removed as part of rewrites to the code. The list of available functions will likely be expanded in future releases -- The session and routing code has been redesigned and rewritten as a [standalone library](https://github.com/Arceliar/ironwood). We expect to see reduced bandwidth use and improved reliability with the new design, especially in mobile networks. This is still an early work-in-progress, so the code hasn't been as well tested or optimized as the old code base. Please bear with us for these next few releases as we work through any bugs or issues -- Cryptographic sessions no longer use a single shared (ephemeral) secret for the entire life of the session. Keys are now rotated regularly for ongoing sessions (both nodes will rotate keys at least once per round trip exchange of traffic, which is arguably *too* aggressive, we may throttle this somehow in a future release) -- Source routing has been added. Under normal circumstances, this is what is used to forward session traffic (e.g. the user's IPv6 traffic) -- DHT-based routing has been added. This is used when the sender does not know a source route to the destination. Forwarding through the DHT is less efficient, but the only information that it requires the sender to know is the destination node's (static) key. This is primarily used during the key exchange at session setup, or as a temporary fallback when a source route fails due to changes in the network -- The greedy routing scheme, used to forward all traffic in previous releases, is now only used for protocol traffic (i.e. DHT setup and source route discovery) +- This version is backwards incompatible with previous versions of Yggdrasil + - The wire protocol version number, exchanged as part of the peer setup handshake, has been increased to 0.4 + - Nodes running this version will **not** be able to peer with earlier versions of Yggdrasil + - Please note that **the network may be temporarily unstable** while infrastructure is being upgraded to the new release + - Please also note that nodes may be removed from the public peers repository if they do not upgrade within some time period after release (perhaps a couple of weeks) +- IP addresses are derived from ed25519 public (signing) keys + - Previously, addresses were derived from a hash of X25519 (Diffie-Hellman) keys + - Note that this means **all node addresses have changed with respect to previous releases**, so any existing services will be hosted at new addresses + - The services page of the main repo has been updated to only list services in the new v0.4 network + - Service operators are encouraged to submit a PR if they wish to be (re-)added to the list +- It is now recommended to peer over TLS + - Link-local peers from multicast peer discovery will now connect over TLS, with the key from the multicast announcement pinned to the connection + - `socks://` peers now expect the destination endpoint to be a `tls://` listener +- Multicast peer discovery is now more configurable + - There are separate configuration options to control if beacons are sent, what port to listen on for incoming connections (if sending beacons), and whether or not to listen for beacons from other nodes (and open connections when receiving a beacon) + - Each configuration entry in the list specifies a regular expression to match against interface names + - If an interface matches multiple regex in the list, it will use the settings for the first entry in the list that it matches with +- The session and routing code has been redesigned and rewritten: + - This is still an early work-in-progress, so the code hasn't been as well tested or optimized as the old code base. Please bear with us for these next few releases as we work through any bugs or issues + - Generally speaking, we expect to see reduced bandwidth use and improved reliability with the new design, especially in mobile networks + - Cryptographic sessions no longer use a single shared (ephemeral) secret for the entire life of the session. Keys are now rotated regularly for ongoing sessions (both nodes will rotate keys at least once per round trip exchange of traffic, which is arguably *too* aggressive, we may throttle this somehow in a future release) + - Source routing has been added. Under normal circumstances, this is what is used to forward session traffic (e.g. the user's IPv6 traffic) + - DHT-based routing has been added. This is used when the sender does not know a source route to the destination. Forwarding through the DHT is less efficient, but the only information that it requires the sender to know is the destination node's (static) key. This is primarily used during the key exchange at session setup, or as a temporary fallback when a source route fails due to changes in the network + - The new DHT design does not support crawling, and does not inherently allow nodes to look up the owner of an arbitrary key. In Yggdrasil, responding to lookups is implemented at the application level, and a response is only sent if the destination key matches the node's IP or /64 prefix + - The greedy routing scheme, used to forward all traffic in previous releases, is now only used for protocol traffic (i.e. DHT setup and source route discovery) + - The code now lives in a [standalone library](https://github.com/Arceliar/ironwood). You are encouraged **not** to use it, as it's still considered pre-alpha, but it's available for those who want to experiment with the new routing algorithm in other contexts +- Many of the admin functions available over `yggdrasilctl` have been changed or removed as part of rewrites to the code + - Several remote `debug` functions have been added temporarily, to allow for crawling and census gathering during the transition to the new version, but we intend to remove this at some point in the (possibly distant) future + - The list of available functions will likely be expanded in future releases +- The configuration file format has been updated in response to the changed/removed features ### Removed -- TunnelRouting (aka cryptokey routing) has been removed. We recommend tunneling an existing standard over Yggdrasil instead (e.g. `ip6gre` and `ip6gretap`) -- SessionFirewall has been removed. This was never a true firewall, it was simply a way to prevent a node from being flooded with unwanted sessions. The new code base needs to address that problem in other ways. Users who want a firewall or other packet filter should configure something supported by their OS (e.g. `ip6tables`) -- SIGHUP handling has been removed. SIGHUP will be handled normally (by exiting) instead of attempting to reload (parts of) the config file -- The whitepaper (and the rest of the doc folder) has been removed. This documentation was outdated since the routing code as been rewritten. New documentation will likely appear in a future release -- `cmd/yggrasilsim` has been removed. Since the routing code is now a separate library, it probably makes more sense to rewrite this as part of the library test code (or otherwise keep it separate from this repo) -- DHT lookups have been removed. This means there's nothing in the protocol that inherently makes it possible to crawl through the network. That said, `yggdrasilctl` exposes several remote `debug` functions, which make it possible to continue crawling the network. These will also be removed in a future release, if/when we're reasonably confident that things are working as intended +- TunnelRouting (aka cryptokey routing) has been removed + - It was too easy to accidentally break routing by capturing the route to peers with the tun adapter + - We recommend tunneling an existing standard over Yggdrasil instead (e.g. `ip6gre` and `ip6gretap`) +- SessionFirewall has been removed + - This was never a true firewall, it was simply a way to prevent a node from being flooded with unwanted sessions, so the name could be misleading and lead to a false sense of security + - Due to design changes, the new code needs to address the possible memory exhaustion attacks in other ways, and a single configurable list no longer makes sense + - Users who want a firewall or other packet filter mechansim should configure something supported by their OS instead (e.g. `ip6tables`) +- SIGHUP handling has been removed + - Previously, we set a custom SIGHUP handler, and used it to reload (parts of) the config file + - It was never obvious which parts could be reloaded while live, and which required the application to be killed and restarted to take effect + - Reloading the config without restarting was also a delicate and bug-prone process, and was distracting from more important developments + - SIGHUP will be handled normally (i.e. by exiting) +- The `doc` folder has been removed + - In light of the routing scheme's redesign and reimplementation, the documentation was out out-of-date + - New documentation may be added in a future release +- `cmd/yggrasilsim` has been removed, and is unlikely to return to this repository ## [0.3.16] - 2021-03-18 ### Added From 9391430bc08e91a99ca7dbc713c3cdcc4a12d66d Mon Sep 17 00:00:00 2001 From: Chris Hills Date: Fri, 2 Jul 2021 12:53:05 +0100 Subject: [PATCH 005/345] Update binary path in systemd service files to match the website. --- contrib/systemd/yggdrasil-default-config.service | 4 ++-- contrib/systemd/yggdrasil.service | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/systemd/yggdrasil-default-config.service b/contrib/systemd/yggdrasil-default-config.service index e9fe45be..b5af52f8 100644 --- a/contrib/systemd/yggdrasil-default-config.service +++ b/contrib/systemd/yggdrasil-default-config.service @@ -9,5 +9,5 @@ After=local-fs.target Type=oneshot Group=yggdrasil StandardOutput=file:/etc/yggdrasil.conf -ExecStart=/usr/bin/yggdrasil -genconf -ExecStartPost=/usr/bin/chmod 0640 /etc/yggdrasil.conf +ExecStart=/usr/local/bin/yggdrasil -genconf +ExecStartPost=/usr/local/bin/chmod 0640 /etc/yggdrasil.conf diff --git a/contrib/systemd/yggdrasil.service b/contrib/systemd/yggdrasil.service index 3002e61b..44afaf2b 100644 --- a/contrib/systemd/yggdrasil.service +++ b/contrib/systemd/yggdrasil.service @@ -12,7 +12,7 @@ ProtectSystem=true SyslogIdentifier=yggdrasil CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW ExecStartPre=+-/sbin/modprobe tun -ExecStart=/usr/bin/yggdrasil -useconffile /etc/yggdrasil.conf +ExecStart=/usr/local/bin/yggdrasil -useconffile /etc/yggdrasil.conf ExecReload=/bin/kill -HUP $MAINPID Restart=always TimeoutStopSec=5 From ccf03847fc701452ad95e11ea502e358c4b1901f Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 2 Jul 2021 23:07:44 +0100 Subject: [PATCH 006/345] Update changelog --- CHANGELOG.md | 55 ++++++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4c82d3e..4487ba25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,58 +27,53 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [0.4.0] - 2021-07-04 ### Added +- New routing scheme, which is backwards incompatible with previous versions of Yggdrasil + - The wire protocol version number, exchanged as part of the peer setup handshake, has been increased to 0.4 + - Nodes running this new version **will not** be able to peer with earlier versions of Yggdrasil + - Please note that **the network may be temporarily unstable** while infrastructure is being upgraded to the new release - TLS connections now use public key pinning - If no public key was already pinned, then the public key received as part of the TLS handshake is pinned to the connection - The public key received as part of the handshake is checked against the pinned keys, and if no match is found, the connection is rejected ### Changed -- This version is backwards incompatible with previous versions of Yggdrasil - - The wire protocol version number, exchanged as part of the peer setup handshake, has been increased to 0.4 - - Nodes running this version will **not** be able to peer with earlier versions of Yggdrasil - - Please note that **the network may be temporarily unstable** while infrastructure is being upgraded to the new release - - Please also note that nodes may be removed from the public peers repository if they do not upgrade within some time period after release (perhaps a couple of weeks) -- IP addresses are derived from ed25519 public (signing) keys +- IP addresses are now derived from ed25519 public (signing) keys - Previously, addresses were derived from a hash of X25519 (Diffie-Hellman) keys - - Note that this means **all node addresses have changed with respect to previous releases**, so any existing services will be hosted at new addresses - - The services page of the main repo has been updated to only list services in the new v0.4 network - - Service operators are encouraged to submit a PR if they wish to be (re-)added to the list + - Importantly, this means that **all internal IPv6 addresses will change with this release** — this will affect anyone running public services or relying on Yggdrasil for remote access - It is now recommended to peer over TLS - - Link-local peers from multicast peer discovery will now connect over TLS, with the key from the multicast announcement pinned to the connection - - `socks://` peers now expect the destination endpoint to be a `tls://` listener + - Link-local peers from multicast peer discovery will now connect over TLS, with the key from the multicast beacon pinned to the connection + - `socks://` peers now expect the destination endpoint to be a `tls://` listener, instead of a `tcp://` listener - Multicast peer discovery is now more configurable - There are separate configuration options to control if beacons are sent, what port to listen on for incoming connections (if sending beacons), and whether or not to listen for beacons from other nodes (and open connections when receiving a beacon) - Each configuration entry in the list specifies a regular expression to match against interface names - If an interface matches multiple regex in the list, it will use the settings for the first entry in the list that it matches with -- The session and routing code has been redesigned and rewritten: - - This is still an early work-in-progress, so the code hasn't been as well tested or optimized as the old code base. Please bear with us for these next few releases as we work through any bugs or issues - - Generally speaking, we expect to see reduced bandwidth use and improved reliability with the new design, especially in mobile networks - - Cryptographic sessions no longer use a single shared (ephemeral) secret for the entire life of the session. Keys are now rotated regularly for ongoing sessions (both nodes will rotate keys at least once per round trip exchange of traffic, which is arguably *too* aggressive, we may throttle this somehow in a future release) +- The session and routing code has been entirely redesigned and rewritten + - This is still an early work-in-progress, so the code hasn't been as well tested or optimized as the old code base — please bear with us for these next few releases as we work through any bugs or issues + - Generally speaking, we expect to see reduced bandwidth use and improved reliability with the new design, especially in cases where nodes move around or change peerings frequently + - Cryptographic sessions no longer use a single shared (ephemeral) secret for the entire life of the session. Keys are now rotated regularly for ongoing sessions (currently rotated at least once per round trip exchange of traffic, subject to change in future releases) - Source routing has been added. Under normal circumstances, this is what is used to forward session traffic (e.g. the user's IPv6 traffic) - DHT-based routing has been added. This is used when the sender does not know a source route to the destination. Forwarding through the DHT is less efficient, but the only information that it requires the sender to know is the destination node's (static) key. This is primarily used during the key exchange at session setup, or as a temporary fallback when a source route fails due to changes in the network - - The new DHT design does not support crawling, and does not inherently allow nodes to look up the owner of an arbitrary key. In Yggdrasil, responding to lookups is implemented at the application level, and a response is only sent if the destination key matches the node's IP or /64 prefix + - The new DHT design is no longer RPC-based, does not support crawling and does not inherently allow nodes to look up the owner of an arbitrary key. Responding to lookups is now implemented at the application level and a response is only sent if the destination key matches the node's `/128` IP or `/64` prefix - The greedy routing scheme, used to forward all traffic in previous releases, is now only used for protocol traffic (i.e. DHT setup and source route discovery) - - The code now lives in a [standalone library](https://github.com/Arceliar/ironwood). You are encouraged **not** to use it, as it's still considered pre-alpha, but it's available for those who want to experiment with the new routing algorithm in other contexts + - The routing logic now lives in a [standalone library](https://github.com/Arceliar/ironwood). You are encouraged **not** to use it, as it's still considered pre-alpha, but it's available for those who want to experiment with the new routing algorithm in other contexts - Many of the admin functions available over `yggdrasilctl` have been changed or removed as part of rewrites to the code - Several remote `debug` functions have been added temporarily, to allow for crawling and census gathering during the transition to the new version, but we intend to remove this at some point in the (possibly distant) future - The list of available functions will likely be expanded in future releases - The configuration file format has been updated in response to the changed/removed features ### Removed -- TunnelRouting (aka cryptokey routing) has been removed - - It was too easy to accidentally break routing by capturing the route to peers with the tun adapter - - We recommend tunneling an existing standard over Yggdrasil instead (e.g. `ip6gre` and `ip6gretap`) -- SessionFirewall has been removed - - This was never a true firewall, it was simply a way to prevent a node from being flooded with unwanted sessions, so the name could be misleading and lead to a false sense of security - - Due to design changes, the new code needs to address the possible memory exhaustion attacks in other ways, and a single configurable list no longer makes sense +- Tunnel routing (a.k.a. crypto-key routing or "CKR") has been removed + - It was far too easy to accidentally break routing altogether by capturing the route to peers with the TUN adapter + - We recommend tunnelling an existing standard over Yggdrasil instead (e.g. `ip6gre`, `ip6gretap` or other encapsulations) + - All `TunnelRouting` configuration options will no longer take effect +- Session firewall has been removed + - This was never a true firewall — it didn't behave like a stateful IP firewall, often allowed return traffic unexpectedly and was simply a way to prevent a node from being flooded with unwanted sessions, so the name could be misleading and usually lead to a false sense of security + - Due to design changes, the new code needs to address the possible memory exhaustion attacks in other ways and a single configurable list no longer makes sense - Users who want a firewall or other packet filter mechansim should configure something supported by their OS instead (e.g. `ip6tables`) -- SIGHUP handling has been removed - - Previously, we set a custom SIGHUP handler, and used it to reload (parts of) the config file - - It was never obvious which parts could be reloaded while live, and which required the application to be killed and restarted to take effect + - All `SessionFirewall` configuration options will no longer take effect +- `SIGHUP` handling to reload the configuration at runtime has been removed + - It was not obvious which parts of the configuration could be reloaded at runtime, and which required the application to be killed and restarted to take effect - Reloading the config without restarting was also a delicate and bug-prone process, and was distracting from more important developments - - SIGHUP will be handled normally (i.e. by exiting) -- The `doc` folder has been removed - - In light of the routing scheme's redesign and reimplementation, the documentation was out out-of-date - - New documentation may be added in a future release + - `SIGHUP` will be handled normally (i.e. by exiting) - `cmd/yggrasilsim` has been removed, and is unlikely to return to this repository ## [0.3.16] - 2021-03-18 From 540e0bc2ce92202745ed49891d8bb3adbe36b749 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 2 Jul 2021 23:11:16 +0100 Subject: [PATCH 007/345] Update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4487ba25..bdb634f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - The new DHT design is no longer RPC-based, does not support crawling and does not inherently allow nodes to look up the owner of an arbitrary key. Responding to lookups is now implemented at the application level and a response is only sent if the destination key matches the node's `/128` IP or `/64` prefix - The greedy routing scheme, used to forward all traffic in previous releases, is now only used for protocol traffic (i.e. DHT setup and source route discovery) - The routing logic now lives in a [standalone library](https://github.com/Arceliar/ironwood). You are encouraged **not** to use it, as it's still considered pre-alpha, but it's available for those who want to experiment with the new routing algorithm in other contexts + - Session MTUs may be slightly lower now, in order to accommodate large packet headers if required - Many of the admin functions available over `yggdrasilctl` have been changed or removed as part of rewrites to the code - Several remote `debug` functions have been added temporarily, to allow for crawling and census gathering during the transition to the new version, but we intend to remove this at some point in the (possibly distant) future - The list of available functions will likely be expanded in future releases @@ -63,7 +64,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Removed - Tunnel routing (a.k.a. crypto-key routing or "CKR") has been removed - It was far too easy to accidentally break routing altogether by capturing the route to peers with the TUN adapter - - We recommend tunnelling an existing standard over Yggdrasil instead (e.g. `ip6gre`, `ip6gretap` or other encapsulations) + - We recommend tunnelling an existing standard over Yggdrasil instead (e.g. `ip6gre`, `ip6gretap` or other similar encapsulations, using Yggdrasil IPv6 addresses as the tunnel endpoints) - All `TunnelRouting` configuration options will no longer take effect - Session firewall has been removed - This was never a true firewall — it didn't behave like a stateful IP firewall, often allowed return traffic unexpectedly and was simply a way to prevent a node from being flooded with unwanted sessions, so the name could be misleading and usually lead to a false sense of security From 4d47ba8bf4815855d75cb2fcac3568aadb8cecad Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 2 Jul 2021 23:21:38 +0100 Subject: [PATCH 008/345] Update README.md --- README.md | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index d1d254a6..a709ae4e 100644 --- a/README.md +++ b/README.md @@ -20,25 +20,11 @@ internet-like topologies. ## Supported Platforms -We actively support the following platforms, and packages are available for -some of the below: +Yggdrasil works on a number of platforms, including Linux, macOS, Ubiquiti +EdgeRouter, VyOS, Windows, FreeBSD, OpenBSD and OpenWrt. -- Linux - - `.deb` and `.rpm` packages are built by CI for Debian and Red Hat-based - distributions - - Arch, Nix, Void packages also available within their respective repositories -- macOS - - `.pkg` packages are built by CI -- Ubiquiti EdgeOS - - `.deb` Vyatta packages are built by CI -- Windows -- FreeBSD -- OpenBSD -- OpenWrt - -Please see our [Platforms](https://yggdrasil-network.github.io/platforms.html) pages for more -specific information about each of our supported platforms, including -installation steps and caveats. +Please see our [Installation](https://yggdrasil-network.github.io/installation.html) +page for more information. You may also find other platform-specific wrappers, scripts or tools in the `contrib` folder. @@ -97,21 +83,18 @@ by giving the Yggdrasil binary the `CAP_NET_ADMIN` capability. ## Documentation -Documentation is available on our [GitHub -Pages](https://yggdrasil-network.github.io) site, or in the base submodule -repository within `doc/yggdrasil-network.github.io`. +Documentation is available on our [GitHub Pages](https://yggdrasil-network.github.io) +site. -- [Configuration file options](https://yggdrasil-network.github.io/configuration.html) -- [Platform-specific documentation](https://yggdrasil-network.github.io/platforms.html) +- [Configuration file](https://yggdrasil-network.github.io/configuration.html) - [Frequently asked questions](https://yggdrasil-network.github.io/faq.html) -- [Admin API documentation](https://yggdrasil-network.github.io/admin.html) - [Version changelog](CHANGELOG.md) ## Community Feel free to join us on our [Matrix channel](https://matrix.to/#/#yggdrasil:matrix.org) at `#yggdrasil:matrix.org` -or in the `#yggdrasil` IRC channel on Freenode. +or in the `#yggdrasil` IRC channel on [libera.chat](https://libera.chat). ## License From f7b91a8f939420f74ce8b911a6690fc961086033 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 2 Jul 2021 23:24:34 +0100 Subject: [PATCH 009/345] Update README.md --- README.md | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index a709ae4e..f1f71d11 100644 --- a/README.md +++ b/README.md @@ -11,23 +11,14 @@ allows pretty much any IPv6-capable application to communicate securely with other Yggdrasil nodes. Yggdrasil does not require you to have IPv6 Internet connectivity - it also works over IPv4. -Although Yggdrasil shares many similarities with -[cjdns](https://github.com/cjdelisle/cjdns), it employs a different routing -algorithm based on a globally-agreed spanning tree and greedy routing in a -metric space, and aims to implement some novel local backpressure routing -techniques. In theory, Yggdrasil should scale well on networks with -internet-like topologies. - ## Supported Platforms Yggdrasil works on a number of platforms, including Linux, macOS, Ubiquiti EdgeRouter, VyOS, Windows, FreeBSD, OpenBSD and OpenWrt. Please see our [Installation](https://yggdrasil-network.github.io/installation.html) -page for more information. - -You may also find other platform-specific wrappers, scripts or tools in the -`contrib` folder. +page for more information. You may also find other platform-specific wrappers, scripts +or tools in the `contrib` folder. ## Building @@ -83,10 +74,10 @@ by giving the Yggdrasil binary the `CAP_NET_ADMIN` capability. ## Documentation -Documentation is available on our [GitHub Pages](https://yggdrasil-network.github.io) -site. +Documentation is available [on our website](https://yggdrasil-network.github.io). -- [Configuration file](https://yggdrasil-network.github.io/configuration.html) +- [Installing Yggdrasil](https://yggdrasil-network.github.io/installation.html) +- [Configuring Yggdrasil](https://yggdrasil-network.github.io/configuration.html) - [Frequently asked questions](https://yggdrasil-network.github.io/faq.html) - [Version changelog](CHANGELOG.md) From 5844079f67de4909c8479221598de73c3a8b6132 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sat, 3 Jul 2021 17:27:00 -0500 Subject: [PATCH 010/345] make sure genconf exits, clean up some commented out code --- cmd/yggdrasil/main.go | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index c8165175..d6d0d1a6 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -226,22 +226,6 @@ func getArgs() yggArgs { // The main function is responsible for configuring and starting Yggdrasil. func run(args yggArgs, ctx context.Context, done chan struct{}) { defer close(done) - // Configure the command line parameters. - /* - genconf := flag.Bool("genconf", false, "print a new config to stdout") - useconf := flag.Bool("useconf", false, "read HJSON/JSON config from stdin") - useconffile := flag.String("useconffile", "", "read HJSON/JSON config from specified file path") - normaliseconf := flag.Bool("normaliseconf", false, "use in combination with either -useconf or -useconffile, outputs your configuration normalised") - confjson := flag.Bool("json", false, "print configuration from -genconf or -normaliseconf as JSON instead of HJSON") - autoconf := flag.Bool("autoconf", false, "automatic mode (dynamic IP, peer with IPv6 neighbors)") - ver := flag.Bool("version", false, "prints the version of this build") - logto := flag.String("logto", "stdout", "file path to log to, \"syslog\" or \"stdout\"") - getaddr := flag.Bool("address", false, "returns the IPv6 address as derived from the supplied configuration") - getsnet := flag.Bool("subnet", false, "returns the IPv6 subnet as derived from the supplied configuration") - loglevel := flag.String("loglevel", "info", "loglevel to enable") - flag.Parse() - */ - // Create a new logger that logs output to stdout. var logger *log.Logger switch args.logto { @@ -301,6 +285,7 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) { case args.genconf: // Generate a new configuration and print it to stdout. fmt.Println(doGenconf(args.confjson)) + return default: // No flags were provided, therefore print the list of flags to stdout. flag.PrintDefaults() @@ -414,6 +399,8 @@ func main() { cancel() <-done return + case <-done: + return } } } From 2fc34bbd5a17e002b323017de5d14a69c5940421 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 4 Jul 2021 09:26:17 +0100 Subject: [PATCH 011/345] Revert "Merge pull request #796 from Chaz6/update-systemd-files" This reverts commit 88bd098f91fdf7ca693018ab7982f680b5c9db92, reversing changes made to 4d798a34940af2eacba73f274ea9260fb57e8452. --- contrib/systemd/yggdrasil-default-config.service | 4 ++-- contrib/systemd/yggdrasil.service | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/systemd/yggdrasil-default-config.service b/contrib/systemd/yggdrasil-default-config.service index b5af52f8..e9fe45be 100644 --- a/contrib/systemd/yggdrasil-default-config.service +++ b/contrib/systemd/yggdrasil-default-config.service @@ -9,5 +9,5 @@ After=local-fs.target Type=oneshot Group=yggdrasil StandardOutput=file:/etc/yggdrasil.conf -ExecStart=/usr/local/bin/yggdrasil -genconf -ExecStartPost=/usr/local/bin/chmod 0640 /etc/yggdrasil.conf +ExecStart=/usr/bin/yggdrasil -genconf +ExecStartPost=/usr/bin/chmod 0640 /etc/yggdrasil.conf diff --git a/contrib/systemd/yggdrasil.service b/contrib/systemd/yggdrasil.service index 44afaf2b..3002e61b 100644 --- a/contrib/systemd/yggdrasil.service +++ b/contrib/systemd/yggdrasil.service @@ -12,7 +12,7 @@ ProtectSystem=true SyslogIdentifier=yggdrasil CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW ExecStartPre=+-/sbin/modprobe tun -ExecStart=/usr/local/bin/yggdrasil -useconffile /etc/yggdrasil.conf +ExecStart=/usr/bin/yggdrasil -useconffile /etc/yggdrasil.conf ExecReload=/bin/kill -HUP $MAINPID Restart=always TimeoutStopSec=5 From f990a56046646ef97322c910b8cd057e99ad035d Mon Sep 17 00:00:00 2001 From: Arceliar Date: Mon, 5 Jul 2021 13:14:12 -0500 Subject: [PATCH 012/345] have the core wrap and export the underlying PacketConn, move IPv6 ReadWriteCloser wrapper logic to a separate package --- cmd/yggdrasil/main.go | 4 +- src/core/api.go | 42 +------ src/core/core.go | 62 ++++++++- src/core/link.go | 2 +- src/core/nodeinfo.go | 4 +- src/core/proto.go | 9 +- src/core/types.go | 7 -- src/{core => ipv6rwc}/icmpv6.go | 2 +- src/{core/keystore.go => ipv6rwc/ipv6rwc.go} | 125 +++++++++++++------ src/tuntap/iface.go | 4 +- src/tuntap/tun.go | 19 ++- 11 files changed, 170 insertions(+), 110 deletions(-) rename src/{core => ipv6rwc}/icmpv6.go (99%) rename src/{core/keystore.go => ipv6rwc/ipv6rwc.go} (77%) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index d6d0d1a6..95d40151 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -29,6 +29,7 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/defaults" "github.com/yggdrasil-network/yggdrasil-go/src/core" + "github.com/yggdrasil-network/yggdrasil-go/src/ipv6rwc" "github.com/yggdrasil-network/yggdrasil-go/src/multicast" "github.com/yggdrasil-network/yggdrasil-go/src/tuntap" "github.com/yggdrasil-network/yggdrasil-go/src/version" @@ -353,7 +354,8 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) { } n.multicast.SetupAdminHandlers(n.admin) // Start the TUN/TAP interface - if err := n.tuntap.Init(&n.core, cfg, logger, nil); err != nil { + rwc := ipv6rwc.NewReadWriteCloser(&n.core) + if err := n.tuntap.Init(rwc, cfg, logger, nil); err != nil { logger.Errorln("An error occurred initialising TUN/TAP:", err) } else if err := n.tuntap.Start(); err != nil { logger.Errorln("An error occurred starting TUN/TAP:", err) diff --git a/src/core/api.go b/src/core/api.go index 05d9f36f..6b219340 100644 --- a/src/core/api.go +++ b/src/core/api.go @@ -48,7 +48,7 @@ type Session struct { func (c *Core) GetSelf() Self { var self Self - s := c.pc.PacketConn.Debug.GetSelf() + s := c.PacketConn.PacketConn.Debug.GetSelf() self.Key = s.Key self.Root = s.Root self.Coords = s.Coords @@ -63,7 +63,7 @@ func (c *Core) GetPeers() []Peer { names[info.conn] = info.lname } c.links.mutex.Unlock() - ps := c.pc.PacketConn.Debug.GetPeers() + ps := c.PacketConn.PacketConn.Debug.GetPeers() for _, p := range ps { var info Peer info.Key = p.Key @@ -81,7 +81,7 @@ func (c *Core) GetPeers() []Peer { func (c *Core) GetDHT() []DHTEntry { var dhts []DHTEntry - ds := c.pc.PacketConn.Debug.GetDHT() + ds := c.PacketConn.PacketConn.Debug.GetDHT() for _, d := range ds { var info DHTEntry info.Key = d.Key @@ -94,7 +94,7 @@ func (c *Core) GetDHT() []DHTEntry { func (c *Core) GetPaths() []PathEntry { var paths []PathEntry - ps := c.pc.PacketConn.Debug.GetPaths() + ps := c.PacketConn.PacketConn.Debug.GetPaths() for _, p := range ps { var info PathEntry info.Key = p.Key @@ -106,7 +106,7 @@ func (c *Core) GetPaths() []PathEntry { func (c *Core) GetSessions() []Session { var sessions []Session - ss := c.pc.Debug.GetSessions() + ss := c.PacketConn.Debug.GetSessions() for _, s := range ss { var info Session info.Key = s.Key @@ -239,38 +239,6 @@ func (c *Core) PublicKey() ed25519.PublicKey { return c.public } -func (c *Core) MaxMTU() uint64 { - return c.store.maxSessionMTU() -} - -func (c *Core) SetMTU(mtu uint64) { - if mtu < 1280 { - mtu = 1280 - } - c.store.mutex.Lock() - c.store.mtu = mtu - c.store.mutex.Unlock() -} - -func (c *Core) MTU() uint64 { - c.store.mutex.Lock() - mtu := c.store.mtu - c.store.mutex.Unlock() - return mtu -} - -// Implement io.ReadWriteCloser - -func (c *Core) Read(p []byte) (n int, err error) { - n, err = c.store.readPC(p) - return -} - -func (c *Core) Write(p []byte) (n int, err error) { - n, err = c.store.writePC(p) - return -} - func (c *Core) Close() error { c.Stop() return nil diff --git a/src/core/core.go b/src/core/core.go index 89d49177..ac0ea1f0 100644 --- a/src/core/core.go +++ b/src/core/core.go @@ -7,10 +7,12 @@ import ( "errors" "fmt" "io/ioutil" + "net" "net/url" "time" - iw "github.com/Arceliar/ironwood/encrypted" + iwe "github.com/Arceliar/ironwood/encrypted" + iwt "github.com/Arceliar/ironwood/types" "github.com/Arceliar/phony" "github.com/gologme/log" @@ -26,13 +28,12 @@ type Core struct { // We're going to keep our own copy of the provided config - that way we can // guarantee that it will be covered by the mutex phony.Inbox - pc *iw.PacketConn + *iwe.PacketConn config *config.NodeConfig // Config secret ed25519.PrivateKey public ed25519.PublicKey links links proto protoHandler - store keyStore log *log.Logger addPeerTimer *time.Timer ctx context.Context @@ -62,9 +63,8 @@ func (c *Core) _init() error { c.public = c.secret.Public().(ed25519.PublicKey) // TODO check public against current.PublicKey, error if they don't match - c.pc, err = iw.NewPacketConn(c.secret) + c.PacketConn, err = iwe.NewPacketConn(c.secret) c.ctx, c.ctxCancel = context.WithCancel(context.Background()) - c.store.init(c) c.proto.init(c) if err := c.proto.nodeinfo.setNodeInfo(c.config.NodeInfo, c.config.NodeInfoPrivacy); err != nil { return fmt.Errorf("setNodeInfo: %w", err) @@ -168,7 +168,7 @@ func (c *Core) Stop() { func (c *Core) _stop() { c.log.Infoln("Stopping...") c.ctxCancel() - c.pc.Close() + c.PacketConn.Close() // TODO make c.Close() do the right thing (act like c.Stop()) if c.addPeerTimer != nil { c.addPeerTimer.Stop() c.addPeerTimer = nil @@ -181,3 +181,53 @@ func (c *Core) _stop() { */ c.log.Infoln("Stopped") } + +func (c *Core) MTU() uint64 { + const sessionTypeOverhead = 1 + return c.PacketConn.MTU() - sessionTypeOverhead +} + +func (c *Core) ReadFrom(p []byte) (n int, from net.Addr, err error) { + buf := make([]byte, c.PacketConn.MTU(), 65535) + for { + bs := buf + n, from, err = c.PacketConn.ReadFrom(bs) + if err != nil { + return 0, from, err + } + if n == 0 { + continue + } + switch bs[0] { + case typeSessionTraffic: + // This is what we want to handle here + case typeSessionProto: + var key keyArray + copy(key[:], from.(iwt.Addr)) + data := append([]byte(nil), bs[1:n]...) + c.proto.handleProto(nil, key, data) + continue + default: + continue + } + bs = bs[1:n] + copy(p, bs) + if len(p) < len(bs) { + n = len(p) + } else { + n = len(bs) + } + return + } +} + +func (c *Core) WriteTo(p []byte, addr net.Addr) (n int, err error) { + buf := make([]byte, 0, 65535) + buf = append(buf, typeSessionTraffic) + buf = append(buf, p...) + n, err = c.PacketConn.WriteTo(buf, addr) + if n > 0 { + n -= 1 + } + return +} diff --git a/src/core/link.go b/src/core/link.go index 165b18b2..ccab9219 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -230,7 +230,7 @@ func (intf *link) handler() (chan struct{}, error) { intf.links.core.log.Infof("Connected %s: %s, source %s", strings.ToUpper(intf.info.linkType), themString, intf.info.local) // Run the handler - err = intf.links.core.pc.HandleConn(ed25519.PublicKey(intf.info.key[:]), intf.conn) + err = intf.links.core.HandleConn(ed25519.PublicKey(intf.info.key[:]), intf.conn) // TODO don't report an error if it's just a 'use of closed network connection' if err != nil { intf.links.core.log.Infof("Disconnected %s: %s, source %s; error: %s", diff --git a/src/core/nodeinfo.go b/src/core/nodeinfo.go index 30644710..90153118 100644 --- a/src/core/nodeinfo.go +++ b/src/core/nodeinfo.go @@ -129,7 +129,7 @@ func (m *nodeinfo) _sendReq(key keyArray, callback func(nodeinfo NodeInfoPayload if callback != nil { m._addCallback(key, callback) } - _, _ = m.proto.core.pc.WriteTo([]byte{typeSessionProto, typeProtoNodeInfoRequest}, iwt.Addr(key[:])) + _, _ = m.proto.core.WriteTo([]byte{typeSessionProto, typeProtoNodeInfoRequest}, iwt.Addr(key[:])) } func (m *nodeinfo) handleReq(from phony.Actor, key keyArray) { @@ -146,7 +146,7 @@ func (m *nodeinfo) handleRes(from phony.Actor, key keyArray, info NodeInfoPayloa func (m *nodeinfo) _sendRes(key keyArray) { bs := append([]byte{typeSessionProto, typeProtoNodeInfoResponse}, m._getNodeInfo()...) - _, _ = m.proto.core.pc.WriteTo(bs, iwt.Addr(key[:])) + _, _ = m.proto.core.WriteTo(bs, iwt.Addr(key[:])) } // Admin socket stuff diff --git a/src/core/proto.go b/src/core/proto.go index 557ac1d5..f9d12c8a 100644 --- a/src/core/proto.go +++ b/src/core/proto.go @@ -1,6 +1,7 @@ package core import ( + "crypto/ed25519" "encoding/hex" "encoding/json" "errors" @@ -29,6 +30,8 @@ type reqInfo struct { timer *time.Timer // time.AfterFunc cleanup } +type keyArray [ed25519.PublicKeySize]byte + type protoHandler struct { phony.Inbox core *Core @@ -149,7 +152,7 @@ func (p *protoHandler) _handleGetPeersRequest(key keyArray) { for _, pinfo := range peers { tmp := append(bs, pinfo.Key[:]...) const responseOverhead = 2 // 1 debug type, 1 getpeers type - if uint64(len(tmp))+responseOverhead > p.core.store.maxSessionMTU() { + if uint64(len(tmp))+responseOverhead > p.core.MTU() { break } bs = tmp @@ -191,7 +194,7 @@ func (p *protoHandler) _handleGetDHTRequest(key keyArray) { for _, dinfo := range dinfos { tmp := append(bs, dinfo.Key[:]...) const responseOverhead = 2 // 1 debug type, 1 getdht type - if uint64(len(tmp))+responseOverhead > p.core.store.maxSessionMTU() { + if uint64(len(tmp))+responseOverhead > p.core.MTU() { break } bs = tmp @@ -209,7 +212,7 @@ func (p *protoHandler) _handleGetDHTResponse(key keyArray, bs []byte) { func (p *protoHandler) _sendDebug(key keyArray, dType uint8, data []byte) { bs := append([]byte{typeSessionProto, typeProtoDebug, dType}, data...) - _, _ = p.core.pc.WriteTo(bs, iwt.Addr(key[:])) + _, _ = p.core.WriteTo(bs, iwt.Addr(key[:])) } // Admin socket stuff diff --git a/src/core/types.go b/src/core/types.go index e325b55e..258563a1 100644 --- a/src/core/types.go +++ b/src/core/types.go @@ -1,12 +1,5 @@ package core -// Out-of-band packet types -const ( - typeKeyDummy = iota // nolint:deadcode,varcheck - typeKeyLookup - typeKeyResponse -) - // In-band packet types const ( typeSessionDummy = iota // nolint:deadcode,varcheck diff --git a/src/core/icmpv6.go b/src/ipv6rwc/icmpv6.go similarity index 99% rename from src/core/icmpv6.go rename to src/ipv6rwc/icmpv6.go index d15fbbcb..8faf1d51 100644 --- a/src/core/icmpv6.go +++ b/src/ipv6rwc/icmpv6.go @@ -1,4 +1,4 @@ -package core +package ipv6rwc // The ICMPv6 module implements functions to easily create ICMPv6 // packets. These functions, when mixed with the built-in Go IPv6 diff --git a/src/core/keystore.go b/src/ipv6rwc/ipv6rwc.go similarity index 77% rename from src/core/keystore.go rename to src/ipv6rwc/ipv6rwc.go index 21fb8459..1c715f0f 100644 --- a/src/core/keystore.go +++ b/src/ipv6rwc/ipv6rwc.go @@ -1,4 +1,4 @@ -package core +package ipv6rwc import ( "crypto/ed25519" @@ -14,14 +14,22 @@ import ( iwt "github.com/Arceliar/ironwood/types" "github.com/yggdrasil-network/yggdrasil-go/src/address" + "github.com/yggdrasil-network/yggdrasil-go/src/core" ) const keyStoreTimeout = 2 * time.Minute +// Out-of-band packet types +const ( + typeKeyDummy = iota // nolint:deadcode,varcheck + typeKeyLookup + typeKeyResponse +) + type keyArray [ed25519.PublicKeySize]byte type keyStore struct { - core *Core + core *core.Core address address.Address subnet address.Subnet mutex sync.Mutex @@ -45,11 +53,11 @@ type buffer struct { timeout *time.Timer } -func (k *keyStore) init(core *Core) { - k.core = core - k.address = *address.AddrForKey(k.core.public) - k.subnet = *address.SubnetForKey(k.core.public) - if err := k.core.pc.SetOutOfBandHandler(k.oobHandler); err != nil { +func (k *keyStore) init(c *core.Core) { + k.core = c + k.address = *address.AddrForKey(k.core.PublicKey()) + k.subnet = *address.SubnetForKey(k.core.PublicKey()) + if err := k.core.SetOutOfBandHandler(k.oobHandler); err != nil { err = fmt.Errorf("tun.core.SetOutOfBandHander: %w", err) panic(err) } @@ -66,7 +74,7 @@ func (k *keyStore) sendToAddress(addr address.Address, bs []byte) { if info := k.addrToInfo[addr]; info != nil { k.resetTimeout(info) k.mutex.Unlock() - _, _ = k.core.pc.WriteTo(bs, iwt.Addr(info.key[:])) + _, _ = k.core.WriteTo(bs, iwt.Addr(info.key[:])) } else { var buf *buffer if buf = k.addrBuffer[addr]; buf == nil { @@ -95,7 +103,7 @@ func (k *keyStore) sendToSubnet(subnet address.Subnet, bs []byte) { if info := k.subnetToInfo[subnet]; info != nil { k.resetTimeout(info) k.mutex.Unlock() - _, _ = k.core.pc.WriteTo(bs, iwt.Addr(info.key[:])) + _, _ = k.core.WriteTo(bs, iwt.Addr(info.key[:])) } else { var buf *buffer if buf = k.subnetBuffer[subnet]; buf == nil { @@ -135,11 +143,11 @@ func (k *keyStore) update(key ed25519.PublicKey) *keyInfo { k.resetTimeout(info) k.mutex.Unlock() if buf := k.addrBuffer[info.address]; buf != nil { - k.core.pc.WriteTo(buf.packet, iwt.Addr(info.key[:])) + k.core.WriteTo(buf.packet, iwt.Addr(info.key[:])) delete(k.addrBuffer, info.address) } if buf := k.subnetBuffer[info.subnet]; buf != nil { - k.core.pc.WriteTo(buf.packet, iwt.Addr(info.key[:])) + k.core.WriteTo(buf.packet, iwt.Addr(info.key[:])) delete(k.subnetBuffer, info.subnet) } } else { @@ -191,46 +199,29 @@ func (k *keyStore) oobHandler(fromKey, toKey ed25519.PublicKey, data []byte) { } func (k *keyStore) sendKeyLookup(partial ed25519.PublicKey) { - sig := ed25519.Sign(k.core.secret, partial[:]) + sig := ed25519.Sign(k.core.PrivateKey(), partial[:]) bs := append([]byte{typeKeyLookup}, sig...) - _ = k.core.pc.SendOutOfBand(partial, bs) + _ = k.core.SendOutOfBand(partial, bs) } func (k *keyStore) sendKeyResponse(dest ed25519.PublicKey) { - sig := ed25519.Sign(k.core.secret, dest[:]) + sig := ed25519.Sign(k.core.PrivateKey(), dest[:]) bs := append([]byte{typeKeyResponse}, sig...) - _ = k.core.pc.SendOutOfBand(dest, bs) -} - -func (k *keyStore) maxSessionMTU() uint64 { - const sessionTypeOverhead = 1 - return k.core.pc.MTU() - sessionTypeOverhead + _ = k.core.SendOutOfBand(dest, bs) } func (k *keyStore) readPC(p []byte) (int, error) { - buf := make([]byte, k.core.pc.MTU(), 65535) + buf := make([]byte, k.core.MTU(), 65535) for { bs := buf - n, from, err := k.core.pc.ReadFrom(bs) + n, from, err := k.core.ReadFrom(bs) if err != nil { return n, err } if n == 0 { continue } - switch bs[0] { - case typeSessionTraffic: - // This is what we want to handle here - case typeSessionProto: - var key keyArray - copy(key[:], from.(iwt.Addr)) - data := append([]byte(nil), bs[1:n]...) - k.core.proto.handleProto(nil, key, data) - continue - default: - continue - } - bs = bs[1:n] + bs = bs[:n] if len(bs) == 0 { continue } @@ -294,15 +285,69 @@ func (k *keyStore) writePC(bs []byte) (int, error) { strErr := fmt.Sprint("incorrect source address: ", net.IP(srcAddr[:]).String()) return 0, errors.New(strErr) } - buf := make([]byte, 1+len(bs), 65535) - buf[0] = typeSessionTraffic - copy(buf[1:], bs) if dstAddr.IsValid() { - k.sendToAddress(dstAddr, buf) + k.sendToAddress(dstAddr, bs) } else if dstSubnet.IsValid() { - k.sendToSubnet(dstSubnet, buf) + k.sendToSubnet(dstSubnet, bs) } else { return 0, errors.New("invalid destination address") } return len(bs), nil } + +// Exported API + +func (k *keyStore) MaxMTU() uint64 { + return k.core.MTU() +} + +func (k *keyStore) SetMTU(mtu uint64) { + if mtu > k.MaxMTU() { + mtu = k.MaxMTU() + } + if mtu < 1280 { + mtu = 1280 + } + k.mutex.Lock() + k.mtu = mtu + k.mutex.Unlock() +} + +func (k *keyStore) MTU() uint64 { + k.mutex.Lock() + mtu := k.mtu + k.mutex.Unlock() + return mtu +} + +type ReadWriteCloser struct { + keyStore +} + +func NewReadWriteCloser(c *core.Core) *ReadWriteCloser { + rwc := new(ReadWriteCloser) + rwc.init(c) + return rwc +} + +func (rwc *ReadWriteCloser) Address() address.Address { + return rwc.address +} + +func (rwc *ReadWriteCloser) Subnet() address.Subnet { + return rwc.subnet +} + +func (rwc *ReadWriteCloser) Read(p []byte) (n int, err error) { + return rwc.readPC(p) +} + +func (rwc *ReadWriteCloser) Write(p []byte) (n int, err error) { + return rwc.writePC(p) +} + +func (rwc *ReadWriteCloser) Close() error { + err := rwc.core.Close() + rwc.core.Stop() + return err +} diff --git a/src/tuntap/iface.go b/src/tuntap/iface.go index e72b091f..f629399a 100644 --- a/src/tuntap/iface.go +++ b/src/tuntap/iface.go @@ -17,7 +17,7 @@ func (tun *TunAdapter) read() { begin := TUN_OFFSET_BYTES end := begin + n bs := buf[begin:end] - if _, err := tun.core.Write(bs); err != nil { + if _, err := tun.rwc.Write(bs); err != nil { tun.log.Debugln("Unable to send packet:", err) } } @@ -27,7 +27,7 @@ func (tun *TunAdapter) write() { var buf [TUN_OFFSET_BYTES + 65535]byte for { bs := buf[TUN_OFFSET_BYTES:] - n, err := tun.core.Read(bs) + n, err := tun.rwc.Read(bs) if err != nil { tun.log.Errorln("Exiting tun writer due to core read error:", err) return diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index dbba018b..4caefe4a 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -21,8 +21,8 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/address" "github.com/yggdrasil-network/yggdrasil-go/src/config" - "github.com/yggdrasil-network/yggdrasil-go/src/core" "github.com/yggdrasil-network/yggdrasil-go/src/defaults" + "github.com/yggdrasil-network/yggdrasil-go/src/ipv6rwc" ) type MTU uint16 @@ -32,7 +32,7 @@ type MTU uint16 // should pass this object to the yggdrasil.SetRouterAdapter() function before // calling yggdrasil.Start(). type TunAdapter struct { - core *core.Core + rwc *ipv6rwc.ReadWriteCloser config *config.NodeConfig log *log.Logger addr address.Address @@ -93,8 +93,8 @@ func MaximumMTU() uint64 { // Init initialises the TUN module. You must have acquired a Listener from // the Yggdrasil core before this point and it must not be in use elsewhere. -func (tun *TunAdapter) Init(core *core.Core, config *config.NodeConfig, log *log.Logger, options interface{}) error { - tun.core = core +func (tun *TunAdapter) Init(rwc *ipv6rwc.ReadWriteCloser, config *config.NodeConfig, log *log.Logger, options interface{}) error { + tun.rwc = rwc tun.config = config tun.log = log return nil @@ -119,9 +119,8 @@ func (tun *TunAdapter) _start() error { if tun.config == nil { return errors.New("no configuration available to TUN") } - pk := tun.core.PublicKey() - tun.addr = *address.AddrForKey(pk) - tun.subnet = *address.SubnetForKey(pk) + tun.addr = tun.rwc.Address() + tun.subnet = tun.rwc.Subnet() addr := fmt.Sprintf("%s/%d", net.IP(tun.addr[:]).String(), 8*len(address.GetPrefix())-1) if tun.config.IfName == "none" || tun.config.IfName == "dummy" { tun.log.Debugln("Not starting TUN as ifname is none or dummy") @@ -130,8 +129,8 @@ func (tun *TunAdapter) _start() error { return nil } mtu := tun.config.IfMTU - if tun.core.MaxMTU() < mtu { - mtu = tun.core.MaxMTU() + if tun.rwc.MaxMTU() < mtu { + mtu = tun.rwc.MaxMTU() } if err := tun.setup(tun.config.IfName, addr, mtu); err != nil { return err @@ -139,7 +138,7 @@ func (tun *TunAdapter) _start() error { if tun.MTU() != mtu { tun.log.Warnf("Warning: Interface MTU %d automatically adjusted to %d (supported range is 1280-%d)", tun.config.IfMTU, tun.MTU(), MaximumMTU()) } - tun.core.SetMTU(tun.MTU()) + tun.rwc.SetMTU(tun.MTU()) tun.isOpen = true tun.isEnabled = true go tun.read() From e4ce2c79a9a6430f7145798a9a3e93c544bd869c Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 5 Jul 2021 22:26:09 +0100 Subject: [PATCH 013/345] Add LocalAddr to complete net.PacketConn interface --- src/core/core.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/core.go b/src/core/core.go index ac0ea1f0..8c816d2b 100644 --- a/src/core/core.go +++ b/src/core/core.go @@ -231,3 +231,7 @@ func (c *Core) WriteTo(p []byte, addr net.Addr) (n int, err error) { } return } + +func (c *Core) LocalAddr() net.Addr { + return iwt.Addr(c.public) +} From e224c02d6d88cfd36a0f8598dccfd4cbd4e1f297 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 5 Jul 2021 22:35:46 +0100 Subject: [PATCH 014/345] Revert "Add LocalAddr to complete net.PacketConn interface" This reverts commit e4ce2c79a9a6430f7145798a9a3e93c544bd869c. --- src/core/core.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/core/core.go b/src/core/core.go index 8c816d2b..ac0ea1f0 100644 --- a/src/core/core.go +++ b/src/core/core.go @@ -231,7 +231,3 @@ func (c *Core) WriteTo(p []byte, addr net.Addr) (n int, err error) { } return } - -func (c *Core) LocalAddr() net.Addr { - return iwt.Addr(c.public) -} From 3704ebf4cbeab2b5818ca545e0bebfce2c7bd10a Mon Sep 17 00:00:00 2001 From: Arceliar Date: Tue, 6 Jul 2021 19:45:12 -0500 Subject: [PATCH 015/345] fix debug rpcs and cleanup core.Close/core.Stop --- src/core/api.go | 5 ----- src/core/core.go | 26 ++++++++++++++++---------- src/core/nodeinfo.go | 4 ++-- src/core/proto.go | 2 +- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/core/api.go b/src/core/api.go index 6b219340..c312923d 100644 --- a/src/core/api.go +++ b/src/core/api.go @@ -239,11 +239,6 @@ func (c *Core) PublicKey() ed25519.PublicKey { return c.public } -func (c *Core) Close() error { - c.Stop() - return nil -} - // Hack to get the admin stuff working, TODO something cleaner type AddHandler interface { diff --git a/src/core/core.go b/src/core/core.go index ac0ea1f0..0332980b 100644 --- a/src/core/core.go +++ b/src/core/core.go @@ -161,25 +161,31 @@ func (c *Core) _start(nc *config.NodeConfig, log *log.Logger) error { // Stop shuts down the Yggdrasil node. func (c *Core) Stop() { - phony.Block(c, c._stop) + phony.Block(c, func() { + c.log.Infoln("Stopping...") + c._close() + c.log.Infoln("Stopped") + }) +} + +func (c *Core) Close() error { + var err error + phony.Block(c, func() { + err = c._close() + }) + return err } // This function is unsafe and should only be ran by the core actor. -func (c *Core) _stop() { - c.log.Infoln("Stopping...") +func (c *Core) _close() error { c.ctxCancel() - c.PacketConn.Close() // TODO make c.Close() do the right thing (act like c.Stop()) + err := c.PacketConn.Close() if c.addPeerTimer != nil { c.addPeerTimer.Stop() c.addPeerTimer = nil } _ = c.links.stop() - /* FIXME this deadlocks, need a waitgroup or something to coordinate shutdown - for _, peer := range c.GetPeers() { - c.DisconnectPeer(peer.Port) - } - */ - c.log.Infoln("Stopped") + return err } func (c *Core) MTU() uint64 { diff --git a/src/core/nodeinfo.go b/src/core/nodeinfo.go index 90153118..4ca21d73 100644 --- a/src/core/nodeinfo.go +++ b/src/core/nodeinfo.go @@ -129,7 +129,7 @@ func (m *nodeinfo) _sendReq(key keyArray, callback func(nodeinfo NodeInfoPayload if callback != nil { m._addCallback(key, callback) } - _, _ = m.proto.core.WriteTo([]byte{typeSessionProto, typeProtoNodeInfoRequest}, iwt.Addr(key[:])) + _, _ = m.proto.core.PacketConn.WriteTo([]byte{typeSessionProto, typeProtoNodeInfoRequest}, iwt.Addr(key[:])) } func (m *nodeinfo) handleReq(from phony.Actor, key keyArray) { @@ -146,7 +146,7 @@ func (m *nodeinfo) handleRes(from phony.Actor, key keyArray, info NodeInfoPayloa func (m *nodeinfo) _sendRes(key keyArray) { bs := append([]byte{typeSessionProto, typeProtoNodeInfoResponse}, m._getNodeInfo()...) - _, _ = m.proto.core.WriteTo(bs, iwt.Addr(key[:])) + _, _ = m.proto.core.PacketConn.WriteTo(bs, iwt.Addr(key[:])) } // Admin socket stuff diff --git a/src/core/proto.go b/src/core/proto.go index f9d12c8a..e60caeff 100644 --- a/src/core/proto.go +++ b/src/core/proto.go @@ -212,7 +212,7 @@ func (p *protoHandler) _handleGetDHTResponse(key keyArray, bs []byte) { func (p *protoHandler) _sendDebug(key keyArray, dType uint8, data []byte) { bs := append([]byte{typeSessionProto, typeProtoDebug, dType}, data...) - _, _ = p.core.WriteTo(bs, iwt.Addr(key[:])) + _, _ = p.core.PacketConn.WriteTo(bs, iwt.Addr(key[:])) } // Admin socket stuff From cd5383f7b799932b2536e4ee82e768558a073ec5 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Wed, 7 Jul 2021 18:36:51 -0500 Subject: [PATCH 016/345] fix core tests --- src/core/core_test.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/core/core_test.go b/src/core/core_test.go index dd60af21..fcfe2e31 100644 --- a/src/core/core_test.go +++ b/src/core/core_test.go @@ -44,13 +44,11 @@ func CreateAndConnectTwo(t testing.TB, verbose bool) (nodeA *Core, nodeB *Core) if err := nodeA.Start(GenerateConfig(), GetLoggerWithPrefix("A: ", verbose)); err != nil { t.Fatal(err) } - nodeA.SetMTU(1500) nodeB = new(Core) if err := nodeB.Start(GenerateConfig(), GetLoggerWithPrefix("B: ", verbose)); err != nil { t.Fatal(err) } - nodeB.SetMTU(1500) u, err := url.Parse("tcp://" + nodeA.links.tcp.getAddr().String()) if err != nil { @@ -94,7 +92,7 @@ func CreateEchoListener(t testing.TB, nodeA *Core, bufLen int, repeats int) chan buf := make([]byte, bufLen) res := make([]byte, bufLen) for i := 0; i < repeats; i++ { - n, err := nodeA.Read(buf) + n, from, err := nodeA.ReadFrom(buf) if err != nil { t.Error(err) return @@ -106,7 +104,7 @@ func CreateEchoListener(t testing.TB, nodeA *Core, bufLen int, repeats int) chan copy(res, buf) copy(res[8:24], buf[24:40]) copy(res[24:40], buf[8:24]) - _, err = nodeA.Write(res) + _, err = nodeA.WriteTo(res, from) if err != nil { t.Error(err) } @@ -141,12 +139,12 @@ func TestCore_Start_Transfer(t *testing.T) { msg[0] = 0x60 copy(msg[8:24], nodeB.Address()) copy(msg[24:40], nodeA.Address()) - _, err := nodeB.Write(msg) + _, err := nodeB.WriteTo(msg, nodeA.LocalAddr()) if err != nil { t.Fatal(err) } buf := make([]byte, msgLen) - _, err = nodeB.Read(buf) + _, _, err = nodeB.ReadFrom(buf) if err != nil { t.Fatal(err) } @@ -179,12 +177,13 @@ func BenchmarkCore_Start_Transfer(b *testing.B) { b.SetBytes(int64(msgLen)) b.ResetTimer() + addr := nodeA.LocalAddr() for i := 0; i < b.N; i++ { - _, err := nodeB.Write(msg) + _, err := nodeB.WriteTo(msg, addr) if err != nil { b.Fatal(err) } - _, err = nodeB.Read(buf) + _, _, err = nodeB.ReadFrom(buf) if err != nil { b.Fatal(err) } From 04ecdf60453846e0ab397f1a36497bb3b268f2bb Mon Sep 17 00:00:00 2001 From: Timur Demin Date: Tue, 6 Jul 2021 21:24:21 +0500 Subject: [PATCH 017/345] Preallocate memory when deriving address from key This makes src/address.AddrForKey preallocate 32 bytes before starting the address derivation. As benches in syg_go show, reallocating temp takes 20% of the function runtime. --- src/address/address.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/address/address.go b/src/address/address.go index 7add23ac..0e2400ed 100644 --- a/src/address/address.go +++ b/src/address/address.go @@ -64,7 +64,7 @@ func AddrForKey(publicKey ed25519.PublicKey) *Address { buf[idx] = ^buf[idx] } var addr Address - var temp []byte + var temp = make([]byte, 0, 32) done := false ones := byte(0) bits := byte(0) From 6a0ddc20efb5d5e79cc64630d3fdeddb8101149f Mon Sep 17 00:00:00 2001 From: cofob <49928332+cofob@users.noreply.github.com> Date: Wed, 21 Jul 2021 17:57:59 +0700 Subject: [PATCH 018/345] Allow yggdrasil bind to ports <1024 --- contrib/systemd/yggdrasil.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/systemd/yggdrasil.service b/contrib/systemd/yggdrasil.service index 3002e61b..27d27907 100644 --- a/contrib/systemd/yggdrasil.service +++ b/contrib/systemd/yggdrasil.service @@ -10,7 +10,7 @@ Group=yggdrasil ProtectHome=true ProtectSystem=true SyslogIdentifier=yggdrasil -CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW +CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE ExecStartPre=+-/sbin/modprobe tun ExecStart=/usr/bin/yggdrasil -useconffile /etc/yggdrasil.conf ExecReload=/bin/kill -HUP $MAINPID From d8df9755f2e8c41ee21110f77bc0b0b662f59414 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 28 Jul 2021 22:11:20 +0100 Subject: [PATCH 019/345] Allow specifying TLS SNI with ?sni= in peering URI --- src/core/link.go | 1 + src/core/tcp.go | 1 + src/core/tls.go | 13 ++++++++----- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/core/link.go b/src/core/link.go index ccab9219..f753156e 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -98,6 +98,7 @@ func (l *links) call(u *url.URL, sintf string) error { l.tcp.call(pathtokens[0], tcpOpts, sintf) case "tls": tcpOpts.upgrade = l.tcp.tls.forDialer + tcpOpts.tlsSNI = u.Query().Get("sni") l.tcp.call(u.Host, tcpOpts, sintf) default: return errors.New("unknown call scheme: " + u.Scheme) diff --git a/src/core/tcp.go b/src/core/tcp.go index 572fd652..7b1773b8 100644 --- a/src/core/tcp.go +++ b/src/core/tcp.go @@ -64,6 +64,7 @@ type tcpOptions struct { socksProxyAddr string socksProxyAuth *proxy.Auth socksPeerAddr string + tlsSNI string } func (l *TcpListener) Stop() { diff --git a/src/core/tls.go b/src/core/tls.go index 4c25225b..eb21fcbc 100644 --- a/src/core/tls.go +++ b/src/core/tls.go @@ -77,8 +77,8 @@ func (t *tcptls) init(tcp *tcp) { } } -func (t *tcptls) configForOptions(options *tcpOptions) *tls.Config { - config := *t.config +func (t *tcptls) configForOptions(options *tcpOptions, serverName string) *tls.Config { + config := t.config.Clone() config.VerifyPeerCertificate = func(rawCerts [][]byte, _ [][]*x509.Certificate) error { if len(rawCerts) != 1 { return errors.New("tls not exactly 1 cert") @@ -103,11 +103,14 @@ func (t *tcptls) configForOptions(options *tcpOptions) *tls.Config { } return nil } - return &config + if serverName != "" { + config.ServerName = serverName + } + return config } func (t *tcptls) upgradeListener(c net.Conn, options *tcpOptions) (net.Conn, error) { - config := t.configForOptions(options) + config := t.configForOptions(options, "") conn := tls.Server(c, config) if err := conn.Handshake(); err != nil { return c, err @@ -116,7 +119,7 @@ func (t *tcptls) upgradeListener(c net.Conn, options *tcpOptions) (net.Conn, err } func (t *tcptls) upgradeDialer(c net.Conn, options *tcpOptions) (net.Conn, error) { - config := t.configForOptions(options) + config := t.configForOptions(options, options.tlsSNI) conn := tls.Client(c, config) if err := conn.Handshake(); err != nil { return c, err From f094cf34bf23bde6d6c8515c79f1ad14ea3a230c Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 28 Jul 2021 22:23:33 +0100 Subject: [PATCH 020/345] Set SNI by default if the peering URI contains a DNS name --- src/core/link.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/core/link.go b/src/core/link.go index f753156e..98a7ab31 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -99,6 +99,13 @@ func (l *links) call(u *url.URL, sintf string) error { case "tls": tcpOpts.upgrade = l.tcp.tls.forDialer tcpOpts.tlsSNI = u.Query().Get("sni") + if tcpOpts.tlsSNI == "" { + // SNI headers must contain hostnames and not IP addresses, so we must make sure + // that we do not populate the SNI with an IP literal. + if host, _, err := net.SplitHostPort(u.Host); err == nil && net.ParseIP(host) == nil { + tcpOpts.tlsSNI = host + } + } l.tcp.call(u.Host, tcpOpts, sintf) default: return errors.New("unknown call scheme: " + u.Scheme) From bbdff033ce29d657c099f73f7946c1d5061a1b9c Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 1 Aug 2021 21:36:51 +0100 Subject: [PATCH 021/345] Update SNI code --- src/core/link.go | 14 +++++++++++--- src/core/tls.go | 10 ++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/core/link.go b/src/core/link.go index 98a7ab31..755d38a3 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -98,10 +98,18 @@ func (l *links) call(u *url.URL, sintf string) error { l.tcp.call(pathtokens[0], tcpOpts, sintf) case "tls": tcpOpts.upgrade = l.tcp.tls.forDialer - tcpOpts.tlsSNI = u.Query().Get("sni") + // SNI headers must contain hostnames and not IP addresses, so we must make sure + // that we do not populate the SNI with an IP literal. We do this by splitting + // the host-port combo from the query option and then seeing if it parses to an + // IP address successfully or not. + if sni := u.Query().Get("sni"); sni != "" { + if host, _, err := net.SplitHostPort(sni); err == nil && net.ParseIP(host) == nil { + tcpOpts.tlsSNI = host + } + } + // If the SNI is not configured still because the above failed then we'll try + // again but this time we'll use the host part of the peering URI instead. if tcpOpts.tlsSNI == "" { - // SNI headers must contain hostnames and not IP addresses, so we must make sure - // that we do not populate the SNI with an IP literal. if host, _, err := net.SplitHostPort(u.Host); err == nil && net.ParseIP(host) == nil { tcpOpts.tlsSNI = host } diff --git a/src/core/tls.go b/src/core/tls.go index eb21fcbc..9e340ac4 100644 --- a/src/core/tls.go +++ b/src/core/tls.go @@ -77,7 +77,7 @@ func (t *tcptls) init(tcp *tcp) { } } -func (t *tcptls) configForOptions(options *tcpOptions, serverName string) *tls.Config { +func (t *tcptls) configForOptions(options *tcpOptions) *tls.Config { config := t.config.Clone() config.VerifyPeerCertificate = func(rawCerts [][]byte, _ [][]*x509.Certificate) error { if len(rawCerts) != 1 { @@ -103,14 +103,11 @@ func (t *tcptls) configForOptions(options *tcpOptions, serverName string) *tls.C } return nil } - if serverName != "" { - config.ServerName = serverName - } return config } func (t *tcptls) upgradeListener(c net.Conn, options *tcpOptions) (net.Conn, error) { - config := t.configForOptions(options, "") + config := t.configForOptions(options) conn := tls.Server(c, config) if err := conn.Handshake(); err != nil { return c, err @@ -119,7 +116,8 @@ func (t *tcptls) upgradeListener(c net.Conn, options *tcpOptions) (net.Conn, err } func (t *tcptls) upgradeDialer(c net.Conn, options *tcpOptions) (net.Conn, error) { - config := t.configForOptions(options, options.tlsSNI) + config := t.configForOptions(options) + config.ServerName = options.tlsSNI conn := tls.Client(c, config) if err := conn.Handshake(); err != nil { return c, err From d1cd671bece1c69942f069d059174f01d5565406 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 1 Aug 2021 21:39:49 +0100 Subject: [PATCH 022/345] Fix bug --- src/core/link.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/link.go b/src/core/link.go index 755d38a3..8797b886 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -103,8 +103,8 @@ func (l *links) call(u *url.URL, sintf string) error { // the host-port combo from the query option and then seeing if it parses to an // IP address successfully or not. if sni := u.Query().Get("sni"); sni != "" { - if host, _, err := net.SplitHostPort(sni); err == nil && net.ParseIP(host) == nil { - tcpOpts.tlsSNI = host + if net.ParseIP(sni) == nil { + tcpOpts.tlsSNI = sni } } // If the SNI is not configured still because the above failed then we'll try From cbb6dc1b7d16616a27b31befcc5a9cf2b08b62c2 Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Tue, 3 Aug 2021 02:47:38 +0500 Subject: [PATCH 023/345] Split yggdrasilctl code into separate functions (refactoring) (#815) * Move yggdrasilctl responses to separate functions * Move yggdrasilctl request switch to separate function * Add empty lines * Create struct CmdLine for yggdrasilctl * Move yggdrasilctl command line parsing to separate func * Turn struct CmdLine into CmdLineEnv * Rename func parseCmdLine to parseFlagsAndArgs * Move yggdrasilctl endpoint setting logic into separate func * Function to create yggdrasilctl CmdLineEnv * Reorder code * Move struct fields into lines * Turn yggdrasilctl CmdLineEnv funcs to methods * Move yggdrasilctl connection code to separate func * Rename functions * Move yggdrasilctl command line env to separate mod * Move yggdrasilctl command line env to main mod * Run goimports Co-authored-by: Neil Alexander --- cmd/yggdrasilctl/cmd_line_env.go | 94 +++++ cmd/yggdrasilctl/main.go | 651 ++++++++++++++++--------------- 2 files changed, 422 insertions(+), 323 deletions(-) create mode 100644 cmd/yggdrasilctl/cmd_line_env.go diff --git a/cmd/yggdrasilctl/cmd_line_env.go b/cmd/yggdrasilctl/cmd_line_env.go new file mode 100644 index 00000000..bd6df8fc --- /dev/null +++ b/cmd/yggdrasilctl/cmd_line_env.go @@ -0,0 +1,94 @@ +package main + +import ( + "bytes" + "flag" + "fmt" + "io/ioutil" + "log" + "os" + + "github.com/hjson/hjson-go" + "golang.org/x/text/encoding/unicode" + + "github.com/yggdrasil-network/yggdrasil-go/src/defaults" +) + +type CmdLineEnv struct { + args []string + endpoint, server string + injson, verbose, ver bool +} + +func newCmdLineEnv() CmdLineEnv { + var cmdLineEnv CmdLineEnv + cmdLineEnv.endpoint = defaults.GetDefaults().DefaultAdminListen + return cmdLineEnv +} + +func (cmdLineEnv *CmdLineEnv) parseFlagsAndArgs() { + flag.Usage = func() { + fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] command [key=value] [key=value] ...\n\n", os.Args[0]) + fmt.Println("Options:") + flag.PrintDefaults() + fmt.Println() + fmt.Println("Please note that options must always specified BEFORE the command\non the command line or they will be ignored.") + fmt.Println() + fmt.Println("Commands:\n - Use \"list\" for a list of available commands") + fmt.Println() + fmt.Println("Examples:") + fmt.Println(" - ", os.Args[0], "list") + fmt.Println(" - ", os.Args[0], "getPeers") + fmt.Println(" - ", os.Args[0], "-v getSelf") + fmt.Println(" - ", os.Args[0], "setTunTap name=auto mtu=1500 tap_mode=false") + fmt.Println(" - ", os.Args[0], "-endpoint=tcp://localhost:9001 getDHT") + fmt.Println(" - ", os.Args[0], "-endpoint=unix:///var/run/ygg.sock getDHT") + } + + server := flag.String("endpoint", cmdLineEnv.endpoint, "Admin socket endpoint") + injson := flag.Bool("json", false, "Output in JSON format (as opposed to pretty-print)") + verbose := flag.Bool("v", false, "Verbose output (includes public keys)") + ver := flag.Bool("version", false, "Prints the version of this build") + + flag.Parse() + + cmdLineEnv.args = flag.Args() + cmdLineEnv.server = *server + cmdLineEnv.injson = *injson + cmdLineEnv.verbose = *verbose + cmdLineEnv.ver = *ver +} + +func (cmdLineEnv *CmdLineEnv) setEndpoint(logger *log.Logger) { + if cmdLineEnv.server == cmdLineEnv.endpoint { + if config, err := ioutil.ReadFile(defaults.GetDefaults().DefaultConfigFile); err == nil { + if bytes.Equal(config[0:2], []byte{0xFF, 0xFE}) || + bytes.Equal(config[0:2], []byte{0xFE, 0xFF}) { + utf := unicode.UTF16(unicode.BigEndian, unicode.UseBOM) + decoder := utf.NewDecoder() + config, err = decoder.Bytes(config) + if err != nil { + panic(err) + } + } + var dat map[string]interface{} + if err := hjson.Unmarshal(config, &dat); err != nil { + panic(err) + } + if ep, ok := dat["AdminListen"].(string); ok && (ep != "none" && ep != "") { + cmdLineEnv.endpoint = ep + logger.Println("Found platform default config file", defaults.GetDefaults().DefaultConfigFile) + logger.Println("Using endpoint", cmdLineEnv.endpoint, "from AdminListen") + } else { + logger.Println("Configuration file doesn't contain appropriate AdminListen option") + logger.Println("Falling back to platform default", defaults.GetDefaults().DefaultAdminListen) + } + } else { + logger.Println("Can't open config file from default location", defaults.GetDefaults().DefaultConfigFile) + logger.Println("Falling back to platform default", defaults.GetDefaults().DefaultAdminListen) + } + } else { + cmdLineEnv.endpoint = cmdLineEnv.server + logger.Println("Using endpoint", cmdLineEnv.endpoint, "from command line") + } +} diff --git a/cmd/yggdrasilctl/main.go b/cmd/yggdrasilctl/main.go index 91923392..788b4f19 100644 --- a/cmd/yggdrasilctl/main.go +++ b/cmd/yggdrasilctl/main.go @@ -6,7 +6,6 @@ import ( "errors" "flag" "fmt" - "io/ioutil" "log" "net" "net/url" @@ -15,10 +14,6 @@ import ( "strconv" "strings" - "golang.org/x/text/encoding/unicode" - - "github.com/hjson/hjson-go" - "github.com/yggdrasil-network/yggdrasil-go/src/defaults" "github.com/yggdrasil-network/yggdrasil-go/src/version" ) @@ -32,6 +27,7 @@ func main() { func run() int { logbuffer := &bytes.Buffer{} logger := log.New(logbuffer, "", log.Flags()) + defer func() int { if r := recover(); r != nil { logger.Println("Fatal error:", r) @@ -41,97 +37,24 @@ func run() int { return 0 }() - endpoint := defaults.GetDefaults().DefaultAdminListen + cmdLineEnv := newCmdLineEnv() + cmdLineEnv.parseFlagsAndArgs() - flag.Usage = func() { - fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] command [key=value] [key=value] ...\n\n", os.Args[0]) - fmt.Println("Options:") - flag.PrintDefaults() - fmt.Println() - fmt.Println("Please note that options must always specified BEFORE the command\non the command line or they will be ignored.") - fmt.Println() - fmt.Println("Commands:\n - Use \"list\" for a list of available commands") - fmt.Println() - fmt.Println("Examples:") - fmt.Println(" - ", os.Args[0], "list") - fmt.Println(" - ", os.Args[0], "getPeers") - fmt.Println(" - ", os.Args[0], "-v getSelf") - fmt.Println(" - ", os.Args[0], "setTunTap name=auto mtu=1500 tap_mode=false") - fmt.Println(" - ", os.Args[0], "-endpoint=tcp://localhost:9001 getDHT") - fmt.Println(" - ", os.Args[0], "-endpoint=unix:///var/run/ygg.sock getDHT") - } - server := flag.String("endpoint", endpoint, "Admin socket endpoint") - injson := flag.Bool("json", false, "Output in JSON format (as opposed to pretty-print)") - verbose := flag.Bool("v", false, "Verbose output (includes public keys)") - ver := flag.Bool("version", false, "Prints the version of this build") - flag.Parse() - args := flag.Args() - - if *ver { + if cmdLineEnv.ver { fmt.Println("Build name:", version.BuildName()) fmt.Println("Build version:", version.BuildVersion()) fmt.Println("To get the version number of the running Yggdrasil node, run", os.Args[0], "getSelf") return 0 } - if len(args) == 0 { + if len(cmdLineEnv.args) == 0 { flag.Usage() return 0 } - if *server == endpoint { - if config, err := ioutil.ReadFile(defaults.GetDefaults().DefaultConfigFile); err == nil { - if bytes.Equal(config[0:2], []byte{0xFF, 0xFE}) || - bytes.Equal(config[0:2], []byte{0xFE, 0xFF}) { - utf := unicode.UTF16(unicode.BigEndian, unicode.UseBOM) - decoder := utf.NewDecoder() - config, err = decoder.Bytes(config) - if err != nil { - panic(err) - } - } - var dat map[string]interface{} - if err := hjson.Unmarshal(config, &dat); err != nil { - panic(err) - } - if ep, ok := dat["AdminListen"].(string); ok && (ep != "none" && ep != "") { - endpoint = ep - logger.Println("Found platform default config file", defaults.GetDefaults().DefaultConfigFile) - logger.Println("Using endpoint", endpoint, "from AdminListen") - } else { - logger.Println("Configuration file doesn't contain appropriate AdminListen option") - logger.Println("Falling back to platform default", defaults.GetDefaults().DefaultAdminListen) - } - } else { - logger.Println("Can't open config file from default location", defaults.GetDefaults().DefaultConfigFile) - logger.Println("Falling back to platform default", defaults.GetDefaults().DefaultAdminListen) - } - } else { - endpoint = *server - logger.Println("Using endpoint", endpoint, "from command line") - } + cmdLineEnv.setEndpoint(logger) - var conn net.Conn - u, err := url.Parse(endpoint) - if err == nil { - switch strings.ToLower(u.Scheme) { - case "unix": - logger.Println("Connecting to UNIX socket", endpoint[7:]) - conn, err = net.Dial("unix", endpoint[7:]) - case "tcp": - logger.Println("Connecting to TCP socket", u.Host) - conn, err = net.Dial("tcp", u.Host) - default: - logger.Println("Unknown protocol or malformed address - check your endpoint") - err = errors.New("protocol not supported") - } - } else { - logger.Println("Connecting to TCP socket", u.Host) - conn, err = net.Dial("tcp", endpoint) - } - if err != nil { - panic(err) - } + conn := connect(cmdLineEnv.endpoint, logger) logger.Println("Connected") defer conn.Close() @@ -140,7 +63,7 @@ func run() int { send := make(admin_info) recv := make(admin_info) - for c, a := range args { + for c, a := range cmdLineEnv.args { if c == 0 { if strings.HasPrefix(a, "-") { logger.Printf("Ignoring flag %s as it should be specified before other parameters\n", a) @@ -176,7 +99,9 @@ func run() int { if err := encoder.Encode(&send); err != nil { panic(err) } + logger.Printf("Request sent") + if err := decoder.Decode(&recv); err == nil { logger.Printf("Response received") if recv["status"] == "error" { @@ -195,252 +120,16 @@ func run() int { fmt.Println("Missing response body (malformed response?)") return 1 } - req := recv["request"].(map[string]interface{}) res := recv["response"].(map[string]interface{}) - if *injson { + if cmdLineEnv.injson { if json, err := json.MarshalIndent(res, "", " "); err == nil { fmt.Println(string(json)) } return 0 } - switch strings.ToLower(req["request"].(string)) { - case "dot": - fmt.Println(res["dot"]) - case "list", "getpeers", "getswitchpeers", "getdht", "getsessions", "dhtping": - maxWidths := make(map[string]int) - var keyOrder []string - keysOrdered := false - - for _, tlv := range res { - for slk, slv := range tlv.(map[string]interface{}) { - if !keysOrdered { - for k := range slv.(map[string]interface{}) { - if !*verbose { - if k == "box_pub_key" || k == "box_sig_key" || k == "nodeinfo" || k == "was_mtu_fixed" { - continue - } - } - keyOrder = append(keyOrder, fmt.Sprint(k)) - } - sort.Strings(keyOrder) - keysOrdered = true - } - for k, v := range slv.(map[string]interface{}) { - if len(fmt.Sprint(slk)) > maxWidths["key"] { - maxWidths["key"] = len(fmt.Sprint(slk)) - } - if len(fmt.Sprint(v)) > maxWidths[k] { - maxWidths[k] = len(fmt.Sprint(v)) - if maxWidths[k] < len(k) { - maxWidths[k] = len(k) - } - } - } - } - - if len(keyOrder) > 0 { - fmt.Printf("%-"+fmt.Sprint(maxWidths["key"])+"s ", "") - for _, v := range keyOrder { - fmt.Printf("%-"+fmt.Sprint(maxWidths[v])+"s ", v) - } - fmt.Println() - } - - for slk, slv := range tlv.(map[string]interface{}) { - fmt.Printf("%-"+fmt.Sprint(maxWidths["key"])+"s ", slk) - for _, k := range keyOrder { - preformatted := slv.(map[string]interface{})[k] - var formatted string - switch k { - case "bytes_sent", "bytes_recvd": - formatted = fmt.Sprintf("%d", uint(preformatted.(float64))) - case "uptime", "last_seen": - seconds := uint(preformatted.(float64)) % 60 - minutes := uint(preformatted.(float64)/60) % 60 - hours := uint(preformatted.(float64) / 60 / 60) - formatted = fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds) - default: - formatted = fmt.Sprint(preformatted) - } - fmt.Printf("%-"+fmt.Sprint(maxWidths[k])+"s ", formatted) - } - fmt.Println() - } - } - case "gettuntap", "settuntap": - for k, v := range res { - fmt.Println("Interface name:", k) - if mtu, ok := v.(map[string]interface{})["mtu"].(float64); ok { - fmt.Println("Interface MTU:", mtu) - } - if tap_mode, ok := v.(map[string]interface{})["tap_mode"].(bool); ok { - fmt.Println("TAP mode:", tap_mode) - } - } - case "getself": - for k, v := range res["self"].(map[string]interface{}) { - if buildname, ok := v.(map[string]interface{})["build_name"].(string); ok && buildname != "unknown" { - fmt.Println("Build name:", buildname) - } - if buildversion, ok := v.(map[string]interface{})["build_version"].(string); ok && buildversion != "unknown" { - fmt.Println("Build version:", buildversion) - } - fmt.Println("IPv6 address:", k) - if subnet, ok := v.(map[string]interface{})["subnet"].(string); ok { - fmt.Println("IPv6 subnet:", subnet) - } - if boxSigKey, ok := v.(map[string]interface{})["key"].(string); ok { - fmt.Println("Public key:", boxSigKey) - } - if coords, ok := v.(map[string]interface{})["coords"].(string); ok { - fmt.Println("Coords:", coords) - } - if *verbose { - if nodeID, ok := v.(map[string]interface{})["node_id"].(string); ok { - fmt.Println("Node ID:", nodeID) - } - if boxPubKey, ok := v.(map[string]interface{})["box_pub_key"].(string); ok { - fmt.Println("Public encryption key:", boxPubKey) - } - if boxSigKey, ok := v.(map[string]interface{})["box_sig_key"].(string); ok { - fmt.Println("Public signing key:", boxSigKey) - } - } - } - case "getswitchqueues": - maximumqueuesize := float64(4194304) - portqueues := make(map[float64]float64) - portqueuesize := make(map[float64]float64) - portqueuepackets := make(map[float64]float64) - v := res["switchqueues"].(map[string]interface{}) - if queuecount, ok := v["queues_count"].(float64); ok { - fmt.Printf("Active queue count: %d queues\n", uint(queuecount)) - } - if queuesize, ok := v["queues_size"].(float64); ok { - fmt.Printf("Active queue size: %d bytes\n", uint(queuesize)) - } - if highestqueuecount, ok := v["highest_queues_count"].(float64); ok { - fmt.Printf("Highest queue count: %d queues\n", uint(highestqueuecount)) - } - if highestqueuesize, ok := v["highest_queues_size"].(float64); ok { - fmt.Printf("Highest queue size: %d bytes\n", uint(highestqueuesize)) - } - if m, ok := v["maximum_queues_size"].(float64); ok { - maximumqueuesize = m - fmt.Printf("Maximum queue size: %d bytes\n", uint(maximumqueuesize)) - } - if queues, ok := v["queues"].([]interface{}); ok { - if len(queues) != 0 { - fmt.Println("Active queues:") - for _, v := range queues { - queueport := v.(map[string]interface{})["queue_port"].(float64) - queuesize := v.(map[string]interface{})["queue_size"].(float64) - queuepackets := v.(map[string]interface{})["queue_packets"].(float64) - queueid := v.(map[string]interface{})["queue_id"].(string) - portqueues[queueport]++ - portqueuesize[queueport] += queuesize - portqueuepackets[queueport] += queuepackets - queuesizepercent := (100 / maximumqueuesize) * queuesize - fmt.Printf("- Switch port %d, Stream ID: %v, size: %d bytes (%d%% full), %d packets\n", - uint(queueport), []byte(queueid), uint(queuesize), - uint(queuesizepercent), uint(queuepackets)) - } - } - } - if len(portqueuesize) > 0 && len(portqueuepackets) > 0 { - fmt.Println("Aggregated statistics by switchport:") - for k, v := range portqueuesize { - queuesizepercent := (100 / (portqueues[k] * maximumqueuesize)) * v - fmt.Printf("- Switch port %d, size: %d bytes (%d%% full), %d packets\n", - uint(k), uint(v), uint(queuesizepercent), uint(portqueuepackets[k])) - } - } - case "addpeer", "removepeer", "addallowedencryptionpublickey", "removeallowedencryptionpublickey", "addsourcesubnet", "addroute", "removesourcesubnet", "removeroute": - if _, ok := res["added"]; ok { - for _, v := range res["added"].([]interface{}) { - fmt.Println("Added:", fmt.Sprint(v)) - } - } - if _, ok := res["not_added"]; ok { - for _, v := range res["not_added"].([]interface{}) { - fmt.Println("Not added:", fmt.Sprint(v)) - } - } - if _, ok := res["removed"]; ok { - for _, v := range res["removed"].([]interface{}) { - fmt.Println("Removed:", fmt.Sprint(v)) - } - } - if _, ok := res["not_removed"]; ok { - for _, v := range res["not_removed"].([]interface{}) { - fmt.Println("Not removed:", fmt.Sprint(v)) - } - } - case "getallowedencryptionpublickeys": - if _, ok := res["allowed_box_pubs"]; !ok { - fmt.Println("All connections are allowed") - } else if res["allowed_box_pubs"] == nil { - fmt.Println("All connections are allowed") - } else { - fmt.Println("Connections are allowed only from the following public box keys:") - for _, v := range res["allowed_box_pubs"].([]interface{}) { - fmt.Println("-", v) - } - } - case "getmulticastinterfaces": - if _, ok := res["multicast_interfaces"]; !ok { - fmt.Println("No multicast interfaces found") - } else if res["multicast_interfaces"] == nil { - fmt.Println("No multicast interfaces found") - } else { - fmt.Println("Multicast peer discovery is active on:") - for _, v := range res["multicast_interfaces"].([]interface{}) { - fmt.Println("-", v) - } - } - case "getsourcesubnets": - if _, ok := res["source_subnets"]; !ok { - fmt.Println("No source subnets found") - } else if res["source_subnets"] == nil { - fmt.Println("No source subnets found") - } else { - fmt.Println("Source subnets:") - for _, v := range res["source_subnets"].([]interface{}) { - fmt.Println("-", v) - } - } - case "getroutes": - if routes, ok := res["routes"].(map[string]interface{}); !ok { - fmt.Println("No routes found") - } else { - if res["routes"] == nil || len(routes) == 0 { - fmt.Println("No routes found") - } else { - fmt.Println("Routes:") - for k, v := range routes { - if pv, ok := v.(string); ok { - fmt.Println("-", k, " via ", pv) - } - } - } - } - case "settunnelrouting": - fallthrough - case "gettunnelrouting": - if enabled, ok := res["enabled"].(bool); !ok { - fmt.Println("Tunnel routing is disabled") - } else if !enabled { - fmt.Println("Tunnel routing is disabled") - } else { - fmt.Println("Tunnel routing is enabled") - } - default: - if json, err := json.MarshalIndent(recv["response"], "", " "); err == nil { - fmt.Println(string(json)) - } - } + handleAll(recv, cmdLineEnv.verbose) } else { logger.Println("Error receiving response:", err) } @@ -448,5 +137,321 @@ func run() int { if v, ok := recv["status"]; ok && v != "success" { return 1 } + return 0 } + +func connect(endpoint string, logger *log.Logger) net.Conn { + var conn net.Conn + + u, err := url.Parse(endpoint) + + if err == nil { + switch strings.ToLower(u.Scheme) { + case "unix": + logger.Println("Connecting to UNIX socket", endpoint[7:]) + conn, err = net.Dial("unix", endpoint[7:]) + case "tcp": + logger.Println("Connecting to TCP socket", u.Host) + conn, err = net.Dial("tcp", u.Host) + default: + logger.Println("Unknown protocol or malformed address - check your endpoint") + err = errors.New("protocol not supported") + } + } else { + logger.Println("Connecting to TCP socket", u.Host) + conn, err = net.Dial("tcp", endpoint) + } + + if err != nil { + panic(err) + } + + return conn +} + +func handleAll(recv map[string]interface{}, verbose bool) { + req := recv["request"].(map[string]interface{}) + res := recv["response"].(map[string]interface{}) + + switch strings.ToLower(req["request"].(string)) { + case "dot": + handleDot(res) + case "list", "getpeers", "getswitchpeers", "getdht", "getsessions", "dhtping": + handleVariousInfo(res, verbose) + case "gettuntap", "settuntap": + handleGetAndSetTunTap(res) + case "getself": + handleGetSelf(res, verbose) + case "getswitchqueues": + handleGetSwitchQueues(res) + case "addpeer", "removepeer", "addallowedencryptionpublickey", "removeallowedencryptionpublickey", "addsourcesubnet", "addroute", "removesourcesubnet", "removeroute": + handleAddsAndRemoves(res) + case "getallowedencryptionpublickeys": + handleGetAllowedEncryptionPublicKeys(res) + case "getmulticastinterfaces": + handleGetMulticastInterfaces(res) + case "getsourcesubnets": + handleGetSourceSubnets(res) + case "getroutes": + handleGetRoutes(res) + case "settunnelrouting": + fallthrough + case "gettunnelrouting": + handleGetTunnelRouting(res) + default: + if json, err := json.MarshalIndent(recv["response"], "", " "); err == nil { + fmt.Println(string(json)) + } + } +} + +func handleDot(res map[string]interface{}) { + fmt.Println(res["dot"]) +} + +func handleVariousInfo(res map[string]interface{}, verbose bool) { + maxWidths := make(map[string]int) + var keyOrder []string + keysOrdered := false + + for _, tlv := range res { + for slk, slv := range tlv.(map[string]interface{}) { + if !keysOrdered { + for k := range slv.(map[string]interface{}) { + if !verbose { + if k == "box_pub_key" || k == "box_sig_key" || k == "nodeinfo" || k == "was_mtu_fixed" { + continue + } + } + keyOrder = append(keyOrder, fmt.Sprint(k)) + } + sort.Strings(keyOrder) + keysOrdered = true + } + for k, v := range slv.(map[string]interface{}) { + if len(fmt.Sprint(slk)) > maxWidths["key"] { + maxWidths["key"] = len(fmt.Sprint(slk)) + } + if len(fmt.Sprint(v)) > maxWidths[k] { + maxWidths[k] = len(fmt.Sprint(v)) + if maxWidths[k] < len(k) { + maxWidths[k] = len(k) + } + } + } + } + + if len(keyOrder) > 0 { + fmt.Printf("%-"+fmt.Sprint(maxWidths["key"])+"s ", "") + for _, v := range keyOrder { + fmt.Printf("%-"+fmt.Sprint(maxWidths[v])+"s ", v) + } + fmt.Println() + } + + for slk, slv := range tlv.(map[string]interface{}) { + fmt.Printf("%-"+fmt.Sprint(maxWidths["key"])+"s ", slk) + for _, k := range keyOrder { + preformatted := slv.(map[string]interface{})[k] + var formatted string + switch k { + case "bytes_sent", "bytes_recvd": + formatted = fmt.Sprintf("%d", uint(preformatted.(float64))) + case "uptime", "last_seen": + seconds := uint(preformatted.(float64)) % 60 + minutes := uint(preformatted.(float64)/60) % 60 + hours := uint(preformatted.(float64) / 60 / 60) + formatted = fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds) + default: + formatted = fmt.Sprint(preformatted) + } + fmt.Printf("%-"+fmt.Sprint(maxWidths[k])+"s ", formatted) + } + fmt.Println() + } + } +} + +func handleGetAndSetTunTap(res map[string]interface{}) { + for k, v := range res { + fmt.Println("Interface name:", k) + if mtu, ok := v.(map[string]interface{})["mtu"].(float64); ok { + fmt.Println("Interface MTU:", mtu) + } + if tap_mode, ok := v.(map[string]interface{})["tap_mode"].(bool); ok { + fmt.Println("TAP mode:", tap_mode) + } + } +} + +func handleGetSelf(res map[string]interface{}, verbose bool) { + for k, v := range res["self"].(map[string]interface{}) { + if buildname, ok := v.(map[string]interface{})["build_name"].(string); ok && buildname != "unknown" { + fmt.Println("Build name:", buildname) + } + if buildversion, ok := v.(map[string]interface{})["build_version"].(string); ok && buildversion != "unknown" { + fmt.Println("Build version:", buildversion) + } + fmt.Println("IPv6 address:", k) + if subnet, ok := v.(map[string]interface{})["subnet"].(string); ok { + fmt.Println("IPv6 subnet:", subnet) + } + if boxSigKey, ok := v.(map[string]interface{})["key"].(string); ok { + fmt.Println("Public key:", boxSigKey) + } + if coords, ok := v.(map[string]interface{})["coords"].(string); ok { + fmt.Println("Coords:", coords) + } + if verbose { + if nodeID, ok := v.(map[string]interface{})["node_id"].(string); ok { + fmt.Println("Node ID:", nodeID) + } + if boxPubKey, ok := v.(map[string]interface{})["box_pub_key"].(string); ok { + fmt.Println("Public encryption key:", boxPubKey) + } + if boxSigKey, ok := v.(map[string]interface{})["box_sig_key"].(string); ok { + fmt.Println("Public signing key:", boxSigKey) + } + } + } +} + +func handleGetSwitchQueues(res map[string]interface{}) { + maximumqueuesize := float64(4194304) + portqueues := make(map[float64]float64) + portqueuesize := make(map[float64]float64) + portqueuepackets := make(map[float64]float64) + v := res["switchqueues"].(map[string]interface{}) + if queuecount, ok := v["queues_count"].(float64); ok { + fmt.Printf("Active queue count: %d queues\n", uint(queuecount)) + } + if queuesize, ok := v["queues_size"].(float64); ok { + fmt.Printf("Active queue size: %d bytes\n", uint(queuesize)) + } + if highestqueuecount, ok := v["highest_queues_count"].(float64); ok { + fmt.Printf("Highest queue count: %d queues\n", uint(highestqueuecount)) + } + if highestqueuesize, ok := v["highest_queues_size"].(float64); ok { + fmt.Printf("Highest queue size: %d bytes\n", uint(highestqueuesize)) + } + if m, ok := v["maximum_queues_size"].(float64); ok { + maximumqueuesize = m + fmt.Printf("Maximum queue size: %d bytes\n", uint(maximumqueuesize)) + } + if queues, ok := v["queues"].([]interface{}); ok { + if len(queues) != 0 { + fmt.Println("Active queues:") + for _, v := range queues { + queueport := v.(map[string]interface{})["queue_port"].(float64) + queuesize := v.(map[string]interface{})["queue_size"].(float64) + queuepackets := v.(map[string]interface{})["queue_packets"].(float64) + queueid := v.(map[string]interface{})["queue_id"].(string) + portqueues[queueport]++ + portqueuesize[queueport] += queuesize + portqueuepackets[queueport] += queuepackets + queuesizepercent := (100 / maximumqueuesize) * queuesize + fmt.Printf("- Switch port %d, Stream ID: %v, size: %d bytes (%d%% full), %d packets\n", + uint(queueport), []byte(queueid), uint(queuesize), + uint(queuesizepercent), uint(queuepackets)) + } + } + } + if len(portqueuesize) > 0 && len(portqueuepackets) > 0 { + fmt.Println("Aggregated statistics by switchport:") + for k, v := range portqueuesize { + queuesizepercent := (100 / (portqueues[k] * maximumqueuesize)) * v + fmt.Printf("- Switch port %d, size: %d bytes (%d%% full), %d packets\n", + uint(k), uint(v), uint(queuesizepercent), uint(portqueuepackets[k])) + } + } +} + +func handleAddsAndRemoves(res map[string]interface{}) { + if _, ok := res["added"]; ok { + for _, v := range res["added"].([]interface{}) { + fmt.Println("Added:", fmt.Sprint(v)) + } + } + if _, ok := res["not_added"]; ok { + for _, v := range res["not_added"].([]interface{}) { + fmt.Println("Not added:", fmt.Sprint(v)) + } + } + if _, ok := res["removed"]; ok { + for _, v := range res["removed"].([]interface{}) { + fmt.Println("Removed:", fmt.Sprint(v)) + } + } + if _, ok := res["not_removed"]; ok { + for _, v := range res["not_removed"].([]interface{}) { + fmt.Println("Not removed:", fmt.Sprint(v)) + } + } +} + +func handleGetAllowedEncryptionPublicKeys(res map[string]interface{}) { + if _, ok := res["allowed_box_pubs"]; !ok { + fmt.Println("All connections are allowed") + } else if res["allowed_box_pubs"] == nil { + fmt.Println("All connections are allowed") + } else { + fmt.Println("Connections are allowed only from the following public box keys:") + for _, v := range res["allowed_box_pubs"].([]interface{}) { + fmt.Println("-", v) + } + } +} + +func handleGetMulticastInterfaces(res map[string]interface{}) { + if _, ok := res["multicast_interfaces"]; !ok { + fmt.Println("No multicast interfaces found") + } else if res["multicast_interfaces"] == nil { + fmt.Println("No multicast interfaces found") + } else { + fmt.Println("Multicast peer discovery is active on:") + for _, v := range res["multicast_interfaces"].([]interface{}) { + fmt.Println("-", v) + } + } +} + +func handleGetSourceSubnets(res map[string]interface{}) { + if _, ok := res["source_subnets"]; !ok { + fmt.Println("No source subnets found") + } else if res["source_subnets"] == nil { + fmt.Println("No source subnets found") + } else { + fmt.Println("Source subnets:") + for _, v := range res["source_subnets"].([]interface{}) { + fmt.Println("-", v) + } + } +} + +func handleGetRoutes(res map[string]interface{}) { + if routes, ok := res["routes"].(map[string]interface{}); !ok { + fmt.Println("No routes found") + } else { + if res["routes"] == nil || len(routes) == 0 { + fmt.Println("No routes found") + } else { + fmt.Println("Routes:") + for k, v := range routes { + if pv, ok := v.(string); ok { + fmt.Println("-", k, " via ", pv) + } + } + } + } +} + +func handleGetTunnelRouting(res map[string]interface{}) { + if enabled, ok := res["enabled"].(bool); !ok { + fmt.Println("Tunnel routing is disabled") + } else if !enabled { + fmt.Println("Tunnel routing is disabled") + } else { + fmt.Println("Tunnel routing is enabled") + } +} From ebe366ef3bcb1b22a31225b06d140d013e463647 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sat, 7 Aug 2021 10:17:21 +0100 Subject: [PATCH 024/345] Add IPReadWriteCloser interface --- src/tuntap/tun.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index 4caefe4a..8676ff99 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -11,6 +11,7 @@ package tuntap import ( "errors" "fmt" + "io" "net" //"sync" @@ -22,17 +23,23 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/address" "github.com/yggdrasil-network/yggdrasil-go/src/config" "github.com/yggdrasil-network/yggdrasil-go/src/defaults" - "github.com/yggdrasil-network/yggdrasil-go/src/ipv6rwc" ) -type MTU uint16 +type IPReadWriteCloser interface { + io.ReadWriteCloser + MaxMTU() uint64 + SetMTU(mtu uint64) + MTU() uint64 + Address() address.Address + Subnet() address.Subnet +} // TunAdapter represents a running TUN interface and extends the // yggdrasil.Adapter type. In order to use the TUN adapter with Yggdrasil, you // should pass this object to the yggdrasil.SetRouterAdapter() function before // calling yggdrasil.Start(). type TunAdapter struct { - rwc *ipv6rwc.ReadWriteCloser + rwc IPReadWriteCloser config *config.NodeConfig log *log.Logger addr address.Address @@ -93,7 +100,7 @@ func MaximumMTU() uint64 { // Init initialises the TUN module. You must have acquired a Listener from // the Yggdrasil core before this point and it must not be in use elsewhere. -func (tun *TunAdapter) Init(rwc *ipv6rwc.ReadWriteCloser, config *config.NodeConfig, log *log.Logger, options interface{}) error { +func (tun *TunAdapter) Init(rwc IPReadWriteCloser, config *config.NodeConfig, log *log.Logger, options interface{}) error { tun.rwc = rwc tun.config = config tun.log = log From 3613614b418ddb7d99b931ce0c6a40e89ed04fc8 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sat, 7 Aug 2021 12:56:36 -0500 Subject: [PATCH 025/345] Revert "Add IPReadWriteCloser interface" This reverts commit ebe366ef3bcb1b22a31225b06d140d013e463647. --- src/tuntap/tun.go | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index 8676ff99..4caefe4a 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -11,7 +11,6 @@ package tuntap import ( "errors" "fmt" - "io" "net" //"sync" @@ -23,23 +22,17 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/address" "github.com/yggdrasil-network/yggdrasil-go/src/config" "github.com/yggdrasil-network/yggdrasil-go/src/defaults" + "github.com/yggdrasil-network/yggdrasil-go/src/ipv6rwc" ) -type IPReadWriteCloser interface { - io.ReadWriteCloser - MaxMTU() uint64 - SetMTU(mtu uint64) - MTU() uint64 - Address() address.Address - Subnet() address.Subnet -} +type MTU uint16 // TunAdapter represents a running TUN interface and extends the // yggdrasil.Adapter type. In order to use the TUN adapter with Yggdrasil, you // should pass this object to the yggdrasil.SetRouterAdapter() function before // calling yggdrasil.Start(). type TunAdapter struct { - rwc IPReadWriteCloser + rwc *ipv6rwc.ReadWriteCloser config *config.NodeConfig log *log.Logger addr address.Address @@ -100,7 +93,7 @@ func MaximumMTU() uint64 { // Init initialises the TUN module. You must have acquired a Listener from // the Yggdrasil core before this point and it must not be in use elsewhere. -func (tun *TunAdapter) Init(rwc IPReadWriteCloser, config *config.NodeConfig, log *log.Logger, options interface{}) error { +func (tun *TunAdapter) Init(rwc *ipv6rwc.ReadWriteCloser, config *config.NodeConfig, log *log.Logger, options interface{}) error { tun.rwc = rwc tun.config = config tun.log = log From 538ee13669bed5c3637888d0b3ae9e49d833d20c Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Wed, 1 Sep 2021 06:16:57 +0500 Subject: [PATCH 026/345] Add type core.AddHandlerFunc --- src/admin/admin.go | 6 +++--- src/core/api.go | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/admin/admin.go b/src/admin/admin.go index d41a48e1..ce831395 100644 --- a/src/admin/admin.go +++ b/src/admin/admin.go @@ -38,8 +38,8 @@ type AdminSocketResponse struct { } type handler struct { - args []string // List of human-readable argument names - handler func(json.RawMessage) (interface{}, error) // First is input map, second is output + args []string // List of human-readable argument names + handler core.AddHandlerFunc // First is input map, second is output } type ListResponse struct { @@ -51,7 +51,7 @@ type ListEntry struct { } // AddHandler is called for each admin function to add the handler and help documentation to the API. -func (a *AdminSocket) AddHandler(name string, args []string, handlerfunc func(json.RawMessage) (interface{}, error)) error { +func (a *AdminSocket) AddHandler(name string, args []string, handlerfunc core.AddHandlerFunc) error { if _, ok := a.handlers[strings.ToLower(name)]; ok { return errors.New("handler already exists") } diff --git a/src/core/api.go b/src/core/api.go index c312923d..ae13d499 100644 --- a/src/core/api.go +++ b/src/core/api.go @@ -242,9 +242,11 @@ func (c *Core) PublicKey() ed25519.PublicKey { // Hack to get the admin stuff working, TODO something cleaner type AddHandler interface { - AddHandler(name string, args []string, handlerfunc func(json.RawMessage) (interface{}, error)) error + AddHandler(name string, args []string, handlerfunc AddHandlerFunc) error } +type AddHandlerFunc func(json.RawMessage) (interface{}, error) + // SetAdmin must be called after Init and before Start. // It sets the admin handler for NodeInfo and the Debug admin functions. func (c *Core) SetAdmin(a AddHandler) error { From a5f2ba80a2d4aecd61f06e85bc1e69995d821f75 Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Wed, 1 Sep 2021 06:24:25 +0500 Subject: [PATCH 027/345] Organize code in "src/core/proto.go" --- src/core/proto.go | 83 ++++++++++++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 34 deletions(-) diff --git a/src/core/proto.go b/src/core/proto.go index e60caeff..da9d9b99 100644 --- a/src/core/proto.go +++ b/src/core/proto.go @@ -34,21 +34,26 @@ type keyArray [ed25519.PublicKeySize]byte type protoHandler struct { phony.Inbox - core *Core + nodeinfo nodeinfo - sreqs map[keyArray]*reqInfo - preqs map[keyArray]*reqInfo - dreqs map[keyArray]*reqInfo + core *Core + + getSelfRequests map[keyArray]*reqInfo + getPeersRequests map[keyArray]*reqInfo + getDHTRequests map[keyArray]*reqInfo } func (p *protoHandler) init(core *Core) { p.core = core p.nodeinfo.init(p) - p.sreqs = make(map[keyArray]*reqInfo) - p.preqs = make(map[keyArray]*reqInfo) - p.dreqs = make(map[keyArray]*reqInfo) + + p.getSelfRequests = make(map[keyArray]*reqInfo) + p.getPeersRequests = make(map[keyArray]*reqInfo) + p.getDHTRequests = make(map[keyArray]*reqInfo) } +// Common functions + func (p *protoHandler) handleProto(from phony.Actor, key keyArray, bs []byte) { if len(bs) == 0 { return @@ -85,22 +90,29 @@ func (p *protoHandler) _handleDebug(key keyArray, bs []byte) { } } +func (p *protoHandler) _sendDebug(key keyArray, dType uint8, data []byte) { + bs := append([]byte{typeSessionProto, typeProtoDebug, dType}, data...) + _, _ = p.core.PacketConn.WriteTo(bs, iwt.Addr(key[:])) +} + +// Get self + func (p *protoHandler) sendGetSelfRequest(key keyArray, callback func([]byte)) { p.Act(nil, func() { - if info := p.sreqs[key]; info != nil { + if info := p.getSelfRequests[key]; info != nil { info.timer.Stop() - delete(p.sreqs, key) + delete(p.getSelfRequests, key) } info := new(reqInfo) info.callback = callback info.timer = time.AfterFunc(time.Minute, func() { p.Act(nil, func() { - if p.sreqs[key] == info { - delete(p.sreqs, key) + if p.getSelfRequests[key] == info { + delete(p.getSelfRequests, key) } }) }) - p.sreqs[key] = info + p.getSelfRequests[key] = info p._sendDebug(key, typeDebugGetSelfRequest, nil) }) } @@ -119,29 +131,31 @@ func (p *protoHandler) _handleGetSelfRequest(key keyArray) { } func (p *protoHandler) _handleGetSelfResponse(key keyArray, bs []byte) { - if info := p.sreqs[key]; info != nil { + if info := p.getSelfRequests[key]; info != nil { info.timer.Stop() info.callback(bs) - delete(p.sreqs, key) + delete(p.getSelfRequests, key) } } +// Get peers + func (p *protoHandler) sendGetPeersRequest(key keyArray, callback func([]byte)) { p.Act(nil, func() { - if info := p.preqs[key]; info != nil { + if info := p.getPeersRequests[key]; info != nil { info.timer.Stop() - delete(p.preqs, key) + delete(p.getPeersRequests, key) } info := new(reqInfo) info.callback = callback info.timer = time.AfterFunc(time.Minute, func() { p.Act(nil, func() { - if p.preqs[key] == info { - delete(p.preqs, key) + if p.getPeersRequests[key] == info { + delete(p.getPeersRequests, key) } }) }) - p.preqs[key] = info + p.getPeersRequests[key] = info p._sendDebug(key, typeDebugGetPeersRequest, nil) }) } @@ -161,29 +175,31 @@ func (p *protoHandler) _handleGetPeersRequest(key keyArray) { } func (p *protoHandler) _handleGetPeersResponse(key keyArray, bs []byte) { - if info := p.preqs[key]; info != nil { + if info := p.getPeersRequests[key]; info != nil { info.timer.Stop() info.callback(bs) - delete(p.preqs, key) + delete(p.getPeersRequests, key) } } +// Get DHT + func (p *protoHandler) sendGetDHTRequest(key keyArray, callback func([]byte)) { p.Act(nil, func() { - if info := p.dreqs[key]; info != nil { + if info := p.getDHTRequests[key]; info != nil { info.timer.Stop() - delete(p.dreqs, key) + delete(p.getDHTRequests, key) } info := new(reqInfo) info.callback = callback info.timer = time.AfterFunc(time.Minute, func() { p.Act(nil, func() { - if p.dreqs[key] == info { - delete(p.dreqs, key) + if p.getDHTRequests[key] == info { + delete(p.getDHTRequests, key) } }) }) - p.dreqs[key] = info + p.getDHTRequests[key] = info p._sendDebug(key, typeDebugGetDHTRequest, nil) }) } @@ -203,19 +219,14 @@ func (p *protoHandler) _handleGetDHTRequest(key keyArray) { } func (p *protoHandler) _handleGetDHTResponse(key keyArray, bs []byte) { - if info := p.dreqs[key]; info != nil { + if info := p.getDHTRequests[key]; info != nil { info.timer.Stop() info.callback(bs) - delete(p.dreqs, key) + delete(p.getDHTRequests, key) } } -func (p *protoHandler) _sendDebug(key keyArray, dType uint8, data []byte) { - bs := append([]byte{typeSessionProto, typeProtoDebug, dType}, data...) - _, _ = p.core.PacketConn.WriteTo(bs, iwt.Addr(key[:])) -} - -// Admin socket stuff +// Admin socket stuff for "Get self" type DebugGetSelfRequest struct { Key string `json:"key"` @@ -255,6 +266,8 @@ func (p *protoHandler) getSelfHandler(in json.RawMessage) (interface{}, error) { } } +// Admin socket stuff for "Get peers" + type DebugGetPeersRequest struct { Key string `json:"key"` } @@ -303,6 +316,8 @@ func (p *protoHandler) getPeersHandler(in json.RawMessage) (interface{}, error) } } +// Admin socket stuff for "Get DHT" + type DebugGetDHTRequest struct { Key string `json:"key"` } From 3c89781057bed6e87daf3f40523c21d0a569d59b Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Wed, 1 Sep 2021 07:57:45 +0500 Subject: [PATCH 028/345] Align and reorder code for lesser diff --- src/core/proto.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/proto.go b/src/core/proto.go index da9d9b99..1151d006 100644 --- a/src/core/proto.go +++ b/src/core/proto.go @@ -35,8 +35,8 @@ type keyArray [ed25519.PublicKeySize]byte type protoHandler struct { phony.Inbox + core *Core nodeinfo nodeinfo - core *Core getSelfRequests map[keyArray]*reqInfo getPeersRequests map[keyArray]*reqInfo From 571186ca772e96b1f4226b2dd56252b9aa3e5a30 Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Fri, 3 Sep 2021 01:45:30 +0500 Subject: [PATCH 029/345] Rename protohandler attributes --- src/core/proto.go | 54 +++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/core/proto.go b/src/core/proto.go index 1151d006..3045972e 100644 --- a/src/core/proto.go +++ b/src/core/proto.go @@ -38,18 +38,18 @@ type protoHandler struct { core *Core nodeinfo nodeinfo - getSelfRequests map[keyArray]*reqInfo - getPeersRequests map[keyArray]*reqInfo - getDHTRequests map[keyArray]*reqInfo + selfRequests map[keyArray]*reqInfo + peersRequests map[keyArray]*reqInfo + dhtRequests map[keyArray]*reqInfo } func (p *protoHandler) init(core *Core) { p.core = core p.nodeinfo.init(p) - p.getSelfRequests = make(map[keyArray]*reqInfo) - p.getPeersRequests = make(map[keyArray]*reqInfo) - p.getDHTRequests = make(map[keyArray]*reqInfo) + p.selfRequests = make(map[keyArray]*reqInfo) + p.peersRequests = make(map[keyArray]*reqInfo) + p.dhtRequests = make(map[keyArray]*reqInfo) } // Common functions @@ -99,20 +99,20 @@ func (p *protoHandler) _sendDebug(key keyArray, dType uint8, data []byte) { func (p *protoHandler) sendGetSelfRequest(key keyArray, callback func([]byte)) { p.Act(nil, func() { - if info := p.getSelfRequests[key]; info != nil { + if info := p.selfRequests[key]; info != nil { info.timer.Stop() - delete(p.getSelfRequests, key) + delete(p.selfRequests, key) } info := new(reqInfo) info.callback = callback info.timer = time.AfterFunc(time.Minute, func() { p.Act(nil, func() { - if p.getSelfRequests[key] == info { - delete(p.getSelfRequests, key) + if p.selfRequests[key] == info { + delete(p.selfRequests, key) } }) }) - p.getSelfRequests[key] = info + p.selfRequests[key] = info p._sendDebug(key, typeDebugGetSelfRequest, nil) }) } @@ -131,10 +131,10 @@ func (p *protoHandler) _handleGetSelfRequest(key keyArray) { } func (p *protoHandler) _handleGetSelfResponse(key keyArray, bs []byte) { - if info := p.getSelfRequests[key]; info != nil { + if info := p.selfRequests[key]; info != nil { info.timer.Stop() info.callback(bs) - delete(p.getSelfRequests, key) + delete(p.selfRequests, key) } } @@ -142,20 +142,20 @@ func (p *protoHandler) _handleGetSelfResponse(key keyArray, bs []byte) { func (p *protoHandler) sendGetPeersRequest(key keyArray, callback func([]byte)) { p.Act(nil, func() { - if info := p.getPeersRequests[key]; info != nil { + if info := p.peersRequests[key]; info != nil { info.timer.Stop() - delete(p.getPeersRequests, key) + delete(p.peersRequests, key) } info := new(reqInfo) info.callback = callback info.timer = time.AfterFunc(time.Minute, func() { p.Act(nil, func() { - if p.getPeersRequests[key] == info { - delete(p.getPeersRequests, key) + if p.peersRequests[key] == info { + delete(p.peersRequests, key) } }) }) - p.getPeersRequests[key] = info + p.peersRequests[key] = info p._sendDebug(key, typeDebugGetPeersRequest, nil) }) } @@ -175,10 +175,10 @@ func (p *protoHandler) _handleGetPeersRequest(key keyArray) { } func (p *protoHandler) _handleGetPeersResponse(key keyArray, bs []byte) { - if info := p.getPeersRequests[key]; info != nil { + if info := p.peersRequests[key]; info != nil { info.timer.Stop() info.callback(bs) - delete(p.getPeersRequests, key) + delete(p.peersRequests, key) } } @@ -186,20 +186,20 @@ func (p *protoHandler) _handleGetPeersResponse(key keyArray, bs []byte) { func (p *protoHandler) sendGetDHTRequest(key keyArray, callback func([]byte)) { p.Act(nil, func() { - if info := p.getDHTRequests[key]; info != nil { + if info := p.dhtRequests[key]; info != nil { info.timer.Stop() - delete(p.getDHTRequests, key) + delete(p.dhtRequests, key) } info := new(reqInfo) info.callback = callback info.timer = time.AfterFunc(time.Minute, func() { p.Act(nil, func() { - if p.getDHTRequests[key] == info { - delete(p.getDHTRequests, key) + if p.dhtRequests[key] == info { + delete(p.dhtRequests, key) } }) }) - p.getDHTRequests[key] = info + p.dhtRequests[key] = info p._sendDebug(key, typeDebugGetDHTRequest, nil) }) } @@ -219,10 +219,10 @@ func (p *protoHandler) _handleGetDHTRequest(key keyArray) { } func (p *protoHandler) _handleGetDHTResponse(key keyArray, bs []byte) { - if info := p.getDHTRequests[key]; info != nil { + if info := p.dhtRequests[key]; info != nil { info.timer.Stop() info.callback(bs) - delete(p.getDHTRequests, key) + delete(p.dhtRequests, key) } } From 52345a2de49d47bfad23b5cf45435cd84fd971bc Mon Sep 17 00:00:00 2001 From: Fyodor Ustinov Date: Tue, 21 Sep 2021 23:19:25 +0300 Subject: [PATCH 030/345] Check tun.config is not equal to nil before usage (#830) We have to check tun.config is not nil before first use, not after. --- src/tuntap/tun.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index 4caefe4a..eddccbcd 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -114,11 +114,11 @@ func (tun *TunAdapter) _start() error { if tun.isOpen { return errors.New("TUN module is already started") } - tun.config.RLock() - defer tun.config.RUnlock() if tun.config == nil { return errors.New("no configuration available to TUN") } + tun.config.RLock() + defer tun.config.RUnlock() tun.addr = tun.rwc.Address() tun.subnet = tun.rwc.Subnet() addr := fmt.Sprintf("%s/%d", net.IP(tun.addr[:]).String(), 8*len(address.GetPrefix())-1) From 1c7deb72db461ee4c1ec96137b9242fb6acd1837 Mon Sep 17 00:00:00 2001 From: Paul Dee <647633+systemcrash@users.noreply.github.com> Date: Tue, 21 Sep 2021 22:19:40 +0200 Subject: [PATCH 031/345] Align struct elements to byte boundaries: reduce memory footprint. (#834) --- cmd/yggdrasil/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 95d40151..58b8230d 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -185,14 +185,14 @@ func setLogLevel(loglevel string, logger *log.Logger) { type yggArgs struct { genconf bool useconf bool - useconffile string normaliseconf bool confjson bool autoconf bool ver bool - logto string getaddr bool getsnet bool + useconffile string + logto string loglevel string } From 529a33034becaf0f44fc5b3069fb33f46e4c2bcd Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 23 Sep 2021 04:34:58 -0500 Subject: [PATCH 032/345] gofmt to add new build comments --- src/core/debug.go | 1 + src/core/tcp_darwin.go | 1 + src/core/tcp_linux.go | 1 + src/core/tcp_other.go | 1 + src/defaults/defaults_darwin.go | 1 + src/defaults/defaults_freebsd.go | 1 + src/defaults/defaults_linux.go | 1 + src/defaults/defaults_openbsd.go | 1 + src/defaults/defaults_other.go | 1 + src/defaults/defaults_windows.go | 1 + src/multicast/multicast_darwin.go | 1 + src/multicast/multicast_other.go | 1 + src/multicast/multicast_unix.go | 1 + src/multicast/multicast_windows.go | 1 + src/tuntap/tun_bsd.go | 1 + src/tuntap/tun_darwin.go | 1 + src/tuntap/tun_linux.go | 1 + src/tuntap/tun_other.go | 1 + src/tuntap/tun_windows.go | 1 + 19 files changed, 19 insertions(+) diff --git a/src/core/debug.go b/src/core/debug.go index 0fc08259..eb406798 100644 --- a/src/core/debug.go +++ b/src/core/debug.go @@ -1,3 +1,4 @@ +//go:build debug // +build debug package core diff --git a/src/core/tcp_darwin.go b/src/core/tcp_darwin.go index 6b85c621..2ea3abc8 100644 --- a/src/core/tcp_darwin.go +++ b/src/core/tcp_darwin.go @@ -1,3 +1,4 @@ +//go:build darwin // +build darwin package core diff --git a/src/core/tcp_linux.go b/src/core/tcp_linux.go index 558b4e56..e59c3121 100644 --- a/src/core/tcp_linux.go +++ b/src/core/tcp_linux.go @@ -1,3 +1,4 @@ +//go:build linux // +build linux package core diff --git a/src/core/tcp_other.go b/src/core/tcp_other.go index 97b81ed1..8dd76f28 100644 --- a/src/core/tcp_other.go +++ b/src/core/tcp_other.go @@ -1,3 +1,4 @@ +//go:build !darwin && !linux // +build !darwin,!linux package core diff --git a/src/defaults/defaults_darwin.go b/src/defaults/defaults_darwin.go index e16f398f..060ce814 100644 --- a/src/defaults/defaults_darwin.go +++ b/src/defaults/defaults_darwin.go @@ -1,3 +1,4 @@ +//go:build darwin // +build darwin package defaults diff --git a/src/defaults/defaults_freebsd.go b/src/defaults/defaults_freebsd.go index 6c3e1c60..84df48ad 100644 --- a/src/defaults/defaults_freebsd.go +++ b/src/defaults/defaults_freebsd.go @@ -1,3 +1,4 @@ +//go:build freebsd // +build freebsd package defaults diff --git a/src/defaults/defaults_linux.go b/src/defaults/defaults_linux.go index 95c7ae95..c7f5f119 100644 --- a/src/defaults/defaults_linux.go +++ b/src/defaults/defaults_linux.go @@ -1,3 +1,4 @@ +//go:build linux // +build linux package defaults diff --git a/src/defaults/defaults_openbsd.go b/src/defaults/defaults_openbsd.go index ef339546..0ec877ca 100644 --- a/src/defaults/defaults_openbsd.go +++ b/src/defaults/defaults_openbsd.go @@ -1,3 +1,4 @@ +//go:build openbsd // +build openbsd package defaults diff --git a/src/defaults/defaults_other.go b/src/defaults/defaults_other.go index d1417322..37637425 100644 --- a/src/defaults/defaults_other.go +++ b/src/defaults/defaults_other.go @@ -1,3 +1,4 @@ +//go:build !linux && !darwin && !windows && !openbsd && !freebsd // +build !linux,!darwin,!windows,!openbsd,!freebsd package defaults diff --git a/src/defaults/defaults_windows.go b/src/defaults/defaults_windows.go index e81d09cf..c1ea9689 100644 --- a/src/defaults/defaults_windows.go +++ b/src/defaults/defaults_windows.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package defaults diff --git a/src/multicast/multicast_darwin.go b/src/multicast/multicast_darwin.go index e7075c0a..7ad0c543 100644 --- a/src/multicast/multicast_darwin.go +++ b/src/multicast/multicast_darwin.go @@ -1,3 +1,4 @@ +//go:build darwin // +build darwin package multicast diff --git a/src/multicast/multicast_other.go b/src/multicast/multicast_other.go index dfcf625f..9977951c 100644 --- a/src/multicast/multicast_other.go +++ b/src/multicast/multicast_other.go @@ -1,3 +1,4 @@ +//go:build !linux && !darwin && !netbsd && !freebsd && !openbsd && !dragonflybsd && !windows // +build !linux,!darwin,!netbsd,!freebsd,!openbsd,!dragonflybsd,!windows package multicast diff --git a/src/multicast/multicast_unix.go b/src/multicast/multicast_unix.go index 1ff48b17..9c822fcf 100644 --- a/src/multicast/multicast_unix.go +++ b/src/multicast/multicast_unix.go @@ -1,3 +1,4 @@ +//go:build linux || netbsd || freebsd || openbsd || dragonflybsd // +build linux netbsd freebsd openbsd dragonflybsd package multicast diff --git a/src/multicast/multicast_windows.go b/src/multicast/multicast_windows.go index 3666faaa..515412a4 100644 --- a/src/multicast/multicast_windows.go +++ b/src/multicast/multicast_windows.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package multicast diff --git a/src/tuntap/tun_bsd.go b/src/tuntap/tun_bsd.go index 75158857..fe36266b 100644 --- a/src/tuntap/tun_bsd.go +++ b/src/tuntap/tun_bsd.go @@ -1,3 +1,4 @@ +//go:build openbsd || freebsd // +build openbsd freebsd package tuntap diff --git a/src/tuntap/tun_darwin.go b/src/tuntap/tun_darwin.go index 75938881..6f6e2528 100644 --- a/src/tuntap/tun_darwin.go +++ b/src/tuntap/tun_darwin.go @@ -1,3 +1,4 @@ +//go:build !mobile // +build !mobile package tuntap diff --git a/src/tuntap/tun_linux.go b/src/tuntap/tun_linux.go index 0a845368..f849c00f 100644 --- a/src/tuntap/tun_linux.go +++ b/src/tuntap/tun_linux.go @@ -1,3 +1,4 @@ +//go:build !mobile // +build !mobile package tuntap diff --git a/src/tuntap/tun_other.go b/src/tuntap/tun_other.go index c0321267..8ce24953 100644 --- a/src/tuntap/tun_other.go +++ b/src/tuntap/tun_other.go @@ -1,3 +1,4 @@ +//go:build !linux && !darwin && !windows && !openbsd && !freebsd && !mobile // +build !linux,!darwin,!windows,!openbsd,!freebsd,!mobile package tuntap diff --git a/src/tuntap/tun_windows.go b/src/tuntap/tun_windows.go index 7b7ee710..8dce7274 100644 --- a/src/tuntap/tun_windows.go +++ b/src/tuntap/tun_windows.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package tuntap From 86e5306eec42324a7e68b4a5e37b7b9d89e98c83 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 23 Sep 2021 04:35:31 -0500 Subject: [PATCH 033/345] fix race from mutex that wasn't held long enough --- src/ipv6rwc/ipv6rwc.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/ipv6rwc/ipv6rwc.go b/src/ipv6rwc/ipv6rwc.go index 1c715f0f..f71c638e 100644 --- a/src/ipv6rwc/ipv6rwc.go +++ b/src/ipv6rwc/ipv6rwc.go @@ -129,6 +129,7 @@ func (k *keyStore) sendToSubnet(subnet address.Subnet, bs []byte) { func (k *keyStore) update(key ed25519.PublicKey) *keyInfo { k.mutex.Lock() + defer k.mutex.Unlock() var kArray keyArray copy(kArray[:], key) var info *keyInfo @@ -140,8 +141,6 @@ func (k *keyStore) update(key ed25519.PublicKey) *keyInfo { k.keyToInfo[info.key] = info k.addrToInfo[info.address] = info k.subnetToInfo[info.subnet] = info - k.resetTimeout(info) - k.mutex.Unlock() if buf := k.addrBuffer[info.address]; buf != nil { k.core.WriteTo(buf.packet, iwt.Addr(info.key[:])) delete(k.addrBuffer, info.address) @@ -150,10 +149,8 @@ func (k *keyStore) update(key ed25519.PublicKey) *keyInfo { k.core.WriteTo(buf.packet, iwt.Addr(info.key[:])) delete(k.subnetBuffer, info.subnet) } - } else { - k.resetTimeout(info) - k.mutex.Unlock() } + k.resetTimeout(info) return info } From e5d638ff4bdd1bf9847e6e645b658b14f60278ae Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 23 Sep 2021 04:39:12 -0500 Subject: [PATCH 034/345] better way to empty ipv6rwc buffer --- src/ipv6rwc/ipv6rwc.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/ipv6rwc/ipv6rwc.go b/src/ipv6rwc/ipv6rwc.go index f71c638e..fc2a688f 100644 --- a/src/ipv6rwc/ipv6rwc.go +++ b/src/ipv6rwc/ipv6rwc.go @@ -129,10 +129,10 @@ func (k *keyStore) sendToSubnet(subnet address.Subnet, bs []byte) { func (k *keyStore) update(key ed25519.PublicKey) *keyInfo { k.mutex.Lock() - defer k.mutex.Unlock() var kArray keyArray copy(kArray[:], key) var info *keyInfo + var packets [][]byte if info = k.keyToInfo[kArray]; info == nil { info = new(keyInfo) info.key = kArray @@ -142,15 +142,19 @@ func (k *keyStore) update(key ed25519.PublicKey) *keyInfo { k.addrToInfo[info.address] = info k.subnetToInfo[info.subnet] = info if buf := k.addrBuffer[info.address]; buf != nil { - k.core.WriteTo(buf.packet, iwt.Addr(info.key[:])) + packets = append(packets, buf.packet) delete(k.addrBuffer, info.address) } if buf := k.subnetBuffer[info.subnet]; buf != nil { - k.core.WriteTo(buf.packet, iwt.Addr(info.key[:])) + packets = append(packets, buf.packet) delete(k.subnetBuffer, info.subnet) } } k.resetTimeout(info) + k.mutex.Unlock() + for _, packet := range packets { + k.core.WriteTo(packet, iwt.Addr(info.key[:])) + } return info } From 9a1d1df85edb5442ec75382334fd5a265382800f Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 23 Sep 2021 12:11:03 +0100 Subject: [PATCH 035/345] Use newer Xcode image for macOS builds in CircleCI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5ebd26e2..fa49c34d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -105,7 +105,7 @@ jobs: build-macos: macos: - xcode: "10.0.0" + xcode: "13.0.0" working_directory: ~/go/src/github.com/yggdrasil-network/yggdrasil-go From 99227b60cedfb278b1b6d6ac9ae965f47fce5ccf Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Tue, 28 Sep 2021 11:02:15 +0100 Subject: [PATCH 036/345] Update CI to use Go 1.17, produce Apple Silicon builds (closes #844) --- .circleci/config.yml | 16 ++++--- contrib/macos/create-pkg.sh | 4 ++ src/multicast/multicast_darwin.go | 40 ++-------------- src/multicast/multicast_darwin_cgo.go | 69 +++++++++++++++++++++++++++ src/multicast/multicast_other.go | 4 +- 5 files changed, 89 insertions(+), 44 deletions(-) create mode 100644 src/multicast/multicast_darwin_cgo.go diff --git a/.circleci/config.yml b/.circleci/config.yml index fa49c34d..065f2b0b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ version: 2.1 jobs: lint: docker: - - image: circleci/golang:1.16 + - image: circleci/golang:1.17 steps: - checkout @@ -23,7 +23,7 @@ jobs: build-linux: docker: - - image: circleci/golang:1.16 + - image: circleci/golang:1.17 steps: - checkout @@ -124,11 +124,11 @@ jobs: echo -e "Host *\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config - run: - name: Install Go 1.16 + name: Install Go 1.17 command: | cd /tmp - curl -LO https://dl.google.com/go/go1.16.darwin-amd64.pkg - sudo installer -pkg /tmp/go1.16.darwin-amd64.pkg -target / + curl -LO https://dl.google.com/go/go1.17.darwin-amd64.pkg + sudo installer -pkg /tmp/go1.17.darwin-amd64.pkg -target / #- run: # name: Install Gomobile @@ -142,11 +142,15 @@ jobs: GO111MODULE=on GOOS=darwin GOARCH=amd64 ./build cp yggdrasil /tmp/upload/$CINAME-$CIVERSION-darwin-amd64 cp yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-darwin-amd64; + GO111MODULE=on GOOS=darwin GOARCH=arm64 ./build + cp yggdrasil /tmp/upload/$CINAME-$CIVERSION-darwin-arm64 + cp yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-darwin-arm64; - run: name: Build for macOS (.pkg format) command: | PKGARCH=amd64 sh contrib/macos/create-pkg.sh + PKGARCH=arm64 sh contrib/macos/create-pkg.sh mv *.pkg /tmp/upload/ #- run: @@ -164,7 +168,7 @@ jobs: build-other: docker: - - image: circleci/golang:1.16 + - image: circleci/golang:1.17 steps: - checkout diff --git a/contrib/macos/create-pkg.sh b/contrib/macos/create-pkg.sh index cc9a74f7..919c45ed 100755 --- a/contrib/macos/create-pkg.sh +++ b/contrib/macos/create-pkg.sh @@ -15,6 +15,10 @@ command -v mkbom >/dev/null 2>&1 || ( sudo make install || (echo "Failed to build mkbom"; exit 1) ) +# Build Yggdrasil +echo "running GO111MODULE=on GOOS=darwin GOARCH=${PKGARCH-amd64} ./build" +GO111MODULE=on GOOS=darwin GOARCH=${PKGARCH-amd64} ./build + # Check if we can find the files we need - they should # exist if you are running this script from the root of # the yggdrasil-go repo and you have ran ./build diff --git a/src/multicast/multicast_darwin.go b/src/multicast/multicast_darwin.go index 7ad0c543..22cf3998 100644 --- a/src/multicast/multicast_darwin.go +++ b/src/multicast/multicast_darwin.go @@ -1,49 +1,17 @@ -//go:build darwin -// +build darwin +//go:build !cgo && (darwin || ios) +// +build !cgo +// +build darwin ios package multicast -/* -#cgo CFLAGS: -x objective-c -#cgo LDFLAGS: -framework Foundation -#import -NSNetServiceBrowser *serviceBrowser; -void StartAWDLBrowsing() { - if (serviceBrowser == nil) { - serviceBrowser = [[NSNetServiceBrowser alloc] init]; - serviceBrowser.includesPeerToPeer = YES; - } - [serviceBrowser searchForServicesOfType:@"_yggdrasil._tcp" inDomain:@""]; -} -void StopAWDLBrowsing() { - if (serviceBrowser == nil) { - return; - } - [serviceBrowser stop]; -} -*/ -import "C" import ( "syscall" - "time" "golang.org/x/sys/unix" ) func (m *Multicast) _multicastStarted() { - if !m.isOpen { - return - } - C.StopAWDLBrowsing() - for intf := range m._interfaces { - if intf == "awdl0" { - C.StartAWDLBrowsing() - break - } - } - time.AfterFunc(time.Minute, func() { - m.Act(nil, m._multicastStarted) - }) + } func (m *Multicast) multicastReuse(network string, address string, c syscall.RawConn) error { diff --git a/src/multicast/multicast_darwin_cgo.go b/src/multicast/multicast_darwin_cgo.go new file mode 100644 index 00000000..b7d7358c --- /dev/null +++ b/src/multicast/multicast_darwin_cgo.go @@ -0,0 +1,69 @@ +//go:build (darwin && cgo) || (ios && cgo) +// +build darwin,cgo ios,cgo + +package multicast + +/* +#cgo CFLAGS: -x objective-c +#cgo LDFLAGS: -framework Foundation +#import +NSNetServiceBrowser *serviceBrowser; +void StartAWDLBrowsing() { + if (serviceBrowser == nil) { + serviceBrowser = [[NSNetServiceBrowser alloc] init]; + serviceBrowser.includesPeerToPeer = YES; + } + [serviceBrowser searchForServicesOfType:@"_yggdrasil._tcp" inDomain:@""]; +} +void StopAWDLBrowsing() { + if (serviceBrowser == nil) { + return; + } + [serviceBrowser stop]; +} +*/ +import "C" +import ( + "syscall" + "time" + + "golang.org/x/sys/unix" +) + +func (m *Multicast) _multicastStarted() { + if !m.isOpen { + return + } + C.StopAWDLBrowsing() + for intf := range m._interfaces { + if intf == "awdl0" { + C.StartAWDLBrowsing() + break + } + } + time.AfterFunc(time.Minute, func() { + m.Act(nil, m._multicastStarted) + }) +} + +func (m *Multicast) multicastReuse(network string, address string, c syscall.RawConn) error { + var control error + var reuseport error + var recvanyif error + + control = c.Control(func(fd uintptr) { + reuseport = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1) + + // sys/socket.h: #define SO_RECV_ANYIF 0x1104 + recvanyif = unix.SetsockoptInt(int(fd), syscall.SOL_SOCKET, 0x1104, 1) + }) + + switch { + case reuseport != nil: + return reuseport + case recvanyif != nil: + return recvanyif + default: + return control + } +} diff --git a/src/multicast/multicast_other.go b/src/multicast/multicast_other.go index 9977951c..263f4ffc 100644 --- a/src/multicast/multicast_other.go +++ b/src/multicast/multicast_other.go @@ -1,5 +1,5 @@ -//go:build !linux && !darwin && !netbsd && !freebsd && !openbsd && !dragonflybsd && !windows -// +build !linux,!darwin,!netbsd,!freebsd,!openbsd,!dragonflybsd,!windows +//go:build !linux && !darwin && !ios && !netbsd && !freebsd && !openbsd && !dragonflybsd && !windows +// +build !linux,!darwin,!ios,!netbsd,!freebsd,!openbsd,!dragonflybsd,!windows package multicast From 4859accbb038f8db3c3a541d0f3f3f76de75b9fb Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Tue, 2 Nov 2021 18:03:16 +0000 Subject: [PATCH 037/345] Fix panic in `address.GetKey()` (fixes #860) --- src/address/address.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/address/address.go b/src/address/address.go index 0e2400ed..c7f2eb46 100644 --- a/src/address/address.go +++ b/src/address/address.go @@ -129,7 +129,11 @@ func (a *Address) GetKey() ed25519.PublicKey { bits <<= byte(idx % 8) keyIdx := keyOffset + (idx - addrOffset) bits >>= byte(keyIdx % 8) - key[keyIdx/8] |= bits + idx := keyIdx / 8 + if idx >= len(key) { + break + } + key[idx] |= bits } for idx := range key { key[idx] = ^key[idx] From 5c19f3f88c6b664456721a933c4e37c85214504d Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 3 Nov 2021 10:33:00 +0000 Subject: [PATCH 038/345] Update dependencies --- go.mod | 11 +++++------ go.sum | 52 ++++++++++++++++++++++++++++++++-------------------- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/go.mod b/go.mod index 398504cb..05044531 100644 --- a/go.mod +++ b/go.mod @@ -17,10 +17,9 @@ require ( github.com/mitchellh/mapstructure v1.4.1 github.com/vishvananda/netlink v1.1.0 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect - golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect - golang.org/x/net v0.0.0-20210610132358-84b48f89b13b - golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 - golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f - golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2 - golang.zx2c4.com/wireguard/windows v0.3.14 + golang.org/x/net v0.0.0-20211101193420-4a448f8816b3 + golang.org/x/sys v0.0.0-20211102192858-4dd72447c267 + golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b + golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a + golang.zx2c4.com/wireguard/windows v0.4.12 ) diff --git a/go.sum b/go.sum index 5d11fad6..e6df746b 100644 --- a/go.sum +++ b/go.sum @@ -38,42 +38,54 @@ github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYp github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210610132358-84b48f89b13b h1:k+E048sYJHyVnsr1GDrRZWQ32D2C7lWs9JRc0bel53A= -golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210927181540-4e4d966f7476/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211011170408-caeb26a5c8c0/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211101193420-4a448f8816b3 h1:VrJZAjbekhoRn7n5FBujY31gboH+iB3pdLxn3gE9FjU= +golang.org/x/net v0.0.0-20211101193420-4a448f8816b3/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 h1:faDu4veV+8pcThn4fewv6TVlNCezafGoC1gM/mxQLbQ= -golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211102192858-4dd72447c267 h1:7zYaz3tjChtpayGDzu6H0hDAUM5zIGA2XW7kRNgQ0jc= +golang.org/x/sys v0.0.0-20211102192858-4dd72447c267/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f h1:yQJrRE0hDxDFmZLlRaw+3vusO4fwNHgHIjUOMO7bHYI= -golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b h1:NXqSWXSRUSCaFuvitrWtU169I3876zRTalMRbfd6LL0= +golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.zx2c4.com/wireguard v0.0.0-20210510202332-9844c74f67ec/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg= -golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2 h1:wfOOSvHgIzTZ9h5Vb6yUFZNn7uf3bT7PeYsHOO7tYDM= -golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2/go.mod h1:laHzsbfMhGSobUmruXWAyMKKHSqvIcrqZJMyHD+/3O8= -golang.zx2c4.com/wireguard/windows v0.3.14 h1:5yIDYyrQyGkLqV+tzY4ilMNeIvQeMXAz0glZz9u179A= -golang.zx2c4.com/wireguard/windows v0.3.14/go.mod h1:3P4IEAsb+BjlKZmpUXgy74c0iX9AVwwr3WcVJ8nPgME= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.zx2c4.com/wireguard v0.0.0-20211012062646-82d2aa87aa62/go.mod h1:id8Oh3eCCmpj9uVGWVjsUAl6UPX5ysMLzu6QxJU2UOU= +golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a h1:tTbyylK9/D3u/wEP26Vx7L700UpY48nhioJWZM1vhZw= +golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a/go.mod h1:id8Oh3eCCmpj9uVGWVjsUAl6UPX5ysMLzu6QxJU2UOU= +golang.zx2c4.com/wireguard/windows v0.4.12 h1:CUmbdWKVNzTSsVb4yUAiEwL3KsabdJkEPdDjCHxBlhA= +golang.zx2c4.com/wireguard/windows v0.4.12/go.mod h1:PW4y+d9oY83XU9rRwRwrJDwEMuhVjMxu2gfD1cfzS7w= From 4f3117d81d76d5219063016e458c4d2f748ff05d Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 3 Nov 2021 17:40:06 +0000 Subject: [PATCH 039/345] Use `network-online.target` instead of `network.target` for systemd service unit --- contrib/systemd/yggdrasil.service | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/systemd/yggdrasil.service b/contrib/systemd/yggdrasil.service index 27d27907..f8c2dd22 100644 --- a/contrib/systemd/yggdrasil.service +++ b/contrib/systemd/yggdrasil.service @@ -1,8 +1,8 @@ [Unit] Description=yggdrasil -Wants=network.target +Wants=network-online.target Wants=yggdrasil-default-config.service -After=network.target +After=network-online.target After=yggdrasil-default-config.service [Service] From 1f64319712a83aaa7f79789ab247db9542b04dbf Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 3 Nov 2021 17:53:35 +0000 Subject: [PATCH 040/345] Version 0.4.1 --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bdb634f3..05291f85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - in case of vulnerabilities. --> +## [0.4.1] - 2021-11-03 +### Added +- TLS peerings now support Server Name Indication (SNI) + - The SNI is sent automatically if the peering URI contains a DNS name + - A custom SNI can be specified by adding the `?sni=domain.com` parameter to the peering URI +- A new `ipv6rwc` API package now implements the IPv6-specific logic separate from the `tun` package + +### Fixed +- A crash when calculating the partial public key for very high IPv6 addresses has been fixed +- A crash due to a concurrent map write has been fixed +- A crash due to missing TUN configuration has been fixed +- A race condition in the keystore code has been fixed + ## [0.4.0] - 2021-07-04 ### Added - New routing scheme, which is backwards incompatible with previous versions of Yggdrasil From 03a5cce5bb739d5f3ad5d9877c38817cf88eccd5 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 3 Nov 2021 20:03:27 +0000 Subject: [PATCH 041/345] Revert Wireguard update This reverts commit 5c19f3f88c6b664456721a933c4e37c85214504d. --- go.mod | 11 ++++++----- go.sum | 52 ++++++++++++++++++++-------------------------------- 2 files changed, 26 insertions(+), 37 deletions(-) diff --git a/go.mod b/go.mod index 05044531..398504cb 100644 --- a/go.mod +++ b/go.mod @@ -17,9 +17,10 @@ require ( github.com/mitchellh/mapstructure v1.4.1 github.com/vishvananda/netlink v1.1.0 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect - golang.org/x/net v0.0.0-20211101193420-4a448f8816b3 - golang.org/x/sys v0.0.0-20211102192858-4dd72447c267 - golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b - golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a - golang.zx2c4.com/wireguard/windows v0.4.12 + golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect + golang.org/x/net v0.0.0-20210610132358-84b48f89b13b + golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 + golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f + golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2 + golang.zx2c4.com/wireguard/windows v0.3.14 ) diff --git a/go.sum b/go.sum index e6df746b..5d11fad6 100644 --- a/go.sum +++ b/go.sum @@ -38,54 +38,42 @@ github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYp github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210927181540-4e4d966f7476/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211011170408-caeb26a5c8c0/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211101193420-4a448f8816b3 h1:VrJZAjbekhoRn7n5FBujY31gboH+iB3pdLxn3gE9FjU= -golang.org/x/net v0.0.0-20211101193420-4a448f8816b3/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b h1:k+E048sYJHyVnsr1GDrRZWQ32D2C7lWs9JRc0bel53A= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211102192858-4dd72447c267 h1:7zYaz3tjChtpayGDzu6H0hDAUM5zIGA2XW7kRNgQ0jc= -golang.org/x/sys v0.0.0-20211102192858-4dd72447c267/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 h1:faDu4veV+8pcThn4fewv6TVlNCezafGoC1gM/mxQLbQ= +golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b h1:NXqSWXSRUSCaFuvitrWtU169I3876zRTalMRbfd6LL0= -golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= +golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f h1:yQJrRE0hDxDFmZLlRaw+3vusO4fwNHgHIjUOMO7bHYI= +golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.zx2c4.com/wireguard v0.0.0-20211012062646-82d2aa87aa62/go.mod h1:id8Oh3eCCmpj9uVGWVjsUAl6UPX5ysMLzu6QxJU2UOU= -golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a h1:tTbyylK9/D3u/wEP26Vx7L700UpY48nhioJWZM1vhZw= -golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a/go.mod h1:id8Oh3eCCmpj9uVGWVjsUAl6UPX5ysMLzu6QxJU2UOU= -golang.zx2c4.com/wireguard/windows v0.4.12 h1:CUmbdWKVNzTSsVb4yUAiEwL3KsabdJkEPdDjCHxBlhA= -golang.zx2c4.com/wireguard/windows v0.4.12/go.mod h1:PW4y+d9oY83XU9rRwRwrJDwEMuhVjMxu2gfD1cfzS7w= +golang.zx2c4.com/wireguard v0.0.0-20210510202332-9844c74f67ec/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg= +golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2 h1:wfOOSvHgIzTZ9h5Vb6yUFZNn7uf3bT7PeYsHOO7tYDM= +golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2/go.mod h1:laHzsbfMhGSobUmruXWAyMKKHSqvIcrqZJMyHD+/3O8= +golang.zx2c4.com/wireguard/windows v0.3.14 h1:5yIDYyrQyGkLqV+tzY4ilMNeIvQeMXAz0glZz9u179A= +golang.zx2c4.com/wireguard/windows v0.3.14/go.mod h1:3P4IEAsb+BjlKZmpUXgy74c0iX9AVwwr3WcVJ8nPgME= From e4e58831bf6b3d2a194c12c4e8dc3fd7351e6165 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 3 Nov 2021 22:16:53 +0000 Subject: [PATCH 042/345] Version 0.4.2 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05291f85..bb418b11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - in case of vulnerabilities. --> +## [0.4.2] - 2021-11-03 +### Fixed +- Reverted a dependency update which resulted in problems building with Go 1.16 and running on Windows + ## [0.4.1] - 2021-11-03 ### Added - TLS peerings now support Server Name Indication (SNI) From 87e936195ebaa1d11475d6fb3a73958c654be977 Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Thu, 4 Nov 2021 13:05:53 +0500 Subject: [PATCH 043/345] Add some tests (#828) * Add tests * Add tests * Add tests * Add tests * Fix code style * Remove unnecessary tests --- src/address/address_test.go | 114 ++++++++++++++++++++++++++++++++++++ src/config/config_test.go | 54 +++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 src/address/address_test.go create mode 100644 src/config/config_test.go diff --git a/src/address/address_test.go b/src/address/address_test.go new file mode 100644 index 00000000..a7939e0f --- /dev/null +++ b/src/address/address_test.go @@ -0,0 +1,114 @@ +package address + +import ( + "bytes" + "crypto/ed25519" + "math/rand" + "testing" +) + +func TestAddress_Address_IsValid(t *testing.T) { + var address Address + rand.Read(address[:]) + + address[0] = 0 + + if address.IsValid() { + t.Fatal("invalid address marked as valid") + } + + address[0] = 0x03 + + if address.IsValid() { + t.Fatal("invalid address marked as valid") + } + + address[0] = 0x02 + + if !address.IsValid() { + t.Fatal("valid address marked as invalid") + } +} + +func TestAddress_Subnet_IsValid(t *testing.T) { + var subnet Subnet + rand.Read(subnet[:]) + + subnet[0] = 0 + + if subnet.IsValid() { + t.Fatal("invalid subnet marked as valid") + } + + subnet[0] = 0x02 + + if subnet.IsValid() { + t.Fatal("invalid subnet marked as valid") + } + + subnet[0] = 0x03 + + if !subnet.IsValid() { + t.Fatal("valid subnet marked as invalid") + } +} + +func TestAddress_AddrForKey(t *testing.T) { + publicKey := ed25519.PublicKey{ + 189, 186, 207, 216, 34, 64, 222, 61, 205, 18, 57, 36, 203, 181, 82, 86, + 251, 141, 171, 8, 170, 152, 227, 5, 82, 138, 184, 79, 65, 158, 110, 251, + } + + expectedAddress := Address{ + 2, 0, 132, 138, 96, 79, 187, 126, 67, 132, 101, 219, 141, 182, 104, 149, + } + + if *AddrForKey(publicKey) != expectedAddress { + t.Fatal("invalid address returned") + } +} + +func TestAddress_SubnetForKey(t *testing.T) { + publicKey := ed25519.PublicKey{ + 189, 186, 207, 216, 34, 64, 222, 61, 205, 18, 57, 36, 203, 181, 82, 86, + 251, 141, 171, 8, 170, 152, 227, 5, 82, 138, 184, 79, 65, 158, 110, 251, + } + + expectedSubnet := Subnet{3, 0, 132, 138, 96, 79, 187, 126} + + if *SubnetForKey(publicKey) != expectedSubnet { + t.Fatal("invalid subnet returned") + } +} + +func TestAddress_Address_GetKey(t *testing.T) { + address := Address{ + 2, 0, 132, 138, 96, 79, 187, 126, 67, 132, 101, 219, 141, 182, 104, 149, + } + + expectedPublicKey := ed25519.PublicKey{ + 189, 186, 207, 216, 34, 64, 222, 61, + 205, 18, 57, 36, 203, 181, 127, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + } + + if !bytes.Equal(address.GetKey(), expectedPublicKey) { + t.Fatal("invalid public key returned") + } +} + +func TestAddress_Subnet_GetKey(t *testing.T) { + subnet := Subnet{3, 0, 132, 138, 96, 79, 187, 126} + + expectedPublicKey := ed25519.PublicKey{ + 189, 186, 207, 216, 34, 64, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + } + + if !bytes.Equal(subnet.GetKey(), expectedPublicKey) { + t.Fatal("invalid public key returned") + } +} diff --git a/src/config/config_test.go b/src/config/config_test.go new file mode 100644 index 00000000..8b6e14e1 --- /dev/null +++ b/src/config/config_test.go @@ -0,0 +1,54 @@ +package config + +import ( + "bytes" + "encoding/hex" + "testing" +) + +func TestConfig_Keys(t *testing.T) { + var nodeConfig NodeConfig + nodeConfig.NewKeys() + + publicKey1, err := hex.DecodeString(nodeConfig.PublicKey) + + if err != nil { + t.Fatal("can not decode generated public key") + } + + if len(publicKey1) == 0 { + t.Fatal("empty public key generated") + } + + privateKey1, err := hex.DecodeString(nodeConfig.PrivateKey) + + if err != nil { + t.Fatal("can not decode generated private key") + } + + if len(privateKey1) == 0 { + t.Fatal("empty private key generated") + } + + nodeConfig.NewKeys() + + publicKey2, err := hex.DecodeString(nodeConfig.PublicKey) + + if err != nil { + t.Fatal("can not decode generated public key") + } + + if bytes.Equal(publicKey2, publicKey1) { + t.Fatal("same public key generated") + } + + privateKey2, err := hex.DecodeString(nodeConfig.PrivateKey) + + if err != nil { + t.Fatal("can not decode generated private key") + } + + if bytes.Equal(privateKey2, privateKey1) { + t.Fatal("same private key generated") + } +} From 408d381591e99c273bf8db520a185478cdd8024f Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 6 Dec 2021 11:19:58 +0000 Subject: [PATCH 044/345] Set `hostArchitectures` in macOS `.pkg` installer --- contrib/macos/create-pkg.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/macos/create-pkg.sh b/contrib/macos/create-pkg.sh index 919c45ed..773f01ee 100755 --- a/contrib/macos/create-pkg.sh +++ b/contrib/macos/create-pkg.sh @@ -79,6 +79,7 @@ PKGNAME=$(sh contrib/semver/name.sh) PKGVERSION=$(sh contrib/semver/version.sh --bare) PKGARCH=${PKGARCH-amd64} PAYLOADSIZE=$(( $(wc -c pkgbuild/flat/base.pkg/Payload | awk '{ print $1 }') / 1024 )) +[ "$PKGARCH" = "amd64" ] && PKGHOSTARCH="x86_64" || PKGHOSTARCH=${PKGARCH} # Create the PackageInfo file cat > pkgbuild/flat/base.pkg/PackageInfo << EOF @@ -98,7 +99,7 @@ cat > pkgbuild/flat/Distribution << EOF Yggdrasil (${PKGNAME}-${PKGVERSION}) - +