mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-22 15:20:30 +00:00
Merge pull request #96 from neilalexander/dedebug
Create Core API, remove DEBUG function calls
This commit is contained in:
commit
742eded4ff
@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
export GOPATH=$PWD
|
||||
go get -d yggdrasil
|
||||
go run misc/sim/treesim.go
|
||||
go run -tags debug misc/sim/treesim.go
|
||||
|
@ -213,7 +213,11 @@ func (a *admin) init(c *Core, listenaddr string) {
|
||||
}, errors.New("Failed to remove allowed box pub key")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (a *admin) start() error {
|
||||
go a.listen()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *admin) listen() {
|
||||
@ -356,11 +360,11 @@ func (a *admin) addPeer(addr string) error {
|
||||
if err == nil {
|
||||
switch strings.ToLower(u.Scheme) {
|
||||
case "tcp":
|
||||
a.core.DEBUG_addTCPConn(u.Host)
|
||||
a.core.tcp.connect(u.Host)
|
||||
case "udp":
|
||||
a.core.DEBUG_maybeSendUDPKeys(u.Host)
|
||||
a.core.udp.connect(u.Host)
|
||||
case "socks":
|
||||
a.core.DEBUG_addSOCKSConn(u.Host, u.Path[1:])
|
||||
a.core.tcp.connectSOCKS(u.Host, u.Path[1:])
|
||||
default:
|
||||
return errors.New("invalid peer: " + addr)
|
||||
}
|
||||
@ -368,13 +372,13 @@ func (a *admin) addPeer(addr string) error {
|
||||
// no url scheme provided
|
||||
addr = strings.ToLower(addr)
|
||||
if strings.HasPrefix(addr, "udp:") {
|
||||
a.core.DEBUG_maybeSendUDPKeys(addr[4:])
|
||||
a.core.udp.connect(addr[4:])
|
||||
return nil
|
||||
} else {
|
||||
if strings.HasPrefix(addr, "tcp:") {
|
||||
addr = addr[4:]
|
||||
}
|
||||
a.core.DEBUG_addTCPConn(addr)
|
||||
a.core.tcp.connect(addr)
|
||||
return nil
|
||||
}
|
||||
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 {
|
||||
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()
|
||||
self := admin_nodeInfo{
|
||||
{"ip", net.IP(addr[:]).String()},
|
||||
{"subnet", fmt.Sprintf("%s/64", net.IP(subnet[:]).String())},
|
||||
{"ip", a.core.GetAddress().String()},
|
||||
{"subnet", a.core.GetSubnet().String()},
|
||||
{"coords", fmt.Sprint(coords)},
|
||||
}
|
||||
return &self
|
||||
|
@ -3,7 +3,13 @@ package yggdrasil
|
||||
import "io/ioutil"
|
||||
import "log"
|
||||
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 {
|
||||
// This is the main data structure that holds everything else for a node
|
||||
boxPub boxPubKey
|
||||
@ -26,13 +32,6 @@ type Core struct {
|
||||
ifceExpr []*regexp.Regexp // the zone of link-local IPv6 peers must match this
|
||||
}
|
||||
|
||||
func (c *Core) Init() {
|
||||
// Only called by the simulator, to set up nodes with random keys
|
||||
bpub, bpriv := newBoxKeys()
|
||||
spub, spriv := newSigKeys()
|
||||
c.init(bpub, bpriv, spub, spriv)
|
||||
}
|
||||
|
||||
func (c *Core) init(bpub *boxPubKey,
|
||||
bpriv *boxPrivKey,
|
||||
spub *sigPubKey,
|
||||
@ -42,7 +41,9 @@ func (c *Core) init(bpub *boxPubKey,
|
||||
// Start launches goroutines that depend on structs being set up
|
||||
// This is pretty much required to completely avoid race conditions
|
||||
util_initByteStore()
|
||||
c.log = log.New(ioutil.Discard, "", 0)
|
||||
if c.log == nil {
|
||||
c.log = log.New(ioutil.Discard, "", 0)
|
||||
}
|
||||
c.boxPub, c.boxPriv = *bpub, *bpriv
|
||||
c.sigPub, c.sigPriv = *spub, *spriv
|
||||
c.admin.core = c
|
||||
@ -57,18 +58,176 @@ func (c *Core) init(bpub *boxPubKey,
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
ip := net.IP(c.router.addr[:]).String()
|
||||
if err := c.tun.start(nc.IfName, nc.IfTAPMode, fmt.Sprintf("%s/8", ip), nc.IfMTU); err != nil {
|
||||
c.log.Println("Failed to start TUN/TAP")
|
||||
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 {
|
||||
return getNodeID(&c.boxPub)
|
||||
}
|
||||
|
||||
// Gets the tree ID.
|
||||
func (c *Core) GetTreeID() *TreeID {
|
||||
return getTreeID(&c.sigPub)
|
||||
}
|
||||
|
||||
func (c *Core) GetAddress() *address {
|
||||
return address_addrForNodeID(c.GetNodeID())
|
||||
// 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
|
||||
}
|
||||
|
||||
func (c *Core) GetSubnet() *subnet {
|
||||
return address_subnetForNodeID(c.GetNodeID())
|
||||
// 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)
|
||||
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
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
// +build debug
|
||||
|
||||
package yggdrasil
|
||||
|
||||
// These are functions that should not exist
|
||||
@ -15,6 +17,28 @@ import "net"
|
||||
import "log"
|
||||
import "regexp"
|
||||
|
||||
import _ "net/http/pprof"
|
||||
import "net/http"
|
||||
import "runtime"
|
||||
|
||||
// Starts the function profiler. This is only supported when built with
|
||||
// '-tags build'.
|
||||
func StartProfiler(log *log.Logger) error {
|
||||
runtime.SetBlockProfileRate(1)
|
||||
go func() { log.Println(http.ListenAndServe("localhost:6060", nil)) }()
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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() {
|
||||
bpub, bpriv := newBoxKeys()
|
||||
spub, spriv := newSigKeys()
|
||||
c.init(bpub, bpriv, spub, spriv)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Core
|
||||
|
||||
func (c *Core) DEBUG_getSigningPublicKey() sigPubKey {
|
||||
@ -279,6 +303,14 @@ func (c *Core) DEBUG_init(bpub []byte,
|
||||
copy(sigPub[:], spub)
|
||||
copy(sigPriv[:], spriv)
|
||||
c.init(&boxPub, &boxPriv, &sigPub, &sigPriv)
|
||||
|
||||
if err := c.router.start(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := c.switchTable.start(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -432,3 +464,28 @@ func DEBUG_simLinkPeers(p, q *peer) {
|
||||
func (c *Core) DEBUG_simFixMTU() {
|
||||
c.tun.mtu = 65535
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
func Util_testAddrIDMask() {
|
||||
for idx := 0; idx < 16; idx++ {
|
||||
var orig NodeID
|
||||
orig[8] = 42
|
||||
for bidx := 0; bidx < idx; bidx++ {
|
||||
orig[bidx/8] |= (0x80 >> uint8(bidx%8))
|
||||
}
|
||||
addr := address_addrForNodeID(&orig)
|
||||
nid, mask := addr.getNodeIDandMask()
|
||||
for b := 0; b < len(mask); b++ {
|
||||
nid[b] &= mask[b]
|
||||
orig[b] &= mask[b]
|
||||
}
|
||||
if *nid != orig {
|
||||
fmt.Println(orig)
|
||||
fmt.Println(*addr)
|
||||
fmt.Println(*nid)
|
||||
fmt.Println(*mask)
|
||||
panic(idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import "errors"
|
||||
|
||||
type macAddress [6]byte
|
||||
|
||||
const ETHER = 14
|
||||
const len_ETHER = 14
|
||||
|
||||
type icmpv6 struct {
|
||||
tun *tunDevice
|
||||
@ -79,13 +79,13 @@ func (i *icmpv6) parse_packet_tap(datain []byte) ([]byte, error) {
|
||||
}
|
||||
|
||||
// Hand over to parse_packet_tun to interpret the IPv6 packet
|
||||
ipv6packet, err := i.parse_packet_tun(datain[ETHER:])
|
||||
ipv6packet, err := i.parse_packet_tun(datain[len_ETHER:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create the response buffer
|
||||
dataout := make([]byte, ETHER+ipv6.HeaderLen+32)
|
||||
dataout := make([]byte, len_ETHER+ipv6.HeaderLen+32)
|
||||
|
||||
// Populate the response ethernet headers
|
||||
copy(dataout[:6], datain[6:12])
|
||||
@ -93,7 +93,7 @@ func (i *icmpv6) parse_packet_tap(datain []byte) ([]byte, error) {
|
||||
binary.BigEndian.PutUint16(dataout[12:14], uint16(0x86DD))
|
||||
|
||||
// Copy the returned packet to our response ethernet frame
|
||||
copy(dataout[ETHER:], ipv6packet)
|
||||
copy(dataout[len_ETHER:], ipv6packet)
|
||||
return dataout, nil
|
||||
}
|
||||
|
||||
@ -157,7 +157,7 @@ func (i *icmpv6) create_icmpv6_tap(dstmac macAddress, dst net.IP, src net.IP, mt
|
||||
}
|
||||
|
||||
// Create the response buffer
|
||||
dataout := make([]byte, ETHER+len(ipv6packet))
|
||||
dataout := make([]byte, len_ETHER+len(ipv6packet))
|
||||
|
||||
// Populate the response ethernet headers
|
||||
copy(dataout[:6], dstmac[:6])
|
||||
@ -165,7 +165,7 @@ func (i *icmpv6) create_icmpv6_tap(dstmac macAddress, dst net.IP, src net.IP, mt
|
||||
binary.BigEndian.PutUint16(dataout[12:14], uint16(0x86DD))
|
||||
|
||||
// Copy the returned packet to our response ethernet frame
|
||||
copy(dataout[ETHER:], ipv6packet)
|
||||
copy(dataout[len_ETHER:], ipv6packet)
|
||||
return dataout, nil
|
||||
}
|
||||
|
||||
|
@ -48,19 +48,19 @@ func (m *multicast) init(core *Core) {
|
||||
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 {
|
||||
m.core.log.Println("Multicast discovery is disabled")
|
||||
} else {
|
||||
m.core.log.Println("Multicast discovery is enabled")
|
||||
addr, err := net.ResolveUDPAddr("udp", m.groupAddr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
listenString := fmt.Sprintf("[::]:%v", addr.Port)
|
||||
conn, err := net.ListenPacket("udp6", listenString)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
//defer conn.Close() // Let it close on its own when the application exits
|
||||
m.sock = ipv6.NewPacketConn(conn)
|
||||
@ -72,6 +72,7 @@ func (m *multicast) start() {
|
||||
go m.listen()
|
||||
go m.announce()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *multicast) announce() {
|
||||
@ -80,7 +81,7 @@ func (m *multicast) announce() {
|
||||
panic(err)
|
||||
}
|
||||
var anAddr net.TCPAddr
|
||||
myAddr := m.core.DEBUG_getGlobalTCPAddr()
|
||||
myAddr := m.core.tcp.getAddr()
|
||||
anAddr.Port = myAddr.Port
|
||||
destAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr)
|
||||
if err != nil {
|
||||
@ -155,7 +156,7 @@ func (m *multicast) listen() {
|
||||
saddr := addr.String()
|
||||
//if _, isIn := n.peers[saddr]; isIn { continue }
|
||||
//n.peers[saddr] = struct{}{}
|
||||
m.core.DEBUG_addTCPConn(saddr)
|
||||
m.core.tcp.connect(saddr)
|
||||
//fmt.Println("DEBUG:", "added multicast peer:", saddr)
|
||||
}
|
||||
}
|
||||
|
12
src/yggdrasil/release.go
Normal file
12
src/yggdrasil/release.go
Normal file
@ -0,0 +1,12 @@
|
||||
// +build !debug
|
||||
|
||||
package yggdrasil
|
||||
|
||||
import "errors"
|
||||
import "log"
|
||||
|
||||
// Starts the function profiler. This is only supported when built with
|
||||
// '-tags build'.
|
||||
func StartProfiler(_ *log.Logger) error {
|
||||
return errors.New("Release builds do not support -pprof, build using '-tags debug'")
|
||||
}
|
@ -64,7 +64,13 @@ func (r *router) init(core *Core) {
|
||||
r.core.tun.send = send
|
||||
r.reset = make(chan struct{}, 1)
|
||||
r.admin = make(chan func())
|
||||
// go r.mainLoop()
|
||||
}
|
||||
|
||||
func (r *router) start() error {
|
||||
r.core.log.Println("Starting router")
|
||||
go r.mainLoop()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *router) mainLoop() {
|
||||
|
@ -167,6 +167,9 @@ func (t *switchTable) init(core *Core, key sigPubKey) {
|
||||
t.updater.Store(&sync.Once{})
|
||||
t.table.Store(lookupTable{})
|
||||
t.drop = make(map[sigPubKey]int64)
|
||||
}
|
||||
|
||||
func (t *switchTable) start() error {
|
||||
doTicker := func() {
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
@ -176,6 +179,7 @@ func (t *switchTable) init(core *Core, key sigPubKey) {
|
||||
}
|
||||
}
|
||||
go doTicker()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *switchTable) getLocator() switchLocator {
|
||||
|
@ -16,6 +16,7 @@ import "errors"
|
||||
import "sync"
|
||||
import "fmt"
|
||||
import "bufio"
|
||||
import "golang.org/x/net/proxy"
|
||||
|
||||
const tcp_msgSize = 2048 + 65535 // TODO figure out what makes sense
|
||||
|
||||
@ -42,6 +43,32 @@ type tcpInfo struct {
|
||||
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) {
|
||||
iface.core = core
|
||||
|
||||
@ -51,7 +78,8 @@ func (iface *tcpInterface) init(core *Core, addr string) (err error) {
|
||||
iface.conns = make(map[tcpInfo](chan struct{}))
|
||||
go iface.listener()
|
||||
}
|
||||
return
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (iface *tcpInterface) listener() {
|
||||
@ -274,12 +302,14 @@ func (iface *tcpInterface) reader(sock net.Conn, in func([]byte)) {
|
||||
sock.SetReadDeadline(timeout)
|
||||
n, err := sock.Read(bs[len(frag):])
|
||||
if err != nil || n == 0 {
|
||||
// iface.core.log.Println(err)
|
||||
break
|
||||
}
|
||||
frag = bs[:len(frag)+n]
|
||||
for {
|
||||
msg, ok, err := tcp_chop_msg(&frag)
|
||||
if err != nil {
|
||||
// iface.core.log.Println(err)
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
|
@ -5,8 +5,8 @@ package yggdrasil
|
||||
import "github.com/songgao/packets/ethernet"
|
||||
import "github.com/yggdrasil-network/water"
|
||||
|
||||
const IPv6_HEADER_LENGTH = 40
|
||||
const ETHER_HEADER_LENGTH = 14
|
||||
const tun_IPv6_HEADER_LENGTH = 40
|
||||
const tun_ETHER_HEADER_LENGTH = 14
|
||||
|
||||
type tunDevice struct {
|
||||
core *Core
|
||||
@ -36,6 +36,15 @@ func (tun *tunDevice) init(core *Core) {
|
||||
tun.icmpv6.init(tun)
|
||||
}
|
||||
|
||||
func (tun *tunDevice) start(ifname string, iftapmode bool, addr string, mtu int) error {
|
||||
if err := tun.setup(ifname, iftapmode, addr, mtu); err != nil {
|
||||
return err
|
||||
}
|
||||
go func() { panic(tun.read()) }()
|
||||
go func() { panic(tun.write()) }()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tun *tunDevice) write() error {
|
||||
for {
|
||||
data := <-tun.recv
|
||||
@ -50,7 +59,7 @@ func (tun *tunDevice) write() error {
|
||||
ethernet.NotTagged, // VLAN tagging
|
||||
ethernet.IPv6, // Ethertype
|
||||
len(data)) // Payload length
|
||||
copy(frame[ETHER_HEADER_LENGTH:], data[:])
|
||||
copy(frame[tun_ETHER_HEADER_LENGTH:], data[:])
|
||||
if _, err := tun.iface.Write(frame); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -66,7 +75,7 @@ func (tun *tunDevice) write() error {
|
||||
func (tun *tunDevice) read() error {
|
||||
mtu := tun.mtu
|
||||
if tun.iface.IsTAP() {
|
||||
mtu += ETHER_HEADER_LENGTH
|
||||
mtu += tun_ETHER_HEADER_LENGTH
|
||||
}
|
||||
buf := make([]byte, mtu)
|
||||
for {
|
||||
@ -77,10 +86,10 @@ func (tun *tunDevice) read() error {
|
||||
}
|
||||
o := 0
|
||||
if tun.iface.IsTAP() {
|
||||
o = ETHER_HEADER_LENGTH
|
||||
o = tun_ETHER_HEADER_LENGTH
|
||||
}
|
||||
if buf[o]&0xf0 != 0x60 ||
|
||||
n != 256*int(buf[o+4])+int(buf[o+5])+IPv6_HEADER_LENGTH+o {
|
||||
n != 256*int(buf[o+4])+int(buf[o+5])+tun_IPv6_HEADER_LENGTH+o {
|
||||
// Either not an IPv6 packet or not the complete packet for some reason
|
||||
//panic("Should not happen in testing")
|
||||
continue
|
||||
|
@ -33,7 +33,7 @@ func (tun *tunDevice) setup(ifname string, iftapmode bool, addr string, mtu int)
|
||||
return tun.setupAddress(addr)
|
||||
}
|
||||
|
||||
const SIOCAIFADDR_IN6 = 2155899162
|
||||
const darwin_SIOCAIFADDR_IN6 = 2155899162
|
||||
|
||||
type in6_addrlifetime struct {
|
||||
ia6t_expire float64
|
||||
@ -103,9 +103,9 @@ func (tun *tunDevice) setupAddress(addr string) error {
|
||||
tun.core.log.Printf("Interface IPv6: %s", addr)
|
||||
tun.core.log.Printf("Interface MTU: %d", ir.ifru_mtu)
|
||||
|
||||
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(SIOCAIFADDR_IN6), uintptr(unsafe.Pointer(&ar))); errno != 0 {
|
||||
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(darwin_SIOCAIFADDR_IN6), uintptr(unsafe.Pointer(&ar))); errno != 0 {
|
||||
err = errno
|
||||
tun.core.log.Printf("Error in SIOCAIFADDR_IN6: %v", errno)
|
||||
tun.core.log.Printf("Error in darwin_SIOCAIFADDR_IN6: %v", errno)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -65,6 +65,25 @@ type udpKeys struct {
|
||||
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) {
|
||||
iface.core = core
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
||||
|
@ -2,34 +2,10 @@ package yggdrasil
|
||||
|
||||
// These are misc. utility functions that didn't really fit anywhere else
|
||||
|
||||
import "fmt"
|
||||
import "runtime"
|
||||
|
||||
//import "sync"
|
||||
|
||||
func Util_testAddrIDMask() {
|
||||
for idx := 0; idx < 16; idx++ {
|
||||
var orig NodeID
|
||||
orig[8] = 42
|
||||
for bidx := 0; bidx < idx; bidx++ {
|
||||
orig[bidx/8] |= (0x80 >> uint8(bidx%8))
|
||||
}
|
||||
addr := address_addrForNodeID(&orig)
|
||||
nid, mask := addr.getNodeIDandMask()
|
||||
for b := 0; b < len(mask); b++ {
|
||||
nid[b] &= mask[b]
|
||||
orig[b] &= mask[b]
|
||||
}
|
||||
if *nid != orig {
|
||||
fmt.Println(orig)
|
||||
fmt.Println(*addr)
|
||||
fmt.Println(*nid)
|
||||
fmt.Println(*mask)
|
||||
panic(idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func util_yield() {
|
||||
runtime.Gosched()
|
||||
}
|
||||
|
206
yggdrasil.go
206
yggdrasil.go
@ -5,18 +5,13 @@ import "encoding/hex"
|
||||
import "flag"
|
||||
import "fmt"
|
||||
import "io/ioutil"
|
||||
import "net"
|
||||
import "os"
|
||||
import "os/signal"
|
||||
import "syscall"
|
||||
import "time"
|
||||
import "regexp"
|
||||
import "math/rand"
|
||||
|
||||
import _ "net/http/pprof"
|
||||
import "net/http"
|
||||
import "log"
|
||||
import "runtime"
|
||||
|
||||
import "yggdrasil"
|
||||
import "yggdrasil/config"
|
||||
@ -32,63 +27,20 @@ type node struct {
|
||||
core Core
|
||||
}
|
||||
|
||||
func (n *node) init(cfg *nodeConfig, logger *log.Logger) {
|
||||
boxPub, err := hex.DecodeString(cfg.EncryptionPublicKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
boxPriv, err := hex.DecodeString(cfg.EncryptionPrivateKey)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Generates default configuration. This is used when outputting the -genconf
|
||||
// parameter and also when using -autoconf. The isAutoconf flag is used to
|
||||
// determine whether the operating system should select a free port by itself
|
||||
// (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
|
||||
// isAutoconf is that the TCP and UDP ports will likely end up with different
|
||||
// port numbers.
|
||||
func generateConfig(isAutoconf bool) *nodeConfig {
|
||||
// Create a new core.
|
||||
core := Core{}
|
||||
bpub, bpriv := core.DEBUG_newBoxKeys()
|
||||
spub, spriv := core.DEBUG_newSigKeys()
|
||||
// Generate encryption keys.
|
||||
bpub, bpriv := core.NewEncryptionKeys()
|
||||
spub, spriv := core.NewSigningKeys()
|
||||
// Create a node configuration and populate it.
|
||||
cfg := nodeConfig{}
|
||||
if isAutoconf {
|
||||
cfg.Listen = "[::]:0"
|
||||
@ -104,13 +56,15 @@ func generateConfig(isAutoconf bool) *nodeConfig {
|
||||
cfg.Peers = []string{}
|
||||
cfg.AllowedEncryptionPublicKeys = []string{}
|
||||
cfg.MulticastInterfaces = []string{".*"}
|
||||
cfg.IfName = core.DEBUG_GetTUNDefaultIfName()
|
||||
cfg.IfMTU = core.DEBUG_GetTUNDefaultIfMTU()
|
||||
cfg.IfTAPMode = core.DEBUG_GetTUNDefaultIfTAPMode()
|
||||
cfg.IfName = core.GetTUNDefaultIfName()
|
||||
cfg.IfMTU = core.GetTUNDefaultIfMTU()
|
||||
cfg.IfTAPMode = core.GetTUNDefaultIfTAPMode()
|
||||
|
||||
return &cfg
|
||||
}
|
||||
|
||||
// Generates a new configuration and returns it in HJSON format. This is used
|
||||
// with -genconf.
|
||||
func doGenconf() string {
|
||||
cfg := generateConfig(false)
|
||||
bs, err := hjson.Marshal(cfg)
|
||||
@ -120,30 +74,43 @@ func doGenconf() string {
|
||||
return string(bs)
|
||||
}
|
||||
|
||||
var pprof = flag.Bool("pprof", false, "Run pprof, see http://localhost:6060/debug/pprof/")
|
||||
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)")
|
||||
|
||||
// The main function is responsible for configuring and starting Yggdrasil.
|
||||
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()
|
||||
|
||||
var cfg *nodeConfig
|
||||
switch {
|
||||
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)
|
||||
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 err error
|
||||
if *useconffile != "" {
|
||||
// Read the file from the filesystem
|
||||
config, err = ioutil.ReadFile(*useconffile)
|
||||
} else {
|
||||
// Read the file from stdin.
|
||||
config, err = ioutil.ReadAll(os.Stdin)
|
||||
}
|
||||
if err != nil {
|
||||
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)
|
||||
var dat map[string]interface{}
|
||||
if err := hjson.Unmarshal(config, &dat); err != nil {
|
||||
@ -155,7 +122,8 @@ func main() {
|
||||
}
|
||||
json.Unmarshal(confJson, &cfg)
|
||||
// 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{
|
||||
"Multicast": "",
|
||||
"LinkLocal": "MulticastInterfaces",
|
||||
@ -165,6 +133,7 @@ func main() {
|
||||
"SigPriv": "SigningPrivateKey",
|
||||
"AllowedBoxPubs": "AllowedEncryptionPublicKeys",
|
||||
}
|
||||
// Loop over the mappings aove and see if we have anything to fix.
|
||||
for from, to := range changes {
|
||||
if _, ok := dat[from]; ok {
|
||||
if to == "" {
|
||||
@ -175,15 +144,24 @@ func main() {
|
||||
if !*normaliseconf {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
bs, err := hjson.Marshal(cfg)
|
||||
if err != nil {
|
||||
@ -193,48 +171,86 @@ func main() {
|
||||
return
|
||||
}
|
||||
case *genconf:
|
||||
// Generate a new configuration and print it to stdout.
|
||||
fmt.Println(doGenconf())
|
||||
default:
|
||||
// No flags were provided, therefore print the list of flags to stdout.
|
||||
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 {
|
||||
return
|
||||
}
|
||||
// Create a new logger that logs output to stdout.
|
||||
logger := log.New(os.Stdout, "", log.Flags())
|
||||
// If the -pprof flag was provided then start the pprof service on port 6060.
|
||||
if *pprof {
|
||||
runtime.SetBlockProfileRate(1)
|
||||
go func() { log.Println(http.ListenAndServe("localhost:6060", nil)) }()
|
||||
if err := yggdrasil.StartProfiler(logger); err != nil {
|
||||
logger.Println(err)
|
||||
}
|
||||
}
|
||||
// Setup
|
||||
logger.Println("Initializing...")
|
||||
// Setup the Yggdrasil node itself. The node{} type includes a Core, so we
|
||||
// don't need to create this manually.
|
||||
n := node{}
|
||||
n.init(cfg, logger)
|
||||
if cfg.IfName != "none" {
|
||||
logger.Println("Starting TUN/TAP...")
|
||||
} else {
|
||||
logger.Println("Not starting TUN/TAP")
|
||||
// Check to see if any allowed encryption keys were provided in the config.
|
||||
// If they were then set them now.
|
||||
for _, pBoxStr := range cfg.AllowedEncryptionPublicKeys {
|
||||
n.core.AddAllowedEncryptionPublicKey(pBoxStr)
|
||||
}
|
||||
//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()
|
||||
// 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)
|
||||
}
|
||||
}()
|
||||
logger.Println("Started...")
|
||||
address := (*n.core.GetAddress())[:]
|
||||
subnet := (*n.core.GetSubnet())[:]
|
||||
subnet = append(subnet, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
logger.Printf("Your IPv6 address is %s", net.IP(address).String())
|
||||
logger.Printf("Your IPv6 subnet is %s/64", net.IP(subnet).String())
|
||||
// Catch interrupt to exit gracefully
|
||||
// The Stop function ensures that the TUN/TAP adapter is correctly shut down
|
||||
// before the program exits.
|
||||
defer func() {
|
||||
n.core.Stop()
|
||||
}()
|
||||
// Make some nice output that tells us what our IPv6 address and subnet are.
|
||||
// This is just logged to stdout for the user.
|
||||
address := n.core.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)
|
||||
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() {
|
||||
c <- os.Interrupt
|
||||
}
|
||||
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
|
||||
logger.Println("Stopping...")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user