mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 11:15:07 +03:00 
			
		
		
		
	Merge pull request #474 from neilalexander/gomobile
Various API changes and simplifications to fix mobile builds
This commit is contained in:
		
						commit
						7c4c1558ff
					
				
					 19 changed files with 87 additions and 659 deletions
				
			
		| 
						 | 
				
			
			@ -60,7 +60,7 @@ func (a *AdminSocket) Init(c *yggdrasil.Core, state *config.NodeState, log *log.
 | 
			
		|||
	go func() {
 | 
			
		||||
		for {
 | 
			
		||||
			e := <-a.reconfigure
 | 
			
		||||
			current, previous := state.Get()
 | 
			
		||||
			current, previous := state.GetCurrent(), state.GetPrevious()
 | 
			
		||||
			if current.AdminListen != previous.AdminListen {
 | 
			
		||||
				a.listenaddr = current.AdminListen
 | 
			
		||||
				a.Stop()
 | 
			
		||||
| 
						 | 
				
			
			@ -69,7 +69,7 @@ func (a *AdminSocket) Init(c *yggdrasil.Core, state *config.NodeState, log *log.
 | 
			
		|||
			e <- nil
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	current, _ := state.Get()
 | 
			
		||||
	current := state.GetCurrent()
 | 
			
		||||
	a.listenaddr = current.AdminListen
 | 
			
		||||
	a.AddHandler("list", []string{}, func(in Info) (Info, error) {
 | 
			
		||||
		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) {
 | 
			
		||||
		ip := c.Address().String()
 | 
			
		||||
		subnet := c.Subnet()
 | 
			
		||||
		return Info{
 | 
			
		||||
			"self": Info{
 | 
			
		||||
				ip: Info{
 | 
			
		||||
					"box_pub_key":   c.BoxPubKey(),
 | 
			
		||||
					"box_pub_key":   c.EncryptionPublicKey(),
 | 
			
		||||
					"build_name":    yggdrasil.BuildName(),
 | 
			
		||||
					"build_version": yggdrasil.BuildVersion(),
 | 
			
		||||
					"coords":        fmt.Sprintf("%v", c.Coords()),
 | 
			
		||||
					"subnet":        c.Subnet().String(),
 | 
			
		||||
					"subnet":        subnet.String(),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		}, nil
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,21 +16,27 @@ type NodeState struct {
 | 
			
		|||
	Mutex    sync.RWMutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get returns both the current and previous node configs
 | 
			
		||||
func (s *NodeState) Get() (NodeConfig, NodeConfig) {
 | 
			
		||||
// Current returns the current node config
 | 
			
		||||
func (s *NodeState) GetCurrent() NodeConfig {
 | 
			
		||||
	s.Mutex.RLock()
 | 
			
		||||
	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
 | 
			
		||||
// 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()
 | 
			
		||||
	defer s.Mutex.Unlock()
 | 
			
		||||
	s.Previous = s.Current
 | 
			
		||||
	s.Current = n
 | 
			
		||||
	return s.Current, s.Previous
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NodeConfig defines all configuration values needed to run a signle yggdrasil node
 | 
			
		||||
| 
						 | 
				
			
			@ -115,3 +121,19 @@ func GenerateConfig() *NodeConfig {
 | 
			
		|||
 | 
			
		||||
	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.log = log
 | 
			
		||||
	m.listeners = make(map[string]*yggdrasil.TcpListener)
 | 
			
		||||
	current, _ := m.config.Get()
 | 
			
		||||
	current := m.config.GetCurrent()
 | 
			
		||||
	m.listenPort = current.LinkLocalTCPPort
 | 
			
		||||
	m.groupAddr = "[ff02::114]:9001"
 | 
			
		||||
	return nil
 | 
			
		||||
| 
						 | 
				
			
			@ -92,7 +92,7 @@ func (m *Multicast) UpdateConfig(config *config.NodeConfig) {
 | 
			
		|||
func (m *Multicast) Interfaces() map[string]net.Interface {
 | 
			
		||||
	interfaces := make(map[string]net.Interface)
 | 
			
		||||
	// Get interface expressions from config
 | 
			
		||||
	current, _ := m.config.Get()
 | 
			
		||||
	current := m.config.GetCurrent()
 | 
			
		||||
	exprs := current.MulticastInterfaces
 | 
			
		||||
	// Ask the system for network 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
 | 
			
		||||
// goroutine, e.g. through router.doAdmin
 | 
			
		||||
func (c *cryptokey) configure() error {
 | 
			
		||||
	current, _ := c.tun.config.Get()
 | 
			
		||||
	current := c.tun.config.GetCurrent()
 | 
			
		||||
 | 
			
		||||
	// Set enabled/disabled state
 | 
			
		||||
	c.setEnabled(current.TunnelRouting.Enable)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -108,10 +108,10 @@ func (s *tunConn) writer() error {
 | 
			
		|||
					} else {
 | 
			
		||||
						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
 | 
			
		||||
					ptb := &icmp.PacketTooBig{
 | 
			
		||||
						MTU:  int(maxsize),
 | 
			
		||||
						MTU:  int(e.PacketMaximumSize()),
 | 
			
		||||
						Data: b[:900],
 | 
			
		||||
					}
 | 
			
		||||
					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
 | 
			
		||||
// read/write goroutines to handle packets on that interface.
 | 
			
		||||
func (tun *TunAdapter) Start() error {
 | 
			
		||||
	current, _ := tun.config.Get()
 | 
			
		||||
	current := tun.config.GetCurrent()
 | 
			
		||||
	if tun.config == nil || tun.listener == nil || tun.dialer == nil {
 | 
			
		||||
		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.
 | 
			
		||||
type NodeInfoPayload nodeinfoPayload
 | 
			
		||||
type NodeInfoPayload []byte
 | 
			
		||||
 | 
			
		||||
// SwitchQueues represents information from the switch related to link
 | 
			
		||||
// congestion and a list of switch queues created in response to congestion on a
 | 
			
		||||
| 
						 | 
				
			
			@ -261,7 +261,7 @@ func BuildVersion() string {
 | 
			
		|||
	return buildVersion
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ListenConn returns a listener for Yggdrasil session connections.
 | 
			
		||||
// ConnListen returns a listener for Yggdrasil session connections.
 | 
			
		||||
func (c *Core) ConnListen() (*Listener, error) {
 | 
			
		||||
	c.sessions.listenerMutex.Lock()
 | 
			
		||||
	defer c.sessions.listenerMutex.Unlock()
 | 
			
		||||
| 
						 | 
				
			
			@ -290,18 +290,6 @@ func (c *Core) ListenTCP(uri string) (*TcpListener, error) {
 | 
			
		|||
	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.
 | 
			
		||||
func (c *Core) NodeID() *crypto.NodeID {
 | 
			
		||||
	return crypto.GetNodeID(&c.boxPub)
 | 
			
		||||
| 
						 | 
				
			
			@ -312,13 +300,13 @@ func (c *Core) TreeID() *crypto.TreeID {
 | 
			
		|||
	return crypto.GetTreeID(&c.sigPub)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SigPubKey gets the node's signing public key.
 | 
			
		||||
func (c *Core) SigPubKey() string {
 | 
			
		||||
// SigningPublicKey gets the node's signing public key.
 | 
			
		||||
func (c *Core) SigningPublicKey() string {
 | 
			
		||||
	return hex.EncodeToString(c.sigPub[:])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BoxPubKey gets the node's encryption public key.
 | 
			
		||||
func (c *Core) BoxPubKey() string {
 | 
			
		||||
// EncryptionPublicKey gets the node's encryption public key.
 | 
			
		||||
func (c *Core) EncryptionPublicKey() string {
 | 
			
		||||
	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.
 | 
			
		||||
func (c *Core) Address() *net.IP {
 | 
			
		||||
func (c *Core) Address() net.IP {
 | 
			
		||||
	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
 | 
			
		||||
// /64 subnet.
 | 
			
		||||
func (c *Core) Subnet() *net.IPNet {
 | 
			
		||||
func (c *Core) Subnet() net.IPNet {
 | 
			
		||||
	subnet := address.SubnetForNodeID(c.NodeID())[:]
 | 
			
		||||
	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
 | 
			
		||||
// router
 | 
			
		||||
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 {
 | 
			
		||||
// MyNodeInfo gets the currently configured nodeinfo.
 | 
			
		||||
func (c *Core) MyNodeInfo() NodeInfoPayload {
 | 
			
		||||
	return c.router.nodeinfo.getNodeInfo()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -373,7 +355,7 @@ func (c *Core) GetNodeInfo(keyString, coordString string, nocache bool) (NodeInf
 | 
			
		|||
	}
 | 
			
		||||
	if !nocache {
 | 
			
		||||
		if response, err := c.router.nodeinfo.getCachedNodeInfo(key); err == nil {
 | 
			
		||||
			return NodeInfoPayload(response), nil
 | 
			
		||||
			return response, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	var coords []byte
 | 
			
		||||
| 
						 | 
				
			
			@ -388,9 +370,9 @@ func (c *Core) GetNodeInfo(keyString, coordString string, nocache bool) (NodeInf
 | 
			
		|||
			coords = append(coords, uint8(u64))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	response := make(chan *nodeinfoPayload, 1)
 | 
			
		||||
	response := make(chan *NodeInfoPayload, 1)
 | 
			
		||||
	sendNodeInfoRequest := func() {
 | 
			
		||||
		c.router.nodeinfo.addCallback(key, func(nodeinfo *nodeinfoPayload) {
 | 
			
		||||
		c.router.nodeinfo.addCallback(key, func(nodeinfo *NodeInfoPayload) {
 | 
			
		||||
			defer func() { recover() }()
 | 
			
		||||
			select {
 | 
			
		||||
			case response <- nodeinfo:
 | 
			
		||||
| 
						 | 
				
			
			@ -405,9 +387,9 @@ func (c *Core) GetNodeInfo(keyString, coordString string, nocache bool) (NodeInf
 | 
			
		|||
		close(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
 | 
			
		||||
| 
						 | 
				
			
			@ -493,7 +475,8 @@ func (c *Core) RemoveAllowedEncryptionPublicKey(bstr string) (err error) {
 | 
			
		|||
	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) {
 | 
			
		||||
	var key crypto.BoxPubKey
 | 
			
		||||
	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 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
 | 
			
		||||
// if so, the maximum supported packet size that should be used for the
 | 
			
		||||
// connection.
 | 
			
		||||
func (e *ConnError) PacketTooBig() (bool, int) {
 | 
			
		||||
	return e.maxsize > 0, e.maxsize
 | 
			
		||||
func (e *ConnError) PacketTooBig() bool {
 | 
			
		||||
	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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ func (c *Core) init() error {
 | 
			
		|||
		c.log = log.New(ioutil.Discard, "", 0)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	current, _ := c.config.Get()
 | 
			
		||||
	current := c.config.GetCurrent()
 | 
			
		||||
 | 
			
		||||
	boxPrivHex, err := hex.DecodeString(current.EncryptionPrivateKey)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -94,7 +94,7 @@ func (c *Core) init() error {
 | 
			
		|||
func (c *Core) addPeerLoop() {
 | 
			
		||||
	for {
 | 
			
		||||
		//  the peers from the config - these could change!
 | 
			
		||||
		current, _ := c.config.Get()
 | 
			
		||||
		current := c.config.GetCurrent()
 | 
			
		||||
 | 
			
		||||
		// Add peers from the Peers section
 | 
			
		||||
		for _, peer := range current.Peers {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,7 @@ import (
 | 
			
		|||
 | 
			
		||||
type nodeinfo struct {
 | 
			
		||||
	core            *Core
 | 
			
		||||
	myNodeInfo      nodeinfoPayload
 | 
			
		||||
	myNodeInfo      NodeInfoPayload
 | 
			
		||||
	myNodeInfoMutex sync.RWMutex
 | 
			
		||||
	callbacks       map[crypto.BoxPubKey]nodeinfoCallback
 | 
			
		||||
	callbacksMutex  sync.Mutex
 | 
			
		||||
| 
						 | 
				
			
			@ -21,15 +21,13 @@ type nodeinfo struct {
 | 
			
		|||
	cacheMutex      sync.RWMutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type nodeinfoPayload []byte
 | 
			
		||||
 | 
			
		||||
type nodeinfoCached struct {
 | 
			
		||||
	payload nodeinfoPayload
 | 
			
		||||
	payload NodeInfoPayload
 | 
			
		||||
	created time.Time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type nodeinfoCallback struct {
 | 
			
		||||
	call    func(nodeinfo *nodeinfoPayload)
 | 
			
		||||
	call    func(nodeinfo *NodeInfoPayload)
 | 
			
		||||
	created time.Time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +36,7 @@ type nodeinfoReqRes struct {
 | 
			
		|||
	SendPermPub crypto.BoxPubKey // Sender's permanent key
 | 
			
		||||
	SendCoords  []byte           // Sender's coords
 | 
			
		||||
	IsResponse  bool
 | 
			
		||||
	NodeInfo    nodeinfoPayload
 | 
			
		||||
	NodeInfo    NodeInfoPayload
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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
 | 
			
		||||
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()
 | 
			
		||||
	defer m.callbacksMutex.Unlock()
 | 
			
		||||
	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
 | 
			
		||||
func (m *nodeinfo) callback(sender crypto.BoxPubKey, nodeinfo nodeinfoPayload) {
 | 
			
		||||
func (m *nodeinfo) callback(sender crypto.BoxPubKey, nodeinfo NodeInfoPayload) {
 | 
			
		||||
	m.callbacksMutex.Lock()
 | 
			
		||||
	defer m.callbacksMutex.Unlock()
 | 
			
		||||
	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
 | 
			
		||||
func (m *nodeinfo) getNodeInfo() nodeinfoPayload {
 | 
			
		||||
func (m *nodeinfo) getNodeInfo() NodeInfoPayload {
 | 
			
		||||
	m.myNodeInfoMutex.RLock()
 | 
			
		||||
	defer m.myNodeInfoMutex.RUnlock()
 | 
			
		||||
	return m.myNodeInfo
 | 
			
		||||
| 
						 | 
				
			
			@ -135,7 +133,7 @@ func (m *nodeinfo) setNodeInfo(given interface{}, privacy bool) error {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// 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()
 | 
			
		||||
	defer m.cacheMutex.Unlock()
 | 
			
		||||
	m.cache[key] = nodeinfoCached{
 | 
			
		||||
| 
						 | 
				
			
			@ -145,13 +143,13 @@ func (m *nodeinfo) addCachedNodeInfo(key crypto.BoxPubKey, payload nodeinfoPaylo
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// 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()
 | 
			
		||||
	defer m.cacheMutex.RUnlock()
 | 
			
		||||
	if nodeinfo, ok := m.cache[key]; ok {
 | 
			
		||||
		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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -132,187 +132,12 @@ func (r *router) mainLoop() {
 | 
			
		|||
		case f := <-r.admin:
 | 
			
		||||
			f()
 | 
			
		||||
		case e := <-r.reconfigure:
 | 
			
		||||
			current, _ := r.core.config.Get()
 | 
			
		||||
			current := r.core.config.GetCurrent()
 | 
			
		||||
			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.
 | 
			
		||||
func (r *router) handleIn(packet []byte) {
 | 
			
		||||
	pType, pTypeLen := wire_decode_uint64(packet)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -394,7 +394,7 @@ func (p *nodeinfoReqRes) decode(bs []byte) bool {
 | 
			
		|||
		if len(bs) == 0 {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		p.NodeInfo = make(nodeinfoPayload, len(bs))
 | 
			
		||||
		p.NodeInfo = make(NodeInfoPayload, len(bs))
 | 
			
		||||
		if !wire_chop_slice(p.NodeInfo[:], &bs) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue