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 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
@@ -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);
@@ -1,4 +1,4 @@
1
- import { BLUE, CYAN, db, er, GREEN, idn, MAGENTA, nf, rs } from 'node-ansi-logger';
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 || '0', 16);
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
- const word = parseInt(g || '0', 16);
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
- const names = questions
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
- 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}`);
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
- 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}`);
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 { AnsiLogger, BLUE, nt } from 'node-ansi-logger';
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.mdnsIpv4.log.logLevel = "warn";
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.mdnsIpv6.log.logLevel = "warn";
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.unicastIpv4.log.logLevel = "warn";
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.unicastIpv6.log.logLevel = "warn";
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.log.notice(`Sending message from mDNS ipv4 multicast ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to unicast ipv4 reflector`);
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.log.notice(`Sending message from mDNS ipv6 multicast ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to unicast ipv6 reflector`);
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
- this.log.notice(`Received message from unicast reflector on ipv4 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt}: ${msg.toString()}`);
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
- this.log.notice(`Received message from unicast reflector on ipv6 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt}: ${msg.toString()}`);
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('closed', () => resolve());
154
+ this.mdnsIpv4.once('close', () => resolve());
87
155
  this.mdnsIpv4.stop();
88
156
  });
89
157
  promises[1] = new Promise((resolve) => {
90
- this.mdnsIpv6.once('closed', () => resolve());
158
+ this.mdnsIpv6.once('close', () => resolve());
91
159
  this.mdnsIpv6.stop();
92
160
  });
93
161
  promises[2] = new Promise((resolve) => {
94
- this.unicastIpv4.once('closed', () => resolve());
162
+ this.unicastIpv4.once('close', () => resolve());
95
163
  this.unicastIpv4.stop();
96
164
  });
97
165
  promises[3] = new Promise((resolve) => {
98
- this.unicastIpv6.once('closed', () => resolve());
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.mdnsIpv4.log.logLevel = "warn";
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.mdnsIpv6.log.logLevel = "warn";
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.unicastIpv4.log.logLevel = "warn";
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.unicastIpv6.log.logLevel = "warn";
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 || 'N/A'}, Host IPv4: ${hostIpv4 || 'N/A'}, Host IPv6: ${hostIpv6List.length > 0 ? hostIpv6List.join(', ') : 'N/A'}`);
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
- this.log.notice(`Reflecting message from unicast client ipv4 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to mDNS ipv4 multicast`);
183
- const upgradedMsg = this.upgradeAddress(msg);
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 unicast client ipv4 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to ipv4 broadcast address ${BLUE}${broadcastAddress}${nt}:${BLUE}${MDNS_MULTICAST_PORT}${nt}`);
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 unicast client ipv4 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to ipv4 localhost address ${BLUE}localhost${nt}:${BLUE}${MDNS_MULTICAST_PORT}${nt}`);
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
- this.unicastIpv4.send(Buffer.from('mDNS Reflector Server reflected your message'), rinfo.address, rinfo.port);
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
- this.log.notice(`Reflecting message from unicast client ipv6 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to mDNS ipv6 multicast`);
201
- const upgradedMsg = this.upgradeAddress(msg);
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 unicast client ipv6 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to ipv6 broadcast address ${BLUE}${broadcastAddress}${nt}:${BLUE}${MDNS_MULTICAST_PORT}${nt}`);
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 unicast client ipv6 ${BLUE}${rinfo.address}${nt}:${BLUE}${rinfo.port}${nt} to ipv6 localhost address ${BLUE}localhost${nt}:${BLUE}${MDNS_MULTICAST_PORT}${nt}`);
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
- this.unicastIpv6.send(Buffer.from('mDNS Reflector Server reflected your message'), rinfo.address, rinfo.port);
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('closed', () => resolve());
277
+ this.mdnsIpv4.once('close', () => resolve());
232
278
  this.mdnsIpv4.stop();
233
279
  });
234
280
  promises[1] = new Promise((resolve) => {
235
- this.mdnsIpv6.once('closed', () => resolve());
281
+ this.mdnsIpv6.once('close', () => resolve());
236
282
  this.mdnsIpv6.stop();
237
283
  });
238
284
  promises[2] = new Promise((resolve) => {
239
- this.unicastIpv4.once('closed', () => resolve());
285
+ this.unicastIpv4.once('close', () => resolve());
240
286
  this.unicastIpv4.stop();
241
287
  });
242
288
  promises[3] = new Promise((resolve) => {
243
- this.unicastIpv6.once('closed', () => resolve());
289
+ this.unicastIpv6.once('close', () => resolve());
244
290
  this.unicastIpv6.stop();
245
291
  });
246
292
  await Promise.all(promises);
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.4.6-dev-20251228-e06f048",
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-e06f048",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.4.6-dev-20251228-e06f048",
3
+ "version": "3.4.6-dev-20251228-a2d4bd7",
4
4
  "description": "Matterbridge plugin manager for Matter",
5
5
  "author": "https://github.com/Luligu",
6
6
  "license": "Apache-2.0",