matterbridge 3.4.6-dev-20251228-e06f048 → 3.4.6-dev-20251228-a2d4bd7
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 -4
- package/dist/dgram/mb_mdns.js +9 -1
- package/dist/dgram/mdns.js +35 -15
- package/dist/dgram/mdnsReflectorClient.js +83 -15
- package/dist/dgram/mdnsReflectorServer.js +67 -21
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -32,11 +32,14 @@ Advantages:
|
|
|
32
32
|
|
|
33
33
|
### Added
|
|
34
34
|
|
|
35
|
+
- [MdnsReflectorClient]: Added already seen cache.
|
|
36
|
+
- [MdnsReflectorServer]: Added --share-with-clients to share mDNS between all reflector clients.
|
|
37
|
+
- [reflector]: [Full guide](https://github.com/Luligu/matterbridge/blob/dev/docker-reflector/Docker%20reflector.md).
|
|
38
|
+
|
|
35
39
|
### Changed
|
|
36
40
|
|
|
37
41
|
- [package]: Updated dependencies.
|
|
38
|
-
|
|
39
|
-
### Fixed
|
|
42
|
+
- [reflector]: Bumped `reflector` version to v.1.1.0.
|
|
40
43
|
|
|
41
44
|
<a href="https://www.buymeacoffee.com/luligugithub"><img src="https://matterbridge.io/bmc-button.svg" alt="Buy me a coffee" width="80"></a>
|
|
42
45
|
|
|
@@ -57,8 +60,6 @@ Advantages:
|
|
|
57
60
|
|
|
58
61
|
- [package]: Updated dependencies.
|
|
59
62
|
|
|
60
|
-
### Fixed
|
|
61
|
-
|
|
62
63
|
<a href="https://www.buymeacoffee.com/luligugithub"><img src="https://matterbridge.io/bmc-button.svg" alt="Buy me a coffee" width="80"></a>
|
|
63
64
|
|
|
64
65
|
## [3.4.4] - 2025-12-19
|
package/dist/dgram/mb_mdns.js
CHANGED
|
@@ -25,7 +25,13 @@ Options:
|
|
|
25
25
|
--noIpv6 Disable IPv6 mDNS server (default: enabled).
|
|
26
26
|
--no-timeout Disable automatic timeout of 10 minutes. Reflector mode disables timeout automatically.
|
|
27
27
|
--reflector-client Enable mDNS reflector client (default: disabled).
|
|
28
|
+
--filter <string[]> Filters to apply to incoming mDNS messages.
|
|
29
|
+
--localhost Use localhost addresses to send messages to the container.
|
|
28
30
|
--reflector-server Enable mDNS reflector server (default: disabled).
|
|
31
|
+
--filter <string[]> Filters to apply to incoming mDNS messages.
|
|
32
|
+
--broadcast Use broadcast addresses to reflect messages to the lan.
|
|
33
|
+
--localhost Use localhost addresses to reflect messages to the lan.
|
|
34
|
+
--share-with-clients Share messages between reflector clients.
|
|
29
35
|
-d, --debug Enable debug logging (default: disabled).
|
|
30
36
|
-v, --verbose Enable verbose logging (default: disabled).
|
|
31
37
|
-s, --silent Enable silent mode, only log notices, warnings and errors.
|
|
@@ -81,7 +87,7 @@ Examples:
|
|
|
81
87
|
await reflectorServer?.stop();
|
|
82
88
|
}
|
|
83
89
|
const query = (mdns) => {
|
|
84
|
-
mdns.log.info('Sending mDNS query for services...');
|
|
90
|
+
mdns.log.info('Sending mDNS query for common services...');
|
|
85
91
|
mdns.sendQuery([
|
|
86
92
|
{ name: '_matterc._udp.local', type: 12, class: 1, unicastResponse: true },
|
|
87
93
|
{ name: '_matter._tcp.local', type: 12, class: 1, unicastResponse: true },
|
|
@@ -154,6 +160,7 @@ Examples:
|
|
|
154
160
|
mdnsIpv4.filters.push(...filters);
|
|
155
161
|
mdnsIpv4.start();
|
|
156
162
|
mdnsIpv4.on('ready', (address) => {
|
|
163
|
+
mdnsIpv4?.socket.setMulticastLoopback(false);
|
|
157
164
|
mdnsIpv4?.log.info(`mdnsIpv4 server ready on ${address.family} ${address.address}:${address.port}`);
|
|
158
165
|
if (hasParameter('advertise')) {
|
|
159
166
|
advertise(mdnsIpv4);
|
|
@@ -174,6 +181,7 @@ Examples:
|
|
|
174
181
|
mdnsIpv6.filters.push(...filters);
|
|
175
182
|
mdnsIpv6.start();
|
|
176
183
|
mdnsIpv6.on('ready', (address) => {
|
|
184
|
+
mdnsIpv6?.socket.setMulticastLoopback(false);
|
|
177
185
|
mdnsIpv6?.log.info(`mdnsIpv6 server ready on ${address.family} ${address.address}:${address.port}`);
|
|
178
186
|
if (hasParameter('advertise')) {
|
|
179
187
|
advertise(mdnsIpv6);
|
package/dist/dgram/mdns.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BLUE, CYAN, db,
|
|
1
|
+
import { BLUE, CYAN, db, GREEN, idn, MAGENTA, nf, rs } from 'node-ansi-logger';
|
|
2
2
|
import { hasParameter } from '../utils/commandLine.js';
|
|
3
3
|
import { Multicast } from './multicast.js';
|
|
4
4
|
export var DnsRecordType;
|
|
@@ -106,6 +106,28 @@ export var DnsClassFlag;
|
|
|
106
106
|
DnsClassFlag[DnsClassFlag["FLUSH"] = 32768] = "FLUSH";
|
|
107
107
|
DnsClassFlag[DnsClassFlag["QU"] = 32768] = "QU";
|
|
108
108
|
})(DnsClassFlag || (DnsClassFlag = {}));
|
|
109
|
+
export function isMdns(message) {
|
|
110
|
+
if (!message || message.length < 12)
|
|
111
|
+
return false;
|
|
112
|
+
const id = message.readUInt16BE(0);
|
|
113
|
+
return id === 0;
|
|
114
|
+
}
|
|
115
|
+
export function isMdnsQuery(message) {
|
|
116
|
+
if (message.length < 12)
|
|
117
|
+
return false;
|
|
118
|
+
const id = message.readUInt16BE(0);
|
|
119
|
+
const flags = message.readUInt16BE(2);
|
|
120
|
+
const qr = (flags & 0x8000) >> 15;
|
|
121
|
+
return id == 0 && qr === 0;
|
|
122
|
+
}
|
|
123
|
+
export function isMdnsResponse(message) {
|
|
124
|
+
if (message.length < 12)
|
|
125
|
+
return false;
|
|
126
|
+
const id = message.readUInt16BE(0);
|
|
127
|
+
const flags = message.readUInt16BE(2);
|
|
128
|
+
const qr = (flags & 0x8000) >> 15;
|
|
129
|
+
return id == 0 && qr === 1;
|
|
130
|
+
}
|
|
109
131
|
export class Mdns extends Multicast {
|
|
110
132
|
deviceQueries = new Map();
|
|
111
133
|
deviceResponses = new Map();
|
|
@@ -306,9 +328,10 @@ export class Mdns extends Multicast {
|
|
|
306
328
|
throw new Error(`Invalid IPv6 address: ${ipv6WithOptionalScope}`);
|
|
307
329
|
const groups = [...leftParts, ...Array(missing).fill('0'), ...rightParts];
|
|
308
330
|
return Buffer.from(groups.flatMap((g) => {
|
|
309
|
-
const word = parseInt(g
|
|
310
|
-
if (!Number.isFinite(word) || word < 0 || word > 0xffff)
|
|
331
|
+
const word = parseInt(g, 16);
|
|
332
|
+
if (!Number.isFinite(word) || word < 0 || word > 0xffff) {
|
|
311
333
|
throw new Error(`Invalid IPv6 group: ${g}`);
|
|
334
|
+
}
|
|
312
335
|
return [(word >> 8) & 0xff, word & 0xff];
|
|
313
336
|
}));
|
|
314
337
|
}
|
|
@@ -316,7 +339,9 @@ export class Mdns extends Multicast {
|
|
|
316
339
|
if (groups.length !== 8)
|
|
317
340
|
throw new Error(`Invalid IPv6 address: ${ipv6WithOptionalScope}`);
|
|
318
341
|
return Buffer.from(groups.flatMap((g) => {
|
|
319
|
-
|
|
342
|
+
if (!g)
|
|
343
|
+
throw new Error(`Invalid IPv6 group: ${g}`);
|
|
344
|
+
const word = parseInt(g, 16);
|
|
320
345
|
if (!Number.isFinite(word) || word < 0 || word > 0xffff)
|
|
321
346
|
throw new Error(`Invalid IPv6 group: ${g}`);
|
|
322
347
|
return [(word >> 8) & 0xff, word & 0xff];
|
|
@@ -436,18 +461,15 @@ export class Mdns extends Multicast {
|
|
|
436
461
|
const query = Buffer.concat([header, ...questionBuffers]);
|
|
437
462
|
if (hasParameter('v') || hasParameter('verbose')) {
|
|
438
463
|
const decoded = this.decodeMdnsMessage(query);
|
|
439
|
-
this.logMdnsMessage(decoded);
|
|
464
|
+
this.logMdnsMessage(decoded, undefined, 'Sending query mDNS message');
|
|
440
465
|
}
|
|
441
466
|
this.socket.send(query, 0, query.length, this.multicastPort, this.multicastAddress, (error) => {
|
|
442
467
|
if (error) {
|
|
443
|
-
this.log.error(`Dgram mDNS server failed to send query message: ${error.message}`);
|
|
468
|
+
this.log.error(`Dgram mDNS server failed to send query message: ${error instanceof Error ? error.message : error}`);
|
|
444
469
|
this.emit('error', error);
|
|
445
470
|
}
|
|
446
471
|
else {
|
|
447
|
-
|
|
448
|
-
.map((q) => `- name ${MAGENTA}${q.name}${db} type ${MAGENTA}${this.dnsTypeToString(q.type)}${db} class ${MAGENTA}${this.dnsQuestionClassToString(q.class)}${db} unicastResponse ${MAGENTA}${q.unicastResponse}${db}`)
|
|
449
|
-
.join('\n');
|
|
450
|
-
this.log.debug(`Dgram mDNS server sent query message:\n${names}`);
|
|
472
|
+
this.log.debug(`Dgram mDNS server sent query message`);
|
|
451
473
|
this.emit('sent', query, this.multicastAddress, this.multicastPort);
|
|
452
474
|
}
|
|
453
475
|
});
|
|
@@ -476,17 +498,15 @@ export class Mdns extends Multicast {
|
|
|
476
498
|
const response = Buffer.concat([header, ...answerBuffers]);
|
|
477
499
|
if (hasParameter('v') || hasParameter('verbose')) {
|
|
478
500
|
const decoded = this.decodeMdnsMessage(response);
|
|
479
|
-
this.logMdnsMessage(decoded);
|
|
501
|
+
this.logMdnsMessage(decoded, undefined, 'Sending response mDNS message');
|
|
480
502
|
}
|
|
481
503
|
this.socket.send(response, 0, response.length, this.multicastPort, this.multicastAddress, (error) => {
|
|
482
504
|
if (error) {
|
|
483
|
-
|
|
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}`);
|
|
505
|
+
this.log.error(`Dgram mDNS server failed to send response message: ${error instanceof Error ? error.message : error}`);
|
|
485
506
|
this.emit('error', error);
|
|
486
507
|
}
|
|
487
508
|
else {
|
|
488
|
-
|
|
489
|
-
this.log.debug(`Dgram mDNS server sent response message:\n${items}`);
|
|
509
|
+
this.log.debug(`Dgram mDNS server sent response message`);
|
|
490
510
|
this.emit('sent', response, this.multicastAddress, this.multicastPort);
|
|
491
511
|
}
|
|
492
512
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import { AnsiLogger, BLUE, nt, nf } from 'node-ansi-logger';
|
|
2
3
|
import { getStringArrayParameter, hasParameter } from '../utils/commandLine.js';
|
|
3
|
-
import { Mdns } from './mdns.js';
|
|
4
|
+
import { isMdns, isMdnsQuery, Mdns } from './mdns.js';
|
|
4
5
|
import { MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_IPV6_ADDRESS, MDNS_MULTICAST_PORT } from './multicast.js';
|
|
5
6
|
import { Unicast } from './unicast.js';
|
|
6
7
|
import { MDNS_REFLECTOR_ADDRESS, MDNS_REFLECTOR_BIND_ADDRESS_IPV4, MDNS_REFLECTOR_BIND_ADDRESS_IPV6, MDNS_REFLECTOR_HOST_DOCKER, MDNS_REFLECTOR_PORT } from './mdnsReflectorTypes.js';
|
|
@@ -13,22 +14,51 @@ export class MdnsReflectorClient {
|
|
|
13
14
|
mdnsIpv6 = new Mdns('mDNS udp6 Server', MDNS_MULTICAST_IPV6_ADDRESS, MDNS_MULTICAST_PORT, 'udp6', true, undefined, MDNS_REFLECTOR_BIND_ADDRESS_IPV6);
|
|
14
15
|
unicastIpv4 = new Unicast('mDNS udp4 Reflector Client', 'udp4', false, undefined, MDNS_REFLECTOR_BIND_ADDRESS_IPV4);
|
|
15
16
|
unicastIpv6 = new Unicast('mDNS udp6 Reflector Client', 'udp6', false, undefined, MDNS_REFLECTOR_BIND_ADDRESS_IPV6);
|
|
17
|
+
reflectedIpv4 = new Map();
|
|
18
|
+
reflectedIpv6 = new Map();
|
|
19
|
+
TTL_MS = 1500;
|
|
16
20
|
constructor() {
|
|
17
21
|
this.log.logNameColor = '\x1b[38;5;97m';
|
|
18
22
|
this.mdnsIpv4.log.logNameColor = '\x1b[38;5;97m';
|
|
19
|
-
this.
|
|
23
|
+
if (!this.debug && !this.verbose && !this.silent)
|
|
24
|
+
this.mdnsIpv4.log.logLevel = "warn";
|
|
20
25
|
this.mdnsIpv6.log.logNameColor = '\x1b[38;5;97m';
|
|
21
|
-
this.
|
|
26
|
+
if (!this.debug && !this.verbose && !this.silent)
|
|
27
|
+
this.mdnsIpv6.log.logLevel = "warn";
|
|
22
28
|
this.unicastIpv4.log.logNameColor = '\x1b[38;5;97m';
|
|
23
|
-
this.
|
|
29
|
+
if (!this.debug && !this.verbose && !this.silent)
|
|
30
|
+
this.unicastIpv4.log.logLevel = "warn";
|
|
24
31
|
this.unicastIpv6.log.logNameColor = '\x1b[38;5;97m';
|
|
25
|
-
this.
|
|
32
|
+
if (!this.debug && !this.verbose && !this.silent)
|
|
33
|
+
this.unicastIpv6.log.logLevel = "warn";
|
|
26
34
|
const filters = getStringArrayParameter('filter');
|
|
27
35
|
if (filters)
|
|
28
36
|
this.mdnsIpv4.filters.push(...filters);
|
|
29
37
|
if (filters)
|
|
30
38
|
this.mdnsIpv6.filters.push(...filters);
|
|
31
39
|
}
|
|
40
|
+
fingerprint(buf) {
|
|
41
|
+
return crypto.createHash('sha1').update(buf).digest('hex');
|
|
42
|
+
}
|
|
43
|
+
remember(cache, key, ttlMs) {
|
|
44
|
+
cache.set(key, Date.now() + ttlMs);
|
|
45
|
+
}
|
|
46
|
+
seenRecently(cache, key) {
|
|
47
|
+
const exp = cache.get(key);
|
|
48
|
+
if (!exp)
|
|
49
|
+
return false;
|
|
50
|
+
if (exp < Date.now()) {
|
|
51
|
+
cache.delete(key);
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
prune(cache) {
|
|
57
|
+
const now = Date.now();
|
|
58
|
+
for (const [k, exp] of cache)
|
|
59
|
+
if (exp < now)
|
|
60
|
+
cache.delete(k);
|
|
61
|
+
}
|
|
32
62
|
async start() {
|
|
33
63
|
this.log.notice('mDNS Reflector Client starting...');
|
|
34
64
|
this.mdnsIpv4.on('error', (err) => {
|
|
@@ -61,41 +91,79 @@ export class MdnsReflectorClient {
|
|
|
61
91
|
this.unicastIpv6.start();
|
|
62
92
|
});
|
|
63
93
|
await Promise.all(promises);
|
|
94
|
+
this.mdnsIpv4.socket.setMulticastLoopback(false);
|
|
95
|
+
this.mdnsIpv6.socket.setMulticastLoopback(false);
|
|
64
96
|
this.mdnsIpv4.on('message', (msg, rinfo) => {
|
|
65
|
-
this.
|
|
97
|
+
if (this.seenRecently(this.reflectedIpv4, this.fingerprint(msg))) {
|
|
98
|
+
this.log.info(`Ignoring recently reflected ${isMdnsQuery(msg) ? 'query' : 'response'} message from mDNS ipv4 multicast ${BLUE}${rinfo.address}${nf}:${BLUE}${rinfo.port}${nf}`);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
this.log.notice(`Sending ${isMdnsQuery(msg) ? 'query' : 'response'} message from mDNS ipv4 multicast ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to ipv4 reflector server`);
|
|
66
102
|
this.unicastIpv4.send(msg, MDNS_REFLECTOR_HOST_DOCKER, MDNS_REFLECTOR_PORT);
|
|
67
103
|
this.unicastIpv4.send(msg, MDNS_REFLECTOR_ADDRESS, MDNS_REFLECTOR_PORT);
|
|
68
104
|
});
|
|
69
105
|
this.mdnsIpv6.on('message', (msg, rinfo) => {
|
|
70
|
-
this.
|
|
106
|
+
if (this.seenRecently(this.reflectedIpv6, this.fingerprint(msg))) {
|
|
107
|
+
this.log.info(`Ignoring recently reflected ${isMdnsQuery(msg) ? 'query' : 'response'} message from mDNS ipv6 multicast ${BLUE}${rinfo.address}${nf}:${BLUE}${rinfo.port}${nf}`);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
this.log.notice(`Sending ${isMdnsQuery(msg) ? 'query' : 'response'} message from mDNS ipv6 multicast ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to ipv6 reflector server`);
|
|
71
111
|
this.unicastIpv6.send(msg, MDNS_REFLECTOR_HOST_DOCKER, MDNS_REFLECTOR_PORT);
|
|
72
112
|
this.unicastIpv6.send(msg, MDNS_REFLECTOR_ADDRESS, MDNS_REFLECTOR_PORT);
|
|
73
113
|
});
|
|
74
114
|
this.unicastIpv4.on('message', (msg, rinfo) => {
|
|
75
|
-
|
|
115
|
+
if (isMdns(msg)) {
|
|
116
|
+
this.remember(this.reflectedIpv4, this.fingerprint(msg), this.TTL_MS);
|
|
117
|
+
this.prune(this.reflectedIpv4);
|
|
118
|
+
this.log.notice(`Reflecting ${isMdnsQuery(msg) ? 'query' : 'response'} message from reflector server on ipv4 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to mDNS ipv4 multicast`);
|
|
119
|
+
this.mdnsIpv4.send(msg, MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_PORT);
|
|
120
|
+
if (hasParameter('localhost')) {
|
|
121
|
+
this.log.notice(`Reflecting ${isMdnsQuery(msg) ? 'query' : 'response'} message from reflector server on ipv4 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to mDNS ipv4 localhost`);
|
|
122
|
+
this.mdnsIpv4.send(msg, 'localhost', MDNS_MULTICAST_PORT);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
this.log.info(`Received message from reflector server on ipv4 ${BLUE}${rinfo.address}${nf}:${BLUE}${rinfo.port}${nf}: ${msg.toString()}`);
|
|
127
|
+
}
|
|
76
128
|
});
|
|
77
129
|
this.unicastIpv6.on('message', (msg, rinfo) => {
|
|
78
|
-
|
|
79
|
-
|
|
130
|
+
if (isMdns(msg)) {
|
|
131
|
+
this.remember(this.reflectedIpv6, this.fingerprint(msg), this.TTL_MS);
|
|
132
|
+
this.prune(this.reflectedIpv6);
|
|
133
|
+
this.log.notice(`Reflecting ${isMdnsQuery(msg) ? 'query' : 'response'} message from reflector server on ipv6 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to mDNS ipv6 multicast`);
|
|
134
|
+
this.mdnsIpv6.send(msg, MDNS_MULTICAST_IPV6_ADDRESS, MDNS_MULTICAST_PORT);
|
|
135
|
+
if (hasParameter('localhost')) {
|
|
136
|
+
this.log.notice(`Reflecting ${isMdnsQuery(msg) ? 'query' : 'response'} message from reflector server on ipv6 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to mDNS ipv6 localhost`);
|
|
137
|
+
this.mdnsIpv6.send(msg, 'localhost', MDNS_MULTICAST_PORT);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
this.log.info(`Received message from reflector server on ipv6 ${BLUE}${rinfo.address}${nf}:${BLUE}${rinfo.port}${nf}: ${msg.toString()}`);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
this.unicastIpv4.send(Buffer.from('Ipv4 reflector client started'), MDNS_REFLECTOR_HOST_DOCKER, MDNS_REFLECTOR_PORT);
|
|
145
|
+
this.unicastIpv4.send(Buffer.from('Ipv4 reflector client started'), MDNS_REFLECTOR_ADDRESS, MDNS_REFLECTOR_PORT);
|
|
146
|
+
this.unicastIpv6.send(Buffer.from('Ipv6 reflector client started'), MDNS_REFLECTOR_HOST_DOCKER, MDNS_REFLECTOR_PORT);
|
|
147
|
+
this.unicastIpv6.send(Buffer.from('Ipv6 reflector client started'), MDNS_REFLECTOR_ADDRESS, MDNS_REFLECTOR_PORT);
|
|
80
148
|
this.log.notice('mDNS Reflector Client started.');
|
|
81
149
|
}
|
|
82
150
|
async stop() {
|
|
83
151
|
this.log.notice('mDNS Reflector Client stopping...');
|
|
84
152
|
const promises = [];
|
|
85
153
|
promises[0] = new Promise((resolve) => {
|
|
86
|
-
this.mdnsIpv4.once('
|
|
154
|
+
this.mdnsIpv4.once('close', () => resolve());
|
|
87
155
|
this.mdnsIpv4.stop();
|
|
88
156
|
});
|
|
89
157
|
promises[1] = new Promise((resolve) => {
|
|
90
|
-
this.mdnsIpv6.once('
|
|
158
|
+
this.mdnsIpv6.once('close', () => resolve());
|
|
91
159
|
this.mdnsIpv6.stop();
|
|
92
160
|
});
|
|
93
161
|
promises[2] = new Promise((resolve) => {
|
|
94
|
-
this.unicastIpv4.once('
|
|
162
|
+
this.unicastIpv4.once('close', () => resolve());
|
|
95
163
|
this.unicastIpv4.stop();
|
|
96
164
|
});
|
|
97
165
|
promises[3] = new Promise((resolve) => {
|
|
98
|
-
this.unicastIpv6.once('
|
|
166
|
+
this.unicastIpv6.once('close', () => resolve());
|
|
99
167
|
this.unicastIpv6.stop();
|
|
100
168
|
});
|
|
101
169
|
await Promise.all(promises);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import os from 'node:os';
|
|
2
|
-
import { AnsiLogger, BLUE, nt } from 'node-ansi-logger';
|
|
2
|
+
import { AnsiLogger, BLUE, nt, nf } from 'node-ansi-logger';
|
|
3
3
|
import { hasParameter, getStringArrayParameter } from '../utils/commandLine.js';
|
|
4
|
-
import { Mdns } from './mdns.js';
|
|
4
|
+
import { isMdns, isMdnsQuery, isMdnsResponse, Mdns } from './mdns.js';
|
|
5
5
|
import { MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_IPV6_ADDRESS, MDNS_MULTICAST_PORT } from './multicast.js';
|
|
6
6
|
import { Unicast } from './unicast.js';
|
|
7
7
|
import { MDNS_REFLECTOR_BIND_ADDRESS_IPV4, MDNS_REFLECTOR_BIND_ADDRESS_IPV6, MDNS_REFLECTOR_PORT } from './mdnsReflectorTypes.js';
|
|
@@ -19,13 +19,17 @@ export class MdnsReflectorServer {
|
|
|
19
19
|
constructor() {
|
|
20
20
|
this.log.logNameColor = '\x1b[38;5;115m';
|
|
21
21
|
this.mdnsIpv4.log.logNameColor = '\x1b[38;5;115m';
|
|
22
|
-
this.
|
|
22
|
+
if (!this.debug && !this.verbose && !this.silent)
|
|
23
|
+
this.mdnsIpv4.log.logLevel = "warn";
|
|
23
24
|
this.mdnsIpv6.log.logNameColor = '\x1b[38;5;115m';
|
|
24
|
-
this.
|
|
25
|
+
if (!this.debug && !this.verbose && !this.silent)
|
|
26
|
+
this.mdnsIpv6.log.logLevel = "warn";
|
|
25
27
|
this.unicastIpv4.log.logNameColor = '\x1b[38;5;115m';
|
|
26
|
-
this.
|
|
28
|
+
if (!this.debug && !this.verbose && !this.silent)
|
|
29
|
+
this.unicastIpv4.log.logLevel = "warn";
|
|
27
30
|
this.unicastIpv6.log.logNameColor = '\x1b[38;5;115m';
|
|
28
|
-
this.
|
|
31
|
+
if (!this.debug && !this.verbose && !this.silent)
|
|
32
|
+
this.unicastIpv6.log.logLevel = "warn";
|
|
29
33
|
const filters = getStringArrayParameter('filter');
|
|
30
34
|
if (filters)
|
|
31
35
|
this.mdnsIpv4.filters.push(...filters);
|
|
@@ -131,7 +135,7 @@ export class MdnsReflectorServer {
|
|
|
131
135
|
this.log.error(`**UpgradeAddress failed to parse message: ${error.message}`);
|
|
132
136
|
return msg;
|
|
133
137
|
}
|
|
134
|
-
this.log.info(`**UpgradeAddress message completed. Interface: ${selectedInterfaceName
|
|
138
|
+
this.log.info(`**UpgradeAddress message completed. Interface: ${selectedInterfaceName}, Host IPv4: ${hostIpv4 || 'N/A'}, Host IPv6: ${hostIpv6List.length > 0 ? hostIpv6List.join(', ') : 'N/A'}`);
|
|
135
139
|
if (hasParameter('log-reflector-messages')) {
|
|
136
140
|
try {
|
|
137
141
|
let decodedMessage = this.mdnsIpv4.decodeMdnsMessage(msg);
|
|
@@ -177,41 +181,83 @@ export class MdnsReflectorServer {
|
|
|
177
181
|
this.unicastIpv6.start();
|
|
178
182
|
});
|
|
179
183
|
await Promise.all(promises);
|
|
184
|
+
this.mdnsIpv4.socket.setMulticastLoopback(false);
|
|
185
|
+
this.mdnsIpv6.socket.setMulticastLoopback(false);
|
|
186
|
+
this.mdnsIpv4.on('message', (msg, rinfo) => {
|
|
187
|
+
if (this.ipv4Clients.size === 0)
|
|
188
|
+
return;
|
|
189
|
+
this.log.notice(`Sending ${isMdnsQuery(msg) ? 'query' : 'response'} message from mDNS ipv4 multicast ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to ${this.ipv4Clients.size} ipv4 reflector clients`);
|
|
190
|
+
for (const client of this.ipv4Clients.values()) {
|
|
191
|
+
this.unicastIpv4.send(msg, client.address, client.port);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
this.mdnsIpv6.on('message', (msg, rinfo) => {
|
|
195
|
+
if (this.ipv6Clients.size === 0)
|
|
196
|
+
return;
|
|
197
|
+
this.log.notice(`Sending ${isMdnsQuery(msg) ? 'query' : 'response'} message from mDNS ipv6 multicast ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to ${this.ipv6Clients.size} ipv6 reflector clients`);
|
|
198
|
+
for (const client of this.ipv6Clients.values()) {
|
|
199
|
+
this.unicastIpv6.send(msg, client.address, client.port);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
180
202
|
this.unicastIpv4.on('message', (msg, rinfo) => {
|
|
181
203
|
this.ipv4Clients.set(`${rinfo.address}:${rinfo.port}`, rinfo);
|
|
182
|
-
|
|
183
|
-
|
|
204
|
+
if (!isMdns(msg)) {
|
|
205
|
+
this.log.info(`Received message from reflector client on ipv4 ${BLUE}${rinfo.address}${nf}:${BLUE}${rinfo.port}${nf}: ${msg.toString()}`);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
this.log.notice(`Reflecting message from reflector client on ipv4 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to mDNS ipv4 multicast`);
|
|
209
|
+
const upgradedMsg = isMdnsResponse(msg) ? this.upgradeAddress(msg) : msg;
|
|
184
210
|
this.mdnsIpv4.send(upgradedMsg, MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_PORT);
|
|
185
211
|
if (hasParameter('broadcast')) {
|
|
186
212
|
const broadcastAddress = this.getBroadcastAddress(this.mdnsIpv4);
|
|
187
213
|
if (broadcastAddress) {
|
|
188
|
-
this.log.notice(`Reflecting message from
|
|
214
|
+
this.log.notice(`Reflecting message from reflector client on ipv4 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to ipv4 broadcast address ${BLUE}${broadcastAddress}${nt}:${BLUE}${MDNS_MULTICAST_PORT}${nt}`);
|
|
189
215
|
this.mdnsIpv4.send(upgradedMsg, broadcastAddress, MDNS_MULTICAST_PORT);
|
|
190
216
|
}
|
|
191
217
|
}
|
|
192
218
|
if (hasParameter('localhost')) {
|
|
193
|
-
this.log.notice(`Reflecting message from
|
|
219
|
+
this.log.notice(`Reflecting message from reflector client on ipv4 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to ipv4 localhost address ${BLUE}localhost${nt}:${BLUE}${MDNS_MULTICAST_PORT}${nt}`);
|
|
194
220
|
this.mdnsIpv4.send(upgradedMsg, 'localhost', MDNS_MULTICAST_PORT);
|
|
195
221
|
}
|
|
196
|
-
|
|
222
|
+
if (hasParameter('share-with-clients')) {
|
|
223
|
+
this.log.notice(`Sharing message from reflector client on ipv4 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} with other ipv4 reflector clients`);
|
|
224
|
+
for (const client of this.ipv4Clients.values()) {
|
|
225
|
+
if (client.address === rinfo.address && client.port === rinfo.port)
|
|
226
|
+
continue;
|
|
227
|
+
this.unicastIpv4.send(upgradedMsg, client.address, client.port);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
this.unicastIpv4.send(Buffer.from('mDNS ipv4 reflector server reflected your message'), rinfo.address, rinfo.port);
|
|
197
231
|
});
|
|
198
232
|
this.unicastIpv6.on('message', (msg, rinfo) => {
|
|
199
233
|
this.ipv6Clients.set(`${rinfo.address}:${rinfo.port}`, rinfo);
|
|
200
|
-
|
|
201
|
-
|
|
234
|
+
if (!isMdns(msg)) {
|
|
235
|
+
this.log.info(`Received message from reflector client on ipv6 ${BLUE}${rinfo.address}${nf}:${BLUE}${rinfo.port}${nf}: ${msg.toString()}`);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
this.log.notice(`Reflecting message from reflector client on ipv6 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to mDNS ipv6 multicast`);
|
|
239
|
+
const upgradedMsg = isMdnsResponse(msg) ? this.upgradeAddress(msg) : msg;
|
|
202
240
|
this.mdnsIpv6.send(upgradedMsg, MDNS_MULTICAST_IPV6_ADDRESS, MDNS_MULTICAST_PORT);
|
|
203
241
|
if (hasParameter('broadcast')) {
|
|
204
242
|
const broadcastAddress = this.getBroadcastAddress(this.mdnsIpv6);
|
|
205
243
|
if (broadcastAddress) {
|
|
206
|
-
this.log.notice(`Reflecting message from
|
|
244
|
+
this.log.notice(`Reflecting message from reflector client on ipv6 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to ipv6 broadcast address ${BLUE}${broadcastAddress}${nt}:${BLUE}${MDNS_MULTICAST_PORT}${nt}`);
|
|
207
245
|
this.mdnsIpv6.send(upgradedMsg, broadcastAddress, MDNS_MULTICAST_PORT);
|
|
208
246
|
}
|
|
209
247
|
}
|
|
210
248
|
if (hasParameter('localhost')) {
|
|
211
|
-
this.log.notice(`Reflecting message from
|
|
249
|
+
this.log.notice(`Reflecting message from reflector client on ipv6 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to ipv6 localhost address ${BLUE}localhost${nt}:${BLUE}${MDNS_MULTICAST_PORT}${nt}`);
|
|
212
250
|
this.mdnsIpv6.send(upgradedMsg, 'localhost', MDNS_MULTICAST_PORT);
|
|
213
251
|
}
|
|
214
|
-
|
|
252
|
+
if (hasParameter('share-with-clients')) {
|
|
253
|
+
this.log.notice(`Sharing message from reflector client on ipv6 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} with other ipv6 reflector clients`);
|
|
254
|
+
for (const client of this.ipv6Clients.values()) {
|
|
255
|
+
if (client.address === rinfo.address && client.port === rinfo.port)
|
|
256
|
+
continue;
|
|
257
|
+
this.unicastIpv6.send(upgradedMsg, client.address, client.port);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
this.unicastIpv6.send(Buffer.from('mDNS ipv6 reflector server reflected your message'), rinfo.address, rinfo.port);
|
|
215
261
|
});
|
|
216
262
|
this.log.notice('mDNS Reflector Server started.');
|
|
217
263
|
}
|
|
@@ -228,19 +274,19 @@ export class MdnsReflectorServer {
|
|
|
228
274
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
229
275
|
const promises = [];
|
|
230
276
|
promises[0] = new Promise((resolve) => {
|
|
231
|
-
this.mdnsIpv4.once('
|
|
277
|
+
this.mdnsIpv4.once('close', () => resolve());
|
|
232
278
|
this.mdnsIpv4.stop();
|
|
233
279
|
});
|
|
234
280
|
promises[1] = new Promise((resolve) => {
|
|
235
|
-
this.mdnsIpv6.once('
|
|
281
|
+
this.mdnsIpv6.once('close', () => resolve());
|
|
236
282
|
this.mdnsIpv6.stop();
|
|
237
283
|
});
|
|
238
284
|
promises[2] = new Promise((resolve) => {
|
|
239
|
-
this.unicastIpv4.once('
|
|
285
|
+
this.unicastIpv4.once('close', () => resolve());
|
|
240
286
|
this.unicastIpv4.stop();
|
|
241
287
|
});
|
|
242
288
|
promises[3] = new Promise((resolve) => {
|
|
243
|
-
this.unicastIpv6.once('
|
|
289
|
+
this.unicastIpv6.once('close', () => resolve());
|
|
244
290
|
this.unicastIpv6.stop();
|
|
245
291
|
});
|
|
246
292
|
await Promise.all(promises);
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge",
|
|
3
|
-
"version": "3.4.6-dev-20251228-
|
|
3
|
+
"version": "3.4.6-dev-20251228-a2d4bd7",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "matterbridge",
|
|
9
|
-
"version": "3.4.6-dev-20251228-
|
|
9
|
+
"version": "3.4.6-dev-20251228-a2d4bd7",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@matter/main": "0.15.6",
|
package/package.json
CHANGED