mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 03:05:07 +03:00 
			
		
		
		
	Revise multicast format to include protocol version, discriminator for TLS roots
This commit is contained in:
		
							parent
							
								
									002b984c04
								
							
						
					
					
						commit
						57d9a2399f
					
				
					 5 changed files with 112 additions and 11 deletions
				
			
		| 
						 | 
					@ -3,6 +3,7 @@ package main
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"crypto/ed25519"
 | 
						"crypto/ed25519"
 | 
				
			||||||
 | 
						"crypto/sha1"
 | 
				
			||||||
	"encoding/hex"
 | 
						"encoding/hex"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"flag"
 | 
						"flag"
 | 
				
			||||||
| 
						 | 
					@ -195,6 +196,10 @@ func main() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	n := &node{}
 | 
						n := &node{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Track certificate fingerprints for configured roots, so
 | 
				
			||||||
 | 
						// that we can match them using the multicast discriminator.
 | 
				
			||||||
 | 
						fingerprints := map[[20]byte]struct{}{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Setup the Yggdrasil node itself.
 | 
						// Setup the Yggdrasil node itself.
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		options := []core.SetupOption{
 | 
							options := []core.SetupOption{
 | 
				
			||||||
| 
						 | 
					@ -214,6 +219,7 @@ func main() {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for _, root := range cfg.RootCertificates {
 | 
							for _, root := range cfg.RootCertificates {
 | 
				
			||||||
			options = append(options, core.RootCertificate(*root))
 | 
								options = append(options, core.RootCertificate(*root))
 | 
				
			||||||
 | 
								fingerprints[sha1.Sum(root.Raw[:])] = struct{}{}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for _, allowed := range cfg.AllowedPublicKeys {
 | 
							for _, allowed := range cfg.AllowedPublicKeys {
 | 
				
			||||||
			k, err := hex.DecodeString(allowed)
 | 
								k, err := hex.DecodeString(allowed)
 | 
				
			||||||
| 
						 | 
					@ -252,6 +258,29 @@ func main() {
 | 
				
			||||||
				Priority: uint8(intf.Priority),
 | 
									Priority: uint8(intf.Priority),
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if len(fingerprints) > 0 {
 | 
				
			||||||
 | 
								var matcher multicast.DiscriminatorMatch = func(b []byte) bool {
 | 
				
			||||||
 | 
									// Break apart the discriminator into 20-byte chunks and
 | 
				
			||||||
 | 
									// see whether any of them match the configured root CA
 | 
				
			||||||
 | 
									// fingerprints. If any of them match, we'll return true.
 | 
				
			||||||
 | 
									var f [20]byte
 | 
				
			||||||
 | 
									for len(b) >= len(f) {
 | 
				
			||||||
 | 
										b = b[copy(f[:], b):]
 | 
				
			||||||
 | 
										if _, ok := fingerprints[f]; ok {
 | 
				
			||||||
 | 
											return true
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									return false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// Populate our own discriminator with the fingerprints of our
 | 
				
			||||||
 | 
								// configured root CAs.
 | 
				
			||||||
 | 
								var discriminator multicast.Discriminator
 | 
				
			||||||
 | 
								for f := range fingerprints {
 | 
				
			||||||
 | 
									discriminator = append(discriminator, f[:]...)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								options = append(options, matcher)
 | 
				
			||||||
 | 
								options = append(options, discriminator)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if n.multicast, err = multicast.New(n.core, logger, options...); err != nil {
 | 
							if n.multicast, err = multicast.New(n.core, logger, options...); err != nil {
 | 
				
			||||||
			panic(err)
 | 
								panic(err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,22 +7,33 @@ import (
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type multicastAdvertisement struct {
 | 
					type multicastAdvertisement struct {
 | 
				
			||||||
	PublicKey ed25519.PublicKey
 | 
						MajorVersion  uint16
 | 
				
			||||||
	Port      uint16
 | 
						MinorVersion  uint16
 | 
				
			||||||
 | 
						PublicKey     ed25519.PublicKey
 | 
				
			||||||
 | 
						Port          uint16
 | 
				
			||||||
 | 
						Discriminator []byte
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *multicastAdvertisement) MarshalBinary() ([]byte, error) {
 | 
					func (m *multicastAdvertisement) MarshalBinary() ([]byte, error) {
 | 
				
			||||||
	b := make([]byte, 0, ed25519.PublicKeySize+2)
 | 
						b := make([]byte, 0, ed25519.PublicKeySize+8+len(m.Discriminator))
 | 
				
			||||||
 | 
						b = binary.BigEndian.AppendUint16(b, m.MajorVersion)
 | 
				
			||||||
 | 
						b = binary.BigEndian.AppendUint16(b, m.MinorVersion)
 | 
				
			||||||
	b = append(b, m.PublicKey...)
 | 
						b = append(b, m.PublicKey...)
 | 
				
			||||||
	b = binary.BigEndian.AppendUint16(b, m.Port)
 | 
						b = binary.BigEndian.AppendUint16(b, m.Port)
 | 
				
			||||||
 | 
						b = binary.BigEndian.AppendUint16(b, uint16(len(m.Discriminator)))
 | 
				
			||||||
 | 
						b = append(b, m.Discriminator...)
 | 
				
			||||||
	return b, nil
 | 
						return b, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *multicastAdvertisement) UnmarshalBinary(b []byte) error {
 | 
					func (m *multicastAdvertisement) UnmarshalBinary(b []byte) error {
 | 
				
			||||||
	if len(b) < ed25519.PublicKeySize+2 {
 | 
						if len(b) < ed25519.PublicKeySize+8 {
 | 
				
			||||||
		return fmt.Errorf("invalid multicast beacon")
 | 
							return fmt.Errorf("invalid multicast beacon")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	m.PublicKey = b[:ed25519.PublicKeySize]
 | 
						m.MajorVersion = binary.BigEndian.Uint16(b[0:2])
 | 
				
			||||||
	m.Port = binary.BigEndian.Uint16(b[ed25519.PublicKeySize:])
 | 
						m.MinorVersion = binary.BigEndian.Uint16(b[2:4])
 | 
				
			||||||
 | 
						m.PublicKey = append(m.PublicKey[:0], b[4:4+ed25519.PublicKeySize]...)
 | 
				
			||||||
 | 
						m.Port = binary.BigEndian.Uint16(b[4+ed25519.PublicKeySize : 6+ed25519.PublicKeySize])
 | 
				
			||||||
 | 
						dl := binary.BigEndian.Uint16(b[6+ed25519.PublicKeySize : 8+ed25519.PublicKeySize])
 | 
				
			||||||
 | 
						m.Discriminator = append(m.Discriminator[:0], b[8+ed25519.PublicKeySize:8+ed25519.PublicKeySize+dl]...)
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										38
									
								
								src/multicast/advertisement_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/multicast/advertisement_test.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,38 @@
 | 
				
			||||||
 | 
					package multicast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"crypto/ed25519"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestMulticastAdvertisementRoundTrip(t *testing.T) {
 | 
				
			||||||
 | 
						pk, sk, err := ed25519.GenerateKey(nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						orig := multicastAdvertisement{
 | 
				
			||||||
 | 
							MajorVersion:  1,
 | 
				
			||||||
 | 
							MinorVersion:  2,
 | 
				
			||||||
 | 
							PublicKey:     pk,
 | 
				
			||||||
 | 
							Port:          3,
 | 
				
			||||||
 | 
							Discriminator: sk, // any bytes will do
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ob, err := orig.MarshalBinary()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var new multicastAdvertisement
 | 
				
			||||||
 | 
						if err := new.UnmarshalBinary(ob); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !reflect.DeepEqual(orig, new) {
 | 
				
			||||||
 | 
							t.Logf("original: %+v", orig)
 | 
				
			||||||
 | 
							t.Logf("new:      %+v", new)
 | 
				
			||||||
 | 
							t.Fatalf("differences found after round-trip")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
package multicast
 | 
					package multicast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"encoding/hex"
 | 
						"encoding/hex"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
| 
						 | 
					@ -30,8 +31,10 @@ type Multicast struct {
 | 
				
			||||||
	_interfaces map[string]*interfaceInfo
 | 
						_interfaces map[string]*interfaceInfo
 | 
				
			||||||
	_timer      *time.Timer
 | 
						_timer      *time.Timer
 | 
				
			||||||
	config      struct {
 | 
						config      struct {
 | 
				
			||||||
		_groupAddr  GroupAddress
 | 
							_discriminator      []byte
 | 
				
			||||||
		_interfaces map[MulticastInterface]struct{}
 | 
							_discriminatorMatch func([]byte) bool
 | 
				
			||||||
 | 
							_groupAddr          GroupAddress
 | 
				
			||||||
 | 
							_interfaces         map[MulticastInterface]struct{}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -321,8 +324,11 @@ func (m *Multicast) _announce() {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			addr := linfo.listener.Addr().(*net.TCPAddr)
 | 
								addr := linfo.listener.Addr().(*net.TCPAddr)
 | 
				
			||||||
			adv := multicastAdvertisement{
 | 
								adv := multicastAdvertisement{
 | 
				
			||||||
				PublicKey: m.core.PublicKey(),
 | 
									MajorVersion:  core.ProtocolVersionMajor,
 | 
				
			||||||
				Port:      uint16(addr.Port),
 | 
									MinorVersion:  core.ProtocolVersionMinor,
 | 
				
			||||||
 | 
									PublicKey:     m.core.PublicKey(),
 | 
				
			||||||
 | 
									Port:          uint16(addr.Port),
 | 
				
			||||||
 | 
									Discriminator: m.config._discriminator,
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			msg, err := adv.MarshalBinary()
 | 
								msg, err := adv.MarshalBinary()
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
| 
						 | 
					@ -373,7 +379,16 @@ func (m *Multicast) listen() {
 | 
				
			||||||
		if err := adv.UnmarshalBinary(bs[:n]); err != nil {
 | 
							if err := adv.UnmarshalBinary(bs[:n]); err != nil {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if adv.PublicKey.Equal(m.core.PublicKey()) {
 | 
							switch {
 | 
				
			||||||
 | 
							case adv.MajorVersion != core.ProtocolVersionMajor:
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							case adv.MinorVersion != core.ProtocolVersionMinor:
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							case adv.PublicKey.Equal(m.core.PublicKey()):
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							case m.config._discriminatorMatch == nil && !bytes.Equal(adv.Discriminator, m.config._discriminator):
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							case m.config._discriminatorMatch != nil && !m.config._discriminatorMatch(adv.Discriminator):
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		from := fromAddr.(*net.UDPAddr)
 | 
							from := fromAddr.(*net.UDPAddr)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,10 @@ func (m *Multicast) _applyOption(opt SetupOption) {
 | 
				
			||||||
		m.config._interfaces[v] = struct{}{}
 | 
							m.config._interfaces[v] = struct{}{}
 | 
				
			||||||
	case GroupAddress:
 | 
						case GroupAddress:
 | 
				
			||||||
		m.config._groupAddr = v
 | 
							m.config._groupAddr = v
 | 
				
			||||||
 | 
						case Discriminator:
 | 
				
			||||||
 | 
							m.config._discriminator = append(m.config._discriminator[:0], v...)
 | 
				
			||||||
 | 
						case DiscriminatorMatch:
 | 
				
			||||||
 | 
							m.config._discriminatorMatch = v
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +28,10 @@ type MulticastInterface struct {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type GroupAddress string
 | 
					type GroupAddress string
 | 
				
			||||||
 | 
					type Discriminator []byte
 | 
				
			||||||
 | 
					type DiscriminatorMatch func([]byte) bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (a MulticastInterface) isSetupOption() {}
 | 
					func (a MulticastInterface) isSetupOption() {}
 | 
				
			||||||
func (a GroupAddress) isSetupOption()       {}
 | 
					func (a GroupAddress) isSetupOption()       {}
 | 
				
			||||||
 | 
					func (a Discriminator) isSetupOption()      {}
 | 
				
			||||||
 | 
					func (a DiscriminatorMatch) isSetupOption() {}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue