2017-12-29 04:16:20 +00:00
package main
import "bytes"
import "encoding/hex"
import "encoding/json"
import "flag"
import "fmt"
import "io/ioutil"
import "net"
import "os"
import "os/signal"
import "time"
2018-01-09 08:08:54 +00:00
import "regexp"
2017-12-29 04:16:20 +00:00
import _ "net/http/pprof"
import "net/http"
import "log"
import "runtime"
import "golang.org/x/net/ipv6"
import . "yggdrasil"
/ * *
* This is a very crude wrapper around src / yggdrasil
* It can generate a new config ( -- genconf )
* It can read a config from stdin ( -- useconf )
* It can run with an automatic config ( -- autoconf )
2018-01-04 22:37:51 +00:00
* /
2017-12-29 04:16:20 +00:00
type nodeConfig struct {
2018-01-21 00:17:15 +00:00
Listen string
AdminListen string
Peers [ ] string
BoxPub string
BoxPriv string
SigPub string
SigPriv string
Multicast bool
LinkLocal string
IfName string
2017-12-29 04:16:20 +00:00
}
type node struct {
2018-01-04 22:37:51 +00:00
core Core
sock * ipv6 . PacketConn
2017-12-29 04:16:20 +00:00
}
func ( n * node ) init ( cfg * nodeConfig , logger * log . Logger ) {
2018-01-04 22:37:51 +00:00
boxPub , err := hex . DecodeString ( cfg . BoxPub )
if err != nil {
panic ( err )
}
boxPriv , err := hex . DecodeString ( cfg . BoxPriv )
if err != nil {
panic ( err )
}
sigPub , err := hex . DecodeString ( cfg . SigPub )
if err != nil {
panic ( err )
}
sigPriv , err := hex . DecodeString ( cfg . SigPriv )
if err != nil {
panic ( err )
}
n . core . DEBUG_init ( boxPub , boxPriv , sigPub , sigPriv )
n . core . DEBUG_setLogger ( logger )
2018-01-09 08:08:54 +00:00
ifceExpr , err := regexp . Compile ( cfg . LinkLocal )
if err != nil {
panic ( err )
}
n . core . DEBUG_setIfceExpr ( ifceExpr )
2018-01-04 22:37:51 +00:00
logger . Println ( "Starting interface..." )
2018-02-09 23:42:55 +00:00
n . core . DEBUG_setupAndStartGlobalTCPInterface ( cfg . Listen ) // Listen for peers on TCP
n . core . DEBUG_setupAndStartGlobalUDPInterface ( cfg . Listen ) // Also listen on UDP, TODO allow separate configuration for ip/port to listen on each of these
2018-01-04 22:37:51 +00:00
logger . Println ( "Started interface" )
2018-01-21 00:17:15 +00:00
logger . Println ( "Starting admin socket..." )
n . core . DEBUG_setupAndStartAdminInterface ( cfg . AdminListen )
logger . Println ( "Started admin socket" )
2018-01-04 22:37:51 +00:00
go func ( ) {
if len ( cfg . Peers ) == 0 {
return
}
for {
for _ , p := range cfg . Peers {
2018-02-09 23:42:55 +00:00
switch {
case len ( p ) >= 4 && p [ : 4 ] == "udp:" : n . core . DEBUG_maybeSendUDPKeys ( p [ 4 : ] )
case len ( p ) >= 4 && p [ : 4 ] == "tcp:" : n . core . DEBUG_addTCPConn ( p [ 4 : ] )
default : n . core . DEBUG_addTCPConn ( p )
}
2018-01-04 22:37:51 +00:00
time . Sleep ( time . Second )
}
time . Sleep ( time . Minute )
}
} ( )
2017-12-29 04:16:20 +00:00
}
func generateConfig ( ) * nodeConfig {
2018-01-04 22:37:51 +00:00
core := Core { }
bpub , bpriv := core . DEBUG_newBoxKeys ( )
spub , spriv := core . DEBUG_newSigKeys ( )
cfg := nodeConfig { }
cfg . Listen = "[::]:0"
2018-01-21 18:55:45 +00:00
cfg . AdminListen = "localhost:9001"
2018-01-04 22:37:51 +00:00
cfg . BoxPub = hex . EncodeToString ( bpub [ : ] )
cfg . BoxPriv = hex . EncodeToString ( bpriv [ : ] )
cfg . SigPub = hex . EncodeToString ( spub [ : ] )
cfg . SigPriv = hex . EncodeToString ( spriv [ : ] )
cfg . Peers = [ ] string { }
cfg . Multicast = true
2018-01-09 08:08:54 +00:00
cfg . LinkLocal = ""
2018-01-04 22:37:51 +00:00
cfg . IfName = "auto"
return & cfg
2017-12-29 04:16:20 +00:00
}
func doGenconf ( ) string {
2018-01-04 22:37:51 +00:00
cfg := generateConfig ( )
bs , err := json . MarshalIndent ( cfg , "" , " " )
if err != nil {
panic ( err )
}
return string ( bs )
2017-12-29 04:16:20 +00:00
}
var multicastAddr = "[ff02::114]:9001"
func ( n * node ) listen ( ) {
2018-01-04 22:37:51 +00:00
groupAddr , err := net . ResolveUDPAddr ( "udp6" , multicastAddr )
if err != nil {
panic ( err )
}
bs := make ( [ ] byte , 2048 )
for {
nBytes , rcm , fromAddr , err := n . sock . ReadFrom ( bs )
if err != nil {
panic ( err )
}
//if rcm == nil { continue } // wat
//fmt.Println("DEBUG:", "packet from:", fromAddr.String())
2018-01-24 23:44:39 +00:00
if rcm != nil {
// Windows can't set the flag needed to return a non-nil value here
// So only make these checks if we get something useful back
// TODO? Skip them always, I'm not sure if they're really needed...
if ! rcm . Dst . IsLinkLocalMulticast ( ) {
continue
}
if ! rcm . Dst . Equal ( groupAddr . IP ) {
continue
}
2018-01-04 22:37:51 +00:00
}
anAddr := string ( bs [ : nBytes ] )
2018-02-09 23:42:55 +00:00
addr , err := net . ResolveTCPAddr ( "tcp6" , anAddr )
2018-01-04 22:37:51 +00:00
if err != nil {
panic ( err )
continue
} // Panic for testing, remove later
from := fromAddr . ( * net . UDPAddr )
//fmt.Println("DEBUG:", "heard:", addr.IP.String(), "from:", from.IP.String())
if addr . IP . String ( ) != from . IP . String ( ) {
continue
}
addr . Zone = from . Zone
saddr := addr . String ( )
//if _, isIn := n.peers[saddr]; isIn { continue }
//n.peers[saddr] = struct{}{}
2018-02-09 23:42:55 +00:00
n . core . DEBUG_addTCPConn ( saddr ) // FIXME? can result in 2 connections per peer
2018-01-04 22:37:51 +00:00
//fmt.Println("DEBUG:", "added multicast peer:", saddr)
}
2017-12-29 04:16:20 +00:00
}
func ( n * node ) announce ( ) {
2018-01-04 22:37:51 +00:00
groupAddr , err := net . ResolveUDPAddr ( "udp6" , multicastAddr )
if err != nil {
panic ( err )
}
2018-02-09 23:42:55 +00:00
var anAddr net . TCPAddr
tcpAddr := n . core . DEBUG_getGlobalTCPAddr ( )
anAddr . Port = tcpAddr . Port
2018-01-04 22:37:51 +00:00
destAddr , err := net . ResolveUDPAddr ( "udp6" , multicastAddr )
if err != nil {
panic ( err )
}
for {
ifaces , err := net . Interfaces ( )
if err != nil {
panic ( err )
}
for _ , iface := range ifaces {
n . sock . JoinGroup ( & iface , groupAddr )
//err := n.sock.JoinGroup(&iface, groupAddr)
//if err != nil { panic(err) }
addrs , err := iface . Addrs ( )
if err != nil {
panic ( err )
}
for _ , addr := range addrs {
addrIP , _ , _ := net . ParseCIDR ( addr . String ( ) )
if addrIP . To4 ( ) != nil {
continue
} // IPv6 only
if ! addrIP . IsLinkLocalUnicast ( ) {
continue
}
anAddr . IP = addrIP
anAddr . Zone = iface . Name
destAddr . Zone = iface . Name
msg := [ ] byte ( anAddr . String ( ) )
n . sock . WriteTo ( msg , nil , destAddr )
break
}
time . Sleep ( time . Second )
}
time . Sleep ( time . Second )
}
2017-12-29 04:16:20 +00:00
}
var pprof = flag . Bool ( "pprof" , false , "Run pprof, see http://localhost:6060/debug/pprof/" )
var genconf = flag . Bool ( "genconf" , false , "print a new config to stdout" )
var useconf = flag . Bool ( "useconf" , false , "read config from stdin" )
var autoconf = flag . Bool ( "autoconf" , false , "automatic mode (dynamic IP, peer with IPv6 neighbors)" )
func main ( ) {
2018-01-04 22:37:51 +00:00
flag . Parse ( )
var cfg * nodeConfig
switch {
case * autoconf :
cfg = generateConfig ( )
case * useconf :
config , err := ioutil . ReadAll ( os . Stdin )
if err != nil {
panic ( err )
}
decoder := json . NewDecoder ( bytes . NewReader ( config ) )
2018-01-09 08:08:54 +00:00
cfg = generateConfig ( )
err = decoder . Decode ( cfg )
2018-01-04 22:37:51 +00:00
if err != nil {
panic ( err )
}
case * genconf :
fmt . Println ( doGenconf ( ) )
default :
flag . PrintDefaults ( )
}
if cfg == nil {
return
}
logger := log . New ( os . Stdout , "" , log . Flags ( ) )
if * pprof {
runtime . SetBlockProfileRate ( 1 )
go func ( ) { log . Println ( http . ListenAndServe ( "localhost:6060" , nil ) ) } ( )
}
// Setup
logger . Println ( "Initializing..." )
n := node { }
n . init ( cfg , logger )
logger . Println ( "Starting tun..." )
2018-02-04 17:25:20 +00:00
//n.core.DEBUG_startTun(cfg.IfName) // 1280, the smallest supported MTU
n . core . DEBUG_startTunWithMTU ( cfg . IfName , 65535 ) // Largest supported MTU
2018-01-04 22:37:51 +00:00
defer func ( ) {
logger . Println ( "Closing..." )
n . core . DEBUG_stopTun ( )
} ( )
logger . Println ( "Started..." )
if cfg . Multicast {
addr , err := net . ResolveUDPAddr ( "udp" , multicastAddr )
if err != nil {
panic ( err )
}
listenString := fmt . Sprintf ( "[::]:%v" , addr . Port )
conn , err := net . ListenPacket ( "udp6" , listenString )
if err != nil {
panic ( err )
}
//defer conn.Close() // Let it close on its own when the application exits
n . sock = ipv6 . NewPacketConn ( conn )
if err = n . sock . SetControlMessage ( ipv6 . FlagDst , true ) ; err != nil {
2018-01-24 23:44:39 +00:00
// Windows can't set this flag, so we need to handle it in other ways
//panic(err)
2018-01-04 22:37:51 +00:00
}
go n . listen ( )
go n . announce ( )
}
// Catch interrupt to exit gracefully
c := make ( chan os . Signal , 1 )
2018-01-26 00:58:33 +00:00
signal . Notify ( c , os . Interrupt , os . Kill )
2018-01-04 22:37:51 +00:00
<- c
logger . Println ( "Stopping..." )
2017-12-29 04:16:20 +00:00
}