mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 11:15:07 +03:00 
			
		
		
		
	Some attempt at exchanging session metadata over the wire (broken)
This commit is contained in:
		
							parent
							
								
									4f435705e3
								
							
						
					
					
						commit
						a1b72c16d8
					
				
					 9 changed files with 228 additions and 83 deletions
				
			
		| 
						 | 
				
			
			@ -470,7 +470,9 @@ func (a *admin) getData_getSelf() *admin_nodeInfo {
 | 
			
		|||
		{"ip", a.core.GetAddress().String()},
 | 
			
		||||
		{"subnet", a.core.GetSubnet().String()},
 | 
			
		||||
		{"coords", fmt.Sprint(coords)},
 | 
			
		||||
		{"friendly_name", a.core.friendlyName},
 | 
			
		||||
		{"name", a.core.metadata.name},
 | 
			
		||||
		{"location", a.core.metadata.location},
 | 
			
		||||
		{"contact", a.core.metadata.contact},
 | 
			
		||||
	}
 | 
			
		||||
	return &self
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -494,7 +496,6 @@ func (a *admin) getData_getPeers() []admin_nodeInfo {
 | 
			
		|||
			{"bytes_sent", atomic.LoadUint64(&p.bytesSent)},
 | 
			
		||||
			{"bytes_recvd", atomic.LoadUint64(&p.bytesRecvd)},
 | 
			
		||||
			{"endpoint", p.endpoint},
 | 
			
		||||
			{"friendly_name", p.friendlyName},
 | 
			
		||||
		}
 | 
			
		||||
		peerInfos = append(peerInfos, info)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -520,7 +521,6 @@ func (a *admin) getData_getSwitchPeers() []admin_nodeInfo {
 | 
			
		|||
			{"bytes_sent", atomic.LoadUint64(&peer.bytesSent)},
 | 
			
		||||
			{"bytes_recvd", atomic.LoadUint64(&peer.bytesRecvd)},
 | 
			
		||||
			{"endpoint", peer.endpoint},
 | 
			
		||||
			{"friendly_name", peer.friendlyName},
 | 
			
		||||
		}
 | 
			
		||||
		peerInfos = append(peerInfos, info)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@ package config
 | 
			
		|||
 | 
			
		||||
// NodeConfig defines all configuration values needed to run a signle yggdrasil node
 | 
			
		||||
