mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-10 09:50:27 +00:00
Merge pull request #474 from neilalexander/gomobile
Various API changes and simplifications to fix mobile builds
This commit is contained in:
commit
7c4c1558ff
8
build
8
build
@ -31,14 +31,14 @@ if [ $IOS ]; then
|
|||||||
echo "Building framework for iOS"
|
echo "Building framework for iOS"
|
||||||
gomobile bind -target ios -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" \
|
gomobile bind -target ios -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" \
|
||||||
github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil \
|
github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil \
|
||||||
github.com/yggdrasil-network/yggdrasil-go/src/mobile \
|
github.com/yggdrasil-network/yggdrasil-go/src/config \
|
||||||
github.com/yggdrasil-network/yggdrasil-go/src/config
|
github.com/yggdrasil-network/yggdrasil-extras/src/mobile
|
||||||
elif [ $ANDROID ]; then
|
elif [ $ANDROID ]; then
|
||||||
echo "Building aar for Android"
|
echo "Building aar for Android"
|
||||||
gomobile bind -target android -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" \
|
gomobile bind -target android -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" \
|
||||||
github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil \
|
github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil \
|
||||||
github.com/yggdrasil-network/yggdrasil-go/src/mobile \
|
github.com/yggdrasil-network/yggdrasil-go/src/config \
|
||||||
github.com/yggdrasil-network/yggdrasil-go/src/config
|
github.com/yggdrasil-network/yggdrasil-extras/src/mobile
|
||||||
else
|
else
|
||||||
for CMD in `ls cmd/` ; do
|
for CMD in `ls cmd/` ; do
|
||||||
echo "Building: $CMD"
|
echo "Building: $CMD"
|
||||||
|
@ -60,7 +60,7 @@ func (a *AdminSocket) Init(c *yggdrasil.Core, state *config.NodeState, log *log.
|
|||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
e := <-a.reconfigure
|
e := <-a.reconfigure
|
||||||
current, previous := state.Get()
|
current, previous := state.GetCurrent(), state.GetPrevious()
|
||||||
if current.AdminListen != previous.AdminListen {
|
if current.AdminListen != previous.AdminListen {
|
||||||
a.listenaddr = current.AdminListen
|
a.listenaddr = current.AdminListen
|
||||||
a.Stop()
|
a.Stop()
|
||||||
@ -69,7 +69,7 @@ func (a *AdminSocket) Init(c *yggdrasil.Core, state *config.NodeState, log *log.
|
|||||||
e <- nil
|
e <- nil
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
current, _ := state.Get()
|
current := state.GetCurrent()
|
||||||
a.listenaddr = current.AdminListen
|
a.listenaddr = current.AdminListen
|
||||||
a.AddHandler("list", []string{}, func(in Info) (Info, error) {
|
a.AddHandler("list", []string{}, func(in Info) (Info, error) {
|
||||||
handlers := make(map[string]interface{})
|
handlers := make(map[string]interface{})
|
||||||
@ -85,14 +85,15 @@ func (a *AdminSocket) Init(c *yggdrasil.Core, state *config.NodeState, log *log.
|
|||||||
*/
|
*/
|
||||||
a.AddHandler("getSelf", []string{}, func(in Info) (Info, error) {
|
a.AddHandler("getSelf", []string{}, func(in Info) (Info, error) {
|
||||||
ip := c.Address().String()
|
ip := c.Address().String()
|
||||||
|
subnet := c.Subnet()
|
||||||
return Info{
|
return Info{
|
||||||
"self": Info{
|
"self": Info{
|
||||||
ip: Info{
|
ip: Info{
|
||||||
"box_pub_key": c.BoxPubKey(),
|
"box_pub_key": c.EncryptionPublicKey(),
|
||||||
"build_name": yggdrasil.BuildName(),
|
"build_name": yggdrasil.BuildName(),
|
||||||
"build_version": yggdrasil.BuildVersion(),
|
"build_version": yggdrasil.BuildVersion(),
|
||||||
"coords": fmt.Sprintf("%v", c.Coords()),
|
"coords": fmt.Sprintf("%v", c.Coords()),
|
||||||
"subnet": c.Subnet().String(),
|
"subnet": subnet.String(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -16,21 +16,27 @@ type NodeState struct {
|
|||||||
Mutex sync.RWMutex
|
Mutex sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns both the current and previous node configs
|
// Current returns the current node config
|
||||||
func (s *NodeState) Get() (NodeConfig, NodeConfig) {
|
func (s *NodeState) GetCurrent() NodeConfig {
|
||||||
s.Mutex.RLock()
|
s.Mutex.RLock()
|
||||||
defer s.Mutex.RUnlock()
|
defer s.Mutex.RUnlock()
|
||||||
return s.Current, s.Previous
|
return s.Current
|
||||||
|
}
|
||||||
|
|
||||||
|
// Previous returns the previous node config
|
||||||
|
func (s *NodeState) GetPrevious() NodeConfig {
|
||||||
|
s.Mutex.RLock()
|
||||||
|
defer s.Mutex.RUnlock()
|
||||||
|
return s.Previous
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace the node configuration with new configuration. This method returns
|
// Replace the node configuration with new configuration. This method returns
|
||||||
// both the new and the previous node configs
|
// both the new and the previous node configs
|
||||||
func (s *NodeState) Replace(n NodeConfig) (NodeConfig, NodeConfig) {
|
func (s *NodeState) Replace(n NodeConfig) {
|
||||||
s.Mutex.Lock()
|
s.Mutex.Lock()
|
||||||
defer s.Mutex.Unlock()
|
defer s.Mutex.Unlock()
|
||||||
s.Previous = s.Current
|
s.Previous = s.Current
|
||||||
s.Current = n
|
s.Current = n
|
||||||
return s.Current, s.Previous
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeConfig defines all configuration values needed to run a signle yggdrasil node
|
// NodeConfig defines all configuration values needed to run a signle yggdrasil node
|
||||||
@ -115,3 +121,19 @@ func GenerateConfig() *NodeConfig {
|
|||||||
|
|
||||||
return &cfg
|
return &cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewEncryptionKeys generates a new encryption keypair. The encryption keys are
|
||||||
|
// used to encrypt traffic and to derive the IPv6 address/subnet of the node.
|
||||||
|
func (cfg *NodeConfig) NewEncryptionKeys() {
|
||||||
|
bpub, bpriv := crypto.NewBoxKeys()
|
||||||
|
cfg.EncryptionPublicKey = hex.EncodeToString(bpub[:])
|
||||||
|
cfg.EncryptionPrivateKey = hex.EncodeToString(bpriv[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSigningKeys generates a new signing keypair. The signing keys are used to
|
||||||
|
// derive the structure of the spanning tree.
|
||||||
|
func (cfg *NodeConfig) NewSigningKeys() {
|
||||||
|
spub, spriv := crypto.NewSigKeys()
|
||||||
|
cfg.SigningPublicKey = hex.EncodeToString(spub[:])
|
||||||
|
cfg.SigningPrivateKey = hex.EncodeToString(spriv[:])
|
||||||
|
}
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
package dummy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gologme/log"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DummyAdapter is a non-specific adapter that is used by the mobile APIs.
|
|
||||||
// You can also use it to send or receive custom traffic over Yggdrasil.
|
|
||||||
type DummyAdapter struct {
|
|
||||||
yggdrasil.Adapter
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init initialises the dummy adapter.
|
|
||||||
func (m *DummyAdapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte, reject <-chan yggdrasil.RejectedPacket) {
|
|
||||||
m.Adapter.Init(config, log, send, recv, reject)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name returns the name of the adapter. This is always "dummy" for dummy
|
|
||||||
// adapters.
|
|
||||||
func (m *DummyAdapter) Name() string {
|
|
||||||
return "dummy"
|
|
||||||
}
|
|
||||||
|
|
||||||
// MTU gets the adapter's MTU. This returns your platform's maximum MTU for
|
|
||||||
// dummy adapters.
|
|
||||||
func (m *DummyAdapter) MTU() int {
|
|
||||||
return defaults.GetDefaults().MaximumIfMTU
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsTAP always returns false for dummy adapters.
|
|
||||||
func (m *DummyAdapter) IsTAP() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recv waits for and returns for a packet from the router.
|
|
||||||
func (m *DummyAdapter) Recv() ([]byte, error) {
|
|
||||||
packet := <-m.Adapter.Recv
|
|
||||||
return packet, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send a packet to the router.
|
|
||||||
func (m *DummyAdapter) Send(buf []byte) error {
|
|
||||||
packet := append(util.GetBytes(), buf[:]...)
|
|
||||||
m.Adapter.Send <- packet
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start is not implemented for dummy adapters.
|
|
||||||
func (m *DummyAdapter) Start(address.Address, address.Subnet) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close is not implemented for dummy adapters.
|
|
||||||
func (m *DummyAdapter) Close() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,108 +0,0 @@
|
|||||||
package mobile
|
|
||||||
|
|
||||||
/*
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type awdl struct {
|
|
||||||
link *link
|
|
||||||
reconfigure chan chan error
|
|
||||||
mutex sync.RWMutex // protects interfaces below
|
|
||||||
interfaces map[string]*awdlInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
type awdlInterface struct {
|
|
||||||
linkif *linkInterface
|
|
||||||
rwc awdlReadWriteCloser
|
|
||||||
peer *peer
|
|
||||||
stream stream
|
|
||||||
}
|
|
||||||
|
|
||||||
type awdlReadWriteCloser struct {
|
|
||||||
fromAWDL chan []byte
|
|
||||||
toAWDL chan []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c awdlReadWriteCloser) Read(p []byte) (n int, err error) {
|
|
||||||
if packet, ok := <-c.fromAWDL; ok {
|
|
||||||
n = copy(p, packet)
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
return 0, io.EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c awdlReadWriteCloser) Write(p []byte) (n int, err error) {
|
|
||||||
var pc []byte
|
|
||||||
pc = append(pc, p...)
|
|
||||||
c.toAWDL <- pc
|
|
||||||
return len(pc), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c awdlReadWriteCloser) Close() error {
|
|
||||||
close(c.fromAWDL)
|
|
||||||
close(c.toAWDL)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *awdl) init(l *link) error {
|
|
||||||
a.link = l
|
|
||||||
a.mutex.Lock()
|
|
||||||
a.interfaces = make(map[string]*awdlInterface)
|
|
||||||
a.reconfigure = make(chan chan error, 1)
|
|
||||||
a.mutex.Unlock()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for e := range a.reconfigure {
|
|
||||||
e <- nil
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *awdl) create(name, local, remote string, incoming bool) (*awdlInterface, error) {
|
|
||||||
rwc := awdlReadWriteCloser{
|
|
||||||
fromAWDL: make(chan []byte, 1),
|
|
||||||
toAWDL: make(chan []byte, 1),
|
|
||||||
}
|
|
||||||
s := stream{}
|
|
||||||
s.init(rwc)
|
|
||||||
linkif, err := a.link.create(&s, name, "awdl", local, remote, incoming, true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
intf := awdlInterface{
|
|
||||||
linkif: linkif,
|
|
||||||
rwc: rwc,
|
|
||||||
}
|
|
||||||
a.mutex.Lock()
|
|
||||||
a.interfaces[name] = &intf
|
|
||||||
a.mutex.Unlock()
|
|
||||||
go intf.linkif.handler()
|
|
||||||
return &intf, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *awdl) getInterface(identity string) *awdlInterface {
|
|
||||||
a.mutex.RLock()
|
|
||||||
defer a.mutex.RUnlock()
|
|
||||||
if intf, ok := a.interfaces[identity]; ok {
|
|
||||||
return intf
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *awdl) shutdown(identity string) error {
|
|
||||||
if intf, ok := a.interfaces[identity]; ok {
|
|
||||||
close(intf.linkif.closed)
|
|
||||||
intf.rwc.Close()
|
|
||||||
a.mutex.Lock()
|
|
||||||
delete(a.interfaces, identity)
|
|
||||||
a.mutex.Unlock()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return errors.New("Interface not found or already closed")
|
|
||||||
}
|
|
||||||
*/
|
|
@ -1,149 +0,0 @@
|
|||||||
package mobile
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gologme/log"
|
|
||||||
|
|
||||||
hjson "github.com/hjson/hjson-go"
|
|
||||||
"github.com/mitchellh/mapstructure"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/dummy"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/multicast"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Yggdrasil mobile package is meant to "plug the gap" for mobile support, as
|
|
||||||
// Gomobile will not create headers for Swift/Obj-C etc if they have complex
|
|
||||||
// (non-native) types. Therefore for iOS we will expose some nice simple
|
|
||||||
// functions. Note that in the case of iOS we handle reading/writing to/from TUN
|
|
||||||
// in Swift therefore we use the "dummy" TUN interface instead.
|
|
||||||
type Yggdrasil struct {
|
|
||||||
core yggdrasil.Core
|
|
||||||
multicast multicast.Multicast
|
|
||||||
log MobileLogger
|
|
||||||
dummy.DummyAdapter
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Yggdrasil) addStaticPeers(cfg *config.NodeConfig) {
|
|
||||||
if len(cfg.Peers) == 0 && len(cfg.InterfacePeers) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for {
|
|
||||||
for _, peer := range cfg.Peers {
|
|
||||||
m.core.AddPeer(peer, "")
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
}
|
|
||||||
for intf, intfpeers := range cfg.InterfacePeers {
|
|
||||||
for _, peer := range intfpeers {
|
|
||||||
m.core.AddPeer(peer, intf)
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
time.Sleep(time.Minute)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartAutoconfigure starts a node with a randomly generated config
|
|
||||||
func (m *Yggdrasil) StartAutoconfigure() error {
|
|
||||||
logger := log.New(m.log, "", 0)
|
|
||||||
logger.EnableLevel("error")
|
|
||||||
logger.EnableLevel("warn")
|
|
||||||
logger.EnableLevel("info")
|
|
||||||
nc := config.GenerateConfig()
|
|
||||||
nc.IfName = "dummy"
|
|
||||||
nc.AdminListen = "tcp://localhost:9001"
|
|
||||||
nc.Peers = []string{}
|
|
||||||
if hostname, err := os.Hostname(); err == nil {
|
|
||||||
nc.NodeInfo = map[string]interface{}{"name": hostname}
|
|
||||||
}
|
|
||||||
if err := m.core.SetRouterAdapter(m); err != nil {
|
|
||||||
logger.Errorln("An error occured setting router adapter:", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
state, err := m.core.Start(nc, logger)
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorln("An error occured starting Yggdrasil:", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
m.multicast.Init(&m.core, state, logger, nil)
|
|
||||||
if err := m.multicast.Start(); err != nil {
|
|
||||||
logger.Errorln("An error occurred starting multicast:", err)
|
|
||||||
}
|
|
||||||
go m.addStaticPeers(nc)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartJSON starts a node with the given JSON config. You can get JSON config
|
|
||||||
// (rather than HJSON) by using the GenerateConfigJSON() function
|
|
||||||
func (m *Yggdrasil) StartJSON(configjson []byte) error {
|
|
||||||
logger := log.New(m.log, "", 0)
|
|
||||||
logger.EnableLevel("error")
|
|
||||||
logger.EnableLevel("warn")
|
|
||||||
logger.EnableLevel("info")
|
|
||||||
nc := config.GenerateConfig()
|
|
||||||
var dat map[string]interface{}
|
|
||||||
if err := hjson.Unmarshal(configjson, &dat); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := mapstructure.Decode(dat, &nc); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
nc.IfName = "dummy"
|
|
||||||
if err := m.core.SetRouterAdapter(m); err != nil {
|
|
||||||
logger.Errorln("An error occured setting router adapter:", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
state, err := m.core.Start(nc, logger)
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorln("An error occured starting Yggdrasil:", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
m.multicast.Init(&m.core, state, logger, nil)
|
|
||||||
if err := m.multicast.Start(); err != nil {
|
|
||||||
logger.Errorln("An error occurred starting multicast:", err)
|
|
||||||
}
|
|
||||||
go m.addStaticPeers(nc)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop the mobile Yggdrasil instance
|
|
||||||
func (m *Yggdrasil) Stop() error {
|
|
||||||
m.core.Stop()
|
|
||||||
if err := m.Stop(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateConfigJSON generates mobile-friendly configuration in JSON format
|
|
||||||
func GenerateConfigJSON() []byte {
|
|
||||||
nc := config.GenerateConfig()
|
|
||||||
nc.IfName = "dummy"
|
|
||||||
if json, err := json.Marshal(nc); err == nil {
|
|
||||||
return json
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAddressString gets the node's IPv6 address
|
|
||||||
func (m *Yggdrasil) GetAddressString() string {
|
|
||||||
return m.core.Address().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSubnetString gets the node's IPv6 subnet in CIDR notation
|
|
||||||
func (m *Yggdrasil) GetSubnetString() string {
|
|
||||||
return m.core.Subnet().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBoxPubKeyString gets the node's public encryption key
|
|
||||||
func (m *Yggdrasil) GetBoxPubKeyString() string {
|
|
||||||
return m.core.BoxPubKey()
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSigPubKeyString gets the node's public signing key
|
|
||||||
func (m *Yggdrasil) GetSigPubKeyString() string {
|
|
||||||
return m.core.SigPubKey()
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
// +build android
|
|
||||||
|
|
||||||
package mobile
|
|
||||||
|
|
||||||
import "log"
|
|
||||||
|
|
||||||
type MobileLogger struct{}
|
|
||||||
|
|
||||||
func (nsl MobileLogger) Write(p []byte) (n int, err error) {
|
|
||||||
log.Println(string(p))
|
|
||||||
return len(p), nil
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
// +build darwin
|
|
||||||
|
|
||||||
package mobile
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo CFLAGS: -x objective-c
|
|
||||||
#cgo LDFLAGS: -framework Foundation
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
void Log(const char *text) {
|
|
||||||
NSString *nss = [NSString stringWithUTF8String:text];
|
|
||||||
NSLog(@"%@", nss);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MobileLogger struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (nsl MobileLogger) Write(p []byte) (n int, err error) {
|
|
||||||
p = append(p, 0)
|
|
||||||
cstr := (*C.char)(unsafe.Pointer(&p[0]))
|
|
||||||
C.Log(cstr)
|
|
||||||
return len(p), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
func (c *Core) AWDLCreateInterface(name, local, remote string, incoming bool) error {
|
|
||||||
if intf, err := c.link.awdl.create(name, local, remote, incoming); err != nil || intf == nil {
|
|
||||||
c.log.Println("c.link.awdl.create:", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Core) AWDLShutdownInterface(name string) error {
|
|
||||||
return c.link.awdl.shutdown(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Core) AWDLRecvPacket(identity string) ([]byte, error) {
|
|
||||||
if intf := c.link.awdl.getInterface(identity); intf != nil {
|
|
||||||
read, ok := <-intf.rwc.toAWDL
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("AWDLRecvPacket: channel closed")
|
|
||||||
}
|
|
||||||
return read, nil
|
|
||||||
}
|
|
||||||
return nil, errors.New("AWDLRecvPacket identity not known: " + identity)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Core) AWDLSendPacket(identity string, buf []byte) error {
|
|
||||||
packet := append(util.GetBytes(), buf[:]...)
|
|
||||||
if intf := c.link.awdl.getInterface(identity); intf != nil {
|
|
||||||
intf.rwc.fromAWDL <- packet
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return errors.New("AWDLSendPacket identity not known: " + identity)
|
|
||||||
}
|
|
||||||
*/
|
|
@ -35,7 +35,7 @@ func (m *Multicast) Init(core *yggdrasil.Core, state *config.NodeState, log *log
|
|||||||
m.config = state
|
m.config = state
|
||||||
m.log = log
|
m.log = log
|
||||||
m.listeners = make(map[string]*yggdrasil.TcpListener)
|
m.listeners = make(map[string]*yggdrasil.TcpListener)
|
||||||
current, _ := m.config.Get()
|
current := m.config.GetCurrent()
|
||||||
m.listenPort = current.LinkLocalTCPPort
|
m.listenPort = current.LinkLocalTCPPort
|
||||||
m.groupAddr = "[ff02::114]:9001"
|
m.groupAddr = "[ff02::114]:9001"
|
||||||
return nil
|
return nil
|
||||||
@ -92,7 +92,7 @@ func (m *Multicast) UpdateConfig(config *config.NodeConfig) {
|
|||||||
func (m *Multicast) Interfaces() map[string]net.Interface {
|
func (m *Multicast) Interfaces() map[string]net.Interface {
|
||||||
interfaces := make(map[string]net.Interface)
|
interfaces := make(map[string]net.Interface)
|
||||||
// Get interface expressions from config
|
// Get interface expressions from config
|
||||||
current, _ := m.config.Get()
|
current := m.config.GetCurrent()
|
||||||
exprs := current.MulticastInterfaces
|
exprs := current.MulticastInterfaces
|
||||||
// Ask the system for network interfaces
|
// Ask the system for network interfaces
|
||||||
allifaces, err := net.Interfaces()
|
allifaces, err := net.Interfaces()
|
||||||
|
@ -59,7 +59,7 @@ func (c *cryptokey) init(tun *TunAdapter) {
|
|||||||
// Configure the CKR routes - this must only ever be called from the router
|
// Configure the CKR routes - this must only ever be called from the router
|
||||||
// goroutine, e.g. through router.doAdmin
|
// goroutine, e.g. through router.doAdmin
|
||||||
func (c *cryptokey) configure() error {
|
func (c *cryptokey) configure() error {
|
||||||
current, _ := c.tun.config.Get()
|
current := c.tun.config.GetCurrent()
|
||||||
|
|
||||||
// Set enabled/disabled state
|
// Set enabled/disabled state
|
||||||
c.setEnabled(current.TunnelRouting.Enable)
|
c.setEnabled(current.TunnelRouting.Enable)
|
||||||
|
@ -108,10 +108,10 @@ func (s *tunConn) writer() error {
|
|||||||
} else {
|
} else {
|
||||||
s.tun.log.Errorln(s.conn.String(), "TUN/TAP generic write error:", err)
|
s.tun.log.Errorln(s.conn.String(), "TUN/TAP generic write error:", err)
|
||||||
}
|
}
|
||||||
} else if ispackettoobig, maxsize := e.PacketTooBig(); ispackettoobig {
|
} else if e.PacketTooBig() {
|
||||||
// TODO: This currently isn't aware of IPv4 for CKR
|
// TODO: This currently isn't aware of IPv4 for CKR
|
||||||
ptb := &icmp.PacketTooBig{
|
ptb := &icmp.PacketTooBig{
|
||||||
MTU: int(maxsize),
|
MTU: int(e.PacketMaximumSize()),
|
||||||
Data: b[:900],
|
Data: b[:900],
|
||||||
}
|
}
|
||||||
if packet, err := CreateICMPv6(b[8:24], b[24:40], ipv6.ICMPTypePacketTooBig, 0, ptb); err == nil {
|
if packet, err := CreateICMPv6(b[8:24], b[24:40], ipv6.ICMPTypePacketTooBig, 0, ptb); err == nil {
|
||||||
|
@ -119,7 +119,7 @@ func (tun *TunAdapter) Init(config *config.NodeState, log *log.Logger, listener
|
|||||||
// Start the setup process for the TUN/TAP adapter. If successful, starts the
|
// Start the setup process for the TUN/TAP adapter. If successful, starts the
|
||||||
// read/write goroutines to handle packets on that interface.
|
// read/write goroutines to handle packets on that interface.
|
||||||
func (tun *TunAdapter) Start() error {
|
func (tun *TunAdapter) Start() error {
|
||||||
current, _ := tun.config.Get()
|
current := tun.config.GetCurrent()
|
||||||
if tun.config == nil || tun.listener == nil || tun.dialer == nil {
|
if tun.config == nil || tun.listener == nil || tun.dialer == nil {
|
||||||
return errors.New("No configuration available to TUN/TAP")
|
return errors.New("No configuration available to TUN/TAP")
|
||||||
}
|
}
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
// +build mobile
|
|
||||||
|
|
||||||
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 {
|
|
||||||
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 {
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -59,7 +59,7 @@ type DHTRes struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NodeInfoPayload represents a RequestNodeInfo response, in bytes.
|
// NodeInfoPayload represents a RequestNodeInfo response, in bytes.
|
||||||
type NodeInfoPayload nodeinfoPayload
|
type NodeInfoPayload []byte
|
||||||
|
|
||||||
// SwitchQueues represents information from the switch related to link
|
// SwitchQueues represents information from the switch related to link
|
||||||
// congestion and a list of switch queues created in response to congestion on a
|
// congestion and a list of switch queues created in response to congestion on a
|
||||||
@ -261,7 +261,7 @@ func BuildVersion() string {
|
|||||||
return buildVersion
|
return buildVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListenConn returns a listener for Yggdrasil session connections.
|
// ConnListen returns a listener for Yggdrasil session connections.
|
||||||
func (c *Core) ConnListen() (*Listener, error) {
|
func (c *Core) ConnListen() (*Listener, error) {
|
||||||
c.sessions.listenerMutex.Lock()
|
c.sessions.listenerMutex.Lock()
|
||||||
defer c.sessions.listenerMutex.Unlock()
|
defer c.sessions.listenerMutex.Unlock()
|
||||||
@ -290,18 +290,6 @@ func (c *Core) ListenTCP(uri string) (*TcpListener, error) {
|
|||||||
return c.link.tcp.listen(uri)
|
return c.link.tcp.listen(uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEncryptionKeys generates a new encryption keypair. The encryption keys are
|
|
||||||
// used to encrypt traffic and to derive the IPv6 address/subnet of the node.
|
|
||||||
func (c *Core) NewEncryptionKeys() (*crypto.BoxPubKey, *crypto.BoxPrivKey) {
|
|
||||||
return crypto.NewBoxKeys()
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSigningKeys generates a new signing keypair. The signing keys are used to
|
|
||||||
// derive the structure of the spanning tree.
|
|
||||||
func (c *Core) NewSigningKeys() (*crypto.SigPubKey, *crypto.SigPrivKey) {
|
|
||||||
return crypto.NewSigKeys()
|
|
||||||
}
|
|
||||||
|
|
||||||
// NodeID gets the node ID.
|
// NodeID gets the node ID.
|
||||||
func (c *Core) NodeID() *crypto.NodeID {
|
func (c *Core) NodeID() *crypto.NodeID {
|
||||||
return crypto.GetNodeID(&c.boxPub)
|
return crypto.GetNodeID(&c.boxPub)
|
||||||
@ -312,13 +300,13 @@ func (c *Core) TreeID() *crypto.TreeID {
|
|||||||
return crypto.GetTreeID(&c.sigPub)
|
return crypto.GetTreeID(&c.sigPub)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SigPubKey gets the node's signing public key.
|
// SigningPublicKey gets the node's signing public key.
|
||||||
func (c *Core) SigPubKey() string {
|
func (c *Core) SigningPublicKey() string {
|
||||||
return hex.EncodeToString(c.sigPub[:])
|
return hex.EncodeToString(c.sigPub[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// BoxPubKey gets the node's encryption public key.
|
// EncryptionPublicKey gets the node's encryption public key.
|
||||||
func (c *Core) BoxPubKey() string {
|
func (c *Core) EncryptionPublicKey() string {
|
||||||
return hex.EncodeToString(c.boxPub[:])
|
return hex.EncodeToString(c.boxPub[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,27 +318,21 @@ func (c *Core) Coords() []byte {
|
|||||||
|
|
||||||
// Address gets the IPv6 address of the Yggdrasil node. This is always a /128
|
// Address gets the IPv6 address of the Yggdrasil node. This is always a /128
|
||||||
// address.
|
// address.
|
||||||
func (c *Core) Address() *net.IP {
|
func (c *Core) Address() net.IP {
|
||||||
address := net.IP(address.AddrForNodeID(c.NodeID())[:])
|
address := net.IP(address.AddrForNodeID(c.NodeID())[:])
|
||||||
return &address
|
return address
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subnet gets the routed IPv6 subnet of the Yggdrasil node. This is always a
|
// Subnet gets the routed IPv6 subnet of the Yggdrasil node. This is always a
|
||||||
// /64 subnet.
|
// /64 subnet.
|
||||||
func (c *Core) Subnet() *net.IPNet {
|
func (c *Core) Subnet() net.IPNet {
|
||||||
subnet := address.SubnetForNodeID(c.NodeID())[:]
|
subnet := address.SubnetForNodeID(c.NodeID())[:]
|
||||||
subnet = append(subnet, 0, 0, 0, 0, 0, 0, 0, 0)
|
subnet = append(subnet, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||||
return &net.IPNet{IP: subnet, Mask: net.CIDRMask(64, 128)}
|
return net.IPNet{IP: subnet, Mask: net.CIDRMask(64, 128)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RouterAddresses returns the raw address and subnet types as used by the
|
// MyNodeInfo gets the currently configured nodeinfo.
|
||||||
// router
|
func (c *Core) MyNodeInfo() NodeInfoPayload {
|
||||||
func (c *Core) RouterAddresses() (address.Address, address.Subnet) {
|
|
||||||
return c.router.addr, c.router.subnet
|
|
||||||
}
|
|
||||||
|
|
||||||
// NodeInfo gets the currently configured nodeinfo.
|
|
||||||
func (c *Core) MyNodeInfo() nodeinfoPayload {
|
|
||||||
return c.router.nodeinfo.getNodeInfo()
|
return c.router.nodeinfo.getNodeInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,7 +355,7 @@ func (c *Core) GetNodeInfo(keyString, coordString string, nocache bool) (NodeInf
|
|||||||
}
|
}
|
||||||
if !nocache {
|
if !nocache {
|
||||||
if response, err := c.router.nodeinfo.getCachedNodeInfo(key); err == nil {
|
if response, err := c.router.nodeinfo.getCachedNodeInfo(key); err == nil {
|
||||||
return NodeInfoPayload(response), nil
|
return response, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var coords []byte
|
var coords []byte
|
||||||
@ -388,9 +370,9 @@ func (c *Core) GetNodeInfo(keyString, coordString string, nocache bool) (NodeInf
|
|||||||
coords = append(coords, uint8(u64))
|
coords = append(coords, uint8(u64))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
response := make(chan *nodeinfoPayload, 1)
|
response := make(chan *NodeInfoPayload, 1)
|
||||||
sendNodeInfoRequest := func() {
|
sendNodeInfoRequest := func() {
|
||||||
c.router.nodeinfo.addCallback(key, func(nodeinfo *nodeinfoPayload) {
|
c.router.nodeinfo.addCallback(key, func(nodeinfo *NodeInfoPayload) {
|
||||||
defer func() { recover() }()
|
defer func() { recover() }()
|
||||||
select {
|
select {
|
||||||
case response <- nodeinfo:
|
case response <- nodeinfo:
|
||||||
@ -405,9 +387,9 @@ func (c *Core) GetNodeInfo(keyString, coordString string, nocache bool) (NodeInf
|
|||||||
close(response)
|
close(response)
|
||||||
}()
|
}()
|
||||||
for res := range response {
|
for res := range response {
|
||||||
return NodeInfoPayload(*res), nil
|
return *res, nil
|
||||||
}
|
}
|
||||||
return NodeInfoPayload{}, errors.New(fmt.Sprintf("getNodeInfo timeout: %s", keyString))
|
return NodeInfoPayload{}, fmt.Errorf("getNodeInfo timeout: %s", keyString)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSessionGatekeeper allows you to configure a handler function for deciding
|
// SetSessionGatekeeper allows you to configure a handler function for deciding
|
||||||
@ -493,7 +475,8 @@ func (c *Core) RemoveAllowedEncryptionPublicKey(bstr string) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a DHT ping to the node with the provided key and coords, optionally looking up the specified target NodeID.
|
// DHTPing sends a DHT ping to the node with the provided key and coords,
|
||||||
|
// optionally looking up the specified target NodeID.
|
||||||
func (c *Core) DHTPing(keyString, coordString, targetString string) (DHTRes, error) {
|
func (c *Core) DHTPing(keyString, coordString, targetString string) (DHTRes, error) {
|
||||||
var key crypto.BoxPubKey
|
var key crypto.BoxPubKey
|
||||||
if keyBytes, err := hex.DecodeString(keyString); err != nil {
|
if keyBytes, err := hex.DecodeString(keyString); err != nil {
|
||||||
@ -553,5 +536,5 @@ func (c *Core) DHTPing(keyString, coordString, targetString string) (DHTRes, err
|
|||||||
}
|
}
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
return DHTRes{}, errors.New(fmt.Sprintf("DHT ping timeout: %s", keyString))
|
return DHTRes{}, fmt.Errorf("DHT ping timeout: %s", keyString)
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,17 @@ func (e *ConnError) Temporary() bool {
|
|||||||
// PacketTooBig returns in response to sending a packet that is too large, and
|
// PacketTooBig returns in response to sending a packet that is too large, and
|
||||||
// if so, the maximum supported packet size that should be used for the
|
// if so, the maximum supported packet size that should be used for the
|
||||||
// connection.
|
// connection.
|
||||||
func (e *ConnError) PacketTooBig() (bool, int) {
|
func (e *ConnError) PacketTooBig() bool {
|
||||||
return e.maxsize > 0, e.maxsize
|
return e.maxsize > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// PacketMaximumSize returns the maximum supported packet size. This will only
|
||||||
|
// return a non-zero value if ConnError.PacketTooBig() returns true.
|
||||||
|
func (e *ConnError) PacketMaximumSize() int {
|
||||||
|
if !e.PacketTooBig() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return e.maxsize
|
||||||
}
|
}
|
||||||
|
|
||||||
// Closed returns if the session is already closed and is now unusable.
|
// Closed returns if the session is already closed and is now unusable.
|
||||||
|
@ -45,7 +45,7 @@ func (c *Core) init() error {
|
|||||||
c.log = log.New(ioutil.Discard, "", 0)
|
c.log = log.New(ioutil.Discard, "", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
current, _ := c.config.Get()
|
current := c.config.GetCurrent()
|
||||||
|
|
||||||
boxPrivHex, err := hex.DecodeString(current.EncryptionPrivateKey)
|
boxPrivHex, err := hex.DecodeString(current.EncryptionPrivateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -94,7 +94,7 @@ func (c *Core) init() error {
|
|||||||
func (c *Core) addPeerLoop() {
|
func (c *Core) addPeerLoop() {
|
||||||
for {
|
for {
|
||||||
// the peers from the config - these could change!
|
// the peers from the config - these could change!
|
||||||
current, _ := c.config.Get()
|
current := c.config.GetCurrent()
|
||||||
|
|
||||||
// Add peers from the Peers section
|
// Add peers from the Peers section
|
||||||
for _, peer := range current.Peers {
|
for _, peer := range current.Peers {
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
|
|
||||||
type nodeinfo struct {
|
type nodeinfo struct {
|
||||||
core *Core
|
core *Core
|
||||||
myNodeInfo nodeinfoPayload
|
myNodeInfo NodeInfoPayload
|
||||||
myNodeInfoMutex sync.RWMutex
|
myNodeInfoMutex sync.RWMutex
|
||||||
callbacks map[crypto.BoxPubKey]nodeinfoCallback
|
callbacks map[crypto.BoxPubKey]nodeinfoCallback
|
||||||
callbacksMutex sync.Mutex
|
callbacksMutex sync.Mutex
|
||||||
@ -21,15 +21,13 @@ type nodeinfo struct {
|
|||||||
cacheMutex sync.RWMutex
|
cacheMutex sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
type nodeinfoPayload []byte
|
|
||||||
|
|
||||||
type nodeinfoCached struct {
|
type nodeinfoCached struct {
|
||||||
payload nodeinfoPayload
|
payload NodeInfoPayload
|
||||||
created time.Time
|
created time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type nodeinfoCallback struct {
|
type nodeinfoCallback struct {
|
||||||
call func(nodeinfo *nodeinfoPayload)
|
call func(nodeinfo *NodeInfoPayload)
|
||||||
created time.Time
|
created time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,7 +36,7 @@ type nodeinfoReqRes struct {
|
|||||||
SendPermPub crypto.BoxPubKey // Sender's permanent key
|
SendPermPub crypto.BoxPubKey // Sender's permanent key
|
||||||
SendCoords []byte // Sender's coords
|
SendCoords []byte // Sender's coords
|
||||||
IsResponse bool
|
IsResponse bool
|
||||||
NodeInfo nodeinfoPayload
|
NodeInfo NodeInfoPayload
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialises the nodeinfo cache/callback maps, and starts a goroutine to keep
|
// Initialises the nodeinfo cache/callback maps, and starts a goroutine to keep
|
||||||
@ -70,7 +68,7 @@ func (m *nodeinfo) init(core *Core) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add a callback for a nodeinfo lookup
|
// Add a callback for a nodeinfo lookup
|
||||||
func (m *nodeinfo) addCallback(sender crypto.BoxPubKey, call func(nodeinfo *nodeinfoPayload)) {
|
func (m *nodeinfo) addCallback(sender crypto.BoxPubKey, call func(nodeinfo *NodeInfoPayload)) {
|
||||||
m.callbacksMutex.Lock()
|
m.callbacksMutex.Lock()
|
||||||
defer m.callbacksMutex.Unlock()
|
defer m.callbacksMutex.Unlock()
|
||||||
m.callbacks[sender] = nodeinfoCallback{
|
m.callbacks[sender] = nodeinfoCallback{
|
||||||
@ -80,7 +78,7 @@ func (m *nodeinfo) addCallback(sender crypto.BoxPubKey, call func(nodeinfo *node
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handles the callback, if there is one
|
// Handles the callback, if there is one
|
||||||
func (m *nodeinfo) callback(sender crypto.BoxPubKey, nodeinfo nodeinfoPayload) {
|
func (m *nodeinfo) callback(sender crypto.BoxPubKey, nodeinfo NodeInfoPayload) {
|
||||||
m.callbacksMutex.Lock()
|
m.callbacksMutex.Lock()
|
||||||
defer m.callbacksMutex.Unlock()
|
defer m.callbacksMutex.Unlock()
|
||||||
if callback, ok := m.callbacks[sender]; ok {
|
if callback, ok := m.callbacks[sender]; ok {
|
||||||
@ -90,7 +88,7 @@ func (m *nodeinfo) callback(sender crypto.BoxPubKey, nodeinfo nodeinfoPayload) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the current node's nodeinfo
|
// Get the current node's nodeinfo
|
||||||
func (m *nodeinfo) getNodeInfo() nodeinfoPayload {
|
func (m *nodeinfo) getNodeInfo() NodeInfoPayload {
|
||||||
m.myNodeInfoMutex.RLock()
|
m.myNodeInfoMutex.RLock()
|
||||||
defer m.myNodeInfoMutex.RUnlock()
|
defer m.myNodeInfoMutex.RUnlock()
|
||||||
return m.myNodeInfo
|
return m.myNodeInfo
|
||||||
@ -135,7 +133,7 @@ func (m *nodeinfo) setNodeInfo(given interface{}, privacy bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add nodeinfo into the cache for a node
|
// Add nodeinfo into the cache for a node
|
||||||
func (m *nodeinfo) addCachedNodeInfo(key crypto.BoxPubKey, payload nodeinfoPayload) {
|
func (m *nodeinfo) addCachedNodeInfo(key crypto.BoxPubKey, payload NodeInfoPayload) {
|
||||||
m.cacheMutex.Lock()
|
m.cacheMutex.Lock()
|
||||||
defer m.cacheMutex.Unlock()
|
defer m.cacheMutex.Unlock()
|
||||||
m.cache[key] = nodeinfoCached{
|
m.cache[key] = nodeinfoCached{
|
||||||
@ -145,13 +143,13 @@ func (m *nodeinfo) addCachedNodeInfo(key crypto.BoxPubKey, payload nodeinfoPaylo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get a nodeinfo entry from the cache
|
// Get a nodeinfo entry from the cache
|
||||||
func (m *nodeinfo) getCachedNodeInfo(key crypto.BoxPubKey) (nodeinfoPayload, error) {
|
func (m *nodeinfo) getCachedNodeInfo(key crypto.BoxPubKey) (NodeInfoPayload, error) {
|
||||||
m.cacheMutex.RLock()
|
m.cacheMutex.RLock()
|
||||||
defer m.cacheMutex.RUnlock()
|
defer m.cacheMutex.RUnlock()
|
||||||
if nodeinfo, ok := m.cache[key]; ok {
|
if nodeinfo, ok := m.cache[key]; ok {
|
||||||
return nodeinfo.payload, nil
|
return nodeinfo.payload, nil
|
||||||
}
|
}
|
||||||
return nodeinfoPayload{}, errors.New("No cache entry found")
|
return NodeInfoPayload{}, errors.New("No cache entry found")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handles a nodeinfo request/response - called from the router
|
// Handles a nodeinfo request/response - called from the router
|
||||||
|
@ -132,187 +132,12 @@ func (r *router) mainLoop() {
|
|||||||
case f := <-r.admin:
|
case f := <-r.admin:
|
||||||
f()
|
f()
|
||||||
case e := <-r.reconfigure:
|
case e := <-r.reconfigure:
|
||||||
current, _ := r.core.config.Get()
|
current := r.core.config.GetCurrent()
|
||||||
e <- r.nodeinfo.setNodeInfo(current.NodeInfo, current.NodeInfoPrivacy)
|
e <- r.nodeinfo.setNodeInfo(current.NodeInfo, current.NodeInfoPrivacy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// Checks a packet's to/from address to make sure it's in the allowed range.
|
|
||||||
// If a session to the destination exists, gets the session and passes the packet to it.
|
|
||||||
// If no session exists, it triggers (or continues) a search.
|
|
||||||
// If the session hasn't responded recently, it triggers a ping or search to keep things alive or deal with broken coords *relatively* quickly.
|
|
||||||
// It also deals with oversized packets if there are MTU issues by calling into icmpv6.go to spoof PacketTooBig traffic, or DestinationUnreachable if the other side has their adapter disabled.
|
|
||||||
func (r *router) sendPacket(bs []byte) {
|
|
||||||
var sourceAddr address.Address
|
|
||||||
var destAddr address.Address
|
|
||||||
var destSnet address.Subnet
|
|
||||||
var destPubKey *crypto.BoxPubKey
|
|
||||||
var destNodeID *crypto.NodeID
|
|
||||||
var addrlen int
|
|
||||||
if bs[0]&0xf0 == 0x60 {
|
|
||||||
// Check if we have a fully-sized header
|
|
||||||
if len(bs) < 40 {
|
|
||||||
panic("Tried to send a packet shorter than an IPv6 header...")
|
|
||||||
}
|
|
||||||
// IPv6 address
|
|
||||||
addrlen = 16
|
|
||||||
copy(sourceAddr[:addrlen], bs[8:])
|
|
||||||
copy(destAddr[:addrlen], bs[24:])
|
|
||||||
copy(destSnet[:addrlen/2], bs[24:])
|
|
||||||
} else if bs[0]&0xf0 == 0x40 {
|
|
||||||
// Check if we have a fully-sized header
|
|
||||||
if len(bs) < 20 {
|
|
||||||
panic("Tried to send a packet shorter than an IPv4 header...")
|
|
||||||
}
|
|
||||||
// IPv4 address
|
|
||||||
addrlen = 4
|
|
||||||
copy(sourceAddr[:addrlen], bs[12:])
|
|
||||||
copy(destAddr[:addrlen], bs[16:])
|
|
||||||
} else {
|
|
||||||
// Unknown address length
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !r.cryptokey.isValidSource(sourceAddr, addrlen) {
|
|
||||||
// The packet had a source address that doesn't belong to us or our
|
|
||||||
// configured crypto-key routing source subnets
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !destAddr.IsValid() && !destSnet.IsValid() {
|
|
||||||
// The addresses didn't match valid Yggdrasil node addresses so let's see
|
|
||||||
// whether it matches a crypto-key routing range instead
|
|
||||||
if key, err := r.cryptokey.getPublicKeyForAddress(destAddr, addrlen); err == nil {
|
|
||||||
// A public key was found, get the node ID for the search
|
|
||||||
destPubKey = &key
|
|
||||||
destNodeID = crypto.GetNodeID(destPubKey)
|
|
||||||
// Do a quick check to ensure that the node ID refers to a vaild Yggdrasil
|
|
||||||
// address or subnet - this might be superfluous
|
|
||||||
addr := *address.AddrForNodeID(destNodeID)
|
|
||||||
copy(destAddr[:], addr[:])
|
|
||||||
copy(destSnet[:], addr[:])
|
|
||||||
if !destAddr.IsValid() && !destSnet.IsValid() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// No public key was found in the CKR table so we've exhausted our options
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
searchCompleted := func(sinfo *sessionInfo, err error) {
|
|
||||||
if err != nil {
|
|
||||||
r.core.log.Debugln("DHT search failed:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
doSearch := func(packet []byte) {
|
|
||||||
var nodeID, mask *crypto.NodeID
|
|
||||||
switch {
|
|
||||||
case destNodeID != nil:
|
|
||||||
// We already know the full node ID, probably because it's from a CKR
|
|
||||||
// route in which the public key is known ahead of time
|
|
||||||
nodeID = destNodeID
|
|
||||||
var m crypto.NodeID
|
|
||||||
for i := range m {
|
|
||||||
m[i] = 0xFF
|
|
||||||
}
|
|
||||||
mask = &m
|
|
||||||
case destAddr.IsValid():
|
|
||||||
// We don't know the full node ID - try and use the address to generate
|
|
||||||
// a truncated node ID
|
|
||||||
nodeID, mask = destAddr.GetNodeIDandMask()
|
|
||||||
case destSnet.IsValid():
|
|
||||||
// We don't know the full node ID - try and use the subnet to generate
|
|
||||||
// a truncated node ID
|
|
||||||
nodeID, mask = destSnet.GetNodeIDandMask()
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
sinfo, isIn := r.core.searches.searches[*nodeID]
|
|
||||||
if !isIn {
|
|
||||||
sinfo = r.core.searches.newIterSearch(nodeID, mask, searchCompleted)
|
|
||||||
}
|
|
||||||
if packet != nil {
|
|
||||||
sinfo.packet = packet
|
|
||||||
}
|
|
||||||
r.core.searches.continueSearch(sinfo)
|
|
||||||
}
|
|
||||||
var sinfo *sessionInfo
|
|
||||||
var isIn bool
|
|
||||||
if destAddr.IsValid() {
|
|
||||||
sinfo, isIn = r.core.sessions.getByTheirAddr(&destAddr)
|
|
||||||
}
|
|
||||||
if destSnet.IsValid() {
|
|
||||||
sinfo, isIn = r.core.sessions.getByTheirSubnet(&destSnet)
|
|
||||||
}
|
|
||||||
sTime := sinfo.time.Load().(time.Time)
|
|
||||||
pingTime := sinfo.pingTime.Load().(time.Time)
|
|
||||||
pingSend := sinfo.pingSend.Load().(time.Time)
|
|
||||||
switch {
|
|
||||||
case !isIn || !sinfo.init.Load().(bool):
|
|
||||||
// No or unintiialized session, so we need to search first
|
|
||||||
doSearch(bs)
|
|
||||||
case time.Since(sTime) > 6*time.Second:
|
|
||||||
if sTime.Before(pingTime) && time.Since(pingTime) > 6*time.Second {
|
|
||||||
// We haven't heard from the dest in a while
|
|
||||||
// We tried pinging but didn't get a response
|
|
||||||
// They may have changed coords
|
|
||||||
// Try searching to discover new coords
|
|
||||||
// Note that search spam is throttled internally
|
|
||||||
doSearch(nil)
|
|
||||||
} else {
|
|
||||||
// We haven't heard about the dest in a while
|
|
||||||
now := time.Now()
|
|
||||||
|
|
||||||
if !sTime.Before(pingTime) {
|
|
||||||
// Update pingTime to start the clock for searches (above)
|
|
||||||
sinfo.pingTime.Store(now)
|
|
||||||
}
|
|
||||||
if time.Since(pingSend) > time.Second {
|
|
||||||
// Send at most 1 ping per second
|
|
||||||
sinfo.pingSend.Store(now)
|
|
||||||
r.core.sessions.sendPingPong(sinfo, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fallthrough // Also send the packet
|
|
||||||
default:
|
|
||||||
// If we know the public key ahead of time (i.e. a CKR route) then check
|
|
||||||
// if the session perm pub key matches before we send the packet to it
|
|
||||||
if destPubKey != nil {
|
|
||||||
if !bytes.Equal((*destPubKey)[:], sinfo.theirPermPub[:]) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drop packets if the session MTU is 0 - this means that one or other
|
|
||||||
// side probably has their TUN adapter disabled
|
|
||||||
if sinfo.getMTU() == 0 {
|
|
||||||
// Don't continue - drop the packet
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 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
|
|
||||||
if int(sinfo.getMTU()) < window {
|
|
||||||
window = int(sinfo.getMTU())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send the error back to the adapter
|
|
||||||
r.reject <- RejectedPacket{
|
|
||||||
Reason: PacketTooBig,
|
|
||||||
Packet: bs[:window],
|
|
||||||
Detail: int(sinfo.getMTU()),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't continue - drop the packet
|
|
||||||
return
|
|
||||||
}
|
|
||||||
sinfo.send <- bs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Checks incoming traffic type and passes it to the appropriate handler.
|
// Checks incoming traffic type and passes it to the appropriate handler.
|
||||||
func (r *router) handleIn(packet []byte) {
|
func (r *router) handleIn(packet []byte) {
|
||||||
pType, pTypeLen := wire_decode_uint64(packet)
|
pType, pTypeLen := wire_decode_uint64(packet)
|
||||||
|
@ -394,7 +394,7 @@ func (p *nodeinfoReqRes) decode(bs []byte) bool {
|
|||||||
if len(bs) == 0 {
|
if len(bs) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
p.NodeInfo = make(nodeinfoPayload, len(bs))
|
p.NodeInfo = make(NodeInfoPayload, len(bs))
|
||||||
if !wire_chop_slice(p.NodeInfo[:], &bs) {
|
if !wire_chop_slice(p.NodeInfo[:], &bs) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user