From b704d7b497d2e0a4fc58a7b78383d06fcd410ca1 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sun, 4 Feb 2018 11:25:20 -0600 Subject: [PATCH 1/3] change mtu and enable udp chunking --- src/yggdrasil/udp.go | 2 +- yggdrasil.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/yggdrasil/udp.go b/src/yggdrasil/udp.go index 8d88df1d..ea396889 100644 --- a/src/yggdrasil/udp.go +++ b/src/yggdrasil/udp.go @@ -322,7 +322,7 @@ func (iface *udpInterface) reader() { //////////////////////////////////////////////////////////////////////////////// -const udp_chunkSize = 65535 +const udp_chunkSize = 1024 func udp_decode(bs []byte) (chunks, chunk, count uint8, payload []byte) { if len(bs) >= 3 { diff --git a/yggdrasil.go b/yggdrasil.go index 90ddb907..e583b184 100644 --- a/yggdrasil.go +++ b/yggdrasil.go @@ -249,8 +249,8 @@ func main() { n := node{} n.init(cfg, logger) logger.Println("Starting tun...") - n.core.DEBUG_startTun(cfg.IfName) // 1280, the smallest supported MTU - //n.core.DEBUG_startTunWithMTU(cfg.IfName, 65535) // Largest supported MTU + //n.core.DEBUG_startTun(cfg.IfName) // 1280, the smallest supported MTU + n.core.DEBUG_startTunWithMTU(cfg.IfName, 65535) // Largest supported MTU defer func() { logger.Println("Closing...") n.core.DEBUG_stopTun() From d42448932955cf2753e5ae00aacf8d6d57d0c019 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Fri, 9 Feb 2018 17:42:55 -0600 Subject: [PATCH 2/3] add tcp support and use it by default --- README.md | 3 + misc/yggdrasil.go.tcp | 283 ------------------------------------------ src/yggdrasil/udp.go | 2 +- yggdrasil.go | 19 +-- 4 files changed, 16 insertions(+), 291 deletions(-) delete mode 100644 misc/yggdrasil.go.tcp diff --git a/README.md b/README.md index edab6a7d..51829307 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,9 @@ In practice, you probably want to run this instead: This keeps a persistent set of keys (and by extension, IP address) and gives you the option of editing the configuration file. If you want to use it as an overlay network on top of e.g. the internet, then you can do so by adding the remote devices domain/address and port (as a string, e.g. `"1.2.3.4:5678"`) to the list of `Peers` in the configuration file. +You can control whether or not it peers over TCP or UDP by adding `tcp:` or `udp:` to the start of the string, i.e. `"udp:1.2.3.4:5678"`. +It is currently configured to accept incoming TCP and UDP connections. +In the interest of testing the TCP machinery, it's set to create TCP connections for auto-peering (over link-local IPv6), and to use TCP by default if no transport is specified for a manually configured peer. ### Platforms diff --git a/misc/yggdrasil.go.tcp b/misc/yggdrasil.go.tcp deleted file mode 100644 index c2c9a6b9..00000000 --- a/misc/yggdrasil.go.tcp +++ /dev/null @@ -1,283 +0,0 @@ -package main - -import "bytes" -import "encoding/hex" -import "encoding/json" -import "flag" -import "fmt" -import "io/ioutil" -import "net" -import "os" -import "os/signal" -import "time" -import "regexp" - -import _ "net/http/pprof" -import "net/http" -import "log" -import "runtime" - -import "golang.org/x/net/ipv6" - -import . "yggdrasil" - -/** -* This is a very crude wrapper around src/yggdrasil -* It can generate a new config (--genconf) -* It can read a config from stdin (--useconf) -* It can run with an automatic config (--autoconf) - */ - -type nodeConfig struct { - Listen string - AdminListen string - Peers []string - BoxPub string - BoxPriv string - SigPub string - SigPriv string - Multicast bool - LinkLocal string - IfName string -} - -type node struct { - core Core - sock *ipv6.PacketConn -} - -func (n *node) init(cfg *nodeConfig, logger *log.Logger) { - boxPub, err := hex.DecodeString(cfg.BoxPub) - if err != nil { - panic(err) - } - boxPriv, err := hex.DecodeString(cfg.BoxPriv) - if err != nil { - panic(err) - } - sigPub, err := hex.DecodeString(cfg.SigPub) - if err != nil { - panic(err) - } - sigPriv, err := hex.DecodeString(cfg.SigPriv) - if err != nil { - panic(err) - } - n.core.DEBUG_init(boxPub, boxPriv, sigPub, sigPriv) - n.core.DEBUG_setLogger(logger) - ifceExpr, err := regexp.Compile(cfg.LinkLocal) - if err != nil { - panic(err) - } - n.core.DEBUG_setIfceExpr(ifceExpr) - logger.Println("Starting interface...") - n.core.DEBUG_setupAndStartGlobalTCPInterface(cfg.Listen) - logger.Println("Started interface") - logger.Println("Starting admin socket...") - n.core.DEBUG_setupAndStartAdminInterface(cfg.AdminListen) - logger.Println("Started admin socket") - go func() { - if len(cfg.Peers) == 0 { - return - } - for { - for _, p := range cfg.Peers { - n.core.DEBUG_addTCPConn(p) - time.Sleep(time.Second) - } - time.Sleep(time.Minute) - } - }() -} - -func generateConfig() *nodeConfig { - core := Core{} - bpub, bpriv := core.DEBUG_newBoxKeys() - spub, spriv := core.DEBUG_newSigKeys() - cfg := nodeConfig{} - cfg.Listen = "[::]:0" - cfg.AdminListen = "localhost:9001" - cfg.BoxPub = hex.EncodeToString(bpub[:]) - cfg.BoxPriv = hex.EncodeToString(bpriv[:]) - cfg.SigPub = hex.EncodeToString(spub[:]) - cfg.SigPriv = hex.EncodeToString(spriv[:]) - cfg.Peers = []string{} - cfg.Multicast = true - cfg.LinkLocal = "" - cfg.IfName = "auto" - return &cfg -} - -func doGenconf() string { - cfg := generateConfig() - bs, err := json.MarshalIndent(cfg, "", " ") - if err != nil { - panic(err) - } - return string(bs) -} - -var multicastAddr = "[ff02::114]:9001" - -func (n *node) listen() { - groupAddr, err := net.ResolveUDPAddr("udp6", multicastAddr) - if err != nil { - panic(err) - } - bs := make([]byte, 2048) - for { - nBytes, rcm, fromAddr, err := n.sock.ReadFrom(bs) - if err != nil { - panic(err) - } - //if rcm == nil { continue } // wat - //fmt.Println("DEBUG:", "packet from:", fromAddr.String()) - if rcm != nil { - // Windows can't set the flag needed to return a non-nil value here - // So only make these checks if we get something useful back - // TODO? Skip them always, I'm not sure if they're really needed... - if !rcm.Dst.IsLinkLocalMulticast() { - continue - } - if !rcm.Dst.Equal(groupAddr.IP) { - continue - } - } - anAddr := string(bs[:nBytes]) - addr, err := net.ResolveTCPAddr("tcp6", anAddr) - if err != nil { - panic(err) - continue - } // Panic for testing, remove later - from := fromAddr.(*net.UDPAddr) - //fmt.Println("DEBUG:", "heard:", addr.IP.String(), "from:", from.IP.String()) - if addr.IP.String() != from.IP.String() { - continue - } - addr.Zone = from.Zone - saddr := addr.String() - //if _, isIn := n.peers[saddr]; isIn { continue } - //n.peers[saddr] = struct{}{} - n.core.DEBUG_addTCPConn(saddr) - //fmt.Println("DEBUG:", "added multicast peer:", saddr) - } -} - -func (n *node) announce() { - groupAddr, err := net.ResolveUDPAddr("udp6", multicastAddr) - if err != nil { - panic(err) - } - var anAddr net.TCPAddr - tcpAddr := n.core.DEBUG_getGlobalTCPAddr() - anAddr.Port = tcpAddr.Port - destAddr, err := net.ResolveUDPAddr("udp6", multicastAddr) - if err != nil { - panic(err) - } - for { - ifaces, err := net.Interfaces() - if err != nil { - panic(err) - } - for _, iface := range ifaces { - n.sock.JoinGroup(&iface, groupAddr) - //err := n.sock.JoinGroup(&iface, groupAddr) - //if err != nil { panic(err) } - addrs, err := iface.Addrs() - if err != nil { - panic(err) - } - for _, addr := range addrs { - addrIP, _, _ := net.ParseCIDR(addr.String()) - if addrIP.To4() != nil { - continue - } // IPv6 only - if !addrIP.IsLinkLocalUnicast() { - continue - } - anAddr.IP = addrIP - anAddr.Zone = iface.Name - destAddr.Zone = iface.Name - msg := []byte(anAddr.String()) - n.sock.WriteTo(msg, nil, destAddr) - break - } - time.Sleep(time.Second) - } - time.Sleep(time.Second) - } -} - -var pprof = flag.Bool("pprof", false, "Run pprof, see http://localhost:6060/debug/pprof/") -var genconf = flag.Bool("genconf", false, "print a new config to stdout") -var useconf = flag.Bool("useconf", false, "read config from stdin") -var autoconf = flag.Bool("autoconf", false, "automatic mode (dynamic IP, peer with IPv6 neighbors)") - -func main() { - flag.Parse() - var cfg *nodeConfig - switch { - case *autoconf: - cfg = generateConfig() - case *useconf: - config, err := ioutil.ReadAll(os.Stdin) - if err != nil { - panic(err) - } - decoder := json.NewDecoder(bytes.NewReader(config)) - cfg = generateConfig() - err = decoder.Decode(cfg) - if err != nil { - panic(err) - } - case *genconf: - fmt.Println(doGenconf()) - default: - flag.PrintDefaults() - } - if cfg == nil { - return - } - logger := log.New(os.Stdout, "", log.Flags()) - if *pprof { - runtime.SetBlockProfileRate(1) - go func() { log.Println(http.ListenAndServe("localhost:6060", nil)) }() - } - // Setup - logger.Println("Initializing...") - n := node{} - n.init(cfg, logger) - logger.Println("Starting tun...") - //n.core.DEBUG_startTun(cfg.IfName) // 1280, the smallest supported MTU - n.core.DEBUG_startTunWithMTU(cfg.IfName, 65535) // Largest supported MTU - defer func() { - logger.Println("Closing...") - n.core.DEBUG_stopTun() - }() - logger.Println("Started...") - if cfg.Multicast { - addr, err := net.ResolveUDPAddr("udp", multicastAddr) - if err != nil { - panic(err) - } - listenString := fmt.Sprintf("[::]:%v", addr.Port) - conn, err := net.ListenPacket("udp6", listenString) - if err != nil { - panic(err) - } - //defer conn.Close() // Let it close on its own when the application exits - n.sock = ipv6.NewPacketConn(conn) - if err = n.sock.SetControlMessage(ipv6.FlagDst, true); err != nil { - // Windows can't set this flag, so we need to handle it in other ways - //panic(err) - } - go n.listen() - go n.announce() - } - // Catch interrupt to exit gracefully - c := make(chan os.Signal, 1) - signal.Notify(c, os.Interrupt, os.Kill) - <-c - logger.Println("Stopping...") -} diff --git a/src/yggdrasil/udp.go b/src/yggdrasil/udp.go index 4e28f363..990a0890 100644 --- a/src/yggdrasil/udp.go +++ b/src/yggdrasil/udp.go @@ -319,7 +319,7 @@ func (iface *udpInterface) reader() { //////////////////////////////////////////////////////////////////////////////// -const udp_chunkSize = 1024 +const udp_chunkSize = 508 // Apparently the maximum guaranteed safe IPv4 size func udp_decode(bs []byte) (chunks, chunk, count uint8, payload []byte) { if len(bs) >= 3 { diff --git a/yggdrasil.go b/yggdrasil.go index e583b184..efb61513 100644 --- a/yggdrasil.go +++ b/yggdrasil.go @@ -71,7 +71,8 @@ func (n *node) init(cfg *nodeConfig, logger *log.Logger) { } n.core.DEBUG_setIfceExpr(ifceExpr) logger.Println("Starting interface...") - n.core.DEBUG_setupAndStartGlobalUDPInterface(cfg.Listen) + n.core.DEBUG_setupAndStartGlobalTCPInterface(cfg.Listen) // Listen for peers on TCP + n.core.DEBUG_setupAndStartGlobalUDPInterface(cfg.Listen) // Also listen on UDP, TODO allow separate configuration for ip/port to listen on each of these logger.Println("Started interface") logger.Println("Starting admin socket...") n.core.DEBUG_setupAndStartAdminInterface(cfg.AdminListen) @@ -82,7 +83,11 @@ func (n *node) init(cfg *nodeConfig, logger *log.Logger) { } for { for _, p := range cfg.Peers { - n.core.DEBUG_maybeSendUDPKeys(p) + switch { + case len(p) >= 4 && p[:4] == "udp:": n.core.DEBUG_maybeSendUDPKeys(p[4:]) + case len(p) >= 4 && p[:4] == "tcp:": n.core.DEBUG_addTCPConn(p[4:]) + default: n.core.DEBUG_addTCPConn(p) + } time.Sleep(time.Second) } time.Sleep(time.Minute) @@ -144,7 +149,7 @@ func (n *node) listen() { } } anAddr := string(bs[:nBytes]) - addr, err := net.ResolveUDPAddr("udp6", anAddr) + addr, err := net.ResolveTCPAddr("tcp6", anAddr) if err != nil { panic(err) continue @@ -158,7 +163,7 @@ func (n *node) listen() { saddr := addr.String() //if _, isIn := n.peers[saddr]; isIn { continue } //n.peers[saddr] = struct{}{} - n.core.DEBUG_maybeSendUDPKeys(saddr) + n.core.DEBUG_addTCPConn(saddr) // FIXME? can result in 2 connections per peer //fmt.Println("DEBUG:", "added multicast peer:", saddr) } } @@ -168,9 +173,9 @@ func (n *node) announce() { if err != nil { panic(err) } - var anAddr net.UDPAddr - udpAddr := n.core.DEBUG_getGlobalUDPAddr() - anAddr.Port = udpAddr.Port + var anAddr net.TCPAddr + tcpAddr := n.core.DEBUG_getGlobalTCPAddr() + anAddr.Port = tcpAddr.Port destAddr, err := net.ResolveUDPAddr("udp6", multicastAddr) if err != nil { panic(err) From 869997e4c5667da54e6f0e82fe9d368590974e77 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Fri, 9 Feb 2018 18:50:03 -0600 Subject: [PATCH 3/3] gofmt --- yggdrasil.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/yggdrasil.go b/yggdrasil.go index efb61513..cc3066bd 100644 --- a/yggdrasil.go +++ b/yggdrasil.go @@ -72,7 +72,7 @@ func (n *node) init(cfg *nodeConfig, logger *log.Logger) { n.core.DEBUG_setIfceExpr(ifceExpr) logger.Println("Starting interface...") n.core.DEBUG_setupAndStartGlobalTCPInterface(cfg.Listen) // Listen for peers on TCP - n.core.DEBUG_setupAndStartGlobalUDPInterface(cfg.Listen) // Also listen on UDP, TODO allow separate configuration for ip/port to listen on each of these + n.core.DEBUG_setupAndStartGlobalUDPInterface(cfg.Listen) // Also listen on UDP, TODO allow separate configuration for ip/port to listen on each of these logger.Println("Started interface") logger.Println("Starting admin socket...") n.core.DEBUG_setupAndStartAdminInterface(cfg.AdminListen) @@ -83,11 +83,14 @@ func (n *node) init(cfg *nodeConfig, logger *log.Logger) { } for { for _, p := range cfg.Peers { - switch { - case len(p) >= 4 && p[:4] == "udp:": n.core.DEBUG_maybeSendUDPKeys(p[4:]) - case len(p) >= 4 && p[:4] == "tcp:": n.core.DEBUG_addTCPConn(p[4:]) - default: n.core.DEBUG_addTCPConn(p) - } + switch { + case len(p) >= 4 && p[:4] == "udp:": + n.core.DEBUG_maybeSendUDPKeys(p[4:]) + case len(p) >= 4 && p[:4] == "tcp:": + n.core.DEBUG_addTCPConn(p[4:]) + default: + n.core.DEBUG_addTCPConn(p) + } time.Sleep(time.Second) } time.Sleep(time.Minute)