type NodeConfig struct {
 | 
			
		||||
	FriendlyName                string              `comment:"Friendly name for this node. It is visible to direct peers."`
 | 
			
		||||
	Metadata                    Metadata            `comment:"Optional node metadata. Entirely optional but visible to all\npeers and nodes with open sessions."`
 | 
			
		||||
	Listen                      string              `comment:"Listen address for peer connections. Default is to listen for all\nTCP connections over IPv4 and IPv6 with a random port."`
 | 
			
		||||
	AdminListen                 string              `comment:"Listen address for admin connections Default is to listen for local\nconnections either on TCP/9001 or a UNIX socket depending on your\nplatform. Use this value for yggdrasilctl -endpoint=X."`
 | 
			
		||||
	Peers                       []string            `comment:"List of connection strings for static peers in URI format, i.e.\ntcp://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j."`
 | 
			
		||||
| 
						 | 
				
			
			@ -35,3 +35,9 @@ type SessionFirewall struct {
 | 
			
		|||
	WhitelistEncryptionPublicKeys []string `comment:"List of public keys from which network traffic is always accepted,\nregardless of AllowFromDirect or AllowFromRemote."`
 | 
			
		||||
	BlacklistEncryptionPublicKeys []string `comment:"List of public keys from which network traffic is always rejected,\nregardless of the whitelist, AllowFromDirect or AllowFromRemote."`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Metadata struct {
 | 
			
		||||
	Name     string
 | 
			
		||||
	Location string
 | 
			
		||||
	Contact  string
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ type Core struct {
 | 
			
		|||
	boxPriv     boxPrivKey
 | 
			
		||||
	sigPub      sigPubKey
 | 
			
		||||
	sigPriv     sigPrivKey
 | 
			
		||||
	friendlyName string
 | 
			
		||||
	metadata    metadata
 | 
			
		||||
	switchTable switchTable
 | 
			
		||||
	peers       peers
 | 
			
		||||
	sigs        sigManager
 | 
			
		||||
| 
						 | 
				
			
			@ -40,7 +40,7 @@ func (c *Core) init(bpub *boxPubKey,
 | 
			
		|||
	bpriv *boxPrivKey,
 | 
			
		||||
	spub *sigPubKey,
 | 
			
		||||
	spriv *sigPrivKey,
 | 
			
		||||
	friendlyname string) {
 | 
			
		||||
	metadata metadata) {
 | 
			
		||||
	// TODO separate init and start functions
 | 
			
		||||
	//  Init sets up structs
 | 
			
		||||
	//  Start launches goroutines that depend on structs being set up
 | 
			
		||||
| 
						 | 
				
			
			@ -51,7 +51,7 @@ func (c *Core) init(bpub *boxPubKey,
 | 
			
		|||
	}
 | 
			
		||||
	c.boxPub, c.boxPriv = *bpub, *bpriv
 | 
			
		||||
	c.sigPub, c.sigPriv = *spub, *spriv
 | 
			
		||||
	c.friendlyName = friendlyname
 | 
			
		||||
	c.metadata = metadata
 | 
			
		||||
	c.admin.core = c
 | 
			
		||||
	c.sigs.init()
 | 
			
		||||
	c.searches.init(c)
 | 
			
		||||
| 
						 | 
				
			
			@ -65,11 +65,8 @@ func (c *Core) init(bpub *boxPubKey,
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// Gets the friendly name of this node, as specified in the NodeConfig.
 | 
			
		||||
func (c *Core) GetFriendlyName() string {
 | 
			
		||||
	if c.friendlyName == "" {
 | 
			
		||||
		return "(none)"
 | 
			
		||||
	}
 | 
			
		||||
	return c.friendlyName
 | 
			
		||||
func (c *Core) GetMeta() metadata {
 | 
			
		||||
	return c.metadata
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Starts up Yggdrasil using the provided NodeConfig, and outputs debug logging
 | 
			
		||||
| 
						 | 
				
			
			@ -105,7 +102,13 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error {
 | 
			
		|||
	copy(sigPub[:], sigPubHex)
 | 
			
		||||
	copy(sigPriv[:], sigPrivHex)
 | 
			
		||||
 | 
			
		||||
	c.init(&boxPub, &boxPriv, &sigPub, &sigPriv, nc.FriendlyName)
 | 
			
		||||
	meta := metadata{
 | 
			
		||||
		name:     nc.Metadata.Name,
 | 
			
		||||
		location: nc.Metadata.Location,
 | 
			
		||||
		contact:  nc.Metadata.Contact,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.init(&boxPub, &boxPriv, &sigPub, &sigPriv, meta)
 | 
			
		||||
	c.admin.init(c, nc.AdminListen)
 | 
			
		||||
 | 
			
		||||
	if err := c.tcp.init(c, nc.Listen, nc.ReadTimeout); err != nil {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										7
									
								
								src/yggdrasil/metadata.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/yggdrasil/metadata.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
package yggdrasil
 | 
			
		||||
 | 
			
		||||
type metadata struct {
 | 
			
		||||
	name     string
 | 
			
		||||
	location string
 | 
			
		||||
	contact  string
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +86,7 @@ type peer struct {
 | 
			
		|||
	shared     boxSharedKey
 | 
			
		||||
	linkShared boxSharedKey
 | 
			
		||||
	endpoint   string
 | 
			
		||||
	friendlyName string
 | 
			
		||||
	metadata   metadata
 | 
			
		||||
	firstSeen  time.Time       // To track uptime for getPeers
 | 
			
		||||
	linkOut    (chan []byte)   // used for protocol traffic (to bypass queues)
 | 
			
		||||
	doSend     (chan struct{}) // tell the linkLoop to send a switchMsg
 | 
			
		||||
| 
						 | 
				
			
			@ -96,14 +96,14 @@ type peer struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// Creates a new peer with the specified box, sig, and linkShared keys, using the lowest unocupied port number.
 | 
			
		||||
func (ps *peers) newPeer(box *boxPubKey, sig *sigPubKey, linkShared *boxSharedKey, endpoint string, friendlyname string) *peer {
 | 
			
		||||
func (ps *peers) newPeer(box *boxPubKey, sig *sigPubKey, linkShared *boxSharedKey, endpoint string, metadata metadata) *peer {
 | 
			
		||||
	now := time.Now()
 | 
			
		||||
	p := peer{box: *box,
 | 
			
		||||
		sig:        *sig,
 | 
			
		||||
		shared:     *getSharedKey(&ps.core.boxPriv, box),
 | 
			
		||||
		linkShared: *linkShared,
 | 
			
		||||
		endpoint:   endpoint,
 | 
			
		||||
		friendlyName: friendlyname,
 | 
			
		||||
		metadata:   metadata,
 | 
			
		||||
		firstSeen:  now,
 | 
			
		||||
		doSend:     make(chan struct{}, 1),
 | 
			
		||||
		core:       ps.core}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,7 +47,7 @@ func (r *router) init(core *Core) {
 | 
			
		|||
	r.core = core
 | 
			
		||||
	r.addr = *address_addrForNodeID(&r.core.dht.nodeID)
 | 
			
		||||
	in := make(chan []byte, 32) // TODO something better than this...
 | 
			
		||||
	p := r.core.peers.newPeer(&r.core.boxPub, &r.core.sigPub, &boxSharedKey{}, "(self)", r.core.GetFriendlyName())
 | 
			
		||||
	p := r.core.peers.newPeer(&r.core.boxPub, &r.core.sigPub, &boxSharedKey{}, "(self)", r.core.metadata)
 | 
			
		||||
	p.out = func(packet []byte) {
 | 
			
		||||
		// This is to make very sure it never blocks
 | 
			
		||||
		select {
 | 
			
		||||
| 
						 | 
				
			
			@ -324,6 +324,10 @@ func (r *router) handleProto(packet []byte) {
 | 
			
		|||
		r.handlePing(bs, &p.FromKey)
 | 
			
		||||
	case wire_SessionPong:
 | 
			
		||||
		r.handlePong(bs, &p.FromKey)
 | 
			
		||||
	case wire_SessionMetaRequest:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case wire_SessionMetaResponse:
 | 
			
		||||
		r.handleMeta(bs, &p.FromKey)
 | 
			
		||||
	case wire_DHTLookupRequest:
 | 
			
		||||
		r.handleDHTReq(bs, &p.FromKey)
 | 
			
		||||
	case wire_DHTLookupResponse:
 | 
			
		||||
| 
						 | 
				
			
			@ -368,6 +372,17 @@ func (r *router) handleDHTRes(bs []byte, fromKey *boxPubKey) {
 | 
			
		|||
	r.core.dht.handleRes(&res)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Decodes meta request
 | 
			
		||||
func (r *router) handleMeta(bs []byte, fromKey *boxPubKey) {
 | 
			
		||||
	req := sessionMeta{}
 | 
			
		||||
	if !req.decode(bs) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	req.SendPermPub = *fromKey
 | 
			
		||||
	r.core.log.Printf("handleMeta: %+v\n", req)
 | 
			
		||||
	r.core.sessions.handleMeta(&req)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Passed a function to call.
 | 
			
		||||
// This will send the function to r.admin and block until it finishes.
 | 
			
		||||
// It's used by the admin socket to ask the router mainLoop goroutine about information in the session or dht structs, which cannot be read safely from outside that goroutine.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,6 +25,9 @@ type sessionInfo struct {
 | 
			
		|||
	myHandle      handle
 | 
			
		||||
	theirNonce    boxNonce
 | 
			
		||||
	myNonce       boxNonce
 | 
			
		||||
	metaReqTime   time.Time
 | 
			
		||||
	metaResTime   time.Time
 | 
			
		||||
	theirMetadata metadata
 | 
			
		||||
	theirMTU      uint16
 | 
			
		||||
	myMTU         uint16
 | 
			
		||||
	wasMTUFixed   bool      // Was the MTU fixed by a receive error?
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +57,13 @@ type sessionPing struct {
 | 
			
		|||
	MTU         uint16
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Represents a session metadata packet.
 | 
			
		||||
type sessionMeta struct {
 | 
			
		||||
	SendPermPub boxPubKey // Sender's permanent key
 | 
			
		||||
	IsResponse  bool
 | 
			
		||||
	Metadata    metadata
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Updates session info in response to a ping, after checking that the ping is OK.
 | 
			
		||||
// Returns true if the session was updated, or false otherwise.
 | 
			
		||||
func (s *sessionInfo) update(p *sessionPing) bool {
 | 
			
		||||
| 
						 | 
				
			
			@ -431,6 +441,66 @@ func (ss *sessions) handlePing(ping *sessionPing) {
 | 
			
		|||
		bs, sinfo.packet = sinfo.packet, nil
 | 
			
		||||
		ss.core.router.sendPacket(bs)
 | 
			
		||||
	}
 | 
			
		||||
	if time.Since(sinfo.metaResTime).Minutes() > 15 {
 | 
			
		||||
		if time.Since(sinfo.metaReqTime).Minutes() > 1 {
 | 
			
		||||
			ss.sendMeta(sinfo, false)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ss *sessions) sendMeta(sinfo *sessionInfo, isResponse bool) {
 | 
			
		||||
	meta := sessionMeta{
 | 
			
		||||
		IsResponse: isResponse,
 | 
			
		||||
		Metadata: metadata{
 | 
			
		||||
			name:     "some.name.com", //[]byte(ss.core.friendlyName)[0:len(ss.core.friendlyName):32],
 | 
			
		||||
			location: "Some Place",
 | 
			
		||||
			contact:  "someone@somewhere.com",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	bs := meta.encode()
 | 
			
		||||
	shared := ss.getSharedKey(&ss.core.boxPriv, &sinfo.theirPermPub)
 | 
			
		||||
	payload, nonce := boxSeal(shared, bs, nil)
 | 
			
		||||
	p := wire_protoTrafficPacket{
 | 
			
		||||
		Coords:  sinfo.coords,
 | 
			
		||||
		ToKey:   sinfo.theirPermPub,
 | 
			
		||||
		FromKey: ss.core.boxPub,
 | 
			
		||||
		Nonce:   *nonce,
 | 
			
		||||
		Payload: payload,
 | 
			
		||||
	}
 | 
			
		||||
	packet := p.encode()
 | 
			
		||||
	ss.core.router.out(packet)
 | 
			
		||||
	if isResponse {
 | 
			
		||||
		ss.core.log.Println("Sent meta response to", sinfo.theirAddr)
 | 
			
		||||
	} else {
 | 
			
		||||
		ss.core.log.Println("Sent meta request to", sinfo.theirAddr)
 | 
			
		||||
		sinfo.metaReqTime = time.Now()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handles a meta request/response.
 | 
			
		||||
func (ss *sessions) handleMeta(meta *sessionMeta) {
 | 
			
		||||
	// Get the corresponding session (or create a new session)
 | 
			
		||||
	sinfo, isIn := ss.getByTheirPerm(&meta.SendPermPub)
 | 
			
		||||
	// Check the session firewall
 | 
			
		||||
	if !isIn && ss.sessionFirewallEnabled {
 | 
			
		||||
		if !ss.isSessionAllowed(&meta.SendPermPub, false) {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if !isIn || sinfo.timedout() {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if meta.IsResponse {
 | 
			
		||||
		ss.core.log.Println("Received meta response", string(meta.Metadata.name), "from", sinfo.theirAddr)
 | 
			
		||||
		sinfo.theirMetadata = meta.Metadata
 | 
			
		||||
		sinfo.metaResTime = time.Now()
 | 
			
		||||
		ss.core.log.Println("- name:", meta.Metadata.name)
 | 
			
		||||
		ss.core.log.Println("- contact:", meta.Metadata.contact)
 | 
			
		||||
		ss.core.log.Println("- location:", meta.Metadata.location)
 | 
			
		||||
	} else {
 | 
			
		||||
		ss.core.log.Println("Received meta request", string(meta.Metadata.name), "from", sinfo.theirAddr)
 | 
			
		||||
		ss.sendMeta(sinfo, true)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Used to subtract one nonce from another, staying in the range +- 64.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -287,7 +287,7 @@ func (iface *tcpInterface) handler(sock net.Conn, incoming bool) {
 | 
			
		|||
	}()
 | 
			
		||||
	// Note that multiple connections to the same node are allowed
 | 
			
		||||
	//  E.g. over different interfaces
 | 
			
		||||
	p := iface.core.peers.newPeer(&info.box, &info.sig, getSharedKey(myLinkPriv, &meta.link), sock.RemoteAddr().String(), "(none)")
 | 
			
		||||
	p := iface.core.peers.newPeer(&info.box, &info.sig, getSharedKey(myLinkPriv, &meta.link), sock.RemoteAddr().String(), metadata{})
 | 
			
		||||
	p.linkOut = make(chan []byte, 1)
 | 
			
		||||
	in := func(bs []byte) {
 | 
			
		||||
		p.handlePacket(bs)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,6 +16,8 @@ const (
 | 
			
		|||
	wire_SessionPong                // inside protocol traffic header
 | 
			
		||||
	wire_DHTLookupRequest           // inside protocol traffic header
 | 
			
		||||
	wire_DHTLookupResponse          // inside protocol traffic header
 | 
			
		||||
	wire_SessionMetaRequest         // inside protocol traffic header
 | 
			
		||||
	wire_SessionMetaResponse        // inside protocol traffic header
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Calls wire_put_uint64 on a nil slice.
 | 
			
		||||
| 
						 | 
				
			
			@ -353,6 +355,48 @@ func (p *sessionPing) decode(bs []byte) bool {
 | 
			
		|||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// Encodes a sessionPing into its wire format.
 | 
			
		||||
func (p *sessionMeta) encode() []byte {
 | 
			
		||||
	var pTypeVal uint64
 | 
			
		||||
	if p.IsResponse {
 | 
			
		||||
		pTypeVal = wire_SessionMetaResponse
 | 
			
		||||
	} else {
 | 
			
		||||
		pTypeVal = wire_SessionMetaRequest
 | 
			
		||||
	}
 | 
			
		||||
	bs := wire_encode_uint64(pTypeVal)
 | 
			
		||||
	if p.IsResponse {
 | 
			
		||||
		bs = append(bs, p.Metadata.name...)
 | 
			
		||||
		bs = append(bs, p.Metadata.location...)
 | 
			
		||||
		bs = append(bs, p.Metadata.contact...)
 | 
			
		||||
	}
 | 
			
		||||
	return bs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Decodes an encoded sessionPing into the struct, returning true if successful.
 | 
			
		||||
func (p *sessionMeta) decode(bs []byte) bool {
 | 
			
		||||
	var pType uint64
 | 
			
		||||
	switch {
 | 
			
		||||
	case !wire_chop_uint64(&pType, &bs):
 | 
			
		||||
		return false
 | 
			
		||||
	case pType != wire_SessionMetaRequest && pType != wire_SessionMetaResponse:
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	p.IsResponse = pType == wire_SessionMetaResponse
 | 
			
		||||
	if p.IsResponse {
 | 
			
		||||
		switch {
 | 
			
		||||
		case !wire_chop_slice([]byte(p.Metadata.name), &bs):
 | 
			
		||||
			return false
 | 
			
		||||
		case !wire_chop_slice([]byte(p.Metadata.location), &bs):
 | 
			
		||||
			return false
 | 
			
		||||
		case !wire_chop_slice([]byte(p.Metadata.contact), &bs):
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// Encodes a dhtReq into its wire format.
 | 
			
		||||
func (r *dhtReq) encode() []byte {
 | 
			
		||||
	coords := wire_encode_coords(r.Coords)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue