Skip to content

Commit 56c1eb7

Browse files
committed
fix(dev): ignore link-local addresses in network urls
1 parent 3bb7f12 commit 56c1eb7

2 files changed

Lines changed: 53 additions & 5 deletions

File tree

packages/nuxt-cli/src/dev/listen.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,22 @@ export interface Listener {
5555

5656
const ANY_HOSTS = new Set(['', '0.0.0.0', '::'])
5757

58+
/**
59+
* External IPv4 addresses other devices can reach. IPv4 link-local addresses
60+
* (169.254.0.0/16, from a macOS Thunderbolt Bridge or an unconfigured adapter)
61+
* are excluded because they are unreachable from the rest of the network.
62+
*/
63+
export function getNetworkAddresses(): string[] {
64+
const addresses: string[] = []
65+
for (const info of Object.values(networkInterfaces()).flat()) {
66+
if (!info || info.internal || info.family !== 'IPv4' || info.address.startsWith('169.254.')) {
67+
continue
68+
}
69+
addresses.push(info.address)
70+
}
71+
return addresses
72+
}
73+
5874
/**
5975
* OpenSSL 3 moved the ciphers used by older PKCS#12 exports (RC2-40, RC4, DES)
6076
* into the legacy provider, which Node does not load, so such keystores fail
@@ -137,11 +153,8 @@ export async function listen(handler: RequestListener, options: ListenOptions =
137153
}
138154
if (anyHost) {
139155
urls.push({ url: formatURL('localhost'), type: 'local' })
140-
for (const info of Object.values(networkInterfaces()).flat()) {
141-
if (!info || info.internal || info.family !== 'IPv4') {
142-
continue
143-
}
144-
urls.push({ url: formatURL(info.address), type: 'network' })
156+
for (const address of getNetworkAddresses()) {
157+
urls.push({ url: formatURL(address), type: 'network' })
145158
}
146159
}
147160
else {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { networkInterfaces } from 'node:os'
2+
3+
import { describe, expect, it, vi } from 'vitest'
4+
5+
import { getNetworkAddresses } from '../../src/dev/listen'
6+
7+
vi.mock('node:os', () => ({
8+
networkInterfaces: vi.fn(),
9+
release: () => 'test',
10+
}))
11+
12+
const mocked = vi.mocked(networkInterfaces)
13+
14+
describe('getNetworkAddresses', () => {
15+
it('should return external IPv4 addresses', () => {
16+
mocked.mockReturnValue({
17+
lo0: [{ address: '127.0.0.1', family: 'IPv4', internal: true } as any],
18+
en0: [
19+
{ address: '192.168.1.20', family: 'IPv4', internal: false } as any,
20+
{ address: 'fe80::1', family: 'IPv6', internal: false } as any,
21+
],
22+
})
23+
24+
expect(getNetworkAddresses()).toEqual(['192.168.1.20'])
25+
})
26+
27+
it('should ignore IPv4 link-local addresses', () => {
28+
mocked.mockReturnValue({
29+
bridge0: [{ address: '169.254.13.37', family: 'IPv4', internal: false } as any],
30+
en0: [{ address: '192.168.1.20', family: 'IPv4', internal: false } as any],
31+
})
32+
33+
expect(getNetworkAddresses()).toEqual(['192.168.1.20'])
34+
})
35+
})

0 commit comments

Comments
 (0)