2017-12-29 04:16:20 +00:00
|
|
|
package yggdrasil
|
|
|
|
|
2018-06-12 22:50:08 +00:00
|
|
|
import (
|
|
|
|
"encoding/hex"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"net"
|
|
|
|
"regexp"
|
|
|
|
|
|
|
|
"yggdrasil/config"
|
2018-07-07 11:08:52 +00:00
|
|
|
"yggdrasil/defaults"
|
2018-06-12 22:50:08 +00:00
|
|
|
)
|
2017-12-29 04:16:20 +00:00
|
|
|
|
2018-05-27 21:13:37 +00:00
|
|
|
// The Core object represents the Yggdrasil node. You should create a Core
|
|
|
|
// object for each Yggdrasil node you plan to run.
|
2017-12-29 04:16:20 +00:00
|
|
|
type Core struct {
|
2018-01-04 22:37:51 +00:00
|
|
|
// This is the main data structure that holds everything else for a node
|
|
|
|
boxPub boxPubKey
|
|
|
|
boxPriv boxPrivKey
|
|
|
|
sigPub sigPubKey
|
|
|
|
sigPriv sigPrivKey
|
|
|
|
switchTable switchTable
|
|
|
|
peers peers
|
|
|
|
sigs sigManager
|
|
|
|
sessions sessions
|
|
|
|
router router
|
|
|
|
dht dht
|
|
|
|
tun tunDevice
|
2018-01-21 00:17:15 +00:00
|
|
|
admin admin
|
2018-01-04 22:37:51 +00:00
|
|
|
searches searches
|
2018-05-23 10:13:53 +00:00
|
|
|
multicast multicast
|
2018-05-27 18:22:21 +00:00
|
|
|
tcp tcpInterface
|
2018-01-04 22:37:51 +00:00
|
|
|
log *log.Logger
|
2018-05-23 10:13:53 +00:00
|
|
|
ifceExpr []*regexp.Regexp // the zone of link-local IPv6 peers must match this
|
2017-12-29 04:16:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Core) init(bpub *boxPubKey,
|
2018-01-04 22:37:51 +00:00
|
|
|
bpriv *boxPrivKey,
|
|
|
|
spub *sigPubKey,
|
|
|
|
spriv *sigPrivKey) {
|
|
|
|
// TODO separate init and start functions
|
|
|
|
// Init sets up structs
|
|
|
|
// Start launches goroutines that depend on structs being set up
|
2018-01-26 23:30:51 +00:00
|
|
|
// This is pretty much required to completely avoid race conditions
|
2018-01-04 22:37:51 +00:00
|
|
|
util_initByteStore()
|
2018-05-27 21:13:37 +00:00
|
|
|
if c.log == nil {
|
|
|
|
c.log = log.New(ioutil.Discard, "", 0)
|
|
|
|
}
|
2018-01-04 22:37:51 +00:00
|
|
|
c.boxPub, c.boxPriv = *bpub, *bpriv
|
|
|
|
c.sigPub, c.sigPriv = *spub, *spriv
|
2018-05-07 00:48:26 +00:00
|
|
|
c.admin.core = c
|
2018-01-04 22:37:51 +00:00
|
|
|
c.sigs.init()
|
|
|
|
c.searches.init(c)
|
|
|
|
c.dht.init(c)
|
|
|
|
c.sessions.init(c)
|
2018-05-23 10:13:53 +00:00
|
|
|
c.multicast.init(c)
|
2018-01-04 22:37:51 +00:00
|
|
|
c.peers.init(c)
|
|
|
|
c.router.init(c)
|
|
|
|
c.switchTable.init(c, c.sigPub) // TODO move before peers? before router?
|
|
|
|
c.tun.init(c)
|
2017-12-29 04:16:20 +00:00
|
|
|
}
|
|
|
|
|
2018-05-27 21:13:37 +00:00
|
|
|
// Starts up Yggdrasil using the provided NodeConfig, and outputs debug logging
|
|
|
|
// through the provided log.Logger. The started stack will include TCP and UDP
|
|
|
|
// sockets, a multicast discovery socket, an admin socket, router, switch and
|
|
|
|
// DHT node.
|
|
|
|
func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error {
|
|
|
|
c.log = log
|
|
|
|
c.log.Println("Starting up...")
|
|
|
|
|
|
|
|
var boxPub boxPubKey
|
|
|
|
var boxPriv boxPrivKey
|
|
|
|
var sigPub sigPubKey
|
|
|
|
var sigPriv sigPrivKey
|
|
|
|
boxPubHex, err := hex.DecodeString(nc.EncryptionPublicKey)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
boxPrivHex, err := hex.DecodeString(nc.EncryptionPrivateKey)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
sigPubHex, err := hex.DecodeString(nc.SigningPublicKey)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
sigPrivHex, err := hex.DecodeString(nc.SigningPrivateKey)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
copy(boxPub[:], boxPubHex)
|
|
|
|
copy(boxPriv[:], boxPrivHex)
|
|
|
|
copy(sigPub[:], sigPubHex)
|
|
|
|
copy(sigPriv[:], sigPrivHex)
|
|
|
|
|
|
|
|
c.init(&boxPub, &boxPriv, &sigPub, &sigPriv)
|
|
|
|
c.admin.init(c, nc.AdminListen)
|
|
|
|
|
2018-07-29 14:30:13 +00:00
|
|
|
if err := c.tcp.init(c, nc.Listen, nc.ReadTimeout); err != nil {
|
2018-05-27 21:13:37 +00:00
|
|
|
c.log.Println("Failed to start TCP interface")
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-06-24 00:08:32 +00:00
|
|
|
if err := c.switchTable.start(); err != nil {
|
|
|
|
c.log.Println("Failed to start switch")
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-10-07 16:13:41 +00:00
|
|
|
c.sessions.setSessionFirewallState(nc.SessionFirewall.Enable)
|
2018-10-08 18:51:51 +00:00
|
|
|
c.sessions.setSessionFirewallDefaults(
|
|
|
|
nc.SessionFirewall.AllowFromDirect,
|
|
|
|
nc.SessionFirewall.AllowFromRemote,
|
|
|
|
nc.SessionFirewall.AlwaysAllowOutbound,
|
|
|
|
)
|
2018-10-07 16:13:41 +00:00
|
|
|
c.sessions.setSessionFirewallWhitelist(nc.SessionFirewall.WhitelistEncryptionPublicKeys)
|
|
|
|
c.sessions.setSessionFirewallBlacklist(nc.SessionFirewall.BlacklistEncryptionPublicKeys)
|
|
|
|
|
2018-05-27 21:13:37 +00:00
|
|
|
if err := c.router.start(); err != nil {
|
|
|
|
c.log.Println("Failed to start router")
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-11-06 12:32:16 +00:00
|
|
|
c.router.cryptokey.setEnabled(nc.TunnelRouting.Enable)
|
|
|
|
if c.router.cryptokey.isEnabled() {
|
2018-11-06 11:56:32 +00:00
|
|
|
c.log.Println("Crypto-key routing enabled")
|
2018-11-06 11:11:57 +00:00
|
|
|
for ipv6, pubkey := range nc.TunnelRouting.IPv6Destinations {
|
2018-11-05 16:40:47 +00:00
|
|
|
if err := c.router.cryptokey.addRoute(ipv6, pubkey); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
2018-11-06 00:05:01 +00:00
|
|
|
for _, source := range nc.TunnelRouting.IPv6Sources {
|
|
|
|
if c.router.cryptokey.addSourceSubnet(source); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
2018-11-05 16:40:47 +00:00
|
|
|
}
|
|
|
|
|
2018-05-27 21:13:37 +00:00
|
|
|
if err := c.admin.start(); err != nil {
|
|
|
|
c.log.Println("Failed to start admin socket")
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := c.multicast.start(); err != nil {
|
|
|
|
c.log.Println("Failed to start multicast interface")
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-05-27 21:35:30 +00:00
|
|
|
ip := net.IP(c.router.addr[:]).String()
|
2018-06-14 12:58:07 +00:00
|
|
|
if err := c.tun.start(nc.IfName, nc.IfTAPMode, fmt.Sprintf("%s/%d", ip, 8*len(address_prefix)-1), nc.IfMTU); err != nil {
|
2018-05-27 21:35:30 +00:00
|
|
|
c.log.Println("Failed to start TUN/TAP")
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-05-27 21:13:37 +00:00
|
|
|
c.log.Println("Startup complete")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stops the Yggdrasil node.
|
|
|
|
func (c *Core) Stop() {
|
|
|
|
c.log.Println("Stopping...")
|
|
|
|
c.tun.close()
|
2018-07-07 19:04:11 +00:00
|
|
|
c.admin.close()
|
2018-05-27 21:13:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Generates a new encryption keypair. The encryption keys are used to
|
|
|
|
// encrypt traffic and to derive the IPv6 address/subnet of the node.
|
|
|
|
func (c *Core) NewEncryptionKeys() (*boxPubKey, *boxPrivKey) {
|
|
|
|
return newBoxKeys()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generates a new signing keypair. The signing keys are used to derive the
|
|
|
|
// structure of the spanning tree.
|
|
|
|
func (c *Core) NewSigningKeys() (*sigPubKey, *sigPrivKey) {
|
|
|
|
return newSigKeys()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Gets the node ID.
|
2017-12-29 04:16:20 +00:00
|
|
|
func (c *Core) GetNodeID() *NodeID {
|
2018-01-04 22:37:51 +00:00
|
|
|
return getNodeID(&c.boxPub)
|
2017-12-29 04:16:20 +00:00
|
|
|
}
|
|
|
|
|
2018-05-27 21:13:37 +00:00
|
|
|
// Gets the tree ID.
|
2017-12-29 04:16:20 +00:00
|
|
|
func (c *Core) GetTreeID() *TreeID {
|
2018-01-04 22:37:51 +00:00
|
|
|
return getTreeID(&c.sigPub)
|
2017-12-29 04:16:20 +00:00
|
|
|
}
|
2018-05-21 15:15:31 +00:00
|
|
|
|
2018-05-27 21:13:37 +00:00
|
|
|
// Gets the IPv6 address of the Yggdrasil node. This is always a /128.
|
|
|
|
func (c *Core) GetAddress() *net.IP {
|
|
|
|
address := net.IP(address_addrForNodeID(c.GetNodeID())[:])
|
|
|
|
return &address
|
|
|
|
}
|
|
|
|
|
|
|
|
// Gets the routed IPv6 subnet of the Yggdrasil node. This is always a /64.
|
|
|
|
func (c *Core) GetSubnet() *net.IPNet {
|
|
|
|
subnet := address_subnetForNodeID(c.GetNodeID())[:]
|
|
|
|
subnet = append(subnet, 0, 0, 0, 0, 0, 0, 0, 0)
|
2018-06-02 20:21:05 +00:00
|
|
|
return &net.IPNet{IP: subnet, Mask: net.CIDRMask(64, 128)}
|
2018-05-27 21:13:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
2018-09-25 15:55:57 +00:00
|
|
|
func (c *Core) AddPeer(addr string, sintf string) error {
|
|
|
|
return c.admin.addPeer(addr, sintf)
|
2018-05-27 21:13:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Adds an expression to select multicast interfaces for peer discovery. This
|
|
|
|
// should be done before calling Start. This function can be called multiple
|
|
|
|
// times to add multiple search expressions.
|
|
|
|
func (c *Core) AddMulticastInterfaceExpr(expr *regexp.Regexp) {
|
|
|
|
c.ifceExpr = append(c.ifceExpr, expr)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Adds an allowed public key. This allow peerings to be restricted only to
|
|
|
|
// keys that you have selected.
|
|
|
|
func (c *Core) AddAllowedEncryptionPublicKey(boxStr string) error {
|
|
|
|
return c.admin.addAllowedEncryptionPublicKey(boxStr)
|
|
|
|
}
|
|
|
|
|
2018-07-07 11:08:52 +00:00
|
|
|
// Gets the default admin listen address for your platform.
|
|
|
|
func (c *Core) GetAdminDefaultListen() string {
|
|
|
|
return defaults.GetDefaults().DefaultAdminListen
|
|
|
|
}
|
|
|
|
|
2018-05-27 21:13:37 +00:00
|
|
|
// Gets the default TUN/TAP interface name for your platform.
|
|
|
|
func (c *Core) GetTUNDefaultIfName() string {
|
2018-07-07 11:08:52 +00:00
|
|
|
return defaults.GetDefaults().DefaultIfName
|
2018-05-27 21:13:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
2018-07-07 11:08:52 +00:00
|
|
|
return defaults.GetDefaults().DefaultIfMTU
|
2018-05-27 21:13:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
2018-07-07 11:08:52 +00:00
|
|
|
return defaults.GetDefaults().MaximumIfMTU
|
2018-05-27 21:13:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Gets the default TUN/TAP interface mode for your platform.
|
|
|
|
func (c *Core) GetTUNDefaultIfTAPMode() bool {
|
2018-07-07 11:08:52 +00:00
|
|
|
return defaults.GetDefaults().DefaultIfTAPMode
|
2018-05-27 21:13:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Gets the current TUN/TAP interface name.
|
|
|
|
func (c *Core) GetTUNIfName() string {
|
|
|
|
return c.tun.iface.Name()
|
2018-05-21 15:15:31 +00:00
|
|
|
}
|
|
|
|
|
2018-05-27 21:13:37 +00:00
|
|
|
// Gets the current TUN/TAP interface MTU.
|
|
|
|
func (c *Core) GetTUNIfMTU() int {
|
|
|
|
return c.tun.mtu
|
2018-05-21 15:15:31 +00:00
|
|
|
}
|