mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 11:15:07 +03:00 
			
		
		
		
	Document yggdrasil.go
This commit is contained in:
		
							parent
							
								
									f40525693e
								
							
						
					
					
						commit
						b019297458
					
				
					 1 changed files with 72 additions and 12 deletions
				
			
		
							
								
								
									
										84
									
								
								yggdrasil.go
									
										
									
									
									
								
							
							
						
						
									
										84
									
								
								yggdrasil.go
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -31,10 +31,20 @@ type node struct {
 | 
			
		|||
	core Core
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Generates default configuration. This is used when outputting the -genconf
 | 
			
		||||
// parameter and also when using -autoconf. The isAutoconf flag is used to
 | 
			
		||||
// determine whether the operating system should select a free port by itself
 | 
			
		||||
// (which guarantees that there will not be a conflict with any other services)
 | 
			
		||||
// or whether to generate a random port number. The only side effect of setting
 | 
			
		||||
// isAutoconf is that the TCP and UDP ports will likely end up with different
 | 
			
		||||
// port numbers.
 | 
			
		||||
func generateConfig(isAutoconf bool) *nodeConfig {
 | 
			
		||||
	// Create a new core.
 | 
			
		||||
	core := Core{}
 | 
			
		||||
	// Generate encryption keys.
 | 
			
		||||
	bpub, bpriv := core.NewEncryptionKeys()
 | 
			
		||||
	spub, spriv := core.NewSigningKeys()
 | 
			
		||||
	// Create a node configuration and populate it.
 | 
			
		||||
	cfg := nodeConfig{}
 | 
			
		||||
	if isAutoconf {
 | 
			
		||||
		cfg.Listen = "[::]:0"
 | 
			
		||||
| 
						 | 
				
			
			@ -57,6 +67,8 @@ func generateConfig(isAutoconf bool) *nodeConfig {
 | 
			
		|||
	return &cfg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Generates a new configuration and returns it in HJSON format. This is used
 | 
			
		||||
// with -genconf.
 | 
			
		||||
func doGenconf() string {
 | 
			
		||||
	cfg := generateConfig(false)
 | 
			
		||||
	bs, err := hjson.Marshal(cfg)
 | 
			
		||||
| 
						 | 
				
			
			@ -66,37 +78,51 @@ func doGenconf() string {
 | 
			
		|||
	return string(bs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 useconffile = flag.String("useconffile", "", "read config from specified file path")
 | 
			
		||||
var normaliseconf = flag.Bool("normaliseconf", false, "use in combination with either -useconf or -useconffile, outputs your configuration normalised")
 | 
			
		||||
var autoconf = flag.Bool("autoconf", false, "automatic mode (dynamic IP, peer with IPv6 neighbors)")
 | 
			
		||||
 | 
			
		||||
// The main function is responsible for configuring and starting Yggdrasil.
 | 
			
		||||
func main() {
 | 
			
		||||
	// Configure the command line parameters.
 | 
			
		||||
	pprof := flag.Bool("pprof", false, "Run pprof, see http://localhost:6060/debug/pprof/")
 | 
			
		||||
	genconf := flag.Bool("genconf", false, "print a new config to stdout")
 | 
			
		||||
	useconf := flag.Bool("useconf", false, "read config from stdin")
 | 
			
		||||
	useconffile := flag.String("useconffile", "", "read config from specified file path")
 | 
			
		||||
	normaliseconf := flag.Bool("normaliseconf", false, "use in combination with either -useconf or -useconffile, outputs your configuration normalised")
 | 
			
		||||
	autoconf := flag.Bool("autoconf", false, "automatic mode (dynamic IP, peer with IPv6 neighbors)")
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
 | 
			
		||||
	var cfg *nodeConfig
 | 
			
		||||
	switch {
 | 
			
		||||
	case *autoconf:
 | 
			
		||||
		// Use an autoconf-generated config, this will give us random keys and
 | 
			
		||||
		// port numbers, and will use an automatically selected TUN/TAP interface.
 | 
			
		||||
		cfg = generateConfig(true)
 | 
			
		||||
	case *useconffile != "" || *useconf:
 | 
			
		||||
		// Use a configuration file. If -useconf, the configuration will be read
 | 
			
		||||
		// from stdin. If -useconffile, the configuration will be read from the
 | 
			
		||||
		// filesystem.
 | 
			
		||||
		var config []byte
 | 
			
		||||
		var err error
 | 
			
		||||
		if *useconffile != "" {
 | 
			
		||||
			// Read the file from the filesystem
 | 
			
		||||
			config, err = ioutil.ReadFile(*useconffile)
 | 
			
		||||
		} else {
 | 
			
		||||
			// Read the file from stdin.
 | 
			
		||||
			config, err = ioutil.ReadAll(os.Stdin)
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		// Generate a new configuration - this gives us a set of sane defaults -
 | 
			
		||||
		// then parse the configuration we loaded above on top of it. The effect
 | 
			
		||||
		// of this is that any configuration item that is missing from the provided
 | 
			
		||||
		// configuration will use a sane default.
 | 
			
		||||
		cfg = generateConfig(false)
 | 
			
		||||
		var dat map[string]interface{}
 | 
			
		||||
		if err := hjson.Unmarshal(config, &dat); err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		// For now we will do a little bit to help the user adjust their
 | 
			
		||||
		// configuration to match the new configuration format
 | 
			
		||||
		// configuration to match the new configuration format, as some of the key
 | 
			
		||||
		// names have changed recently.
 | 
			
		||||
		changes := map[string]string{
 | 
			
		||||
			"Multicast":      "",
 | 
			
		||||
			"LinkLocal":      "MulticastInterfaces",
 | 
			
		||||
| 
						 | 
				
			
			@ -106,6 +132,7 @@ func main() {
 | 
			
		|||
			"SigPriv":        "SigningPrivateKey",
 | 
			
		||||
			"AllowedBoxPubs": "AllowedEncryptionPublicKeys",
 | 
			
		||||
		}
 | 
			
		||||
		// Loop over the mappings aove and see if we have anything to fix.
 | 
			
		||||
		for from, to := range changes {
 | 
			
		||||
			if _, ok := dat[from]; ok {
 | 
			
		||||
				if to == "" {
 | 
			
		||||
| 
						 | 
				
			
			@ -116,15 +143,24 @@ func main() {
 | 
			
		|||
					if !*normaliseconf {
 | 
			
		||||
						log.Println("Warning: Deprecated config option", from, "- please rename to", to)
 | 
			
		||||
					}
 | 
			
		||||
					// If the configuration file doesn't already contain a line with the
 | 
			
		||||
					// new name then set it to the old value. This makes sure that we
 | 
			
		||||
					// don't overwrite something that was put there intentionally.
 | 
			
		||||
					if _, ok := dat[to]; !ok {
 | 
			
		||||
						dat[to] = dat[from]
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		// Overlay our newly mapped configuration onto the autoconf node config that
 | 
			
		||||
		// we generated above.
 | 
			
		||||
		if err = mapstructure.Decode(dat, &cfg); err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		// If the -normaliseconf option was specified then remarshal the above
 | 
			
		||||
		// configuration and print it back to stdout. This lets the user update
 | 
			
		||||
		// their configuration file with newly mapped names (like above) or to
 | 
			
		||||
		// convert from plain JSON to commented HJSON.
 | 
			
		||||
		if *normaliseconf {
 | 
			
		||||
			bs, err := hjson.Marshal(cfg)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -134,23 +170,35 @@ func main() {
 | 
			
		|||
			return
 | 
			
		||||
		}
 | 
			
		||||
	case *genconf:
 | 
			
		||||
		// Generate a new configuration and print it to stdout.
 | 
			
		||||
		fmt.Println(doGenconf())
 | 
			
		||||
	default:
 | 
			
		||||
		// No flags were provided, therefore print the list of flags to stdout.
 | 
			
		||||
		flag.PrintDefaults()
 | 
			
		||||
	}
 | 
			
		||||
	// Have we got a working configuration? If we don't then it probably means
 | 
			
		||||
	// that neither -autoconf, -useconf or -useconffile were set above. Stop
 | 
			
		||||
	// if we don't.
 | 
			
		||||
	if cfg == nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	// Create a new logger that logs output to stdout.
 | 
			
		||||
	logger := log.New(os.Stdout, "", log.Flags())
 | 
			
		||||
	// If the -pprof flag was provided then start the pprof service on port 6060.
 | 
			
		||||
	if *pprof {
 | 
			
		||||
		runtime.SetBlockProfileRate(1)
 | 
			
		||||
		go func() { log.Println(http.ListenAndServe("localhost:6060", nil)) }()
 | 
			
		||||
	}
 | 
			
		||||
	// Setup
 | 
			
		||||
	// Setup the Yggdrasil node itself. The node{} type includes a Core, so we
 | 
			
		||||
	// don't need to create this manually.
 | 
			
		||||
	n := node{}
 | 
			
		||||
	// Check to see if any allowed encryption keys were provided in the config.
 | 
			
		||||
	// If they were then set them now.
 | 
			
		||||
	for _, pBoxStr := range cfg.AllowedEncryptionPublicKeys {
 | 
			
		||||
		n.core.AddAllowedEncryptionPublicKey(pBoxStr)
 | 
			
		||||
	}
 | 
			
		||||
	// Check to see if any multicast interface expressions were provided in the
 | 
			
		||||
	// config. If they were then set them now.
 | 
			
		||||
	for _, ll := range cfg.MulticastInterfaces {
 | 
			
		||||
		ifceExpr, err := regexp.Compile(ll)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -158,10 +206,17 @@ func main() {
 | 
			
		|||
		}
 | 
			
		||||
		n.core.AddMulticastInterfaceExpr(ifceExpr)
 | 
			
		||||
	}
 | 
			
		||||
	// Now that we have a working configuration, and we have provided any allowed
 | 
			
		||||
	// encryption keys or multicast interface expressions, we can now actually
 | 
			
		||||
	// start Yggdrasil. This will start the router, switch, DHT node, TCP and UDP
 | 
			
		||||
	// sockets, TUN/TAP adapter and multicast discovery port.
 | 
			
		||||
	if err := n.core.Start(cfg, logger); err != nil {
 | 
			
		||||
		logger.Println("An error occured during startup")
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	// If any static peers were provided in the configuration above then we should
 | 
			
		||||
	// configure them. The loop ensures that disconnected peers will eventually
 | 
			
		||||
	// be reconnected with.
 | 
			
		||||
	go func() {
 | 
			
		||||
		if len(cfg.Peers) == 0 {
 | 
			
		||||
			return
 | 
			
		||||
| 
						 | 
				
			
			@ -174,22 +229,27 @@ func main() {
 | 
			
		|||
			time.Sleep(time.Minute)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	// The Stop function ensures that the TUN/TAP adapter is correctly shut down
 | 
			
		||||
	// before the program exits.
 | 
			
		||||
	defer func() {
 | 
			
		||||
		n.core.Stop()
 | 
			
		||||
	}()
 | 
			
		||||
	// Make some nice output that tells us what our IPv6 address and subnet are.
 | 
			
		||||
	// This is just logged to stdout for the user.
 | 
			
		||||
	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())
 | 
			
		||||
	// Catch interrupt to exit gracefully
 | 
			
		||||
	// Catch interrupts from the operating system to exit gracefully.
 | 
			
		||||
	c := make(chan os.Signal, 1)
 | 
			
		||||
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
 | 
			
		||||
	// Create a function to capture the service being stopped on Windows
 | 
			
		||||
	// Create a function to capture the service being stopped on Windows.
 | 
			
		||||
	winTerminate := func() {
 | 
			
		||||
		c <- os.Interrupt
 | 
			
		||||
	}
 | 
			
		||||
	minwinsvc.SetOnExit(winTerminate)
 | 
			
		||||
	// Wait for the terminate/interrupt signal
 | 
			
		||||
	// Wait for the terminate/interrupt signal. Once a signal is received, the
 | 
			
		||||
	// deferred Stop function above will run which will shut down TUN/TAP.
 | 
			
		||||
	<-c
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue