2017-12-28 22:16:20 -06:00
package main
import "encoding/hex"
import "flag"
import "fmt"
import "io/ioutil"
import "net"
import "os"
import "os/signal"
2018-02-18 21:16:47 +00:00
import "syscall"
2017-12-28 22:16:20 -06:00
import "time"
2018-01-09 02:08:54 -06:00
import "regexp"
2018-03-07 19:41:56 +00:00
import "math/rand"
2017-12-28 22:16:20 -06:00
import _ "net/http/pprof"
import "net/http"
import "log"
import "runtime"
2018-04-19 10:30:40 -04:00
import "yggdrasil"
import "yggdrasil/config"
2017-12-28 22:16:20 -06:00
2018-02-18 21:16:47 +00:00
import "github.com/kardianos/minwinsvc"
2018-05-09 13:54:31 +01:00
import "github.com/neilalexander/hjson-go"
import "github.com/mitchellh/mapstructure"
2018-02-16 14:12:44 +00:00
2018-04-19 10:30:40 -04:00
type nodeConfig = config . NodeConfig
type Core = yggdrasil . Core
2017-12-28 22:16:20 -06:00
type node struct {
2018-01-04 22:37:51 +00:00
core Core
2017-12-28 22:16:20 -06:00
}
func ( n * node ) init ( cfg * nodeConfig , logger * log . Logger ) {
2018-05-23 11:28:20 +01:00
boxPub , err := hex . DecodeString ( cfg . EncryptionPublicKey )
2018-01-04 22:37:51 +00:00
if err != nil {
panic ( err )
}
2018-05-23 11:28:20 +01:00
boxPriv , err := hex . DecodeString ( cfg . EncryptionPrivateKey )
2018-01-04 22:37:51 +00:00
if err != nil {
panic ( err )
}
2018-05-23 11:28:20 +01:00
sigPub , err := hex . DecodeString ( cfg . SigningPublicKey )
2018-01-04 22:37:51 +00:00
if err != nil {
panic ( err )
}
2018-05-23 11:28:20 +01:00
sigPriv , err := hex . DecodeString ( cfg . SigningPrivateKey )
2018-01-04 22:37:51 +00:00
if err != nil {
panic ( err )
}
n . core . DEBUG_init ( boxPub , boxPriv , sigPub , sigPriv )
n . core . DEBUG_setLogger ( logger )
2018-04-19 10:30:40 -04:00
2018-01-04 22:37:51 +00:00
logger . Println ( "Starting interface..." )
2018-02-09 17:42:55 -06:00
n . core . DEBUG_setupAndStartGlobalTCPInterface ( cfg . Listen ) // Listen for peers on TCP
2018-02-09 18:50:03 -06:00
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-05-23 11:28:20 +01:00
for _ , pBoxStr := range cfg . AllowedEncryptionPublicKeys {
n . core . DEBUG_addAllowedEncryptionPublicKey ( pBoxStr )
2018-05-06 19:48:26 -05:00
}
2018-05-23 11:28:20 +01:00
for _ , ll := range cfg . MulticastInterfaces {
2018-05-23 11:13:53 +01:00
ifceExpr , err := regexp . Compile ( ll )
if err != nil {
panic ( err )
}
n . core . DEBUG_setIfceExpr ( ifceExpr )
}
n . core . DEBUG_setupAndStartMulticastInterface ( )
2018-05-06 19:48:26 -05:00
2018-01-04 22:37:51 +00:00
go func ( ) {
if len ( cfg . Peers ) == 0 {
return
}
for {
for _ , p := range cfg . Peers {
2018-04-26 10:23:21 -04:00
n . core . DEBUG_addPeer ( p )
2018-01-04 22:37:51 +00:00
time . Sleep ( time . Second )
}
time . Sleep ( time . Minute )
}
} ( )
2017-12-28 22:16:20 -06:00
}
2018-03-07 19:41:56 +00:00
func generateConfig ( isAutoconf bool ) * nodeConfig {
2018-01-04 22:37:51 +00:00
core := Core { }
bpub , bpriv := core . DEBUG_newBoxKeys ( )
spub , spriv := core . DEBUG_newSigKeys ( )
cfg := nodeConfig { }
2018-03-07 19:41:56 +00:00
if isAutoconf {
cfg . Listen = "[::]:0"
} else {
r1 := rand . New ( rand . NewSource ( time . Now ( ) . UnixNano ( ) ) )
2018-03-10 13:58:48 -06:00
cfg . Listen = fmt . Sprintf ( "[::]:%d" , r1 . Intn ( 65534 - 32768 ) + 32768 )
2018-03-07 19:41:56 +00:00
}
2018-02-11 21:45:44 +00:00
cfg . AdminListen = "[::1]:9001"
2018-05-23 11:28:20 +01:00
cfg . EncryptionPublicKey = hex . EncodeToString ( bpub [ : ] )
cfg . EncryptionPrivateKey = hex . EncodeToString ( bpriv [ : ] )
cfg . SigningPublicKey = hex . EncodeToString ( spub [ : ] )
cfg . SigningPrivateKey = hex . EncodeToString ( spriv [ : ] )
2018-01-04 22:37:51 +00:00
cfg . Peers = [ ] string { }
2018-05-23 11:28:20 +01:00
cfg . AllowedEncryptionPublicKeys = [ ] string { }
cfg . MulticastInterfaces = [ ] string { ".*" }
2018-03-03 12:30:54 +00:00
cfg . IfName = core . DEBUG_GetTUNDefaultIfName ( )
cfg . IfMTU = core . DEBUG_GetTUNDefaultIfMTU ( )
cfg . IfTAPMode = core . DEBUG_GetTUNDefaultIfTAPMode ( )
2018-04-19 10:30:40 -04:00
2018-01-04 22:37:51 +00:00
return & cfg
2017-12-28 22:16:20 -06:00
}
func doGenconf ( ) string {
2018-03-07 19:41:56 +00:00
cfg := generateConfig ( false )
2018-05-09 13:54:31 +01:00
bs , err := hjson . Marshal ( cfg )
2018-01-04 22:37:51 +00:00
if err != nil {
panic ( err )
}
return string ( bs )
2017-12-28 22:16:20 -06: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" )
2018-02-16 14:12:44 +00:00
var useconffile = flag . String ( "useconffile" , "" , "read config from specified file path" )
2018-05-23 12:04:27 +01:00
var normaliseconf = flag . Bool ( "normaliseconf" , false , "use in combination with either -useconf or -useconffile, outputs your configuration normalised" )
2017-12-28 22:16:20 -06:00
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 :
2018-03-07 19:41:56 +00:00
cfg = generateConfig ( true )
2018-02-16 14:12:44 +00:00
case * useconffile != "" || * useconf :
var config [ ] byte
var err error
if * useconffile != "" {
config , err = ioutil . ReadFile ( * useconffile )
} else {
config , err = ioutil . ReadAll ( os . Stdin )
}
2018-01-04 22:37:51 +00:00
if err != nil {
panic ( err )
}
2018-03-07 19:41:56 +00:00
cfg = generateConfig ( false )
2018-05-09 13:54:31 +01:00
var dat map [ string ] interface { }
if err := hjson . Unmarshal ( config , & dat ) ; err != nil {
2018-05-09 14:03:28 +01:00
panic ( err )
}
2018-05-23 12:04:27 +01:00
// For now we will do a little bit to help the user adjust their
// configuration to match the new configuration format
changes := map [ string ] string {
"Multicast" : "" ,
"LinkLocal" : "MulticastInterfaces" ,
"BoxPub" : "EncryptionPublicKey" ,
"BoxPriv" : "EncryptionPrivateKey" ,
"SigPub" : "SigningPublicKey" ,
"SigPriv" : "SigningPrivateKey" ,
2018-05-23 12:32:26 +01:00
"AllowedBoxPubs" : "AllowedEncryptionPublicKeys" ,
2018-05-23 12:04:27 +01:00
}
for from , to := range changes {
2018-05-23 18:53:44 +01:00
if _ , ok := dat [ from ] ; ok {
if to == "" {
2018-05-23 12:04:27 +01:00
if ! * normaliseconf {
2018-05-23 18:53:44 +01:00
log . Println ( "Warning: Deprecated config option" , from , "- please remove" )
2018-05-23 12:04:27 +01:00
}
} else {
if ! * normaliseconf {
2018-05-23 18:53:44 +01:00
log . Println ( "Warning: Deprecated config option" , from , "- please rename to" , to )
2018-05-23 12:04:27 +01:00
}
if _ , ok := dat [ to ] ; ! ok {
dat [ to ] = dat [ from ]
}
}
}
}
2018-05-09 13:54:31 +01:00
if err = mapstructure . Decode ( dat , & cfg ) ; err != nil {
2018-01-04 22:37:51 +00:00
panic ( err )
}
2018-05-23 12:04:27 +01:00
if * normaliseconf {
bs , err := hjson . Marshal ( cfg )
if err != nil {
panic ( err )
}
fmt . Println ( string ( bs ) )
return
}
2018-01-04 22:37:51 +00:00
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 )
2018-02-15 22:29:13 +00:00
if cfg . IfName != "none" {
logger . Println ( "Starting TUN/TAP..." )
} else {
logger . Println ( "Not starting TUN/TAP" )
}
2018-02-04 11:25:20 -06:00
//n.core.DEBUG_startTun(cfg.IfName) // 1280, the smallest supported MTU
2018-02-14 12:53:32 +00:00
n . core . DEBUG_startTunWithMTU ( cfg . IfName , cfg . IfTAPMode , cfg . IfMTU ) // Largest supported MTU
2018-01-04 22:37:51 +00:00
defer func ( ) {
logger . Println ( "Closing..." )
n . core . DEBUG_stopTun ( )
} ( )
logger . Println ( "Started..." )
2018-05-21 16:15:31 +01:00
address := ( * n . core . GetAddress ( ) ) [ : ]
subnet := ( * n . core . GetSubnet ( ) ) [ : ]
subnet = append ( subnet , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 )
logger . Printf ( "Your IPv6 address is %s" , net . IP ( address ) . String ( ) )
logger . Printf ( "Your IPv6 subnet is %s/64" , net . IP ( subnet ) . String ( ) )
2018-01-04 22:37:51 +00:00
// Catch interrupt to exit gracefully
c := make ( chan os . Signal , 1 )
2018-02-18 21:16:47 +00:00
signal . Notify ( c , os . Interrupt , syscall . SIGTERM )
// Create a function to capture the service being stopped on Windows
winTerminate := func ( ) {
2018-02-18 21:32:55 +00:00
c <- os . Interrupt
}
2018-02-18 21:16:47 +00:00
minwinsvc . SetOnExit ( winTerminate )
// Wait for the terminate/interrupt signal
2018-01-04 22:37:51 +00:00
<- c
logger . Println ( "Stopping..." )
2017-12-28 22:16:20 -06:00
}