mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-22 18:50:27 +00:00
Merge pull request #401 from neilalexander/modular
Refactoring for Yggdrasil library
This commit is contained in:
commit
24fa8355f1
@ -24,11 +24,11 @@ jobs:
|
|||||||
command: |
|
command: |
|
||||||
sudo apt-get install -y alien
|
sudo apt-get install -y alien
|
||||||
|
|
||||||
- run:
|
# - run:
|
||||||
name: Test debug builds
|
# name: Test debug builds
|
||||||
command: |
|
# command: |
|
||||||
./build -d
|
# ./build -d
|
||||||
test -f yggdrasil && test -f yggdrasilctl
|
# test -f yggdrasil && test -f yggdrasilctl
|
||||||
|
|
||||||
- run:
|
- run:
|
||||||
name: Build for Linux (including Debian packages and RPMs)
|
name: Build for Linux (including Debian packages and RPMs)
|
||||||
|
10
build
10
build
@ -28,10 +28,16 @@ fi
|
|||||||
|
|
||||||
if [ $IOS ]; then
|
if [ $IOS ]; then
|
||||||
echo "Building framework for iOS"
|
echo "Building framework for iOS"
|
||||||
gomobile bind -target ios -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil
|
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/mobile \
|
||||||
|
github.com/yggdrasil-network/yggdrasil-go/src/config
|
||||||
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" github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil
|
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/mobile \
|
||||||
|
github.com/yggdrasil-network/yggdrasil-go/src/config
|
||||||
else
|
else
|
||||||
for CMD in `ls cmd/` ; do
|
for CMD in `ls cmd/` ; do
|
||||||
echo "Building: $CMD"
|
echo "Building: $CMD"
|
||||||
|
@ -19,6 +19,8 @@ import (
|
|||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/multicast"
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/tuntap"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,6 +29,8 @@ type Core = yggdrasil.Core
|
|||||||
|
|
||||||
type node struct {
|
type node struct {
|
||||||
core Core
|
core Core
|
||||||
|
tuntap tuntap.TunAdapter
|
||||||
|
multicast multicast.Multicast
|
||||||
}
|
}
|
||||||
|
|
||||||
func readConfig(useconf *bool, useconffile *string, normaliseconf *bool) *nodeConfig {
|
func readConfig(useconf *bool, useconffile *string, normaliseconf *bool) *nodeConfig {
|
||||||
@ -185,8 +189,8 @@ func main() {
|
|||||||
var err error
|
var err error
|
||||||
switch {
|
switch {
|
||||||
case *version:
|
case *version:
|
||||||
fmt.Println("Build name:", yggdrasil.GetBuildName())
|
fmt.Println("Build name:", yggdrasil.BuildName())
|
||||||
fmt.Println("Build version:", yggdrasil.GetBuildVersion())
|
fmt.Println("Build version:", yggdrasil.BuildVersion())
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
case *autoconf:
|
case *autoconf:
|
||||||
// Use an autoconf-generated config, this will give us random keys and
|
// Use an autoconf-generated config, this will give us random keys and
|
||||||
@ -244,13 +248,20 @@ func main() {
|
|||||||
// Setup the Yggdrasil node itself. The node{} type includes a Core, so we
|
// Setup the Yggdrasil node itself. The node{} type includes a Core, so we
|
||||||
// don't need to create this manually.
|
// don't need to create this manually.
|
||||||
n := node{}
|
n := node{}
|
||||||
// Now that we have a working configuration, we can now actually start
|
// Before we start the node, set the TUN/TAP to be our router adapter
|
||||||
// Yggdrasil. This will start the router, switch, DHT node, TCP and UDP
|
n.core.SetRouterAdapter(&n.tuntap)
|
||||||
// sockets, TUN/TAP adapter and multicast discovery port.
|
// Now start Yggdrasil - this starts the DHT, router, switch and other core
|
||||||
if err := n.core.Start(cfg, logger); err != nil {
|
// components needed for Yggdrasil to operate
|
||||||
|
state, err := n.core.Start(cfg, logger)
|
||||||
|
if err != nil {
|
||||||
logger.Errorln("An error occurred during startup")
|
logger.Errorln("An error occurred during startup")
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
// Start the multicast interface
|
||||||
|
n.multicast.Init(&n.core, state, logger, nil)
|
||||||
|
if err := n.multicast.Start(); err != nil {
|
||||||
|
logger.Errorln("An error occurred starting multicast:", err)
|
||||||
|
}
|
||||||
// The Stop function ensures that the TUN/TAP adapter is correctly shut down
|
// The Stop function ensures that the TUN/TAP adapter is correctly shut down
|
||||||
// before the program exits.
|
// before the program exits.
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -258,8 +269,8 @@ func main() {
|
|||||||
}()
|
}()
|
||||||
// Make some nice output that tells us what our IPv6 address and subnet are.
|
// Make some nice output that tells us what our IPv6 address and subnet are.
|
||||||
// This is just logged to stdout for the user.
|
// This is just logged to stdout for the user.
|
||||||
address := n.core.GetAddress()
|
address := n.core.Address()
|
||||||
subnet := n.core.GetSubnet()
|
subnet := n.core.Subnet()
|
||||||
logger.Infof("Your IPv6 address is %s", address.String())
|
logger.Infof("Your IPv6 address is %s", address.String())
|
||||||
logger.Infof("Your IPv6 subnet is %s", subnet.String())
|
logger.Infof("Your IPv6 subnet is %s", subnet.String())
|
||||||
// Catch interrupts from the operating system to exit gracefully.
|
// Catch interrupts from the operating system to exit gracefully.
|
||||||
|
@ -2,11 +2,37 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NodeState represents the active and previous configuration of the node and
|
||||||
|
// protects it with a mutex
|
||||||
|
type NodeState struct {
|
||||||
|
Current NodeConfig
|
||||||
|
Previous NodeConfig
|
||||||
|
Mutex sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns both the current and previous node configs
|
||||||
|
func (s *NodeState) Get() (NodeConfig, NodeConfig) {
|
||||||
|
s.Mutex.RLock()
|
||||||
|
defer s.Mutex.RUnlock()
|
||||||
|
return s.Current, 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) {
|
||||||
|
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
|
// NodeConfig defines all configuration values needed to run a signle yggdrasil node
|
||||||
type NodeConfig struct {
|
type NodeConfig struct {
|
||||||
Peers []string `comment:"List of connection strings for outbound peer connections in URI format,\ne.g. tcp://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j. These connections\nwill obey the operating system routing table, therefore you should\nuse this section when you may connect via different interfaces."`
|
Peers []string `comment:"List of connection strings for outbound peer connections in URI format,\ne.g. tcp://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j. These connections\nwill obey the operating system routing table, therefore you should\nuse this section when you may connect via different interfaces."`
|
||||||
|
61
src/dummy/dummy.go
Normal file
61
src/dummy/dummy.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
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,5 +1,6 @@
|
|||||||
package yggdrasil
|
package mobile
|
||||||
|
|
||||||
|
/*
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
@ -104,3 +105,4 @@ func (a *awdl) shutdown(identity string) error {
|
|||||||
}
|
}
|
||||||
return errors.New("Interface not found or already closed")
|
return errors.New("Interface not found or already closed")
|
||||||
}
|
}
|
||||||
|
*/
|
149
src/mobile/mobile.go
Normal file
149
src/mobile/mobile.go
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
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,6 +1,6 @@
|
|||||||
// +build android
|
// +build android
|
||||||
|
|
||||||
package yggdrasil
|
package mobile
|
||||||
|
|
||||||
import "log"
|
import "log"
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
// +build mobile,darwin
|
// +build darwin
|
||||||
|
|
||||||
package yggdrasil
|
package mobile
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#cgo CFLAGS: -x objective-c
|
#cgo CFLAGS: -x objective-c
|
||||||
@ -13,10 +13,7 @@ void Log(const char *text) {
|
|||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type MobileLogger struct {
|
type MobileLogger struct {
|
||||||
@ -29,6 +26,7 @@ func (nsl MobileLogger) Write(p []byte) (n int, err error) {
|
|||||||
return len(p), nil
|
return len(p), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
func (c *Core) AWDLCreateInterface(name, local, remote string, incoming bool) error {
|
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 {
|
if intf, err := c.link.awdl.create(name, local, remote, incoming); err != nil || intf == nil {
|
||||||
c.log.Println("c.link.awdl.create:", err)
|
c.log.Println("c.link.awdl.create:", err)
|
||||||
@ -60,3 +58,4 @@ func (c *Core) AWDLSendPacket(identity string, buf []byte) error {
|
|||||||
}
|
}
|
||||||
return errors.New("AWDLSendPacket identity not known: " + identity)
|
return errors.New("AWDLSendPacket identity not known: " + identity)
|
||||||
}
|
}
|
||||||
|
*/
|
@ -1,4 +1,4 @@
|
|||||||
package yggdrasil
|
package multicast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -7,25 +7,37 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gologme/log"
|
||||||
|
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
||||||
"golang.org/x/net/ipv6"
|
"golang.org/x/net/ipv6"
|
||||||
)
|
)
|
||||||
|
|
||||||
type multicast struct {
|
// Multicast represents the multicast advertisement and discovery mechanism used
|
||||||
core *Core
|
// by Yggdrasil to find peers on the same subnet. When a beacon is received on a
|
||||||
|
// configured multicast interface, Yggdrasil will attempt to peer with that node
|
||||||
|
// automatically.
|
||||||
|
type Multicast struct {
|
||||||
|
core *yggdrasil.Core
|
||||||
|
config *config.NodeState
|
||||||
|
log *log.Logger
|
||||||
reconfigure chan chan error
|
reconfigure chan chan error
|
||||||
sock *ipv6.PacketConn
|
sock *ipv6.PacketConn
|
||||||
groupAddr string
|
groupAddr string
|
||||||
listeners map[string]*tcpListener
|
listeners map[string]*yggdrasil.TcpListener
|
||||||
listenPort uint16
|
listenPort uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *multicast) init(core *Core) {
|
// Init prepares the multicast interface for use.
|
||||||
|
func (m *Multicast) Init(core *yggdrasil.Core, state *config.NodeState, log *log.Logger, options interface{}) error {
|
||||||
m.core = core
|
m.core = core
|
||||||
|
m.config = state
|
||||||
|
m.log = log
|
||||||
m.reconfigure = make(chan chan error, 1)
|
m.reconfigure = make(chan chan error, 1)
|
||||||
m.listeners = make(map[string]*tcpListener)
|
m.listeners = make(map[string]*yggdrasil.TcpListener)
|
||||||
m.core.configMutex.RLock()
|
current, _ := m.config.Get()
|
||||||
m.listenPort = m.core.config.LinkLocalTCPPort
|
m.listenPort = current.LinkLocalTCPPort
|
||||||
m.core.configMutex.RUnlock()
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
e := <-m.reconfigure
|
e := <-m.reconfigure
|
||||||
@ -35,15 +47,19 @@ func (m *multicast) init(core *Core) {
|
|||||||
m.groupAddr = "[ff02::114]:9001"
|
m.groupAddr = "[ff02::114]:9001"
|
||||||
// Check if we've been given any expressions
|
// Check if we've been given any expressions
|
||||||
if count := len(m.interfaces()); count != 0 {
|
if count := len(m.interfaces()); count != 0 {
|
||||||
m.core.log.Infoln("Found", count, "multicast interface(s)")
|
m.log.Infoln("Found", count, "multicast interface(s)")
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *multicast) start() error {
|
// Start starts the multicast interface. This launches goroutines which will
|
||||||
|
// listen for multicast beacons from other hosts and will advertise multicast
|
||||||
|
// beacons out to the network.
|
||||||
|
func (m *Multicast) Start() error {
|
||||||
if len(m.interfaces()) == 0 {
|
if len(m.interfaces()) == 0 {
|
||||||
m.core.log.Infoln("Multicast discovery is disabled")
|
m.log.Infoln("Multicast discovery is disabled")
|
||||||
} else {
|
} else {
|
||||||
m.core.log.Infoln("Multicast discovery is enabled")
|
m.log.Infoln("Multicast discovery is enabled")
|
||||||
addr, err := net.ResolveUDPAddr("udp", m.groupAddr)
|
addr, err := net.ResolveUDPAddr("udp", m.groupAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -68,11 +84,15 @@ func (m *multicast) start() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *multicast) interfaces() map[string]net.Interface {
|
// Stop is not implemented for multicast yet.
|
||||||
|
func (m *Multicast) Stop() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Multicast) interfaces() map[string]net.Interface {
|
||||||
// Get interface expressions from config
|
// Get interface expressions from config
|
||||||
m.core.configMutex.RLock()
|
current, _ := m.config.Get()
|
||||||
exprs := m.core.config.MulticastInterfaces
|
exprs := current.MulticastInterfaces
|
||||||
m.core.configMutex.RUnlock()
|
|
||||||
// Ask the system for network interfaces
|
// Ask the system for network interfaces
|
||||||
interfaces := make(map[string]net.Interface)
|
interfaces := make(map[string]net.Interface)
|
||||||
allifaces, err := net.Interfaces()
|
allifaces, err := net.Interfaces()
|
||||||
@ -108,7 +128,7 @@ func (m *multicast) interfaces() map[string]net.Interface {
|
|||||||
return interfaces
|
return interfaces
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *multicast) announce() {
|
func (m *Multicast) announce() {
|
||||||
groupAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr)
|
groupAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -124,9 +144,9 @@ func (m *multicast) announce() {
|
|||||||
for name, listener := range m.listeners {
|
for name, listener := range m.listeners {
|
||||||
// Prepare our stop function!
|
// Prepare our stop function!
|
||||||
stop := func() {
|
stop := func() {
|
||||||
listener.stop <- true
|
listener.Stop <- true
|
||||||
delete(m.listeners, name)
|
delete(m.listeners, name)
|
||||||
m.core.log.Debugln("No longer multicasting on", name)
|
m.log.Debugln("No longer multicasting on", name)
|
||||||
}
|
}
|
||||||
// If the interface is no longer visible on the system then stop the
|
// If the interface is no longer visible on the system then stop the
|
||||||
// listener, as another one will be started further down
|
// listener, as another one will be started further down
|
||||||
@ -137,7 +157,7 @@ func (m *multicast) announce() {
|
|||||||
// It's possible that the link-local listener address has changed so if
|
// It's possible that the link-local listener address has changed so if
|
||||||
// that is the case then we should clean up the interface listener
|
// that is the case then we should clean up the interface listener
|
||||||
found := false
|
found := false
|
||||||
listenaddr, err := net.ResolveTCPAddr("tcp6", listener.listener.Addr().String())
|
listenaddr, err := net.ResolveTCPAddr("tcp6", listener.Listener.Addr().String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stop()
|
stop()
|
||||||
continue
|
continue
|
||||||
@ -186,17 +206,17 @@ func (m *multicast) announce() {
|
|||||||
// Join the multicast group
|
// Join the multicast group
|
||||||
m.sock.JoinGroup(&iface, groupAddr)
|
m.sock.JoinGroup(&iface, groupAddr)
|
||||||
// Try and see if we already have a TCP listener for this interface
|
// Try and see if we already have a TCP listener for this interface
|
||||||
var listener *tcpListener
|
var listener *yggdrasil.TcpListener
|
||||||
if l, ok := m.listeners[iface.Name]; !ok || l.listener == nil {
|
if l, ok := m.listeners[iface.Name]; !ok || l.Listener == nil {
|
||||||
// No listener was found - let's create one
|
// No listener was found - let's create one
|
||||||
listenaddr := fmt.Sprintf("[%s%%%s]:%d", addrIP, iface.Name, m.listenPort)
|
listenaddr := fmt.Sprintf("[%s%%%s]:%d", addrIP, iface.Name, m.listenPort)
|
||||||
if li, err := m.core.link.tcp.listen(listenaddr); err == nil {
|
if li, err := m.core.ListenTCP(listenaddr); err == nil {
|
||||||
m.core.log.Debugln("Started multicasting on", iface.Name)
|
m.log.Debugln("Started multicasting on", iface.Name)
|
||||||
// Store the listener so that we can stop it later if needed
|
// Store the listener so that we can stop it later if needed
|
||||||
m.listeners[iface.Name] = li
|
m.listeners[iface.Name] = li
|
||||||
listener = li
|
listener = li
|
||||||
} else {
|
} else {
|
||||||
m.core.log.Warnln("Not multicasting on", iface.Name, "due to error:", err)
|
m.log.Warnln("Not multicasting on", iface.Name, "due to error:", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// An existing listener was found
|
// An existing listener was found
|
||||||
@ -207,7 +227,7 @@ func (m *multicast) announce() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Get the listener details and construct the multicast beacon
|
// Get the listener details and construct the multicast beacon
|
||||||
lladdr := listener.listener.Addr().String()
|
lladdr := listener.Listener.Addr().String()
|
||||||
if a, err := net.ResolveTCPAddr("tcp6", lladdr); err == nil {
|
if a, err := net.ResolveTCPAddr("tcp6", lladdr); err == nil {
|
||||||
a.Zone = ""
|
a.Zone = ""
|
||||||
destAddr.Zone = iface.Name
|
destAddr.Zone = iface.Name
|
||||||
@ -221,7 +241,7 @@ func (m *multicast) announce() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *multicast) listen() {
|
func (m *Multicast) listen() {
|
||||||
groupAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr)
|
groupAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -253,8 +273,8 @@ func (m *multicast) listen() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
addr.Zone = ""
|
addr.Zone = ""
|
||||||
if err := m.core.link.call("tcp://"+addr.String(), from.Zone); err != nil {
|
if err := m.core.CallPeer("tcp://"+addr.String(), from.Zone); err != nil {
|
||||||
m.core.log.Debugln("Call from multicast failed:", err)
|
m.log.Debugln("Call from multicast failed:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
// +build darwin
|
// +build darwin
|
||||||
|
|
||||||
package yggdrasil
|
package multicast
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#cgo CFLAGS: -x objective-c
|
#cgo CFLAGS: -x objective-c
|
||||||
@ -31,11 +31,11 @@ import (
|
|||||||
|
|
||||||
var awdlGoroutineStarted bool
|
var awdlGoroutineStarted bool
|
||||||
|
|
||||||
func (m *multicast) multicastStarted() {
|
func (m *Multicast) multicastStarted() {
|
||||||
if awdlGoroutineStarted {
|
if awdlGoroutineStarted {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
m.core.log.Infoln("Multicast discovery will wake up AWDL if required")
|
m.log.Infoln("Multicast discovery will wake up AWDL if required")
|
||||||
awdlGoroutineStarted = true
|
awdlGoroutineStarted = true
|
||||||
for {
|
for {
|
||||||
C.StopAWDLBrowsing()
|
C.StopAWDLBrowsing()
|
||||||
@ -49,7 +49,7 @@ func (m *multicast) multicastStarted() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *multicast) multicastReuse(network string, address string, c syscall.RawConn) error {
|
func (m *Multicast) multicastReuse(network string, address string, c syscall.RawConn) error {
|
||||||
var control error
|
var control error
|
||||||
var reuseport error
|
var reuseport error
|
||||||
var recvanyif error
|
var recvanyif error
|
@ -1,13 +1,13 @@
|
|||||||
// +build !linux,!darwin,!netbsd,!freebsd,!openbsd,!dragonflybsd,!windows
|
// +build !linux,!darwin,!netbsd,!freebsd,!openbsd,!dragonflybsd,!windows
|
||||||
|
|
||||||
package yggdrasil
|
package multicast
|
||||||
|
|
||||||
import "syscall"
|
import "syscall"
|
||||||
|
|
||||||
func (m *multicast) multicastStarted() {
|
func (m *Multicast) multicastStarted() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *multicast) multicastReuse(network string, address string, c syscall.RawConn) error {
|
func (m *Multicast) multicastReuse(network string, address string, c syscall.RawConn) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
@ -1,15 +1,15 @@
|
|||||||
// +build linux netbsd freebsd openbsd dragonflybsd
|
// +build linux netbsd freebsd openbsd dragonflybsd
|
||||||
|
|
||||||
package yggdrasil
|
package multicast
|
||||||
|
|
||||||
import "syscall"
|
import "syscall"
|
||||||
import "golang.org/x/sys/unix"
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
func (m *multicast) multicastStarted() {
|
func (m *Multicast) multicastStarted() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *multicast) multicastReuse(network string, address string, c syscall.RawConn) error {
|
func (m *Multicast) multicastReuse(network string, address string, c syscall.RawConn) error {
|
||||||
var control error
|
var control error
|
||||||
var reuseport error
|
var reuseport error
|
||||||
|
|
@ -1,15 +1,15 @@
|
|||||||
// +build windows
|
// +build windows
|
||||||
|
|
||||||
package yggdrasil
|
package multicast
|
||||||
|
|
||||||
import "syscall"
|
import "syscall"
|
||||||
import "golang.org/x/sys/windows"
|
import "golang.org/x/sys/windows"
|
||||||
|
|
||||||
func (m *multicast) multicastStarted() {
|
func (m *Multicast) multicastStarted() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *multicast) multicastReuse(network string, address string, c syscall.RawConn) error {
|
func (m *Multicast) multicastReuse(network string, address string, c syscall.RawConn) error {
|
||||||
var control error
|
var control error
|
||||||
var reuseaddr error
|
var reuseaddr error
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package yggdrasil
|
package tuntap
|
||||||
|
|
||||||
// The ICMPv6 module implements functions to easily create ICMPv6
|
// The ICMPv6 module implements functions to easily create ICMPv6
|
||||||
// packets. These functions, when mixed with the built-in Go IPv6
|
// packets. These functions, when mixed with the built-in Go IPv6
|
||||||
@ -25,8 +25,8 @@ type macAddress [6]byte
|
|||||||
|
|
||||||
const len_ETHER = 14
|
const len_ETHER = 14
|
||||||
|
|
||||||
type icmpv6 struct {
|
type ICMPv6 struct {
|
||||||
tun *tunAdapter
|
tun *TunAdapter
|
||||||
mylladdr net.IP
|
mylladdr net.IP
|
||||||
mymac macAddress
|
mymac macAddress
|
||||||
peermacs map[address.Address]neighbor
|
peermacs map[address.Address]neighbor
|
||||||
@ -59,7 +59,7 @@ func ipv6Header_Marshal(h *ipv6.Header) ([]byte, error) {
|
|||||||
// Initialises the ICMPv6 module by assigning our link-local IPv6 address and
|
// Initialises the ICMPv6 module by assigning our link-local IPv6 address and
|
||||||
// our MAC address. ICMPv6 messages will always appear to originate from these
|
// our MAC address. ICMPv6 messages will always appear to originate from these
|
||||||
// addresses.
|
// addresses.
|
||||||
func (i *icmpv6) init(t *tunAdapter) {
|
func (i *ICMPv6) Init(t *TunAdapter) {
|
||||||
i.tun = t
|
i.tun = t
|
||||||
i.peermacs = make(map[address.Address]neighbor)
|
i.peermacs = make(map[address.Address]neighbor)
|
||||||
|
|
||||||
@ -69,23 +69,23 @@ func (i *icmpv6) init(t *tunAdapter) {
|
|||||||
i.mylladdr = net.IP{
|
i.mylladdr = net.IP{
|
||||||
0xFE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0xFE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFE}
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFE}
|
||||||
copy(i.mymac[:], i.tun.core.router.addr[:])
|
copy(i.mymac[:], i.tun.addr[:])
|
||||||
copy(i.mylladdr[9:], i.tun.core.router.addr[1:])
|
copy(i.mylladdr[9:], i.tun.addr[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses an incoming ICMPv6 packet. The packet provided may be either an
|
// Parses an incoming ICMPv6 packet. The packet provided may be either an
|
||||||
// ethernet frame containing an IP packet, or the IP packet alone. This is
|
// ethernet frame containing an IP packet, or the IP packet alone. This is
|
||||||
// determined by whether the TUN/TAP adapter is running in TUN (layer 3) or
|
// determined by whether the TUN/TAP adapter is running in TUN (layer 3) or
|
||||||
// TAP (layer 2) mode.
|
// TAP (layer 2) mode.
|
||||||
func (i *icmpv6) parse_packet(datain []byte) {
|
func (i *ICMPv6) ParsePacket(datain []byte) {
|
||||||
var response []byte
|
var response []byte
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// Parse the frame/packet
|
// Parse the frame/packet
|
||||||
if i.tun.iface.IsTAP() {
|
if i.tun.IsTAP() {
|
||||||
response, err = i.parse_packet_tap(datain)
|
response, err = i.UnmarshalPacketL2(datain)
|
||||||
} else {
|
} else {
|
||||||
response, err = i.parse_packet_tun(datain, nil)
|
response, err = i.UnmarshalPacket(datain, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -97,18 +97,18 @@ func (i *icmpv6) parse_packet(datain []byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unwraps the ethernet headers of an incoming ICMPv6 packet and hands off
|
// Unwraps the ethernet headers of an incoming ICMPv6 packet and hands off
|
||||||
// the IP packet to the parse_packet_tun function for further processing.
|
// the IP packet to the ParsePacket function for further processing.
|
||||||
// A response buffer is also created for the response message, also complete
|
// A response buffer is also created for the response message, also complete
|
||||||
// with ethernet headers.
|
// with ethernet headers.
|
||||||
func (i *icmpv6) parse_packet_tap(datain []byte) ([]byte, error) {
|
func (i *ICMPv6) UnmarshalPacketL2(datain []byte) ([]byte, error) {
|
||||||
// Ignore non-IPv6 frames
|
// Ignore non-IPv6 frames
|
||||||
if binary.BigEndian.Uint16(datain[12:14]) != uint16(0x86DD) {
|
if binary.BigEndian.Uint16(datain[12:14]) != uint16(0x86DD) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hand over to parse_packet_tun to interpret the IPv6 packet
|
// Hand over to ParsePacket to interpret the IPv6 packet
|
||||||
mac := datain[6:12]
|
mac := datain[6:12]
|
||||||
ipv6packet, err := i.parse_packet_tun(datain[len_ETHER:], &mac)
|
ipv6packet, err := i.UnmarshalPacket(datain[len_ETHER:], &mac)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -130,7 +130,7 @@ func (i *icmpv6) parse_packet_tap(datain []byte) ([]byte, error) {
|
|||||||
// sanity checks on the packet - i.e. is the packet an ICMPv6 packet, does the
|
// sanity checks on the packet - i.e. is the packet an ICMPv6 packet, does the
|
||||||
// ICMPv6 message match a known expected type. The relevant handler function
|
// ICMPv6 message match a known expected type. The relevant handler function
|
||||||
// is then called and a response packet may be returned.
|
// is then called and a response packet may be returned.
|
||||||
func (i *icmpv6) parse_packet_tun(datain []byte, datamac *[]byte) ([]byte, error) {
|
func (i *ICMPv6) UnmarshalPacket(datain []byte, datamac *[]byte) ([]byte, error) {
|
||||||
// Parse the IPv6 packet headers
|
// Parse the IPv6 packet headers
|
||||||
ipv6Header, err := ipv6.ParseHeader(datain[:ipv6.HeaderLen])
|
ipv6Header, err := ipv6.ParseHeader(datain[:ipv6.HeaderLen])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -156,13 +156,13 @@ func (i *icmpv6) parse_packet_tun(datain []byte, datamac *[]byte) ([]byte, error
|
|||||||
// Check for a supported message type
|
// Check for a supported message type
|
||||||
switch icmpv6Header.Type {
|
switch icmpv6Header.Type {
|
||||||
case ipv6.ICMPTypeNeighborSolicitation:
|
case ipv6.ICMPTypeNeighborSolicitation:
|
||||||
if !i.tun.iface.IsTAP() {
|
if !i.tun.IsTAP() {
|
||||||
return nil, errors.New("Ignoring Neighbor Solicitation in TUN mode")
|
return nil, errors.New("Ignoring Neighbor Solicitation in TUN mode")
|
||||||
}
|
}
|
||||||
response, err := i.handle_ndp(datain[ipv6.HeaderLen:])
|
response, err := i.HandleNDP(datain[ipv6.HeaderLen:])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Create our ICMPv6 response
|
// Create our ICMPv6 response
|
||||||
responsePacket, err := i.create_icmpv6_tun(
|
responsePacket, err := CreateICMPv6(
|
||||||
ipv6Header.Src, i.mylladdr,
|
ipv6Header.Src, i.mylladdr,
|
||||||
ipv6.ICMPTypeNeighborAdvertisement, 0,
|
ipv6.ICMPTypeNeighborAdvertisement, 0,
|
||||||
&icmp.DefaultMessageBody{Data: response})
|
&icmp.DefaultMessageBody{Data: response})
|
||||||
@ -176,7 +176,7 @@ func (i *icmpv6) parse_packet_tun(datain []byte, datamac *[]byte) ([]byte, error
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case ipv6.ICMPTypeNeighborAdvertisement:
|
case ipv6.ICMPTypeNeighborAdvertisement:
|
||||||
if !i.tun.iface.IsTAP() {
|
if !i.tun.IsTAP() {
|
||||||
return nil, errors.New("Ignoring Neighbor Advertisement in TUN mode")
|
return nil, errors.New("Ignoring Neighbor Advertisement in TUN mode")
|
||||||
}
|
}
|
||||||
if datamac != nil {
|
if datamac != nil {
|
||||||
@ -202,9 +202,9 @@ func (i *icmpv6) parse_packet_tun(datain []byte, datamac *[]byte) ([]byte, error
|
|||||||
// Creates an ICMPv6 packet based on the given icmp.MessageBody and other
|
// Creates an ICMPv6 packet based on the given icmp.MessageBody and other
|
||||||
// parameters, complete with ethernet and IP headers, which can be written
|
// parameters, complete with ethernet and IP headers, which can be written
|
||||||
// directly to a TAP adapter.
|
// directly to a TAP adapter.
|
||||||
func (i *icmpv6) create_icmpv6_tap(dstmac macAddress, dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) {
|
func (i *ICMPv6) CreateICMPv6L2(dstmac macAddress, dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) {
|
||||||
// Pass through to create_icmpv6_tun
|
// Pass through to CreateICMPv6
|
||||||
ipv6packet, err := i.create_icmpv6_tun(dst, src, mtype, mcode, mbody)
|
ipv6packet, err := CreateICMPv6(dst, src, mtype, mcode, mbody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -224,9 +224,9 @@ func (i *icmpv6) create_icmpv6_tap(dstmac macAddress, dst net.IP, src net.IP, mt
|
|||||||
|
|
||||||
// Creates an ICMPv6 packet based on the given icmp.MessageBody and other
|
// Creates an ICMPv6 packet based on the given icmp.MessageBody and other
|
||||||
// parameters, complete with IP headers only, which can be written directly to
|
// parameters, complete with IP headers only, which can be written directly to
|
||||||
// a TUN adapter, or called directly by the create_icmpv6_tap function when
|
// a TUN adapter, or called directly by the CreateICMPv6L2 function when
|
||||||
// generating a message for TAP adapters.
|
// generating a message for TAP adapters.
|
||||||
func (i *icmpv6) create_icmpv6_tun(dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) {
|
func CreateICMPv6(dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) {
|
||||||
// Create the ICMPv6 message
|
// Create the ICMPv6 message
|
||||||
icmpMessage := icmp.Message{
|
icmpMessage := icmp.Message{
|
||||||
Type: mtype,
|
Type: mtype,
|
||||||
@ -265,7 +265,7 @@ func (i *icmpv6) create_icmpv6_tun(dst net.IP, src net.IP, mtype ipv6.ICMPType,
|
|||||||
return responsePacket, nil
|
return responsePacket, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *icmpv6) create_ndp_tap(dst address.Address) ([]byte, error) {
|
func (i *ICMPv6) CreateNDPL2(dst address.Address) ([]byte, error) {
|
||||||
// Create the ND payload
|
// Create the ND payload
|
||||||
var payload [28]byte
|
var payload [28]byte
|
||||||
copy(payload[:4], []byte{0x00, 0x00, 0x00, 0x00})
|
copy(payload[:4], []byte{0x00, 0x00, 0x00, 0x00})
|
||||||
@ -287,7 +287,7 @@ func (i *icmpv6) create_ndp_tap(dst address.Address) ([]byte, error) {
|
|||||||
copy(dstmac[2:6], dstaddr[12:16])
|
copy(dstmac[2:6], dstaddr[12:16])
|
||||||
|
|
||||||
// Create the ND request
|
// Create the ND request
|
||||||
requestPacket, err := i.create_icmpv6_tap(
|
requestPacket, err := i.CreateICMPv6L2(
|
||||||
dstmac, dstaddr[:], i.mylladdr,
|
dstmac, dstaddr[:], i.mylladdr,
|
||||||
ipv6.ICMPTypeNeighborSolicitation, 0,
|
ipv6.ICMPTypeNeighborSolicitation, 0,
|
||||||
&icmp.DefaultMessageBody{Data: payload[:]})
|
&icmp.DefaultMessageBody{Data: payload[:]})
|
||||||
@ -305,7 +305,7 @@ func (i *icmpv6) create_ndp_tap(dst address.Address) ([]byte, error) {
|
|||||||
// when the host operating system generates an NDP request for any address in
|
// when the host operating system generates an NDP request for any address in
|
||||||
// the fd00::/8 range, so that the operating system knows to route that traffic
|
// the fd00::/8 range, so that the operating system knows to route that traffic
|
||||||
// to the Yggdrasil TAP adapter.
|
// to the Yggdrasil TAP adapter.
|
||||||
func (i *icmpv6) handle_ndp(in []byte) ([]byte, error) {
|
func (i *ICMPv6) HandleNDP(in []byte) ([]byte, error) {
|
||||||
// Ignore NDP requests for anything outside of fd00::/8
|
// Ignore NDP requests for anything outside of fd00::/8
|
||||||
var source address.Address
|
var source address.Address
|
||||||
copy(source[:], in[8:])
|
copy(source[:], in[8:])
|
361
src/tuntap/tun.go
Normal file
361
src/tuntap/tun.go
Normal file
@ -0,0 +1,361 @@
|
|||||||
|
package tuntap
|
||||||
|
|
||||||
|
// This manages the tun driver to send/recv packets to/from applications
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gologme/log"
|
||||||
|
"golang.org/x/net/icmp"
|
||||||
|
"golang.org/x/net/ipv6"
|
||||||
|
|
||||||
|
"github.com/songgao/packets/ethernet"
|
||||||
|
"github.com/yggdrasil-network/water"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
const tun_IPv6_HEADER_LENGTH = 40
|
||||||
|
const tun_ETHER_HEADER_LENGTH = 14
|
||||||
|
|
||||||
|
// TunAdapter represents a running TUN/TAP interface and extends the
|
||||||
|
// yggdrasil.Adapter type. In order to use the TUN/TAP adapter with Yggdrasil,
|
||||||
|
// you should pass this object to the yggdrasil.SetRouterAdapter() function
|
||||||
|
// before calling yggdrasil.Start().
|
||||||
|
type TunAdapter struct {
|
||||||
|
yggdrasil.Adapter
|
||||||
|
addr address.Address
|
||||||
|
subnet address.Subnet
|
||||||
|
icmpv6 ICMPv6
|
||||||
|
mtu int
|
||||||
|
iface *water.Interface
|
||||||
|
mutex sync.RWMutex // Protects the below
|
||||||
|
isOpen bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the maximum supported MTU for the platform based on the defaults in
|
||||||
|
// defaults.GetDefaults().
|
||||||
|
func getSupportedMTU(mtu int) int {
|
||||||
|
if mtu > defaults.GetDefaults().MaximumIfMTU {
|
||||||
|
return defaults.GetDefaults().MaximumIfMTU
|
||||||
|
}
|
||||||
|
return mtu
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns the name of the adapter, e.g. "tun0". On Windows, this may
|
||||||
|
// return a canonical adapter name instead.
|
||||||
|
func (tun *TunAdapter) Name() string {
|
||||||
|
return tun.iface.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MTU gets the adapter's MTU. This can range between 1280 and 65535, although
|
||||||
|
// the maximum value is determined by your platform. The returned value will
|
||||||
|
// never exceed that of MaximumMTU().
|
||||||
|
func (tun *TunAdapter) MTU() int {
|
||||||
|
return getSupportedMTU(tun.mtu)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsTAP returns true if the adapter is a TAP adapter (Layer 2) or false if it
|
||||||
|
// is a TUN adapter (Layer 3).
|
||||||
|
func (tun *TunAdapter) IsTAP() bool {
|
||||||
|
return tun.iface.IsTAP()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultName gets the default TUN/TAP interface name for your platform.
|
||||||
|
func DefaultName() string {
|
||||||
|
return defaults.GetDefaults().DefaultIfName
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultMTU gets the default TUN/TAP interface MTU for your platform. This can
|
||||||
|
// be as high as MaximumMTU(), depending on platform, but is never lower than 1280.
|
||||||
|
func DefaultMTU() int {
|
||||||
|
return defaults.GetDefaults().DefaultIfMTU
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultIsTAP returns true if the default adapter mode for the current
|
||||||
|
// platform is TAP (Layer 2) and returns false for TUN (Layer 3).
|
||||||
|
func DefaultIsTAP() bool {
|
||||||
|
return defaults.GetDefaults().DefaultIfTAPMode
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaximumMTU returns the maximum supported TUN/TAP interface MTU for your
|
||||||
|
// platform. This can be as high as 65535, depending on platform, but is never
|
||||||
|
// lower than 1280.
|
||||||
|
func MaximumMTU() int {
|
||||||
|
return defaults.GetDefaults().MaximumIfMTU
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init initialises the TUN/TAP adapter.
|
||||||
|
func (tun *TunAdapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte, reject <-chan yggdrasil.RejectedPacket) {
|
||||||
|
tun.Adapter.Init(config, log, send, recv, reject)
|
||||||
|
tun.icmpv6.Init(tun)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
e := <-tun.Reconfigure
|
||||||
|
tun.Config.Mutex.RLock()
|
||||||
|
updated := tun.Config.Current.IfName != tun.Config.Previous.IfName ||
|
||||||
|
tun.Config.Current.IfTAPMode != tun.Config.Previous.IfTAPMode ||
|
||||||
|
tun.Config.Current.IfMTU != tun.Config.Previous.IfMTU
|
||||||
|
tun.Config.Mutex.RUnlock()
|
||||||
|
if updated {
|
||||||
|
tun.Log.Warnln("Reconfiguring TUN/TAP is not supported yet")
|
||||||
|
e <- nil
|
||||||
|
} else {
|
||||||
|
e <- nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(a address.Address, s address.Subnet) error {
|
||||||
|
tun.addr = a
|
||||||
|
tun.subnet = s
|
||||||
|
if tun.Config == nil {
|
||||||
|
return errors.New("No configuration available to TUN/TAP")
|
||||||
|
}
|
||||||
|
tun.Config.Mutex.RLock()
|
||||||
|
ifname := tun.Config.Current.IfName
|
||||||
|
iftapmode := tun.Config.Current.IfTAPMode
|
||||||
|
addr := fmt.Sprintf("%s/%d", net.IP(tun.addr[:]).String(), 8*len(address.GetPrefix())-1)
|
||||||
|
mtu := tun.Config.Current.IfMTU
|
||||||
|
tun.Config.Mutex.RUnlock()
|
||||||
|
if ifname != "none" {
|
||||||
|
if err := tun.setup(ifname, iftapmode, addr, mtu); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ifname == "none" || ifname == "dummy" {
|
||||||
|
tun.Log.Debugln("Not starting TUN/TAP as ifname is none or dummy")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
tun.mutex.Lock()
|
||||||
|
tun.isOpen = true
|
||||||
|
tun.mutex.Unlock()
|
||||||
|
go func() {
|
||||||
|
tun.Log.Debugln("Starting TUN/TAP reader goroutine")
|
||||||
|
tun.Log.Errorln("WARNING: tun.read() exited with error:", tun.read())
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
tun.Log.Debugln("Starting TUN/TAP writer goroutine")
|
||||||
|
tun.Log.Errorln("WARNING: tun.write() exited with error:", tun.write())
|
||||||
|
}()
|
||||||
|
if iftapmode {
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
if _, ok := tun.icmpv6.peermacs[tun.addr]; ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
request, err := tun.icmpv6.CreateNDPL2(tun.addr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if _, err := tun.iface.Write(request); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writes a packet to the TUN/TAP adapter. If the adapter is running in TAP
|
||||||
|
// mode then additional ethernet encapsulation is added for the benefit of the
|
||||||
|
// host operating system.
|
||||||
|
func (tun *TunAdapter) write() error {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case reject := <-tun.Reject:
|
||||||
|
switch reject.Reason {
|
||||||
|
case yggdrasil.PacketTooBig:
|
||||||
|
if mtu, ok := reject.Detail.(int); ok {
|
||||||
|
// Create the Packet Too Big response
|
||||||
|
ptb := &icmp.PacketTooBig{
|
||||||
|
MTU: int(mtu),
|
||||||
|
Data: reject.Packet,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the ICMPv6 response from it
|
||||||
|
icmpv6Buf, err := CreateICMPv6(
|
||||||
|
reject.Packet[8:24], reject.Packet[24:40],
|
||||||
|
ipv6.ICMPTypePacketTooBig, 0, ptb)
|
||||||
|
|
||||||
|
// Send the ICMPv6 response back to the TUN/TAP adapter
|
||||||
|
if err == nil {
|
||||||
|
tun.iface.Write(icmpv6Buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
case data := <-tun.Recv:
|
||||||
|
if tun.iface == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if tun.iface.IsTAP() {
|
||||||
|
var destAddr address.Address
|
||||||
|
if data[0]&0xf0 == 0x60 {
|
||||||
|
if len(data) < 40 {
|
||||||
|
//panic("Tried to send a packet shorter than an IPv6 header...")
|
||||||
|
util.PutBytes(data)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
copy(destAddr[:16], data[24:])
|
||||||
|
} else if data[0]&0xf0 == 0x40 {
|
||||||
|
if len(data) < 20 {
|
||||||
|
//panic("Tried to send a packet shorter than an IPv4 header...")
|
||||||
|
util.PutBytes(data)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
copy(destAddr[:4], data[16:])
|
||||||
|
} else {
|
||||||
|
return errors.New("Invalid address family")
|
||||||
|
}
|
||||||
|
sendndp := func(destAddr address.Address) {
|
||||||
|
neigh, known := tun.icmpv6.peermacs[destAddr]
|
||||||
|
known = known && (time.Since(neigh.lastsolicitation).Seconds() < 30)
|
||||||
|
if !known {
|
||||||
|
request, err := tun.icmpv6.CreateNDPL2(destAddr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if _, err := tun.iface.Write(request); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
tun.icmpv6.peermacs[destAddr] = neighbor{
|
||||||
|
lastsolicitation: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var peermac macAddress
|
||||||
|
var peerknown bool
|
||||||
|
if data[0]&0xf0 == 0x40 {
|
||||||
|
destAddr = tun.addr
|
||||||
|
} else if data[0]&0xf0 == 0x60 {
|
||||||
|
if !bytes.Equal(tun.addr[:16], destAddr[:16]) && !bytes.Equal(tun.subnet[:8], destAddr[:8]) {
|
||||||
|
destAddr = tun.addr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if neighbor, ok := tun.icmpv6.peermacs[destAddr]; ok && neighbor.learned {
|
||||||
|
peermac = neighbor.mac
|
||||||
|
peerknown = true
|
||||||
|
} else if neighbor, ok := tun.icmpv6.peermacs[tun.addr]; ok && neighbor.learned {
|
||||||
|
peermac = neighbor.mac
|
||||||
|
peerknown = true
|
||||||
|
sendndp(destAddr)
|
||||||
|
} else {
|
||||||
|
sendndp(tun.addr)
|
||||||
|
}
|
||||||
|
if peerknown {
|
||||||
|
var proto ethernet.Ethertype
|
||||||
|
switch {
|
||||||
|
case data[0]&0xf0 == 0x60:
|
||||||
|
proto = ethernet.IPv6
|
||||||
|
case data[0]&0xf0 == 0x40:
|
||||||
|
proto = ethernet.IPv4
|
||||||
|
}
|
||||||
|
var frame ethernet.Frame
|
||||||
|
frame.Prepare(
|
||||||
|
peermac[:6], // Destination MAC address
|
||||||
|
tun.icmpv6.mymac[:6], // Source MAC address
|
||||||
|
ethernet.NotTagged, // VLAN tagging
|
||||||
|
proto, // Ethertype
|
||||||
|
len(data)) // Payload length
|
||||||
|
copy(frame[tun_ETHER_HEADER_LENGTH:], data[:])
|
||||||
|
if _, err := tun.iface.Write(frame); err != nil {
|
||||||
|
tun.mutex.RLock()
|
||||||
|
open := tun.isOpen
|
||||||
|
tun.mutex.RUnlock()
|
||||||
|
if !open {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, err := tun.iface.Write(data); err != nil {
|
||||||
|
tun.mutex.RLock()
|
||||||
|
open := tun.isOpen
|
||||||
|
tun.mutex.RUnlock()
|
||||||
|
if !open {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
util.PutBytes(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reads any packets that are waiting on the TUN/TAP adapter. If the adapter
|
||||||
|
// is running in TAP mode then the ethernet headers will automatically be
|
||||||
|
// processed and stripped if necessary. If an ICMPv6 packet is found, then
|
||||||
|
// the relevant helper functions in icmpv6.go are called.
|
||||||
|
func (tun *TunAdapter) read() error {
|
||||||
|
mtu := tun.mtu
|
||||||
|
if tun.iface.IsTAP() {
|
||||||
|
mtu += tun_ETHER_HEADER_LENGTH
|
||||||
|
}
|
||||||
|
buf := make([]byte, mtu)
|
||||||
|
for {
|
||||||
|
n, err := tun.iface.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
tun.mutex.RLock()
|
||||||
|
open := tun.isOpen
|
||||||
|
tun.mutex.RUnlock()
|
||||||
|
if !open {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o := 0
|
||||||
|
if tun.iface.IsTAP() {
|
||||||
|
o = tun_ETHER_HEADER_LENGTH
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case buf[o]&0xf0 == 0x60 && n == 256*int(buf[o+4])+int(buf[o+5])+tun_IPv6_HEADER_LENGTH+o:
|
||||||
|
case buf[o]&0xf0 == 0x40 && n == 256*int(buf[o+2])+int(buf[o+3])+o:
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if buf[o+6] == 58 {
|
||||||
|
if tun.iface.IsTAP() {
|
||||||
|
// Found an ICMPv6 packet
|
||||||
|
b := make([]byte, n)
|
||||||
|
copy(b, buf)
|
||||||
|
go tun.icmpv6.ParsePacket(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
packet := append(util.GetBytes(), buf[o:n]...)
|
||||||
|
tun.Send <- packet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Closes the TUN/TAP adapter. This is only usually called when the Yggdrasil
|
||||||
|
// process stops. Typically this operation will happen quickly, but on macOS
|
||||||
|
// it can block until a read operation is completed.
|
||||||
|
func (tun *TunAdapter) Close() error {
|
||||||
|
tun.mutex.Lock()
|
||||||
|
tun.isOpen = false
|
||||||
|
tun.mutex.Unlock()
|
||||||
|
if tun.iface == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return tun.iface.Close()
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
// +build openbsd freebsd netbsd
|
// +build openbsd freebsd netbsd
|
||||||
|
|
||||||
package yggdrasil
|
package tuntap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
@ -77,7 +77,7 @@ type in6_ifreq_lifetime struct {
|
|||||||
// a system socket and making syscalls to the kernel. This is not refined though
|
// a system socket and making syscalls to the kernel. This is not refined though
|
||||||
// and often doesn't work (if at all), therefore if a call fails, it resorts
|
// and often doesn't work (if at all), therefore if a call fails, it resorts
|
||||||
// to calling "ifconfig" instead.
|
// to calling "ifconfig" instead.
|
||||||
func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
||||||
var config water.Config
|
var config water.Config
|
||||||
if ifname[:4] == "auto" {
|
if ifname[:4] == "auto" {
|
||||||
ifname = "/dev/tap0"
|
ifname = "/dev/tap0"
|
||||||
@ -103,20 +103,20 @@ func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int
|
|||||||
return tun.setupAddress(addr)
|
return tun.setupAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tun *tunAdapter) setupAddress(addr string) error {
|
func (tun *TunAdapter) setupAddress(addr string) error {
|
||||||
var sfd int
|
var sfd int
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// Create system socket
|
// Create system socket
|
||||||
if sfd, err = unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0); err != nil {
|
if sfd, err = unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0); err != nil {
|
||||||
tun.core.log.Printf("Create AF_INET socket failed: %v.", err)
|
tun.Log.Printf("Create AF_INET socket failed: %v.", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Friendly output
|
// Friendly output
|
||||||
tun.core.log.Infof("Interface name: %s", tun.iface.Name())
|
tun.Log.Infof("Interface name: %s", tun.iface.Name())
|
||||||
tun.core.log.Infof("Interface IPv6: %s", addr)
|
tun.Log.Infof("Interface IPv6: %s", addr)
|
||||||
tun.core.log.Infof("Interface MTU: %d", tun.mtu)
|
tun.Log.Infof("Interface MTU: %d", tun.mtu)
|
||||||
|
|
||||||
// Create the MTU request
|
// Create the MTU request
|
||||||
var ir in6_ifreq_mtu
|
var ir in6_ifreq_mtu
|
||||||
@ -126,15 +126,15 @@ func (tun *tunAdapter) setupAddress(addr string) error {
|
|||||||
// Set the MTU
|
// Set the MTU
|
||||||
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(sfd), uintptr(syscall.SIOCSIFMTU), uintptr(unsafe.Pointer(&ir))); errno != 0 {
|
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(sfd), uintptr(syscall.SIOCSIFMTU), uintptr(unsafe.Pointer(&ir))); errno != 0 {
|
||||||
err = errno
|
err = errno
|
||||||
tun.core.log.Errorf("Error in SIOCSIFMTU: %v", errno)
|
tun.Log.Errorf("Error in SIOCSIFMTU: %v", errno)
|
||||||
|
|
||||||
// Fall back to ifconfig to set the MTU
|
// Fall back to ifconfig to set the MTU
|
||||||
cmd := exec.Command("ifconfig", tun.iface.Name(), "mtu", string(tun.mtu))
|
cmd := exec.Command("ifconfig", tun.iface.Name(), "mtu", string(tun.mtu))
|
||||||
tun.core.log.Warnf("Using ifconfig as fallback: %v", strings.Join(cmd.Args, " "))
|
tun.Log.Warnf("Using ifconfig as fallback: %v", strings.Join(cmd.Args, " "))
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tun.core.log.Errorf("SIOCSIFMTU fallback failed: %v.", err)
|
tun.Log.Errorf("SIOCSIFMTU fallback failed: %v.", err)
|
||||||
tun.core.log.Traceln(string(output))
|
tun.Log.Traceln(string(output))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,15 +155,15 @@ func (tun *tunAdapter) setupAddress(addr string) error {
|
|||||||
// Set the interface address
|
// Set the interface address
|
||||||
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(sfd), uintptr(SIOCSIFADDR_IN6), uintptr(unsafe.Pointer(&ar))); errno != 0 {
|
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(sfd), uintptr(SIOCSIFADDR_IN6), uintptr(unsafe.Pointer(&ar))); errno != 0 {
|
||||||
err = errno
|
err = errno
|
||||||
tun.core.log.Errorf("Error in SIOCSIFADDR_IN6: %v", errno)
|
tun.Log.Errorf("Error in SIOCSIFADDR_IN6: %v", errno)
|
||||||
|
|
||||||
// Fall back to ifconfig to set the address
|
// Fall back to ifconfig to set the address
|
||||||
cmd := exec.Command("ifconfig", tun.iface.Name(), "inet6", addr)
|
cmd := exec.Command("ifconfig", tun.iface.Name(), "inet6", addr)
|
||||||
tun.core.log.Warnf("Using ifconfig as fallback: %v", strings.Join(cmd.Args, " "))
|
tun.Log.Warnf("Using ifconfig as fallback: %v", strings.Join(cmd.Args, " "))
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tun.core.log.Errorf("SIOCSIFADDR_IN6 fallback failed: %v.", err)
|
tun.Log.Errorf("SIOCSIFADDR_IN6 fallback failed: %v.", err)
|
||||||
tun.core.log.Traceln(string(output))
|
tun.Log.Traceln(string(output))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
// +build !mobile
|
// +build !mobile
|
||||||
|
|
||||||
package yggdrasil
|
package tuntap
|
||||||
|
|
||||||
// The darwin platform specific tun parts
|
// The darwin platform specific tun parts
|
||||||
|
|
||||||
@ -16,9 +16,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Configures the "utun" adapter with the correct IPv6 address and MTU.
|
// Configures the "utun" adapter with the correct IPv6 address and MTU.
|
||||||
func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
||||||
if iftapmode {
|
if iftapmode {
|
||||||
tun.core.log.Warnln("TAP mode is not supported on this platform, defaulting to TUN")
|
tun.Log.Warnln("TAP mode is not supported on this platform, defaulting to TUN")
|
||||||
}
|
}
|
||||||
config := water.Config{DeviceType: water.TUN}
|
config := water.Config{DeviceType: water.TUN}
|
||||||
iface, err := water.New(config)
|
iface, err := water.New(config)
|
||||||
@ -64,12 +64,12 @@ type ifreq struct {
|
|||||||
|
|
||||||
// Sets the IPv6 address of the utun adapter. On Darwin/macOS this is done using
|
// Sets the IPv6 address of the utun adapter. On Darwin/macOS this is done using
|
||||||
// a system socket and making direct syscalls to the kernel.
|
// a system socket and making direct syscalls to the kernel.
|
||||||
func (tun *tunAdapter) setupAddress(addr string) error {
|
func (tun *TunAdapter) setupAddress(addr string) error {
|
||||||
var fd int
|
var fd int
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if fd, err = unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, 0); err != nil {
|
if fd, err = unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, 0); err != nil {
|
||||||
tun.core.log.Printf("Create AF_SYSTEM socket failed: %v.", err)
|
tun.Log.Printf("Create AF_SYSTEM socket failed: %v.", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,19 +98,19 @@ func (tun *tunAdapter) setupAddress(addr string) error {
|
|||||||
copy(ir.ifr_name[:], tun.iface.Name())
|
copy(ir.ifr_name[:], tun.iface.Name())
|
||||||
ir.ifru_mtu = uint32(tun.mtu)
|
ir.ifru_mtu = uint32(tun.mtu)
|
||||||
|
|
||||||
tun.core.log.Infof("Interface name: %s", ar.ifra_name)
|
tun.Log.Infof("Interface name: %s", ar.ifra_name)
|
||||||
tun.core.log.Infof("Interface IPv6: %s", addr)
|
tun.Log.Infof("Interface IPv6: %s", addr)
|
||||||
tun.core.log.Infof("Interface MTU: %d", ir.ifru_mtu)
|
tun.Log.Infof("Interface MTU: %d", ir.ifru_mtu)
|
||||||
|
|
||||||
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(darwin_SIOCAIFADDR_IN6), uintptr(unsafe.Pointer(&ar))); errno != 0 {
|
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(darwin_SIOCAIFADDR_IN6), uintptr(unsafe.Pointer(&ar))); errno != 0 {
|
||||||
err = errno
|
err = errno
|
||||||
tun.core.log.Errorf("Error in darwin_SIOCAIFADDR_IN6: %v", errno)
|
tun.Log.Errorf("Error in darwin_SIOCAIFADDR_IN6: %v", errno)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(unix.SIOCSIFMTU), uintptr(unsafe.Pointer(&ir))); errno != 0 {
|
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(unix.SIOCSIFMTU), uintptr(unsafe.Pointer(&ir))); errno != 0 {
|
||||||
err = errno
|
err = errno
|
||||||
tun.core.log.Errorf("Error in SIOCSIFMTU: %v", errno)
|
tun.Log.Errorf("Error in SIOCSIFMTU: %v", errno)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -1,19 +1,19 @@
|
|||||||
// +build mobile
|
// +build mobile
|
||||||
|
|
||||||
package yggdrasil
|
package tuntap
|
||||||
|
|
||||||
// This is to catch unsupported platforms
|
// This is to catch unsupported platforms
|
||||||
// If your platform supports tun devices, you could try configuring it manually
|
// 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
|
// Creates the TUN/TAP adapter, if supported by the Water library. Note that
|
||||||
// no guarantees are made at this point on an unsupported platform.
|
// no guarantees are made at this point on an unsupported platform.
|
||||||
func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
||||||
tun.mtu = getSupportedMTU(mtu)
|
tun.mtu = getSupportedMTU(mtu)
|
||||||
return tun.setupAddress(addr)
|
return tun.setupAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't know how to set the IPv6 address on an unknown platform, therefore
|
// 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.
|
// write about it to stdout and don't try to do anything further.
|
||||||
func (tun *tunAdapter) setupAddress(addr string) error {
|
func (tun *TunAdapter) setupAddress(addr string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
// +build !mobile
|
// +build !mobile
|
||||||
|
|
||||||
package yggdrasil
|
package tuntap
|
||||||
|
|
||||||
// The linux platform specific tun parts
|
// The linux platform specific tun parts
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Configures the TAP adapter with the correct IPv6 address and MTU.
|
// Configures the TAP adapter with the correct IPv6 address and MTU.
|
||||||
func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
||||||
var config water.Config
|
var config water.Config
|
||||||
if iftapmode {
|
if iftapmode {
|
||||||
config = water.Config{DeviceType: water.TAP}
|
config = water.Config{DeviceType: water.TAP}
|
||||||
@ -40,9 +40,9 @@ func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Friendly output
|
// Friendly output
|
||||||
tun.core.log.Infof("Interface name: %s", tun.iface.Name())
|
tun.Log.Infof("Interface name: %s", tun.iface.Name())
|
||||||
tun.core.log.Infof("Interface IPv6: %s", addr)
|
tun.Log.Infof("Interface IPv6: %s", addr)
|
||||||
tun.core.log.Infof("Interface MTU: %d", tun.mtu)
|
tun.Log.Infof("Interface MTU: %d", tun.mtu)
|
||||||
return tun.setupAddress(addr)
|
return tun.setupAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int
|
|||||||
// is used to do this, so there is not a hard requirement on "ip" or "ifconfig"
|
// is used to do this, so there is not a hard requirement on "ip" or "ifconfig"
|
||||||
// to exist on the system, but this will fail if Netlink is not present in the
|
// to exist on the system, but this will fail if Netlink is not present in the
|
||||||
// kernel (it nearly always is).
|
// kernel (it nearly always is).
|
||||||
func (tun *tunAdapter) setupAddress(addr string) error {
|
func (tun *TunAdapter) setupAddress(addr string) error {
|
||||||
// Set address
|
// Set address
|
||||||
var netIF *net.Interface
|
var netIF *net.Interface
|
||||||
ifces, err := net.Interfaces()
|
ifces, err := net.Interfaces()
|
@ -1,6 +1,6 @@
|
|||||||
// +build !linux,!darwin,!windows,!openbsd,!freebsd,!netbsd,!mobile
|
// +build !linux,!darwin,!windows,!openbsd,!freebsd,!netbsd,!mobile
|
||||||
|
|
||||||
package yggdrasil
|
package tuntap
|
||||||
|
|
||||||
import water "github.com/yggdrasil-network/water"
|
import water "github.com/yggdrasil-network/water"
|
||||||
|
|
||||||
@ -9,7 +9,7 @@ import water "github.com/yggdrasil-network/water"
|
|||||||
|
|
||||||
// Creates the TUN/TAP adapter, if supported by the Water library. Note that
|
// Creates the TUN/TAP adapter, if supported by the Water library. Note that
|
||||||
// no guarantees are made at this point on an unsupported platform.
|
// no guarantees are made at this point on an unsupported platform.
|
||||||
func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
||||||
var config water.Config
|
var config water.Config
|
||||||
if iftapmode {
|
if iftapmode {
|
||||||
config = water.Config{DeviceType: water.TAP}
|
config = water.Config{DeviceType: water.TAP}
|
||||||
@ -27,7 +27,7 @@ func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int
|
|||||||
|
|
||||||
// We don't know how to set the IPv6 address on an unknown platform, therefore
|
// 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.
|
// write about it to stdout and don't try to do anything further.
|
||||||
func (tun *tunAdapter) setupAddress(addr string) error {
|
func (tun *TunAdapter) setupAddress(addr string) error {
|
||||||
tun.core.log.Warnln("Platform not supported, you must set the address of", tun.iface.Name(), "to", addr)
|
tun.Log.Warnln("Platform not supported, you must set the address of", tun.iface.Name(), "to", addr)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package yggdrasil
|
package tuntap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -13,9 +13,9 @@ import (
|
|||||||
// Configures the TAP adapter with the correct IPv6 address and MTU. On Windows
|
// Configures the TAP adapter with the correct IPv6 address and MTU. On Windows
|
||||||
// we don't make use of a direct operating system API to do this - we instead
|
// we don't make use of a direct operating system API to do this - we instead
|
||||||
// delegate the hard work to "netsh".
|
// delegate the hard work to "netsh".
|
||||||
func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
||||||
if !iftapmode {
|
if !iftapmode {
|
||||||
tun.core.log.Warnln("TUN mode is not supported on this platform, defaulting to TAP")
|
tun.Log.Warnln("TUN mode is not supported on this platform, defaulting to TAP")
|
||||||
}
|
}
|
||||||
config := water.Config{DeviceType: water.TAP}
|
config := water.Config{DeviceType: water.TAP}
|
||||||
config.PlatformSpecificParams.ComponentID = "tap0901"
|
config.PlatformSpecificParams.ComponentID = "tap0901"
|
||||||
@ -31,19 +31,19 @@ func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int
|
|||||||
}
|
}
|
||||||
// Disable/enable the interface to resets its configuration (invalidating iface)
|
// Disable/enable the interface to resets its configuration (invalidating iface)
|
||||||
cmd := exec.Command("netsh", "interface", "set", "interface", iface.Name(), "admin=DISABLED")
|
cmd := exec.Command("netsh", "interface", "set", "interface", iface.Name(), "admin=DISABLED")
|
||||||
tun.core.log.Printf("netsh command: %v", strings.Join(cmd.Args, " "))
|
tun.Log.Printf("netsh command: %v", strings.Join(cmd.Args, " "))
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tun.core.log.Errorf("Windows netsh failed: %v.", err)
|
tun.Log.Errorf("Windows netsh failed: %v.", err)
|
||||||
tun.core.log.Traceln(string(output))
|
tun.Log.Traceln(string(output))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cmd = exec.Command("netsh", "interface", "set", "interface", iface.Name(), "admin=ENABLED")
|
cmd = exec.Command("netsh", "interface", "set", "interface", iface.Name(), "admin=ENABLED")
|
||||||
tun.core.log.Printf("netsh command: %v", strings.Join(cmd.Args, " "))
|
tun.Log.Printf("netsh command: %v", strings.Join(cmd.Args, " "))
|
||||||
output, err = cmd.CombinedOutput()
|
output, err = cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tun.core.log.Errorf("Windows netsh failed: %v.", err)
|
tun.Log.Errorf("Windows netsh failed: %v.", err)
|
||||||
tun.core.log.Traceln(string(output))
|
tun.Log.Traceln(string(output))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Get a new iface
|
// Get a new iface
|
||||||
@ -58,41 +58,41 @@ func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
// Friendly output
|
// Friendly output
|
||||||
tun.core.log.Infof("Interface name: %s", tun.iface.Name())
|
tun.Log.Infof("Interface name: %s", tun.iface.Name())
|
||||||
tun.core.log.Infof("Interface IPv6: %s", addr)
|
tun.Log.Infof("Interface IPv6: %s", addr)
|
||||||
tun.core.log.Infof("Interface MTU: %d", tun.mtu)
|
tun.Log.Infof("Interface MTU: %d", tun.mtu)
|
||||||
return tun.setupAddress(addr)
|
return tun.setupAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the MTU of the TAP adapter.
|
// Sets the MTU of the TAP adapter.
|
||||||
func (tun *tunAdapter) setupMTU(mtu int) error {
|
func (tun *TunAdapter) setupMTU(mtu int) error {
|
||||||
// Set MTU
|
// Set MTU
|
||||||
cmd := exec.Command("netsh", "interface", "ipv6", "set", "subinterface",
|
cmd := exec.Command("netsh", "interface", "ipv6", "set", "subinterface",
|
||||||
fmt.Sprintf("interface=%s", tun.iface.Name()),
|
fmt.Sprintf("interface=%s", tun.iface.Name()),
|
||||||
fmt.Sprintf("mtu=%d", mtu),
|
fmt.Sprintf("mtu=%d", mtu),
|
||||||
"store=active")
|
"store=active")
|
||||||
tun.core.log.Debugln("netsh command: %v", strings.Join(cmd.Args, " "))
|
tun.Log.Debugln("netsh command: %v", strings.Join(cmd.Args, " "))
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tun.core.log.Errorf("Windows netsh failed: %v.", err)
|
tun.Log.Errorf("Windows netsh failed: %v.", err)
|
||||||
tun.core.log.Traceln(string(output))
|
tun.Log.Traceln(string(output))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the IPv6 address of the TAP adapter.
|
// Sets the IPv6 address of the TAP adapter.
|
||||||
func (tun *tunAdapter) setupAddress(addr string) error {
|
func (tun *TunAdapter) setupAddress(addr string) error {
|
||||||
// Set address
|
// Set address
|
||||||
cmd := exec.Command("netsh", "interface", "ipv6", "add", "address",
|
cmd := exec.Command("netsh", "interface", "ipv6", "add", "address",
|
||||||
fmt.Sprintf("interface=%s", tun.iface.Name()),
|
fmt.Sprintf("interface=%s", tun.iface.Name()),
|
||||||
fmt.Sprintf("addr=%s", addr),
|
fmt.Sprintf("addr=%s", addr),
|
||||||
"store=active")
|
"store=active")
|
||||||
tun.core.log.Debugln("netsh command: %v", strings.Join(cmd.Args, " "))
|
tun.Log.Debugln("netsh command: %v", strings.Join(cmd.Args, " "))
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tun.core.log.Errorf("Windows netsh failed: %v.", err)
|
tun.Log.Errorf("Windows netsh failed: %v.", err)
|
||||||
tun.core.log.Traceln(string(output))
|
tun.Log.Traceln(string(output))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
@ -1,18 +1,47 @@
|
|||||||
package yggdrasil
|
package yggdrasil
|
||||||
|
|
||||||
// Defines the minimum required struct members for an adapter type (this is
|
import (
|
||||||
// now the base type for tunAdapter in tun.go)
|
"github.com/gologme/log"
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Adapter defines the minimum required struct members for an adapter type. This
|
||||||
|
// is now the base type for adapters like tun.go. When implementing a new
|
||||||
|
// adapter type, you should extend the adapter struct with this one and should
|
||||||
|
// call the Adapter.Init() function when initialising.
|
||||||
type Adapter struct {
|
type Adapter struct {
|
||||||
core *Core
|
adapterImplementation
|
||||||
send chan<- []byte
|
Core *Core
|
||||||
recv <-chan []byte
|
Config *config.NodeState
|
||||||
reconfigure chan chan error
|
Log *log.Logger
|
||||||
|
Send chan<- []byte
|
||||||
|
Recv <-chan []byte
|
||||||
|
Reject <-chan RejectedPacket
|
||||||
|
Reconfigure chan chan error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialises the adapter.
|
// Defines the minimum required functions for an adapter type. Note that the
|
||||||
func (adapter *Adapter) init(core *Core, send chan<- []byte, recv <-chan []byte) {
|
// implementation of Init() should call Adapter.Init(). This is not exported
|
||||||
adapter.core = core
|
// because doing so breaks the gomobile bindings for iOS/Android.
|
||||||
adapter.send = send
|
type adapterImplementation interface {
|
||||||
adapter.recv = recv
|
Init(*config.NodeState, *log.Logger, chan<- []byte, <-chan []byte, <-chan RejectedPacket)
|
||||||
adapter.reconfigure = make(chan chan error, 1)
|
Name() string
|
||||||
|
MTU() int
|
||||||
|
IsTAP() bool
|
||||||
|
Start(address.Address, address.Subnet) error
|
||||||
|
Close() error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init initialises the adapter with the necessary channels to operate from the
|
||||||
|
// router. When defining a new Adapter type, the Adapter should call this
|
||||||
|
// function from within it's own Init function to set up the channels. It is
|
||||||
|
// otherwise not expected for you to call this function directly.
|
||||||
|
func (adapter *Adapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte, reject <-chan RejectedPacket) {
|
||||||
|
adapter.Config = config
|
||||||
|
adapter.Log = log
|
||||||
|
adapter.Send = send
|
||||||
|
adapter.Recv = recv
|
||||||
|
adapter.Reject = reject
|
||||||
|
adapter.Reconfigure = make(chan chan error, 1)
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@ import (
|
|||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Add authentication
|
// TODO: Add authentication
|
||||||
@ -58,19 +57,17 @@ func (a *admin) init(c *Core) {
|
|||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
e := <-a.reconfigure
|
e := <-a.reconfigure
|
||||||
a.core.configMutex.RLock()
|
current, previous := a.core.config.Get()
|
||||||
if a.core.config.AdminListen != a.core.configOld.AdminListen {
|
if current.AdminListen != previous.AdminListen {
|
||||||
a.listenaddr = a.core.config.AdminListen
|
a.listenaddr = current.AdminListen
|
||||||
a.close()
|
a.close()
|
||||||
a.start()
|
a.start()
|
||||||
}
|
}
|
||||||
a.core.configMutex.RUnlock()
|
|
||||||
e <- nil
|
e <- nil
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
a.core.configMutex.RLock()
|
current, _ := a.core.config.Get()
|
||||||
a.listenaddr = a.core.config.AdminListen
|
a.listenaddr = current.AdminListen
|
||||||
a.core.configMutex.RUnlock()
|
|
||||||
a.addHandler("list", []string{}, func(in admin_info) (admin_info, error) {
|
a.addHandler("list", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
handlers := make(map[string]interface{})
|
handlers := make(map[string]interface{})
|
||||||
for _, handler := range a.handlers {
|
for _, handler := range a.handlers {
|
||||||
@ -171,7 +168,7 @@ func (a *admin) init(c *Core) {
|
|||||||
}, errors.New("Failed to remove peer")
|
}, errors.New("Failed to remove peer")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
a.addHandler("getTunTap", []string{}, func(in admin_info) (r admin_info, e error) {
|
/* a.addHandler("getTunTap", []string{}, func(in admin_info) (r admin_info, e error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
r = admin_info{"none": admin_info{}}
|
r = admin_info{"none": admin_info{}}
|
||||||
@ -211,14 +208,14 @@ func (a *admin) init(c *Core) {
|
|||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
})
|
})*/
|
||||||
a.addHandler("getMulticastInterfaces", []string{}, func(in admin_info) (admin_info, error) {
|
/*a.addHandler("getMulticastInterfaces", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
var intfs []string
|
var intfs []string
|
||||||
for _, v := range a.core.multicast.interfaces() {
|
for _, v := range a.core.multicast.interfaces() {
|
||||||
intfs = append(intfs, v.Name)
|
intfs = append(intfs, v.Name)
|
||||||
}
|
}
|
||||||
return admin_info{"multicast_interfaces": intfs}, nil
|
return admin_info{"multicast_interfaces": intfs}, nil
|
||||||
})
|
})*/
|
||||||
a.addHandler("getAllowedEncryptionPublicKeys", []string{}, func(in admin_info) (admin_info, error) {
|
a.addHandler("getAllowedEncryptionPublicKeys", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
return admin_info{"allowed_box_pubs": a.getAllowedEncryptionPublicKeys()}, nil
|
return admin_info{"allowed_box_pubs": a.getAllowedEncryptionPublicKeys()}, nil
|
||||||
})
|
})
|
||||||
@ -609,6 +606,7 @@ func (a *admin) removePeer(p string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// startTunWithMTU creates the tun/tap device, sets its address, and sets the MTU to the provided value.
|
// startTunWithMTU creates the tun/tap device, sets its address, and sets the MTU to the provided value.
|
||||||
|
/*
|
||||||
func (a *admin) startTunWithMTU(ifname string, iftapmode bool, ifmtu int) error {
|
func (a *admin) startTunWithMTU(ifname string, iftapmode bool, ifmtu int) error {
|
||||||
// Close the TUN first if open
|
// Close the TUN first if open
|
||||||
_ = a.core.router.tun.close()
|
_ = a.core.router.tun.close()
|
||||||
@ -636,6 +634,7 @@ func (a *admin) startTunWithMTU(ifname string, iftapmode bool, ifmtu int) error
|
|||||||
go a.core.router.tun.write()
|
go a.core.router.tun.write()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// getData_getSelf returns the self node's info for admin responses.
|
// getData_getSelf returns the self node's info for admin responses.
|
||||||
func (a *admin) getData_getSelf() *admin_nodeInfo {
|
func (a *admin) getData_getSelf() *admin_nodeInfo {
|
||||||
@ -643,14 +642,14 @@ func (a *admin) getData_getSelf() *admin_nodeInfo {
|
|||||||
coords := table.self.getCoords()
|
coords := table.self.getCoords()
|
||||||
self := admin_nodeInfo{
|
self := admin_nodeInfo{
|
||||||
{"box_pub_key", hex.EncodeToString(a.core.boxPub[:])},
|
{"box_pub_key", hex.EncodeToString(a.core.boxPub[:])},
|
||||||
{"ip", a.core.GetAddress().String()},
|
{"ip", a.core.Address().String()},
|
||||||
{"subnet", a.core.GetSubnet().String()},
|
{"subnet", a.core.Subnet().String()},
|
||||||
{"coords", fmt.Sprint(coords)},
|
{"coords", fmt.Sprint(coords)},
|
||||||
}
|
}
|
||||||
if name := GetBuildName(); name != "unknown" {
|
if name := BuildName(); name != "unknown" {
|
||||||
self = append(self, admin_pair{"build_name", name})
|
self = append(self, admin_pair{"build_name", name})
|
||||||
}
|
}
|
||||||
if version := GetBuildVersion(); version != "unknown" {
|
if version := BuildVersion(); version != "unknown" {
|
||||||
self = append(self, admin_pair{"build_version", version})
|
self = append(self, admin_pair{"build_version", version})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,25 +55,24 @@ func (c *cryptokey) init(core *Core) {
|
|||||||
// 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 {
|
||||||
c.core.configMutex.RLock()
|
current, _ := c.core.config.Get()
|
||||||
defer c.core.configMutex.RUnlock()
|
|
||||||
|
|
||||||
// Set enabled/disabled state
|
// Set enabled/disabled state
|
||||||
c.setEnabled(c.core.config.TunnelRouting.Enable)
|
c.setEnabled(current.TunnelRouting.Enable)
|
||||||
|
|
||||||
// Clear out existing routes
|
// Clear out existing routes
|
||||||
c.ipv6routes = make([]cryptokey_route, 0)
|
c.ipv6routes = make([]cryptokey_route, 0)
|
||||||
c.ipv4routes = make([]cryptokey_route, 0)
|
c.ipv4routes = make([]cryptokey_route, 0)
|
||||||
|
|
||||||
// Add IPv6 routes
|
// Add IPv6 routes
|
||||||
for ipv6, pubkey := range c.core.config.TunnelRouting.IPv6Destinations {
|
for ipv6, pubkey := range current.TunnelRouting.IPv6Destinations {
|
||||||
if err := c.addRoute(ipv6, pubkey); err != nil {
|
if err := c.addRoute(ipv6, pubkey); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add IPv4 routes
|
// Add IPv4 routes
|
||||||
for ipv4, pubkey := range c.core.config.TunnelRouting.IPv4Destinations {
|
for ipv4, pubkey := range current.TunnelRouting.IPv4Destinations {
|
||||||
if err := c.addRoute(ipv4, pubkey); err != nil {
|
if err := c.addRoute(ipv4, pubkey); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -85,7 +84,7 @@ func (c *cryptokey) configure() error {
|
|||||||
|
|
||||||
// Add IPv6 sources
|
// Add IPv6 sources
|
||||||
c.ipv6sources = make([]net.IPNet, 0)
|
c.ipv6sources = make([]net.IPNet, 0)
|
||||||
for _, source := range c.core.config.TunnelRouting.IPv6Sources {
|
for _, source := range current.TunnelRouting.IPv6Sources {
|
||||||
if err := c.addSourceSubnet(source); err != nil {
|
if err := c.addSourceSubnet(source); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -93,7 +92,7 @@ func (c *cryptokey) configure() error {
|
|||||||
|
|
||||||
// Add IPv4 sources
|
// Add IPv4 sources
|
||||||
c.ipv4sources = make([]net.IPNet, 0)
|
c.ipv4sources = make([]net.IPNet, 0)
|
||||||
for _, source := range c.core.config.TunnelRouting.IPv4Sources {
|
for _, source := range current.TunnelRouting.IPv4Sources {
|
||||||
if err := c.addSourceSubnet(source); err != nil {
|
if err := c.addSourceSubnet(source); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,9 @@ package yggdrasil
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gologme/log"
|
"github.com/gologme/log"
|
||||||
@ -12,26 +12,18 @@ import (
|
|||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var buildName string
|
var buildName string
|
||||||
var buildVersion string
|
var buildVersion string
|
||||||
|
|
||||||
type module interface {
|
|
||||||
init(*Core, *config.NodeConfig) error
|
|
||||||
start() error
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Core object represents the Yggdrasil node. You should create a Core
|
// The Core object represents the Yggdrasil node. You should create a Core
|
||||||
// object for each Yggdrasil node you plan to run.
|
// object for each Yggdrasil node you plan to run.
|
||||||
type Core struct {
|
type Core struct {
|
||||||
// This is the main data structure that holds everything else for a node
|
// This is the main data structure that holds everything else for a node
|
||||||
// We're going to keep our own copy of the provided config - that way we can
|
// We're going to keep our own copy of the provided config - that way we can
|
||||||
// guarantee that it will be covered by the mutex
|
// guarantee that it will be covered by the mutex
|
||||||
config config.NodeConfig // Active config
|
config config.NodeState // Config
|
||||||
configOld config.NodeConfig // Previous config
|
|
||||||
configMutex sync.RWMutex // Protects both config and configOld
|
|
||||||
boxPub crypto.BoxPubKey
|
boxPub crypto.BoxPubKey
|
||||||
boxPriv crypto.BoxPrivKey
|
boxPriv crypto.BoxPrivKey
|
||||||
sigPub crypto.SigPubKey
|
sigPub crypto.SigPubKey
|
||||||
@ -43,7 +35,6 @@ type Core struct {
|
|||||||
dht dht
|
dht dht
|
||||||
admin admin
|
admin admin
|
||||||
searches searches
|
searches searches
|
||||||
multicast multicast
|
|
||||||
link link
|
link link
|
||||||
log *log.Logger
|
log *log.Logger
|
||||||
}
|
}
|
||||||
@ -57,19 +48,21 @@ func (c *Core) init() error {
|
|||||||
c.log = log.New(ioutil.Discard, "", 0)
|
c.log = log.New(ioutil.Discard, "", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
boxPubHex, err := hex.DecodeString(c.config.EncryptionPublicKey)
|
current, _ := c.config.Get()
|
||||||
|
|
||||||
|
boxPubHex, err := hex.DecodeString(current.EncryptionPublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
boxPrivHex, err := hex.DecodeString(c.config.EncryptionPrivateKey)
|
boxPrivHex, err := hex.DecodeString(current.EncryptionPrivateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
sigPubHex, err := hex.DecodeString(c.config.SigningPublicKey)
|
sigPubHex, err := hex.DecodeString(current.SigningPublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
sigPrivHex, err := hex.DecodeString(c.config.SigningPrivateKey)
|
sigPrivHex, err := hex.DecodeString(current.SigningPrivateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -83,7 +76,7 @@ func (c *Core) init() error {
|
|||||||
c.searches.init(c)
|
c.searches.init(c)
|
||||||
c.dht.init(c)
|
c.dht.init(c)
|
||||||
c.sessions.init(c)
|
c.sessions.init(c)
|
||||||
c.multicast.init(c)
|
//c.multicast.init(c)
|
||||||
c.peers.init(c)
|
c.peers.init(c)
|
||||||
c.router.init(c)
|
c.router.init(c)
|
||||||
c.switchTable.init(c) // TODO move before peers? before router?
|
c.switchTable.init(c) // TODO move before peers? before router?
|
||||||
@ -96,20 +89,17 @@ func (c *Core) init() error {
|
|||||||
// be reconnected with.
|
// be reconnected with.
|
||||||
func (c *Core) addPeerLoop() {
|
func (c *Core) addPeerLoop() {
|
||||||
for {
|
for {
|
||||||
// Get the peers from the config - these could change!
|
// the peers from the config - these could change!
|
||||||
c.configMutex.RLock()
|
current, _ := c.config.Get()
|
||||||
peers := c.config.Peers
|
|
||||||
interfacepeers := c.config.InterfacePeers
|
|
||||||
c.configMutex.RUnlock()
|
|
||||||
|
|
||||||
// Add peers from the Peers section
|
// Add peers from the Peers section
|
||||||
for _, peer := range peers {
|
for _, peer := range current.Peers {
|
||||||
c.AddPeer(peer, "")
|
c.AddPeer(peer, "")
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add peers from the InterfacePeers section
|
// Add peers from the InterfacePeers section
|
||||||
for intf, intfpeers := range interfacepeers {
|
for intf, intfpeers := range current.InterfacePeers {
|
||||||
for _, peer := range intfpeers {
|
for _, peer := range intfpeers {
|
||||||
c.AddPeer(peer, intf)
|
c.AddPeer(peer, intf)
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
@ -121,15 +111,13 @@ func (c *Core) addPeerLoop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateConfig updates the configuration in Core and then signals the
|
// UpdateConfig updates the configuration in Core with the provided
|
||||||
// various module goroutines to reconfigure themselves if needed
|
// config.NodeConfig and then signals the various module goroutines to
|
||||||
|
// reconfigure themselves if needed.
|
||||||
func (c *Core) UpdateConfig(config *config.NodeConfig) {
|
func (c *Core) UpdateConfig(config *config.NodeConfig) {
|
||||||
c.log.Infoln("Reloading configuration...")
|
c.log.Infoln("Reloading configuration...")
|
||||||
|
|
||||||
c.configMutex.Lock()
|
c.config.Replace(*config)
|
||||||
c.configOld = c.config
|
|
||||||
c.config = *config
|
|
||||||
c.configMutex.Unlock()
|
|
||||||
|
|
||||||
errors := 0
|
errors := 0
|
||||||
|
|
||||||
@ -140,11 +128,9 @@ func (c *Core) UpdateConfig(config *config.NodeConfig) {
|
|||||||
c.sessions.reconfigure,
|
c.sessions.reconfigure,
|
||||||
c.peers.reconfigure,
|
c.peers.reconfigure,
|
||||||
c.router.reconfigure,
|
c.router.reconfigure,
|
||||||
c.router.tun.reconfigure,
|
|
||||||
c.router.cryptokey.reconfigure,
|
c.router.cryptokey.reconfigure,
|
||||||
c.switchTable.reconfigure,
|
c.switchTable.reconfigure,
|
||||||
c.link.reconfigure,
|
c.link.reconfigure,
|
||||||
c.multicast.reconfigure,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, component := range components {
|
for _, component := range components {
|
||||||
@ -163,190 +149,219 @@ func (c *Core) UpdateConfig(config *config.NodeConfig) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBuildName gets the current build name. This is usually injected if built
|
// BuildName gets the current build name. This is usually injected if built
|
||||||
// from git, or returns "unknown" otherwise.
|
// from git, or returns "unknown" otherwise.
|
||||||
func GetBuildName() string {
|
func BuildName() string {
|
||||||
if buildName == "" {
|
if buildName == "" {
|
||||||
return "unknown"
|
return "unknown"
|
||||||
}
|
}
|
||||||
return buildName
|
return buildName
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the current build version. This is usually injected if built from git,
|
// BuildVersion gets the current build version. This is usually injected if
|
||||||
// or returns "unknown" otherwise.
|
// built from git, or returns "unknown" otherwise.
|
||||||
func GetBuildVersion() string {
|
func BuildVersion() string {
|
||||||
if buildVersion == "" {
|
if buildVersion == "" {
|
||||||
return "unknown"
|
return "unknown"
|
||||||
}
|
}
|
||||||
return buildVersion
|
return buildVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
// Starts up Yggdrasil using the provided NodeConfig, and outputs debug logging
|
// SetRouterAdapter instructs Yggdrasil to use the given adapter when starting
|
||||||
// through the provided log.Logger. The started stack will include TCP and UDP
|
// the router. The adapter must implement the standard
|
||||||
// sockets, a multicast discovery socket, an admin socket, router, switch and
|
// adapter.adapterImplementation interface and should extend the adapter.Adapter
|
||||||
// DHT node.
|
// struct.
|
||||||
func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error {
|
func (c *Core) SetRouterAdapter(adapter interface{}) error {
|
||||||
|
// We do this because adapterImplementation is not a valid type for the
|
||||||
|
// gomobile bindings so we just ask for a generic interface and try to cast it
|
||||||
|
// to adapterImplementation instead
|
||||||
|
if a, ok := adapter.(adapterImplementation); ok {
|
||||||
|
c.router.adapter = a
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("unsuitable adapter")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start starts up Yggdrasil using the provided config.NodeConfig, and outputs
|
||||||
|
// debug logging through the provided log.Logger. The started stack will include
|
||||||
|
// TCP and UDP sockets, a multicast discovery socket, an admin socket, router,
|
||||||
|
// switch and DHT node. A config.NodeState is returned which contains both the
|
||||||
|
// current and previous configurations (from reconfigures).
|
||||||
|
func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) (*config.NodeState, error) {
|
||||||
c.log = log
|
c.log = log
|
||||||
|
|
||||||
if name := GetBuildName(); name != "unknown" {
|
c.config = config.NodeState{
|
||||||
|
Current: *nc,
|
||||||
|
Previous: *nc,
|
||||||
|
}
|
||||||
|
|
||||||
|
if name := BuildName(); name != "unknown" {
|
||||||
c.log.Infoln("Build name:", name)
|
c.log.Infoln("Build name:", name)
|
||||||
}
|
}
|
||||||
if version := GetBuildVersion(); version != "unknown" {
|
if version := BuildVersion(); version != "unknown" {
|
||||||
c.log.Infoln("Build version:", version)
|
c.log.Infoln("Build version:", version)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.log.Infoln("Starting up...")
|
c.log.Infoln("Starting up...")
|
||||||
|
|
||||||
c.configMutex.Lock()
|
|
||||||
c.config = *nc
|
|
||||||
c.configOld = c.config
|
|
||||||
c.configMutex.Unlock()
|
|
||||||
|
|
||||||
c.init()
|
c.init()
|
||||||
|
|
||||||
if err := c.link.init(c); err != nil {
|
if err := c.link.init(c); err != nil {
|
||||||
c.log.Errorln("Failed to start link interfaces")
|
c.log.Errorln("Failed to start link interfaces")
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if nc.SwitchOptions.MaxTotalQueueSize >= SwitchQueueTotalMinSize {
|
c.config.Mutex.RLock()
|
||||||
c.switchTable.queueTotalMaxSize = nc.SwitchOptions.MaxTotalQueueSize
|
if c.config.Current.SwitchOptions.MaxTotalQueueSize >= SwitchQueueTotalMinSize {
|
||||||
|
c.switchTable.queueTotalMaxSize = c.config.Current.SwitchOptions.MaxTotalQueueSize
|
||||||
}
|
}
|
||||||
|
c.config.Mutex.RUnlock()
|
||||||
|
|
||||||
if err := c.switchTable.start(); err != nil {
|
if err := c.switchTable.start(); err != nil {
|
||||||
c.log.Errorln("Failed to start switch")
|
c.log.Errorln("Failed to start switch")
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.router.start(); err != nil {
|
if err := c.router.start(); err != nil {
|
||||||
c.log.Errorln("Failed to start router")
|
c.log.Errorln("Failed to start router")
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.admin.start(); err != nil {
|
if err := c.admin.start(); err != nil {
|
||||||
c.log.Errorln("Failed to start admin socket")
|
c.log.Errorln("Failed to start admin socket")
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.multicast.start(); err != nil {
|
if c.router.adapter != nil {
|
||||||
c.log.Errorln("Failed to start multicast interface")
|
if err := c.router.adapter.Start(c.router.addr, c.router.subnet); err != nil {
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.router.tun.start(); err != nil {
|
|
||||||
c.log.Errorln("Failed to start TUN/TAP")
|
c.log.Errorln("Failed to start TUN/TAP")
|
||||||
return err
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
go c.addPeerLoop()
|
go c.addPeerLoop()
|
||||||
|
|
||||||
c.log.Infoln("Startup complete")
|
c.log.Infoln("Startup complete")
|
||||||
return nil
|
return &c.config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stops the Yggdrasil node.
|
// Stop shuts down the Yggdrasil node.
|
||||||
func (c *Core) Stop() {
|
func (c *Core) Stop() {
|
||||||
c.log.Infoln("Stopping...")
|
c.log.Infoln("Stopping...")
|
||||||
c.router.tun.close()
|
if c.router.adapter != nil {
|
||||||
|
c.router.adapter.Close()
|
||||||
|
}
|
||||||
c.admin.close()
|
c.admin.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates a new encryption keypair. The encryption keys are used to
|
// ListenTCP starts a new TCP listener. The input URI should match that of the
|
||||||
// encrypt traffic and to derive the IPv6 address/subnet of the node.
|
// "Listen" configuration item, e.g.
|
||||||
|
// tcp://a.b.c.d:e
|
||||||
|
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) {
|
func (c *Core) NewEncryptionKeys() (*crypto.BoxPubKey, *crypto.BoxPrivKey) {
|
||||||
return crypto.NewBoxKeys()
|
return crypto.NewBoxKeys()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates a new signing keypair. The signing keys are used to derive the
|
// NewSigningKeys generates a new signing keypair. The signing keys are used to
|
||||||
// structure of the spanning tree.
|
// derive the structure of the spanning tree.
|
||||||
func (c *Core) NewSigningKeys() (*crypto.SigPubKey, *crypto.SigPrivKey) {
|
func (c *Core) NewSigningKeys() (*crypto.SigPubKey, *crypto.SigPrivKey) {
|
||||||
return crypto.NewSigKeys()
|
return crypto.NewSigKeys()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the node ID.
|
// NodeID gets the node ID.
|
||||||
func (c *Core) GetNodeID() *crypto.NodeID {
|
func (c *Core) NodeID() *crypto.NodeID {
|
||||||
return crypto.GetNodeID(&c.boxPub)
|
return crypto.GetNodeID(&c.boxPub)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the tree ID.
|
// TreeID gets the tree ID.
|
||||||
func (c *Core) GetTreeID() *crypto.TreeID {
|
func (c *Core) TreeID() *crypto.TreeID {
|
||||||
return crypto.GetTreeID(&c.sigPub)
|
return crypto.GetTreeID(&c.sigPub)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the IPv6 address of the Yggdrasil node. This is always a /128.
|
// SigPubKey gets the node's signing public key.
|
||||||
func (c *Core) GetAddress() *net.IP {
|
func (c *Core) SigPubKey() string {
|
||||||
address := net.IP(address.AddrForNodeID(c.GetNodeID())[:])
|
return hex.EncodeToString(c.sigPub[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoxPubKey gets the node's encryption public key.
|
||||||
|
func (c *Core) BoxPubKey() string {
|
||||||
|
return hex.EncodeToString(c.boxPub[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Address gets the IPv6 address of the Yggdrasil node. This is always a /128
|
||||||
|
// address.
|
||||||
|
func (c *Core) Address() *net.IP {
|
||||||
|
address := net.IP(address.AddrForNodeID(c.NodeID())[:])
|
||||||
return &address
|
return &address
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the routed IPv6 subnet of the Yggdrasil node. This is always a /64.
|
// Subnet gets the routed IPv6 subnet of the Yggdrasil node. This is always a
|
||||||
func (c *Core) GetSubnet() *net.IPNet {
|
// /64 subnet.
|
||||||
subnet := address.SubnetForNodeID(c.GetNodeID())[:]
|
func (c *Core) Subnet() *net.IPNet {
|
||||||
|
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)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the nodeinfo.
|
// RouterAddresses returns the raw address and subnet types as used by the
|
||||||
func (c *Core) GetNodeInfo() nodeinfoPayload {
|
// 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) NodeInfo() nodeinfoPayload {
|
||||||
return c.router.nodeinfo.getNodeInfo()
|
return c.router.nodeinfo.getNodeInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the nodeinfo.
|
// SetNodeInfo the lcal nodeinfo. Note that nodeinfo can be any value or struct,
|
||||||
|
// it will be serialised into JSON automatically.
|
||||||
func (c *Core) SetNodeInfo(nodeinfo interface{}, nodeinfoprivacy bool) {
|
func (c *Core) SetNodeInfo(nodeinfo interface{}, nodeinfoprivacy bool) {
|
||||||
c.router.nodeinfo.setNodeInfo(nodeinfo, nodeinfoprivacy)
|
c.router.nodeinfo.setNodeInfo(nodeinfo, nodeinfoprivacy)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the output logger of the Yggdrasil node after startup. This may be
|
// SetLogger sets the output logger of the Yggdrasil node after startup. This
|
||||||
// useful if you want to redirect the output later.
|
// may be useful if you want to redirect the output later.
|
||||||
func (c *Core) SetLogger(log *log.Logger) {
|
func (c *Core) SetLogger(log *log.Logger) {
|
||||||
c.log = log
|
c.log = log
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds a peer. This should be specified in the peer URI format, i.e.
|
// AddPeer adds a peer. This should be specified in the peer URI format, e.g.:
|
||||||
// tcp://a.b.c.d:e, udp://a.b.c.d:e, socks://a.b.c.d:e/f.g.h.i:j
|
// tcp://a.b.c.d:e
|
||||||
|
// socks://a.b.c.d:e/f.g.h.i:j
|
||||||
|
// This adds the peer to the peer list, so that they will be called again if the
|
||||||
|
// connection drops.
|
||||||
func (c *Core) AddPeer(addr string, sintf string) error {
|
func (c *Core) AddPeer(addr string, sintf string) error {
|
||||||
return c.admin.addPeer(addr, sintf)
|
if err := c.CallPeer(addr, sintf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.config.Mutex.Lock()
|
||||||
|
if sintf == "" {
|
||||||
|
c.config.Current.Peers = append(c.config.Current.Peers, addr)
|
||||||
|
} else {
|
||||||
|
c.config.Current.InterfacePeers[sintf] = append(c.config.Current.InterfacePeers[sintf], addr)
|
||||||
|
}
|
||||||
|
c.config.Mutex.Unlock()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds an allowed public key. This allow peerings to be restricted only to
|
// CallPeer calls a peer once. This should be specified in the peer URI format,
|
||||||
// keys that you have selected.
|
// e.g.:
|
||||||
|
// tcp://a.b.c.d:e
|
||||||
|
// socks://a.b.c.d:e/f.g.h.i:j
|
||||||
|
// This does not add the peer to the peer list, so if the connection drops, the
|
||||||
|
// peer will not be called again automatically.
|
||||||
|
func (c *Core) CallPeer(addr string, sintf string) error {
|
||||||
|
return c.link.call(addr, sintf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddAllowedEncryptionPublicKey adds an allowed public key. This allow peerings
|
||||||
|
// to be restricted only to keys that you have selected.
|
||||||
func (c *Core) AddAllowedEncryptionPublicKey(boxStr string) error {
|
func (c *Core) AddAllowedEncryptionPublicKey(boxStr string) error {
|
||||||
return c.admin.addAllowedEncryptionPublicKey(boxStr)
|
return c.admin.addAllowedEncryptionPublicKey(boxStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the default admin listen address for your platform.
|
|
||||||
func (c *Core) GetAdminDefaultListen() string {
|
|
||||||
return defaults.GetDefaults().DefaultAdminListen
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets the default TUN/TAP interface name for your platform.
|
|
||||||
func (c *Core) GetTUNDefaultIfName() string {
|
|
||||||
return defaults.GetDefaults().DefaultIfName
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets the default TUN/TAP interface MTU for your platform. This can be as high
|
|
||||||
// as 65535, depending on platform, but is never lower than 1280.
|
|
||||||
func (c *Core) GetTUNDefaultIfMTU() int {
|
|
||||||
return defaults.GetDefaults().DefaultIfMTU
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets the maximum supported TUN/TAP interface MTU for your platform. This
|
|
||||||
// can be as high as 65535, depending on platform, but is never lower than 1280.
|
|
||||||
func (c *Core) GetTUNMaximumIfMTU() int {
|
|
||||||
return defaults.GetDefaults().MaximumIfMTU
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets the default TUN/TAP interface mode for your platform.
|
|
||||||
func (c *Core) GetTUNDefaultIfTAPMode() bool {
|
|
||||||
return defaults.GetDefaults().DefaultIfTAPMode
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets the current TUN/TAP interface name.
|
|
||||||
func (c *Core) GetTUNIfName() string {
|
|
||||||
return c.router.tun.iface.Name()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets the current TUN/TAP interface MTU.
|
|
||||||
func (c *Core) GetTUNIfMTU() int {
|
|
||||||
return c.router.tun.mtu
|
|
||||||
}
|
|
||||||
|
@ -86,7 +86,7 @@ func (t *dht) init(c *Core) {
|
|||||||
e <- nil
|
e <- nil
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
t.nodeID = *t.core.GetNodeID()
|
t.nodeID = *t.core.NodeID()
|
||||||
t.peers = make(chan *dhtInfo, 1024)
|
t.peers = make(chan *dhtInfo, 1024)
|
||||||
t.callbacks = make(map[dhtReqKey]dht_callbackInfo)
|
t.callbacks = make(map[dhtReqKey]dht_callbackInfo)
|
||||||
t.reset()
|
t.reset()
|
||||||
|
@ -23,7 +23,6 @@ type link struct {
|
|||||||
reconfigure chan chan error
|
reconfigure chan chan error
|
||||||
mutex sync.RWMutex // protects interfaces below
|
mutex sync.RWMutex // protects interfaces below
|
||||||
interfaces map[linkInfo]*linkInterface
|
interfaces map[linkInfo]*linkInterface
|
||||||
awdl awdl // AWDL interface support
|
|
||||||
tcp tcp // TCP interface support
|
tcp tcp // TCP interface support
|
||||||
// TODO timeout (to remove from switch), read from config.ReadTimeout
|
// TODO timeout (to remove from switch), read from config.ReadTimeout
|
||||||
}
|
}
|
||||||
@ -68,26 +67,15 @@ func (l *link) init(c *Core) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := l.awdl.init(l); err != nil {
|
|
||||||
c.log.Errorln("Failed to start AWDL interface")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
e := <-l.reconfigure
|
e := <-l.reconfigure
|
||||||
tcpresponse := make(chan error)
|
tcpresponse := make(chan error)
|
||||||
awdlresponse := make(chan error)
|
|
||||||
l.tcp.reconfigure <- tcpresponse
|
l.tcp.reconfigure <- tcpresponse
|
||||||
if err := <-tcpresponse; err != nil {
|
if err := <-tcpresponse; err != nil {
|
||||||
e <- err
|
e <- err
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
l.awdl.reconfigure <- awdlresponse
|
|
||||||
if err := <-awdlresponse; err != nil {
|
|
||||||
e <- err
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
e <- nil
|
e <- nil
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -1,130 +0,0 @@
|
|||||||
// +build mobile
|
|
||||||
|
|
||||||
package yggdrasil
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/hex"
|
|
||||||
"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/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This file 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.
|
|
||||||
|
|
||||||
func (c *Core) addStaticPeers(cfg *config.NodeConfig) {
|
|
||||||
if len(cfg.Peers) == 0 && len(cfg.InterfacePeers) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for {
|
|
||||||
for _, peer := range cfg.Peers {
|
|
||||||
c.AddPeer(peer, "")
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
}
|
|
||||||
for intf, intfpeers := range cfg.InterfacePeers {
|
|
||||||
for _, peer := range intfpeers {
|
|
||||||
c.AddPeer(peer, intf)
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
time.Sleep(time.Minute)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Starts a node with a randomly generated config.
|
|
||||||
func (c *Core) StartAutoconfigure() error {
|
|
||||||
mobilelog := MobileLogger{}
|
|
||||||
logger := log.New(mobilelog, "", 0)
|
|
||||||
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 := c.Start(nc, logger); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
go c.addStaticPeers(nc)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Starts a node with the given JSON config. You can get JSON config (rather
|
|
||||||
// than HJSON) by using the GenerateConfigJSON() function.
|
|
||||||
func (c *Core) StartJSON(configjson []byte) error {
|
|
||||||
mobilelog := MobileLogger{}
|
|
||||||
logger := log.New(mobilelog, "", 0)
|
|
||||||
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 := c.Start(nc, logger); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
go c.addStaticPeers(nc)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets the node's IPv6 address.
|
|
||||||
func (c *Core) GetAddressString() string {
|
|
||||||
return c.GetAddress().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets the node's IPv6 subnet in CIDR notation.
|
|
||||||
func (c *Core) GetSubnetString() string {
|
|
||||||
return c.GetSubnet().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets the node's public encryption key.
|
|
||||||
func (c *Core) GetBoxPubKeyString() string {
|
|
||||||
return hex.EncodeToString(c.boxPub[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets the node's public signing key.
|
|
||||||
func (c *Core) GetSigPubKeyString() string {
|
|
||||||
return hex.EncodeToString(c.sigPub[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for a packet from the router. You will use this when implementing a
|
|
||||||
// dummy adapter in place of real TUN - when this call returns a packet, you
|
|
||||||
// will probably want to give it to the OS to write to TUN.
|
|
||||||
func (c *Core) RouterRecvPacket() ([]byte, error) {
|
|
||||||
packet := <-c.router.tun.recv
|
|
||||||
return packet, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send a packet to the router. You will use this when implementing a
|
|
||||||
// dummy adapter in place of real TUN - when the operating system tells you
|
|
||||||
// that a new packet is available from TUN, call this function to give it to
|
|
||||||
// Yggdrasil.
|
|
||||||
func (c *Core) RouterSendPacket(buf []byte) error {
|
|
||||||
packet := append(util.GetBytes(), buf[:]...)
|
|
||||||
c.router.tun.send <- packet
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -101,8 +101,8 @@ func (m *nodeinfo) setNodeInfo(given interface{}, privacy bool) error {
|
|||||||
m.myNodeInfoMutex.Lock()
|
m.myNodeInfoMutex.Lock()
|
||||||
defer m.myNodeInfoMutex.Unlock()
|
defer m.myNodeInfoMutex.Unlock()
|
||||||
defaults := map[string]interface{}{
|
defaults := map[string]interface{}{
|
||||||
"buildname": GetBuildName(),
|
"buildname": BuildName(),
|
||||||
"buildversion": GetBuildVersion(),
|
"buildversion": BuildVersion(),
|
||||||
"buildplatform": runtime.GOOS,
|
"buildplatform": runtime.GOOS,
|
||||||
"buildarch": runtime.GOARCH,
|
"buildarch": runtime.GOARCH,
|
||||||
}
|
}
|
||||||
|
@ -44,42 +44,42 @@ func (ps *peers) init(c *Core) {
|
|||||||
// because the key is in the whitelist or because the whitelist is empty.
|
// because the key is in the whitelist or because the whitelist is empty.
|
||||||
func (ps *peers) isAllowedEncryptionPublicKey(box *crypto.BoxPubKey) bool {
|
func (ps *peers) isAllowedEncryptionPublicKey(box *crypto.BoxPubKey) bool {
|
||||||
boxstr := hex.EncodeToString(box[:])
|
boxstr := hex.EncodeToString(box[:])
|
||||||
ps.core.configMutex.RLock()
|
ps.core.config.Mutex.RLock()
|
||||||
defer ps.core.configMutex.RUnlock()
|
defer ps.core.config.Mutex.RUnlock()
|
||||||
for _, v := range ps.core.config.AllowedEncryptionPublicKeys {
|
for _, v := range ps.core.config.Current.AllowedEncryptionPublicKeys {
|
||||||
if v == boxstr {
|
if v == boxstr {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return len(ps.core.config.AllowedEncryptionPublicKeys) == 0
|
return len(ps.core.config.Current.AllowedEncryptionPublicKeys) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds a key to the whitelist.
|
// Adds a key to the whitelist.
|
||||||
func (ps *peers) addAllowedEncryptionPublicKey(box string) {
|
func (ps *peers) addAllowedEncryptionPublicKey(box string) {
|
||||||
ps.core.configMutex.RLock()
|
ps.core.config.Mutex.RLock()
|
||||||
defer ps.core.configMutex.RUnlock()
|
defer ps.core.config.Mutex.RUnlock()
|
||||||
ps.core.config.AllowedEncryptionPublicKeys =
|
ps.core.config.Current.AllowedEncryptionPublicKeys =
|
||||||
append(ps.core.config.AllowedEncryptionPublicKeys, box)
|
append(ps.core.config.Current.AllowedEncryptionPublicKeys, box)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes a key from the whitelist.
|
// Removes a key from the whitelist.
|
||||||
func (ps *peers) removeAllowedEncryptionPublicKey(box string) {
|
func (ps *peers) removeAllowedEncryptionPublicKey(box string) {
|
||||||
ps.core.configMutex.RLock()
|
ps.core.config.Mutex.RLock()
|
||||||
defer ps.core.configMutex.RUnlock()
|
defer ps.core.config.Mutex.RUnlock()
|
||||||
for k, v := range ps.core.config.AllowedEncryptionPublicKeys {
|
for k, v := range ps.core.config.Current.AllowedEncryptionPublicKeys {
|
||||||
if v == box {
|
if v == box {
|
||||||
ps.core.config.AllowedEncryptionPublicKeys =
|
ps.core.config.Current.AllowedEncryptionPublicKeys =
|
||||||
append(ps.core.config.AllowedEncryptionPublicKeys[:k],
|
append(ps.core.config.Current.AllowedEncryptionPublicKeys[:k],
|
||||||
ps.core.config.AllowedEncryptionPublicKeys[k+1:]...)
|
ps.core.config.Current.AllowedEncryptionPublicKeys[k+1:]...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the whitelist of allowed keys for incoming connections.
|
// Gets the whitelist of allowed keys for incoming connections.
|
||||||
func (ps *peers) getAllowedEncryptionPublicKeys() []string {
|
func (ps *peers) getAllowedEncryptionPublicKeys() []string {
|
||||||
ps.core.configMutex.RLock()
|
ps.core.config.Mutex.RLock()
|
||||||
defer ps.core.configMutex.RUnlock()
|
defer ps.core.config.Mutex.RUnlock()
|
||||||
return ps.core.config.AllowedEncryptionPublicKeys
|
return ps.core.config.Current.AllowedEncryptionPublicKeys
|
||||||
}
|
}
|
||||||
|
|
||||||
// Atomically gets a map[switchPort]*peer of known peers.
|
// Atomically gets a map[switchPort]*peer of known peers.
|
||||||
|
@ -5,7 +5,7 @@ package yggdrasil
|
|||||||
// TODO clean up old/unused code, maybe improve comments on whatever is left
|
// TODO clean up old/unused code, maybe improve comments on whatever is left
|
||||||
|
|
||||||
// Send:
|
// Send:
|
||||||
// Receive a packet from the tun
|
// Receive a packet from the adapter
|
||||||
// Look up session (if none exists, trigger a search)
|
// Look up session (if none exists, trigger a search)
|
||||||
// Hand off to session (which encrypts, etc)
|
// Hand off to session (which encrypts, etc)
|
||||||
// Session will pass it back to router.out, which hands it off to the self peer
|
// Session will pass it back to router.out, which hands it off to the self peer
|
||||||
@ -20,21 +20,18 @@ package yggdrasil
|
|||||||
// If it's dht/seach/etc. traffic, the router passes it to that part
|
// If it's dht/seach/etc. traffic, the router passes it to that part
|
||||||
// If it's an encapsulated IPv6 packet, the router looks up the session for it
|
// If it's an encapsulated IPv6 packet, the router looks up the session for it
|
||||||
// The packet is passed to the session, which decrypts it, router.recvPacket
|
// The packet is passed to the session, which decrypts it, router.recvPacket
|
||||||
// The router then runs some sanity checks before passing it to the tun
|
// The router then runs some sanity checks before passing it to the adapter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/net/icmp"
|
|
||||||
"golang.org/x/net/ipv6"
|
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The router struct has channels to/from the tun/tap device and a self peer (0), which is how messages are passed between this node and the peers/switch layer.
|
// The router struct has channels to/from the adapter device and a self peer (0), which is how messages are passed between this node and the peers/switch layer.
|
||||||
// The router's mainLoop goroutine is responsible for managing all information related to the dht, searches, and crypto sessions.
|
// The router's mainLoop goroutine is responsible for managing all information related to the dht, searches, and crypto sessions.
|
||||||
type router struct {
|
type router struct {
|
||||||
core *Core
|
core *Core
|
||||||
@ -44,23 +41,44 @@ type router struct {
|
|||||||
in <-chan []byte // packets we received from the network, link to peer's "out"
|
in <-chan []byte // packets we received from the network, link to peer's "out"
|
||||||
out func([]byte) // packets we're sending to the network, link to peer's "in"
|
out func([]byte) // packets we're sending to the network, link to peer's "in"
|
||||||
toRecv chan router_recvPacket // packets to handle via recvPacket()
|
toRecv chan router_recvPacket // packets to handle via recvPacket()
|
||||||
tun tunAdapter // TUN/TAP adapter
|
adapter adapterImplementation // TUN/TAP adapter
|
||||||
adapters []Adapter // Other adapters
|
recv chan<- []byte // place where the adapter pulls received packets from
|
||||||
recv chan<- []byte // place where the tun pulls received packets from
|
send <-chan []byte // place where the adapter puts outgoing packets
|
||||||
send <-chan []byte // place where the tun puts outgoing packets
|
reject chan<- RejectedPacket // place where we send error packets back to adapter
|
||||||
reset chan struct{} // signal that coords changed (re-init sessions/dht)
|
reset chan struct{} // signal that coords changed (re-init sessions/dht)
|
||||||
admin chan func() // pass a lambda for the admin socket to query stuff
|
admin chan func() // pass a lambda for the admin socket to query stuff
|
||||||
cryptokey cryptokey
|
cryptokey cryptokey
|
||||||
nodeinfo nodeinfo
|
nodeinfo nodeinfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// Packet and session info, used to check that the packet matches a valid IP range or CKR prefix before sending to the tun.
|
// Packet and session info, used to check that the packet matches a valid IP range or CKR prefix before sending to the adapter.
|
||||||
type router_recvPacket struct {
|
type router_recvPacket struct {
|
||||||
bs []byte
|
bs []byte
|
||||||
sinfo *sessionInfo
|
sinfo *sessionInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializes the router struct, which includes setting up channels to/from the tun/tap.
|
// RejectedPacketReason is the type code used to represent the reason that a
|
||||||
|
// packet was rejected.
|
||||||
|
type RejectedPacketReason int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// The router rejected the packet because it exceeds the session MTU for the
|
||||||
|
// given destination. In TUN/TAP, this results in the generation of an ICMPv6
|
||||||
|
// Packet Too Big message.
|
||||||
|
PacketTooBig = 1 + iota
|
||||||
|
)
|
||||||
|
|
||||||
|
// RejectedPacket represents a rejected packet from the router. This is passed
|
||||||
|
// back to the adapter so that the adapter can respond appropriately, e.g. in
|
||||||
|
// the case of TUN/TAP, a "PacketTooBig" reason can be used to generate an
|
||||||
|
// ICMPv6 Packet Too Big response.
|
||||||
|
type RejectedPacket struct {
|
||||||
|
Reason RejectedPacketReason
|
||||||
|
Packet []byte
|
||||||
|
Detail interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initializes the router struct, which includes setting up channels to/from the adapter.
|
||||||
func (r *router) init(core *Core) {
|
func (r *router) init(core *Core) {
|
||||||
r.core = core
|
r.core = core
|
||||||
r.reconfigure = make(chan chan error, 1)
|
r.reconfigure = make(chan chan error, 1)
|
||||||
@ -107,16 +125,20 @@ func (r *router) init(core *Core) {
|
|||||||
r.toRecv = make(chan router_recvPacket, 32)
|
r.toRecv = make(chan router_recvPacket, 32)
|
||||||
recv := make(chan []byte, 32)
|
recv := make(chan []byte, 32)
|
||||||
send := make(chan []byte, 32)
|
send := make(chan []byte, 32)
|
||||||
|
reject := make(chan RejectedPacket, 32)
|
||||||
r.recv = recv
|
r.recv = recv
|
||||||
r.send = send
|
r.send = send
|
||||||
|
r.reject = reject
|
||||||
r.reset = make(chan struct{}, 1)
|
r.reset = make(chan struct{}, 1)
|
||||||
r.admin = make(chan func(), 32)
|
r.admin = make(chan func(), 32)
|
||||||
r.nodeinfo.init(r.core)
|
r.nodeinfo.init(r.core)
|
||||||
r.core.configMutex.RLock()
|
r.core.config.Mutex.RLock()
|
||||||
r.nodeinfo.setNodeInfo(r.core.config.NodeInfo, r.core.config.NodeInfoPrivacy)
|
r.nodeinfo.setNodeInfo(r.core.config.Current.NodeInfo, r.core.config.Current.NodeInfoPrivacy)
|
||||||
r.core.configMutex.RUnlock()
|
r.core.config.Mutex.RUnlock()
|
||||||
r.cryptokey.init(r.core)
|
r.cryptokey.init(r.core)
|
||||||
r.tun.init(r.core, send, recv)
|
if r.adapter != nil {
|
||||||
|
r.adapter.Init(&r.core.config, r.core.log, send, recv, reject)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Starts the mainLoop goroutine.
|
// Starts the mainLoop goroutine.
|
||||||
@ -126,7 +148,7 @@ func (r *router) start() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes traffic from the tun/tap and passes it to router.send, or from r.in and handles incoming traffic.
|
// Takes traffic from the adapter and passes it to router.send, or from r.in and handles incoming traffic.
|
||||||
// Also adds new peer info to the DHT.
|
// Also adds new peer info to the DHT.
|
||||||
// Also resets the DHT and sesssions in the event of a coord change.
|
// Also resets the DHT and sesssions in the event of a coord change.
|
||||||
// Also does periodic maintenance stuff.
|
// Also does periodic maintenance stuff.
|
||||||
@ -157,9 +179,8 @@ func (r *router) mainLoop() {
|
|||||||
case f := <-r.admin:
|
case f := <-r.admin:
|
||||||
f()
|
f()
|
||||||
case e := <-r.reconfigure:
|
case e := <-r.reconfigure:
|
||||||
r.core.configMutex.RLock()
|
current, _ := r.core.config.Get()
|
||||||
e <- r.nodeinfo.setNodeInfo(r.core.config.NodeInfo, r.core.config.NodeInfoPrivacy)
|
e <- r.nodeinfo.setNodeInfo(current.NodeInfo, current.NodeInfoPrivacy)
|
||||||
r.core.configMutex.RUnlock()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,7 +189,7 @@ func (r *router) mainLoop() {
|
|||||||
// If a session to the destination exists, gets the session and passes the packet to it.
|
// 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 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.
|
// 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 tun/tap disabled.
|
// 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) {
|
func (r *router) sendPacket(bs []byte) {
|
||||||
var sourceAddr address.Address
|
var sourceAddr address.Address
|
||||||
var destAddr address.Address
|
var destAddr address.Address
|
||||||
@ -313,18 +334,11 @@ func (r *router) sendPacket(bs []byte) {
|
|||||||
window = int(sinfo.getMTU())
|
window = int(sinfo.getMTU())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the Packet Too Big response
|
// Send the error back to the adapter
|
||||||
ptb := &icmp.PacketTooBig{
|
r.reject <- RejectedPacket{
|
||||||
MTU: int(sinfo.getMTU()),
|
Reason: PacketTooBig,
|
||||||
Data: bs[:window],
|
Packet: bs[:window],
|
||||||
}
|
Detail: int(sinfo.getMTU()),
|
||||||
|
|
||||||
// Create the ICMPv6 response from it
|
|
||||||
icmpv6Buf, err := r.tun.icmpv6.create_icmpv6_tun(
|
|
||||||
bs[8:24], bs[24:40],
|
|
||||||
ipv6.ICMPTypePacketTooBig, 0, ptb)
|
|
||||||
if err == nil {
|
|
||||||
r.recv <- icmpv6Buf
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't continue - drop the packet
|
// Don't continue - drop the packet
|
||||||
@ -335,7 +349,7 @@ func (r *router) sendPacket(bs []byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Called for incoming traffic by the session worker for that connection.
|
// Called for incoming traffic by the session worker for that connection.
|
||||||
// Checks that the IP address is correct (matches the session) and passes the packet to the tun/tap.
|
// Checks that the IP address is correct (matches the session) and passes the packet to the adapter.
|
||||||
func (r *router) recvPacket(bs []byte, sinfo *sessionInfo) {
|
func (r *router) recvPacket(bs []byte, sinfo *sessionInfo) {
|
||||||
// Note: called directly by the session worker, not the router goroutine
|
// Note: called directly by the session worker, not the router goroutine
|
||||||
if len(bs) < 24 {
|
if len(bs) < 24 {
|
||||||
@ -398,7 +412,7 @@ func (r *router) handleIn(packet []byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handles incoming traffic, i.e. encapuslated ordinary IPv6 packets.
|
// Handles incoming traffic, i.e. encapuslated ordinary IPv6 packets.
|
||||||
// Passes them to the crypto session worker to be decrypted and sent to the tun/tap.
|
// Passes them to the crypto session worker to be decrypted and sent to the adapter.
|
||||||
func (r *router) handleTraffic(packet []byte) {
|
func (r *router) handleTraffic(packet []byte) {
|
||||||
defer util.PutBytes(packet)
|
defer util.PutBytes(packet)
|
||||||
p := wire_trafficPacket{}
|
p := wire_trafficPacket{}
|
||||||
@ -432,7 +446,7 @@ func (r *router) handleProto(packet []byte) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Now do something with the bytes in bs...
|
// Now do something with the bytes in bs...
|
||||||
// send dht messages to dht, sessionRefresh to sessions, data to tun...
|
// send dht messages to dht, sessionRefresh to sessions, data to adapter...
|
||||||
// For data, should check that key and IP match...
|
// For data, should check that key and IP match...
|
||||||
bsType, bsTypeLen := wire_decode_uint64(bs)
|
bsType, bsTypeLen := wire_decode_uint64(bs)
|
||||||
if bsTypeLen == 0 {
|
if bsTypeLen == 0 {
|
||||||
|
@ -148,17 +148,17 @@ func (ss *sessions) init(core *Core) {
|
|||||||
|
|
||||||
// Determines whether the session firewall is enabled.
|
// Determines whether the session firewall is enabled.
|
||||||
func (ss *sessions) isSessionFirewallEnabled() bool {
|
func (ss *sessions) isSessionFirewallEnabled() bool {
|
||||||
ss.core.configMutex.RLock()
|
ss.core.config.Mutex.RLock()
|
||||||
defer ss.core.configMutex.RUnlock()
|
defer ss.core.config.Mutex.RUnlock()
|
||||||
|
|
||||||
return ss.core.config.SessionFirewall.Enable
|
return ss.core.config.Current.SessionFirewall.Enable
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determines whether the session with a given publickey is allowed based on
|
// Determines whether the session with a given publickey is allowed based on
|
||||||
// session firewall rules.
|
// session firewall rules.
|
||||||
func (ss *sessions) isSessionAllowed(pubkey *crypto.BoxPubKey, initiator bool) bool {
|
func (ss *sessions) isSessionAllowed(pubkey *crypto.BoxPubKey, initiator bool) bool {
|
||||||
ss.core.configMutex.RLock()
|
ss.core.config.Mutex.RLock()
|
||||||
defer ss.core.configMutex.RUnlock()
|
defer ss.core.config.Mutex.RUnlock()
|
||||||
|
|
||||||
// Allow by default if the session firewall is disabled
|
// Allow by default if the session firewall is disabled
|
||||||
if !ss.isSessionFirewallEnabled() {
|
if !ss.isSessionFirewallEnabled() {
|
||||||
@ -167,7 +167,7 @@ func (ss *sessions) isSessionAllowed(pubkey *crypto.BoxPubKey, initiator bool) b
|
|||||||
// Prepare for checking whitelist/blacklist
|
// Prepare for checking whitelist/blacklist
|
||||||
var box crypto.BoxPubKey
|
var box crypto.BoxPubKey
|
||||||
// Reject blacklisted nodes
|
// Reject blacklisted nodes
|
||||||
for _, b := range ss.core.config.SessionFirewall.BlacklistEncryptionPublicKeys {
|
for _, b := range ss.core.config.Current.SessionFirewall.BlacklistEncryptionPublicKeys {
|
||||||
key, err := hex.DecodeString(b)
|
key, err := hex.DecodeString(b)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
copy(box[:crypto.BoxPubKeyLen], key)
|
copy(box[:crypto.BoxPubKeyLen], key)
|
||||||
@ -177,7 +177,7 @@ func (ss *sessions) isSessionAllowed(pubkey *crypto.BoxPubKey, initiator bool) b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Allow whitelisted nodes
|
// Allow whitelisted nodes
|
||||||
for _, b := range ss.core.config.SessionFirewall.WhitelistEncryptionPublicKeys {
|
for _, b := range ss.core.config.Current.SessionFirewall.WhitelistEncryptionPublicKeys {
|
||||||
key, err := hex.DecodeString(b)
|
key, err := hex.DecodeString(b)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
copy(box[:crypto.BoxPubKeyLen], key)
|
copy(box[:crypto.BoxPubKeyLen], key)
|
||||||
@ -187,7 +187,7 @@ func (ss *sessions) isSessionAllowed(pubkey *crypto.BoxPubKey, initiator bool) b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Allow outbound sessions if appropriate
|
// Allow outbound sessions if appropriate
|
||||||
if ss.core.config.SessionFirewall.AlwaysAllowOutbound {
|
if ss.core.config.Current.SessionFirewall.AlwaysAllowOutbound {
|
||||||
if initiator {
|
if initiator {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -201,11 +201,11 @@ func (ss *sessions) isSessionAllowed(pubkey *crypto.BoxPubKey, initiator bool) b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Allow direct peers if appropriate
|
// Allow direct peers if appropriate
|
||||||
if ss.core.config.SessionFirewall.AllowFromDirect && isDirectPeer {
|
if ss.core.config.Current.SessionFirewall.AllowFromDirect && isDirectPeer {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// Allow remote nodes if appropriate
|
// Allow remote nodes if appropriate
|
||||||
if ss.core.config.SessionFirewall.AllowFromRemote && !isDirectPeer {
|
if ss.core.config.Current.SessionFirewall.AllowFromRemote && !isDirectPeer {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// Finally, default-deny if not matching any of the above rules
|
// Finally, default-deny if not matching any of the above rules
|
||||||
@ -277,7 +277,9 @@ func (ss *sessions) createSession(theirPermKey *crypto.BoxPubKey) *sessionInfo {
|
|||||||
sinfo.mySesPriv = *priv
|
sinfo.mySesPriv = *priv
|
||||||
sinfo.myNonce = *crypto.NewBoxNonce()
|
sinfo.myNonce = *crypto.NewBoxNonce()
|
||||||
sinfo.theirMTU = 1280
|
sinfo.theirMTU = 1280
|
||||||
sinfo.myMTU = uint16(ss.core.router.tun.mtu)
|
if ss.core.router.adapter != nil {
|
||||||
|
sinfo.myMTU = uint16(ss.core.router.adapter.MTU())
|
||||||
|
}
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
sinfo.time = now
|
sinfo.time = now
|
||||||
sinfo.mtuTime = now
|
sinfo.mtuTime = now
|
||||||
|
@ -188,9 +188,7 @@ func (t *switchTable) init(core *Core) {
|
|||||||
now := time.Now()
|
now := time.Now()
|
||||||
t.core = core
|
t.core = core
|
||||||
t.reconfigure = make(chan chan error, 1)
|
t.reconfigure = make(chan chan error, 1)
|
||||||
t.core.configMutex.RLock()
|
|
||||||
t.key = t.core.sigPub
|
t.key = t.core.sigPub
|
||||||
t.core.configMutex.RUnlock()
|
|
||||||
locator := switchLocator{root: t.key, tstamp: now.Unix()}
|
locator := switchLocator{root: t.key, tstamp: now.Unix()}
|
||||||
peers := make(map[switchPort]peerInfo)
|
peers := make(map[switchPort]peerInfo)
|
||||||
t.data = switchData{locator: locator, peers: peers}
|
t.data = switchData{locator: locator, peers: peers}
|
||||||
|
@ -36,14 +36,18 @@ type tcp struct {
|
|||||||
link *link
|
link *link
|
||||||
reconfigure chan chan error
|
reconfigure chan chan error
|
||||||
mutex sync.Mutex // Protecting the below
|
mutex sync.Mutex // Protecting the below
|
||||||
listeners map[string]*tcpListener
|
listeners map[string]*TcpListener
|
||||||
calls map[string]struct{}
|
calls map[string]struct{}
|
||||||
conns map[linkInfo](chan struct{})
|
conns map[linkInfo](chan struct{})
|
||||||
}
|
}
|
||||||
|
|
||||||
type tcpListener struct {
|
// TcpListener is a stoppable TCP listener interface. These are typically
|
||||||
listener net.Listener
|
// returned from calls to the ListenTCP() function and are also used internally
|
||||||
stop chan bool
|
// to represent listeners created by the "Listen" configuration option and for
|
||||||
|
// multicast interfaces.
|
||||||
|
type TcpListener struct {
|
||||||
|
Listener net.Listener
|
||||||
|
Stop chan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrapper function to set additional options for specific connection types.
|
// Wrapper function to set additional options for specific connection types.
|
||||||
@ -64,7 +68,7 @@ func (t *tcp) getAddr() *net.TCPAddr {
|
|||||||
t.mutex.Lock()
|
t.mutex.Lock()
|
||||||
defer t.mutex.Unlock()
|
defer t.mutex.Unlock()
|
||||||
for _, l := range t.listeners {
|
for _, l := range t.listeners {
|
||||||
return l.listener.Addr().(*net.TCPAddr)
|
return l.Listener.Addr().(*net.TCPAddr)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -76,16 +80,16 @@ func (t *tcp) init(l *link) error {
|
|||||||
t.mutex.Lock()
|
t.mutex.Lock()
|
||||||
t.calls = make(map[string]struct{})
|
t.calls = make(map[string]struct{})
|
||||||
t.conns = make(map[linkInfo](chan struct{}))
|
t.conns = make(map[linkInfo](chan struct{}))
|
||||||
t.listeners = make(map[string]*tcpListener)
|
t.listeners = make(map[string]*TcpListener)
|
||||||
t.mutex.Unlock()
|
t.mutex.Unlock()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
e := <-t.reconfigure
|
e := <-t.reconfigure
|
||||||
t.link.core.configMutex.RLock()
|
t.link.core.config.Mutex.RLock()
|
||||||
added := util.Difference(t.link.core.config.Listen, t.link.core.configOld.Listen)
|
added := util.Difference(t.link.core.config.Current.Listen, t.link.core.config.Previous.Listen)
|
||||||
deleted := util.Difference(t.link.core.configOld.Listen, t.link.core.config.Listen)
|
deleted := util.Difference(t.link.core.config.Previous.Listen, t.link.core.config.Current.Listen)
|
||||||
t.link.core.configMutex.RUnlock()
|
t.link.core.config.Mutex.RUnlock()
|
||||||
if len(added) > 0 || len(deleted) > 0 {
|
if len(added) > 0 || len(deleted) > 0 {
|
||||||
for _, a := range added {
|
for _, a := range added {
|
||||||
if a[:6] != "tcp://" {
|
if a[:6] != "tcp://" {
|
||||||
@ -103,7 +107,7 @@ func (t *tcp) init(l *link) error {
|
|||||||
t.mutex.Lock()
|
t.mutex.Lock()
|
||||||
if listener, ok := t.listeners[d[6:]]; ok {
|
if listener, ok := t.listeners[d[6:]]; ok {
|
||||||
t.mutex.Unlock()
|
t.mutex.Unlock()
|
||||||
listener.stop <- true
|
listener.Stop <- true
|
||||||
} else {
|
} else {
|
||||||
t.mutex.Unlock()
|
t.mutex.Unlock()
|
||||||
}
|
}
|
||||||
@ -115,9 +119,9 @@ func (t *tcp) init(l *link) error {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
t.link.core.configMutex.RLock()
|
t.link.core.config.Mutex.RLock()
|
||||||
defer t.link.core.configMutex.RUnlock()
|
defer t.link.core.config.Mutex.RUnlock()
|
||||||
for _, listenaddr := range t.link.core.config.Listen {
|
for _, listenaddr := range t.link.core.config.Current.Listen {
|
||||||
if listenaddr[:6] != "tcp://" {
|
if listenaddr[:6] != "tcp://" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -129,7 +133,7 @@ func (t *tcp) init(l *link) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tcp) listen(listenaddr string) (*tcpListener, error) {
|
func (t *tcp) listen(listenaddr string) (*TcpListener, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@ -138,9 +142,9 @@ func (t *tcp) listen(listenaddr string) (*tcpListener, error) {
|
|||||||
}
|
}
|
||||||
listener, err := lc.Listen(ctx, "tcp", listenaddr)
|
listener, err := lc.Listen(ctx, "tcp", listenaddr)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
l := tcpListener{
|
l := TcpListener{
|
||||||
listener: listener,
|
Listener: listener,
|
||||||
stop: make(chan bool),
|
Stop: make(chan bool),
|
||||||
}
|
}
|
||||||
go t.listener(&l, listenaddr)
|
go t.listener(&l, listenaddr)
|
||||||
return &l, nil
|
return &l, nil
|
||||||
@ -150,7 +154,7 @@ func (t *tcp) listen(listenaddr string) (*tcpListener, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Runs the listener, which spawns off goroutines for incoming connections.
|
// Runs the listener, which spawns off goroutines for incoming connections.
|
||||||
func (t *tcp) listener(l *tcpListener, listenaddr string) {
|
func (t *tcp) listener(l *TcpListener, listenaddr string) {
|
||||||
if l == nil {
|
if l == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -158,7 +162,7 @@ func (t *tcp) listener(l *tcpListener, listenaddr string) {
|
|||||||
t.mutex.Lock()
|
t.mutex.Lock()
|
||||||
if _, isIn := t.listeners[listenaddr]; isIn {
|
if _, isIn := t.listeners[listenaddr]; isIn {
|
||||||
t.mutex.Unlock()
|
t.mutex.Unlock()
|
||||||
l.listener.Close()
|
l.Listener.Close()
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
t.listeners[listenaddr] = l
|
t.listeners[listenaddr] = l
|
||||||
@ -167,20 +171,20 @@ func (t *tcp) listener(l *tcpListener, listenaddr string) {
|
|||||||
// And here we go!
|
// And here we go!
|
||||||
accepted := make(chan bool)
|
accepted := make(chan bool)
|
||||||
defer func() {
|
defer func() {
|
||||||
t.link.core.log.Infoln("Stopping TCP listener on:", l.listener.Addr().String())
|
t.link.core.log.Infoln("Stopping TCP listener on:", l.Listener.Addr().String())
|
||||||
l.listener.Close()
|
l.Listener.Close()
|
||||||
t.mutex.Lock()
|
t.mutex.Lock()
|
||||||
delete(t.listeners, listenaddr)
|
delete(t.listeners, listenaddr)
|
||||||
t.mutex.Unlock()
|
t.mutex.Unlock()
|
||||||
}()
|
}()
|
||||||
t.link.core.log.Infoln("Listening for TCP on:", l.listener.Addr().String())
|
t.link.core.log.Infoln("Listening for TCP on:", l.Listener.Addr().String())
|
||||||
for {
|
for {
|
||||||
var sock net.Conn
|
var sock net.Conn
|
||||||
var err error
|
var err error
|
||||||
// Listen in a separate goroutine, as that way it does not block us from
|
// Listen in a separate goroutine, as that way it does not block us from
|
||||||
// receiving "stop" events
|
// receiving "stop" events
|
||||||
go func() {
|
go func() {
|
||||||
sock, err = l.listener.Accept()
|
sock, err = l.Listener.Accept()
|
||||||
accepted <- true
|
accepted <- true
|
||||||
}()
|
}()
|
||||||
// Wait for either an accepted connection, or a message telling us to stop
|
// Wait for either an accepted connection, or a message telling us to stop
|
||||||
@ -192,7 +196,7 @@ func (t *tcp) listener(l *tcpListener, listenaddr string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
go t.handler(sock, true, nil)
|
go t.handler(sock, true, nil)
|
||||||
case <-l.stop:
|
case <-l.Stop:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,266 +0,0 @@
|
|||||||
package yggdrasil
|
|
||||||
|
|
||||||
// This manages the tun driver to send/recv packets to/from applications
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/songgao/packets/ethernet"
|
|
||||||
"github.com/yggdrasil-network/water"
|
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
const tun_IPv6_HEADER_LENGTH = 40
|
|
||||||
const tun_ETHER_HEADER_LENGTH = 14
|
|
||||||
|
|
||||||
// Represents a running TUN/TAP interface.
|
|
||||||
type tunAdapter struct {
|
|
||||||
Adapter
|
|
||||||
icmpv6 icmpv6
|
|
||||||
mtu int
|
|
||||||
iface *water.Interface
|
|
||||||
mutex sync.RWMutex // Protects the below
|
|
||||||
isOpen bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets the maximum supported MTU for the platform based on the defaults in
|
|
||||||
// defaults.GetDefaults().
|
|
||||||
func getSupportedMTU(mtu int) int {
|
|
||||||
if mtu > defaults.GetDefaults().MaximumIfMTU {
|
|
||||||
return defaults.GetDefaults().MaximumIfMTU
|
|
||||||
}
|
|
||||||
return mtu
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialises the TUN/TAP adapter.
|
|
||||||
func (tun *tunAdapter) init(core *Core, send chan<- []byte, recv <-chan []byte) {
|
|
||||||
tun.Adapter.init(core, send, recv)
|
|
||||||
tun.icmpv6.init(tun)
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
e := <-tun.reconfigure
|
|
||||||
tun.core.configMutex.RLock()
|
|
||||||
updated := tun.core.config.IfName != tun.core.configOld.IfName ||
|
|
||||||
tun.core.config.IfTAPMode != tun.core.configOld.IfTAPMode ||
|
|
||||||
tun.core.config.IfMTU != tun.core.configOld.IfMTU
|
|
||||||
tun.core.configMutex.RUnlock()
|
|
||||||
if updated {
|
|
||||||
tun.core.log.Warnln("Reconfiguring TUN/TAP is not supported yet")
|
|
||||||
e <- nil
|
|
||||||
} else {
|
|
||||||
e <- nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Starts the setup process for the TUN/TAP adapter, and if successful, starts
|
|
||||||
// the read/write goroutines to handle packets on that interface.
|
|
||||||
func (tun *tunAdapter) start() error {
|
|
||||||
tun.core.configMutex.RLock()
|
|
||||||
ifname := tun.core.config.IfName
|
|
||||||
iftapmode := tun.core.config.IfTAPMode
|
|
||||||
addr := fmt.Sprintf("%s/%d", net.IP(tun.core.router.addr[:]).String(), 8*len(address.GetPrefix())-1)
|
|
||||||
mtu := tun.core.config.IfMTU
|
|
||||||
tun.core.configMutex.RUnlock()
|
|
||||||
if ifname != "none" {
|
|
||||||
if err := tun.setup(ifname, iftapmode, addr, mtu); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ifname == "none" || ifname == "dummy" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
tun.mutex.Lock()
|
|
||||||
tun.isOpen = true
|
|
||||||
tun.mutex.Unlock()
|
|
||||||
go func() { tun.core.log.Errorln("WARNING: tun.read() exited with error:", tun.read()) }()
|
|
||||||
go func() { tun.core.log.Errorln("WARNING: tun.write() exited with error:", tun.write()) }()
|
|
||||||
if iftapmode {
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
if _, ok := tun.icmpv6.peermacs[tun.core.router.addr]; ok {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
request, err := tun.icmpv6.create_ndp_tap(tun.core.router.addr)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if _, err := tun.iface.Write(request); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes a packet to the TUN/TAP adapter. If the adapter is running in TAP
|
|
||||||
// mode then additional ethernet encapsulation is added for the benefit of the
|
|
||||||
// host operating system.
|
|
||||||
func (tun *tunAdapter) write() error {
|
|
||||||
for {
|
|
||||||
data := <-tun.recv
|
|
||||||
if tun.iface == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if tun.iface.IsTAP() {
|
|
||||||
var destAddr address.Address
|
|
||||||
if data[0]&0xf0 == 0x60 {
|
|
||||||
if len(data) < 40 {
|
|
||||||
panic("Tried to send a packet shorter than an IPv6 header...")
|
|
||||||
}
|
|
||||||
copy(destAddr[:16], data[24:])
|
|
||||||
} else if data[0]&0xf0 == 0x40 {
|
|
||||||
if len(data) < 20 {
|
|
||||||
panic("Tried to send a packet shorter than an IPv4 header...")
|
|
||||||
}
|
|
||||||
copy(destAddr[:4], data[16:])
|
|
||||||
} else {
|
|
||||||
return errors.New("Invalid address family")
|
|
||||||
}
|
|
||||||
sendndp := func(destAddr address.Address) {
|
|
||||||
neigh, known := tun.icmpv6.peermacs[destAddr]
|
|
||||||
known = known && (time.Since(neigh.lastsolicitation).Seconds() < 30)
|
|
||||||
if !known {
|
|
||||||
request, err := tun.icmpv6.create_ndp_tap(destAddr)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if _, err := tun.iface.Write(request); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
tun.icmpv6.peermacs[destAddr] = neighbor{
|
|
||||||
lastsolicitation: time.Now(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var peermac macAddress
|
|
||||||
var peerknown bool
|
|
||||||
if data[0]&0xf0 == 0x40 {
|
|
||||||
destAddr = tun.core.router.addr
|
|
||||||
} else if data[0]&0xf0 == 0x60 {
|
|
||||||
if !bytes.Equal(tun.core.router.addr[:16], destAddr[:16]) && !bytes.Equal(tun.core.router.subnet[:8], destAddr[:8]) {
|
|
||||||
destAddr = tun.core.router.addr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if neighbor, ok := tun.icmpv6.peermacs[destAddr]; ok && neighbor.learned {
|
|
||||||
peermac = neighbor.mac
|
|
||||||
peerknown = true
|
|
||||||
} else if neighbor, ok := tun.icmpv6.peermacs[tun.core.router.addr]; ok && neighbor.learned {
|
|
||||||
peermac = neighbor.mac
|
|
||||||
peerknown = true
|
|
||||||
sendndp(destAddr)
|
|
||||||
} else {
|
|
||||||
sendndp(tun.core.router.addr)
|
|
||||||
}
|
|
||||||
if peerknown {
|
|
||||||
var proto ethernet.Ethertype
|
|
||||||
switch {
|
|
||||||
case data[0]&0xf0 == 0x60:
|
|
||||||
proto = ethernet.IPv6
|
|
||||||
case data[0]&0xf0 == 0x40:
|
|
||||||
proto = ethernet.IPv4
|
|
||||||
}
|
|
||||||
var frame ethernet.Frame
|
|
||||||
frame.Prepare(
|
|
||||||
peermac[:6], // Destination MAC address
|
|
||||||
tun.icmpv6.mymac[:6], // Source MAC address
|
|
||||||
ethernet.NotTagged, // VLAN tagging
|
|
||||||
proto, // Ethertype
|
|
||||||
len(data)) // Payload length
|
|
||||||
copy(frame[tun_ETHER_HEADER_LENGTH:], data[:])
|
|
||||||
if _, err := tun.iface.Write(frame); err != nil {
|
|
||||||
tun.mutex.RLock()
|
|
||||||
open := tun.isOpen
|
|
||||||
tun.mutex.RUnlock()
|
|
||||||
if !open {
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if _, err := tun.iface.Write(data); err != nil {
|
|
||||||
tun.mutex.RLock()
|
|
||||||
open := tun.isOpen
|
|
||||||
tun.mutex.RUnlock()
|
|
||||||
if !open {
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
util.PutBytes(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads any packets that are waiting on the TUN/TAP adapter. If the adapter
|
|
||||||
// is running in TAP mode then the ethernet headers will automatically be
|
|
||||||
// processed and stripped if necessary. If an ICMPv6 packet is found, then
|
|
||||||
// the relevant helper functions in icmpv6.go are called.
|
|
||||||
func (tun *tunAdapter) read() error {
|
|
||||||
mtu := tun.mtu
|
|
||||||
if tun.iface.IsTAP() {
|
|
||||||
mtu += tun_ETHER_HEADER_LENGTH
|
|
||||||
}
|
|
||||||
buf := make([]byte, mtu)
|
|
||||||
for {
|
|
||||||
n, err := tun.iface.Read(buf)
|
|
||||||
if err != nil {
|
|
||||||
tun.mutex.RLock()
|
|
||||||
open := tun.isOpen
|
|
||||||
tun.mutex.RUnlock()
|
|
||||||
if !open {
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
// panic(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
o := 0
|
|
||||||
if tun.iface.IsTAP() {
|
|
||||||
o = tun_ETHER_HEADER_LENGTH
|
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case buf[o]&0xf0 == 0x60 && n == 256*int(buf[o+4])+int(buf[o+5])+tun_IPv6_HEADER_LENGTH+o:
|
|
||||||
case buf[o]&0xf0 == 0x40 && n == 256*int(buf[o+2])+int(buf[o+3])+o:
|
|
||||||
default:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if buf[o+6] == 58 {
|
|
||||||
if tun.iface.IsTAP() {
|
|
||||||
// Found an ICMPv6 packet
|
|
||||||
b := make([]byte, n)
|
|
||||||
copy(b, buf)
|
|
||||||
go tun.icmpv6.parse_packet(b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
packet := append(util.GetBytes(), buf[o:n]...)
|
|
||||||
tun.send <- packet
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Closes the TUN/TAP adapter. This is only usually called when the Yggdrasil
|
|
||||||
// process stops. Typically this operation will happen quickly, but on macOS
|
|
||||||
// it can block until a read operation is completed.
|
|
||||||
func (tun *tunAdapter) close() error {
|
|
||||||
tun.mutex.Lock()
|
|
||||||
tun.isOpen = false
|
|
||||||
tun.mutex.Unlock()
|
|
||||||
if tun.iface == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return tun.iface.Close()
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user