mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 03:05:07 +03:00 
			
		
		
		
	Merge branch 'develop' into develop
This commit is contained in:
		
						commit
						6184443bf7
					
				
					 19 changed files with 289 additions and 197 deletions
				
			
		
							
								
								
									
										39
									
								
								CHANGELOG.md
									
										
									
									
									
								
							
							
						
						
									
										39
									
								
								CHANGELOG.md
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -26,6 +26,45 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
 | 
			
		|||
- in case of vulnerabilities.
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
## [0.4.6] - 2022-10-25
 | 
			
		||||
 | 
			
		||||
### Added
 | 
			
		||||
 | 
			
		||||
- Support for prioritising multiple peerings to the same node has been added, useful for nodes with multiple network interfaces
 | 
			
		||||
  - The priority can be configured by specifying `?priority=X` in a `Peers` or `Listen` URI, or by specifying `Priority` within a `MulticastInterfaces` configuration entry
 | 
			
		||||
  - Priorities are values between 0 and 254 (default is 0), lower numbers are prioritised and nodes will automatically negotiate the higher of the two values
 | 
			
		||||
 | 
			
		||||
### Changed
 | 
			
		||||
 | 
			
		||||
- On Linux, `SO_REUSEADDR` is now used on the multicast port instead of `SO_REUSEPORT`, which should allow processes running under different users to run simultaneously
 | 
			
		||||
 | 
			
		||||
### Fixed
 | 
			
		||||
 | 
			
		||||
- Adding peers using the `InterfacePeers` configuration option should now work correctly again
 | 
			
		||||
- Multiple connections from the same remote IP address will no longer be incorrectly dropped
 | 
			
		||||
- The admin socket will no longer incorrectly claim TCP connections as TLS
 | 
			
		||||
- A panic that could occur when calling `GetPeers` while a peering link is being set up has been fixed
 | 
			
		||||
 | 
			
		||||
## [0.4.5] - 2022-10-15
 | 
			
		||||
 | 
			
		||||
### Added
 | 
			
		||||
 | 
			
		||||
- Support for peering over UNIX sockets is now available, by configuring `Listen` and peering URIs in the `unix:///path/to/socket.sock` format
 | 
			
		||||
 | 
			
		||||
### Changed
 | 
			
		||||
 | 
			
		||||
- `yggdrasilctl` has been refactored and now has cleaner output
 | 
			
		||||
- It is now possible to `addPeer` and `removePeer` using the admin socket again
 | 
			
		||||
- The `getSessions` admin socket call reports number of bytes received and transmitted again
 | 
			
		||||
- The link setup code has been refactored, making it easier to support new peering types in the future
 | 
			
		||||
- Yggdrasil now maintains configuration internally, rather than relying on a shared and potentially mutable structure
 | 
			
		||||
 | 
			
		||||
### Fixed
 | 
			
		||||
 | 
			
		||||
- Tracking information about expired root nodes has been fixed, which should hopefully resolve issues with reparenting and connection failures when the root node disappears
 | 
			
		||||
- A bug in the mobile framework code which caused a crash on Android when multicast failed to set up has been fixed
 | 
			
		||||
- Yggdrasil should now shut down gracefully and clean up correctly when running as a Windows service
 | 
			
		||||
 | 
			
		||||
## [0.4.4] - 2022-07-07
 | 
			
		||||
 | 
			
		||||
