Skip to content

Commit 098da36

Browse files
committed
feat: add util to get thin waist addresses
Adds a utillity to get all thin waist addresses for the current host, expanding ip4/ip6 wildcards as appropriate. Largely ports the code from `@libp2p/tcp` for use elsewhere.
1 parent 639ff92 commit 098da36

4 files changed

+134
-2
lines changed

packages/utils/package.json

+14-2
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@
7676
"types": "./dist/src/filters/index.d.ts",
7777
"import": "./dist/src/filters/index.js"
7878
},
79+
"./get-thin-waist-addresses": {
80+
"types": "./dist/src/get-thin-waist-addresses.d.ts",
81+
"browser": "./dist/src/get-thin-waist-addresses.browser.js",
82+
"import": "./dist/src/get-thin-waist-addresses.js"
83+
},
7984
"./global-unicast-ip": {
8085
"types": "./dist/src/global-unicast-ip.d.ts",
8186
"import": "./dist/src/global-unicast-ip.js"
@@ -219,7 +224,14 @@
219224
"it-drain": "^3.0.7",
220225
"it-pair": "^2.0.6",
221226
"sinon": "^19.0.2",
222-
"sinon-ts": "^2.0.0"
227+
"sinon-ts": "^2.0.0",
228+
"wherearewe": "^2.0.1"
229+
},
230+
"sideEffects": false,
231+
"browser": {
232+
"./dist/src/get-thin-waist-addresses.js": "./dist/src/get-thin-waist-addresses.browser.js"
223233
},
224-
"sideEffects": false
234+
"react-native": {
235+
"./dist/src/get-thin-waist-addresses.js": "./dist/src/get-thin-waist-addresses.js"
236+
}
225237
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { multiaddr, type Multiaddr } from '@multiformats/multiaddr'
2+
3+
/**
4+
* Get all thin waist addresses that match the passed multiaddr. Wildcard IP4/6
5+
* addresses will be expanded into all available interfaces.
6+
*/
7+
export function getThinWaistAddresses (ma: Multiaddr): Multiaddr[] {
8+
const options = ma.toOptions()
9+
10+
return [
11+
multiaddr(`/ip${options.family}/${options.host}/${options.transport}/${options.port}`)
12+
]
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import os from 'node:os'
2+
import { multiaddr, type Multiaddr } from '@multiformats/multiaddr'
3+
4+
const FAMILIES = { 4: 'IPv4', 6: 'IPv6' }
5+
6+
function isWildcard (ip: string): boolean {
7+
return ['0.0.0.0', '::'].includes(ip)
8+
}
9+
10+
function getNetworkAddrs (family: 4 | 6): string[] {
11+
const addresses: string[] = []
12+
const networks = os.networkInterfaces()
13+
14+
for (const [, netAddrs] of Object.entries(networks)) {
15+
if (netAddrs != null) {
16+
for (const netAddr of netAddrs) {
17+
if (netAddr.family === FAMILIES[family]) {
18+
addresses.push(netAddr.address)
19+
}
20+
}
21+
}
22+
}
23+
24+
return addresses
25+
}
26+
27+
/**
28+
* Get all thin waist addresses on the current host that match the family of the
29+
* passed multiaddr.
30+
*
31+
* Wildcard IP4/6 addresses will be expanded into all available interfaces.
32+
*/
33+
export function getThinWaistAddresses (ma: Multiaddr): Multiaddr[] {
34+
const options = ma.toOptions()
35+
36+
if (isWildcard(options.host)) {
37+
const addrs = []
38+
39+
for (const host of getNetworkAddrs(options.family)) {
40+
addrs.push(multiaddr(`/ip${options.family}/${host}/${options.transport}/${options.port}`))
41+
}
42+
43+
return addrs
44+
}
45+
46+
return [
47+
multiaddr(`/ip${options.family}/${options.host}/${options.transport}/${options.port}`)
48+
]
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { multiaddr } from '@multiformats/multiaddr'
2+
import { expect } from 'aegir/chai'
3+
import { isNode, isElectronMain } from 'wherearewe'
4+
import { getThinWaistAddresses } from '../src/get-thin-waist-addresses.js'
5+
6+
describe('get-thin-waist-addresses', () => {
7+
it('should get thin waist addresses from specific address', () => {
8+
const input = multiaddr('/ip4/123.123.123.123/tcp/1234')
9+
const addrs = getThinWaistAddresses(input)
10+
11+
expect(addrs).to.deep.equal([input])
12+
})
13+
14+
it('should ignore non-thin waist tuples from specific address', () => {
15+
const input = multiaddr('/ip4/123.123.123.123/udp/1234/webrtc')
16+
const addrs = getThinWaistAddresses(input)
17+
18+
expect(addrs).to.deep.equal([
19+
multiaddr('/ip4/123.123.123.123/udp/1234')
20+
])
21+
})
22+
23+
it('should get thin waist addresses from IPv4 wildcard', function () {
24+
if (!isNode && !isElectronMain) {
25+
return this.skip()
26+
}
27+
28+
const input = multiaddr('/ip4/0.0.0.0/tcp/1234')
29+
const addrs = getThinWaistAddresses(input)
30+
31+
expect(addrs).to.have.property('length').that.is.greaterThan(0)
32+
33+
for (const addr of addrs) {
34+
const options = addr.toOptions()
35+
36+
expect(options).to.have.property('family', 4)
37+
expect(options).to.have.property('host').that.does.not.equal('0.0.0.0')
38+
}
39+
})
40+
41+
it('should get thin waist addresses from IPv6 wildcard', function () {
42+
if (!isNode && !isElectronMain) {
43+
return this.skip()
44+
}
45+
46+
const input = multiaddr('/ip6/::/tcp/1234')
47+
const addrs = getThinWaistAddresses(input)
48+
49+
expect(addrs).to.have.property('length').that.is.greaterThan(0)
50+
51+
for (const addr of addrs) {
52+
const options = addr.toOptions()
53+
54+
expect(options).to.have.property('family', 6)
55+
expect(options).to.have.property('host').that.does.not.equal('::')
56+
}
57+
})
58+
})

0 commit comments

Comments
 (0)