@@ -172,6 +172,9 @@ pub(crate) struct Identify {
172
172
// Public key of the local node, filled by `Litep2p`.
173
173
public : PublicKey ,
174
174
175
+ /// Local peer ID.
176
+ local_peer_id : PeerId ,
177
+
175
178
/// Protocol version.
176
179
protocol_version : String ,
177
180
@@ -191,11 +194,18 @@ pub(crate) struct Identify {
191
194
impl Identify {
192
195
/// Create new [`Identify`] protocol.
193
196
pub ( crate ) fn new ( service : TransportService , config : Config ) -> Self {
197
+ // The public key is always supplied by litep2p and is the one
198
+ // used to identify the local peer. This is a similar story to the
199
+ // supported protocols.
200
+ let public = config. public . expect ( "public key to always be supplied by litep2p; qed" ) ;
201
+ let local_peer_id = public. to_peer_id ( ) ;
202
+
194
203
Self {
195
204
service,
196
205
tx : config. tx_event ,
197
206
peers : HashMap :: new ( ) ,
198
- public : config. public . expect ( "public key to be supplied" ) ,
207
+ public,
208
+ local_peer_id,
199
209
protocol_version : config. protocol_version ,
200
210
user_agent : config. user_agent . unwrap_or ( DEFAULT_AGENT . to_string ( ) ) ,
201
211
pending_inbound : FuturesStream :: new ( ) ,
@@ -313,6 +323,8 @@ impl Identify {
313
323
"outbound substream opened"
314
324
) ;
315
325
326
+ let local_peer_id = self . local_peer_id . clone ( ) ;
327
+
316
328
self . pending_outbound . push ( Box :: pin ( async move {
317
329
let payload =
318
330
match tokio:: time:: timeout ( Duration :: from_secs ( 10 ) , substream. next ( ) ) . await {
@@ -325,17 +337,69 @@ impl Identify {
325
337
Ok ( Some ( Ok ( payload) ) ) => payload,
326
338
} ;
327
339
328
- let info = identify_schema:: Identify :: decode ( payload. to_vec ( ) . as_slice ( ) ) ?;
340
+ let info = identify_schema:: Identify :: decode ( payload. to_vec ( ) . as_slice ( ) ) . map_err (
341
+ |err| {
342
+ tracing:: debug!( target: LOG_TARGET , ?peer, ?err, "peer identified provided undecodable identify response" ) ;
343
+ err
344
+ } ) ?;
329
345
330
346
tracing:: trace!( target: LOG_TARGET , ?peer, ?info, "peer identified" ) ;
331
347
348
+ // The check ensures the provided public key is the same one as the
349
+ // one exchanged during the connection establishment.
350
+ if let Some ( public_key) = & info. public_key {
351
+ let public_key = PublicKey :: from_protobuf_encoding ( & public_key) . map_err ( |err| {
352
+ tracing:: debug!( target: LOG_TARGET , ?peer, ?err, "peer identified provided undecodable public key" ) ;
353
+ err
354
+ } ) ?;
355
+
356
+ if public_key. to_peer_id ( ) != peer {
357
+ tracing:: debug!( target: LOG_TARGET , ?peer, "peer identified provided invalid public key" ) ;
358
+ return Err ( Error :: InvalidData ) ;
359
+ }
360
+ }
361
+
332
362
let listen_addresses = info
333
363
. listen_addrs
334
364
. iter ( )
335
- . filter_map ( |address| Multiaddr :: try_from ( address. clone ( ) ) . ok ( ) )
365
+ . filter_map ( |address| {
366
+ let address = Multiaddr :: try_from ( address. clone ( ) ) . ok ( ) ?;
367
+
368
+ // Ensure the address ends with the provided peer ID and is not empty.
369
+ if address. is_empty ( ) {
370
+ tracing:: debug!( target: LOG_TARGET , ?peer, ?address, "peer identified provided empty listen address" ) ;
371
+ return None ;
372
+ }
373
+ if let Some ( multiaddr:: Protocol :: P2p ( peer_id) ) = address. iter ( ) . last ( ) {
374
+ if peer_id != peer. into ( ) {
375
+ tracing:: debug!( target: LOG_TARGET , ?peer, ?address, "peer identified provided listen address with incorrect peer ID; discarding the address" ) ;
376
+ return None ;
377
+ }
378
+ }
379
+
380
+ Some ( address)
381
+ } )
336
382
. collect ( ) ;
383
+
337
384
let observed_address =
338
- info. observed_addr . and_then ( |address| Multiaddr :: try_from ( address) . ok ( ) ) ;
385
+ info. observed_addr . and_then ( |address| {
386
+ let address = Multiaddr :: try_from ( address) . ok ( ) ?;
387
+
388
+ if address. is_empty ( ) {
389
+ tracing:: debug!( target: LOG_TARGET , ?peer, ?address, "peer identified provided empty observed address" ) ;
390
+ return None ;
391
+ }
392
+
393
+ if let Some ( multiaddr:: Protocol :: P2p ( peer_id) ) = address. iter ( ) . last ( ) {
394
+ if peer_id != local_peer_id. into ( ) {
395
+ tracing:: debug!( target: LOG_TARGET , ?peer, ?address, "peer identified provided observed address with peer ID not matching our peer ID; discarding address" ) ;
396
+ return None ;
397
+ }
398
+ }
399
+
400
+ Some ( address)
401
+ } ) ;
402
+
339
403
let protocol_version = info. protocol_version ;
340
404
let user_agent = info. agent_version ;
341
405
0 commit comments