diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 6af27725..129b01d5 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -172,7 +172,7 @@ func main() { logger = log.New(syslogger, "", log.Flags()) } default: - if logfd, err := os.Create(*logto); err == nil { + if logfd, err := os.OpenFile(*logto, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err == nil { logger = log.New(logfd, "", log.Flags()) } } @@ -231,11 +231,6 @@ func main() { } else { logger.Errorln("Unable to get Listener:", err) } - // 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.Address() @@ -247,15 +242,15 @@ func main() { r := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) signal.Notify(r, os.Interrupt, syscall.SIGHUP) - // Create a function to capture the service being stopped on Windows. - winTerminate := func() { - c <- os.Interrupt - } - minwinsvc.SetOnExit(winTerminate) + // Capture the service being stopped on Windows. + minwinsvc.SetOnExit(n.shutdown) + defer n.shutdown() // Wait for the terminate/interrupt signal. Once a signal is received, the // deferred Stop function above will run which will shut down TUN/TAP. for { select { + case _ = <-c: + goto exit case _ = <-r: if *useconffile != "" { cfg = readConfig(useconf, useconffile, normaliseconf) @@ -265,13 +260,19 @@ func main() { } else { logger.Errorln("Reloading config at runtime is only possible with -useconffile") } - case _ = <-c: - goto exit } } exit: } +func (n *node) shutdown() { + n.core.Stop() + n.admin.Stop() + n.multicast.Stop() + n.tuntap.Stop() + os.Exit(0) +} + func (n *node) sessionFirewall(pubkey *crypto.BoxPubKey, initiator bool) bool { n.state.Mutex.RLock() defer n.state.Mutex.RUnlock() diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index 3c0d8c0f..ba1f18fb 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -26,6 +26,7 @@ type Multicast struct { groupAddr string listeners map[string]*yggdrasil.TcpListener listenPort uint16 + isOpen bool } // Init prepares the multicast interface for use. @@ -61,6 +62,7 @@ func (m *Multicast) Start() error { // Windows can't set this flag, so we need to handle it in other ways } + m.isOpen = true go m.multicastStarted() go m.listen() go m.announce() @@ -70,6 +72,8 @@ func (m *Multicast) Start() error { // Stop is not implemented for multicast yet. func (m *Multicast) Stop() error { + m.isOpen = false + m.sock.Close() return nil } @@ -246,6 +250,9 @@ func (m *Multicast) listen() { for { nBytes, rcm, fromAddr, err := m.sock.ReadFrom(bs) if err != nil { + if !m.isOpen { + return + } panic(err) } if rcm != nil { diff --git a/src/tuntap/iface.go b/src/tuntap/iface.go index 16a3b65d..60c814c2 100644 --- a/src/tuntap/iface.go +++ b/src/tuntap/iface.go @@ -98,6 +98,9 @@ func (tun *TunAdapter) writer() error { util.PutBytes(b) } if err != nil { + if !tun.isOpen { + return err + } tun.log.Errorln("TUN/TAP iface write error:", err) continue } @@ -114,6 +117,9 @@ func (tun *TunAdapter) reader() error { // Wait for a packet to be delivered to us through the TUN/TAP adapter n, err := tun.iface.Read(bs) if err != nil { + if !tun.isOpen { + return err + } panic(err) } if n == 0 { diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index ed5d2d45..b7b4cfa6 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -181,6 +181,16 @@ func (tun *TunAdapter) Start() error { return nil } +// Start the setup process for the TUN/TAP adapter. If successful, starts the +// read/write goroutines to handle packets on that interface. +func (tun *TunAdapter) Stop() error { + tun.isOpen = false + // TODO: we have nothing that cleanly stops all the various goroutines opened + // by TUN/TAP, e.g. readers/writers, sessions + tun.iface.Close() + return nil +} + // UpdateConfig updates the TUN/TAP module with the provided config.NodeConfig // and then signals the various module goroutines to reconfigure themselves if // needed. diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index 3a7f9f1b..62d89a8b 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -88,14 +88,14 @@ func (c *Core) addPeerLoop() { // Add peers from the Peers section for _, peer := range current.Peers { - c.AddPeer(peer, "") + go c.AddPeer(peer, "") time.Sleep(time.Second) } // Add peers from the InterfacePeers section for intf, intfpeers := range current.InterfacePeers { for _, peer := range intfpeers { - c.AddPeer(peer, intf) + go c.AddPeer(peer, intf) time.Sleep(time.Second) } }