From 0b494a8255881fef79c926f74773b1322b0cb505 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 28 Mar 2019 00:30:25 +0000 Subject: [PATCH 01/19] Refactoring: move tuntap and icmpv6 into separate package --- cmd/yggdrasil/main.go | 3 + src/config/config.go | 25 ++++++ src/{yggdrasil => tuntap}/icmpv6.go | 56 ++++++------ src/{yggdrasil => tuntap}/tun.go | 104 +++++++++++++++-------- src/{yggdrasil => tuntap}/tun_bsd.go | 6 +- src/{yggdrasil => tuntap}/tun_darwin.go | 20 ++--- src/{yggdrasil => tuntap}/tun_dummy.go | 6 +- src/{yggdrasil => tuntap}/tun_linux.go | 6 +- src/{yggdrasil => tuntap}/tun_other.go | 6 +- src/{yggdrasil => tuntap}/tun_windows.go | 8 +- src/yggdrasil/adapter.go | 38 ++++++--- src/yggdrasil/admin.go | 85 +++++++++--------- src/yggdrasil/ckr.go | 13 ++- src/yggdrasil/core.go | 64 +++++++------- src/yggdrasil/multicast.go | 10 +-- src/yggdrasil/peer.go | 34 ++++---- src/yggdrasil/router.go | 25 +++--- src/yggdrasil/session.go | 22 ++--- src/yggdrasil/switch.go | 2 - src/yggdrasil/tcp.go | 14 +-- 20 files changed, 307 insertions(+), 240 deletions(-) rename src/{yggdrasil => tuntap}/icmpv6.go (84%) rename src/{yggdrasil => tuntap}/tun.go (69%) rename src/{yggdrasil => tuntap}/tun_bsd.go (97%) rename src/{yggdrasil => tuntap}/tun_darwin.go (81%) rename src/{yggdrasil => tuntap}/tun_dummy.go (79%) rename src/{yggdrasil => tuntap}/tun_linux.go (93%) rename src/{yggdrasil => tuntap}/tun_other.go (87%) rename src/{yggdrasil => tuntap}/tun_windows.go (93%) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 8c8340f..cec7705 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -19,6 +19,7 @@ import ( "github.com/mitchellh/mapstructure" "github.com/yggdrasil-network/yggdrasil-go/src/config" + "github.com/yggdrasil-network/yggdrasil-go/src/tuntap" "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil" ) @@ -27,6 +28,7 @@ type Core = yggdrasil.Core type node struct { core Core + tun tuntap.TunAdapter } func readConfig(useconf *bool, useconffile *string, normaliseconf *bool) *nodeConfig { @@ -247,6 +249,7 @@ func main() { // Now that we have a working configuration, 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. + n.core.SetRouterAdapter(&n.tun) if err := n.core.Start(cfg, logger); err != nil { logger.Errorln("An error occurred during startup") panic(err) diff --git a/src/config/config.go b/src/config/config.go index a900758..861e57a 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -2,11 +2,36 @@ package config import ( "encoding/hex" + "sync" "github.com/yggdrasil-network/yggdrasil-go/src/crypto" "github.com/yggdrasil-network/yggdrasil-go/src/defaults" ) +// NodeState represents the active and previous configuration of the node and +// protects it with a mutex +type NodeState struct { + Current NodeConfig + Previous NodeConfig + Mutex sync.RWMutex +} + +// Get returns both the current and previous node configs +func (s *NodeState) Get() (NodeConfig, NodeConfig) { + s.Mutex.RLock() + defer s.Mutex.RUnlock() + return s.Current, s.Previous +} + +// Replace the node configuration with new configuration +func (s *NodeState) Replace(n NodeConfig) NodeConfig { + s.Mutex.Lock() + defer s.Mutex.Unlock() + s.Previous = s.Current + s.Current = n + return s.Current +} + // NodeConfig defines all configuration values needed to run a signle yggdrasil node type NodeConfig struct { Peers []string `comment:"List of connection strings for outbound peer connections in URI format,\ne.g. tcp://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j. These connections\nwill obey the operating system routing table, therefore you should\nuse this section when you may connect via different interfaces."` diff --git a/src/yggdrasil/icmpv6.go b/src/tuntap/icmpv6.go similarity index 84% rename from src/yggdrasil/icmpv6.go rename to src/tuntap/icmpv6.go index 52ca50c..f4f9efe 100644 --- a/src/yggdrasil/icmpv6.go +++ b/src/tuntap/icmpv6.go @@ -1,4 +1,4 @@ -package yggdrasil +package tuntap // The ICMPv6 module implements functions to easily create ICMPv6 // packets. These functions, when mixed with the built-in Go IPv6 @@ -25,8 +25,8 @@ type macAddress [6]byte const len_ETHER = 14 -type icmpv6 struct { - tun *tunAdapter +type ICMPv6 struct { + tun *TunAdapter mylladdr net.IP mymac macAddress peermacs map[address.Address]neighbor @@ -59,7 +59,7 @@ func ipv6Header_Marshal(h *ipv6.Header) ([]byte, error) { // Initialises the ICMPv6 module by assigning our link-local IPv6 address and // our MAC address. ICMPv6 messages will always appear to originate from these // addresses. -func (i *icmpv6) init(t *tunAdapter) { +func (i *ICMPv6) Init(t *TunAdapter) { i.tun = t i.peermacs = make(map[address.Address]neighbor) @@ -69,23 +69,23 @@ func (i *icmpv6) init(t *tunAdapter) { i.mylladdr = net.IP{ 0xFE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFE} - copy(i.mymac[:], i.tun.core.router.addr[:]) - copy(i.mylladdr[9:], i.tun.core.router.addr[1:]) + copy(i.mymac[:], i.tun.addr[:]) + copy(i.mylladdr[9:], i.tun.addr[1:]) } // Parses an incoming ICMPv6 packet. The packet provided may be either an // ethernet frame containing an IP packet, or the IP packet alone. This is // determined by whether the TUN/TAP adapter is running in TUN (layer 3) or // TAP (layer 2) mode. -func (i *icmpv6) parse_packet(datain []byte) { +func (i *ICMPv6) ParsePacket(datain []byte) { var response []byte var err error // Parse the frame/packet - if i.tun.iface.IsTAP() { - response, err = i.parse_packet_tap(datain) + if i.tun.IsTAP() { + response, err = i.UnmarshalPacketL2(datain) } else { - response, err = i.parse_packet_tun(datain, nil) + response, err = i.UnmarshalPacket(datain, nil) } if err != nil { @@ -93,22 +93,22 @@ func (i *icmpv6) parse_packet(datain []byte) { } // Write the packet to TUN/TAP - i.tun.iface.Write(response) + i.tun.Send <- response } // Unwraps the ethernet headers of an incoming ICMPv6 packet and hands off -// the IP packet to the parse_packet_tun function for further processing. +// the IP packet to the ParsePacket function for further processing. // A response buffer is also created for the response message, also complete // with ethernet headers. -func (i *icmpv6) parse_packet_tap(datain []byte) ([]byte, error) { +func (i *ICMPv6) UnmarshalPacketL2(datain []byte) ([]byte, error) { // Ignore non-IPv6 frames if binary.BigEndian.Uint16(datain[12:14]) != uint16(0x86DD) { return nil, nil } - // Hand over to parse_packet_tun to interpret the IPv6 packet + // Hand over to ParsePacket to interpret the IPv6 packet mac := datain[6:12] - ipv6packet, err := i.parse_packet_tun(datain[len_ETHER:], &mac) + ipv6packet, err := i.UnmarshalPacket(datain[len_ETHER:], &mac) if err != nil { return nil, err } @@ -130,7 +130,7 @@ func (i *icmpv6) parse_packet_tap(datain []byte) ([]byte, error) { // sanity checks on the packet - i.e. is the packet an ICMPv6 packet, does the // ICMPv6 message match a known expected type. The relevant handler function // is then called and a response packet may be returned. -func (i *icmpv6) parse_packet_tun(datain []byte, datamac *[]byte) ([]byte, error) { +func (i *ICMPv6) UnmarshalPacket(datain []byte, datamac *[]byte) ([]byte, error) { // Parse the IPv6 packet headers ipv6Header, err := ipv6.ParseHeader(datain[:ipv6.HeaderLen]) if err != nil { @@ -156,13 +156,13 @@ func (i *icmpv6) parse_packet_tun(datain []byte, datamac *[]byte) ([]byte, error // Check for a supported message type switch icmpv6Header.Type { case ipv6.ICMPTypeNeighborSolicitation: - if !i.tun.iface.IsTAP() { + if !i.tun.IsTAP() { return nil, errors.New("Ignoring Neighbor Solicitation in TUN mode") } - response, err := i.handle_ndp(datain[ipv6.HeaderLen:]) + response, err := i.HandleNDP(datain[ipv6.HeaderLen:]) if err == nil { // Create our ICMPv6 response - responsePacket, err := i.create_icmpv6_tun( + responsePacket, err := CreateICMPv6( ipv6Header.Src, i.mylladdr, ipv6.ICMPTypeNeighborAdvertisement, 0, &icmp.DefaultMessageBody{Data: response}) @@ -176,7 +176,7 @@ func (i *icmpv6) parse_packet_tun(datain []byte, datamac *[]byte) ([]byte, error return nil, err } case ipv6.ICMPTypeNeighborAdvertisement: - if !i.tun.iface.IsTAP() { + if !i.tun.IsTAP() { return nil, errors.New("Ignoring Neighbor Advertisement in TUN mode") } if datamac != nil { @@ -202,9 +202,9 @@ func (i *icmpv6) parse_packet_tun(datain []byte, datamac *[]byte) ([]byte, error // Creates an ICMPv6 packet based on the given icmp.MessageBody and other // parameters, complete with ethernet and IP headers, which can be written // directly to a TAP adapter. -func (i *icmpv6) create_icmpv6_tap(dstmac macAddress, dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) { - // Pass through to create_icmpv6_tun - ipv6packet, err := i.create_icmpv6_tun(dst, src, mtype, mcode, mbody) +func (i *ICMPv6) CreateICMPv6L2(dstmac macAddress, dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) { + // Pass through to CreateICMPv6 + ipv6packet, err := CreateICMPv6(dst, src, mtype, mcode, mbody) if err != nil { return nil, err } @@ -224,9 +224,9 @@ func (i *icmpv6) create_icmpv6_tap(dstmac macAddress, dst net.IP, src net.IP, mt // Creates an ICMPv6 packet based on the given icmp.MessageBody and other // parameters, complete with IP headers only, which can be written directly to -// a TUN adapter, or called directly by the create_icmpv6_tap function when +// a TUN adapter, or called directly by the CreateICMPv6L2 function when // generating a message for TAP adapters. -func (i *icmpv6) create_icmpv6_tun(dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) { +func CreateICMPv6(dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) { // Create the ICMPv6 message icmpMessage := icmp.Message{ Type: mtype, @@ -265,7 +265,7 @@ func (i *icmpv6) create_icmpv6_tun(dst net.IP, src net.IP, mtype ipv6.ICMPType, return responsePacket, nil } -func (i *icmpv6) create_ndp_tap(dst address.Address) ([]byte, error) { +func (i *ICMPv6) CreateNDPL2(dst address.Address) ([]byte, error) { // Create the ND payload var payload [28]byte copy(payload[:4], []byte{0x00, 0x00, 0x00, 0x00}) @@ -287,7 +287,7 @@ func (i *icmpv6) create_ndp_tap(dst address.Address) ([]byte, error) { copy(dstmac[2:6], dstaddr[12:16]) // Create the ND request - requestPacket, err := i.create_icmpv6_tap( + requestPacket, err := i.CreateICMPv6L2( dstmac, dstaddr[:], i.mylladdr, ipv6.ICMPTypeNeighborSolicitation, 0, &icmp.DefaultMessageBody{Data: payload[:]}) @@ -305,7 +305,7 @@ func (i *icmpv6) create_ndp_tap(dst address.Address) ([]byte, error) { // when the host operating system generates an NDP request for any address in // the fd00::/8 range, so that the operating system knows to route that traffic // to the Yggdrasil TAP adapter. -func (i *icmpv6) handle_ndp(in []byte) ([]byte, error) { +func (i *ICMPv6) HandleNDP(in []byte) ([]byte, error) { // Ignore NDP requests for anything outside of fd00::/8 var source address.Address copy(source[:], in[8:]) diff --git a/src/yggdrasil/tun.go b/src/tuntap/tun.go similarity index 69% rename from src/yggdrasil/tun.go rename to src/tuntap/tun.go index 465cbb1..7dab31c 100644 --- a/src/yggdrasil/tun.go +++ b/src/tuntap/tun.go @@ -1,4 +1,4 @@ -package yggdrasil +package tuntap // This manages the tun driver to send/recv packets to/from applications @@ -10,21 +10,29 @@ import ( "sync" "time" + "github.com/gologme/log" + "github.com/songgao/packets/ethernet" "github.com/yggdrasil-network/water" "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/util" + "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil" ) const tun_IPv6_HEADER_LENGTH = 40 const tun_ETHER_HEADER_LENGTH = 14 // Represents a running TUN/TAP interface. -type tunAdapter struct { - Adapter - icmpv6 icmpv6 +type TunAdapter struct { + yggdrasil.Adapter + addr address.Address + subnet address.Subnet + log *log.Logger + config *config.NodeState + icmpv6 ICMPv6 mtu int iface *water.Interface mutex sync.RWMutex // Protects the below @@ -40,20 +48,37 @@ func getSupportedMTU(mtu int) int { return mtu } +// Get the adapter name +func (tun *TunAdapter) Name() string { + return tun.iface.Name() +} + +// Get the adapter MTU +func (tun *TunAdapter) MTU() int { + return getSupportedMTU(tun.mtu) +} + +// Get the adapter mode +func (tun *TunAdapter) IsTAP() bool { + return tun.iface.IsTAP() +} + // Initialises the TUN/TAP adapter. -func (tun *tunAdapter) init(core *Core, send chan<- []byte, recv <-chan []byte) { - tun.Adapter.init(core, send, recv) - tun.icmpv6.init(tun) +func (tun *TunAdapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte) { + tun.config = config + tun.log = log + tun.Adapter.Init(config, log, send, recv) + tun.icmpv6.Init(tun) go func() { for { - e := <-tun.reconfigure - tun.core.configMutex.RLock() - updated := tun.core.config.IfName != tun.core.configOld.IfName || - tun.core.config.IfTAPMode != tun.core.configOld.IfTAPMode || - tun.core.config.IfMTU != tun.core.configOld.IfMTU - tun.core.configMutex.RUnlock() + e := <-tun.Reconfigure + tun.config.Mutex.RLock() + updated := tun.config.Current.IfName != tun.config.Previous.IfName || + tun.config.Current.IfTAPMode != tun.config.Previous.IfTAPMode || + tun.config.Current.IfMTU != tun.config.Previous.IfMTU + tun.config.Mutex.RUnlock() if updated { - tun.core.log.Warnln("Reconfiguring TUN/TAP is not supported yet") + tun.log.Warnln("Reconfiguring TUN/TAP is not supported yet") e <- nil } else { e <- nil @@ -64,13 +89,18 @@ func (tun *tunAdapter) init(core *Core, send chan<- []byte, recv <-chan []byte) // Starts the setup process for the TUN/TAP adapter, and if successful, starts // the read/write goroutines to handle packets on that interface. -func (tun *tunAdapter) start() error { - tun.core.configMutex.RLock() - ifname := tun.core.config.IfName - iftapmode := tun.core.config.IfTAPMode - addr := fmt.Sprintf("%s/%d", net.IP(tun.core.router.addr[:]).String(), 8*len(address.GetPrefix())-1) - mtu := tun.core.config.IfMTU - tun.core.configMutex.RUnlock() +func (tun *TunAdapter) Start(a address.Address, s address.Subnet) error { + tun.addr = a + tun.subnet = s + if tun.config == nil { + return errors.New("No configuration available to TUN/TAP") + } + tun.config.Mutex.RLock() + ifname := tun.config.Current.IfName + iftapmode := tun.config.Current.IfTAPMode + addr := fmt.Sprintf("%s/%d", net.IP(tun.addr[:]).String(), 8*len(address.GetPrefix())-1) + mtu := tun.config.Current.IfMTU + tun.config.Mutex.RUnlock() if ifname != "none" { if err := tun.setup(ifname, iftapmode, addr, mtu); err != nil { return err @@ -82,15 +112,15 @@ func (tun *tunAdapter) start() error { tun.mutex.Lock() tun.isOpen = true tun.mutex.Unlock() - go func() { tun.core.log.Errorln("WARNING: tun.read() exited with error:", tun.read()) }() - go func() { tun.core.log.Errorln("WARNING: tun.write() exited with error:", tun.write()) }() + go func() { tun.log.Errorln("WARNING: tun.read() exited with error:", tun.Read()) }() + go func() { tun.log.Errorln("WARNING: tun.write() exited with error:", tun.Write()) }() if iftapmode { go func() { for { - if _, ok := tun.icmpv6.peermacs[tun.core.router.addr]; ok { + if _, ok := tun.icmpv6.peermacs[tun.addr]; ok { break } - request, err := tun.icmpv6.create_ndp_tap(tun.core.router.addr) + request, err := tun.icmpv6.CreateNDPL2(tun.addr) if err != nil { panic(err) } @@ -107,9 +137,9 @@ func (tun *tunAdapter) start() error { // Writes a packet to the TUN/TAP adapter. If the adapter is running in TAP // mode then additional ethernet encapsulation is added for the benefit of the // host operating system. -func (tun *tunAdapter) write() error { +func (tun *TunAdapter) Write() error { for { - data := <-tun.recv + data := <-tun.Recv if tun.iface == nil { continue } @@ -132,7 +162,7 @@ func (tun *tunAdapter) write() error { neigh, known := tun.icmpv6.peermacs[destAddr] known = known && (time.Since(neigh.lastsolicitation).Seconds() < 30) if !known { - request, err := tun.icmpv6.create_ndp_tap(destAddr) + request, err := tun.icmpv6.CreateNDPL2(destAddr) if err != nil { panic(err) } @@ -147,21 +177,21 @@ func (tun *tunAdapter) write() error { var peermac macAddress var peerknown bool if data[0]&0xf0 == 0x40 { - destAddr = tun.core.router.addr + destAddr = tun.addr } else if data[0]&0xf0 == 0x60 { - if !bytes.Equal(tun.core.router.addr[:16], destAddr[:16]) && !bytes.Equal(tun.core.router.subnet[:8], destAddr[:8]) { - destAddr = tun.core.router.addr + if !bytes.Equal(tun.addr[:16], destAddr[:16]) && !bytes.Equal(tun.subnet[:8], destAddr[:8]) { + destAddr = tun.addr } } if neighbor, ok := tun.icmpv6.peermacs[destAddr]; ok && neighbor.learned { peermac = neighbor.mac peerknown = true - } else if neighbor, ok := tun.icmpv6.peermacs[tun.core.router.addr]; ok && neighbor.learned { + } else if neighbor, ok := tun.icmpv6.peermacs[tun.addr]; ok && neighbor.learned { peermac = neighbor.mac peerknown = true sendndp(destAddr) } else { - sendndp(tun.core.router.addr) + sendndp(tun.addr) } if peerknown { var proto ethernet.Ethertype @@ -210,7 +240,7 @@ func (tun *tunAdapter) write() error { // is running in TAP mode then the ethernet headers will automatically be // processed and stripped if necessary. If an ICMPv6 packet is found, then // the relevant helper functions in icmpv6.go are called. -func (tun *tunAdapter) read() error { +func (tun *TunAdapter) Read() error { mtu := tun.mtu if tun.iface.IsTAP() { mtu += tun_ETHER_HEADER_LENGTH @@ -244,18 +274,18 @@ func (tun *tunAdapter) read() error { // Found an ICMPv6 packet b := make([]byte, n) copy(b, buf) - go tun.icmpv6.parse_packet(b) + go tun.icmpv6.ParsePacket(b) } } packet := append(util.GetBytes(), buf[o:n]...) - tun.send <- packet + tun.Send <- packet } } // Closes the TUN/TAP adapter. This is only usually called when the Yggdrasil // process stops. Typically this operation will happen quickly, but on macOS // it can block until a read operation is completed. -func (tun *tunAdapter) close() error { +func (tun *TunAdapter) Close() error { tun.mutex.Lock() tun.isOpen = false tun.mutex.Unlock() diff --git a/src/yggdrasil/tun_bsd.go b/src/tuntap/tun_bsd.go similarity index 97% rename from src/yggdrasil/tun_bsd.go rename to src/tuntap/tun_bsd.go index 81e2c46..95c13af 100644 --- a/src/yggdrasil/tun_bsd.go +++ b/src/tuntap/tun_bsd.go @@ -1,6 +1,6 @@ // +build openbsd freebsd netbsd -package yggdrasil +package tuntap import ( "encoding/binary" @@ -77,7 +77,7 @@ type in6_ifreq_lifetime struct { // a system socket and making syscalls to the kernel. This is not refined though // and often doesn't work (if at all), therefore if a call fails, it resorts // to calling "ifconfig" instead. -func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { +func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { var config water.Config if ifname[:4] == "auto" { ifname = "/dev/tap0" @@ -103,7 +103,7 @@ func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int return tun.setupAddress(addr) } -func (tun *tunAdapter) setupAddress(addr string) error { +func (tun *TunAdapter) setupAddress(addr string) error { var sfd int var err error diff --git a/src/yggdrasil/tun_darwin.go b/src/tuntap/tun_darwin.go similarity index 81% rename from src/yggdrasil/tun_darwin.go rename to src/tuntap/tun_darwin.go index 7ec1b8b..5dfca13 100644 --- a/src/yggdrasil/tun_darwin.go +++ b/src/tuntap/tun_darwin.go @@ -1,6 +1,6 @@ // +build !mobile -package yggdrasil +package tuntap // The darwin platform specific tun parts @@ -16,9 +16,9 @@ import ( ) // Configures the "utun" adapter with the correct IPv6 address and MTU. -func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { +func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { if iftapmode { - tun.core.log.Warnln("TAP mode is not supported on this platform, defaulting to TUN") + tun.log.Warnln("TAP mode is not supported on this platform, defaulting to TUN") } config := water.Config{DeviceType: water.TUN} iface, err := water.New(config) @@ -64,12 +64,12 @@ type ifreq struct { // Sets the IPv6 address of the utun adapter. On Darwin/macOS this is done using // a system socket and making direct syscalls to the kernel. -func (tun *tunAdapter) setupAddress(addr string) error { +func (tun *TunAdapter) setupAddress(addr string) error { var fd int var err error if fd, err = unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, 0); err != nil { - tun.core.log.Printf("Create AF_SYSTEM socket failed: %v.", err) + tun.log.Printf("Create AF_SYSTEM socket failed: %v.", err) return err } @@ -98,19 +98,19 @@ func (tun *tunAdapter) setupAddress(addr string) error { copy(ir.ifr_name[:], tun.iface.Name()) ir.ifru_mtu = uint32(tun.mtu) - tun.core.log.Infof("Interface name: %s", ar.ifra_name) - tun.core.log.Infof("Interface IPv6: %s", addr) - tun.core.log.Infof("Interface MTU: %d", ir.ifru_mtu) + tun.log.Infof("Interface name: %s", ar.ifra_name) + tun.log.Infof("Interface IPv6: %s", addr) + tun.log.Infof("Interface MTU: %d", ir.ifru_mtu) if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(darwin_SIOCAIFADDR_IN6), uintptr(unsafe.Pointer(&ar))); errno != 0 { err = errno - tun.core.log.Errorf("Error in darwin_SIOCAIFADDR_IN6: %v", errno) + tun.log.Errorf("Error in darwin_SIOCAIFADDR_IN6: %v", errno) return err } if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(unix.SIOCSIFMTU), uintptr(unsafe.Pointer(&ir))); errno != 0 { err = errno - tun.core.log.Errorf("Error in SIOCSIFMTU: %v", errno) + tun.log.Errorf("Error in SIOCSIFMTU: %v", errno) return err } diff --git a/src/yggdrasil/tun_dummy.go b/src/tuntap/tun_dummy.go similarity index 79% rename from src/yggdrasil/tun_dummy.go rename to src/tuntap/tun_dummy.go index 234ab1d..04e6525 100644 --- a/src/yggdrasil/tun_dummy.go +++ b/src/tuntap/tun_dummy.go @@ -1,19 +1,19 @@ // +build mobile -package yggdrasil +package tuntap // This is to catch unsupported platforms // If your platform supports tun devices, you could try configuring it manually // Creates the TUN/TAP adapter, if supported by the Water library. Note that // no guarantees are made at this point on an unsupported platform. -func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { +func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { tun.mtu = getSupportedMTU(mtu) return tun.setupAddress(addr) } // We don't know how to set the IPv6 address on an unknown platform, therefore // write about it to stdout and don't try to do anything further. -func (tun *tunAdapter) setupAddress(addr string) error { +func (tun *TunAdapter) setupAddress(addr string) error { return nil } diff --git a/src/yggdrasil/tun_linux.go b/src/tuntap/tun_linux.go similarity index 93% rename from src/yggdrasil/tun_linux.go rename to src/tuntap/tun_linux.go index 30ada23..051287e 100644 --- a/src/yggdrasil/tun_linux.go +++ b/src/tuntap/tun_linux.go @@ -1,6 +1,6 @@ // +build !mobile -package yggdrasil +package tuntap // The linux platform specific tun parts @@ -15,7 +15,7 @@ import ( ) // Configures the TAP adapter with the correct IPv6 address and MTU. -func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { +func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { var config water.Config if iftapmode { config = water.Config{DeviceType: water.TAP} @@ -50,7 +50,7 @@ func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int // is used to do this, so there is not a hard requirement on "ip" or "ifconfig" // to exist on the system, but this will fail if Netlink is not present in the // kernel (it nearly always is). -func (tun *tunAdapter) setupAddress(addr string) error { +func (tun *TunAdapter) setupAddress(addr string) error { // Set address var netIF *net.Interface ifces, err := net.Interfaces() diff --git a/src/yggdrasil/tun_other.go b/src/tuntap/tun_other.go similarity index 87% rename from src/yggdrasil/tun_other.go rename to src/tuntap/tun_other.go index 07ec25f..17dfa2b 100644 --- a/src/yggdrasil/tun_other.go +++ b/src/tuntap/tun_other.go @@ -1,6 +1,6 @@ // +build !linux,!darwin,!windows,!openbsd,!freebsd,!netbsd,!mobile -package yggdrasil +package tuntap import water "github.com/yggdrasil-network/water" @@ -9,7 +9,7 @@ import water "github.com/yggdrasil-network/water" // Creates the TUN/TAP adapter, if supported by the Water library. Note that // no guarantees are made at this point on an unsupported platform. -func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { +func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { var config water.Config if iftapmode { config = water.Config{DeviceType: water.TAP} @@ -27,7 +27,7 @@ func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int // We don't know how to set the IPv6 address on an unknown platform, therefore // write about it to stdout and don't try to do anything further. -func (tun *tunAdapter) setupAddress(addr string) error { +func (tun *TunAdapter) setupAddress(addr string) error { tun.core.log.Warnln("Platform not supported, you must set the address of", tun.iface.Name(), "to", addr) return nil } diff --git a/src/yggdrasil/tun_windows.go b/src/tuntap/tun_windows.go similarity index 93% rename from src/yggdrasil/tun_windows.go rename to src/tuntap/tun_windows.go index 1c89a43..f5cebe5 100644 --- a/src/yggdrasil/tun_windows.go +++ b/src/tuntap/tun_windows.go @@ -1,4 +1,4 @@ -package yggdrasil +package tuntap import ( "fmt" @@ -13,7 +13,7 @@ import ( // Configures the TAP adapter with the correct IPv6 address and MTU. On Windows // we don't make use of a direct operating system API to do this - we instead // delegate the hard work to "netsh". -func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { +func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { if !iftapmode { tun.core.log.Warnln("TUN mode is not supported on this platform, defaulting to TAP") } @@ -65,7 +65,7 @@ func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int } // Sets the MTU of the TAP adapter. -func (tun *tunAdapter) setupMTU(mtu int) error { +func (tun *TunAdapter) setupMTU(mtu int) error { // Set MTU cmd := exec.Command("netsh", "interface", "ipv6", "set", "subinterface", fmt.Sprintf("interface=%s", tun.iface.Name()), @@ -82,7 +82,7 @@ func (tun *tunAdapter) setupMTU(mtu int) error { } // Sets the IPv6 address of the TAP adapter. -func (tun *tunAdapter) setupAddress(addr string) error { +func (tun *TunAdapter) setupAddress(addr string) error { // Set address cmd := exec.Command("netsh", "interface", "ipv6", "add", "address", fmt.Sprintf("interface=%s", tun.iface.Name()), diff --git a/src/yggdrasil/adapter.go b/src/yggdrasil/adapter.go index 3ce80d2..7437eb0 100644 --- a/src/yggdrasil/adapter.go +++ b/src/yggdrasil/adapter.go @@ -1,18 +1,36 @@ package yggdrasil +import ( + "github.com/gologme/log" + "github.com/yggdrasil-network/yggdrasil-go/src/address" + "github.com/yggdrasil-network/yggdrasil-go/src/config" +) + // Defines the minimum required struct members for an adapter type (this is -// now the base type for tunAdapter in tun.go) +// now the base type for TunAdapter in tun.go) type Adapter struct { - core *Core - send chan<- []byte - recv <-chan []byte - reconfigure chan chan error + adapterImplementation + Core *Core + Send chan<- []byte + Recv <-chan []byte + Reconfigure chan chan error +} + +// Defines the minimum required functions for an adapter type +type adapterImplementation interface { + Init(*config.NodeState, *log.Logger, chan<- []byte, <-chan []byte) + Name() string + MTU() int + IsTAP() bool + Start(address.Address, address.Subnet) error + Read() error + Write() error + Close() error } // Initialises the adapter. -func (adapter *Adapter) init(core *Core, send chan<- []byte, recv <-chan []byte) { - adapter.core = core - adapter.send = send - adapter.recv = recv - adapter.reconfigure = make(chan chan error, 1) +func (adapter Adapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte) { + adapter.Send = send + adapter.Recv = recv + adapter.Reconfigure = make(chan chan error, 1) } diff --git a/src/yggdrasil/admin.go b/src/yggdrasil/admin.go index a0854f2..002f974 100644 --- a/src/yggdrasil/admin.go +++ b/src/yggdrasil/admin.go @@ -16,7 +16,6 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/address" "github.com/yggdrasil-network/yggdrasil-go/src/crypto" - "github.com/yggdrasil-network/yggdrasil-go/src/defaults" ) // TODO: Add authentication @@ -58,19 +57,17 @@ func (a *admin) init(c *Core) { go func() { for { e := <-a.reconfigure - a.core.configMutex.RLock() - if a.core.config.AdminListen != a.core.configOld.AdminListen { - a.listenaddr = a.core.config.AdminListen + current, previous := a.core.config.Get() + if current.AdminListen != previous.AdminListen { + a.listenaddr = current.AdminListen a.close() a.start() } - a.core.configMutex.RUnlock() e <- nil } }() - a.core.configMutex.RLock() - a.listenaddr = a.core.config.AdminListen - a.core.configMutex.RUnlock() + current, _ := a.core.config.Get() + a.listenaddr = current.AdminListen a.addHandler("list", []string{}, func(in admin_info) (admin_info, error) { handlers := make(map[string]interface{}) for _, handler := range a.handlers { @@ -171,47 +168,47 @@ func (a *admin) init(c *Core) { }, errors.New("Failed to remove peer") } }) - a.addHandler("getTunTap", []string{}, func(in admin_info) (r admin_info, e error) { - defer func() { - if err := recover(); err != nil { - r = admin_info{"none": admin_info{}} - e = nil - } - }() + /* a.addHandler("getTunTap", []string{}, func(in admin_info) (r admin_info, e error) { + defer func() { + if err := recover(); err != nil { + r = admin_info{"none": admin_info{}} + e = nil + } + }() - return admin_info{ - a.core.router.tun.iface.Name(): admin_info{ - "tap_mode": a.core.router.tun.iface.IsTAP(), - "mtu": a.core.router.tun.mtu, - }, - }, nil - }) - a.addHandler("setTunTap", []string{"name", "[tap_mode]", "[mtu]"}, func(in admin_info) (admin_info, error) { - // Set sane defaults - iftapmode := defaults.GetDefaults().DefaultIfTAPMode - ifmtu := defaults.GetDefaults().DefaultIfMTU - // Has TAP mode been specified? - if tap, ok := in["tap_mode"]; ok { - iftapmode = tap.(bool) - } - // Check we have enough params for MTU - if mtu, ok := in["mtu"]; ok { - if mtu.(float64) >= 1280 && ifmtu <= defaults.GetDefaults().MaximumIfMTU { - ifmtu = int(in["mtu"].(float64)) - } - } - // Start the TUN adapter - if err := a.startTunWithMTU(in["name"].(string), iftapmode, ifmtu); err != nil { - return admin_info{}, errors.New("Failed to configure adapter") - } else { return admin_info{ a.core.router.tun.iface.Name(): admin_info{ "tap_mode": a.core.router.tun.iface.IsTAP(), - "mtu": ifmtu, + "mtu": a.core.router.tun.mtu, }, }, nil - } - }) + }) + a.addHandler("setTunTap", []string{"name", "[tap_mode]", "[mtu]"}, func(in admin_info) (admin_info, error) { + // Set sane defaults + iftapmode := defaults.GetDefaults().DefaultIfTAPMode + ifmtu := defaults.GetDefaults().DefaultIfMTU + // Has TAP mode been specified? + if tap, ok := in["tap_mode"]; ok { + iftapmode = tap.(bool) + } + // Check we have enough params for MTU + if mtu, ok := in["mtu"]; ok { + if mtu.(float64) >= 1280 && ifmtu <= defaults.GetDefaults().MaximumIfMTU { + ifmtu = int(in["mtu"].(float64)) + } + } + // Start the TUN adapter + if err := a.startTunWithMTU(in["name"].(string), iftapmode, ifmtu); err != nil { + return admin_info{}, errors.New("Failed to configure adapter") + } else { + return admin_info{ + a.core.router.tun.iface.Name(): admin_info{ + "tap_mode": a.core.router.tun.iface.IsTAP(), + "mtu": ifmtu, + }, + }, nil + } + })*/ a.addHandler("getMulticastInterfaces", []string{}, func(in admin_info) (admin_info, error) { var intfs []string for _, v := range a.core.multicast.interfaces() { @@ -609,6 +606,7 @@ func (a *admin) removePeer(p string) error { } // startTunWithMTU creates the tun/tap device, sets its address, and sets the MTU to the provided value. +/* func (a *admin) startTunWithMTU(ifname string, iftapmode bool, ifmtu int) error { // Close the TUN first if open _ = a.core.router.tun.close() @@ -636,6 +634,7 @@ func (a *admin) startTunWithMTU(ifname string, iftapmode bool, ifmtu int) error go a.core.router.tun.write() return nil } +*/ // getData_getSelf returns the self node's info for admin responses. func (a *admin) getData_getSelf() *admin_nodeInfo { diff --git a/src/yggdrasil/ckr.go b/src/yggdrasil/ckr.go index 03bc571..dc4f1b9 100644 --- a/src/yggdrasil/ckr.go +++ b/src/yggdrasil/ckr.go @@ -55,25 +55,24 @@ func (c *cryptokey) init(core *Core) { // Configure the CKR routes - this must only ever be called from the router // goroutine, e.g. through router.doAdmin func (c *cryptokey) configure() error { - c.core.configMutex.RLock() - defer c.core.configMutex.RUnlock() + current, _ := c.core.config.Get() // Set enabled/disabled state - c.setEnabled(c.core.config.TunnelRouting.Enable) + c.setEnabled(current.TunnelRouting.Enable) // Clear out existing routes c.ipv6routes = make([]cryptokey_route, 0) c.ipv4routes = make([]cryptokey_route, 0) // Add IPv6 routes - for ipv6, pubkey := range c.core.config.TunnelRouting.IPv6Destinations { + for ipv6, pubkey := range current.TunnelRouting.IPv6Destinations { if err := c.addRoute(ipv6, pubkey); err != nil { return err } } // Add IPv4 routes - for ipv4, pubkey := range c.core.config.TunnelRouting.IPv4Destinations { + for ipv4, pubkey := range current.TunnelRouting.IPv4Destinations { if err := c.addRoute(ipv4, pubkey); err != nil { return err } @@ -85,7 +84,7 @@ func (c *cryptokey) configure() error { // Add IPv6 sources c.ipv6sources = make([]net.IPNet, 0) - for _, source := range c.core.config.TunnelRouting.IPv6Sources { + for _, source := range current.TunnelRouting.IPv6Sources { if err := c.addSourceSubnet(source); err != nil { return err } @@ -93,7 +92,7 @@ func (c *cryptokey) configure() error { // Add IPv4 sources c.ipv4sources = make([]net.IPNet, 0) - for _, source := range c.core.config.TunnelRouting.IPv4Sources { + for _, source := range current.TunnelRouting.IPv4Sources { if err := c.addSourceSubnet(source); err != nil { return err } diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index 12ff14f..a583d58 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -4,7 +4,6 @@ import ( "encoding/hex" "io/ioutil" "net" - "sync" "time" "github.com/gologme/log" @@ -29,9 +28,7 @@ type Core struct { // This is the main data structure that holds everything else for a node // 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 - config config.NodeConfig // Active config - configOld config.NodeConfig // Previous config - configMutex sync.RWMutex // Protects both config and configOld + config config.NodeState // Config boxPub crypto.BoxPubKey boxPriv crypto.BoxPrivKey sigPub crypto.SigPubKey @@ -57,19 +54,21 @@ func (c *Core) init() error { c.log = log.New(ioutil.Discard, "", 0) } - boxPubHex, err := hex.DecodeString(c.config.EncryptionPublicKey) + current, _ := c.config.Get() + + boxPubHex, err := hex.DecodeString(current.EncryptionPublicKey) if err != nil { return err } - boxPrivHex, err := hex.DecodeString(c.config.EncryptionPrivateKey) + boxPrivHex, err := hex.DecodeString(current.EncryptionPrivateKey) if err != nil { return err } - sigPubHex, err := hex.DecodeString(c.config.SigningPublicKey) + sigPubHex, err := hex.DecodeString(current.SigningPublicKey) if err != nil { return err } - sigPrivHex, err := hex.DecodeString(c.config.SigningPrivateKey) + sigPrivHex, err := hex.DecodeString(current.SigningPrivateKey) if err != nil { return err } @@ -97,19 +96,16 @@ func (c *Core) init() error { func (c *Core) addPeerLoop() { for { // Get the peers from the config - these could change! - c.configMutex.RLock() - peers := c.config.Peers - interfacepeers := c.config.InterfacePeers - c.configMutex.RUnlock() + current, _ := c.config.Get() // Add peers from the Peers section - for _, peer := range peers { + for _, peer := range current.Peers { c.AddPeer(peer, "") time.Sleep(time.Second) } // Add peers from the InterfacePeers section - for intf, intfpeers := range interfacepeers { + for intf, intfpeers := range current.InterfacePeers { for _, peer := range intfpeers { c.AddPeer(peer, intf) time.Sleep(time.Second) @@ -126,10 +122,7 @@ func (c *Core) addPeerLoop() { func (c *Core) UpdateConfig(config *config.NodeConfig) { c.log.Infoln("Reloading configuration...") - c.configMutex.Lock() - c.configOld = c.config - c.config = *config - c.configMutex.Unlock() + c.config.Replace(*config) errors := 0 @@ -140,7 +133,7 @@ func (c *Core) UpdateConfig(config *config.NodeConfig) { c.sessions.reconfigure, c.peers.reconfigure, c.router.reconfigure, - c.router.tun.reconfigure, + //c.router.tun.Reconfigure, c.router.cryptokey.reconfigure, c.switchTable.reconfigure, c.link.reconfigure, @@ -181,13 +174,23 @@ func GetBuildVersion() string { return buildVersion } -// Starts up Yggdrasil using the provided NodeConfig, and outputs debug logging +// Set the router adapter +func (c *Core) SetRouterAdapter(adapter adapterImplementation) { + c.router.tun = adapter +} + +// Starts up Yggdrasil using the provided NodeState, 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.config = config.NodeState{ + Current: *nc, + Previous: *nc, + } + if name := GetBuildName(); name != "unknown" { c.log.Infoln("Build name:", name) } @@ -197,11 +200,6 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error { c.log.Infoln("Starting up...") - c.configMutex.Lock() - c.config = *nc - c.configOld = c.config - c.configMutex.Unlock() - c.init() if err := c.link.init(c); err != nil { @@ -209,9 +207,11 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error { return err } - if nc.SwitchOptions.MaxTotalQueueSize >= SwitchQueueTotalMinSize { - c.switchTable.queueTotalMaxSize = nc.SwitchOptions.MaxTotalQueueSize + c.config.Mutex.RLock() + if c.config.Current.SwitchOptions.MaxTotalQueueSize >= SwitchQueueTotalMinSize { + c.switchTable.queueTotalMaxSize = c.config.Current.SwitchOptions.MaxTotalQueueSize } + c.config.Mutex.RUnlock() if err := c.switchTable.start(); err != nil { c.log.Errorln("Failed to start switch") @@ -233,7 +233,7 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error { return err } - if err := c.router.tun.start(); err != nil { + if err := c.router.tun.Start(c.router.addr, c.router.subnet); err != nil { c.log.Errorln("Failed to start TUN/TAP") return err } @@ -247,7 +247,7 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error { // Stops the Yggdrasil node. func (c *Core) Stop() { c.log.Infoln("Stopping...") - c.router.tun.close() + c.router.tun.Close() c.admin.close() } @@ -343,10 +343,12 @@ func (c *Core) GetTUNDefaultIfTAPMode() bool { // Gets the current TUN/TAP interface name. func (c *Core) GetTUNIfName() string { - return c.router.tun.iface.Name() + //return c.router.tun.iface.Name() + return c.router.tun.Name() } // Gets the current TUN/TAP interface MTU. func (c *Core) GetTUNIfMTU() int { - return c.router.tun.mtu + //return c.router.tun.mtu + return c.router.tun.MTU() } diff --git a/src/yggdrasil/multicast.go b/src/yggdrasil/multicast.go index ca3a1f7..ab1b158 100644 --- a/src/yggdrasil/multicast.go +++ b/src/yggdrasil/multicast.go @@ -23,9 +23,8 @@ func (m *multicast) init(core *Core) { m.core = core m.reconfigure = make(chan chan error, 1) m.listeners = make(map[string]*tcpListener) - m.core.configMutex.RLock() - m.listenPort = m.core.config.LinkLocalTCPPort - m.core.configMutex.RUnlock() + current, _ := m.core.config.Get() + m.listenPort = current.LinkLocalTCPPort go func() { for { e := <-m.reconfigure @@ -70,9 +69,8 @@ func (m *multicast) start() error { func (m *multicast) interfaces() map[string]net.Interface { // Get interface expressions from config - m.core.configMutex.RLock() - exprs := m.core.config.MulticastInterfaces - m.core.configMutex.RUnlock() + current, _ := m.core.config.Get() + exprs := current.MulticastInterfaces // Ask the system for network interfaces interfaces := make(map[string]net.Interface) allifaces, err := net.Interfaces() diff --git a/src/yggdrasil/peer.go b/src/yggdrasil/peer.go index ce35936..06201f9 100644 --- a/src/yggdrasil/peer.go +++ b/src/yggdrasil/peer.go @@ -44,42 +44,42 @@ func (ps *peers) init(c *Core) { // because the key is in the whitelist or because the whitelist is empty. func (ps *peers) isAllowedEncryptionPublicKey(box *crypto.BoxPubKey) bool { boxstr := hex.EncodeToString(box[:]) - ps.core.configMutex.RLock() - defer ps.core.configMutex.RUnlock() - for _, v := range ps.core.config.AllowedEncryptionPublicKeys { + ps.core.config.Mutex.RLock() + defer ps.core.config.Mutex.RUnlock() + for _, v := range ps.core.config.Current.AllowedEncryptionPublicKeys { if v == boxstr { return true } } - return len(ps.core.config.AllowedEncryptionPublicKeys) == 0 + return len(ps.core.config.Current.AllowedEncryptionPublicKeys) == 0 } // Adds a key to the whitelist. func (ps *peers) addAllowedEncryptionPublicKey(box string) { - ps.core.configMutex.RLock() - defer ps.core.configMutex.RUnlock() - ps.core.config.AllowedEncryptionPublicKeys = - append(ps.core.config.AllowedEncryptionPublicKeys, box) + ps.core.config.Mutex.RLock() + defer ps.core.config.Mutex.RUnlock() + ps.core.config.Current.AllowedEncryptionPublicKeys = + append(ps.core.config.Current.AllowedEncryptionPublicKeys, box) } // Removes a key from the whitelist. func (ps *peers) removeAllowedEncryptionPublicKey(box string) { - ps.core.configMutex.RLock() - defer ps.core.configMutex.RUnlock() - for k, v := range ps.core.config.AllowedEncryptionPublicKeys { + ps.core.config.Mutex.RLock() + defer ps.core.config.Mutex.RUnlock() + for k, v := range ps.core.config.Current.AllowedEncryptionPublicKeys { if v == box { - ps.core.config.AllowedEncryptionPublicKeys = - append(ps.core.config.AllowedEncryptionPublicKeys[:k], - ps.core.config.AllowedEncryptionPublicKeys[k+1:]...) + ps.core.config.Current.AllowedEncryptionPublicKeys = + append(ps.core.config.Current.AllowedEncryptionPublicKeys[:k], + ps.core.config.Current.AllowedEncryptionPublicKeys[k+1:]...) } } } // Gets the whitelist of allowed keys for incoming connections. func (ps *peers) getAllowedEncryptionPublicKeys() []string { - ps.core.configMutex.RLock() - defer ps.core.configMutex.RUnlock() - return ps.core.config.AllowedEncryptionPublicKeys + ps.core.config.Mutex.RLock() + defer ps.core.config.Mutex.RUnlock() + return ps.core.config.Current.AllowedEncryptionPublicKeys } // Atomically gets a map[switchPort]*peer of known peers. diff --git a/src/yggdrasil/router.go b/src/yggdrasil/router.go index 1d4c077..04f5ee5 100644 --- a/src/yggdrasil/router.go +++ b/src/yggdrasil/router.go @@ -26,9 +26,6 @@ import ( "bytes" "time" - "golang.org/x/net/icmp" - "golang.org/x/net/ipv6" - "github.com/yggdrasil-network/yggdrasil-go/src/address" "github.com/yggdrasil-network/yggdrasil-go/src/crypto" "github.com/yggdrasil-network/yggdrasil-go/src/util" @@ -44,8 +41,7 @@ type router struct { in <-chan []byte // packets we received from the network, link to peer's "out" out func([]byte) // packets we're sending to the network, link to peer's "in" toRecv chan router_recvPacket // packets to handle via recvPacket() - tun tunAdapter // TUN/TAP adapter - adapters []Adapter // Other adapters + tun adapterImplementation // TUN/TAP adapter recv chan<- []byte // place where the tun pulls received packets from send <-chan []byte // place where the tun puts outgoing packets reset chan struct{} // signal that coords changed (re-init sessions/dht) @@ -112,11 +108,11 @@ func (r *router) init(core *Core) { r.reset = make(chan struct{}, 1) r.admin = make(chan func(), 32) r.nodeinfo.init(r.core) - r.core.configMutex.RLock() - r.nodeinfo.setNodeInfo(r.core.config.NodeInfo, r.core.config.NodeInfoPrivacy) - r.core.configMutex.RUnlock() + r.core.config.Mutex.RLock() + r.nodeinfo.setNodeInfo(r.core.config.Current.NodeInfo, r.core.config.Current.NodeInfoPrivacy) + r.core.config.Mutex.RUnlock() r.cryptokey.init(r.core) - r.tun.init(r.core, send, recv) + r.tun.Init(&r.core.config, r.core.log, send, recv) } // Starts the mainLoop goroutine. @@ -157,9 +153,8 @@ func (r *router) mainLoop() { case f := <-r.admin: f() case e := <-r.reconfigure: - r.core.configMutex.RLock() - e <- r.nodeinfo.setNodeInfo(r.core.config.NodeInfo, r.core.config.NodeInfoPrivacy) - r.core.configMutex.RUnlock() + current, _ := r.core.config.Get() + e <- r.nodeinfo.setNodeInfo(current.NodeInfo, current.NodeInfoPrivacy) } } } @@ -308,7 +303,7 @@ func (r *router) sendPacket(bs []byte) { // Generate an ICMPv6 Packet Too Big for packets larger than session MTU if len(bs) > int(sinfo.getMTU()) { // Get the size of the oversized payload, up to a max of 900 bytes - window := 900 + /*window := 900 if int(sinfo.getMTU()) < window { window = int(sinfo.getMTU()) } @@ -320,12 +315,12 @@ func (r *router) sendPacket(bs []byte) { } // Create the ICMPv6 response from it - icmpv6Buf, err := r.tun.icmpv6.create_icmpv6_tun( + icmpv6Buf, err := CreateICMPv6( bs[8:24], bs[24:40], ipv6.ICMPTypePacketTooBig, 0, ptb) if err == nil { r.recv <- icmpv6Buf - } + }*/ // Don't continue - drop the packet return diff --git a/src/yggdrasil/session.go b/src/yggdrasil/session.go index 012af57..b3563e0 100644 --- a/src/yggdrasil/session.go +++ b/src/yggdrasil/session.go @@ -148,17 +148,17 @@ func (ss *sessions) init(core *Core) { // Determines whether the session firewall is enabled. func (ss *sessions) isSessionFirewallEnabled() bool { - ss.core.configMutex.RLock() - defer ss.core.configMutex.RUnlock() + ss.core.config.Mutex.RLock() + defer ss.core.config.Mutex.RUnlock() - return ss.core.config.SessionFirewall.Enable + return ss.core.config.Current.SessionFirewall.Enable } // Determines whether the session with a given publickey is allowed based on // session firewall rules. func (ss *sessions) isSessionAllowed(pubkey *crypto.BoxPubKey, initiator bool) bool { - ss.core.configMutex.RLock() - defer ss.core.configMutex.RUnlock() + ss.core.config.Mutex.RLock() + defer ss.core.config.Mutex.RUnlock() // Allow by default if the session firewall is disabled if !ss.isSessionFirewallEnabled() { @@ -167,7 +167,7 @@ func (ss *sessions) isSessionAllowed(pubkey *crypto.BoxPubKey, initiator bool) b // Prepare for checking whitelist/blacklist var box crypto.BoxPubKey // Reject blacklisted nodes - for _, b := range ss.core.config.SessionFirewall.BlacklistEncryptionPublicKeys { + for _, b := range ss.core.config.Current.SessionFirewall.BlacklistEncryptionPublicKeys { key, err := hex.DecodeString(b) if err == nil { copy(box[:crypto.BoxPubKeyLen], key) @@ -177,7 +177,7 @@ func (ss *sessions) isSessionAllowed(pubkey *crypto.BoxPubKey, initiator bool) b } } // Allow whitelisted nodes - for _, b := range ss.core.config.SessionFirewall.WhitelistEncryptionPublicKeys { + for _, b := range ss.core.config.Current.SessionFirewall.WhitelistEncryptionPublicKeys { key, err := hex.DecodeString(b) if err == nil { copy(box[:crypto.BoxPubKeyLen], key) @@ -187,7 +187,7 @@ func (ss *sessions) isSessionAllowed(pubkey *crypto.BoxPubKey, initiator bool) b } } // Allow outbound sessions if appropriate - if ss.core.config.SessionFirewall.AlwaysAllowOutbound { + if ss.core.config.Current.SessionFirewall.AlwaysAllowOutbound { if initiator { return true } @@ -201,11 +201,11 @@ func (ss *sessions) isSessionAllowed(pubkey *crypto.BoxPubKey, initiator bool) b } } // Allow direct peers if appropriate - if ss.core.config.SessionFirewall.AllowFromDirect && isDirectPeer { + if ss.core.config.Current.SessionFirewall.AllowFromDirect && isDirectPeer { return true } // Allow remote nodes if appropriate - if ss.core.config.SessionFirewall.AllowFromRemote && !isDirectPeer { + if ss.core.config.Current.SessionFirewall.AllowFromRemote && !isDirectPeer { return true } // Finally, default-deny if not matching any of the above rules @@ -277,7 +277,7 @@ func (ss *sessions) createSession(theirPermKey *crypto.BoxPubKey) *sessionInfo { sinfo.mySesPriv = *priv sinfo.myNonce = *crypto.NewBoxNonce() sinfo.theirMTU = 1280 - sinfo.myMTU = uint16(ss.core.router.tun.mtu) + sinfo.myMTU = uint16(ss.core.router.tun.MTU()) now := time.Now() sinfo.time = now sinfo.mtuTime = now diff --git a/src/yggdrasil/switch.go b/src/yggdrasil/switch.go index 490b15f..0e164b9 100644 --- a/src/yggdrasil/switch.go +++ b/src/yggdrasil/switch.go @@ -188,9 +188,7 @@ func (t *switchTable) init(core *Core) { now := time.Now() t.core = core t.reconfigure = make(chan chan error, 1) - t.core.configMutex.RLock() t.key = t.core.sigPub - t.core.configMutex.RUnlock() locator := switchLocator{root: t.key, tstamp: now.Unix()} peers := make(map[switchPort]peerInfo) t.data = switchData{locator: locator, peers: peers} diff --git a/src/yggdrasil/tcp.go b/src/yggdrasil/tcp.go index 8acf9c1..f25ac41 100644 --- a/src/yggdrasil/tcp.go +++ b/src/yggdrasil/tcp.go @@ -82,10 +82,10 @@ func (t *tcp) init(l *link) error { go func() { for { e := <-t.reconfigure - t.link.core.configMutex.RLock() - added := util.Difference(t.link.core.config.Listen, t.link.core.configOld.Listen) - deleted := util.Difference(t.link.core.configOld.Listen, t.link.core.config.Listen) - t.link.core.configMutex.RUnlock() + t.link.core.config.Mutex.RLock() + added := util.Difference(t.link.core.config.Current.Listen, t.link.core.config.Previous.Listen) + deleted := util.Difference(t.link.core.config.Previous.Listen, t.link.core.config.Current.Listen) + t.link.core.config.Mutex.RUnlock() if len(added) > 0 || len(deleted) > 0 { for _, a := range added { if a[:6] != "tcp://" { @@ -115,9 +115,9 @@ func (t *tcp) init(l *link) error { } }() - t.link.core.configMutex.RLock() - defer t.link.core.configMutex.RUnlock() - for _, listenaddr := range t.link.core.config.Listen { + t.link.core.config.Mutex.RLock() + defer t.link.core.config.Mutex.RUnlock() + for _, listenaddr := range t.link.core.config.Current.Listen { if listenaddr[:6] != "tcp://" { continue } From 0715e829c2b38ed1183d10b942803a3074c01507 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 28 Mar 2019 09:12:00 +0000 Subject: [PATCH 02/19] Fix adapter setup and no longer panics on packets shorter than IP header --- src/tuntap/icmpv6.go | 2 +- src/tuntap/tun.go | 20 +++++++++++++++----- src/yggdrasil/adapter.go | 3 ++- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/tuntap/icmpv6.go b/src/tuntap/icmpv6.go index f4f9efe..55c3280 100644 --- a/src/tuntap/icmpv6.go +++ b/src/tuntap/icmpv6.go @@ -93,7 +93,7 @@ func (i *ICMPv6) ParsePacket(datain []byte) { } // Write the packet to TUN/TAP - i.tun.Send <- response + i.tun.iface.Write(response) } // Unwraps the ethernet headers of an incoming ICMPv6 packet and hands off diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index 7dab31c..780043f 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -107,13 +107,20 @@ func (tun *TunAdapter) Start(a address.Address, s address.Subnet) error { } } if ifname == "none" || ifname == "dummy" { + tun.log.Debugln("Not starting TUN/TAP as ifname is none or dummy") return nil } tun.mutex.Lock() tun.isOpen = true tun.mutex.Unlock() - go func() { tun.log.Errorln("WARNING: tun.read() exited with error:", tun.Read()) }() - go func() { tun.log.Errorln("WARNING: tun.write() exited with error:", tun.Write()) }() + go func() { + tun.log.Debugln("Starting TUN/TAP reader goroutine") + tun.log.Errorln("WARNING: tun.read() exited with error:", tun.Read()) + }() + go func() { + tun.log.Debugln("Starting TUN/TAP writer goroutine") + tun.log.Errorln("WARNING: tun.write() exited with error:", tun.Write()) + }() if iftapmode { go func() { for { @@ -147,12 +154,16 @@ func (tun *TunAdapter) Write() error { var destAddr address.Address if data[0]&0xf0 == 0x60 { if len(data) < 40 { - panic("Tried to send a packet shorter than an IPv6 header...") + //panic("Tried to send a packet shorter than an IPv6 header...") + util.PutBytes(data) + continue } copy(destAddr[:16], data[24:]) } else if data[0]&0xf0 == 0x40 { if len(data) < 20 { - panic("Tried to send a packet shorter than an IPv4 header...") + //panic("Tried to send a packet shorter than an IPv4 header...") + util.PutBytes(data) + continue } copy(destAddr[:4], data[16:]) } else { @@ -255,7 +266,6 @@ func (tun *TunAdapter) Read() error { if !open { return nil } else { - // panic(err) return err } } diff --git a/src/yggdrasil/adapter.go b/src/yggdrasil/adapter.go index 7437eb0..4103d1e 100644 --- a/src/yggdrasil/adapter.go +++ b/src/yggdrasil/adapter.go @@ -29,7 +29,8 @@ type adapterImplementation interface { } // Initialises the adapter. -func (adapter Adapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte) { +func (adapter *Adapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte) { + log.Traceln("Adapter setup - given channels:", send, recv) adapter.Send = send adapter.Recv = recv adapter.Reconfigure = make(chan chan error, 1) From eb22ed44ac24664e7f964a7c1fb27f2d7303d7ba Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 28 Mar 2019 09:50:13 +0000 Subject: [PATCH 03/19] Add new reject channel to router so we can send back rejected packets to adapter (e.g. for ICMPv6 Packet Too Big), implement ICMPv6 PTB in TUN/TAP instead of router --- src/tuntap/tun.go | 188 ++++++++++++++++++++++----------------- src/yggdrasil/adapter.go | 6 +- src/yggdrasil/router.go | 37 +++++--- 3 files changed, 135 insertions(+), 96 deletions(-) diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index 780043f..f85d8bb 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -11,6 +11,8 @@ import ( "time" "github.com/gologme/log" + "golang.org/x/net/icmp" + "golang.org/x/net/ipv6" "github.com/songgao/packets/ethernet" "github.com/yggdrasil-network/water" @@ -64,10 +66,10 @@ func (tun *TunAdapter) IsTAP() bool { } // Initialises the TUN/TAP adapter. -func (tun *TunAdapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte) { +func (tun *TunAdapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte, reject <-chan yggdrasil.RejectedPacket) { tun.config = config tun.log = log - tun.Adapter.Init(config, log, send, recv) + tun.Adapter.Init(config, log, send, recv, reject) tun.icmpv6.Init(tun) go func() { for { @@ -146,81 +148,118 @@ func (tun *TunAdapter) Start(a address.Address, s address.Subnet) error { // host operating system. func (tun *TunAdapter) Write() error { for { - data := <-tun.Recv - if tun.iface == nil { - continue - } - if tun.iface.IsTAP() { - var destAddr address.Address - if data[0]&0xf0 == 0x60 { - if len(data) < 40 { - //panic("Tried to send a packet shorter than an IPv6 header...") - util.PutBytes(data) - continue + select { + case reject := <-tun.Reject: + switch reject.Reason { + case yggdrasil.PacketTooBig: + if mtu, ok := reject.Detail.(int); ok { + // Create the Packet Too Big response + ptb := &icmp.PacketTooBig{ + MTU: int(mtu), + Data: reject.Packet, + } + + // Create the ICMPv6 response from it + icmpv6Buf, err := CreateICMPv6( + reject.Packet[8:24], reject.Packet[24:40], + ipv6.ICMPTypePacketTooBig, 0, ptb) + + // Send the ICMPv6 response back to the TUN/TAP adapter + if err == nil { + tun.iface.Write(icmpv6Buf) + } } - copy(destAddr[:16], data[24:]) - } else if data[0]&0xf0 == 0x40 { - if len(data) < 20 { - //panic("Tried to send a packet shorter than an IPv4 header...") - util.PutBytes(data) - continue - } - copy(destAddr[:4], data[16:]) - } else { - return errors.New("Invalid address family") + fallthrough + default: + continue } - sendndp := func(destAddr address.Address) { - neigh, known := tun.icmpv6.peermacs[destAddr] - known = known && (time.Since(neigh.lastsolicitation).Seconds() < 30) - if !known { - request, err := tun.icmpv6.CreateNDPL2(destAddr) - if err != nil { - panic(err) + case data := <-tun.Recv: + if tun.iface == nil { + continue + } + if tun.iface.IsTAP() { + var destAddr address.Address + if data[0]&0xf0 == 0x60 { + if len(data) < 40 { + //panic("Tried to send a packet shorter than an IPv6 header...") + util.PutBytes(data) + continue } - if _, err := tun.iface.Write(request); err != nil { - panic(err) + copy(destAddr[:16], data[24:]) + } else if data[0]&0xf0 == 0x40 { + if len(data) < 20 { + //panic("Tried to send a packet shorter than an IPv4 header...") + util.PutBytes(data) + continue } - tun.icmpv6.peermacs[destAddr] = neighbor{ - lastsolicitation: time.Now(), + copy(destAddr[:4], data[16:]) + } else { + return errors.New("Invalid address family") + } + sendndp := func(destAddr address.Address) { + neigh, known := tun.icmpv6.peermacs[destAddr] + known = known && (time.Since(neigh.lastsolicitation).Seconds() < 30) + if !known { + request, err := tun.icmpv6.CreateNDPL2(destAddr) + if err != nil { + panic(err) + } + if _, err := tun.iface.Write(request); err != nil { + panic(err) + } + tun.icmpv6.peermacs[destAddr] = neighbor{ + lastsolicitation: time.Now(), + } } } - } - var peermac macAddress - var peerknown bool - if data[0]&0xf0 == 0x40 { - destAddr = tun.addr - } else if data[0]&0xf0 == 0x60 { - if !bytes.Equal(tun.addr[:16], destAddr[:16]) && !bytes.Equal(tun.subnet[:8], destAddr[:8]) { + var peermac macAddress + var peerknown bool + if data[0]&0xf0 == 0x40 { destAddr = tun.addr + } else if data[0]&0xf0 == 0x60 { + if !bytes.Equal(tun.addr[:16], destAddr[:16]) && !bytes.Equal(tun.subnet[:8], destAddr[:8]) { + destAddr = tun.addr + } + } + if neighbor, ok := tun.icmpv6.peermacs[destAddr]; ok && neighbor.learned { + peermac = neighbor.mac + peerknown = true + } else if neighbor, ok := tun.icmpv6.peermacs[tun.addr]; ok && neighbor.learned { + peermac = neighbor.mac + peerknown = true + sendndp(destAddr) + } else { + sendndp(tun.addr) + } + if peerknown { + var proto ethernet.Ethertype + switch { + case data[0]&0xf0 == 0x60: + proto = ethernet.IPv6 + case data[0]&0xf0 == 0x40: + proto = ethernet.IPv4 + } + var frame ethernet.Frame + frame.Prepare( + peermac[:6], // Destination MAC address + tun.icmpv6.mymac[:6], // Source MAC address + ethernet.NotTagged, // VLAN tagging + proto, // Ethertype + len(data)) // Payload length + copy(frame[tun_ETHER_HEADER_LENGTH:], data[:]) + if _, err := tun.iface.Write(frame); err != nil { + tun.mutex.RLock() + open := tun.isOpen + tun.mutex.RUnlock() + if !open { + return nil + } else { + panic(err) + } + } } - } - if neighbor, ok := tun.icmpv6.peermacs[destAddr]; ok && neighbor.learned { - peermac = neighbor.mac - peerknown = true - } else if neighbor, ok := tun.icmpv6.peermacs[tun.addr]; ok && neighbor.learned { - peermac = neighbor.mac - peerknown = true - sendndp(destAddr) } else { - sendndp(tun.addr) - } - if peerknown { - var proto ethernet.Ethertype - switch { - case data[0]&0xf0 == 0x60: - proto = ethernet.IPv6 - case data[0]&0xf0 == 0x40: - proto = ethernet.IPv4 - } - var frame ethernet.Frame - frame.Prepare( - peermac[:6], // Destination MAC address - tun.icmpv6.mymac[:6], // Source MAC address - ethernet.NotTagged, // VLAN tagging - proto, // Ethertype - len(data)) // Payload length - copy(frame[tun_ETHER_HEADER_LENGTH:], data[:]) - if _, err := tun.iface.Write(frame); err != nil { + if _, err := tun.iface.Write(data); err != nil { tun.mutex.RLock() open := tun.isOpen tun.mutex.RUnlock() @@ -231,19 +270,8 @@ func (tun *TunAdapter) Write() error { } } } - } else { - if _, err := tun.iface.Write(data); err != nil { - tun.mutex.RLock() - open := tun.isOpen - tun.mutex.RUnlock() - if !open { - return nil - } else { - panic(err) - } - } + util.PutBytes(data) } - util.PutBytes(data) } } diff --git a/src/yggdrasil/adapter.go b/src/yggdrasil/adapter.go index 4103d1e..6be3ef0 100644 --- a/src/yggdrasil/adapter.go +++ b/src/yggdrasil/adapter.go @@ -13,12 +13,13 @@ type Adapter struct { Core *Core Send chan<- []byte Recv <-chan []byte + Reject <-chan RejectedPacket Reconfigure chan chan error } // Defines the minimum required functions for an adapter type type adapterImplementation interface { - Init(*config.NodeState, *log.Logger, chan<- []byte, <-chan []byte) + Init(*config.NodeState, *log.Logger, chan<- []byte, <-chan []byte, <-chan RejectedPacket) Name() string MTU() int IsTAP() bool @@ -29,9 +30,10 @@ type adapterImplementation interface { } // Initialises the adapter. -func (adapter *Adapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte) { +func (adapter *Adapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte, reject <-chan RejectedPacket) { log.Traceln("Adapter setup - given channels:", send, recv) adapter.Send = send adapter.Recv = recv + adapter.Reject = reject adapter.Reconfigure = make(chan chan error, 1) } diff --git a/src/yggdrasil/router.go b/src/yggdrasil/router.go index 04f5ee5..aa2cd54 100644 --- a/src/yggdrasil/router.go +++ b/src/yggdrasil/router.go @@ -44,6 +44,7 @@ type router struct { tun adapterImplementation // TUN/TAP adapter recv chan<- []byte // place where the tun pulls received packets from send <-chan []byte // place where the tun puts outgoing packets + reject chan<- RejectedPacket // place where we send error packets back to tun reset chan struct{} // signal that coords changed (re-init sessions/dht) admin chan func() // pass a lambda for the admin socket to query stuff cryptokey cryptokey @@ -56,6 +57,19 @@ type router_recvPacket struct { sinfo *sessionInfo } +type RejectedPacketReason int + +const ( + // The router rejected the packet because it is too big for the session + PacketTooBig = 1 + iota +) + +type RejectedPacket struct { + Reason RejectedPacketReason + Packet []byte + Detail interface{} +} + // Initializes the router struct, which includes setting up channels to/from the tun/tap. func (r *router) init(core *Core) { r.core = core @@ -103,8 +117,10 @@ func (r *router) init(core *Core) { r.toRecv = make(chan router_recvPacket, 32) recv := make(chan []byte, 32) send := make(chan []byte, 32) + reject := make(chan RejectedPacket, 32) r.recv = recv r.send = send + r.reject = reject r.reset = make(chan struct{}, 1) r.admin = make(chan func(), 32) r.nodeinfo.init(r.core) @@ -112,7 +128,7 @@ func (r *router) init(core *Core) { r.nodeinfo.setNodeInfo(r.core.config.Current.NodeInfo, r.core.config.Current.NodeInfoPrivacy) r.core.config.Mutex.RUnlock() r.cryptokey.init(r.core) - r.tun.Init(&r.core.config, r.core.log, send, recv) + r.tun.Init(&r.core.config, r.core.log, send, recv, reject) } // Starts the mainLoop goroutine. @@ -303,25 +319,18 @@ func (r *router) sendPacket(bs []byte) { // Generate an ICMPv6 Packet Too Big for packets larger than session MTU if len(bs) > int(sinfo.getMTU()) { // Get the size of the oversized payload, up to a max of 900 bytes - /*window := 900 + window := 900 if int(sinfo.getMTU()) < window { window = int(sinfo.getMTU()) } - // Create the Packet Too Big response - ptb := &icmp.PacketTooBig{ - MTU: int(sinfo.getMTU()), - Data: bs[:window], + // Send the error back to the adapter + r.reject <- RejectedPacket{ + Reason: PacketTooBig, + Packet: bs[:window], + Detail: int(sinfo.getMTU()), } - // Create the ICMPv6 response from it - icmpv6Buf, err := CreateICMPv6( - bs[8:24], bs[24:40], - ipv6.ICMPTypePacketTooBig, 0, ptb) - if err == nil { - r.recv <- icmpv6Buf - }*/ - // Don't continue - drop the packet return } From 03bc7bbcd607269bc40d742b2caee5f7accba1ca Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 28 Mar 2019 15:32:01 +0000 Subject: [PATCH 04/19] Fix TUN/TAP for non-Darwin platforms --- src/tuntap/tun_bsd.go | 24 ++++++++++++------------ src/tuntap/tun_linux.go | 6 +++--- src/tuntap/tun_other.go | 2 +- src/tuntap/tun_windows.go | 32 ++++++++++++++++---------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/tuntap/tun_bsd.go b/src/tuntap/tun_bsd.go index 95c13af..996f314 100644 --- a/src/tuntap/tun_bsd.go +++ b/src/tuntap/tun_bsd.go @@ -109,14 +109,14 @@ func (tun *TunAdapter) setupAddress(addr string) error { // Create system socket if sfd, err = unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0); err != nil { - tun.core.log.Printf("Create AF_INET socket failed: %v.", err) + tun.log.Printf("Create AF_INET socket failed: %v.", err) return err } // Friendly output - tun.core.log.Infof("Interface name: %s", tun.iface.Name()) - tun.core.log.Infof("Interface IPv6: %s", addr) - tun.core.log.Infof("Interface MTU: %d", tun.mtu) + tun.log.Infof("Interface name: %s", tun.iface.Name()) + tun.log.Infof("Interface IPv6: %s", addr) + tun.log.Infof("Interface MTU: %d", tun.mtu) // Create the MTU request var ir in6_ifreq_mtu @@ -126,15 +126,15 @@ func (tun *TunAdapter) setupAddress(addr string) error { // Set the MTU if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(sfd), uintptr(syscall.SIOCSIFMTU), uintptr(unsafe.Pointer(&ir))); errno != 0 { err = errno - tun.core.log.Errorf("Error in SIOCSIFMTU: %v", errno) + tun.log.Errorf("Error in SIOCSIFMTU: %v", errno) // Fall back to ifconfig to set the MTU cmd := exec.Command("ifconfig", tun.iface.Name(), "mtu", string(tun.mtu)) - tun.core.log.Warnf("Using ifconfig as fallback: %v", strings.Join(cmd.Args, " ")) + tun.log.Warnf("Using ifconfig as fallback: %v", strings.Join(cmd.Args, " ")) output, err := cmd.CombinedOutput() if err != nil { - tun.core.log.Errorf("SIOCSIFMTU fallback failed: %v.", err) - tun.core.log.Traceln(string(output)) + tun.log.Errorf("SIOCSIFMTU fallback failed: %v.", err) + tun.log.Traceln(string(output)) } } @@ -155,15 +155,15 @@ func (tun *TunAdapter) setupAddress(addr string) error { // Set the interface address if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(sfd), uintptr(SIOCSIFADDR_IN6), uintptr(unsafe.Pointer(&ar))); errno != 0 { err = errno - tun.core.log.Errorf("Error in SIOCSIFADDR_IN6: %v", errno) + tun.log.Errorf("Error in SIOCSIFADDR_IN6: %v", errno) // Fall back to ifconfig to set the address cmd := exec.Command("ifconfig", tun.iface.Name(), "inet6", addr) - tun.core.log.Warnf("Using ifconfig as fallback: %v", strings.Join(cmd.Args, " ")) + tun.log.Warnf("Using ifconfig as fallback: %v", strings.Join(cmd.Args, " ")) output, err := cmd.CombinedOutput() if err != nil { - tun.core.log.Errorf("SIOCSIFADDR_IN6 fallback failed: %v.", err) - tun.core.log.Traceln(string(output)) + tun.log.Errorf("SIOCSIFADDR_IN6 fallback failed: %v.", err) + tun.log.Traceln(string(output)) } } diff --git a/src/tuntap/tun_linux.go b/src/tuntap/tun_linux.go index 051287e..c9c03c0 100644 --- a/src/tuntap/tun_linux.go +++ b/src/tuntap/tun_linux.go @@ -40,9 +40,9 @@ func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int } } // Friendly output - tun.core.log.Infof("Interface name: %s", tun.iface.Name()) - tun.core.log.Infof("Interface IPv6: %s", addr) - tun.core.log.Infof("Interface MTU: %d", tun.mtu) + tun.log.Infof("Interface name: %s", tun.iface.Name()) + tun.log.Infof("Interface IPv6: %s", addr) + tun.log.Infof("Interface MTU: %d", tun.mtu) return tun.setupAddress(addr) } diff --git a/src/tuntap/tun_other.go b/src/tuntap/tun_other.go index 17dfa2b..48276b4 100644 --- a/src/tuntap/tun_other.go +++ b/src/tuntap/tun_other.go @@ -28,6 +28,6 @@ func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int // We don't know how to set the IPv6 address on an unknown platform, therefore // write about it to stdout and don't try to do anything further. func (tun *TunAdapter) setupAddress(addr string) error { - tun.core.log.Warnln("Platform not supported, you must set the address of", tun.iface.Name(), "to", addr) + tun.log.Warnln("Platform not supported, you must set the address of", tun.iface.Name(), "to", addr) return nil } diff --git a/src/tuntap/tun_windows.go b/src/tuntap/tun_windows.go index f5cebe5..8a66ac6 100644 --- a/src/tuntap/tun_windows.go +++ b/src/tuntap/tun_windows.go @@ -15,7 +15,7 @@ import ( // delegate the hard work to "netsh". func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { if !iftapmode { - tun.core.log.Warnln("TUN mode is not supported on this platform, defaulting to TAP") + tun.log.Warnln("TUN mode is not supported on this platform, defaulting to TAP") } config := water.Config{DeviceType: water.TAP} config.PlatformSpecificParams.ComponentID = "tap0901" @@ -31,19 +31,19 @@ func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int } // Disable/enable the interface to resets its configuration (invalidating iface) cmd := exec.Command("netsh", "interface", "set", "interface", iface.Name(), "admin=DISABLED") - tun.core.log.Printf("netsh command: %v", strings.Join(cmd.Args, " ")) + tun.log.Printf("netsh command: %v", strings.Join(cmd.Args, " ")) output, err := cmd.CombinedOutput() if err != nil { - tun.core.log.Errorf("Windows netsh failed: %v.", err) - tun.core.log.Traceln(string(output)) + tun.log.Errorf("Windows netsh failed: %v.", err) + tun.log.Traceln(string(output)) return err } cmd = exec.Command("netsh", "interface", "set", "interface", iface.Name(), "admin=ENABLED") - tun.core.log.Printf("netsh command: %v", strings.Join(cmd.Args, " ")) + tun.log.Printf("netsh command: %v", strings.Join(cmd.Args, " ")) output, err = cmd.CombinedOutput() if err != nil { - tun.core.log.Errorf("Windows netsh failed: %v.", err) - tun.core.log.Traceln(string(output)) + tun.log.Errorf("Windows netsh failed: %v.", err) + tun.log.Traceln(string(output)) return err } // Get a new iface @@ -58,9 +58,9 @@ func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int panic(err) } // Friendly output - tun.core.log.Infof("Interface name: %s", tun.iface.Name()) - tun.core.log.Infof("Interface IPv6: %s", addr) - tun.core.log.Infof("Interface MTU: %d", tun.mtu) + tun.log.Infof("Interface name: %s", tun.iface.Name()) + tun.log.Infof("Interface IPv6: %s", addr) + tun.log.Infof("Interface MTU: %d", tun.mtu) return tun.setupAddress(addr) } @@ -71,11 +71,11 @@ func (tun *TunAdapter) setupMTU(mtu int) error { fmt.Sprintf("interface=%s", tun.iface.Name()), fmt.Sprintf("mtu=%d", mtu), "store=active") - tun.core.log.Debugln("netsh command: %v", strings.Join(cmd.Args, " ")) + tun.log.Debugln("netsh command: %v", strings.Join(cmd.Args, " ")) output, err := cmd.CombinedOutput() if err != nil { - tun.core.log.Errorf("Windows netsh failed: %v.", err) - tun.core.log.Traceln(string(output)) + tun.log.Errorf("Windows netsh failed: %v.", err) + tun.log.Traceln(string(output)) return err } return nil @@ -88,11 +88,11 @@ func (tun *TunAdapter) setupAddress(addr string) error { fmt.Sprintf("interface=%s", tun.iface.Name()), fmt.Sprintf("addr=%s", addr), "store=active") - tun.core.log.Debugln("netsh command: %v", strings.Join(cmd.Args, " ")) + tun.log.Debugln("netsh command: %v", strings.Join(cmd.Args, " ")) output, err := cmd.CombinedOutput() if err != nil { - tun.core.log.Errorf("Windows netsh failed: %v.", err) - tun.core.log.Traceln(string(output)) + tun.log.Errorf("Windows netsh failed: %v.", err) + tun.log.Traceln(string(output)) return err } return nil From 7ea4e9575e611192ec4b81b51dfc13e89e200e74 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 28 Mar 2019 16:13:14 +0000 Subject: [PATCH 05/19] Break out multicast into a separate package --- cmd/yggdrasil/main.go | 11 +++- src/{yggdrasil => multicast}/multicast.go | 63 +++++++++++-------- .../multicast_darwin.go | 8 +-- .../multicast_other.go | 6 +- .../multicast_unix.go | 6 +- .../multicast_windows.go | 6 +- src/yggdrasil/admin.go | 4 +- src/yggdrasil/core.go | 30 ++++++--- src/yggdrasil/mobile.go | 4 +- src/yggdrasil/tcp.go | 36 +++++------ 10 files changed, 103 insertions(+), 71 deletions(-) rename src/{yggdrasil => multicast}/multicast.go (78%) rename src/{yggdrasil => multicast}/multicast_darwin.go (86%) rename src/{yggdrasil => multicast}/multicast_other.go (53%) rename src/{yggdrasil => multicast}/multicast_unix.go (75%) rename src/{yggdrasil => multicast}/multicast_windows.go (75%) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index cec7705..fe84849 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -19,6 +19,7 @@ import ( "github.com/mitchellh/mapstructure" "github.com/yggdrasil-network/yggdrasil-go/src/config" + "github.com/yggdrasil-network/yggdrasil-go/src/multicast" "github.com/yggdrasil-network/yggdrasil-go/src/tuntap" "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil" ) @@ -27,8 +28,9 @@ type nodeConfig = config.NodeConfig type Core = yggdrasil.Core type node struct { - core Core - tun tuntap.TunAdapter + core Core + tun tuntap.TunAdapter + multicast multicast.Multicast } func readConfig(useconf *bool, useconffile *string, normaliseconf *bool) *nodeConfig { @@ -254,6 +256,11 @@ func main() { logger.Errorln("An error occurred during startup") panic(err) } + // Start the multicast interface + n.multicast.Init(&n.core, cfg, logger) + if err := n.multicast.Start(); err != nil { + logger.Errorln("An error occurred starting multicast:", err) + } // The Stop function ensures that the TUN/TAP adapter is correctly shut down // before the program exits. defer func() { diff --git a/src/yggdrasil/multicast.go b/src/multicast/multicast.go similarity index 78% rename from src/yggdrasil/multicast.go rename to src/multicast/multicast.go index ab1b158..71bdbc8 100644 --- a/src/yggdrasil/multicast.go +++ b/src/multicast/multicast.go @@ -1,4 +1,4 @@ -package yggdrasil +package multicast import ( "context" @@ -7,23 +7,31 @@ import ( "regexp" "time" + "github.com/gologme/log" + + "github.com/yggdrasil-network/yggdrasil-go/src/config" + "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil" "golang.org/x/net/ipv6" ) -type multicast struct { - core *Core +type Multicast struct { + core *yggdrasil.Core + config *config.NodeConfig + log *log.Logger reconfigure chan chan error sock *ipv6.PacketConn groupAddr string - listeners map[string]*tcpListener + listeners map[string]*yggdrasil.TcpListener listenPort uint16 } -func (m *multicast) init(core *Core) { +func (m *Multicast) Init(core *yggdrasil.Core, config *config.NodeConfig, log *log.Logger) { m.core = core + m.config = config + m.log = log m.reconfigure = make(chan chan error, 1) - m.listeners = make(map[string]*tcpListener) - current, _ := m.core.config.Get() + m.listeners = make(map[string]*yggdrasil.TcpListener) + current := m.config //.Get() m.listenPort = current.LinkLocalTCPPort go func() { for { @@ -34,15 +42,15 @@ func (m *multicast) init(core *Core) { m.groupAddr = "[ff02::114]:9001" // Check if we've been given any expressions if count := len(m.interfaces()); count != 0 { - m.core.log.Infoln("Found", count, "multicast interface(s)") + m.log.Infoln("Found", count, "multicast interface(s)") } } -func (m *multicast) start() error { +func (m *Multicast) Start() error { if len(m.interfaces()) == 0 { - m.core.log.Infoln("Multicast discovery is disabled") + m.log.Infoln("Multicast discovery is disabled") } else { - m.core.log.Infoln("Multicast discovery is enabled") + m.log.Infoln("Multicast discovery is enabled") addr, err := net.ResolveUDPAddr("udp", m.groupAddr) if err != nil { return err @@ -67,9 +75,10 @@ func (m *multicast) start() error { return nil } -func (m *multicast) interfaces() map[string]net.Interface { +func (m *Multicast) interfaces() map[string]net.Interface { // Get interface expressions from config - current, _ := m.core.config.Get() + //current, _ := m.config.Get() + current := m.config exprs := current.MulticastInterfaces // Ask the system for network interfaces interfaces := make(map[string]net.Interface) @@ -106,7 +115,7 @@ func (m *multicast) interfaces() map[string]net.Interface { return interfaces } -func (m *multicast) announce() { +func (m *Multicast) announce() { groupAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr) if err != nil { panic(err) @@ -122,9 +131,9 @@ func (m *multicast) announce() { for name, listener := range m.listeners { // Prepare our stop function! stop := func() { - listener.stop <- true + listener.Stop <- true delete(m.listeners, name) - m.core.log.Debugln("No longer multicasting on", name) + m.log.Debugln("No longer multicasting on", name) } // If the interface is no longer visible on the system then stop the // listener, as another one will be started further down @@ -135,7 +144,7 @@ func (m *multicast) announce() { // It's possible that the link-local listener address has changed so if // that is the case then we should clean up the interface listener found := false - listenaddr, err := net.ResolveTCPAddr("tcp6", listener.listener.Addr().String()) + listenaddr, err := net.ResolveTCPAddr("tcp6", listener.Listener.Addr().String()) if err != nil { stop() continue @@ -184,17 +193,18 @@ func (m *multicast) announce() { // Join the multicast group m.sock.JoinGroup(&iface, groupAddr) // Try and see if we already have a TCP listener for this interface - var listener *tcpListener - if l, ok := m.listeners[iface.Name]; !ok || l.listener == nil { + var listener *yggdrasil.TcpListener + if l, ok := m.listeners[iface.Name]; !ok || l.Listener == nil { // No listener was found - let's create one listenaddr := fmt.Sprintf("[%s%%%s]:%d", addrIP, iface.Name, m.listenPort) - if li, err := m.core.link.tcp.listen(listenaddr); err == nil { - m.core.log.Debugln("Started multicasting on", iface.Name) + //if li, err := m.core.link.tcp.listen(listenaddr); err == nil { + if li, err := m.core.ListenTCP(listenaddr); err == nil { + m.log.Debugln("Started multicasting on", iface.Name) // Store the listener so that we can stop it later if needed m.listeners[iface.Name] = li listener = li } else { - m.core.log.Warnln("Not multicasting on", iface.Name, "due to error:", err) + m.log.Warnln("Not multicasting on", iface.Name, "due to error:", err) } } else { // An existing listener was found @@ -205,7 +215,7 @@ func (m *multicast) announce() { continue } // Get the listener details and construct the multicast beacon - lladdr := listener.listener.Addr().String() + lladdr := listener.Listener.Addr().String() if a, err := net.ResolveTCPAddr("tcp6", lladdr); err == nil { a.Zone = "" destAddr.Zone = iface.Name @@ -219,7 +229,7 @@ func (m *multicast) announce() { } } -func (m *multicast) listen() { +func (m *Multicast) listen() { groupAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr) if err != nil { panic(err) @@ -251,8 +261,9 @@ func (m *multicast) listen() { continue } addr.Zone = "" - if err := m.core.link.call("tcp://"+addr.String(), from.Zone); err != nil { - m.core.log.Debugln("Call from multicast failed:", err) + //if err := m.core.link.call("tcp://"+addr.String(), from.Zone); err != nil { + if err := m.core.CallPeer("tcp://"+addr.String(), from.Zone); err != nil { + m.log.Debugln("Call from multicast failed:", err) } } } diff --git a/src/yggdrasil/multicast_darwin.go b/src/multicast/multicast_darwin.go similarity index 86% rename from src/yggdrasil/multicast_darwin.go rename to src/multicast/multicast_darwin.go index 5364611..900354c 100644 --- a/src/yggdrasil/multicast_darwin.go +++ b/src/multicast/multicast_darwin.go @@ -1,6 +1,6 @@ // +build darwin -package yggdrasil +package multicast /* #cgo CFLAGS: -x objective-c @@ -31,11 +31,11 @@ import ( var awdlGoroutineStarted bool -func (m *multicast) multicastStarted() { +func (m *Multicast) multicastStarted() { if awdlGoroutineStarted { return } - m.core.log.Infoln("Multicast discovery will wake up AWDL if required") + m.log.Infoln("Multicast discovery will wake up AWDL if required") awdlGoroutineStarted = true for { C.StopAWDLBrowsing() @@ -49,7 +49,7 @@ func (m *multicast) multicastStarted() { } } -func (m *multicast) multicastReuse(network string, address string, c syscall.RawConn) error { +func (m *Multicast) multicastReuse(network string, address string, c syscall.RawConn) error { var control error var reuseport error var recvanyif error diff --git a/src/yggdrasil/multicast_other.go b/src/multicast/multicast_other.go similarity index 53% rename from src/yggdrasil/multicast_other.go rename to src/multicast/multicast_other.go index e20bbda..16ea15d 100644 --- a/src/yggdrasil/multicast_other.go +++ b/src/multicast/multicast_other.go @@ -1,13 +1,13 @@ // +build !linux,!darwin,!netbsd,!freebsd,!openbsd,!dragonflybsd,!windows -package yggdrasil +package multicast import "syscall" -func (m *multicast) multicastStarted() { +func (m *Multicast) multicastStarted() { } -func (m *multicast) multicastReuse(network string, address string, c syscall.RawConn) error { +func (m *Multicast) multicastReuse(network string, address string, c syscall.RawConn) error { return nil } diff --git a/src/yggdrasil/multicast_unix.go b/src/multicast/multicast_unix.go similarity index 75% rename from src/yggdrasil/multicast_unix.go rename to src/multicast/multicast_unix.go index 3da1ab4..9d6a01a 100644 --- a/src/yggdrasil/multicast_unix.go +++ b/src/multicast/multicast_unix.go @@ -1,15 +1,15 @@ // +build linux netbsd freebsd openbsd dragonflybsd -package yggdrasil +package multicast import "syscall" import "golang.org/x/sys/unix" -func (m *multicast) multicastStarted() { +func (m *Multicast) multicastStarted() { } -func (m *multicast) multicastReuse(network string, address string, c syscall.RawConn) error { +func (m *Multicast) multicastReuse(network string, address string, c syscall.RawConn) error { var control error var reuseport error diff --git a/src/yggdrasil/multicast_windows.go b/src/multicast/multicast_windows.go similarity index 75% rename from src/yggdrasil/multicast_windows.go rename to src/multicast/multicast_windows.go index 3e07f6c..7a846b1 100644 --- a/src/yggdrasil/multicast_windows.go +++ b/src/multicast/multicast_windows.go @@ -1,15 +1,15 @@ // +build windows -package yggdrasil +package multicast import "syscall" import "golang.org/x/sys/windows" -func (m *multicast) multicastStarted() { +func (m *Multicast) multicastStarted() { } -func (m *multicast) multicastReuse(network string, address string, c syscall.RawConn) error { +func (m *Multicast) multicastReuse(network string, address string, c syscall.RawConn) error { var control error var reuseaddr error diff --git a/src/yggdrasil/admin.go b/src/yggdrasil/admin.go index 002f974..2db7ad4 100644 --- a/src/yggdrasil/admin.go +++ b/src/yggdrasil/admin.go @@ -209,13 +209,13 @@ func (a *admin) init(c *Core) { }, nil } })*/ - a.addHandler("getMulticastInterfaces", []string{}, func(in admin_info) (admin_info, error) { + /*a.addHandler("getMulticastInterfaces", []string{}, func(in admin_info) (admin_info, error) { var intfs []string for _, v := range a.core.multicast.interfaces() { intfs = append(intfs, v.Name) } return admin_info{"multicast_interfaces": intfs}, nil - }) + })*/ a.addHandler("getAllowedEncryptionPublicKeys", []string{}, func(in admin_info) (admin_info, error) { return admin_info{"allowed_box_pubs": a.getAllowedEncryptionPublicKeys()}, nil }) diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index a583d58..461e8e9 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -40,9 +40,9 @@ type Core struct { dht dht admin admin searches searches - multicast multicast - link link - log *log.Logger + //multicast multicast + link link + log *log.Logger } func (c *Core) init() error { @@ -82,7 +82,7 @@ func (c *Core) init() error { c.searches.init(c) c.dht.init(c) c.sessions.init(c) - c.multicast.init(c) + //c.multicast.init(c) c.peers.init(c) c.router.init(c) c.switchTable.init(c) // TODO move before peers? before router? @@ -137,7 +137,7 @@ func (c *Core) UpdateConfig(config *config.NodeConfig) { c.router.cryptokey.reconfigure, c.switchTable.reconfigure, c.link.reconfigure, - c.multicast.reconfigure, + //c.multicast.reconfigure, } for _, component := range components { @@ -228,10 +228,10 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error { return err } - if err := c.multicast.start(); err != nil { + /*if err := c.multicast.start(); err != nil { c.log.Errorln("Failed to start multicast interface") return err - } + }*/ if err := c.router.tun.Start(c.router.addr, c.router.subnet); err != nil { c.log.Errorln("Failed to start TUN/TAP") @@ -251,6 +251,11 @@ func (c *Core) Stop() { c.admin.close() } +// ListenOn starts a new listener +func (c *Core) ListenTCP(uri string) (*TcpListener, error) { + return c.link.tcp.listen(uri) +} + // 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() (*crypto.BoxPubKey, *crypto.BoxPrivKey) { @@ -303,11 +308,20 @@ func (c *Core) SetLogger(log *log.Logger) { } // 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 +// tcp://a.b.c.d:e, udp://a.b.c.d:e, socks://a.b.c.d:e/f.g.h.i:j. This adds the +// peer to the peer list, so that they will be called again if the connection +// drops. func (c *Core) AddPeer(addr string, sintf string) error { return c.admin.addPeer(addr, sintf) } +// Calls 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. This calls the +// peer once, and if the connection drops, it won't be called again. +func (c *Core) CallPeer(addr string, sintf string) error { + return c.link.call(addr, sintf) +} + // 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 { diff --git a/src/yggdrasil/mobile.go b/src/yggdrasil/mobile.go index 81aa47f..bad1424 100644 --- a/src/yggdrasil/mobile.go +++ b/src/yggdrasil/mobile.go @@ -115,7 +115,7 @@ func (c *Core) GetSigPubKeyString() string { // dummy adapter in place of real TUN - when this call returns a packet, you // will probably want to give it to the OS to write to TUN. func (c *Core) RouterRecvPacket() ([]byte, error) { - packet := <-c.router.tun.recv + packet := <-c.router.tun.Recv return packet, nil } @@ -125,6 +125,6 @@ func (c *Core) RouterRecvPacket() ([]byte, error) { // Yggdrasil. func (c *Core) RouterSendPacket(buf []byte) error { packet := append(util.GetBytes(), buf[:]...) - c.router.tun.send <- packet + c.router.tun.Send <- packet return nil } diff --git a/src/yggdrasil/tcp.go b/src/yggdrasil/tcp.go index f25ac41..b9681fc 100644 --- a/src/yggdrasil/tcp.go +++ b/src/yggdrasil/tcp.go @@ -36,14 +36,14 @@ type tcp struct { link *link reconfigure chan chan error mutex sync.Mutex // Protecting the below - listeners map[string]*tcpListener + listeners map[string]*TcpListener calls map[string]struct{} conns map[linkInfo](chan struct{}) } -type tcpListener struct { - listener net.Listener - stop chan bool +type TcpListener struct { + Listener net.Listener + Stop chan bool } // Wrapper function to set additional options for specific connection types. @@ -64,7 +64,7 @@ func (t *tcp) getAddr() *net.TCPAddr { t.mutex.Lock() defer t.mutex.Unlock() for _, l := range t.listeners { - return l.listener.Addr().(*net.TCPAddr) + return l.Listener.Addr().(*net.TCPAddr) } return nil } @@ -76,7 +76,7 @@ func (t *tcp) init(l *link) error { t.mutex.Lock() t.calls = make(map[string]struct{}) t.conns = make(map[linkInfo](chan struct{})) - t.listeners = make(map[string]*tcpListener) + t.listeners = make(map[string]*TcpListener) t.mutex.Unlock() go func() { @@ -103,7 +103,7 @@ func (t *tcp) init(l *link) error { t.mutex.Lock() if listener, ok := t.listeners[d[6:]]; ok { t.mutex.Unlock() - listener.stop <- true + listener.Stop <- true } else { t.mutex.Unlock() } @@ -129,7 +129,7 @@ func (t *tcp) init(l *link) error { return nil } -func (t *tcp) listen(listenaddr string) (*tcpListener, error) { +func (t *tcp) listen(listenaddr string) (*TcpListener, error) { var err error ctx := context.Background() @@ -138,9 +138,9 @@ func (t *tcp) listen(listenaddr string) (*tcpListener, error) { } listener, err := lc.Listen(ctx, "tcp", listenaddr) if err == nil { - l := tcpListener{ - listener: listener, - stop: make(chan bool), + l := TcpListener{ + Listener: listener, + Stop: make(chan bool), } go t.listener(&l, listenaddr) return &l, nil @@ -150,7 +150,7 @@ func (t *tcp) listen(listenaddr string) (*tcpListener, error) { } // Runs the listener, which spawns off goroutines for incoming connections. -func (t *tcp) listener(l *tcpListener, listenaddr string) { +func (t *tcp) listener(l *TcpListener, listenaddr string) { if l == nil { return } @@ -158,7 +158,7 @@ func (t *tcp) listener(l *tcpListener, listenaddr string) { t.mutex.Lock() if _, isIn := t.listeners[listenaddr]; isIn { t.mutex.Unlock() - l.listener.Close() + l.Listener.Close() return } else { t.listeners[listenaddr] = l @@ -167,20 +167,20 @@ func (t *tcp) listener(l *tcpListener, listenaddr string) { // And here we go! accepted := make(chan bool) defer func() { - t.link.core.log.Infoln("Stopping TCP listener on:", l.listener.Addr().String()) - l.listener.Close() + t.link.core.log.Infoln("Stopping TCP listener on:", l.Listener.Addr().String()) + l.Listener.Close() t.mutex.Lock() delete(t.listeners, listenaddr) t.mutex.Unlock() }() - t.link.core.log.Infoln("Listening for TCP on:", l.listener.Addr().String()) + t.link.core.log.Infoln("Listening for TCP on:", l.Listener.Addr().String()) for { var sock net.Conn var err error // Listen in a separate goroutine, as that way it does not block us from // receiving "stop" events go func() { - sock, err = l.listener.Accept() + sock, err = l.Listener.Accept() accepted <- true }() // Wait for either an accepted connection, or a message telling us to stop @@ -192,7 +192,7 @@ func (t *tcp) listener(l *tcpListener, listenaddr string) { return } go t.handler(sock, true, nil) - case <-l.stop: + case <-l.Stop: return } } From fd0b614f9c0780e0b85a2ae77174050524ab3d61 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 28 Mar 2019 18:03:14 +0000 Subject: [PATCH 06/19] Temporarily disable debug CircleCI builds as I don't know how badly I've broken the sim with this PR --- .circleci/config.yml | 10 +++++----- src/yggdrasil/core.go | 12 ++---------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 99088d1..9cf7d95 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -24,11 +24,11 @@ jobs: command: | sudo apt-get install -y alien - - run: - name: Test debug builds - command: | - ./build -d - test -f yggdrasil && test -f yggdrasilctl + # - run: + # name: Test debug builds + # command: | + # ./build -d + # test -f yggdrasil && test -f yggdrasilctl - run: name: Build for Linux (including Debian packages and RPMs) diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index 461e8e9..5d45a48 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -40,9 +40,8 @@ type Core struct { dht dht admin admin searches searches - //multicast multicast - link link - log *log.Logger + link link + log *log.Logger } func (c *Core) init() error { @@ -133,11 +132,9 @@ func (c *Core) UpdateConfig(config *config.NodeConfig) { c.sessions.reconfigure, c.peers.reconfigure, c.router.reconfigure, - //c.router.tun.Reconfigure, c.router.cryptokey.reconfigure, c.switchTable.reconfigure, c.link.reconfigure, - //c.multicast.reconfigure, } for _, component := range components { @@ -228,11 +225,6 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error { return err } - /*if err := c.multicast.start(); err != nil { - c.log.Errorln("Failed to start multicast interface") - return err - }*/ - if err := c.router.tun.Start(c.router.addr, c.router.subnet); err != nil { c.log.Errorln("Failed to start TUN/TAP") return err From dd05a7f2a816df8eecc5f50950097908f28b9d69 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 28 Mar 2019 19:09:19 +0000 Subject: [PATCH 07/19] Tweaks --- cmd/yggdrasil/main.go | 9 +++++---- src/multicast/multicast.go | 18 ++++++++++-------- src/yggdrasil/core.go | 35 ++++++++++++++++++----------------- src/yggdrasil/router.go | 30 +++++++++++++++--------------- src/yggdrasil/session.go | 2 +- 5 files changed, 49 insertions(+), 45 deletions(-) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index fe84849..72f0284 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -29,7 +29,7 @@ type Core = yggdrasil.Core type node struct { core Core - tun tuntap.TunAdapter + tuntap tuntap.TunAdapter multicast multicast.Multicast } @@ -251,13 +251,14 @@ func main() { // Now that we have a working configuration, 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. - n.core.SetRouterAdapter(&n.tun) - if err := n.core.Start(cfg, logger); err != nil { + n.core.SetRouterAdapter(&n.tuntap) + state, err := n.core.Start(cfg, logger) + if err != nil { logger.Errorln("An error occurred during startup") panic(err) } // Start the multicast interface - n.multicast.Init(&n.core, cfg, logger) + n.multicast.Init(&n.core, state, logger, nil) if err := n.multicast.Start(); err != nil { logger.Errorln("An error occurred starting multicast:", err) } diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index 71bdbc8..c675680 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -16,7 +16,7 @@ import ( type Multicast struct { core *yggdrasil.Core - config *config.NodeConfig + config *config.NodeState log *log.Logger reconfigure chan chan error sock *ipv6.PacketConn @@ -25,13 +25,13 @@ type Multicast struct { listenPort uint16 } -func (m *Multicast) Init(core *yggdrasil.Core, config *config.NodeConfig, log *log.Logger) { +func (m *Multicast) Init(core *yggdrasil.Core, state *config.NodeState, log *log.Logger, options interface{}) error { m.core = core - m.config = config + m.config = state m.log = log m.reconfigure = make(chan chan error, 1) m.listeners = make(map[string]*yggdrasil.TcpListener) - current := m.config //.Get() + current, _ := m.config.Get() m.listenPort = current.LinkLocalTCPPort go func() { for { @@ -44,6 +44,7 @@ func (m *Multicast) Init(core *yggdrasil.Core, config *config.NodeConfig, log *l if count := len(m.interfaces()); count != 0 { m.log.Infoln("Found", count, "multicast interface(s)") } + return nil } func (m *Multicast) Start() error { @@ -75,10 +76,13 @@ func (m *Multicast) Start() error { return nil } +func (m *Multicast) Stop() error { + return nil +} + func (m *Multicast) interfaces() map[string]net.Interface { // Get interface expressions from config - //current, _ := m.config.Get() - current := m.config + current, _ := m.config.Get() exprs := current.MulticastInterfaces // Ask the system for network interfaces interfaces := make(map[string]net.Interface) @@ -197,7 +201,6 @@ func (m *Multicast) announce() { if l, ok := m.listeners[iface.Name]; !ok || l.Listener == nil { // No listener was found - let's create one listenaddr := fmt.Sprintf("[%s%%%s]:%d", addrIP, iface.Name, m.listenPort) - //if li, err := m.core.link.tcp.listen(listenaddr); err == nil { if li, err := m.core.ListenTCP(listenaddr); err == nil { m.log.Debugln("Started multicasting on", iface.Name) // Store the listener so that we can stop it later if needed @@ -261,7 +264,6 @@ func (m *Multicast) listen() { continue } addr.Zone = "" - //if err := m.core.link.call("tcp://"+addr.String(), from.Zone); err != nil { if err := m.core.CallPeer("tcp://"+addr.String(), from.Zone); err != nil { m.log.Debugln("Call from multicast failed:", err) } diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index 5d45a48..dbc893a 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -17,11 +17,6 @@ import ( var buildName string var buildVersion string -type module interface { - init(*Core, *config.NodeConfig) error - start() error -} - // The Core object represents the Yggdrasil node. You should create a Core // object for each Yggdrasil node you plan to run. type Core struct { @@ -173,14 +168,14 @@ func GetBuildVersion() string { // Set the router adapter func (c *Core) SetRouterAdapter(adapter adapterImplementation) { - c.router.tun = adapter + c.router.adapter = adapter } // Starts up Yggdrasil using the provided NodeState, 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 { +func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) (*config.NodeState, error) { c.log = log c.config = config.NodeState{ @@ -201,7 +196,7 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error { if err := c.link.init(c); err != nil { c.log.Errorln("Failed to start link interfaces") - return err + return nil, err } c.config.Mutex.RLock() @@ -212,34 +207,34 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error { if err := c.switchTable.start(); err != nil { c.log.Errorln("Failed to start switch") - return err + return nil, err } if err := c.router.start(); err != nil { c.log.Errorln("Failed to start router") - return err + return nil, err } if err := c.admin.start(); err != nil { c.log.Errorln("Failed to start admin socket") - return err + return nil, err } - if err := c.router.tun.Start(c.router.addr, c.router.subnet); err != nil { + if err := c.router.adapter.Start(c.router.addr, c.router.subnet); err != nil { c.log.Errorln("Failed to start TUN/TAP") - return err + return nil, err } go c.addPeerLoop() c.log.Infoln("Startup complete") - return nil + return &c.config, nil } // Stops the Yggdrasil node. func (c *Core) Stop() { c.log.Infoln("Stopping...") - c.router.tun.Close() + c.router.adapter.Close() c.admin.close() } @@ -283,6 +278,12 @@ func (c *Core) GetSubnet() *net.IPNet { return &net.IPNet{IP: subnet, Mask: net.CIDRMask(64, 128)} } +// GetRouterAddresses returns the raw address and subnet types as used by the +// router +func (c *Core) GetRouterAddresses() (address.Address, address.Subnet) { + return c.router.addr, c.router.subnet +} + // Gets the nodeinfo. func (c *Core) GetNodeInfo() nodeinfoPayload { return c.router.nodeinfo.getNodeInfo() @@ -350,11 +351,11 @@ func (c *Core) GetTUNDefaultIfTAPMode() bool { // Gets the current TUN/TAP interface name. func (c *Core) GetTUNIfName() string { //return c.router.tun.iface.Name() - return c.router.tun.Name() + return c.router.adapter.Name() } // Gets the current TUN/TAP interface MTU. func (c *Core) GetTUNIfMTU() int { //return c.router.tun.mtu - return c.router.tun.MTU() + return c.router.adapter.MTU() } diff --git a/src/yggdrasil/router.go b/src/yggdrasil/router.go index aa2cd54..6314cb1 100644 --- a/src/yggdrasil/router.go +++ b/src/yggdrasil/router.go @@ -5,7 +5,7 @@ package yggdrasil // TODO clean up old/unused code, maybe improve comments on whatever is left // Send: -// Receive a packet from the tun +// Receive a packet from the adapter // Look up session (if none exists, trigger a search) // Hand off to session (which encrypts, etc) // Session will pass it back to router.out, which hands it off to the self peer @@ -20,7 +20,7 @@ package yggdrasil // If it's dht/seach/etc. traffic, the router passes it to that part // If it's an encapsulated IPv6 packet, the router looks up the session for it // The packet is passed to the session, which decrypts it, router.recvPacket -// The router then runs some sanity checks before passing it to the tun +// The router then runs some sanity checks before passing it to the adapter import ( "bytes" @@ -31,7 +31,7 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/util" ) -// The router struct has channels to/from the tun/tap device and a self peer (0), which is how messages are passed between this node and the peers/switch layer. +// The router struct has channels to/from the adapter device and a self peer (0), which is how messages are passed between this node and the peers/switch layer. // The router's mainLoop goroutine is responsible for managing all information related to the dht, searches, and crypto sessions. type router struct { core *Core @@ -41,17 +41,17 @@ type router struct { in <-chan []byte // packets we received from the network, link to peer's "out" out func([]byte) // packets we're sending to the network, link to peer's "in" toRecv chan router_recvPacket // packets to handle via recvPacket() - tun adapterImplementation // TUN/TAP adapter - recv chan<- []byte // place where the tun pulls received packets from - send <-chan []byte // place where the tun puts outgoing packets - reject chan<- RejectedPacket // place where we send error packets back to tun + adapter adapterImplementation // TUN/TAP adapter + recv chan<- []byte // place where the adapter pulls received packets from + send <-chan []byte // place where the adapter puts outgoing packets + reject chan<- RejectedPacket // place where we send error packets back to adapter reset chan struct{} // signal that coords changed (re-init sessions/dht) admin chan func() // pass a lambda for the admin socket to query stuff cryptokey cryptokey nodeinfo nodeinfo } -// Packet and session info, used to check that the packet matches a valid IP range or CKR prefix before sending to the tun. +// Packet and session info, used to check that the packet matches a valid IP range or CKR prefix before sending to the adapter. type router_recvPacket struct { bs []byte sinfo *sessionInfo @@ -70,7 +70,7 @@ type RejectedPacket struct { Detail interface{} } -// Initializes the router struct, which includes setting up channels to/from the tun/tap. +// Initializes the router struct, which includes setting up channels to/from the adapter. func (r *router) init(core *Core) { r.core = core r.reconfigure = make(chan chan error, 1) @@ -128,7 +128,7 @@ func (r *router) init(core *Core) { r.nodeinfo.setNodeInfo(r.core.config.Current.NodeInfo, r.core.config.Current.NodeInfoPrivacy) r.core.config.Mutex.RUnlock() r.cryptokey.init(r.core) - r.tun.Init(&r.core.config, r.core.log, send, recv, reject) + r.adapter.Init(&r.core.config, r.core.log, send, recv, reject) } // Starts the mainLoop goroutine. @@ -138,7 +138,7 @@ func (r *router) start() error { return nil } -// Takes traffic from the tun/tap and passes it to router.send, or from r.in and handles incoming traffic. +// Takes traffic from the adapter and passes it to router.send, or from r.in and handles incoming traffic. // Also adds new peer info to the DHT. // Also resets the DHT and sesssions in the event of a coord change. // Also does periodic maintenance stuff. @@ -179,7 +179,7 @@ func (r *router) mainLoop() { // If a session to the destination exists, gets the session and passes the packet to it. // If no session exists, it triggers (or continues) a search. // If the session hasn't responded recently, it triggers a ping or search to keep things alive or deal with broken coords *relatively* quickly. -// It also deals with oversized packets if there are MTU issues by calling into icmpv6.go to spoof PacketTooBig traffic, or DestinationUnreachable if the other side has their tun/tap disabled. +// It also deals with oversized packets if there are MTU issues by calling into icmpv6.go to spoof PacketTooBig traffic, or DestinationUnreachable if the other side has their adapter disabled. func (r *router) sendPacket(bs []byte) { var sourceAddr address.Address var destAddr address.Address @@ -339,7 +339,7 @@ func (r *router) sendPacket(bs []byte) { } // Called for incoming traffic by the session worker for that connection. -// Checks that the IP address is correct (matches the session) and passes the packet to the tun/tap. +// Checks that the IP address is correct (matches the session) and passes the packet to the adapter. func (r *router) recvPacket(bs []byte, sinfo *sessionInfo) { // Note: called directly by the session worker, not the router goroutine if len(bs) < 24 { @@ -402,7 +402,7 @@ func (r *router) handleIn(packet []byte) { } // Handles incoming traffic, i.e. encapuslated ordinary IPv6 packets. -// Passes them to the crypto session worker to be decrypted and sent to the tun/tap. +// Passes them to the crypto session worker to be decrypted and sent to the adapter. func (r *router) handleTraffic(packet []byte) { defer util.PutBytes(packet) p := wire_trafficPacket{} @@ -436,7 +436,7 @@ func (r *router) handleProto(packet []byte) { return } // Now do something with the bytes in bs... - // send dht messages to dht, sessionRefresh to sessions, data to tun... + // send dht messages to dht, sessionRefresh to sessions, data to adapter... // For data, should check that key and IP match... bsType, bsTypeLen := wire_decode_uint64(bs) if bsTypeLen == 0 { diff --git a/src/yggdrasil/session.go b/src/yggdrasil/session.go index b3563e0..8deff95 100644 --- a/src/yggdrasil/session.go +++ b/src/yggdrasil/session.go @@ -277,7 +277,7 @@ func (ss *sessions) createSession(theirPermKey *crypto.BoxPubKey) *sessionInfo { sinfo.mySesPriv = *priv sinfo.myNonce = *crypto.NewBoxNonce() sinfo.theirMTU = 1280 - sinfo.myMTU = uint16(ss.core.router.tun.MTU()) + sinfo.myMTU = uint16(ss.core.router.adapter.MTU()) now := time.Now() sinfo.time = now sinfo.mtuTime = now From a8305210786cce91bfca5b61214f5b6a173c620c Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 29 Mar 2019 08:38:09 +0000 Subject: [PATCH 08/19] Don't crash if Yggdrasil is started with no router adapter --- cmd/yggdrasil/main.go | 6 +++--- src/yggdrasil/core.go | 12 ++++++++---- src/yggdrasil/router.go | 4 +++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 72f0284..9278867 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -248,10 +248,10 @@ func main() { // Setup the Yggdrasil node itself. The node{} type includes a Core, so we // don't need to create this manually. n := node{} - // Now that we have a working configuration, 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. + // Before we start the node, set the TUN/TAP to be our router adapter n.core.SetRouterAdapter(&n.tuntap) + // Now start Yggdrasil - this starts the DHT, router, switch and other core + // components needed for Yggdrasil to operate state, err := n.core.Start(cfg, logger) if err != nil { logger.Errorln("An error occurred during startup") diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index dbc893a..0e9b251 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -220,9 +220,11 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) (*config.NodeState, return nil, err } - if err := c.router.adapter.Start(c.router.addr, c.router.subnet); err != nil { - c.log.Errorln("Failed to start TUN/TAP") - return nil, err + if c.router.adapter != nil { + if err := c.router.adapter.Start(c.router.addr, c.router.subnet); err != nil { + c.log.Errorln("Failed to start TUN/TAP") + return nil, err + } } go c.addPeerLoop() @@ -234,7 +236,9 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) (*config.NodeState, // Stops the Yggdrasil node. func (c *Core) Stop() { c.log.Infoln("Stopping...") - c.router.adapter.Close() + if c.router.adapter != nil { + c.router.adapter.Close() + } c.admin.close() } diff --git a/src/yggdrasil/router.go b/src/yggdrasil/router.go index 6314cb1..bef564f 100644 --- a/src/yggdrasil/router.go +++ b/src/yggdrasil/router.go @@ -128,7 +128,9 @@ func (r *router) init(core *Core) { r.nodeinfo.setNodeInfo(r.core.config.Current.NodeInfo, r.core.config.Current.NodeInfoPrivacy) r.core.config.Mutex.RUnlock() r.cryptokey.init(r.core) - r.adapter.Init(&r.core.config, r.core.log, send, recv, reject) + if r.adapter != nil { + r.adapter.Init(&r.core.config, r.core.log, send, recv, reject) + } } // Starts the mainLoop goroutine. From 399e1a2ffe1a375f64517152c336f6e54b9cb945 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 29 Mar 2019 08:58:30 +0000 Subject: [PATCH 09/19] Make AddPeer remember added peer (as opposed to CallPeer which does not) --- src/yggdrasil/core.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index 0e9b251..523ab5e 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -309,7 +309,17 @@ func (c *Core) SetLogger(log *log.Logger) { // peer to the peer list, so that they will be called again if the connection // drops. func (c *Core) AddPeer(addr string, sintf string) error { - return c.admin.addPeer(addr, sintf) + if err := c.CallPeer(addr, sintf); err != nil { + return err + } + c.config.Mutex.Lock() + if sintf == "" { + c.config.Current.Peers = append(c.config.Current.Peers, addr) + } else { + c.config.Current.InterfacePeers[sintf] = append(c.config.Current.InterfacePeers[sintf], addr) + } + c.config.Mutex.Unlock() + return nil } // Calls a peer. This should be specified in the peer URI format, i.e. From b5ac65cacbdc3e50d5059936af106e6634bdd963 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 29 Mar 2019 18:05:17 +0000 Subject: [PATCH 10/19] Rearrange public interface, godoc improvements --- src/tuntap/tun.go | 22 ++++++ src/yggdrasil/adapter.go | 18 +++-- src/yggdrasil/core.go | 154 ++++++++++++++++----------------------- src/yggdrasil/router.go | 2 +- 4 files changed, 99 insertions(+), 97 deletions(-) diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index f85d8bb..5a247bf 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -65,6 +65,28 @@ func (tun *TunAdapter) IsTAP() bool { return tun.iface.IsTAP() } +// Gets the default TUN/TAP interface name for your platform. +func DefaultName() string { + return defaults.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 DefaultMTU() int { + return defaults.GetDefaults().DefaultIfMTU +} + +// Gets the default TUN/TAP interface mode for your platform. +func DefaultIsTAP() bool { + return defaults.GetDefaults().DefaultIfTAPMode +} + +// 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 MaximumMTU() int { + return defaults.GetDefaults().MaximumIfMTU +} + // Initialises the TUN/TAP adapter. func (tun *TunAdapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte, reject <-chan yggdrasil.RejectedPacket) { tun.config = config diff --git a/src/yggdrasil/adapter.go b/src/yggdrasil/adapter.go index 6be3ef0..d373894 100644 --- a/src/yggdrasil/adapter.go +++ b/src/yggdrasil/adapter.go @@ -6,10 +6,12 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/config" ) -// Defines the minimum required struct members for an adapter type (this is -// now the base type for TunAdapter in tun.go) +// Defines the minimum required struct members for an adapter type. This is now +// the base type for adapters like tun.go. When implementing a new adapter type, +// you should extend the adapter struct with this one and should call the +// Adapter.Init() function when initialising. type Adapter struct { - adapterImplementation + AdapterImplementation Core *Core Send chan<- []byte Recv <-chan []byte @@ -17,8 +19,9 @@ type Adapter struct { Reconfigure chan chan error } -// Defines the minimum required functions for an adapter type -type adapterImplementation interface { +// Defines the minimum required functions for an adapter type. Note that the +// implementation of Init() should call Adapter.Init(). +type AdapterImplementation interface { Init(*config.NodeState, *log.Logger, chan<- []byte, <-chan []byte, <-chan RejectedPacket) Name() string MTU() int @@ -29,7 +32,10 @@ type adapterImplementation interface { Close() error } -// Initialises the adapter. +// Initialises the adapter with the necessary channels to operate from the +// router. When defining a new Adapter type, the Adapter should call this +// function from within it's own Init function to set up the channels. It is +// otherwise not expected for you to call this function directly. func (adapter *Adapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte, reject <-chan RejectedPacket) { log.Traceln("Adapter setup - given channels:", send, recv) adapter.Send = send diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index 523ab5e..8444050 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -11,7 +11,6 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/address" "github.com/yggdrasil-network/yggdrasil-go/src/config" "github.com/yggdrasil-network/yggdrasil-go/src/crypto" - "github.com/yggdrasil-network/yggdrasil-go/src/defaults" ) var buildName string @@ -89,7 +88,7 @@ func (c *Core) init() error { // be reconnected with. func (c *Core) addPeerLoop() { for { - // Get the peers from the config - these could change! + // the peers from the config - these could change! current, _ := c.config.Get() // Add peers from the Peers section @@ -111,8 +110,9 @@ func (c *Core) addPeerLoop() { } } -// UpdateConfig updates the configuration in Core and then signals the -// various module goroutines to reconfigure themselves if needed +// UpdateConfig updates the configuration in Core with the provided +// config.NodeConfig and then signals the various module goroutines to +// reconfigure themselves if needed. func (c *Core) UpdateConfig(config *config.NodeConfig) { c.log.Infoln("Reloading configuration...") @@ -148,33 +148,37 @@ func (c *Core) UpdateConfig(config *config.NodeConfig) { } } -// GetBuildName gets the current build name. This is usually injected if built +// BuildName gets the current build name. This is usually injected if built // from git, or returns "unknown" otherwise. -func GetBuildName() string { +func BuildName() string { if buildName == "" { return "unknown" } return buildName } -// Get the current build version. This is usually injected if built from git, -// or returns "unknown" otherwise. -func GetBuildVersion() string { +// BuildVersion gets the current build version. This is usually injected if +// built from git, or returns "unknown" otherwise. +func BuildVersion() string { if buildVersion == "" { return "unknown" } return buildVersion } -// Set the router adapter -func (c *Core) SetRouterAdapter(adapter adapterImplementation) { +// SetRouterAdapter instructs Yggdrasil to use the given adapter when starting +// the router. The adapter must implement the standard +// adapter.AdapterImplementation interface and should extend the adapter.Adapter +// struct. +func (c *Core) SetRouterAdapter(adapter AdapterImplementation) { c.router.adapter = adapter } -// Starts up Yggdrasil using the provided NodeState, 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. +// Start starts up Yggdrasil using the provided config.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. A config.NodeState is returned which contains both the +// current and previous configurations (from reconfigures). func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) (*config.NodeState, error) { c.log = log @@ -183,10 +187,10 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) (*config.NodeState, Previous: *nc, } - if name := GetBuildName(); name != "unknown" { + if name := BuildName(); name != "unknown" { c.log.Infoln("Build name:", name) } - if version := GetBuildVersion(); version != "unknown" { + if version := BuildVersion(); version != "unknown" { c.log.Infoln("Build version:", version) } @@ -233,7 +237,7 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) (*config.NodeState, return &c.config, nil } -// Stops the Yggdrasil node. +// Stop shuts down the Yggdrasil node. func (c *Core) Stop() { c.log.Infoln("Stopping...") if c.router.adapter != nil { @@ -242,72 +246,78 @@ func (c *Core) Stop() { c.admin.close() } -// ListenOn starts a new listener +// ListenTCP starts a new TCP listener. The input URI should match that of the +// "Listen" configuration item, e.g. +// tcp://a.b.c.d:e func (c *Core) ListenTCP(uri string) (*TcpListener, error) { return c.link.tcp.listen(uri) } -// Generates a new encryption keypair. The encryption keys are used to -// encrypt traffic and to derive the IPv6 address/subnet of the node. +// NewEncryptionKeys 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() (*crypto.BoxPubKey, *crypto.BoxPrivKey) { return crypto.NewBoxKeys() } -// Generates a new signing keypair. The signing keys are used to derive the -// structure of the spanning tree. +// NewSigningKeys generates a new signing keypair. The signing keys are used to +// derive the structure of the spanning tree. func (c *Core) NewSigningKeys() (*crypto.SigPubKey, *crypto.SigPrivKey) { return crypto.NewSigKeys() } -// Gets the node ID. -func (c *Core) GetNodeID() *crypto.NodeID { - return crypto.GetNodeID(&c.boxPub) +// NodeID gets the node ID. +func (c *Core) NodeID() *crypto.NodeID { + return crypto.NodeID(&c.boxPub) } -// Gets the tree ID. -func (c *Core) GetTreeID() *crypto.TreeID { - return crypto.GetTreeID(&c.sigPub) +// TreeID gets the tree ID. +func (c *Core) TreeID() *crypto.TreeID { + return crypto.TreeID(&c.sigPub) } -// 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())[:]) +// Address gets the IPv6 address of the Yggdrasil node. This is always a /128 +// address. +func (c *Core) Address() *net.IP { + address := net.IP(address.AddrForNodeID(c.NodeID())[:]) return &address } -// 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 gets the routed IPv6 subnet of the Yggdrasil node. This is always a +// /64 subnet. +func (c *Core) Subnet() *net.IPNet { + subnet := address.SubnetForNodeID(c.NodeID())[:] subnet = append(subnet, 0, 0, 0, 0, 0, 0, 0, 0) return &net.IPNet{IP: subnet, Mask: net.CIDRMask(64, 128)} } -// GetRouterAddresses returns the raw address and subnet types as used by the +// RouterAddresses returns the raw address and subnet types as used by the // router -func (c *Core) GetRouterAddresses() (address.Address, address.Subnet) { +func (c *Core) RouterAddresses() (address.Address, address.Subnet) { return c.router.addr, c.router.subnet } -// Gets the nodeinfo. -func (c *Core) GetNodeInfo() nodeinfoPayload { +// NodeInfo gets the currently configured nodeinfo. +func (c *Core) NodeInfo() nodeinfoPayload { return c.router.nodeinfo.getNodeInfo() } -// Sets the nodeinfo. +// SetNodeInfo the lcal nodeinfo. Note that nodeinfo can be any value or struct, +// it will be serialised into JSON automatically. func (c *Core) SetNodeInfo(nodeinfo interface{}, nodeinfoprivacy bool) { c.router.nodeinfo.setNodeInfo(nodeinfo, nodeinfoprivacy) } -// Sets the output logger of the Yggdrasil node after startup. This may be -// useful if you want to redirect the output later. +// SetLogger 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. This adds the -// peer to the peer list, so that they will be called again if the connection -// drops. +// AddPeer adds a peer. This should be specified in the peer URI format, e.g.: +// tcp://a.b.c.d:e +// socks://a.b.c.d:e/f.g.h.i:j +// This adds the peer to the peer list, so that they will be called again if the +// connection drops. func (c *Core) AddPeer(addr string, sintf string) error { if err := c.CallPeer(addr, sintf); err != nil { return err @@ -322,54 +332,18 @@ func (c *Core) AddPeer(addr string, sintf string) error { return nil } -// Calls 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. This calls the -// peer once, and if the connection drops, it won't be called again. +// CallPeer calls a peer once. This should be specified in the peer URI format, +// e.g.: +// tcp://a.b.c.d:e +// socks://a.b.c.d:e/f.g.h.i:j +// This does not add the peer to the peer list, so if the connection drops, the +// peer will not be called again automatically. func (c *Core) CallPeer(addr string, sintf string) error { return c.link.call(addr, sintf) } -// Adds an allowed public key. This allow peerings to be restricted only to -// keys that you have selected. +// AddAllowedEncryptionPublicKey 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 admin listen address for your platform. -func (c *Core) GetAdminDefaultListen() string { - return defaults.GetDefaults().DefaultAdminListen -} - -// Gets the default TUN/TAP interface name for your platform. -func (c *Core) GetTUNDefaultIfName() string { - return defaults.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 defaults.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 defaults.GetDefaults().MaximumIfMTU -} - -// Gets the default TUN/TAP interface mode for your platform. -func (c *Core) GetTUNDefaultIfTAPMode() bool { - return defaults.GetDefaults().DefaultIfTAPMode -} - -// Gets the current TUN/TAP interface name. -func (c *Core) GetTUNIfName() string { - //return c.router.tun.iface.Name() - return c.router.adapter.Name() -} - -// Gets the current TUN/TAP interface MTU. -func (c *Core) GetTUNIfMTU() int { - //return c.router.tun.mtu - return c.router.adapter.MTU() -} diff --git a/src/yggdrasil/router.go b/src/yggdrasil/router.go index bef564f..9130f55 100644 --- a/src/yggdrasil/router.go +++ b/src/yggdrasil/router.go @@ -41,7 +41,7 @@ type router struct { in <-chan []byte // packets we received from the network, link to peer's "out" out func([]byte) // packets we're sending to the network, link to peer's "in" toRecv chan router_recvPacket // packets to handle via recvPacket() - adapter adapterImplementation // TUN/TAP adapter + adapter AdapterImplementation // TUN/TAP adapter recv chan<- []byte // place where the adapter pulls received packets from send <-chan []byte // place where the adapter puts outgoing packets reject chan<- RejectedPacket // place where we send error packets back to adapter From f19a4e43982dc512a929d113daf51c6552981cff Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 29 Mar 2019 18:18:31 +0000 Subject: [PATCH 11/19] More godoc improvements --- src/multicast/multicast.go | 9 +++++++++ src/tuntap/tun.go | 35 ++++++++++++++++++++++------------- src/yggdrasil/router.go | 10 +++++++++- src/yggdrasil/tcp.go | 4 ++++ 4 files changed, 44 insertions(+), 14 deletions(-) diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index c675680..4e5bc4b 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -14,6 +14,10 @@ import ( "golang.org/x/net/ipv6" ) +// Multicast represents the multicast advertisement and discovery mechanism used +// by Yggdrasil to find peers on the same subnet. When a beacon is received on a +// configured multicast interface, Yggdrasil will attempt to peer with that node +// automatically. type Multicast struct { core *yggdrasil.Core config *config.NodeState @@ -25,6 +29,7 @@ type Multicast struct { listenPort uint16 } +// Init prepares the multicast interface for use. func (m *Multicast) Init(core *yggdrasil.Core, state *config.NodeState, log *log.Logger, options interface{}) error { m.core = core m.config = state @@ -47,6 +52,9 @@ func (m *Multicast) Init(core *yggdrasil.Core, state *config.NodeState, log *log return nil } +// Start starts the multicast interface. This launches goroutines which will +// listen for multicast beacons from other hosts and will advertise multicast +// beacons out to the network. func (m *Multicast) Start() error { if len(m.interfaces()) == 0 { m.log.Infoln("Multicast discovery is disabled") @@ -76,6 +84,7 @@ func (m *Multicast) Start() error { return nil } +// Stop is not implemented for multicast yet. func (m *Multicast) Stop() error { return nil } diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index 5a247bf..600d3d7 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -27,7 +27,10 @@ import ( const tun_IPv6_HEADER_LENGTH = 40 const tun_ETHER_HEADER_LENGTH = 14 -// Represents a running TUN/TAP interface. +// TunAdapter represents a running TUN/TAP interface and extends the +// yggdrasil.Adapter type. In order to use the TUN/TAP adapter with Yggdrasil, +// you should pass this object to the yggdrasil.SetRouterAdapter() function +// before calling yggdrasil.Start(). type TunAdapter struct { yggdrasil.Adapter addr address.Address @@ -50,44 +53,50 @@ func getSupportedMTU(mtu int) int { return mtu } -// Get the adapter name +// Name returns the name of the adapter, e.g. "tun0". On Windows, this may +// return a canonical adapter name instead. func (tun *TunAdapter) Name() string { return tun.iface.Name() } -// Get the adapter MTU +// MTU gets the adapter's MTU. This can range between 1280 and 65535, although +// the maximum value is determined by your platform. The returned value will +// never exceed that of MaximumMTU(). func (tun *TunAdapter) MTU() int { return getSupportedMTU(tun.mtu) } -// Get the adapter mode +// IsTAP returns true if the adapter is a TAP adapter (Layer 2) or false if it +// is a TUN adapter (Layer 3). func (tun *TunAdapter) IsTAP() bool { return tun.iface.IsTAP() } -// Gets the default TUN/TAP interface name for your platform. +// DefaultName gets the default TUN/TAP interface name for your platform. func DefaultName() string { return defaults.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. +// DefaultMTU gets the default TUN/TAP interface MTU for your platform. This can +// be as high as MaximumMTU(), depending on platform, but is never lower than 1280. func DefaultMTU() int { return defaults.GetDefaults().DefaultIfMTU } -// Gets the default TUN/TAP interface mode for your platform. +// DefaultIsTAP returns true if the default adapter mode for the current +// platform is TAP (Layer 2) and returns false for TUN (Layer 3). func DefaultIsTAP() bool { return defaults.GetDefaults().DefaultIfTAPMode } -// 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. +// MaximumMTU returns 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 MaximumMTU() int { return defaults.GetDefaults().MaximumIfMTU } -// Initialises the TUN/TAP adapter. +// Init initialises the TUN/TAP adapter. func (tun *TunAdapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte, reject <-chan yggdrasil.RejectedPacket) { tun.config = config tun.log = log @@ -111,8 +120,8 @@ func (tun *TunAdapter) Init(config *config.NodeState, log *log.Logger, send chan }() } -// Starts the setup process for the TUN/TAP adapter, and if successful, starts -// the read/write goroutines to handle packets on that interface. +// 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) Start(a address.Address, s address.Subnet) error { tun.addr = a tun.subnet = s diff --git a/src/yggdrasil/router.go b/src/yggdrasil/router.go index 9130f55..aee9224 100644 --- a/src/yggdrasil/router.go +++ b/src/yggdrasil/router.go @@ -57,13 +57,21 @@ type router_recvPacket struct { sinfo *sessionInfo } +// RejectedPacketReason is the type code used to represent the reason that a +// packet was rejected. type RejectedPacketReason int const ( - // The router rejected the packet because it is too big for the session + // The router rejected the packet because it exceeds the session MTU for the + // given destination. In TUN/TAP, this results in the generation of an ICMPv6 + // Packet Too Big message. PacketTooBig = 1 + iota ) +// RejectedPacket represents a rejected packet from the router. This is passed +// back to the adapter so that the adapter can respond appropriately, e.g. in +// the case of TUN/TAP, a "PacketTooBig" reason can be used to generate an +// ICMPv6 Packet Too Big response. type RejectedPacket struct { Reason RejectedPacketReason Packet []byte diff --git a/src/yggdrasil/tcp.go b/src/yggdrasil/tcp.go index b9681fc..4361ec8 100644 --- a/src/yggdrasil/tcp.go +++ b/src/yggdrasil/tcp.go @@ -41,6 +41,10 @@ type tcp struct { conns map[linkInfo](chan struct{}) } +// TcpListener is a stoppable TCP listener interface. These are typically +// returned from calls to the ListenTCP() function and are also used internally +// to represent listeners created by the "Listen" configuration option and for +// multicast interfaces. type TcpListener struct { Listener net.Listener Stop chan bool From 4c0c3a23cb6aec8a6364b3fae9220a1a8cd2d99a Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 29 Mar 2019 18:24:57 +0000 Subject: [PATCH 12/19] Fix bugs --- cmd/yggdrasil/main.go | 8 ++++---- src/yggdrasil/admin.go | 8 ++++---- src/yggdrasil/core.go | 4 ++-- src/yggdrasil/dht.go | 2 +- src/yggdrasil/nodeinfo.go | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 9278867..fd8cd7b 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -189,8 +189,8 @@ func main() { var err error switch { case *version: - fmt.Println("Build name:", yggdrasil.GetBuildName()) - fmt.Println("Build version:", yggdrasil.GetBuildVersion()) + fmt.Println("Build name:", yggdrasil.BuildName()) + fmt.Println("Build version:", yggdrasil.BuildVersion()) os.Exit(0) case *autoconf: // Use an autoconf-generated config, this will give us random keys and @@ -269,8 +269,8 @@ func main() { }() // 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() + address := n.core.Address() + subnet := n.core.Subnet() 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. diff --git a/src/yggdrasil/admin.go b/src/yggdrasil/admin.go index 2db7ad4..a9595f8 100644 --- a/src/yggdrasil/admin.go +++ b/src/yggdrasil/admin.go @@ -642,14 +642,14 @@ func (a *admin) getData_getSelf() *admin_nodeInfo { coords := table.self.getCoords() self := admin_nodeInfo{ {"box_pub_key", hex.EncodeToString(a.core.boxPub[:])}, - {"ip", a.core.GetAddress().String()}, - {"subnet", a.core.GetSubnet().String()}, + {"ip", a.core.Address().String()}, + {"subnet", a.core.Subnet().String()}, {"coords", fmt.Sprint(coords)}, } - if name := GetBuildName(); name != "unknown" { + if name := BuildName(); name != "unknown" { self = append(self, admin_pair{"build_name", name}) } - if version := GetBuildVersion(); version != "unknown" { + if version := BuildVersion(); version != "unknown" { self = append(self, admin_pair{"build_version", version}) } diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index 8444050..c0548e2 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -267,12 +267,12 @@ func (c *Core) NewSigningKeys() (*crypto.SigPubKey, *crypto.SigPrivKey) { // NodeID gets the node ID. func (c *Core) NodeID() *crypto.NodeID { - return crypto.NodeID(&c.boxPub) + return crypto.GetNodeID(&c.boxPub) } // TreeID gets the tree ID. func (c *Core) TreeID() *crypto.TreeID { - return crypto.TreeID(&c.sigPub) + return crypto.GetTreeID(&c.sigPub) } // Address gets the IPv6 address of the Yggdrasil node. This is always a /128 diff --git a/src/yggdrasil/dht.go b/src/yggdrasil/dht.go index 5427aca..b081c92 100644 --- a/src/yggdrasil/dht.go +++ b/src/yggdrasil/dht.go @@ -86,7 +86,7 @@ func (t *dht) init(c *Core) { e <- nil } }() - t.nodeID = *t.core.GetNodeID() + t.nodeID = *t.core.NodeID() t.peers = make(chan *dhtInfo, 1024) t.callbacks = make(map[dhtReqKey]dht_callbackInfo) t.reset() diff --git a/src/yggdrasil/nodeinfo.go b/src/yggdrasil/nodeinfo.go index 963a2fc..89b8b89 100644 --- a/src/yggdrasil/nodeinfo.go +++ b/src/yggdrasil/nodeinfo.go @@ -101,8 +101,8 @@ func (m *nodeinfo) setNodeInfo(given interface{}, privacy bool) error { m.myNodeInfoMutex.Lock() defer m.myNodeInfoMutex.Unlock() defaults := map[string]interface{}{ - "buildname": GetBuildName(), - "buildversion": GetBuildVersion(), + "buildname": BuildName(), + "buildversion": BuildVersion(), "buildplatform": runtime.GOOS, "buildarch": runtime.GOARCH, } From 39baf7365c8b7c4eb82ade458eca9985c5d075c5 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sat, 30 Mar 2019 00:09:35 +0000 Subject: [PATCH 13/19] Unexport/modify some interfaces to revive broken iOS/Android builds --- src/tuntap/tun.go | 8 ++++---- src/yggdrasil/adapter.go | 10 ++++------ src/yggdrasil/core.go | 11 ++++++++--- src/yggdrasil/link.go | 14 +------------- src/yggdrasil/mobile.go | 12 ++++++------ src/yggdrasil/mobile_ios.go | 5 ++--- src/yggdrasil/router.go | 2 +- 7 files changed, 26 insertions(+), 36 deletions(-) diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index 600d3d7..5d9f4eb 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -148,11 +148,11 @@ func (tun *TunAdapter) Start(a address.Address, s address.Subnet) error { tun.mutex.Unlock() go func() { tun.log.Debugln("Starting TUN/TAP reader goroutine") - tun.log.Errorln("WARNING: tun.read() exited with error:", tun.Read()) + tun.log.Errorln("WARNING: tun.read() exited with error:", tun.read()) }() go func() { tun.log.Debugln("Starting TUN/TAP writer goroutine") - tun.log.Errorln("WARNING: tun.write() exited with error:", tun.Write()) + tun.log.Errorln("WARNING: tun.write() exited with error:", tun.write()) }() if iftapmode { go func() { @@ -177,7 +177,7 @@ func (tun *TunAdapter) Start(a address.Address, s address.Subnet) error { // Writes a packet to the TUN/TAP adapter. If the adapter is running in TAP // mode then additional ethernet encapsulation is added for the benefit of the // host operating system. -func (tun *TunAdapter) Write() error { +func (tun *TunAdapter) write() error { for { select { case reject := <-tun.Reject: @@ -310,7 +310,7 @@ func (tun *TunAdapter) Write() error { // is running in TAP mode then the ethernet headers will automatically be // processed and stripped if necessary. If an ICMPv6 packet is found, then // the relevant helper functions in icmpv6.go are called. -func (tun *TunAdapter) Read() error { +func (tun *TunAdapter) read() error { mtu := tun.mtu if tun.iface.IsTAP() { mtu += tun_ETHER_HEADER_LENGTH diff --git a/src/yggdrasil/adapter.go b/src/yggdrasil/adapter.go index d373894..e5b1707 100644 --- a/src/yggdrasil/adapter.go +++ b/src/yggdrasil/adapter.go @@ -11,7 +11,7 @@ import ( // you should extend the adapter struct with this one and should call the // Adapter.Init() function when initialising. type Adapter struct { - AdapterImplementation + adapterImplementation Core *Core Send chan<- []byte Recv <-chan []byte @@ -20,15 +20,14 @@ type Adapter struct { } // Defines the minimum required functions for an adapter type. Note that the -// implementation of Init() should call Adapter.Init(). -type AdapterImplementation interface { +// implementation of Init() should call Adapter.Init(). This is not exported +// because doing so breaks the gomobile bindings for iOS/Android. +type adapterImplementation interface { Init(*config.NodeState, *log.Logger, chan<- []byte, <-chan []byte, <-chan RejectedPacket) Name() string MTU() int IsTAP() bool Start(address.Address, address.Subnet) error - Read() error - Write() error Close() error } @@ -37,7 +36,6 @@ type AdapterImplementation interface { // function from within it's own Init function to set up the channels. It is // otherwise not expected for you to call this function directly. func (adapter *Adapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte, reject <-chan RejectedPacket) { - log.Traceln("Adapter setup - given channels:", send, recv) adapter.Send = send adapter.Recv = recv adapter.Reject = reject diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index c0548e2..9634a42 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -168,10 +168,15 @@ func BuildVersion() string { // SetRouterAdapter instructs Yggdrasil to use the given adapter when starting // the router. The adapter must implement the standard -// adapter.AdapterImplementation interface and should extend the adapter.Adapter +// adapter.adapterImplementation interface and should extend the adapter.Adapter // struct. -func (c *Core) SetRouterAdapter(adapter AdapterImplementation) { - c.router.adapter = adapter +func (c *Core) SetRouterAdapter(adapter interface{}) { + // We do this because adapterImplementation is not a valid type for the + // gomobile bindings so we just ask for a generic interface and try to cast it + // to adapterImplementation instead + if a, ok := adapter.(adapterImplementation); ok { + c.router.adapter = a + } } // Start starts up Yggdrasil using the provided config.NodeConfig, and outputs diff --git a/src/yggdrasil/link.go b/src/yggdrasil/link.go index bfec714..de90fd9 100644 --- a/src/yggdrasil/link.go +++ b/src/yggdrasil/link.go @@ -23,8 +23,7 @@ type link struct { reconfigure chan chan error mutex sync.RWMutex // protects interfaces below interfaces map[linkInfo]*linkInterface - awdl awdl // AWDL interface support - tcp tcp // TCP interface support + tcp tcp // TCP interface support // TODO timeout (to remove from switch), read from config.ReadTimeout } @@ -68,26 +67,15 @@ func (l *link) init(c *Core) error { return err } - if err := l.awdl.init(l); err != nil { - c.log.Errorln("Failed to start AWDL interface") - return err - } - go func() { for { e := <-l.reconfigure tcpresponse := make(chan error) - awdlresponse := make(chan error) l.tcp.reconfigure <- tcpresponse if err := <-tcpresponse; err != nil { e <- err continue } - l.awdl.reconfigure <- awdlresponse - if err := <-awdlresponse; err != nil { - e <- err - continue - } e <- nil } }() diff --git a/src/yggdrasil/mobile.go b/src/yggdrasil/mobile.go index bad1424..0c6686d 100644 --- a/src/yggdrasil/mobile.go +++ b/src/yggdrasil/mobile.go @@ -52,7 +52,7 @@ func (c *Core) StartAutoconfigure() error { if hostname, err := os.Hostname(); err == nil { nc.NodeInfo = map[string]interface{}{"name": hostname} } - if err := c.Start(nc, logger); err != nil { + if _, err := c.Start(nc, logger); err != nil { return err } go c.addStaticPeers(nc) @@ -73,7 +73,7 @@ func (c *Core) StartJSON(configjson []byte) error { return err } nc.IfName = "dummy" - if err := c.Start(nc, logger); err != nil { + if _, err := c.Start(nc, logger); err != nil { return err } go c.addStaticPeers(nc) @@ -93,12 +93,12 @@ func GenerateConfigJSON() []byte { // Gets the node's IPv6 address. func (c *Core) GetAddressString() string { - return c.GetAddress().String() + return c.Address().String() } // Gets the node's IPv6 subnet in CIDR notation. func (c *Core) GetSubnetString() string { - return c.GetSubnet().String() + return c.Subnet().String() } // Gets the node's public encryption key. @@ -115,7 +115,7 @@ func (c *Core) GetSigPubKeyString() string { // dummy adapter in place of real TUN - when this call returns a packet, you // will probably want to give it to the OS to write to TUN. func (c *Core) RouterRecvPacket() ([]byte, error) { - packet := <-c.router.tun.Recv + packet := <-c.router.recv return packet, nil } @@ -125,6 +125,6 @@ func (c *Core) RouterRecvPacket() ([]byte, error) { // Yggdrasil. func (c *Core) RouterSendPacket(buf []byte) error { packet := append(util.GetBytes(), buf[:]...) - c.router.tun.Send <- packet + c.router.send <- packet return nil } diff --git a/src/yggdrasil/mobile_ios.go b/src/yggdrasil/mobile_ios.go index 7b08999..96d2fc0 100644 --- a/src/yggdrasil/mobile_ios.go +++ b/src/yggdrasil/mobile_ios.go @@ -13,10 +13,7 @@ void Log(const char *text) { */ import "C" import ( - "errors" "unsafe" - - "github.com/yggdrasil-network/yggdrasil-go/src/util" ) type MobileLogger struct { @@ -29,6 +26,7 @@ func (nsl MobileLogger) Write(p []byte) (n int, err error) { return len(p), nil } +/* func (c *Core) AWDLCreateInterface(name, local, remote string, incoming bool) error { if intf, err := c.link.awdl.create(name, local, remote, incoming); err != nil || intf == nil { c.log.Println("c.link.awdl.create:", err) @@ -60,3 +58,4 @@ func (c *Core) AWDLSendPacket(identity string, buf []byte) error { } return errors.New("AWDLSendPacket identity not known: " + identity) } +*/ diff --git a/src/yggdrasil/router.go b/src/yggdrasil/router.go index aee9224..a3d3d68 100644 --- a/src/yggdrasil/router.go +++ b/src/yggdrasil/router.go @@ -41,7 +41,7 @@ type router struct { in <-chan []byte // packets we received from the network, link to peer's "out" out func([]byte) // packets we're sending to the network, link to peer's "in" toRecv chan router_recvPacket // packets to handle via recvPacket() - adapter AdapterImplementation // TUN/TAP adapter + adapter adapterImplementation // TUN/TAP adapter recv chan<- []byte // place where the adapter pulls received packets from send <-chan []byte // place where the adapter puts outgoing packets reject chan<- RejectedPacket // place where we send error packets back to adapter From 047717abf2d06c8e72c799a89c33507a6f86a5c6 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 1 Apr 2019 18:02:06 +0100 Subject: [PATCH 14/19] Break out mobile and dummy adapter --- build | 4 +- src/dummy/dummy.go | 57 ++++++++ src/mobile/mobile.go | 143 ++++++++++++++++++++ src/{yggdrasil => mobile}/mobile_android.go | 2 +- src/{yggdrasil => mobile}/mobile_ios.go | 4 +- src/yggdrasil/core.go | 10 ++ src/yggdrasil/mobile.go | 130 ------------------ 7 files changed, 215 insertions(+), 135 deletions(-) create mode 100644 src/dummy/dummy.go create mode 100644 src/mobile/mobile.go rename src/{yggdrasil => mobile}/mobile_android.go (90%) rename src/{yggdrasil => mobile}/mobile_ios.go (97%) delete mode 100644 src/yggdrasil/mobile.go diff --git a/build b/build index f6c7246..127af75 100755 --- a/build +++ b/build @@ -28,10 +28,10 @@ fi if [ $IOS ]; then echo "Building framework for iOS" - gomobile bind -target ios -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil + gomobile bind -target ios -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" github.com/yggdrasil-network/yggdrasil-go/src/mobile elif [ $ANDROID ]; then echo "Building aar for Android" - gomobile bind -target android -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil + gomobile bind -target android -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" github.com/yggdrasil-network/yggdrasil-go/src/mobile else for CMD in `ls cmd/` ; do echo "Building: $CMD" diff --git a/src/dummy/dummy.go b/src/dummy/dummy.go new file mode 100644 index 0000000..a199eee --- /dev/null +++ b/src/dummy/dummy.go @@ -0,0 +1,57 @@ +package dummy + +import ( + "github.com/gologme/log" + "github.com/yggdrasil-network/yggdrasil-go/src/config" + "github.com/yggdrasil-network/yggdrasil-go/src/util" + "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil" +) + +type DummyAdapter struct { + yggdrasil.Adapter + send chan<- []byte + recv <-chan []byte + reject <-chan yggdrasil.RejectedPacket +} + +// Init initialises the TUN/TAP adapter. +func (m *DummyAdapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte, reject <-chan yggdrasil.RejectedPacket) { + m.Adapter.Init(config, log, send, recv, reject) +} + +// Name returns the name of the adapter, e.g. "tun0". On Windows, this may +// return a canonical adapter name instead. +func (m *DummyAdapter) Name() string { + return "dummy" +} + +// MTU gets the adapter's MTU. This can range between 1280 and 65535, although +// the maximum value is determined by your platform. The returned value will +// never exceed that of MaximumMTU(). +func (m *DummyAdapter) MTU() int { + return 65535 +} + +// IsTAP returns true if the adapter is a TAP adapter (Layer 2) or false if it +// is a TUN adapter (Layer 3). +func (m *DummyAdapter) IsTAP() bool { + return false +} + +// Wait for a packet from the router. You will use this when implementing a +// dummy adapter in place of real TUN - when this call returns a packet, you +// will probably want to give it to the OS to write to TUN. +func (m *DummyAdapter) Recv() ([]byte, error) { + packet := <-m.recv + return packet, nil +} + +// Send a packet to the router. You will use this when implementing a +// dummy adapter in place of real TUN - when the operating system tells you +// that a new packet is available from TUN, call this function to give it to +// Yggdrasil. +func (m *DummyAdapter) Send(buf []byte) error { + packet := append(util.GetBytes(), buf[:]...) + m.send <- packet + return nil +} diff --git a/src/mobile/mobile.go b/src/mobile/mobile.go new file mode 100644 index 0000000..ecc4d65 --- /dev/null +++ b/src/mobile/mobile.go @@ -0,0 +1,143 @@ +package mobile + +import ( + "encoding/json" + "os" + "time" + + "github.com/gologme/log" + + hjson "github.com/hjson/hjson-go" + "github.com/mitchellh/mapstructure" + "github.com/yggdrasil-network/yggdrasil-go/src/config" + "github.com/yggdrasil-network/yggdrasil-go/src/dummy" + "github.com/yggdrasil-network/yggdrasil-go/src/multicast" + "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil" +) + +// Yggdrasil's mobile package is meant to "plug the gap" for mobile support, as +// Gomobile will not create headers for Swift/Obj-C etc if they have complex +// (non-native) types. Therefore for iOS we will expose some nice simple +// functions. Note that in the case of iOS we handle reading/writing to/from TUN +// in Swift therefore we use the "dummy" TUN interface instead. +type Yggdrasil struct { + core *yggdrasil.Core + multicast *multicast.Multicast + dummy.DummyAdapter +} + +func (m *Yggdrasil) addStaticPeers(cfg *config.NodeConfig) { + if len(cfg.Peers) == 0 && len(cfg.InterfacePeers) == 0 { + return + } + for { + for _, peer := range cfg.Peers { + m.core.AddPeer(peer, "") + time.Sleep(time.Second) + } + for intf, intfpeers := range cfg.InterfacePeers { + for _, peer := range intfpeers { + m.core.AddPeer(peer, intf) + time.Sleep(time.Second) + } + } + time.Sleep(time.Minute) + } +} + +// StartAutoconfigure starts a node with a randomly generated config +func (m *Yggdrasil) StartAutoconfigure() error { + m.core = &yggdrasil.Core{} + //m.Adapter = dummy.DummyAdapter{} + mobilelog := MobileLogger{} + logger := log.New(mobilelog, "", 0) + nc := config.GenerateConfig() + nc.IfName = "dummy" + nc.AdminListen = "tcp://localhost:9001" + nc.Peers = []string{} + if hostname, err := os.Hostname(); err == nil { + nc.NodeInfo = map[string]interface{}{"name": hostname} + } + m.core.SetRouterAdapter(&m) + state, err := m.core.Start(nc, logger) + if err != nil { + return err + } + // Start the multicast interface + m.multicast.Init(m.core, state, logger, nil) + if err := m.multicast.Start(); err != nil { + logger.Errorln("An error occurred starting multicast:", err) + } + go m.addStaticPeers(nc) + return nil +} + +// StartJSON starts a node with the given JSON config. You can get JSON config +// (rather than HJSON) by using the GenerateConfigJSON() function +func (m *Yggdrasil) StartJSON(configjson []byte) error { + m.core = &yggdrasil.Core{} + //m.Adapter = dummy.DummyAdapter{} + mobilelog := MobileLogger{} + logger := log.New(mobilelog, "", 0) + nc := config.GenerateConfig() + var dat map[string]interface{} + if err := hjson.Unmarshal(configjson, &dat); err != nil { + return err + } + if err := mapstructure.Decode(dat, &nc); err != nil { + return err + } + nc.IfName = "dummy" + m.core.SetRouterAdapter(&m) + state, err := m.core.Start(nc, logger) + if err != nil { + return err + } + // Start the multicast interface + m.multicast.Init(m.core, state, logger, nil) + if err := m.multicast.Start(); err != nil { + logger.Errorln("An error occurred starting multicast:", err) + } + go m.addStaticPeers(nc) + return nil +} + +// Stops the mobile Yggdrasil instance +func (m *Yggdrasil) Stop() error { + m.core.Stop() + if err := m.Stop(); err != nil { + return err + } + return nil +} + +// GenerateConfigJSON generates mobile-friendly configuration in JSON format +func GenerateConfigJSON() []byte { + nc := config.GenerateConfig() + nc.IfName = "dummy" + if json, err := json.Marshal(nc); err == nil { + return json + } else { + return nil + } +} + +// GetAddressString gets the node's IPv6 address +func (m *Yggdrasil) GetAddressString() string { + return m.core.Address().String() +} + +// GetSubnetString gets the node's IPv6 subnet in CIDR notation +func (m *Yggdrasil) GetSubnetString() string { + return m.core.Subnet().String() +} + +// GetBoxPubKeyString gets the node's public encryption key +func (m *Yggdrasil) GetBoxPubKeyString() string { + return m.core.BoxPubKey() +} + +// GetSigPubKeyString gets the node's public signing key +func (m *Yggdrasil) GetSigPubKeyString() string { + return m.core.SigPubKey() +} diff --git a/src/yggdrasil/mobile_android.go b/src/mobile/mobile_android.go similarity index 90% rename from src/yggdrasil/mobile_android.go rename to src/mobile/mobile_android.go index 2476484..f3206ac 100644 --- a/src/yggdrasil/mobile_android.go +++ b/src/mobile/mobile_android.go @@ -1,6 +1,6 @@ // +build android -package yggdrasil +package mobile import "log" diff --git a/src/yggdrasil/mobile_ios.go b/src/mobile/mobile_ios.go similarity index 97% rename from src/yggdrasil/mobile_ios.go rename to src/mobile/mobile_ios.go index 96d2fc0..26b219c 100644 --- a/src/yggdrasil/mobile_ios.go +++ b/src/mobile/mobile_ios.go @@ -1,6 +1,6 @@ -// +build mobile,darwin +// +build darwin -package yggdrasil +package mobile /* #cgo CFLAGS: -x objective-c diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index 9634a42..fcee124 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -280,6 +280,16 @@ func (c *Core) TreeID() *crypto.TreeID { return crypto.GetTreeID(&c.sigPub) } +// SigPubKey gets the node's signing public key. +func (c *Core) SigPubKey() string { + return hex.EncodeToString(c.sigPub[:]) +} + +// BoxPubKey gets the node's encryption public key. +func (c *Core) BoxPubKey() string { + return hex.EncodeToString(c.boxPub[:]) +} + // Address gets the IPv6 address of the Yggdrasil node. This is always a /128 // address. func (c *Core) Address() *net.IP { diff --git a/src/yggdrasil/mobile.go b/src/yggdrasil/mobile.go deleted file mode 100644 index 0c6686d..0000000 --- a/src/yggdrasil/mobile.go +++ /dev/null @@ -1,130 +0,0 @@ -// +build mobile - -package yggdrasil - -import ( - "encoding/hex" - "encoding/json" - "os" - "time" - - "github.com/gologme/log" - - hjson "github.com/hjson/hjson-go" - "github.com/mitchellh/mapstructure" - "github.com/yggdrasil-network/yggdrasil-go/src/config" - "github.com/yggdrasil-network/yggdrasil-go/src/util" -) - -// This file is meant to "plug the gap" for mobile support, as Gomobile will -// not create headers for Swift/Obj-C etc if they have complex (non-native) -// types. Therefore for iOS we will expose some nice simple functions. Note -// that in the case of iOS we handle reading/writing to/from TUN in Swift -// therefore we use the "dummy" TUN interface instead. - -func (c *Core) addStaticPeers(cfg *config.NodeConfig) { - if len(cfg.Peers) == 0 && len(cfg.InterfacePeers) == 0 { - return - } - for { - for _, peer := range cfg.Peers { - c.AddPeer(peer, "") - time.Sleep(time.Second) - } - for intf, intfpeers := range cfg.InterfacePeers { - for _, peer := range intfpeers { - c.AddPeer(peer, intf) - time.Sleep(time.Second) - } - } - time.Sleep(time.Minute) - } -} - -// Starts a node with a randomly generated config. -func (c *Core) StartAutoconfigure() error { - mobilelog := MobileLogger{} - logger := log.New(mobilelog, "", 0) - nc := config.GenerateConfig() - nc.IfName = "dummy" - nc.AdminListen = "tcp://localhost:9001" - nc.Peers = []string{} - if hostname, err := os.Hostname(); err == nil { - nc.NodeInfo = map[string]interface{}{"name": hostname} - } - if _, err := c.Start(nc, logger); err != nil { - return err - } - go c.addStaticPeers(nc) - return nil -} - -// Starts a node with the given JSON config. You can get JSON config (rather -// than HJSON) by using the GenerateConfigJSON() function. -func (c *Core) StartJSON(configjson []byte) error { - mobilelog := MobileLogger{} - logger := log.New(mobilelog, "", 0) - nc := config.GenerateConfig() - var dat map[string]interface{} - if err := hjson.Unmarshal(configjson, &dat); err != nil { - return err - } - if err := mapstructure.Decode(dat, &nc); err != nil { - return err - } - nc.IfName = "dummy" - if _, err := c.Start(nc, logger); err != nil { - return err - } - go c.addStaticPeers(nc) - return nil -} - -// Generates mobile-friendly configuration in JSON format. -func GenerateConfigJSON() []byte { - nc := config.GenerateConfig() - nc.IfName = "dummy" - if json, err := json.Marshal(nc); err == nil { - return json - } else { - return nil - } -} - -// Gets the node's IPv6 address. -func (c *Core) GetAddressString() string { - return c.Address().String() -} - -// Gets the node's IPv6 subnet in CIDR notation. -func (c *Core) GetSubnetString() string { - return c.Subnet().String() -} - -// Gets the node's public encryption key. -func (c *Core) GetBoxPubKeyString() string { - return hex.EncodeToString(c.boxPub[:]) -} - -// Gets the node's public signing key. -func (c *Core) GetSigPubKeyString() string { - return hex.EncodeToString(c.sigPub[:]) -} - -// Wait for a packet from the router. You will use this when implementing a -// dummy adapter in place of real TUN - when this call returns a packet, you -// will probably want to give it to the OS to write to TUN. -func (c *Core) RouterRecvPacket() ([]byte, error) { - packet := <-c.router.recv - return packet, nil -} - -// Send a packet to the router. You will use this when implementing a -// dummy adapter in place of real TUN - when the operating system tells you -// that a new packet is available from TUN, call this function to give it to -// Yggdrasil. -func (c *Core) RouterSendPacket(buf []byte) error { - packet := append(util.GetBytes(), buf[:]...) - c.router.send <- packet - return nil -} From 58f5cc88d03abee0afc1f3555c8aad0b1f274a1f Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 1 Apr 2019 19:59:50 +0100 Subject: [PATCH 15/19] Fix session bug, fix dummy adapter, fix mobile framework builds --- build | 10 +++++++-- src/dummy/dummy.go | 46 ++++++++++++++++++++++------------------ src/mobile/mobile.go | 38 ++++++++++++++++----------------- src/yggdrasil/core.go | 5 ++++- src/yggdrasil/session.go | 4 +++- 5 files changed, 58 insertions(+), 45 deletions(-) diff --git a/build b/build index 127af75..f76ee7b 100755 --- a/build +++ b/build @@ -28,10 +28,16 @@ fi if [ $IOS ]; then echo "Building framework for iOS" - gomobile bind -target ios -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" github.com/yggdrasil-network/yggdrasil-go/src/mobile + gomobile bind -target ios -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" \ + github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil \ + github.com/yggdrasil-network/yggdrasil-go/src/mobile \ + github.com/yggdrasil-network/yggdrasil-go/src/config elif [ $ANDROID ]; then echo "Building aar for Android" - gomobile bind -target android -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" github.com/yggdrasil-network/yggdrasil-go/src/mobile + gomobile bind -target android -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" \ + github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil \ + github.com/yggdrasil-network/yggdrasil-go/src/mobile \ + github.com/yggdrasil-network/yggdrasil-go/src/config else for CMD in `ls cmd/` ; do echo "Building: $CMD" diff --git a/src/dummy/dummy.go b/src/dummy/dummy.go index a199eee..ca6bb7b 100644 --- a/src/dummy/dummy.go +++ b/src/dummy/dummy.go @@ -2,56 +2,60 @@ package dummy import ( "github.com/gologme/log" + "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/util" "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil" ) +// DummyAdapter is a non-specific adapter that is used by the mobile APIs. +// You can also use it to send or receive custom traffic over Yggdrasil. type DummyAdapter struct { yggdrasil.Adapter - send chan<- []byte - recv <-chan []byte - reject <-chan yggdrasil.RejectedPacket } -// Init initialises the TUN/TAP adapter. +// Init initialises the dummy adapter. func (m *DummyAdapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte, reject <-chan yggdrasil.RejectedPacket) { m.Adapter.Init(config, log, send, recv, reject) } -// Name returns the name of the adapter, e.g. "tun0". On Windows, this may -// return a canonical adapter name instead. +// Name returns the name of the adapter. This is always "dummy" for dummy +// adapters. func (m *DummyAdapter) Name() string { return "dummy" } -// MTU gets the adapter's MTU. This can range between 1280 and 65535, although -// the maximum value is determined by your platform. The returned value will -// never exceed that of MaximumMTU(). +// MTU gets the adapter's MTU. This returns your platform's maximum MTU for +// dummy adapters. func (m *DummyAdapter) MTU() int { - return 65535 + return defaults.GetDefaults().MaximumIfMTU } -// IsTAP returns true if the adapter is a TAP adapter (Layer 2) or false if it -// is a TUN adapter (Layer 3). +// IsTAP always returns false for dummy adapters. func (m *DummyAdapter) IsTAP() bool { return false } -// Wait for a packet from the router. You will use this when implementing a -// dummy adapter in place of real TUN - when this call returns a packet, you -// will probably want to give it to the OS to write to TUN. +// Recv waits for and returns for a packet from the router. func (m *DummyAdapter) Recv() ([]byte, error) { - packet := <-m.recv + packet := <-m.Adapter.Recv return packet, nil } -// Send a packet to the router. You will use this when implementing a -// dummy adapter in place of real TUN - when the operating system tells you -// that a new packet is available from TUN, call this function to give it to -// Yggdrasil. +// Send a packet to the router. func (m *DummyAdapter) Send(buf []byte) error { packet := append(util.GetBytes(), buf[:]...) - m.send <- packet + m.Adapter.Send <- packet + return nil +} + +// Start is not implemented for dummy adapters. +func (m *DummyAdapter) Start(address.Address, address.Subnet) error { + return nil +} + +// Close is not implemented for dummy adapters. +func (m *DummyAdapter) Close() error { return nil } diff --git a/src/mobile/mobile.go b/src/mobile/mobile.go index ecc4d65..5eec96e 100644 --- a/src/mobile/mobile.go +++ b/src/mobile/mobile.go @@ -15,14 +15,15 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil" ) -// Yggdrasil's mobile package is meant to "plug the gap" for mobile support, as +// Yggdrasil mobile package is meant to "plug the gap" for mobile support, as // Gomobile will not create headers for Swift/Obj-C etc if they have complex // (non-native) types. Therefore for iOS we will expose some nice simple // functions. Note that in the case of iOS we handle reading/writing to/from TUN // in Swift therefore we use the "dummy" TUN interface instead. type Yggdrasil struct { - core *yggdrasil.Core - multicast *multicast.Multicast + core yggdrasil.Core + multicast multicast.Multicast + log MobileLogger dummy.DummyAdapter } @@ -47,10 +48,7 @@ func (m *Yggdrasil) addStaticPeers(cfg *config.NodeConfig) { // StartAutoconfigure starts a node with a randomly generated config func (m *Yggdrasil) StartAutoconfigure() error { - m.core = &yggdrasil.Core{} - //m.Adapter = dummy.DummyAdapter{} - mobilelog := MobileLogger{} - logger := log.New(mobilelog, "", 0) + logger := log.New(m.log, "", 0) nc := config.GenerateConfig() nc.IfName = "dummy" nc.AdminListen = "tcp://localhost:9001" @@ -58,13 +56,15 @@ func (m *Yggdrasil) StartAutoconfigure() error { if hostname, err := os.Hostname(); err == nil { nc.NodeInfo = map[string]interface{}{"name": hostname} } - m.core.SetRouterAdapter(&m) + if err := m.core.SetRouterAdapter(m); err != nil { + logger.Errorln("An error occured setting router adapter:", err) + return err + } state, err := m.core.Start(nc, logger) if err != nil { return err } - // Start the multicast interface - m.multicast.Init(m.core, state, logger, nil) + m.multicast.Init(&m.core, state, logger, nil) if err := m.multicast.Start(); err != nil { logger.Errorln("An error occurred starting multicast:", err) } @@ -75,10 +75,7 @@ func (m *Yggdrasil) StartAutoconfigure() error { // StartJSON starts a node with the given JSON config. You can get JSON config // (rather than HJSON) by using the GenerateConfigJSON() function func (m *Yggdrasil) StartJSON(configjson []byte) error { - m.core = &yggdrasil.Core{} - //m.Adapter = dummy.DummyAdapter{} - mobilelog := MobileLogger{} - logger := log.New(mobilelog, "", 0) + logger := log.New(m.log, "", 0) nc := config.GenerateConfig() var dat map[string]interface{} if err := hjson.Unmarshal(configjson, &dat); err != nil { @@ -88,13 +85,15 @@ func (m *Yggdrasil) StartJSON(configjson []byte) error { return err } nc.IfName = "dummy" - m.core.SetRouterAdapter(&m) + if err := m.core.SetRouterAdapter(m); err != nil { + logger.Errorln("An error occured setting router adapter:", err) + return err + } state, err := m.core.Start(nc, logger) if err != nil { return err } - // Start the multicast interface - m.multicast.Init(m.core, state, logger, nil) + m.multicast.Init(&m.core, state, logger, nil) if err := m.multicast.Start(); err != nil { logger.Errorln("An error occurred starting multicast:", err) } @@ -102,7 +101,7 @@ func (m *Yggdrasil) StartJSON(configjson []byte) error { return nil } -// Stops the mobile Yggdrasil instance +// Stop the mobile Yggdrasil instance func (m *Yggdrasil) Stop() error { m.core.Stop() if err := m.Stop(); err != nil { @@ -117,9 +116,8 @@ func GenerateConfigJSON() []byte { nc.IfName = "dummy" if json, err := json.Marshal(nc); err == nil { return json - } else { - return nil } + return nil } // GetAddressString gets the node's IPv6 address diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index fcee124..037ef09 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -2,6 +2,7 @@ package yggdrasil import ( "encoding/hex" + "errors" "io/ioutil" "net" "time" @@ -170,13 +171,15 @@ func BuildVersion() string { // the router. The adapter must implement the standard // adapter.adapterImplementation interface and should extend the adapter.Adapter // struct. -func (c *Core) SetRouterAdapter(adapter interface{}) { +func (c *Core) SetRouterAdapter(adapter interface{}) error { // We do this because adapterImplementation is not a valid type for the // gomobile bindings so we just ask for a generic interface and try to cast it // to adapterImplementation instead if a, ok := adapter.(adapterImplementation); ok { c.router.adapter = a + return nil } + return errors.New("unsuitable adapter") } // Start starts up Yggdrasil using the provided config.NodeConfig, and outputs diff --git a/src/yggdrasil/session.go b/src/yggdrasil/session.go index 8deff95..74255c0 100644 --- a/src/yggdrasil/session.go +++ b/src/yggdrasil/session.go @@ -277,7 +277,9 @@ func (ss *sessions) createSession(theirPermKey *crypto.BoxPubKey) *sessionInfo { sinfo.mySesPriv = *priv sinfo.myNonce = *crypto.NewBoxNonce() sinfo.theirMTU = 1280 - sinfo.myMTU = uint16(ss.core.router.adapter.MTU()) + if ss.core.router.adapter != nil { + sinfo.myMTU = uint16(ss.core.router.adapter.MTU()) + } now := time.Now() sinfo.time = now sinfo.mtuTime = now From 350b51cabb0e92444dc0e6de3e00cc7cbf06e387 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 1 Apr 2019 20:10:14 +0100 Subject: [PATCH 16/19] TUN/TAP now uses config, log, etc from adapter.go --- src/tuntap/tun.go | 38 +++++++++++++++++--------------------- src/tuntap/tun_bsd.go | 24 ++++++++++++------------ src/tuntap/tun_darwin.go | 14 +++++++------- src/tuntap/tun_linux.go | 6 +++--- src/tuntap/tun_other.go | 2 +- src/tuntap/tun_windows.go | 32 ++++++++++++++++---------------- src/yggdrasil/adapter.go | 14 +++++++++----- 7 files changed, 65 insertions(+), 65 deletions(-) diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index 5d9f4eb..c93b116 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -35,8 +35,6 @@ type TunAdapter struct { yggdrasil.Adapter addr address.Address subnet address.Subnet - log *log.Logger - config *config.NodeState icmpv6 ICMPv6 mtu int iface *water.Interface @@ -98,20 +96,18 @@ func MaximumMTU() int { // Init initialises the TUN/TAP adapter. func (tun *TunAdapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte, reject <-chan yggdrasil.RejectedPacket) { - tun.config = config - tun.log = log tun.Adapter.Init(config, log, send, recv, reject) tun.icmpv6.Init(tun) go func() { for { e := <-tun.Reconfigure - tun.config.Mutex.RLock() - updated := tun.config.Current.IfName != tun.config.Previous.IfName || - tun.config.Current.IfTAPMode != tun.config.Previous.IfTAPMode || - tun.config.Current.IfMTU != tun.config.Previous.IfMTU - tun.config.Mutex.RUnlock() + tun.Config.Mutex.RLock() + updated := tun.Config.Current.IfName != tun.Config.Previous.IfName || + tun.Config.Current.IfTAPMode != tun.Config.Previous.IfTAPMode || + tun.Config.Current.IfMTU != tun.Config.Previous.IfMTU + tun.Config.Mutex.RUnlock() if updated { - tun.log.Warnln("Reconfiguring TUN/TAP is not supported yet") + tun.Log.Warnln("Reconfiguring TUN/TAP is not supported yet") e <- nil } else { e <- nil @@ -125,34 +121,34 @@ func (tun *TunAdapter) Init(config *config.NodeState, log *log.Logger, send chan func (tun *TunAdapter) Start(a address.Address, s address.Subnet) error { tun.addr = a tun.subnet = s - if tun.config == nil { + if tun.Config == nil { return errors.New("No configuration available to TUN/TAP") } - tun.config.Mutex.RLock() - ifname := tun.config.Current.IfName - iftapmode := tun.config.Current.IfTAPMode + tun.Config.Mutex.RLock() + ifname := tun.Config.Current.IfName + iftapmode := tun.Config.Current.IfTAPMode addr := fmt.Sprintf("%s/%d", net.IP(tun.addr[:]).String(), 8*len(address.GetPrefix())-1) - mtu := tun.config.Current.IfMTU - tun.config.Mutex.RUnlock() + mtu := tun.Config.Current.IfMTU + tun.Config.Mutex.RUnlock() if ifname != "none" { if err := tun.setup(ifname, iftapmode, addr, mtu); err != nil { return err } } if ifname == "none" || ifname == "dummy" { - tun.log.Debugln("Not starting TUN/TAP as ifname is none or dummy") + tun.Log.Debugln("Not starting TUN/TAP as ifname is none or dummy") return nil } tun.mutex.Lock() tun.isOpen = true tun.mutex.Unlock() go func() { - tun.log.Debugln("Starting TUN/TAP reader goroutine") - tun.log.Errorln("WARNING: tun.read() exited with error:", tun.read()) + tun.Log.Debugln("Starting TUN/TAP reader goroutine") + tun.Log.Errorln("WARNING: tun.read() exited with error:", tun.read()) }() go func() { - tun.log.Debugln("Starting TUN/TAP writer goroutine") - tun.log.Errorln("WARNING: tun.write() exited with error:", tun.write()) + tun.Log.Debugln("Starting TUN/TAP writer goroutine") + tun.Log.Errorln("WARNING: tun.write() exited with error:", tun.write()) }() if iftapmode { go func() { diff --git a/src/tuntap/tun_bsd.go b/src/tuntap/tun_bsd.go index 996f314..27c9bb2 100644 --- a/src/tuntap/tun_bsd.go +++ b/src/tuntap/tun_bsd.go @@ -109,14 +109,14 @@ func (tun *TunAdapter) setupAddress(addr string) error { // Create system socket if sfd, err = unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0); err != nil { - tun.log.Printf("Create AF_INET socket failed: %v.", err) + tun.Log.Printf("Create AF_INET socket failed: %v.", err) return err } // Friendly output - tun.log.Infof("Interface name: %s", tun.iface.Name()) - tun.log.Infof("Interface IPv6: %s", addr) - tun.log.Infof("Interface MTU: %d", tun.mtu) + tun.Log.Infof("Interface name: %s", tun.iface.Name()) + tun.Log.Infof("Interface IPv6: %s", addr) + tun.Log.Infof("Interface MTU: %d", tun.mtu) // Create the MTU request var ir in6_ifreq_mtu @@ -126,15 +126,15 @@ func (tun *TunAdapter) setupAddress(addr string) error { // Set the MTU if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(sfd), uintptr(syscall.SIOCSIFMTU), uintptr(unsafe.Pointer(&ir))); errno != 0 { err = errno - tun.log.Errorf("Error in SIOCSIFMTU: %v", errno) + tun.Log.Errorf("Error in SIOCSIFMTU: %v", errno) // Fall back to ifconfig to set the MTU cmd := exec.Command("ifconfig", tun.iface.Name(), "mtu", string(tun.mtu)) - tun.log.Warnf("Using ifconfig as fallback: %v", strings.Join(cmd.Args, " ")) + tun.Log.Warnf("Using ifconfig as fallback: %v", strings.Join(cmd.Args, " ")) output, err := cmd.CombinedOutput() if err != nil { - tun.log.Errorf("SIOCSIFMTU fallback failed: %v.", err) - tun.log.Traceln(string(output)) + tun.Log.Errorf("SIOCSIFMTU fallback failed: %v.", err) + tun.Log.Traceln(string(output)) } } @@ -155,15 +155,15 @@ func (tun *TunAdapter) setupAddress(addr string) error { // Set the interface address if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(sfd), uintptr(SIOCSIFADDR_IN6), uintptr(unsafe.Pointer(&ar))); errno != 0 { err = errno - tun.log.Errorf("Error in SIOCSIFADDR_IN6: %v", errno) + tun.Log.Errorf("Error in SIOCSIFADDR_IN6: %v", errno) // Fall back to ifconfig to set the address cmd := exec.Command("ifconfig", tun.iface.Name(), "inet6", addr) - tun.log.Warnf("Using ifconfig as fallback: %v", strings.Join(cmd.Args, " ")) + tun.Log.Warnf("Using ifconfig as fallback: %v", strings.Join(cmd.Args, " ")) output, err := cmd.CombinedOutput() if err != nil { - tun.log.Errorf("SIOCSIFADDR_IN6 fallback failed: %v.", err) - tun.log.Traceln(string(output)) + tun.Log.Errorf("SIOCSIFADDR_IN6 fallback failed: %v.", err) + tun.Log.Traceln(string(output)) } } diff --git a/src/tuntap/tun_darwin.go b/src/tuntap/tun_darwin.go index 5dfca13..60786b8 100644 --- a/src/tuntap/tun_darwin.go +++ b/src/tuntap/tun_darwin.go @@ -18,7 +18,7 @@ import ( // Configures the "utun" adapter with the correct IPv6 address and MTU. func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { if iftapmode { - tun.log.Warnln("TAP mode is not supported on this platform, defaulting to TUN") + tun.Log.Warnln("TAP mode is not supported on this platform, defaulting to TUN") } config := water.Config{DeviceType: water.TUN} iface, err := water.New(config) @@ -69,7 +69,7 @@ func (tun *TunAdapter) setupAddress(addr string) error { var err error if fd, err = unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, 0); err != nil { - tun.log.Printf("Create AF_SYSTEM socket failed: %v.", err) + tun.Log.Printf("Create AF_SYSTEM socket failed: %v.", err) return err } @@ -98,19 +98,19 @@ func (tun *TunAdapter) setupAddress(addr string) error { copy(ir.ifr_name[:], tun.iface.Name()) ir.ifru_mtu = uint32(tun.mtu) - tun.log.Infof("Interface name: %s", ar.ifra_name) - tun.log.Infof("Interface IPv6: %s", addr) - tun.log.Infof("Interface MTU: %d", ir.ifru_mtu) + tun.Log.Infof("Interface name: %s", ar.ifra_name) + tun.Log.Infof("Interface IPv6: %s", addr) + tun.Log.Infof("Interface MTU: %d", ir.ifru_mtu) if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(darwin_SIOCAIFADDR_IN6), uintptr(unsafe.Pointer(&ar))); errno != 0 { err = errno - tun.log.Errorf("Error in darwin_SIOCAIFADDR_IN6: %v", errno) + tun.Log.Errorf("Error in darwin_SIOCAIFADDR_IN6: %v", errno) return err } if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(unix.SIOCSIFMTU), uintptr(unsafe.Pointer(&ir))); errno != 0 { err = errno - tun.log.Errorf("Error in SIOCSIFMTU: %v", errno) + tun.Log.Errorf("Error in SIOCSIFMTU: %v", errno) return err } diff --git a/src/tuntap/tun_linux.go b/src/tuntap/tun_linux.go index c9c03c0..7d22857 100644 --- a/src/tuntap/tun_linux.go +++ b/src/tuntap/tun_linux.go @@ -40,9 +40,9 @@ func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int } } // Friendly output - tun.log.Infof("Interface name: %s", tun.iface.Name()) - tun.log.Infof("Interface IPv6: %s", addr) - tun.log.Infof("Interface MTU: %d", tun.mtu) + tun.Log.Infof("Interface name: %s", tun.iface.Name()) + tun.Log.Infof("Interface IPv6: %s", addr) + tun.Log.Infof("Interface MTU: %d", tun.mtu) return tun.setupAddress(addr) } diff --git a/src/tuntap/tun_other.go b/src/tuntap/tun_other.go index 48276b4..bb302d1 100644 --- a/src/tuntap/tun_other.go +++ b/src/tuntap/tun_other.go @@ -28,6 +28,6 @@ func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int // We don't know how to set the IPv6 address on an unknown platform, therefore // write about it to stdout and don't try to do anything further. func (tun *TunAdapter) setupAddress(addr string) error { - tun.log.Warnln("Platform not supported, you must set the address of", tun.iface.Name(), "to", addr) + tun.Log.Warnln("Platform not supported, you must set the address of", tun.iface.Name(), "to", addr) return nil } diff --git a/src/tuntap/tun_windows.go b/src/tuntap/tun_windows.go index 8a66ac6..5a158b1 100644 --- a/src/tuntap/tun_windows.go +++ b/src/tuntap/tun_windows.go @@ -15,7 +15,7 @@ import ( // delegate the hard work to "netsh". func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { if !iftapmode { - tun.log.Warnln("TUN mode is not supported on this platform, defaulting to TAP") + tun.Log.Warnln("TUN mode is not supported on this platform, defaulting to TAP") } config := water.Config{DeviceType: water.TAP} config.PlatformSpecificParams.ComponentID = "tap0901" @@ -31,19 +31,19 @@ func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int } // Disable/enable the interface to resets its configuration (invalidating iface) cmd := exec.Command("netsh", "interface", "set", "interface", iface.Name(), "admin=DISABLED") - tun.log.Printf("netsh command: %v", strings.Join(cmd.Args, " ")) + tun.Log.Printf("netsh command: %v", strings.Join(cmd.Args, " ")) output, err := cmd.CombinedOutput() if err != nil { - tun.log.Errorf("Windows netsh failed: %v.", err) - tun.log.Traceln(string(output)) + tun.Log.Errorf("Windows netsh failed: %v.", err) + tun.Log.Traceln(string(output)) return err } cmd = exec.Command("netsh", "interface", "set", "interface", iface.Name(), "admin=ENABLED") - tun.log.Printf("netsh command: %v", strings.Join(cmd.Args, " ")) + tun.Log.Printf("netsh command: %v", strings.Join(cmd.Args, " ")) output, err = cmd.CombinedOutput() if err != nil { - tun.log.Errorf("Windows netsh failed: %v.", err) - tun.log.Traceln(string(output)) + tun.Log.Errorf("Windows netsh failed: %v.", err) + tun.Log.Traceln(string(output)) return err } // Get a new iface @@ -58,9 +58,9 @@ func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int panic(err) } // Friendly output - tun.log.Infof("Interface name: %s", tun.iface.Name()) - tun.log.Infof("Interface IPv6: %s", addr) - tun.log.Infof("Interface MTU: %d", tun.mtu) + tun.Log.Infof("Interface name: %s", tun.iface.Name()) + tun.Log.Infof("Interface IPv6: %s", addr) + tun.Log.Infof("Interface MTU: %d", tun.mtu) return tun.setupAddress(addr) } @@ -71,11 +71,11 @@ func (tun *TunAdapter) setupMTU(mtu int) error { fmt.Sprintf("interface=%s", tun.iface.Name()), fmt.Sprintf("mtu=%d", mtu), "store=active") - tun.log.Debugln("netsh command: %v", strings.Join(cmd.Args, " ")) + tun.Log.Debugln("netsh command: %v", strings.Join(cmd.Args, " ")) output, err := cmd.CombinedOutput() if err != nil { - tun.log.Errorf("Windows netsh failed: %v.", err) - tun.log.Traceln(string(output)) + tun.Log.Errorf("Windows netsh failed: %v.", err) + tun.Log.Traceln(string(output)) return err } return nil @@ -88,11 +88,11 @@ func (tun *TunAdapter) setupAddress(addr string) error { fmt.Sprintf("interface=%s", tun.iface.Name()), fmt.Sprintf("addr=%s", addr), "store=active") - tun.log.Debugln("netsh command: %v", strings.Join(cmd.Args, " ")) + tun.Log.Debugln("netsh command: %v", strings.Join(cmd.Args, " ")) output, err := cmd.CombinedOutput() if err != nil { - tun.log.Errorf("Windows netsh failed: %v.", err) - tun.log.Traceln(string(output)) + tun.Log.Errorf("Windows netsh failed: %v.", err) + tun.Log.Traceln(string(output)) return err } return nil diff --git a/src/yggdrasil/adapter.go b/src/yggdrasil/adapter.go index e5b1707..8fadb19 100644 --- a/src/yggdrasil/adapter.go +++ b/src/yggdrasil/adapter.go @@ -6,13 +6,15 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/config" ) -// Defines the minimum required struct members for an adapter type. This is now -// the base type for adapters like tun.go. When implementing a new adapter type, -// you should extend the adapter struct with this one and should call the -// Adapter.Init() function when initialising. +// Adapter defines the minimum required struct members for an adapter type. This +// is now the base type for adapters like tun.go. When implementing a new +// adapter type, you should extend the adapter struct with this one and should +// call the Adapter.Init() function when initialising. type Adapter struct { adapterImplementation Core *Core + Config *config.NodeState + Log *log.Logger Send chan<- []byte Recv <-chan []byte Reject <-chan RejectedPacket @@ -31,11 +33,13 @@ type adapterImplementation interface { Close() error } -// Initialises the adapter with the necessary channels to operate from the +// Init initialises the adapter with the necessary channels to operate from the // router. When defining a new Adapter type, the Adapter should call this // function from within it's own Init function to set up the channels. It is // otherwise not expected for you to call this function directly. func (adapter *Adapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte, reject <-chan RejectedPacket) { + adapter.Config = config + adapter.Log = log adapter.Send = send adapter.Recv = recv adapter.Reject = reject From 90feae6a7d24124a01a2e32975851117e0328b97 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 1 Apr 2019 20:12:39 +0100 Subject: [PATCH 17/19] Comment out AWDL (doesn't work in iOS properly) and move out of main package --- src/{yggdrasil => mobile}/awdl.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) rename src/{yggdrasil => mobile}/awdl.go (98%) diff --git a/src/yggdrasil/awdl.go b/src/mobile/awdl.go similarity index 98% rename from src/yggdrasil/awdl.go rename to src/mobile/awdl.go index 5e8cce1..4fb4386 100644 --- a/src/yggdrasil/awdl.go +++ b/src/mobile/awdl.go @@ -1,4 +1,5 @@ -package yggdrasil +/* +package mobile import ( "errors" @@ -104,3 +105,4 @@ func (a *awdl) shutdown(identity string) error { } return errors.New("Interface not found or already closed") } +*/ From 2e72c7c93d9d9a6306d8b669a823cd395c057a44 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 1 Apr 2019 22:45:30 +0100 Subject: [PATCH 18/19] Fix mobile logging --- src/mobile/awdl.go | 2 +- src/mobile/mobile.go | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/mobile/awdl.go b/src/mobile/awdl.go index 4fb4386..9a073ef 100644 --- a/src/mobile/awdl.go +++ b/src/mobile/awdl.go @@ -1,6 +1,6 @@ -/* package mobile +/* import ( "errors" "io" diff --git a/src/mobile/mobile.go b/src/mobile/mobile.go index 5eec96e..02bd30f 100644 --- a/src/mobile/mobile.go +++ b/src/mobile/mobile.go @@ -49,6 +49,9 @@ func (m *Yggdrasil) addStaticPeers(cfg *config.NodeConfig) { // StartAutoconfigure starts a node with a randomly generated config func (m *Yggdrasil) StartAutoconfigure() error { logger := log.New(m.log, "", 0) + logger.EnableLevel("error") + logger.EnableLevel("warn") + logger.EnableLevel("info") nc := config.GenerateConfig() nc.IfName = "dummy" nc.AdminListen = "tcp://localhost:9001" @@ -62,6 +65,7 @@ func (m *Yggdrasil) StartAutoconfigure() error { } state, err := m.core.Start(nc, logger) if err != nil { + logger.Errorln("An error occured starting Yggdrasil:", err) return err } m.multicast.Init(&m.core, state, logger, nil) @@ -76,6 +80,9 @@ func (m *Yggdrasil) StartAutoconfigure() error { // (rather than HJSON) by using the GenerateConfigJSON() function func (m *Yggdrasil) StartJSON(configjson []byte) error { logger := log.New(m.log, "", 0) + logger.EnableLevel("error") + logger.EnableLevel("warn") + logger.EnableLevel("info") nc := config.GenerateConfig() var dat map[string]interface{} if err := hjson.Unmarshal(configjson, &dat); err != nil { @@ -91,6 +98,7 @@ func (m *Yggdrasil) StartJSON(configjson []byte) error { } state, err := m.core.Start(nc, logger) if err != nil { + logger.Errorln("An error occured starting Yggdrasil:", err) return err } m.multicast.Init(&m.core, state, logger, nil) From 9bc24f8dbfff90344f765c3a8ea3c965f537308f Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 15 Apr 2019 22:00:38 +0100 Subject: [PATCH 19/19] Return both current and previous config when replacing --- src/config/config.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/config/config.go b/src/config/config.go index 861e57a..8137cac 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -23,13 +23,14 @@ func (s *NodeState) Get() (NodeConfig, NodeConfig) { return s.Current, s.Previous } -// Replace the node configuration with new configuration -func (s *NodeState) Replace(n NodeConfig) NodeConfig { +// Replace the node configuration with new configuration. This method returns +// both the new and the previous node configs +func (s *NodeState) Replace(n NodeConfig) (NodeConfig, NodeConfig) { s.Mutex.Lock() defer s.Mutex.Unlock() s.Previous = s.Current s.Current = n - return s.Current + return s.Current, s.Previous } // NodeConfig defines all configuration values needed to run a signle yggdrasil node