diff --git a/src/crypto/crypto.go b/src/crypto/crypto.go index 3a6e02d..92adf89 100644 --- a/src/crypto/crypto.go +++ b/src/crypto/crypto.go @@ -194,6 +194,16 @@ type BoxSharedKey [BoxSharedKeyLen]byte // BoxNonce is the nonce used in NaCl-like crypto "box" operations (curve25519+xsalsa20+poly1305), and must not be reused for different messages encrypted using the same BoxSharedKey. type BoxNonce [BoxNonceLen]byte +// String returns a string representation of the "box" key. +func (k BoxPubKey) String() string { + return hex.EncodeToString(k[:]) +} + +// Network returns "pubkey" for "box" keys. +func (n BoxPubKey) Network() string { + return "pubkey" +} + // NewBoxKeys generates a new pair of public/private crypto box keys. func NewBoxKeys() (*BoxPubKey, *BoxPrivKey) { pubBytes, privBytes, err := box.GenerateKey(rand.Reader) diff --git a/src/yggdrasil/conn.go b/src/yggdrasil/conn.go index f622903..078dca3 100644 --- a/src/yggdrasil/conn.go +++ b/src/yggdrasil/conn.go @@ -353,13 +353,15 @@ func (c *Conn) Close() (err error) { // LocalAddr returns the complete node ID of the local side of the connection. // This is always going to return your own node's node ID. func (c *Conn) LocalAddr() net.Addr { - return crypto.GetNodeID(&c.core.boxPub) + return c.core.boxPub } // RemoteAddr returns the complete node ID of the remote side of the connection. func (c *Conn) RemoteAddr() net.Addr { - // RemoteAddr is set during the dial or accept, and isn't changed, so it's safe to access directly - return c.nodeID + if c.session != nil { + return c.session.theirPermPub + } + return nil } // SetDeadline is equivalent to calling both SetReadDeadline and diff --git a/src/yggdrasil/dialer.go b/src/yggdrasil/dialer.go index 490502b..293f6d0 100644 --- a/src/yggdrasil/dialer.go +++ b/src/yggdrasil/dialer.go @@ -17,19 +17,32 @@ type Dialer struct { core *Core } -// Dial opens a session to the given node. The first parameter should be "nodeid" -// and the second parameter should contain a hexadecimal representation of the -// target node ID. It uses DialContext internally. +// Dial opens a session to the given node. The first parameter should be +// "pubkey" or "nodeid" and the second parameter should contain a hexadecimal +// representation of the target. It uses DialContext internally. func (d *Dialer) Dial(network, address string) (net.Conn, error) { return d.DialContext(nil, network, address) } -// DialContext is used internally by Dial, and should only be used with a context that includes a timeout. It uses DialByNodeIDandMask internally. +// DialContext is used internally by Dial, and should only be used with a +// context that includes a timeout. It uses DialByNodeIDandMask internally when +// the network is "nodeid", or DialByPublicKey when the network is "pubkey". func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { var nodeID crypto.NodeID var nodeMask crypto.NodeID // Process switch network { + case "pubkey": + dest, err := hex.DecodeString(address) + if err != nil { + return nil, err + } + if len(dest) != crypto.BoxPubKeyLen { + return nil, errors.New("invalid key length supplied") + } + var pubKey crypto.BoxPubKey + copy(pubKey[:], dest) + return d.DialByPublicKey(ctx, &pubKey) case "nodeid": // A node ID was provided - we don't need to do anything special with it if tokens := strings.Split(address, "/"); len(tokens) == 2 { @@ -62,8 +75,9 @@ func (d *Dialer) DialContext(ctx context.Context, network, address string) (net. } } -// DialByNodeIDandMask opens a session to the given node based on raw -// NodeID parameters. If ctx is nil or has no timeout, then a default timeout of 6 seconds will apply, beginning *after* the search finishes. +// DialByNodeIDandMask opens a session to the given node based on raw NodeID +// parameters. If ctx is nil or has no timeout, then a default timeout of 6 +// seconds will apply, beginning *after* the search finishes. func (d *Dialer) DialByNodeIDandMask(ctx context.Context, nodeID, nodeMask *crypto.NodeID) (net.Conn, error) { startDial := time.Now() conn := newConn(d.core, nodeID, nodeMask, nil) @@ -92,3 +106,15 @@ func (d *Dialer) DialByNodeIDandMask(ctx context.Context, nodeID, nodeMask *cryp return nil, errors.New("session handshake timeout") } } + +// DialByPublicKey opens a session to the given node based on the public key. If +// ctx is nil or has no timeout, then a default timeout of 6 seconds will apply, +// beginning *after* the search finishes. +func (d *Dialer) DialByPublicKey(ctx context.Context, pubKey *crypto.BoxPubKey) (net.Conn, error) { + nodeID := crypto.GetNodeID(pubKey) + var nodeMask crypto.NodeID + for i := range nodeMask { + nodeMask[i] = 0xFF + } + return d.DialByNodeIDandMask(ctx, nodeID, &nodeMask) +} diff --git a/src/yggdrasil/listener.go b/src/yggdrasil/listener.go index 6383097..1b908b4 100644 --- a/src/yggdrasil/listener.go +++ b/src/yggdrasil/listener.go @@ -39,7 +39,7 @@ func (l *Listener) Close() (err error) { return nil } -// Addr is not implemented for this type yet +// Addr returns the address of the listener func (l *Listener) Addr() net.Addr { - return nil + return l.core.boxPub }