5
0
mirror of https://github.com/cwinfo/yggdrasil-go.git synced 2024-11-22 20:00:27 +00:00

Merge pull request #306 from neilalexander/ios

AWDL support, Android tweaks
This commit is contained in:
Neil Alexander 2019-01-13 23:14:01 +00:00 committed by GitHub
commit 3fa5893fd6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 235 additions and 120 deletions

21
build
View File

@ -6,13 +6,14 @@ PKGVER=${PKGVER:-$(sh contrib/semver/version.sh --bare)}
LDFLAGS="-X $PKGSRC.buildName=$PKGNAME -X $PKGSRC.buildVersion=$PKGVER" LDFLAGS="-X $PKGSRC.buildName=$PKGNAME -X $PKGSRC.buildVersion=$PKGVER"
while getopts "udmtc:l:" option while getopts "udaitc:l:" option
do do
case "${option}" case "${option}"
in in
u) UPX=true;; u) UPX=true;;
d) DEBUG=true;; d) DEBUG=true;;
m) MOBILE=true;; i) IOS=true;;
a) ANDROID=true;;
t) TABLES=true;; t) TABLES=true;;
c) GCFLAGS="$GCFLAGS $OPTARG";; c) GCFLAGS="$GCFLAGS $OPTARG";;
l) LDFLAGS="$LDFLAGS $OPTARG";; l) LDFLAGS="$LDFLAGS $OPTARG";;
@ -23,12 +24,17 @@ if [ -z $TABLES ]; then
STRIP="-s -w" STRIP="-s -w"
fi fi
for CMD in `ls cmd/` ; do if [ $IOS ]; then
echo "Building framework for iOS"
gomobile bind -target ios -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil
elif [ $ANDROID ]; then
echo "Building aar for Android"
gomobile bind -target android -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil
else
for CMD in `ls cmd/` ; do
echo "Building: $CMD" echo "Building: $CMD"
if [ $MOBILE ]; then if [ $DEBUG ]; then
go build -ldflags="$LDFLAGS" -gcflags="$GCFLAGS" -tags mobile -v ./cmd/$CMD
elif [ $DEBUG ]; then
go build -ldflags="$LDFLAGS" -gcflags="$GCFLAGS" -tags debug -v ./cmd/$CMD go build -ldflags="$LDFLAGS" -gcflags="$GCFLAGS" -tags debug -v ./cmd/$CMD
else else
go build -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" -v ./cmd/$CMD go build -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" -v ./cmd/$CMD
@ -36,4 +42,5 @@ for CMD in `ls cmd/` ; do
if [ $UPX ]; then if [ $UPX ]; then
upx --brute $CMD upx --brute $CMD
fi fi
done done
fi

View File

