Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: exchange signed peer records in identify #682

Merged
merged 6 commits into from
Jul 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 86 additions & 14 deletions src/identify/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
'use strict'

const { Buffer } = require('buffer')
const debug = require('debug')
const log = debug('libp2p:identify')
log.error = debug('libp2p:identify:error')

const errCode = require('err-code')
const { Buffer } = require('buffer')
const pb = require('it-protocol-buffers')
const lp = require('it-length-prefixed')
const pipe = require('it-pipe')
Expand All @@ -13,8 +17,8 @@ const { toBuffer } = require('it-buffer')

const Message = require('./message')

const log = debug('libp2p:identify')
log.error = debug('libp2p:identify:error')
const Envelope = require('../record/envelope')
const PeerRecord = require('../record/peer-record')

const {
MULTICODEC_IDENTIFY,
Expand All @@ -23,7 +27,6 @@ const {
PROTOCOL_VERSION
} = require('./consts')

const errCode = require('err-code')
const { codes } = require('../errors')

class IdentifyService {
Expand Down Expand Up @@ -79,22 +82,30 @@ class IdentifyService {
this._protocols = protocols

this.handleMessage = this.handleMessage.bind(this)

// TODO: this should be stored in the certified AddressBook in follow up PR
this._selfRecord = undefined
}

/**
* Send an Identify Push update to the list of connections
* @param {Array<Connection>} connections
* @returns {Promise<void>}
*/
push (connections) {
async push (connections) {
const signedPeerRecord = await this._getSelfPeerRecord()
const listenAddrs = this._libp2p.multiaddrs.map((ma) => ma.buffer)
const protocols = Array.from(this._protocols.keys())

const pushes = connections.map(async connection => {
try {
const { stream } = await connection.newStream(MULTICODEC_IDENTIFY_PUSH)

await pipe(
[{
listenAddrs: this._libp2p.multiaddrs.map((ma) => ma.buffer),
protocols: Array.from(this._protocols.keys())
listenAddrs,
signedPeerRecord,
protocols
}],
pb.encode(Message),
stream,
Expand Down Expand Up @@ -160,7 +171,8 @@ class IdentifyService {
publicKey,
listenAddrs,
protocols,
observedAddr
observedAddr,
signedPeerRecord
} = message

const id = await PeerId.createFromPubKey(publicKey)
Expand All @@ -172,8 +184,26 @@ class IdentifyService {
// Get the observedAddr if there is one
observedAddr = IdentifyService.getCleanMultiaddr(observedAddr)

let addresses

try {
const envelope = await Envelope.openAndCertify(signedPeerRecord, PeerRecord.DOMAIN)
const peerRecord = await PeerRecord.createFromProtobuf(envelope.payload)

addresses = peerRecord.multiaddrs
} catch (err) {
log('received invalid envelope, discard it and fallback to listenAddrs is available', err)
// Try Legacy
addresses = listenAddrs
}

// Update peers data in PeerStore
this.peerStore.addressBook.set(id, listenAddrs.map((addr) => multiaddr(addr)))
try {
this.peerStore.addressBook.set(id, addresses.map((addr) => multiaddr(addr)))
} catch (err) {
log.error('received invalid addrs', err)
}

this.peerStore.protoBook.set(id, protocols)

// TODO: Track our observed address so that we can score it
Expand Down Expand Up @@ -201,8 +231,8 @@ class IdentifyService {
}

/**
* Sends the `Identify` response to the requesting peer over the
* given `connection`
* Sends the `Identify` response with the Signed Peer Record
* to the requesting peer over the given `connection`
* @private
* @param {object} options
* @param {*} options.stream
Expand All @@ -214,11 +244,14 @@ class IdentifyService {
publicKey = this.peerId.pubKey.bytes
}

const signedPeerRecord = await this._getSelfPeerRecord()

const message = Message.encode({
protocolVersion: PROTOCOL_VERSION,
agentVersion: AGENT_VERSION,
publicKey,
listenAddrs: this._libp2p.multiaddrs.map((ma) => ma.buffer),
signedPeerRecord,
observedAddr: connection.remoteAddr.buffer,
protocols: Array.from(this._protocols.keys())
})
Expand Down Expand Up @@ -258,17 +291,56 @@ class IdentifyService {
return log.error('received invalid message', err)
}

// Update peers data in PeerStore
const id = connection.remotePeer

let addresses

try {
this.peerStore.addressBook.set(id, message.listenAddrs.map((addr) => multiaddr(addr)))
const envelope = await Envelope.openAndCertify(message.signedPeerRecord, PeerRecord.DOMAIN)
const peerRecord = await PeerRecord.createFromProtobuf(envelope.payload)

addresses = peerRecord.multiaddrs
} catch (err) {
return log.error('received invalid listen addrs', err)
log('received invalid envelope, discard it and fallback to listenAddrs is available', err)
// Try Legacy
addresses = message.listenAddrs
}

try {
this.peerStore.addressBook.set(id, addresses.map((addr) => multiaddr(addr)))
} catch (err) {
log.error('received invalid addrs', err)
}

// Update the protocols
this.peerStore.protoBook.set(id, message.protocols)
}

/**
* Get self signed peer record raw envelope.
* @return {Buffer}
*/
async _getSelfPeerRecord () {
jacobheun marked this conversation as resolved.
Show resolved Hide resolved
// TODO: support invalidation when dynamic multiaddrs are supported
if (this._selfRecord) {
return this._selfRecord
}

try {
const peerRecord = new PeerRecord({
peerId: this.peerId,
multiaddrs: this._libp2p.multiaddrs
})
const envelope = await Envelope.seal(peerRecord, this.peerId)

this._selfRecord = envelope.marshal()

return this._selfRecord
} catch (err) {
log.error('failed to get self peer record')
}
return null
}
}

module.exports.IdentifyService = IdentifyService
Expand Down
5 changes: 5 additions & 0 deletions src/identify/message.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ message Identify {
optional bytes observedAddr = 4;

repeated string protocols = 3;

// signedPeerRecord contains a serialized SignedEnvelope containing a PeerRecord,
// signed by the sending node. It contains the same addresses as the listenAddrs field, but
// in a form that lets us share authenticated addrs with other peers.
optional bytes signedPeerRecord = 8;
}
`

Expand Down
2 changes: 2 additions & 0 deletions src/record/peer-record/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,6 @@ PeerRecord.createFromProtobuf = (buf) => {
return new PeerRecord({ peerId, multiaddrs, seqNumber })
}

PeerRecord.DOMAIN = ENVELOPE_DOMAIN_PEER_RECORD

module.exports = PeerRecord
Loading