From 4c115de6330ff7a3ca1861acda6a45496346be1d Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 27 May 2018 22:13:37 +0100 Subject: [PATCH] De-debug --- src/yggdrasil/admin.go | 21 ++-- src/yggdrasil/core.go | 179 ++++++++++++++++++++++++++++++++-- src/yggdrasil/debug.go | 8 ++ src/yggdrasil/multicast.go | 11 ++- src/yggdrasil/router.go | 6 ++ src/yggdrasil/switch.go | 4 + src/yggdrasil/tcp.go | 32 ++++++- src/yggdrasil/udp.go | 19 ++++ yggdrasil.go | 191 ++++++++++++++++++++----------------- 9 files changed, 363 insertions(+), 108 deletions(-) diff --git a/src/yggdrasil/admin.go b/src/yggdrasil/admin.go index 5bf9d3fa..05e5c9a1 100644 --- a/src/yggdrasil/admin.go +++ b/src/yggdrasil/admin.go @@ -213,7 +213,11 @@ func (a *admin) init(c *Core, listenaddr string) { }, errors.New("Failed to remove allowed box pub key") } }) +} + +func (a *admin) start() error { go a.listen() + return nil } func (a *admin) listen() { @@ -356,11 +360,11 @@ func (a *admin) addPeer(addr string) error { if err == nil { switch strings.ToLower(u.Scheme) { case "tcp": - a.core.DEBUG_addTCPConn(u.Host) + a.core.tcp.connect(u.Host) case "udp": - a.core.DEBUG_maybeSendUDPKeys(u.Host) + a.core.udp.connect(u.Host) case "socks": - a.core.DEBUG_addSOCKSConn(u.Host, u.Path[1:]) + a.core.tcp.connectSOCKS(u.Host, u.Path[1:]) default: return errors.New("invalid peer: " + addr) } @@ -368,13 +372,13 @@ func (a *admin) addPeer(addr string) error { // no url scheme provided addr = strings.ToLower(addr) if strings.HasPrefix(addr, "udp:") { - a.core.DEBUG_maybeSendUDPKeys(addr[4:]) + a.core.udp.connect(addr[4:]) return nil } else { if strings.HasPrefix(addr, "tcp:") { addr = addr[4:] } - a.core.DEBUG_addTCPConn(addr) + a.core.tcp.connect(addr) return nil } return errors.New("invalid peer: " + addr) @@ -421,13 +425,10 @@ func (a *admin) startTunWithMTU(ifname string, iftapmode bool, ifmtu int) error func (a *admin) getData_getSelf() *admin_nodeInfo { table := a.core.switchTable.table.Load().(lookupTable) - addr := (*a.core.GetAddress())[:] - subnet := (*a.core.GetSubnet())[:] - subnet = append(subnet, 0, 0, 0, 0, 0, 0, 0, 0) coords := table.self.getCoords() self := admin_nodeInfo{ - {"ip", net.IP(addr[:]).String()}, - {"subnet", fmt.Sprintf("%s/64", net.IP(subnet[:]).String())}, + {"ip", a.core.GetAddress().String()}, + {"subnet", a.core.GetSubnet().String()}, {"coords", fmt.Sprint(coords)}, } return &self diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index 2dd8f85a..27e4e0ab 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -3,7 +3,13 @@ package yggdrasil import "io/ioutil" import "log" import "regexp" +import "net" +import "fmt" +import "encoding/hex" +import "yggdrasil/config" +// The Core object represents the Yggdrasil node. You should create a Core +// object for each Yggdrasil node you plan to run. type Core struct { // This is the main data structure that holds everything else for a node boxPub boxPubKey @@ -26,8 +32,9 @@ type Core struct { ifceExpr []*regexp.Regexp // the zone of link-local IPv6 peers must match this } +// This function is only called by the simulator to set up a node with random +// keys. It should not be used and may be removed in the future. func (c *Core) Init() { - // Only called by the simulator, to set up nodes with random keys bpub, bpriv := newBoxKeys() spub, spriv := newSigKeys() c.init(bpub, bpriv, spub, spriv) @@ -42,7 +49,9 @@ func (c *Core) init(bpub *boxPubKey, // Start launches goroutines that depend on structs being set up // This is pretty much required to completely avoid race conditions util_initByteStore() - c.log = log.New(ioutil.Discard, "", 0) + if c.log == nil { + c.log = log.New(ioutil.Discard, "", 0) + } c.boxPub, c.boxPriv = *bpub, *bpriv c.sigPub, c.sigPriv = *spub, *spriv c.admin.core = c @@ -57,18 +66,176 @@ func (c *Core) init(bpub *boxPubKey, c.tun.init(c) } +// Starts up Yggdrasil using the provided NodeConfig, and outputs debug logging +// through the provided log.Logger. The started stack will include TCP and UDP +// sockets, a multicast discovery socket, an admin socket, router, switch and +// DHT node. +func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error { + c.log = log + c.log.Println("Starting up...") + + var boxPub boxPubKey + var boxPriv boxPrivKey + var sigPub sigPubKey + var sigPriv sigPrivKey + boxPubHex, err := hex.DecodeString(nc.EncryptionPublicKey) + if err != nil { + return err + } + boxPrivHex, err := hex.DecodeString(nc.EncryptionPrivateKey) + if err != nil { + return err + } + sigPubHex, err := hex.DecodeString(nc.SigningPublicKey) + if err != nil { + return err + } + sigPrivHex, err := hex.DecodeString(nc.SigningPrivateKey) + if err != nil { + return err + } + copy(boxPub[:], boxPubHex) + copy(boxPriv[:], boxPrivHex) + copy(sigPub[:], sigPubHex) + copy(sigPriv[:], sigPrivHex) + + c.init(&boxPub, &boxPriv, &sigPub, &sigPriv) + c.admin.init(c, nc.AdminListen) + + if err := c.tcp.init(c, nc.Listen); err != nil { + c.log.Println("Failed to start TCP interface") + return err + } + + if err := c.udp.init(c, nc.Listen); err != nil { + c.log.Println("Failed to start UDP interface") + return err + } + + if err := c.router.start(); err != nil { + c.log.Println("Failed to start router") + return err + } + + if err := c.switchTable.start(); err != nil { + c.log.Println("Failed to start switch table ticker") + return err + } + + ip := net.IP(c.router.addr[:]).String() + if err := c.tun.setup(nc.IfName, nc.IfTAPMode, fmt.Sprintf("%s/8", ip), nc.IfMTU); err != nil { + c.log.Println("Failed to start TUN/TAP") + return err + } + + if err := c.admin.start(); err != nil { + c.log.Println("Failed to start admin socket") + return err + } + + if err := c.multicast.start(); err != nil { + c.log.Println("Failed to start multicast interface") + return err + } + + c.log.Println("Startup complete") + return nil +} + +// Stops the Yggdrasil node. +func (c *Core) Stop() { + c.log.Println("Stopping...") + c.tun.close() +} + +// Generates a new encryption keypair. The encryption keys are used to +// encrypt traffic and to derive the IPv6 address/subnet of the node. +func (c *Core) NewEncryptionKeys() (*boxPubKey, *boxPrivKey) { + return newBoxKeys() +} + +// Generates a new signing keypair. The signing keys are used to derive the +// structure of the spanning tree. +func (c *Core) NewSigningKeys() (*sigPubKey, *sigPrivKey) { + return newSigKeys() +} + +// Gets the node ID. func (c *Core) GetNodeID() *NodeID { return getNodeID(&c.boxPub) } +// Gets the tree ID. func (c *Core) GetTreeID() *TreeID { return getTreeID(&c.sigPub) } -func (c *Core) GetAddress() *address { - return address_addrForNodeID(c.GetNodeID()) +// Gets the IPv6 address of the Yggdrasil node. This is always a /128. +func (c *Core) GetAddress() *net.IP { + address := net.IP(address_addrForNodeID(c.GetNodeID())[:]) + return &address } -func (c *Core) GetSubnet() *subnet { - return address_subnetForNodeID(c.GetNodeID()) +// Gets the routed IPv6 subnet of the Yggdrasil node. This is always a /64. +func (c *Core) GetSubnet() *net.IPNet { + subnet := address_subnetForNodeID(c.GetNodeID())[:] + subnet = append(subnet, 0, 0, 0, 0, 0, 0, 0, 0) + return &net.IPNet{ IP: subnet, Mask: net.CIDRMask(64, 128) } +} + +// Sets the output logger of the Yggdrasil node after startup. This may be +// useful if you want to redirect the output later. +func (c *Core) SetLogger(log *log.Logger) { + c.log = log +} + +// Adds a peer. This should be specified in the peer URI format, i.e. +// tcp://a.b.c.d:e, udp://a.b.c.d:e, socks://a.b.c.d:e/f.g.h.i:j +func (c *Core) AddPeer(addr string) error { + return c.admin.addPeer(addr) +} + +// Adds an expression to select multicast interfaces for peer discovery. This +// should be done before calling Start. This function can be called multiple +// times to add multiple search expressions. +func (c *Core) AddMulticastInterfaceExpr(expr *regexp.Regexp) { + c.ifceExpr = append(c.ifceExpr, expr) +} + +// Adds an allowed public key. This allow peerings to be restricted only to +// keys that you have selected. +func (c *Core) AddAllowedEncryptionPublicKey(boxStr string) error { + return c.admin.addAllowedEncryptionPublicKey(boxStr) +} + +// Gets the default TUN/TAP interface name for your platform. +func (c *Core) GetTUNDefaultIfName() string { + return getDefaults().defaultIfName +} + +// Gets the default TUN/TAP interface MTU for your platform. This can be as high +// as 65535, depending on platform, but is never lower than 1280. +func (c *Core) GetTUNDefaultIfMTU() int { + return getDefaults().defaultIfMTU +} + +// Gets the maximum supported TUN/TAP interface MTU for your platform. This +// can be as high as 65535, depending on platform, but is never lower than 1280. +func (c *Core) GetTUNMaximumIfMTU() int { + return getDefaults().maximumIfMTU +} + +// Gets the default TUN/TAP interface mode for your platform. +func (c *Core) GetTUNDefaultIfTAPMode() bool { + return getDefaults().defaultIfTAPMode +} + +// Gets the current TUN/TAP interface name. +func (c *Core) GetTUNIfName() string { + return c.tun.iface.Name() +} + +// Gets the current TUN/TAP interface MTU. +func (c *Core) GetTUNIfMTU() int { + return c.tun.mtu } diff --git a/src/yggdrasil/debug.go b/src/yggdrasil/debug.go index 40cc5c4f..c687162c 100644 --- a/src/yggdrasil/debug.go +++ b/src/yggdrasil/debug.go @@ -279,6 +279,14 @@ func (c *Core) DEBUG_init(bpub []byte, copy(sigPub[:], spub) copy(sigPriv[:], spriv) c.init(&boxPub, &boxPriv, &sigPub, &sigPriv) + + if err := c.router.start(); err != nil { + panic(err) + } + + if err := c.switchTable.start(); err != nil { + panic(err) + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/yggdrasil/multicast.go b/src/yggdrasil/multicast.go index 6f11cb6a..c86159c7 100644 --- a/src/yggdrasil/multicast.go +++ b/src/yggdrasil/multicast.go @@ -48,19 +48,19 @@ func (m *multicast) init(core *Core) { m.core.log.Println("Found", len(m.interfaces), "multicast interface(s)") } -func (m *multicast) start() { +func (m *multicast) start() error { if len(m.core.ifceExpr) == 0 { m.core.log.Println("Multicast discovery is disabled") } else { m.core.log.Println("Multicast discovery is enabled") addr, err := net.ResolveUDPAddr("udp", m.groupAddr) if err != nil { - panic(err) + return err } listenString := fmt.Sprintf("[::]:%v", addr.Port) conn, err := net.ListenPacket("udp6", listenString) if err != nil { - panic(err) + return err } //defer conn.Close() // Let it close on its own when the application exits m.sock = ipv6.NewPacketConn(conn) @@ -72,6 +72,7 @@ func (m *multicast) start() { go m.listen() go m.announce() } + return nil } func (m *multicast) announce() { @@ -80,7 +81,7 @@ func (m *multicast) announce() { panic(err) } var anAddr net.TCPAddr - myAddr := m.core.DEBUG_getGlobalTCPAddr() + myAddr := m.core.tcp.getAddr() anAddr.Port = myAddr.Port destAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr) if err != nil { @@ -155,7 +156,7 @@ func (m *multicast) listen() { saddr := addr.String() //if _, isIn := n.peers[saddr]; isIn { continue } //n.peers[saddr] = struct{}{} - m.core.DEBUG_addTCPConn(saddr) + m.core.tcp.connect(saddr) //fmt.Println("DEBUG:", "added multicast peer:", saddr) } } diff --git a/src/yggdrasil/router.go b/src/yggdrasil/router.go index ad11d6e7..545a15be 100644 --- a/src/yggdrasil/router.go +++ b/src/yggdrasil/router.go @@ -64,7 +64,13 @@ func (r *router) init(core *Core) { r.core.tun.send = send r.reset = make(chan struct{}, 1) r.admin = make(chan func()) + // go r.mainLoop() +} + +func (r *router) start() error { + r.core.log.Println("Starting router") go r.mainLoop() + return nil } func (r *router) mainLoop() { diff --git a/src/yggdrasil/switch.go b/src/yggdrasil/switch.go index a005b106..1db63f61 100644 --- a/src/yggdrasil/switch.go +++ b/src/yggdrasil/switch.go @@ -167,6 +167,9 @@ func (t *switchTable) init(core *Core, key sigPubKey) { t.updater.Store(&sync.Once{}) t.table.Store(lookupTable{}) t.drop = make(map[sigPubKey]int64) +} + +func (t *switchTable) start() error { doTicker := func() { ticker := time.NewTicker(time.Second) defer ticker.Stop() @@ -176,6 +179,7 @@ func (t *switchTable) init(core *Core, key sigPubKey) { } } go doTicker() + return nil } func (t *switchTable) getLocator() switchLocator { diff --git a/src/yggdrasil/tcp.go b/src/yggdrasil/tcp.go index 869b6afd..c152d0d1 100644 --- a/src/yggdrasil/tcp.go +++ b/src/yggdrasil/tcp.go @@ -16,6 +16,7 @@ import "errors" import "sync" import "fmt" import "bufio" +import "golang.org/x/net/proxy" const tcp_msgSize = 2048 + 65535 // TODO figure out what makes sense @@ -42,6 +43,32 @@ type tcpInfo struct { remoteAddr string } +func (iface *tcpInterface) getAddr() *net.TCPAddr { + return iface.serv.Addr().(*net.TCPAddr) +} + +func (iface *tcpInterface) connect(addr string) { + iface.call(addr) +} + +func (iface *tcpInterface) connectSOCKS(socksaddr, peeraddr string) { + go func() { + dialer, err := proxy.SOCKS5("tcp", socksaddr, nil, proxy.Direct) + if err == nil { + conn, err := dialer.Dial("tcp", peeraddr) + if err == nil { + iface.callWithConn(&wrappedConn{ + c: conn, + raddr: &wrappedAddr{ + network: "tcp", + addr: peeraddr, + }, + }) + } + } + }() +} + func (iface *tcpInterface) init(core *Core, addr string) (err error) { iface.core = core @@ -51,7 +78,8 @@ func (iface *tcpInterface) init(core *Core, addr string) (err error) { iface.conns = make(map[tcpInfo](chan struct{})) go iface.listener() } - return + + return err } func (iface *tcpInterface) listener() { @@ -274,12 +302,14 @@ func (iface *tcpInterface) reader(sock net.Conn, in func([]byte)) { sock.SetReadDeadline(timeout) n, err := sock.Read(bs[len(frag):]) if err != nil || n == 0 { + // iface.core.log.Println(err) break } frag = bs[:len(frag)+n] for { msg, ok, err := tcp_chop_msg(&frag) if err != nil { + // iface.core.log.Println(err) return } if !ok { diff --git a/src/yggdrasil/udp.go b/src/yggdrasil/udp.go index 02fb9d6d..0be507f3 100644 --- a/src/yggdrasil/udp.go +++ b/src/yggdrasil/udp.go @@ -65,6 +65,25 @@ type udpKeys struct { sig sigPubKey } +func (iface *udpInterface) getAddr() *net.UDPAddr { + return iface.sock.LocalAddr().(*net.UDPAddr) +} + +func (iface *udpInterface) connect(saddr string) { + udpAddr, err := net.ResolveUDPAddr("udp", saddr) + if err != nil { + panic(err) + } + var addr connAddr + addr.fromUDPAddr(udpAddr) + iface.mutex.RLock() + _, isIn := iface.conns[addr] + iface.mutex.RUnlock() + if !isIn { + iface.sendKeys(addr) + } +} + func (iface *udpInterface) init(core *Core, addr string) (err error) { iface.core = core udpAddr, err := net.ResolveUDPAddr("udp", addr) diff --git a/yggdrasil.go b/yggdrasil.go index 91403bba..dbfd74a5 100644 --- a/yggdrasil.go +++ b/yggdrasil.go @@ -5,7 +5,6 @@ import "encoding/hex" import "flag" import "fmt" import "io/ioutil" -import "net" import "os" import "os/signal" import "syscall" @@ -32,63 +31,20 @@ type node struct { core Core } -func (n *node) init(cfg *nodeConfig, logger *log.Logger) { - boxPub, err := hex.DecodeString(cfg.EncryptionPublicKey) - if err != nil { - panic(err) - } - boxPriv, err := hex.DecodeString(cfg.EncryptionPrivateKey) - if err != nil { - panic(err) - } - sigPub, err := hex.DecodeString(cfg.SigningPublicKey) - if err != nil { - panic(err) - } - sigPriv, err := hex.DecodeString(cfg.SigningPrivateKey) - if err != nil { - panic(err) - } - n.core.DEBUG_init(boxPub, boxPriv, sigPub, sigPriv) - n.core.DEBUG_setLogger(logger) - - 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 - logger.Println("Started interface") - logger.Println("Starting admin socket...") - n.core.DEBUG_setupAndStartAdminInterface(cfg.AdminListen) - logger.Println("Started admin socket") - for _, pBoxStr := range cfg.AllowedEncryptionPublicKeys { - n.core.DEBUG_addAllowedEncryptionPublicKey(pBoxStr) - } - for _, ll := range cfg.MulticastInterfaces { - ifceExpr, err := regexp.Compile(ll) - if err != nil { - panic(err) - } - n.core.DEBUG_setIfceExpr(ifceExpr) - } - n.core.DEBUG_setupAndStartMulticastInterface() - - go func() { - if len(cfg.Peers) == 0 { - return - } - for { - for _, p := range cfg.Peers { - n.core.DEBUG_addPeer(p) - time.Sleep(time.Second) - } - time.Sleep(time.Minute) - } - }() -} - +// Generates default configuration. This is used when outputting the -genconf +// parameter and also when using -autoconf. The isAutoconf flag is used to +// determine whether the operating system should select a free port by itself +// (which guarantees that there will not be a conflict with any other services) +// or whether to generate a random port number. The only side effect of setting +// isAutoconf is that the TCP and UDP ports will likely end up with different +// port numbers. func generateConfig(isAutoconf bool) *nodeConfig { + // Create a new core. core := Core{} - bpub, bpriv := core.DEBUG_newBoxKeys() - spub, spriv := core.DEBUG_newSigKeys() + // Generate encryption keys. + bpub, bpriv := core.NewEncryptionKeys() + spub, spriv := core.NewSigningKeys() + // Create a node configuration and populate it. cfg := nodeConfig{} if isAutoconf { cfg.Listen = "[::]:0" @@ -111,6 +67,8 @@ func generateConfig(isAutoconf bool) *nodeConfig { return &cfg } +// Generates a new configuration and returns it in HJSON format. This is used +// with -genconf. func doGenconf() string { cfg := generateConfig(false) bs, err := hjson.Marshal(cfg) @@ -120,30 +78,43 @@ func doGenconf() string { return string(bs) } -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 useconffile = flag.String("useconffile", "", "read config from specified file path") -var normaliseconf = flag.Bool("normaliseconf", false, "use in combination with either -useconf or -useconffile, outputs your configuration normalised") -var autoconf = flag.Bool("autoconf", false, "automatic mode (dynamic IP, peer with IPv6 neighbors)") - +// The main function is responsible for configuring and starting Yggdrasil. func main() { + // Configure the command line parameters. + pprof := flag.Bool("pprof", false, "Run pprof, see http://localhost:6060/debug/pprof/") + genconf := flag.Bool("genconf", false, "print a new config to stdout") + useconf := flag.Bool("useconf", false, "read config from stdin") + useconffile := flag.String("useconffile", "", "read config from specified file path") + normaliseconf := flag.Bool("normaliseconf", false, "use in combination with either -useconf or -useconffile, outputs your configuration normalised") + autoconf := flag.Bool("autoconf", false, "automatic mode (dynamic IP, peer with IPv6 neighbors)") flag.Parse() + var cfg *nodeConfig switch { case *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 = generateConfig(true) case *useconffile != "" || *useconf: + // Use a configuration file. If -useconf, the configuration will be read + // from stdin. If -useconffile, the configuration will be read from the + // filesystem. var config []byte var err error if *useconffile != "" { + // Read the file from the filesystem config, err = ioutil.ReadFile(*useconffile) } else { + // Read the file from stdin. config, err = ioutil.ReadAll(os.Stdin) } if err != nil { panic(err) } + // Generate a new configuration - this gives us a set of sane defaults - + // then parse the configuration we loaded above on top of it. The effect + // of this is that any configuration item that is missing from the provided + // configuration will use a sane default. cfg = generateConfig(false) var dat map[string]interface{} if err := hjson.Unmarshal(config, &dat); err != nil { @@ -155,7 +126,8 @@ func main() { } json.Unmarshal(confJson, &cfg) // For now we will do a little bit to help the user adjust their - // configuration to match the new configuration format + // configuration to match the new configuration format, as some of the key + // names have changed recently. changes := map[string]string{ "Multicast": "", "LinkLocal": "MulticastInterfaces", @@ -165,6 +137,7 @@ func main() { "SigPriv": "SigningPrivateKey", "AllowedBoxPubs": "AllowedEncryptionPublicKeys", } + // Loop over the mappings aove and see if we have anything to fix. for from, to := range changes { if _, ok := dat[from]; ok { if to == "" { @@ -175,15 +148,24 @@ func main() { if !*normaliseconf { log.Println("Warning: Deprecated config option", from, "- please rename to", to) } + // If the configuration file doesn't already contain a line with the + // new name then set it to the old value. This makes sure that we + // don't overwrite something that was put there intentionally. if _, ok := dat[to]; !ok { dat[to] = dat[from] } } } } + // Overlay our newly mapped configuration onto the autoconf node config that + // we generated above. if err = mapstructure.Decode(dat, &cfg); err != nil { panic(err) } + // 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 { bs, err := hjson.Marshal(cfg) if err != nil { @@ -193,48 +175,85 @@ func main() { return } case *genconf: + // Generate a new configuration and print it to stdout. fmt.Println(doGenconf()) default: + // No flags were provided, therefore print the list of flags to stdout. flag.PrintDefaults() } + // Have we got a working configuration? If we don't then it probably means + // that neither -autoconf, -useconf or -useconffile were set above. Stop + // if we don't. if cfg == nil { return } + // Create a new logger that logs output to stdout. logger := log.New(os.Stdout, "", log.Flags()) + // If the -pprof flag was provided then start the pprof service on port 6060. if *pprof { runtime.SetBlockProfileRate(1) go func() { log.Println(http.ListenAndServe("localhost:6060", nil)) }() } - // Setup - logger.Println("Initializing...") + // Setup the Yggdrasil node itself. The node{} type includes a Core, so we + // don't need to create this manually. n := node{} - n.init(cfg, logger) - if cfg.IfName != "none" { - logger.Println("Starting TUN/TAP...") - } else { - logger.Println("Not starting TUN/TAP") + // Check to see if any allowed encryption keys were provided in the config. + // If they were then set them now. + for _, pBoxStr := range cfg.AllowedEncryptionPublicKeys { + n.core.AddAllowedEncryptionPublicKey(pBoxStr) } - //n.core.DEBUG_startTun(cfg.IfName) // 1280, the smallest supported MTU - n.core.DEBUG_startTunWithMTU(cfg.IfName, cfg.IfTAPMode, cfg.IfMTU) // Largest supported MTU - defer func() { - logger.Println("Closing...") - n.core.DEBUG_stopTun() + // Check to see if any multicast interface expressions were provided in the + // config. If they were then set them now. + for _, ll := range cfg.MulticastInterfaces { + ifceExpr, err := regexp.Compile(ll) + if err != nil { + panic(err) + } + n.core.AddMulticastInterfaceExpr(ifceExpr) + } + // Now that we have a working configuration, and we have provided any allowed + // encryption keys or multicast interface expressions, we can now actually + // start Yggdrasil. This will start the router, switch, DHT node, TCP and UDP + // sockets, TUN/TAP adapter and multicast discovery port. + if err := n.core.Start(cfg, logger); err != nil { + logger.Println("An error occurred during startup") + panic(err) + } + // If any static peers were provided in the configuration above then we should + // configure them. The loop ensures that disconnected peers will eventually + // be reconnected with. + go func() { + if len(cfg.Peers) == 0 { + return + } + for { + for _, p := range cfg.Peers { + n.core.AddPeer(p) + time.Sleep(time.Second) + } + time.Sleep(time.Minute) + } }() - logger.Println("Started...") - address := (*n.core.GetAddress())[:] - subnet := (*n.core.GetSubnet())[:] - subnet = append(subnet, 0, 0, 0, 0, 0, 0, 0, 0) - logger.Printf("Your IPv6 address is %s", net.IP(address).String()) - logger.Printf("Your IPv6 subnet is %s/64", net.IP(subnet).String()) - // Catch interrupt to exit gracefully + // The Stop function ensures that the TUN/TAP adapter is correctly shut down + // before the program exits. + defer func() { + n.core.Stop() + }() + // Make some nice output that tells us what our IPv6 address and subnet are. + // This is just logged to stdout for the user. + address := n.core.GetAddress() + subnet := n.core.GetSubnet() + logger.Printf("Your IPv6 address is %s", address.String()) + logger.Printf("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) - // Create a function to capture the service being stopped on Windows + // Create a function to capture the service being stopped on Windows. winTerminate := func() { c <- os.Interrupt } minwinsvc.SetOnExit(winTerminate) - // Wait for the terminate/interrupt signal + // Wait for the terminate/interrupt signal. Once a signal is received, the + // deferred Stop function above will run which will shut down TUN/TAP. <-c - logger.Println("Stopping...") }