@ -34,8 +34,16 @@ func (l *awdl) init(c *Core) error {
return nil return nil
} }
func (l *awdl) create(fromAWDL chan []byte, toAWDL chan []byte, boxPubKey *crypto.BoxPubKey, sigPubKey *crypto.SigPubKey, name string) (*awdlInterface, error) { func (l *awdl) create(fromAWDL chan []byte, toAWDL chan []byte /*boxPubKey *crypto.BoxPubKey, sigPubKey *crypto.SigPubKey*/, name string) (*awdlInterface, error) {
/* intf := awdlInterface{
awdl: l,
fromAWDL: fromAWDL,
toAWDL: toAWDL,
shutdown: make(chan bool),
}
l.mutex.Lock()
l.interfaces[name] = &intf
l.mutex.Unlock()
myLinkPub, myLinkPriv := crypto.NewBoxKeys() myLinkPub, myLinkPriv := crypto.NewBoxKeys()
meta := version_getBaseMetadata() meta := version_getBaseMetadata()
meta.box = l.core.boxPub meta.box = l.core.boxPub
@ -51,25 +59,17 @@ func (l *awdl) create(fromAWDL chan []byte, toAWDL chan []byte, boxPubKey *crypt
if !meta.decode(metaBytes) || !meta.check() { if !meta.decode(metaBytes) || !meta.check() {
return nil, errors.New("Metadata decode failure") return nil, errors.New("Metadata decode failure")
} }
l.core.log.Println("version_getBaseMetadata{}")
base := version_getBaseMetadata() base := version_getBaseMetadata()
if meta.ver > base.ver || meta.ver == base.ver && meta.minorVer > base.minorVer { if meta.ver > base.ver || meta.ver == base.ver && meta.minorVer > base.minorVer {
return nil, errors.New("Failed to connect to node: " + name + " version: " + fmt.Sprintf("%d.%d", meta.ver, meta.minorVer)) return nil, errors.New("Failed to connect to node: " + name + " version: " + fmt.Sprintf("%d.%d", meta.ver, meta.minorVer))
} }
l.core.log.Println("crypto.GetSharedKey")
shared := crypto.GetSharedKey(myLinkPriv, &meta.link) shared := crypto.GetSharedKey(myLinkPriv, &meta.link)
*/ //shared := crypto.GetSharedKey(&l.core.boxPriv, boxPubKey)
shared := crypto.GetSharedKey(&l.core.boxPriv, boxPubKey) l.core.log.Println("l.core.peers.newPeer")
intf := awdlInterface{ intf.peer = l.core.peers.newPeer(&meta.box, &meta.sig, shared, name)
awdl: l,
fromAWDL: fromAWDL,
toAWDL: toAWDL,
shutdown: make(chan bool),
peer: l.core.peers.newPeer(boxPubKey, sigPubKey, shared, name),
//peer: l.core.peers.newPeer(&meta.box, &meta.sig, shared, name),
}
if intf.peer != nil { if intf.peer != nil {
l.mutex.Lock()
l.interfaces[name] = &intf
l.mutex.Unlock()
intf.peer.linkOut = make(chan []byte, 1) // protocol traffic intf.peer.linkOut = make(chan []byte, 1) // protocol traffic
intf.peer.out = func(msg []byte) { intf.peer.out = func(msg []byte) {
defer func() { recover() }() defer func() { recover() }()
@ -84,6 +84,7 @@ func (l *awdl) create(fromAWDL chan []byte, toAWDL chan []byte, boxPubKey *crypt
go intf.peer.linkLoop() go intf.peer.linkLoop()
return &intf, nil return &intf, nil
} }
delete(l.interfaces, name)
return nil, errors.New("l.core.peers.newPeer failed") return nil, errors.New("l.core.peers.newPeer failed")
} }

View File

@ -5,15 +5,14 @@ package yggdrasil
import ( import (
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors"
"log" "log"
"os" "os"
"regexp" "regexp"
"time"
hjson "github.com/hjson/hjson-go" hjson "github.com/hjson/hjson-go"
"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/crypto"
"github.com/yggdrasil-network/yggdrasil-go/src/util" "github.com/yggdrasil-network/yggdrasil-go/src/util"
) )
@ -23,6 +22,26 @@ import (
// that in the case of iOS we handle reading/writing to/from TUN in Swift // that in the case of iOS we handle reading/writing to/from TUN in Swift
// therefore we use the "dummy" TUN interface instead. // 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 { func (c *Core) StartAutoconfigure() error {
mobilelog := MobileLogger{} mobilelog := MobileLogger{}
logger := log.New(mobilelog, "", 0) logger := log.New(mobilelog, "", 0)
@ -40,9 +59,12 @@ func (c *Core) StartAutoconfigure() error {
if err := c.Start(nc, logger); err != nil { if err := c.Start(nc, logger); err != nil {
return err return err
} }
go c.addStaticPeers(nc)
return nil 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 { func (c *Core) StartJSON(configjson []byte) error {
mobilelog := MobileLogger{} mobilelog := MobileLogger{}
logger := log.New(mobilelog, "", 0) logger := log.New(mobilelog, "", 0)
@ -55,7 +77,9 @@ func (c *Core) StartJSON(configjson []byte) error {
return err return err
} }
nc.IfName = "dummy" nc.IfName = "dummy"
//c.log.Println(nc.MulticastInterfaces)
for _, ll := range nc.MulticastInterfaces { for _, ll := range nc.MulticastInterfaces {
//c.log.Println("Processing MC", ll)
ifceExpr, err := regexp.Compile(ll) ifceExpr, err := regexp.Compile(ll)
if err != nil { if err != nil {
panic(err) panic(err)
@ -65,9 +89,11 @@ func (c *Core) StartJSON(configjson []byte) error {
if err := c.Start(nc, logger); err != nil { if err := c.Start(nc, logger); err != nil {
return err return err
} }
go c.addStaticPeers(nc)
return nil return nil
} }
// Generates mobile-friendly configuration in JSON format.
func GenerateConfigJSON() []byte { func GenerateConfigJSON() []byte {
nc := config.GenerateConfig(false) nc := config.GenerateConfig(false)
nc.IfName = "dummy" nc.IfName = "dummy"
@ -78,90 +104,40 @@ func GenerateConfigJSON() []byte {
} }
} }
// Gets the node's IPv6 address.
func (c *Core) GetAddressString() string { func (c *Core) GetAddressString() string {
return c.GetAddress().String() return c.GetAddress().String()
} }
// Gets the node's IPv6 subnet in CIDR notation.
func (c *Core) GetSubnetString() string { func (c *Core) GetSubnetString() string {
return c.GetSubnet().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) { func (c *Core) RouterRecvPacket() ([]byte, error) {
packet := <-c.router.tun.recv packet := <-c.router.tun.recv
return packet, nil 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 { func (c *Core) RouterSendPacket(buf []byte) error {
packet := append(util.GetBytes(), buf[:]...) packet := append(util.GetBytes(), buf[:]...)
c.router.tun.send <- packet c.router.tun.send <- packet
return nil return nil
} }
func (c *Core) AWDLCreateInterface(boxPubKey string, sigPubKey string, name string) error {
fromAWDL := make(chan []byte, 32)
toAWDL := make(chan []byte, 32)
var boxPub crypto.BoxPubKey
var sigPub crypto.SigPubKey
boxPubHex, err := hex.DecodeString(boxPubKey)
if err != nil {
c.log.Println(err)
return err
}
sigPubHex, err := hex.DecodeString(sigPubKey)
if err != nil {
c.log.Println(err)
return err
}
copy(boxPub[:], boxPubHex)
copy(sigPub[:], sigPubHex)
if intf, err := c.awdl.create(fromAWDL, toAWDL, &boxPub, &sigPub, name); err == nil {
if intf != nil {
c.log.Println(err)
return err
} else {
c.log.Println("c.awdl.create didn't return an interface")
return errors.New("c.awdl.create didn't return an interface")
}
} else {
c.log.Println(err)
return err
}
}
func (c *Core) AWDLCreateInterfaceFromContext(context []byte, name string) error {
if len(context) < crypto.BoxPubKeyLen+crypto.SigPubKeyLen {
return errors.New("Not enough bytes in context")
}
boxPubKey := hex.EncodeToString(context[:crypto.BoxPubKeyLen])
sigPubKey := hex.EncodeToString(context[crypto.BoxPubKeyLen:])
return c.AWDLCreateInterface(boxPubKey, sigPubKey, name)
}
func (c *Core) AWDLShutdownInterface(name string) error {
return c.awdl.shutdown(name)
}
func (c *Core) AWDLRecvPacket(identity string) ([]byte, error) {
if intf := c.awdl.getInterface(identity); intf != nil {
return <-intf.toAWDL, nil
}
return nil, errors.New("AWDLRecvPacket identity not known: " + identity)
}
func (c *Core) AWDLSendPacket(identity string, buf []byte) error {
packet := append(util.GetBytes(), buf[:]...)
if intf := c.awdl.getInterface(identity); intf != nil {
intf.fromAWDL <- packet
return nil
}
return errors.New("AWDLSendPacket identity not known: " + identity)
}
func (c *Core) AWDLConnectionContext() []byte {
var context []byte
context = append(context, c.boxPub[:]...)
context = append(context, c.sigPub[:]...)
return context
}

View File

@ -0,0 +1,12 @@
// +build android
package yggdrasil
import "log"
type MobileLogger struct{}
func (nsl MobileLogger) Write(p []byte) (n int, err error) {
log.Println(string(p))
return len(p), nil
}

View File

@ -12,7 +12,12 @@ void Log(const char *text) {
} }
*/ */
import "C" import "C"
import "unsafe" import (
"errors"
"unsafe"
"github.com/yggdrasil-network/yggdrasil-go/src/util"
)
type MobileLogger struct { type MobileLogger struct {
} }
@ -23,3 +28,41 @@ func (nsl MobileLogger) Write(p []byte) (n int, err error) {
C.Log(cstr) C.Log(cstr)
return len(p), nil return len(p), nil
} }
func (c *Core) AWDLCreateInterface(name string) error {
fromAWDL := make(chan []byte, 32)
toAWDL := make(chan []byte, 32)
if intf, err := c.awdl.create(fromAWDL, toAWDL, name); err == nil {
if intf != nil {
c.log.Println(err)
return err
} else {
c.log.Println("c.awdl.create didn't return an interface")
return errors.New("c.awdl.create didn't return an interface")
}
} else {
c.log.Println(err)
return err
}
}
func (c *Core) AWDLShutdownInterface(name string) error {
return c.awdl.shutdown(name)
}
func (c *Core) AWDLRecvPacket(identity string) ([]byte, error) {
if intf := c.awdl.getInterface(identity); intf != nil {
return <-intf.toAWDL, nil
}
return nil, errors.New("AWDLRecvPacket identity not known: " + identity)
}
func (c *Core) AWDLSendPacket(identity string, buf []byte) error {
packet := append(util.GetBytes(), buf[:]...)
if intf := c.awdl.getInterface(identity); intf != nil {
intf.fromAWDL <- packet
return nil
}
return errors.New("AWDLSendPacket identity not known: " + identity)
}

View File

@ -157,6 +157,6 @@ func (m *multicast) listen() {
} }
addr.Zone = from.Zone addr.Zone = from.Zone
saddr := addr.String() saddr := addr.String()
m.core.tcp.connect(saddr, "") m.core.tcp.connect(saddr, addr.Zone)
} }
} }

View File

@ -0,0 +1,28 @@
// +build darwin
package yggdrasil
import "syscall"
import "golang.org/x/sys/unix"
func multicastReuse(network string, address string, c syscall.RawConn) error {
var control error
var reuseport error
var recvanyif error
control = c.Control(func(fd uintptr) {
reuseport = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
// sys/socket.h: #define SO_RECV_ANYIF 0x1104
recvanyif = unix.SetsockoptInt(int(fd), syscall.SOL_SOCKET, 0x1104, 1)
})
switch {
case reuseport != nil:
return reuseport
case recvanyif != nil:
return recvanyif
default:
return control
}
}

View File

@ -1,4 +1,4 @@
// +build linux darwin netbsd freebsd openbsd dragonflybsd // +build linux netbsd freebsd openbsd dragonflybsd
package yggdrasil package yggdrasil

View File

@ -15,6 +15,7 @@ package yggdrasil
// See version.go for version metadata format // See version.go for version metadata format
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -88,7 +89,11 @@ func (iface *tcpInterface) init(core *Core, addr string, readTimeout int32) (err
iface.tcp_timeout = default_tcp_timeout iface.tcp_timeout = default_tcp_timeout
} }
iface.serv, err = net.Listen("tcp", addr) ctx := context.Background()
lc := net.ListenConfig{
Control: iface.tcpContext,
}
iface.serv, err = lc.Listen(ctx, "tcp", addr)
if err == nil { if err == nil {
iface.calls = make(map[string]struct{}) iface.calls = make(map[string]struct{})
iface.conns = make(map[tcpInfo](chan struct{})) iface.conns = make(map[tcpInfo](chan struct{}))
@ -164,7 +169,9 @@ func (iface *tcpInterface) call(saddr string, socksaddr *string, sintf string) {
}, },
} }
} else { } else {
dialer := net.Dialer{} dialer := net.Dialer{
Control: iface.tcpContext,
}
if sintf != "" { if sintf != "" {
ief, err := net.InterfaceByName(sintf) ief, err := net.InterfaceByName(sintf)
if err != nil { if err != nil {

View File

@ -0,0 +1,28 @@
// +build darwin
package yggdrasil
import (
"syscall"
"golang.org/x/sys/unix"
)
// WARNING: This context is used both by net.Dialer and net.Listen in tcp.go
func (iface *tcpInterface) tcpContext(network, address string, c syscall.RawConn) error {
var control error
var recvanyif error
control = c.Control(func(fd uintptr) {
// sys/socket.h: #define SO_RECV_ANYIF 0x1104
recvanyif = unix.SetsockoptInt(int(fd), syscall.SOL_SOCKET, 0x1104, 1)
})
switch {
case recvanyif != nil:
return recvanyif
default:
return control
}
}

View File

@ -0,0 +1,13 @@
// +build !darwin
package yggdrasil
import (
"syscall"
)
// WARNING: This context is used both by net.Dialer and net.Listen in tcp.go
func (iface *tcpInterface) tcpContext(network, address string, c syscall.RawConn) error {
return nil
}