### Fixed
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,7 @@ import (
 | 
			
		|||
	"os/signal"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/text/encoding/unicode"
 | 
			
		||||
| 
						 | 
				
			
			@ -183,8 +184,7 @@ func getArgs() yggArgs {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// The main function is responsible for configuring and starting Yggdrasil.
 | 
			
		||||
func run(args yggArgs, ctx context.Context, done chan struct{}) {
 | 
			
		||||
	defer close(done)
 | 
			
		||||
func run(args yggArgs, ctx context.Context) {
 | 
			
		||||
	// Create a new logger that logs output to stdout.
 | 
			
		||||
	var logger *log.Logger
 | 
			
		||||
	switch args.logto {
 | 
			
		||||
| 
						 | 
				
			
			@ -295,7 +295,10 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) {
 | 
			
		|||
		if err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		options := []core.SetupOption{}
 | 
			
		||||
		options := []core.SetupOption{
 | 
			
		||||
			core.NodeInfo(cfg.NodeInfo),
 | 
			
		||||
			core.NodeInfoPrivacy(cfg.NodeInfoPrivacy),
 | 
			
		||||
		}
 | 
			
		||||
		for _, addr := range cfg.Listen {
 | 
			
		||||
			options = append(options, core.ListenAddress(addr))
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -337,10 +340,11 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) {
 | 
			
		|||
		options := []multicast.SetupOption{}
 | 
			
		||||
		for _, intf := range cfg.MulticastInterfaces {
 | 
			
		||||
			options = append(options, multicast.MulticastInterface{
 | 
			
		||||
				Regex:  regexp.MustCompile(intf.Regex),
 | 
			
		||||
				Beacon: intf.Beacon,
 | 
			
		||||
				Listen: intf.Listen,
 | 
			
		||||
				Port:   intf.Port,
 | 
			
		||||
				Regex:    regexp.MustCompile(intf.Regex),
 | 
			
		||||
				Beacon:   intf.Beacon,
 | 
			
		||||
				Listen:   intf.Listen,
 | 
			
		||||
				Port:     intf.Port,
 | 
			
		||||
				Priority: uint8(intf.Priority),
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		if n.multicast, err = multicast.New(n.core, logger, options...); err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -373,14 +377,11 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) {
 | 
			
		|||
	logger.Infof("Your public key is %s", hex.EncodeToString(public[:]))
 | 
			
		||||
	logger.Infof("Your IPv6 address is %s", address.String())
 | 
			
		||||
	logger.Infof("Your IPv6 subnet is %s", subnet.String())
 | 
			
		||||
	// Catch interrupts from the operating system to exit gracefully.
 | 
			
		||||
	<-ctx.Done()
 | 
			
		||||
	// Capture the service being stopped on Windows.
 | 
			
		||||
	minwinsvc.SetOnExit(n.shutdown)
 | 
			
		||||
	n.shutdown()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n *node) shutdown() {
 | 
			
		||||
	// Block until we are told to shut down.
 | 
			
		||||
	<-ctx.Done()
 | 
			
		||||
 | 
			
		||||
	// Shut down the node.
 | 
			
		||||
	_ = n.admin.Stop()
 | 
			
		||||
	_ = n.multicast.Stop()
 | 
			
		||||
	_ = n.tun.Stop()
 | 
			
		||||
| 
						 | 
				
			
			@ -389,24 +390,19 @@ func (n *node) shutdown() {
 | 
			
		|||
 | 
			
		||||
func main() {
 | 
			
		||||
	args := getArgs()
 | 
			
		||||
	hup := make(chan os.Signal, 1)
 | 
			
		||||
	//signal.Notify(hup, os.Interrupt, syscall.SIGHUP)
 | 
			
		||||
	term := make(chan os.Signal, 1)
 | 
			
		||||
	signal.Notify(term, os.Interrupt, syscall.SIGTERM)
 | 
			
		||||
	for {
 | 
			
		||||
		done := make(chan struct{})
 | 
			
		||||
		ctx, cancel := context.WithCancel(context.Background())
 | 
			
		||||
		go run(args, ctx, done)
 | 
			
		||||
		select {
 | 
			
		||||
		case <-hup:
 | 
			
		||||
			cancel()
 | 
			
		||||
			<-done
 | 
			
		||||
		case <-term:
 | 
			
		||||
			cancel()
 | 
			
		||||
			<-done
 | 
			
		||||
			return
 | 
			
		||||
		case <-done:
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Catch interrupts from the operating system to exit gracefully.
 | 
			
		||||
	ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
 | 
			
		||||
 | 
			
		||||
	// Capture the service being stopped on Windows.
 | 
			
		||||
	minwinsvc.SetOnExit(cancel)
 | 
			
		||||
 | 
			
		||||
	// Start the node, block and then wait for it to shut down.
 | 
			
		||||
	var wg sync.WaitGroup
 | 
			
		||||
	wg.Add(1)
 | 
			
		||||
	go func() {
 | 
			
		||||
		defer wg.Done()
 | 
			
		||||
		run(args, ctx)
 | 
			
		||||
	}()
 | 
			
		||||
	wg.Wait()
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -174,7 +174,7 @@ func run() int {
 | 
			
		|||
		if err := json.Unmarshal(recv.Response, &resp); err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		table.SetHeader([]string{"Port", "Public Key", "IP Address", "Uptime", "RX", "TX", "URI"})
 | 
			
		||||
		table.SetHeader([]string{"Port", "Public Key", "IP Address", "Uptime", "RX", "TX", "Pr", "URI"})
 | 
			
		||||
		for _, peer := range resp.Peers {
 | 
			
		||||
			table.Append([]string{
 | 
			
		||||
				fmt.Sprintf("%d", peer.Port),
 | 
			
		||||
| 
						 | 
				
			
			@ -183,6 +183,7 @@ func run() int {
 | 
			
		|||
				(time.Duration(peer.Uptime) * time.Second).String(),
 | 
			
		||||
				peer.RXBytes.String(),
 | 
			
		||||
				peer.TXBytes.String(),
 | 
			
		||||
				fmt.Sprintf("%d", peer.Priority),
 | 
			
		||||
				peer.Remote,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -83,10 +83,11 @@ func (m *Yggdrasil) StartJSON(configjson []byte) error {
 | 
			
		|||
		options := []multicast.SetupOption{}
 | 
			
		||||
		for _, intf := range m.config.MulticastInterfaces {
 | 
			
		||||
			options = append(options, multicast.MulticastInterface{
 | 
			
		||||
				Regex:  regexp.MustCompile(intf.Regex),
 | 
			
		||||
				Beacon: intf.Beacon,
 | 
			
		||||
				Listen: intf.Listen,
 | 
			
		||||
				Port:   intf.Port,
 | 
			
		||||
				Regex:    regexp.MustCompile(intf.Regex),
 | 
			
		||||
				Beacon:   intf.Beacon,
 | 
			
		||||
				Listen:   intf.Listen,
 | 
			
		||||
				Port:     intf.Port,
 | 
			
		||||
				Priority: uint8(intf.Priority),
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		m.multicast, err = multicast.New(m.core, logger, options...)
 | 
			
		||||
| 
						 | 
				
			
			@ -114,6 +115,18 @@ func (m *Yggdrasil) Send(p []byte) error {
 | 
			
		|||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Send sends a packet from given buffer to Yggdrasil. From first byte up to length.
 | 
			
		||||
func (m *Yggdrasil) SendBuffer(p []byte, length int) error {
 | 
			
		||||
	if m.iprwc == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if len(p) < length {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	_, _ = m.iprwc.Write(p[:length])
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Recv waits for and reads a packet coming from Yggdrasil. It
 | 
			
		||||
// will be a fully formed IPv6 packet
 | 
			
		||||
func (m *Yggdrasil) Recv() ([]byte, error) {
 | 
			
		||||
| 
						 | 
				
			
			@ -125,6 +138,15 @@ func (m *Yggdrasil) Recv() ([]byte, error) {
 | 
			
		|||
	return buf[:n], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Recv waits for and reads a packet coming from Yggdrasil to given buffer, returning size of packet
 | 
			
		||||
func (m *Yggdrasil) RecvBuffer(buf []byte) (int, error) {
 | 
			
		||||
	if m.iprwc == nil {
 | 
			
		||||
		return 0, nil
 | 
			
		||||
	}
 | 
			
		||||
	n, _ := m.iprwc.Read(buf)
 | 
			
		||||
	return n, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Stop the mobile Yggdrasil instance
 | 
			
		||||
func (m *Yggdrasil) Stop() error {
 | 
			
		||||
	logger := log.New(m.log, "", 0)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										14
									
								
								go.mod
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								go.mod
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -3,19 +3,19 @@ module github.com/yggdrasil-network/yggdrasil-go
 | 
			
		|||
go 1.17
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/Arceliar/ironwood v0.0.0-20220924160422-ed4b6d4750b6
 | 
			
		||||
	github.com/Arceliar/ironwood v0.0.0-20221025225125-45b4281814c2
 | 
			
		||||
	github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979
 | 
			
		||||
	github.com/cheggaaa/pb/v3 v3.0.8
 | 
			
		||||
	github.com/gologme/log v1.2.0
 | 
			
		||||
	github.com/hashicorp/go-syslog v1.0.0
 | 
			
		||||
	github.com/hjson/hjson-go v3.1.0+incompatible
 | 
			
		||||
	github.com/kardianos/minwinsvc v1.0.0
 | 
			
		||||
	github.com/kardianos/minwinsvc v1.0.2
 | 
			
		||||
	github.com/mitchellh/mapstructure v1.4.1
 | 
			
		||||
	github.com/vishvananda/netlink v1.1.0
 | 
			
		||||
	golang.org/x/mobile v0.0.0-20220722155234-aaac322e2105
 | 
			
		||||
	golang.org/x/net v0.0.0-20220722155237-a158d28d115b
 | 
			
		||||
	golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f
 | 
			
		||||
	golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b
 | 
			
		||||
	golang.org/x/mobile v0.0.0-20221020085226-b36e6246172e
 | 
			
		||||
	golang.org/x/net v0.0.0-20221014081412-f15817d10f9b
 | 
			
		||||
	golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43
 | 
			
		||||
	golang.org/x/text v0.3.8
 | 
			
		||||
	golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a
 | 
			
		||||
	golang.zx2c4.com/wireguard/windows v0.4.12
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ require (
 | 
			
		|||
require (
 | 
			
		||||
	github.com/mattn/go-colorable v0.1.8 // indirect
 | 
			
		||||
	github.com/rivo/uniseg v0.2.0 // indirect
 | 
			
		||||
	golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
 | 
			
		||||
	golang.org/x/crypto v0.0.0-20221012134737-56aed061732a // indirect
 | 
			
		||||
	golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
 | 
			
		||||
	golang.org/x/tools v0.1.12 // indirect
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										29
									
								
								go.sum
									
										
									
									
									
								
							
							
						
						
									
										29
									
								
								go.sum
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
github.com/Arceliar/ironwood v0.0.0-20220924160422-ed4b6d4750b6 h1:iwL6nm2ibyuHXYimRNtFof7RJfe8JB+6CPDskV7K7gA=
 | 
			
		||||
github.com/Arceliar/ironwood v0.0.0-20220924160422-ed4b6d4750b6/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk=
 | 
			
		||||
github.com/Arceliar/ironwood v0.0.0-20221025225125-45b4281814c2 h1:Usab30pNT2i/vZvpXcN9uOr5IO1RZPcUqoGH0DIAPnU=
 | 
			
		||||
github.com/Arceliar/ironwood v0.0.0-20221025225125-45b4281814c2/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk=
 | 
			
		||||
github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979 h1:WndgpSW13S32VLQ3ugUxx2EnnWmgba1kCqPkd4Gk1yQ=
 | 
			
		||||
github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979/go.mod h1:6Lkn+/zJilRMsKmbmG1RPoamiArC6HS73xbwRyp3UyI=
 | 
			
		||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 | 
			
		||||
| 
						 | 
				
			
			@ -17,8 +17,8 @@ github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwM
 | 
			
		|||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
 | 
			
		||||
github.com/hjson/hjson-go v3.1.0+incompatible h1:DY/9yE8ey8Zv22bY+mHV1uk2yRy0h8tKhZ77hEdi0Aw=
 | 
			
		||||
github.com/hjson/hjson-go v3.1.0+incompatible/go.mod h1:qsetwF8NlsTsOTwZTApNlTCerV+b2GjYRRcIk4JMFio=
 | 
			
		||||
github.com/kardianos/minwinsvc v1.0.0 h1:+JfAi8IBJna0jY2dJGZqi7o15z13JelFIklJCAENALA=
 | 
			
		||||
github.com/kardianos/minwinsvc v1.0.0/go.mod h1:Bgd0oc+D0Qo3bBytmNtyRKVlp85dAloLKhfxanPFFRc=
 | 
			
		||||
github.com/kardianos/minwinsvc v1.0.2 h1:JmZKFJQrmTGa/WiW+vkJXKmfzdjabuEW4Tirj5lLdR0=
 | 
			
		||||
github.com/kardianos/minwinsvc v1.0.2/go.mod h1:LUZNYhNmxujx2tR7FbdxqYJ9XDDoCd3MQcl1o//FWl4=
 | 
			
		||||
github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ=
 | 
			
		||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
 | 
			
		||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
 | 
			
		||||
| 
						 | 
				
			
			@ -48,14 +48,15 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
 | 
			
		|||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a h1:NmSIgad6KjE6VvHciPZuNRTKxGhlPfD6OA87W/PLkqg=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 | 
			
		||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
 | 
			
		||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 | 
			
		||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 | 
			
		||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
 | 
			
		||||
golang.org/x/mobile v0.0.0-20220722155234-aaac322e2105 h1:3vUV5x5+3LfQbgk7paCM6INOaJG9xXQbn79xoNkwfIk=
 | 
			
		||||
golang.org/x/mobile v0.0.0-20220722155234-aaac322e2105/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ=
 | 
			
		||||
golang.org/x/mobile v0.0.0-20221020085226-b36e6246172e h1:zSgtO19fpg781xknwqiQPmOHaASr6E7ZVlTseLd9Fx4=
 | 
			
		||||
golang.org/x/mobile v0.0.0-20221020085226-b36e6246172e/go.mod h1:aAjjkJNdrh3PMckS4B10TGS2nag27cbKR1y2BpUxsiY=
 | 
			
		||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
 | 
			
		||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 | 
			
		||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
 | 
			
		||||
| 
						 | 
				
			
			@ -67,18 +68,20 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
 | 
			
		|||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 | 
			
		||||
golang.org/x/net v0.0.0-20210927181540-4e4d966f7476/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 | 
			
		||||
golang.org/x/net v0.0.0-20211011170408-caeb26a5c8c0/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 | 
			
		||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
 | 
			
		||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 | 
			
		||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 | 
			
		||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b h1:tvrvnPFcdzp294diPnrdZZZ8XUt2Tyj7svb7X52iDuU=
 | 
			
		||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
 | 
			
		||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
			
		||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
			
		||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
			
		||||
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
| 
						 | 
				
			
			@ -88,21 +91,23 @@ golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBc
 | 
			
		|||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
 | 
			
		||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 h1:OK7RB6t2WQX54srQQYSXMW8dF5C6/8+oA/s5QBmmto4=
 | 
			
		||||
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
			
		||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 | 
			
		||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
			
		||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
			
		||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
			
		||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 | 
			
		||||
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b h1:NXqSWXSRUSCaFuvitrWtU169I3876zRTalMRbfd6LL0=
 | 
			
		||||
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
 | 
			
		||||
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
 | 
			
		||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
 | 
			
		||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 | 
			
		||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 | 
			
		||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 | 
			
		||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
 | 
			
		||||
golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
 | 
			
		||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
 | 
			
		||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 | 
			
		||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -327,6 +327,7 @@ func (a *AdminSocket) handleRequest(conn net.Conn) {
 | 
			
		|||
		var buf json.RawMessage
 | 
			
		||||
		var req AdminSocketRequest
 | 
			
		||||
		var resp AdminSocketResponse
 | 
			
		||||
		req.Arguments = []byte("{}")
 | 
			
		||||
		if err := func() error {
 | 
			
		||||
			if err = decoder.Decode(&buf); err != nil {
 | 
			
		||||
				return fmt.Errorf("Failed to find request")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@ type PeerEntry struct {
 | 
			
		|||
	IPAddress string   `json:"address"`
 | 
			
		||||
	PublicKey string   `json:"key"`
 | 
			
		||||
	Port      uint64   `json:"port"`
 | 
			
		||||
	Priority  uint64   `json:"priority"`
 | 
			
		||||
	Coords    []uint64 `json:"coords"`
 | 
			
		||||
	Remote    string   `json:"remote"`
 | 
			
		||||
	RXBytes   DataUnit `json:"bytes_recvd"`
 | 
			
		||||
| 
						 | 
				
			
			@ -35,6 +36,7 @@ func (a *AdminSocket) getPeersHandler(req *GetPeersRequest, res *GetPeersRespons
 | 
			
		|||
			IPAddress: net.IP(addr[:]).String(),
 | 
			
		||||
			PublicKey: hex.EncodeToString(p.Key),
 | 
			
		||||
			Port:      p.Port,
 | 
			
		||||
			Priority:  uint64(p.Priority), // can't be uint8 thanks to gobind
 | 
			
		||||
			Coords:    p.Coords,
 | 
			
		||||
			Remote:    p.Remote,
 | 
			
		||||
			RXBytes:   DataUnit(p.RXBytes),
 | 
			
		||||
| 
						 | 
				
			
			@ -43,6 +45,9 @@ func (a *AdminSocket) getPeersHandler(req *GetPeersRequest, res *GetPeersRespons
 | 
			
		|||
		})
 | 
			
		||||
	}
 | 
			
		||||
	sort.Slice(res.Peers, func(i, j int) bool {
 | 
			
		||||
		if res.Peers[i].Port == res.Peers[j].Port {
 | 
			
		||||
			return res.Peers[i].Priority < res.Peers[j].Priority
 | 
			
		||||
		}
 | 
			
		||||
		return res.Peers[i].Port < res.Peers[j].Port
 | 
			
		||||
	})
 | 
			
		||||
	return nil
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,10 +40,11 @@ type NodeConfig struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
type MulticastInterfaceConfig struct {
 | 
			
		||||
	Regex  string
 | 
			
		||||
	Beacon bool
 | 
			
		||||
	Listen bool
 | 
			
		||||
	Port   uint16
 | 
			
		||||
	Regex    string
 | 
			
		||||
	Beacon   bool
 | 
			
		||||
	Listen   bool
 | 
			
		||||
	Port     uint16
 | 
			
		||||
	Priority uint64 // really uint8, but gobind won't export it
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewSigningKeys replaces the signing keypair in the NodeConfig with a new
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,14 +20,15 @@ type SelfInfo struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
type PeerInfo struct {
 | 
			
		||||
	Key     ed25519.PublicKey
 | 
			
		||||
	Root    ed25519.PublicKey
 | 
			
		||||
	Coords  []uint64
 | 
			
		||||
	Port    uint64
 | 
			
		||||
	Remote  string
 | 
			
		||||
	RXBytes uint64
 | 
			
		||||
	TXBytes uint64
 | 
			
		||||
	Uptime  time.Duration
 | 
			
		||||
	Key      ed25519.PublicKey
 | 
			
		||||
	Root     ed25519.PublicKey
 | 
			
		||||
	Coords   []uint64
 | 
			
		||||
	Port     uint64
 | 
			
		||||
	Priority uint8
 | 
			
		||||
	Remote   string
 | 
			
		||||
	RXBytes  uint64
 | 
			
		||||
	TXBytes  uint64
 | 
			
		||||
	Uptime   time.Duration
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DHTEntryInfo struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -62,6 +63,9 @@ func (c *Core) GetPeers() []PeerInfo {
 | 
			
		|||
	names := make(map[net.Conn]string)
 | 
			
		||||
	phony.Block(&c.links, func() {
 | 
			
		||||
		for _, info := range c.links._links {
 | 
			
		||||
			if info == nil {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			names[info.conn] = info.lname
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
| 
						 | 
				
			
			@ -72,6 +76,7 @@ func (c *Core) GetPeers() []PeerInfo {
 | 
			
		|||
		info.Root = p.Root
 | 
			
		||||
		info.Coords = p.Coords
 | 
			
		||||
		info.Port = p.Port
 | 
			
		||||
		info.Priority = p.Priority
 | 
			
		||||
		info.Remote = p.Conn.RemoteAddr().String()
 | 
			
		||||
		if name := names[p.Conn]; name != "" {
 | 
			
		||||
			info.Remote = name
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,7 @@ import (
 | 
			
		|||
	"io"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync/atomic"
 | 
			
		||||
	"time"
 | 
			
		||||
| 
						 | 
				
			
			@ -45,6 +46,7 @@ type link struct {
 | 
			
		|||
 | 
			
		||||
type linkOptions struct {
 | 
			
		||||
	pinnedEd25519Keys map[keyArray]struct{}
 | 
			
		||||
	priority          uint8
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Listener struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -120,17 +122,24 @@ func (l *links) call(u *url.URL, sintf string) (linkInfo, error) {
 | 
			
		|||
		copy(sigPubKey[:], sigPub)
 | 
			
		||||
		options.pinnedEd25519Keys[sigPubKey] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
	if p := u.Query().Get("priority"); p != "" {
 | 
			
		||||
		pi, err := strconv.ParseUint(p, 10, 8)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return info, fmt.Errorf("priority invalid: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
		options.priority = uint8(pi)
 | 
			
		||||
	}
 | 
			
		||||
	switch info.linkType {
 | 
			
		||||
	case "tcp":
 | 
			
		||||
		go func() {
 | 
			
		||||
			if err := l.tcp.dial(u, options, sintf); err != nil {
 | 
			
		||||
			if err := l.tcp.dial(u, options, sintf); err != nil && err != io.EOF {
 | 
			
		||||
				l.core.log.Warnf("Failed to dial TCP %s: %s\n", u.Host, err)
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
 | 
			
		||||
	case "socks":
 | 
			
		||||
		go func() {
 | 
			
		||||
			if err := l.socks.dial(u, options); err != nil {
 | 
			
		||||
			if err := l.socks.dial(u, options); err != nil && err != io.EOF {
 | 
			
		||||
				l.core.log.Warnf("Failed to dial SOCKS %s: %s\n", u.Host, err)
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
| 
						 | 
				
			
			@ -154,14 +163,14 @@ func (l *links) call(u *url.URL, sintf string) (linkInfo, error) {
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
		go func() {
 | 
			
		||||
			if err := l.tls.dial(u, options, sintf, tlsSNI); err != nil {
 | 
			
		||||
			if err := l.tls.dial(u, options, sintf, tlsSNI); err != nil && err != io.EOF {
 | 
			
		||||
				l.core.log.Warnf("Failed to dial TLS %s: %s\n", u.Host, err)
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
 | 
			
		||||
	case "unix":
 | 
			
		||||
		go func() {
 | 
			
		||||
			if err := l.unix.dial(u, options, sintf); err != nil {
 | 
			
		||||
			if err := l.unix.dial(u, options, sintf); err != nil && err != io.EOF {
 | 
			
		||||
				l.core.log.Warnf("Failed to dial UNIX %s: %s\n", u.Host, err)
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
| 
						 | 
				
			
			@ -272,8 +281,7 @@ func (intf *link) handler() error {
 | 
			
		|||
		var key keyArray
 | 
			
		||||
		copy(key[:], meta.key)
 | 
			
		||||
		if _, allowed := pinned[key]; !allowed {
 | 
			
		||||
			intf.links.core.log.Errorf("Failed to connect to node: %q sent ed25519 key that does not match pinned keys", intf.name())
 | 
			
		||||
			return fmt.Errorf("failed to connect: host sent ed25519 key that does not match pinned keys")
 | 
			
		||||
			return fmt.Errorf("node public key that does not match pinned keys")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// Check if we're authorized to connect to this key / IP
 | 
			
		||||
| 
						 | 
				
			
			@ -286,31 +294,33 @@ func (intf *link) handler() error {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if intf.incoming && !intf.force && !isallowed {
 | 
			
		||||
		intf.links.core.log.Warnf("%s connection from %s forbidden: AllowedEncryptionPublicKeys does not contain key %s",
 | 
			
		||||
			strings.ToUpper(intf.info.linkType), intf.info.remote, hex.EncodeToString(meta.key))
 | 
			
		||||
		_ = intf.close()
 | 
			
		||||
		return fmt.Errorf("forbidden connection")
 | 
			
		||||
		return fmt.Errorf("node public key %q is not in AllowedPublicKeys", hex.EncodeToString(meta.key))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	phony.Block(intf.links, func() {
 | 
			
		||||
		intf.links._links[intf.info] = intf
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	dir := "outbound"
 | 
			
		||||
	if intf.incoming {
 | 
			
		||||
		dir = "inbound"
 | 
			
		||||
	}
 | 
			
		||||
	remoteAddr := net.IP(address.AddrForKey(meta.key)[:]).String()
 | 
			
		||||
	remoteStr := fmt.Sprintf("%s@%s", remoteAddr, intf.info.remote)
 | 
			
		||||
	localStr := intf.conn.LocalAddr()
 | 
			
		||||
	intf.links.core.log.Infof("Connected %s: %s, source %s",
 | 
			
		||||
		strings.ToUpper(intf.info.linkType), remoteStr, localStr)
 | 
			
		||||
	intf.links.core.log.Infof("Connected %s %s: %s, source %s",
 | 
			
		||||
		dir, strings.ToUpper(intf.info.linkType), remoteStr, localStr)
 | 
			
		||||
 | 
			
		||||
	// TODO don't report an error if it's just a 'use of closed network connection'
 | 
			
		||||
	if err = intf.links.core.HandleConn(meta.key, intf.conn); err != nil && err != io.EOF {
 | 
			
		||||
		intf.links.core.log.Infof("Disconnected %s: %s, source %s; error: %s",
 | 
			
		||||
			strings.ToUpper(intf.info.linkType), remoteStr, localStr, err)
 | 
			
		||||
	} else {
 | 
			
		||||
		intf.links.core.log.Infof("Disconnected %s: %s, source %s",
 | 
			
		||||
			strings.ToUpper(intf.info.linkType), remoteStr, localStr)
 | 
			
		||||
	err = intf.links.core.HandleConn(meta.key, intf.conn, intf.options.priority)
 | 
			
		||||
	switch err {
 | 
			
		||||
	case io.EOF, net.ErrClosed, nil:
 | 
			
		||||
		intf.links.core.log.Infof("Disconnected %s %s: %s, source %s",
 | 
			
		||||
			dir, strings.ToUpper(intf.info.linkType), remoteStr, localStr)
 | 
			
		||||
	default:
 | 
			
		||||
		intf.links.core.log.Infof("Disconnected %s %s: %s, source %s; error: %s",
 | 
			
		||||
			dir, strings.ToUpper(intf.info.linkType), remoteStr, localStr, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -318,14 +328,7 @@ func (intf *link) close() error {
 | 
			
		|||
	return intf.conn.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (intf *link) name() string {
 | 
			
		||||
	return intf.lname
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func linkInfoFor(linkType, sintf, remote string) linkInfo {
 | 
			
		||||
	if h, _, err := net.SplitHostPort(remote); err == nil {
 | 
			
		||||
		remote = h
 | 
			
		||||
	}
 | 
			
		||||
	return linkInfo{
 | 
			
		||||
		linkType: linkType,
 | 
			
		||||
		local:    sintf,
 | 
			
		||||
| 
						 | 
				
			
			@ -353,3 +356,12 @@ func (c *linkConn) Write(p []byte) (n int, err error) {
 | 
			
		|||
	atomic.AddUint64(&c.tx, uint64(n))
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func linkOptionsForListener(u *url.URL) (l linkOptions) {
 | 
			
		||||
	if p := u.Query().Get("priority"); p != "" {
 | 
			
		||||
		if pi, err := strconv.ParseUint(p, 10, 8); err == nil {
 | 
			
		||||
			l.priority = uint8(pi)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ func (l *links) newLinkSOCKS() *linkSOCKS {
 | 
			
		|||
func (l *linkSOCKS) dial(url *url.URL, options linkOptions) error {
 | 
			
		||||
	info := linkInfoFor("socks", "", url.Path)
 | 
			
		||||
	if l.links.isConnectedTo(info) {
 | 
			
		||||
		return fmt.Errorf("duplicate connection attempt")
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	proxyAuth := &proxy.Auth{}
 | 
			
		||||
	proxyAuth.User = url.User.Username()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,24 +31,24 @@ func (l *links) newLinkTCP() *linkTCP {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func (l *linkTCP) dial(url *url.URL, options linkOptions, sintf string) error {
 | 
			
		||||
	info := linkInfoFor("tcp", sintf, strings.SplitN(url.Host, "%", 2)[0])
 | 
			
		||||
	if l.links.isConnectedTo(info) {
 | 
			
		||||
		return fmt.Errorf("duplicate connection attempt")
 | 
			
		||||
	}
 | 
			
		||||
	addr, err := net.ResolveTCPAddr("tcp", url.Host)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	addr.Zone = sintf
 | 
			
		||||
	dialer, err := l.dialerFor(addr.String(), sintf)
 | 
			
		||||
	dialer, err := l.dialerFor(addr, sintf)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	info := linkInfoFor("tcp", sintf, tcpIDFor(dialer.LocalAddr, addr))
 | 
			
		||||
	if l.links.isConnectedTo(info) {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	conn, err := dialer.DialContext(l.core.ctx, "tcp", addr.String())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return l.handler(url.String(), info, conn, options, false)
 | 
			
		||||
	uri := strings.TrimRight(strings.SplitN(url.String(), "?", 2)[0], "/")
 | 
			
		||||
	return l.handler(uri, info, conn, options, false, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *linkTCP) listen(url *url.URL, sintf string) (*Listener, error) {
 | 
			
		||||
| 
						 | 
				
			
			@ -82,10 +82,11 @@ func (l *linkTCP) listen(url *url.URL, sintf string) (*Listener, error) {
 | 
			
		|||
				cancel()
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			addr := conn.RemoteAddr().(*net.TCPAddr)
 | 
			
		||||
			name := fmt.Sprintf("tls://%s", addr)
 | 
			
		||||
			info := linkInfoFor("tcp", sintf, strings.SplitN(addr.IP.String(), "%", 2)[0])
 | 
			
		||||
			if err = l.handler(name, info, conn, linkOptions{}, true); err != nil {
 | 
			
		||||
			laddr := conn.LocalAddr().(*net.TCPAddr)
 | 
			
		||||
			raddr := conn.RemoteAddr().(*net.TCPAddr)
 | 
			
		||||
			name := fmt.Sprintf("tcp://%s", raddr)
 | 
			
		||||
			info := linkInfoFor("tcp", sintf, tcpIDFor(laddr, raddr))
 | 
			
		||||
			if err = l.handler(name, info, conn, linkOptionsForListener(url), true, raddr.IP.IsLinkLocalUnicast()); err != nil {
 | 
			
		||||
				l.core.log.Errorln("Failed to create inbound link:", err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -96,13 +97,13 @@ func (l *linkTCP) listen(url *url.URL, sintf string) (*Listener, error) {
 | 
			
		|||
	return entry, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *linkTCP) handler(name string, info linkInfo, conn net.Conn, options linkOptions, incoming bool) error {
 | 
			
		||||
func (l *linkTCP) handler(name string, info linkInfo, conn net.Conn, options linkOptions, incoming, force bool) error {
 | 
			
		||||
	return l.links.create(
 | 
			
		||||
		conn,     // connection
 | 
			
		||||
		name,     // connection name
 | 
			
		||||
		info,     // connection info
 | 
			
		||||
		incoming, // not incoming
 | 
			
		||||
		false,    // not forced
 | 
			
		||||
		force,    // not forced
 | 
			
		||||
		options,  // connection options
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -121,13 +122,11 @@ func (l *linkTCP) getAddr() *net.TCPAddr {
 | 
			
		|||
	return addr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *linkTCP) dialerFor(saddr, sintf string) (*net.Dialer, error) {
 | 
			
		||||
	dst, err := net.ResolveTCPAddr("tcp", saddr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
func (l *linkTCP) dialerFor(dst *net.TCPAddr, sintf string) (*net.Dialer, error) {
 | 
			
		||||
	if dst.IP.IsLinkLocalUnicast() {
 | 
			
		||||
		dst.Zone = sintf
 | 
			
		||||
		if sintf != "" {
 | 
			
		||||
			dst.Zone = sintf
 | 
			
		||||
		}
 | 
			
		||||
		if dst.Zone == "" {
 | 
			
		||||
			return nil, fmt.Errorf("link-local address requires a zone")
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -181,3 +180,16 @@ func (l *linkTCP) dialerFor(saddr, sintf string) (*net.Dialer, error) {
 | 
			
		|||
	}
 | 
			
		||||
	return dialer, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func tcpIDFor(local net.Addr, remoteAddr *net.TCPAddr) string {
 | 
			
		||||
	if localAddr, ok := local.(*net.TCPAddr); ok && localAddr.IP.Equal(remoteAddr.IP) {
 | 
			
		||||
		// Nodes running on the same host — include both the IP and port.
 | 
			
		||||
		return remoteAddr.String()
 | 
			
		||||
	}
 | 
			
		||||
	if remoteAddr.IP.IsLinkLocalUnicast() {
 | 
			
		||||
		// Nodes discovered via multicast — include the IP only.
 | 
			
		||||
		return remoteAddr.IP.String()
 | 
			
		||||
	}
 | 
			
		||||
	// Nodes connected remotely — include both the IP and port.
 | 
			
		||||
	return remoteAddr.String()
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,19 +47,18 @@ func (l *links) newLinkTLS(tcp *linkTCP) *linkTLS {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func (l *linkTLS) dial(url *url.URL, options linkOptions, sintf, sni string) error {
 | 
			
		||||
	info := linkInfoFor("tls", sintf, strings.SplitN(url.Host, "%", 2)[0])
 | 
			
		||||
	if l.links.isConnectedTo(info) {
 | 
			
		||||
		return fmt.Errorf("duplicate connection attempt")
 | 
			
		||||
	}
 | 
			
		||||
	addr, err := net.ResolveTCPAddr("tcp", url.Host)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	addr.Zone = sintf
 | 
			
		||||
	dialer, err := l.tcp.dialerFor(addr.String(), sintf)
 | 
			
		||||
	dialer, err := l.tcp.dialerFor(addr, sintf)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	info := linkInfoFor("tls", sintf, tcpIDFor(dialer.LocalAddr, addr))
 | 
			
		||||
	if l.links.isConnectedTo(info) {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	tlsconfig := l.config.Clone()
 | 
			
		||||
	tlsconfig.ServerName = sni
 | 
			
		||||
	tlsdialer := &tls.Dialer{
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +69,8 @@ func (l *linkTLS) dial(url *url.URL, options linkOptions, sintf, sni string) err
 | 
			
		|||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return l.handler(url.String(), info, conn, options, false)
 | 
			
		||||
	uri := strings.TrimRight(strings.SplitN(url.String(), "?", 2)[0], "/")
 | 
			
		||||
	return l.handler(uri, info, conn, options, false, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *linkTLS) listen(url *url.URL, sintf string) (*Listener, error) {
 | 
			
		||||
| 
						 | 
				
			
			@ -105,10 +105,11 @@ func (l *linkTLS) listen(url *url.URL, sintf string) (*Listener, error) {
 | 
			
		|||
				cancel()
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			addr := conn.RemoteAddr().(*net.TCPAddr)
 | 
			
		||||
			name := fmt.Sprintf("tls://%s", addr)
 | 
			
		||||
			info := linkInfoFor("tls", sintf, strings.SplitN(addr.IP.String(), "%", 2)[0])
 | 
			
		||||
			if err = l.handler(name, info, conn, linkOptions{}, true); err != nil {
 | 
			
		||||
			laddr := conn.LocalAddr().(*net.TCPAddr)
 | 
			
		||||
			raddr := conn.RemoteAddr().(*net.TCPAddr)
 | 
			
		||||
			name := fmt.Sprintf("tls://%s", raddr)
 | 
			
		||||
			info := linkInfoFor("tls", sintf, tcpIDFor(laddr, raddr))
 | 
			
		||||
			if err = l.handler(name, info, conn, linkOptionsForListener(url), true, raddr.IP.IsLinkLocalUnicast()); err != nil {
 | 
			
		||||
				l.core.log.Errorln("Failed to create inbound link:", err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -119,20 +120,18 @@ func (l *linkTLS) listen(url *url.URL, sintf string) (*Listener, error) {
 | 
			
		|||
	return entry, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RFC5280 section 4.1.2.5
 | 
			
		||||
var notAfterNeverExpires = time.Date(9999, time.December, 31, 23, 59, 59, 0, time.UTC)
 | 
			
		||||
 | 
			
		||||
func (l *linkTLS) generateConfig() (*tls.Config, error) {
 | 
			
		||||
	certBuf := &bytes.Buffer{}
 | 
			
		||||
 | 
			
		||||
	// TODO: because NotAfter is finite, we should add some mechanism to
 | 
			
		||||
	// regenerate the certificate and restart the listeners periodically
 | 
			
		||||
	// for nodes with very high uptimes. Perhaps regenerate certs and restart
 | 
			
		||||
	// listeners every few months or so.
 | 
			
		||||
	cert := x509.Certificate{
 | 
			
		||||
		SerialNumber: big.NewInt(1),
 | 
			
		||||
		Subject: pkix.Name{
 | 
			
		||||
			CommonName: hex.EncodeToString(l.links.core.public[:]),
 | 
			
		||||
		},
 | 
			
		||||
		NotBefore:             time.Now(),
 | 
			
		||||
		NotAfter:              time.Now().Add(time.Hour * 24 * 365),
 | 
			
		||||
		NotAfter:              notAfterNeverExpires,
 | 
			
		||||
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
 | 
			
		||||
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
 | 
			
		||||
		BasicConstraintsValid: true,
 | 
			
		||||
| 
						 | 
				
			
			@ -166,6 +165,6 @@ func (l *linkTLS) generateConfig() (*tls.Config, error) {
 | 
			
		|||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *linkTLS) handler(name string, info linkInfo, conn net.Conn, options linkOptions, incoming bool) error {
 | 
			
		||||
	return l.tcp.handler(name, info, conn, options, incoming)
 | 
			
		||||
func (l *linkTLS) handler(name string, info linkInfo, conn net.Conn, options linkOptions, incoming, force bool) error {
 | 
			
		||||
	return l.tcp.handler(name, info, conn, options, incoming, force)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ package core
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"time"
 | 
			
		||||
| 
						 | 
				
			
			@ -36,7 +35,7 @@ func (l *links) newLinkUNIX() *linkUNIX {
 | 
			
		|||
func (l *linkUNIX) dial(url *url.URL, options linkOptions, _ string) error {
 | 
			
		||||
	info := linkInfoFor("unix", "", url.Path)
 | 
			
		||||
	if l.links.isConnectedTo(info) {
 | 
			
		||||
		return fmt.Errorf("duplicate connection attempt")
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	addr, err := net.ResolveUnixAddr("unix", url.Path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +74,7 @@ func (l *linkUNIX) listen(url *url.URL, _ string) (*Listener, error) {
 | 
			
		|||
				break
 | 
			
		||||
			}
 | 
			
		||||
			info := linkInfoFor("unix", "", url.String())
 | 
			
		||||
			if err = l.handler(url.String(), info, conn, linkOptions{}, true); err != nil {
 | 
			
		||||
			if err = l.handler(url.String(), info, conn, linkOptionsForListener(url), true); err != nil {
 | 
			
		||||
				l.core.log.Errorln("Failed to create inbound link:", err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,6 @@ import (
 | 
			
		|||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	iwt "github.com/Arceliar/ironwood/types"
 | 
			
		||||
| 
						 | 
				
			
			@ -14,18 +13,15 @@ import (
 | 
			
		|||
	"github.com/yggdrasil-network/yggdrasil-go/src/version"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NodeInfoPayload represents a RequestNodeInfo response, in bytes.
 | 
			
		||||
type NodeInfoPayload []byte
 | 
			
		||||
 | 
			
		||||
type nodeinfo struct {
 | 
			
		||||
	phony.Inbox
 | 
			
		||||
	proto      *protoHandler
 | 
			
		||||
	myNodeInfo NodeInfoPayload
 | 
			
		||||
	myNodeInfo json.RawMessage
 | 
			
		||||
	callbacks  map[keyArray]nodeinfoCallback
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type nodeinfoCallback struct {
 | 
			
		||||
	call    func(nodeinfo NodeInfoPayload)
 | 
			
		||||
	call    func(nodeinfo json.RawMessage)
 | 
			
		||||
	created time.Time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -54,7 +50,7 @@ func (m *nodeinfo) _cleanup() {
 | 
			
		|||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *nodeinfo) _addCallback(sender keyArray, call func(nodeinfo NodeInfoPayload)) {
 | 
			
		||||
func (m *nodeinfo) _addCallback(sender keyArray, call func(nodeinfo json.RawMessage)) {
 | 
			
		||||
	m.callbacks[sender] = nodeinfoCallback{
 | 
			
		||||
		created: time.Now(),
 | 
			
		||||
		call:    call,
 | 
			
		||||
| 
						 | 
				
			
			@ -62,67 +58,55 @@ func (m *nodeinfo) _addCallback(sender keyArray, call func(nodeinfo NodeInfoPayl
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// Handles the callback, if there is one
 | 
			
		||||
func (m *nodeinfo) _callback(sender keyArray, nodeinfo NodeInfoPayload) {
 | 
			
		||||
func (m *nodeinfo) _callback(sender keyArray, nodeinfo json.RawMessage) {
 | 
			
		||||
	if callback, ok := m.callbacks[sender]; ok {
 | 
			
		||||
		callback.call(nodeinfo)
 | 
			
		||||
		delete(m.callbacks, sender)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *nodeinfo) _getNodeInfo() NodeInfoPayload {
 | 
			
		||||
func (m *nodeinfo) _getNodeInfo() json.RawMessage {
 | 
			
		||||
	return m.myNodeInfo
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set the current node's nodeinfo
 | 
			
		||||
func (m *nodeinfo) setNodeInfo(given interface{}, privacy bool) (err error) {
 | 
			
		||||
func (m *nodeinfo) setNodeInfo(given map[string]interface{}, privacy bool) (err error) {
 | 
			
		||||
	phony.Block(m, func() {
 | 
			
		||||
		err = m._setNodeInfo(given, privacy)
 | 
			
		||||
	})
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *nodeinfo) _setNodeInfo(given interface{}, privacy bool) error {
 | 
			
		||||
	defaults := map[string]interface{}{
 | 
			
		||||
		"buildname":     version.BuildName(),
 | 
			
		||||
		"buildversion":  version.BuildVersion(),
 | 
			
		||||
		"buildplatform": runtime.GOOS,
 | 
			
		||||
		"buildarch":     runtime.GOARCH,
 | 
			
		||||
func (m *nodeinfo) _setNodeInfo(given map[string]interface{}, privacy bool) error {
 | 
			
		||||
	newnodeinfo := make(map[string]interface{}, len(given))
 | 
			
		||||
	for k, v := range given {
 | 
			
		||||
		newnodeinfo[k] = v
 | 
			
		||||
	}
 | 
			
		||||
	newnodeinfo := make(map[string]interface{})
 | 
			
		||||
	if !privacy {
 | 
			
		||||
		for k, v := range defaults {
 | 
			
		||||
			newnodeinfo[k] = v
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if nodeinfomap, ok := given.(map[string]interface{}); ok {
 | 
			
		||||
		for key, value := range nodeinfomap {
 | 
			
		||||
			if _, ok := defaults[key]; ok {
 | 
			
		||||
				if strvalue, strok := value.(string); strok && strings.EqualFold(strvalue, "null") || value == nil {
 | 
			
		||||
					delete(newnodeinfo, key)
 | 
			
		||||
				}
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			newnodeinfo[key] = value
 | 
			
		||||
		}
 | 
			
		||||
		newnodeinfo["buildname"] = version.BuildName()
 | 
			
		||||
		newnodeinfo["buildversion"] = version.BuildVersion()
 | 
			
		||||
		newnodeinfo["buildplatform"] = runtime.GOOS
 | 
			
		||||
		newnodeinfo["buildarch"] = runtime.GOARCH
 | 
			
		||||
	}
 | 
			
		||||
	newjson, err := json.Marshal(newnodeinfo)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		if len(newjson) > 16384 {
 | 
			
		||||
			return errors.New("NodeInfo exceeds max length of 16384 bytes")
 | 
			
		||||
		}
 | 
			
		||||
	switch {
 | 
			
		||||
	case err != nil:
 | 
			
		||||
		return fmt.Errorf("NodeInfo marshalling failed: %w", err)
 | 
			
		||||
	case len(newjson) > 16384:
 | 
			
		||||
		return fmt.Errorf("NodeInfo exceeds max length of 16384 bytes")
 | 
			
		||||
	default:
 | 
			
		||||
		m.myNodeInfo = newjson
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *nodeinfo) sendReq(from phony.Actor, key keyArray, callback func(nodeinfo NodeInfoPayload)) {
 | 
			
		||||
func (m *nodeinfo) sendReq(from phony.Actor, key keyArray, callback func(nodeinfo json.RawMessage)) {
 | 
			
		||||
	m.Act(from, func() {
 | 
			
		||||
		m._sendReq(key, callback)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *nodeinfo) _sendReq(key keyArray, callback func(nodeinfo NodeInfoPayload)) {
 | 
			
		||||
func (m *nodeinfo) _sendReq(key keyArray, callback func(nodeinfo json.RawMessage)) {
 | 
			
		||||
	if callback != nil {
 | 
			
		||||
		m._addCallback(key, callback)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -135,7 +119,7 @@ func (m *nodeinfo) handleReq(from phony.Actor, key keyArray) {
 | 
			
		|||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *nodeinfo) handleRes(from phony.Actor, key keyArray, info NodeInfoPayload) {
 | 
			
		||||
func (m *nodeinfo) handleRes(from phony.Actor, key keyArray, info json.RawMessage) {
 | 
			
		||||
	m.Act(from, func() {
 | 
			
		||||
		m._callback(key, info)
 | 
			
		||||
	})
 | 
			
		||||
| 
						 | 
				
			
			@ -169,7 +153,7 @@ func (m *nodeinfo) nodeInfoAdminHandler(in json.RawMessage) (interface{}, error)
 | 
			
		|||
	}
 | 
			
		||||
	copy(key[:], kbs)
 | 
			
		||||
	ch := make(chan []byte, 1)
 | 
			
		||||
	m.sendReq(nil, key, func(info NodeInfoPayload) {
 | 
			
		||||
	m.sendReq(nil, key, func(info json.RawMessage) {
 | 
			
		||||
		ch <- info
 | 
			
		||||
	})
 | 
			
		||||
	timer := time.NewTimer(6 * time.Second)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,11 +37,12 @@ type Multicast struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
type interfaceInfo struct {
 | 
			
		||||
	iface  net.Interface
 | 
			
		||||
	addrs  []net.Addr
 | 
			
		||||
	beacon bool
 | 
			
		||||
	listen bool
 | 
			
		||||
	port   uint16
 | 
			
		||||
	iface    net.Interface
 | 
			
		||||
	addrs    []net.Addr
 | 
			
		||||
	beacon   bool
 | 
			
		||||
	listen   bool
 | 
			
		||||
	port     uint16
 | 
			
		||||
	priority uint8
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type listenerInfo struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -77,7 +78,11 @@ func (m *Multicast) _start() error {
 | 
			
		|||
	if m._isOpen {
 | 
			
		||||
		return fmt.Errorf("multicast module is already started")
 | 
			
		||||
	}
 | 
			
		||||
	if len(m.config._interfaces) == 0 {
 | 
			
		||||
	var anyEnabled bool
 | 
			
		||||
	for intf := range m.config._interfaces {
 | 
			
		||||
		anyEnabled = anyEnabled || intf.Beacon || intf.Listen
 | 
			
		||||
	}
 | 
			
		||||
	if !anyEnabled {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	m.log.Debugln("Starting multicast module")
 | 
			
		||||
| 
						 | 
				
			
			@ -190,10 +195,11 @@ func (m *Multicast) _getAllowedInterfaces() map[string]*interfaceInfo {
 | 
			
		|||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			interfaces[iface.Name] = &interfaceInfo{
 | 
			
		||||
				iface:  iface,
 | 
			
		||||
				beacon: ifcfg.Beacon,
 | 
			
		||||
				listen: ifcfg.Listen,
 | 
			
		||||
				port:   ifcfg.Port,
 | 
			
		||||
				iface:    iface,
 | 
			
		||||
				beacon:   ifcfg.Beacon,
 | 
			
		||||
				listen:   ifcfg.Listen,
 | 
			
		||||
				port:     ifcfg.Port,
 | 
			
		||||
				priority: ifcfg.Priority,
 | 
			
		||||
			}
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -383,7 +389,7 @@ func (m *Multicast) listen() {
 | 
			
		|||
		})
 | 
			
		||||
		if info, ok := interfaces[from.Zone]; ok && info.listen {
 | 
			
		||||
			addr.Zone = ""
 | 
			
		||||
			pin := fmt.Sprintf("/?key=%s", hex.EncodeToString(key))
 | 
			
		||||
			pin := fmt.Sprintf("/?key=%s&priority=%d", hex.EncodeToString(key), info.priority)
 | 
			
		||||
			u, err := url.Parse("tls://" + addr.String() + pin)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				m.log.Debugln("Call from multicast failed, parse error:", addr.String(), err)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,15 +15,19 @@ func (m *Multicast) _multicastStarted() {
 | 
			
		|||
 | 
			
		||||
func (m *Multicast) multicastReuse(network string, address string, c syscall.RawConn) error {
 | 
			
		||||
	var control error
 | 
			
		||||
	var reuseport error
 | 
			
		||||
	var reuseaddr error
 | 
			
		||||
 | 
			
		||||
	control = c.Control(func(fd uintptr) {
 | 
			
		||||
		reuseport = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
 | 
			
		||||
		// Previously we used SO_REUSEPORT here, but that meant that machines running
 | 
			
		||||
		// Yggdrasil nodes as different users would inevitably fail with EADDRINUSE.
 | 
			
		||||
		// The behaviour for multicast is similar with both, so we'll use SO_REUSEADDR
 | 
			
		||||
		// instead.
 | 
			
		||||
		reuseaddr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	switch {
 | 
			
		||||
	case reuseport != nil:
 | 
			
		||||
		return reuseport
 | 
			
		||||
	case reuseaddr != nil:
 | 
			
		||||
		return reuseaddr
 | 
			
		||||
	default:
 | 
			
		||||
		return control
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,10 +16,11 @@ type SetupOption interface {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
type MulticastInterface struct {
 | 
			
		||||
	Regex  *regexp.Regexp
 | 
			
		||||
	Beacon bool
 | 
			
		||||
	Listen bool
 | 
			
		||||
	Port   uint16
 | 
			
		||||
	Regex    *regexp.Regexp
 | 
			
		||||
	Beacon   bool
 | 
			
		||||
	Listen   bool
 | 
			
		||||
	Port     uint16
 | 
			
		||||
	Priority uint8
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GroupAddress string
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue