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