diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 8c8340f0..cec77056 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 a9007585..861e57ac 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 52ca50c6..f4f9efe8 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 465cbb1c..7dab31c8 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 81e2c46c..95c13afc 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 7ec1b8b9..5dfca137 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 234ab1de..04e65257 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 30ada235..051287ee 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 07ec25fd..17dfa2b4 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 1c89a437..f5cebe55 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 3ce80d2b..7437eb0a 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 a0854f22..002f974c 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 03bc5718..dc4f1b90 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 12ff14fc..a583d582 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 ca3a1f75..ab1b158e 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 ce359368..06201f9b 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 1d4c0771..04f5ee51 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 012af579..b3563e05 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 490b15f3..0e164b9a 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 8acf9c17..f25ac412 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 }