matterbridge 3.4.5-dev-20251224-e00e572 → 3.4.5-dev-20251224-457def5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/dist/dgram/mb_mdns.js +97 -44
- package/dist/dgram/mdns.js +80 -14
- package/dist/utils/network.js +14 -3
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -34,10 +34,15 @@ Advantages:
|
|
|
34
34
|
|
|
35
35
|
- [DevContainer]: Refactored Dev Container setup. The Matterbridge instance can now be paired on native Linux hosts or WSL 2 with Docker engine CLI integration. On Docker Desktop on Windows or macOS is not possible cause Docker Desktop runs inside a VM and not directly on the host so mDNS is not supported.
|
|
36
36
|
- [DevContainer]: Since is now possible to pair from Dev Container, named volumes have been added to persist storage and plugins across rebuilds.
|
|
37
|
+
- [mb_mdns]: Added query and advertise interval. Improved help for easy mDNS testing.
|
|
38
|
+
- [mb_mdns]: Advertise full DNS-SD record set (PTR/SRV/TXT/A/AAAA) for matterbridge.\_http.\_tcp.local on port 8283.
|
|
39
|
+
- [mdns]: Added TXT/SRV/A/AAAA encoders into the Mdns class.
|
|
40
|
+
- [mb_mdns]: Added broadcast parameter to allow advertising when multicast is not available.
|
|
37
41
|
|
|
38
42
|
### Changed
|
|
39
43
|
|
|
40
44
|
- [package]: Updated dependencies.
|
|
45
|
+
- [mdns]: Mdns.sendResponse now accepts an array and sends multi-answer responses.
|
|
41
46
|
|
|
42
47
|
### Fixed
|
|
43
48
|
|
package/dist/dgram/mb_mdns.js
CHANGED
|
@@ -1,37 +1,48 @@
|
|
|
1
|
-
import { getParameter, getStringArrayParameter, hasParameter } from '../utils/commandLine.js';
|
|
1
|
+
import { getIntParameter, getParameter, getStringArrayParameter, hasParameter } from '../utils/commandLine.js';
|
|
2
2
|
import { MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_IPV6_ADDRESS, MDNS_MULTICAST_PORT } from './multicast.js';
|
|
3
3
|
import { Mdns } from './mdns.js';
|
|
4
4
|
{
|
|
5
5
|
if (hasParameter('h') || hasParameter('help')) {
|
|
6
|
-
console.log(`
|
|
6
|
+
console.log(`Copyright (c) Matterbridge. All rights reserved.\n`);
|
|
7
|
+
console.log(`Usage: mb_mdns [options...]
|
|
8
|
+
|
|
9
|
+
If no command line is provided, mb_mdns shows all incoming mDNS records.
|
|
7
10
|
|
|
8
11
|
Options:
|
|
9
12
|
-h, --help Show this help message and exit.
|
|
10
13
|
--interfaceName <name> Network interface name to bind to (default all interfaces).
|
|
11
14
|
--ipv4InterfaceAddress <address> IPv4 address of the network interface to bind to (default: 0.0.0.0).
|
|
12
15
|
--ipv6InterfaceAddress <address> IPv6 address of the network interface to bind to (default: ::).
|
|
13
|
-
--outgoingIpv4InterfaceAddress <address> Outgoing IPv4 address (default first external address).
|
|
14
|
-
--outgoingIpv6InterfaceAddress <address> Outgoing IPv6 address (default first external address).
|
|
15
|
-
--advertise
|
|
16
|
-
--query
|
|
17
|
-
--filter <string
|
|
16
|
+
--outgoingIpv4InterfaceAddress <address> Outgoing IPv4 address of the network interface (default first external address).
|
|
17
|
+
--outgoingIpv6InterfaceAddress <address> Outgoing IPv6 address of the network interface (default first external address).
|
|
18
|
+
--advertise <interval> Enable matterbridge mDNS advertisement each ms (default interval: 10000ms).
|
|
19
|
+
--query <interval> Enable common mDNS services query each ms (default interval: 10000ms).
|
|
20
|
+
--filter <string...> Filter strings to match in the mDNS record name (default: no filter).
|
|
18
21
|
-v, --verbose Enable verbose logging (default: disabled).
|
|
19
22
|
|
|
20
23
|
Examples:
|
|
21
|
-
#
|
|
24
|
+
# Listen for Matter device commissioner service records only on eth0 interface
|
|
22
25
|
mb_mdns --interfaceName eth0 --filter _matterc._udp
|
|
23
26
|
|
|
24
|
-
#
|
|
27
|
+
# Listen for Matter device discovery service records only on eth0 interface
|
|
25
28
|
mb_mdns --interfaceName eth0 --filter _matter._tcp
|
|
26
29
|
|
|
27
|
-
#
|
|
28
|
-
mb_mdns --
|
|
30
|
+
# Listen for Matter commissioner and discovery service records on all interfaces
|
|
31
|
+
mb_mdns --filter _matterc._udp _matter._tcp
|
|
29
32
|
|
|
30
33
|
# Query for mDNS devices every 10s on a specific interface
|
|
31
34
|
mb_mdns --interfaceName eth0 --query
|
|
35
|
+
|
|
36
|
+
# Advertise matterbridge._http._tcp.local every 5s with filter
|
|
37
|
+
mb_mdns --advertise 5000 --filter matterbridge._http._tcp.local
|
|
38
|
+
|
|
39
|
+
# Query each 5s and listen for matterbridge._http._tcp.local service records
|
|
40
|
+
mb_mdns --query 5000 --filter matterbridge._http._tcp.local
|
|
41
|
+
|
|
32
42
|
`);
|
|
33
43
|
process.exit(0);
|
|
34
44
|
}
|
|
45
|
+
const { default: pkg } = await import('../../package.json', { with: { type: 'json' } });
|
|
35
46
|
const mdnsIpv4 = new Mdns('mDNS Server udp4', MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_PORT, 'udp4', true, getParameter('interfaceName'), getParameter('ipv4InterfaceAddress') || '0.0.0.0', getParameter('outgoingIpv4InterfaceAddress'));
|
|
36
47
|
const mdnsIpv6 = new Mdns('mDNS Server udp6', MDNS_MULTICAST_IPV6_ADDRESS, MDNS_MULTICAST_PORT, 'udp6', true, getParameter('interfaceName'), getParameter('ipv6InterfaceAddress') || '::', getParameter('outgoingIpv6InterfaceAddress'));
|
|
37
48
|
if (hasParameter('v') || hasParameter('verbose')) {
|
|
@@ -55,29 +66,71 @@ Examples:
|
|
|
55
66
|
mdnsIpv6.logDevices();
|
|
56
67
|
process.exit(0);
|
|
57
68
|
}
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
{ name: '
|
|
62
|
-
{ name: '_http._tcp.local', type: 12, class: 1, unicastResponse: false },
|
|
63
|
-
{ name: '_services._dns-sd._udp.local', type: 12, class: 1, unicastResponse: false },
|
|
64
|
-
]);
|
|
65
|
-
};
|
|
66
|
-
const advertiseUdp4 = () => {
|
|
67
|
-
const ptrRdata = mdnsIpv4.encodeDnsName('matterbridge._http._tcp.local');
|
|
68
|
-
mdnsIpv4.sendResponse('_http._tcp.local', 12, 1, 120, ptrRdata);
|
|
69
|
-
};
|
|
70
|
-
const queryUdp6 = () => {
|
|
71
|
-
mdnsIpv6.sendQuery([
|
|
69
|
+
const query = (mdns) => {
|
|
70
|
+
mdns.log.info('Sending mDNS query for services...');
|
|
71
|
+
mdns.sendQuery([
|
|
72
|
+
{ name: '_matterc._udp.local', type: 12, class: 1, unicastResponse: true },
|
|
72
73
|
{ name: '_matter._tcp.local', type: 12, class: 1, unicastResponse: true },
|
|
73
74
|
{ name: '_shelly._tcp.local', type: 12, class: 1, unicastResponse: true },
|
|
74
75
|
{ name: '_http._tcp.local', type: 12, class: 1, unicastResponse: true },
|
|
75
76
|
{ name: '_services._dns-sd._udp.local', type: 12, class: 1, unicastResponse: true },
|
|
76
77
|
]);
|
|
77
78
|
};
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
const advertise = (mdns) => {
|
|
80
|
+
mdns.log.info('Sending mDNS advertisement for matterbridge service...');
|
|
81
|
+
const serviceType = '_http._tcp.local';
|
|
82
|
+
const instanceName = 'matterbridge._http._tcp.local';
|
|
83
|
+
const hostName = 'matterbridge.local';
|
|
84
|
+
const port = 8283;
|
|
85
|
+
const ttl = 120;
|
|
86
|
+
const ptrInstanceRdata = mdns.encodeDnsName(instanceName);
|
|
87
|
+
const ptrServiceTypeRdata = mdns.encodeDnsName(serviceType);
|
|
88
|
+
const srvRdata = mdns.encodeSrvRdata(0, 0, port, hostName);
|
|
89
|
+
const txtRdata = mdns.encodeTxtRdata([`version=${pkg.version}`, 'path=/']);
|
|
90
|
+
const answers = [
|
|
91
|
+
{ name: '_services._dns-sd._udp.local', rtype: 12, rclass: 1, ttl, rdata: ptrServiceTypeRdata },
|
|
92
|
+
{ name: serviceType, rtype: 12, rclass: 1, ttl, rdata: ptrInstanceRdata },
|
|
93
|
+
{ name: instanceName, rtype: 33, rclass: 1 | 32768, ttl, rdata: srvRdata },
|
|
94
|
+
{ name: instanceName, rtype: 16, rclass: 1 | 32768, ttl, rdata: txtRdata },
|
|
95
|
+
];
|
|
96
|
+
try {
|
|
97
|
+
const ipv4 = mdns.getIpv4InterfaceAddress(mdns.interfaceName);
|
|
98
|
+
if (ipv4) {
|
|
99
|
+
answers.push({ name: hostName, rtype: 1, rclass: 1 | 32768, ttl, rdata: mdns.encodeA(ipv4) });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
mdns.log.warn(`Error sending mDNS advertisement for matterbridge service A record: ${error.message}`);
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
const ipv6 = mdns.getIpv6InterfaceAddress(mdns.interfaceName);
|
|
107
|
+
if (ipv6) {
|
|
108
|
+
answers.push({ name: hostName, rtype: 28, rclass: 1 | 32768, ttl, rdata: mdns.encodeAAAA(ipv6) });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
mdns.log.warn(`Error sending mDNS advertisement for matterbridge service AAAA record: ${error.message}`);
|
|
113
|
+
}
|
|
114
|
+
const response = mdns.sendResponse(answers);
|
|
115
|
+
if (hasParameter('broadcast')) {
|
|
116
|
+
try {
|
|
117
|
+
const address = mdns.socketType === 'udp4' ? mdns.getIpv4InterfaceAddress(mdns.interfaceName) : mdns.getIpv6InterfaceAddress(mdns.interfaceName);
|
|
118
|
+
const mask = mdns.socketType === 'udp4' ? mdns.getNetmask(address) : undefined;
|
|
119
|
+
const broadcastAddress = mdns.socketType === 'udp4' ? mdns.getIpv4BroadcastAddress(address, mask) : mdns.getIpv6BroadcastAddress();
|
|
120
|
+
mdns.log.info(`Broadcasting mDNS advertisement for matterbridge service to ${broadcastAddress}...`);
|
|
121
|
+
mdns.socket.send(response, 0, response.length, mdns.multicastPort, broadcastAddress, (error) => {
|
|
122
|
+
if (error) {
|
|
123
|
+
mdns.log.error(`Error broadcasting mDNS advertisement: ${error.message}`);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
mdns.log.info(`mDNS advertisement broadcasted successfully to ${broadcastAddress}`);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
mdns.log.error(`Error broadcasting mDNS advertisement: ${error.message}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
81
134
|
};
|
|
82
135
|
process.on('SIGINT', () => {
|
|
83
136
|
cleanupAndLogAndExit();
|
|
@@ -85,33 +138,33 @@ Examples:
|
|
|
85
138
|
mdnsIpv4.start();
|
|
86
139
|
mdnsIpv4.on('ready', (address) => {
|
|
87
140
|
mdnsIpv4.log.info(`mdnsIpv4 server ready on ${address.family} ${address.address}:${address.port}`);
|
|
88
|
-
if (
|
|
89
|
-
|
|
141
|
+
if (hasParameter('advertise')) {
|
|
142
|
+
advertise(mdnsIpv4);
|
|
90
143
|
setInterval(() => {
|
|
91
|
-
|
|
92
|
-
}, 10000).unref();
|
|
144
|
+
advertise(mdnsIpv4);
|
|
145
|
+
}, getIntParameter('advertise') || 10000).unref();
|
|
93
146
|
}
|
|
94
|
-
if (
|
|
95
|
-
|
|
147
|
+
if (hasParameter('query')) {
|
|
148
|
+
query(mdnsIpv4);
|
|
96
149
|
setInterval(() => {
|
|
97
|
-
|
|
98
|
-
}, 10000).unref();
|
|
150
|
+
query(mdnsIpv4);
|
|
151
|
+
}, getIntParameter('query') || 10000).unref();
|
|
99
152
|
}
|
|
100
153
|
});
|
|
101
154
|
mdnsIpv6.start();
|
|
102
155
|
mdnsIpv6.on('ready', (address) => {
|
|
103
156
|
mdnsIpv6.log.info(`mdnsIpv6 server ready on ${address.family} ${address.address}:${address.port}`);
|
|
104
|
-
if (
|
|
105
|
-
|
|
157
|
+
if (hasParameter('advertise')) {
|
|
158
|
+
advertise(mdnsIpv6);
|
|
106
159
|
setInterval(() => {
|
|
107
|
-
|
|
108
|
-
}, 10000).unref();
|
|
160
|
+
advertise(mdnsIpv6);
|
|
161
|
+
}, getIntParameter('advertise') || 10000).unref();
|
|
109
162
|
}
|
|
110
|
-
if (
|
|
111
|
-
|
|
163
|
+
if (hasParameter('query')) {
|
|
164
|
+
query(mdnsIpv6);
|
|
112
165
|
setInterval(() => {
|
|
113
|
-
|
|
114
|
-
}, 10000).unref();
|
|
166
|
+
query(mdnsIpv6);
|
|
167
|
+
}, getIntParameter('query') || 10000).unref();
|
|
115
168
|
}
|
|
116
169
|
});
|
|
117
170
|
setTimeout(() => {
|
package/dist/dgram/mdns.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BLUE, CYAN, db, er, GREEN, idn, MAGENTA, nf, rs } from 'node-ansi-logger';
|
|
2
|
+
import { hasParameter } from '../utils/commandLine.js';
|
|
2
3
|
import { Multicast } from './multicast.js';
|
|
3
4
|
export var DnsRecordType;
|
|
4
5
|
(function (DnsRecordType) {
|
|
@@ -271,6 +272,56 @@ export class Mdns extends Multicast {
|
|
|
271
272
|
});
|
|
272
273
|
return Buffer.concat([...buffers, Buffer.from([0])]);
|
|
273
274
|
}
|
|
275
|
+
encodeTxtRdata(txt) {
|
|
276
|
+
const parts = txt.map((entry) => {
|
|
277
|
+
const value = Buffer.from(entry, 'utf8');
|
|
278
|
+
if (value.length > 255)
|
|
279
|
+
throw new Error(`TXT entry too long: ${entry}`);
|
|
280
|
+
return Buffer.concat([Buffer.from([value.length]), value]);
|
|
281
|
+
});
|
|
282
|
+
return Buffer.concat(parts);
|
|
283
|
+
}
|
|
284
|
+
encodeSrvRdata(priority, weight, port, target) {
|
|
285
|
+
const fixed = Buffer.alloc(6);
|
|
286
|
+
fixed.writeUInt16BE(priority, 0);
|
|
287
|
+
fixed.writeUInt16BE(weight, 2);
|
|
288
|
+
fixed.writeUInt16BE(port, 4);
|
|
289
|
+
return Buffer.concat([fixed, this.encodeDnsName(target)]);
|
|
290
|
+
}
|
|
291
|
+
encodeA(ipv4) {
|
|
292
|
+
const parts = ipv4.split('.').map((p) => Number(p));
|
|
293
|
+
if (parts.length !== 4 || parts.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) {
|
|
294
|
+
throw new Error(`Invalid IPv4 address: ${ipv4}`);
|
|
295
|
+
}
|
|
296
|
+
return Buffer.from(parts);
|
|
297
|
+
}
|
|
298
|
+
encodeAAAA(ipv6WithOptionalScope) {
|
|
299
|
+
const ipv6 = ipv6WithOptionalScope.split('%')[0];
|
|
300
|
+
const [left, right] = ipv6.split('::');
|
|
301
|
+
const leftParts = left ? left.split(':').filter(Boolean) : [];
|
|
302
|
+
const rightParts = right ? right.split(':').filter(Boolean) : [];
|
|
303
|
+
if (ipv6.includes('::')) {
|
|
304
|
+
const missing = 8 - (leftParts.length + rightParts.length);
|
|
305
|
+
if (missing < 0)
|
|
306
|
+
throw new Error(`Invalid IPv6 address: ${ipv6WithOptionalScope}`);
|
|
307
|
+
const groups = [...leftParts, ...Array(missing).fill('0'), ...rightParts];
|
|
308
|
+
return Buffer.from(groups.flatMap((g) => {
|
|
309
|
+
const word = parseInt(g || '0', 16);
|
|
310
|
+
if (!Number.isFinite(word) || word < 0 || word > 0xffff)
|
|
311
|
+
throw new Error(`Invalid IPv6 group: ${g}`);
|
|
312
|
+
return [(word >> 8) & 0xff, word & 0xff];
|
|
313
|
+
}));
|
|
314
|
+
}
|
|
315
|
+
const groups = ipv6.split(':');
|
|
316
|
+
if (groups.length !== 8)
|
|
317
|
+
throw new Error(`Invalid IPv6 address: ${ipv6WithOptionalScope}`);
|
|
318
|
+
return Buffer.from(groups.flatMap((g) => {
|
|
319
|
+
const word = parseInt(g || '0', 16);
|
|
320
|
+
if (!Number.isFinite(word) || word < 0 || word > 0xffff)
|
|
321
|
+
throw new Error(`Invalid IPv6 group: ${g}`);
|
|
322
|
+
return [(word >> 8) & 0xff, word & 0xff];
|
|
323
|
+
}));
|
|
324
|
+
}
|
|
274
325
|
decodeResourceRecord(msg, offset) {
|
|
275
326
|
const nameResult = this.decodeDnsName(msg, offset);
|
|
276
327
|
const name = nameResult.name;
|
|
@@ -383,8 +434,10 @@ export class Mdns extends Multicast {
|
|
|
383
434
|
return Buffer.concat([qname, qfields]);
|
|
384
435
|
});
|
|
385
436
|
const query = Buffer.concat([header, ...questionBuffers]);
|
|
386
|
-
|
|
387
|
-
|
|
437
|
+
if (hasParameter('v') || hasParameter('verbose')) {
|
|
438
|
+
const decoded = this.decodeMdnsMessage(query);
|
|
439
|
+
this.logMdnsMessage(decoded);
|
|
440
|
+
}
|
|
388
441
|
this.socket.send(query, 0, query.length, this.multicastPort, this.multicastAddress, (error) => {
|
|
389
442
|
if (error) {
|
|
390
443
|
this.log.error(`Dgram mDNS server failed to send query message: ${error.message}`);
|
|
@@ -398,33 +451,46 @@ export class Mdns extends Multicast {
|
|
|
398
451
|
this.emit('sent', query, this.multicastAddress, this.multicastPort);
|
|
399
452
|
}
|
|
400
453
|
});
|
|
454
|
+
return query;
|
|
401
455
|
}
|
|
402
|
-
sendResponse(
|
|
456
|
+
sendResponse(answers) {
|
|
457
|
+
if (!Array.isArray(answers) || answers.length === 0) {
|
|
458
|
+
throw new Error('sendResponse requires a non-empty answers array');
|
|
459
|
+
}
|
|
403
460
|
const header = Buffer.alloc(12);
|
|
404
461
|
header.writeUInt16BE(0, 0);
|
|
405
462
|
header.writeUInt16BE(0x8400, 2);
|
|
406
463
|
header.writeUInt16BE(0, 4);
|
|
407
|
-
header.writeUInt16BE(
|
|
464
|
+
header.writeUInt16BE(answers.length, 6);
|
|
408
465
|
header.writeUInt16BE(0, 8);
|
|
409
466
|
header.writeUInt16BE(0, 10);
|
|
410
|
-
const
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
467
|
+
const answerBuffers = answers.map(({ name, rtype, rclass, ttl, rdata }) => {
|
|
468
|
+
const aname = this.encodeDnsName(name);
|
|
469
|
+
const answerFixed = Buffer.alloc(10);
|
|
470
|
+
answerFixed.writeUInt16BE(rtype, 0);
|
|
471
|
+
answerFixed.writeUInt16BE(rclass, 2);
|
|
472
|
+
answerFixed.writeUInt32BE(ttl, 4);
|
|
473
|
+
answerFixed.writeUInt16BE(rdata.length, 8);
|
|
474
|
+
return Buffer.concat([aname, answerFixed, rdata]);
|
|
475
|
+
});
|
|
476
|
+
const response = Buffer.concat([header, ...answerBuffers]);
|
|
477
|
+
if (hasParameter('v') || hasParameter('verbose')) {
|
|
478
|
+
const decoded = this.decodeMdnsMessage(response);
|
|
479
|
+
this.logMdnsMessage(decoded);
|
|
480
|
+
}
|
|
418
481
|
this.socket.send(response, 0, response.length, this.multicastPort, this.multicastAddress, (error) => {
|
|
419
482
|
if (error) {
|
|
420
|
-
|
|
483
|
+
const items = answers.map((a) => `- name ${MAGENTA}${a.name}${er} type ${MAGENTA}${this.dnsTypeToString(a.rtype)}${er} class ${MAGENTA}${this.dnsResponseClassToString(a.rclass)}${er} ttl ${MAGENTA}${a.ttl}${er}`).join('\n');
|
|
484
|
+
this.log.error(`Dgram mDNS server failed to send response message (${MAGENTA}${answers.length}${er} answers): ${error instanceof Error ? error.message : error}\n${items}`);
|
|
421
485
|
this.emit('error', error);
|
|
422
486
|
}
|
|
423
487
|
else {
|
|
424
|
-
|
|
488
|
+
const items = answers.map((a) => `- name ${MAGENTA}${a.name}${db} type ${MAGENTA}${this.dnsTypeToString(a.rtype)}${db} class ${MAGENTA}${this.dnsResponseClassToString(a.rclass)}${db} ttl ${MAGENTA}${a.ttl}${db}`).join('\n');
|
|
489
|
+
this.log.debug(`Dgram mDNS server sent response message:\n${items}`);
|
|
425
490
|
this.emit('sent', response, this.multicastAddress, this.multicastPort);
|
|
426
491
|
}
|
|
427
492
|
});
|
|
493
|
+
return response;
|
|
428
494
|
}
|
|
429
495
|
dnsTypeToString(type) {
|
|
430
496
|
const typeMap = {
|
package/dist/utils/network.js
CHANGED
|
@@ -41,13 +41,24 @@ export function getIpv4InterfaceAddress() {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
-
export function getIpv6InterfaceAddress() {
|
|
44
|
+
export function getIpv6InterfaceAddress(scope = false) {
|
|
45
45
|
for (const [interfaceName, interfaceDetails] of Object.entries(os.networkInterfaces())) {
|
|
46
46
|
if (!interfaceName || !interfaceDetails || interfaceDetails.length === 0)
|
|
47
47
|
continue;
|
|
48
48
|
for (const detail of interfaceDetails) {
|
|
49
|
-
if (detail.family === 'IPv6' && !detail.internal)
|
|
50
|
-
|
|
49
|
+
if (detail.family === 'IPv6' && !detail.internal) {
|
|
50
|
+
const address = detail.address;
|
|
51
|
+
if (!scope)
|
|
52
|
+
return address;
|
|
53
|
+
if (address.includes('%'))
|
|
54
|
+
return address;
|
|
55
|
+
const isWindows = os.platform() === 'win32';
|
|
56
|
+
const zoneId = isWindows ? detail.scopeid : interfaceName;
|
|
57
|
+
if (zoneId !== undefined && zoneId !== null && `${zoneId}`.length > 0) {
|
|
58
|
+
return `${address}%${zoneId}`;
|
|
59
|
+
}
|
|
60
|
+
return address;
|
|
61
|
+
}
|
|
51
62
|
}
|
|
52
63
|
}
|
|
53
64
|
}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge",
|
|
3
|
-
"version": "3.4.5-dev-20251224-
|
|
3
|
+
"version": "3.4.5-dev-20251224-457def5",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "matterbridge",
|
|
9
|
-
"version": "3.4.5-dev-20251224-
|
|
9
|
+
"version": "3.4.5-dev-20251224-457def5",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@matter/main": "0.15.6",
|
package/package.json
CHANGED