diff --git a/src/bundles/peer-locations.js b/src/bundles/peer-locations.js index e38207df9..91f075137 100644 --- a/src/bundles/peer-locations.js +++ b/src/bundles/peer-locations.js @@ -121,20 +121,21 @@ const parseLatency = (latency) => { return value } -const getPublicIP = memoizee((identity) => { +export const getPublicIP = memoizee((identity) => { if (!identity) return for (const maddr of identity.addresses) { try { const addr = Multiaddr(maddr).nodeAddress() - if (!ip.isPrivate(addr.address)) { + + if ((ip.isV4Format(addr.address) || ip.isV6Format(addr.address)) && !ip.isPrivate(addr.address)) { return addr.address } } catch (_) {} } }) -const isPrivateAndNearby = (maddr, identity) => { +export const isPrivateAndNearby = (maddr, identity) => { const publicIP = getPublicIP(identity) let isPrivate = false let isNearby = false @@ -157,9 +158,9 @@ const isPrivateAndNearby = (maddr, identity) => { // none of the calls bellow for ip library should fail. isPrivate = ip.isPrivate(addr.address) - if (addr.family === 4) { + if (ip.isV4Format(addr.address)) { isNearby = ip.cidrSubnet(`${publicIP}/24`).contains(addr.address) - } else if (addr.family === 6) { + } else if (ip.isV6Format(addr.address)) { isNearby = ip.cidrSubnet(`${publicIP}/48`).contains(addr.address) && !ip.cidrSubnet('fc00::/8').contains(addr.address) // peerIP6 ∉ fc00::/8 to fix case of cjdns where IPs are not spatial allocated. diff --git a/src/bundles/peer-locations.test.js b/src/bundles/peer-locations.test.js index a05d352f1..6b99b5528 100644 --- a/src/bundles/peer-locations.test.js +++ b/src/bundles/peer-locations.test.js @@ -1,7 +1,7 @@ -/* global it, expect */ +/* global it, describe, expect */ import { composeBundlesRaw, createReactorBundle } from 'redux-bundler' import Multiaddr from 'multiaddr' -import createPeerLocationsBundle from './peer-locations' +import createPeerLocationsBundle, { getPublicIP, isPrivateAndNearby } from './peer-locations' import { fakeCid } from '../../test/helpers/cid' import { randomInt, randomNum } from '../../test/helpers/random' import sleep from '../../test/helpers/sleep' @@ -267,3 +267,126 @@ it('should resolve alternative address for failed address lookup', async () => { expect(Object.keys(peerLocs)).toHaveLength(1) expectLocation(peerLocs[nextPeers[1].peer.toB58String()]) }) + +describe('getPublicIP', () => { + it('returns undefined on null identity', async () => { + expect(getPublicIP()).toEqual(undefined) + expect(getPublicIP(null)).toEqual(undefined) + expect(getPublicIP(undefined)).toEqual(undefined) + }) + + it('returns undefined on local IPs only', async () => { + const res = getPublicIP({ + addresses: [ + '/ip6/::1/tcp/4003', + '/ip4/127.0.0.1/tcp/4003', + '/ip4/192.168.0.0/tcp/4003', + '/ip4/192.168.255.255/tcp/4003', + '/ip4/10.0.0.0/tcp/4003', + '/ip4/10.255.255.255/tcp/4003', + '/ip4/172.16.0.0/tcp/4003', + '/ip4/172.16.255.255/tcp/4003' + ] + }) + + expect(res).toEqual(undefined) + }) + + it('returns undefined on discovery.libp2p.io', async () => { + const res = getPublicIP({ + addresses: [ + '/dnsaddr/ws-star.discovery.libp2p.io/tcp/443/wss/p2p-websocket-star/ipfs/QmbJbcN3Fvy5bC7Tr95STx5VFiP1G1WLPCHNceh1yShfbb', + '/dns4/ws-star.discovery.libp2p.io/tcp/443/wss/p2p-websocket-star/ipfs/QmYy3ka6HsQzpdTXY63nUKShsVdgg5zdhMXZXFeNGPyMT4' + ] + }) + + expect(res).toEqual(undefined) + }) + + it('returns correct IPv4', async () => { + const res = getPublicIP({ + addresses: [ + '/ip4/127.0.0.1/tcp/4003', + '/ip4/126.1.0.1/tcp/4003' + ] + }) + + expect(res).toEqual('126.1.0.1') + }) + + it('returns correct IPv6', async () => { + const res = getPublicIP({ + addresses: [ + '/ip4/127.0.0.1/tcp/4003', + '/ip6/::1/tcp/4003', + '/ip6/963c:d4b6:470b:e67b:afc1:c377:213:cad0/tcp/4003' + ] + }) + + expect(res).toEqual('963c:d4b6:470b:e67b:afc1:c377:213:cad0') + }) +}) + +describe('isPrivateAndNearby', () => { + it('is not nearby, nor private without identity argument', async () => { + const maddr = Multiaddr('/ip4/1.1.1.255/tcp/4003') + const { isNearby, isPrivate } = isPrivateAndNearby(maddr) + + expect(isNearby).toEqual(false) + expect(isPrivate).toEqual(false) + }) + + it('is nearby on ip/24 range', async () => { + const identity = { + addresses: ['/ip4/1.1.1.1/tcp/4003'] + } + + const maddr = Multiaddr('/ip4/1.1.1.255/tcp/4003') + const { isNearby, isPrivate } = isPrivateAndNearby(maddr, identity) + + expect(isNearby).toEqual(true) + expect(isPrivate).toEqual(false) + }) + + it('is private on local address', async () => { + const identity = { + addresses: ['/ip4/1.1.1.1/tcp/4003'] + } + + const maddr = Multiaddr('/ip4/192.168.1.0/tcp/4003') + const { isNearby, isPrivate } = isPrivateAndNearby(maddr, identity) + + expect(isNearby).toEqual(false) + expect(isPrivate).toEqual(true) + }) + + it('is not nearby, nor private with public IPv4', async () => { + const identity = { + addresses: ['/ip4/1.1.1.1/tcp/4003'] + } + + const maddr = Multiaddr('/ip4/2.2.2.2/tcp/4003') + const { isNearby, isPrivate } = isPrivateAndNearby(maddr, identity) + + expect(isNearby).toEqual(false) + expect(isPrivate).toEqual(false) + }) + + it('is not nearby, nor private for /p2p-websocket-star multiaddr', async () => { + const identity = { + addresses: ['/ip4/1.1.1.1/tcp/4003'] + } + + let maddr = Multiaddr('/dnsaddr/ws-star.discovery.libp2p.io/tcp/443/wss/p2p-websocket-star/ipfs/QmbJbcN3Fvy5bC7Tr95STx5VFiP1G1WLPCHNceh1yShfbb') + let { isNearby, isPrivate } = isPrivateAndNearby(maddr, identity) + + expect(isNearby).toEqual(false) + expect(isPrivate).toEqual(false) + + maddr = Multiaddr('/dns4/ws-star.discovery.libp2p.io/tcp/443/wss/p2p-websocket-star/ipfs/QmYy3ka6HsQzpdTXY63nUKShsVdgg5zdhMXZXFeNGPyMT4'); + ({ isNearby, isPrivate } = isPrivateAndNearby(maddr, identity)) + + expect(isNearby).toEqual(false) + expect(isPrivate).toEqual(false) + }) +})