matterbridge 3.4.5-dev-20251225-742588e → 3.4.6-dev-20251228-e06f048

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
@@ -28,7 +28,19 @@ Advantages:
28
28
  - individual plugin isolation in childbridge mode;
29
29
  - ability to update the plugin in childbridge mode without restarting matterbridge;
30
30
 
31
- ## [3.4.5] - Dev branch
31
+ ## [3.4.6] - Dev branch
32
+
33
+ ### Added
34
+
35
+ ### Changed
36
+
37
+ - [package]: Updated dependencies.
38
+
39
+ ### Fixed
40
+
41
+ <a href="https://www.buymeacoffee.com/luligugithub"><img src="https://matterbridge.io/bmc-button.svg" alt="Buy me a coffee" width="80"></a>
42
+
43
+ ## [3.4.5] - 2025-12-27
32
44
 
33
45
  ### Added
34
46
 
@@ -36,17 +48,14 @@ Advantages:
36
48
  - [DevContainer]: Since is now possible to pair from Dev Container, named volumes have been added to persist storage and plugins across rebuilds.
37
49
  - [mb_mdns]: Added query and advertise interval. Improved help for easy mDNS testing.
38
50
  - [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.
41
- - [mb_mdns]: Added \_matterbridge.\_tcp.local to query and advertise.
42
- - [mb_mdns]: Added localhost parameter to send unicast messages to localhost.
43
- - [mb_mdns]: Added unicastIpv4 parameter to send unicast messages.
44
- - [mb_mdns]: Added unicastIpv6 parameter to send unicast messages.
51
+ - [Mdns]: Added TXT/SRV/A/AAAA encoders into the Mdns class.
52
+ - [Mdns]: Mdns.sendResponse now accepts an array and sends multi-answer responses.
53
+ - [MdnsReflectorClient]: Added MdnsReflectorClient class.
54
+ - [MdnsReflectorServer]: Added MdnsReflectorServer class.
45
55
 
46
56
  ### Changed
47
57
 
48
58
  - [package]: Updated dependencies.
49
- - [mdns]: Mdns.sendResponse now accepts an array and sends multi-answer responses.
50
59
 
51
60
  ### Fixed
52
61
 
@@ -2,7 +2,11 @@ import dgram from 'node:dgram';
2
2
  import EventEmitter from 'node:events';
3
3
  import os from 'node:os';
4
4
  import { AnsiLogger, BLUE, db, idn, nf, rs } from 'node-ansi-logger';
5
+ import { hasParameter } from '../utils/commandLine.js';
5
6
  export class Dgram extends EventEmitter {
7
+ verbose = hasParameter('v') || hasParameter('verbose');
8
+ debug = hasParameter('d') || hasParameter('debug') || hasParameter('v') || hasParameter('verbose');
9
+ silent = hasParameter('s') || hasParameter('silent');
6
10
  log;
7
11
  socket;
8
12
  bound = false;
@@ -12,7 +16,7 @@ export class Dgram extends EventEmitter {
12
16
  interfaceNetmask;
13
17
  constructor(name, socketType, reuseAddr = true, interfaceName, interfaceAddress) {
14
18
  super();
15
- this.log = new AnsiLogger({ logName: name, logTimestampFormat: 4, logLevel: "debug" });
19
+ this.log = new AnsiLogger({ logName: name, logTimestampFormat: 4, logLevel: this.debug ? "debug" : this.silent ? "notice" : "info" });
16
20
  this.socket = dgram.createSocket({ type: socketType, reuseAddr });
17
21
  this.socketType = socketType;
18
22
  this.interfaceName = interfaceName;
@@ -1,14 +1,15 @@
1
+ import os from 'node:os';
1
2
  import { getIntParameter, getParameter, getStringArrayParameter, hasParameter } from '../utils/commandLine.js';
2
3
  import { MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_IPV6_ADDRESS, MDNS_MULTICAST_PORT } from './multicast.js';
3
4
  import { Mdns } from './mdns.js';
4
- import { Unicast } from './unicast.js';
5
- import { MDNS_REFLECTOR_ADDRESS, MDNS_REFLECTOR_PORT } from './mMdnsReflector.js';
5
+ import { MdnsReflectorClient } from './mdnsReflectorClient.js';
6
+ import { MdnsReflectorServer } from './mdnsReflectorServer.js';
6
7
  {
7
8
  if (hasParameter('h') || hasParameter('help')) {
8
- console.log(`Copyright (c) Matterbridge. All rights reserved.\n`);
9
+ console.log(`Copyright (c) Matterbridge. All rights reserved. Version 1.0.0.\n`);
9
10
  console.log(`Usage: mb_mdns [options...]
10
11
 
11
- If no command line is provided, mb_mdns shows all incoming mDNS records.
12
+ If no command line is provided, mb_mdns shows all incoming mDNS records on all interfaces (0.0.0.0 and ::).
12
13
 
13
14
  Options:
14
15
  -h, --help Show this help message and exit.
@@ -17,14 +18,17 @@ Options:
17
18
  --ipv6InterfaceAddress <address> IPv6 address of the network interface to bind to (default: ::).
18
19
  --outgoingIpv4InterfaceAddress <address> Outgoing IPv4 address of the network interface (default first external address).
19
20
  --outgoingIpv6InterfaceAddress <address> Outgoing IPv6 address of the network interface (default first external address).
20
- --unicastIpv4 <address> Unicast IPv4 address to send mDNS advertisements to (default: disabled).
21
- --unicastIpv6 <address> Unicast IPv6 address to send mDNS advertisements to (default: disabled).
22
- --broadcast Enable broadcasting of mDNS advertisements (default: disabled).
23
- --localhost Enable sending mDNS advertisements to localhost (default: disabled).
24
21
  --advertise <interval> Enable matterbridge mDNS advertisement each ms (default interval: 10000ms).
25
22
  --query <interval> Enable common mDNS services query each ms (default interval: 10000ms).
26
23
  --filter <string...> Filter strings to match in the mDNS record name (default: no filter).
24
+ --noIpv4 Disable IPv4 mDNS server (default: enabled).
25
+ --noIpv6 Disable IPv6 mDNS server (default: enabled).
26
+ --no-timeout Disable automatic timeout of 10 minutes. Reflector mode disables timeout automatically.
27
+ --reflector-client Enable mDNS reflector client (default: disabled).
28
+ --reflector-server Enable mDNS reflector server (default: disabled).
29
+ -d, --debug Enable debug logging (default: disabled).
27
30
  -v, --verbose Enable verbose logging (default: disabled).
31
+ -s, --silent Enable silent mode, only log notices, warnings and errors.
28
32
 
29
33
  Examples:
30
34
  # Listen for Matter device commissioner service records only on eth0 interface
@@ -52,42 +56,29 @@ Examples:
52
56
  let mdnsIpv6QueryInterval;
53
57
  let mdnsIpv4AdvertiseInterval;
54
58
  let mdnsIpv6AdvertiseInterval;
55
- 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'));
56
- const mdnsIpv6 = new Mdns('mDNS Server udp6', MDNS_MULTICAST_IPV6_ADDRESS, MDNS_MULTICAST_PORT, 'udp6', true, getParameter('interfaceName'), getParameter('ipv6InterfaceAddress') || '::', getParameter('outgoingIpv6InterfaceAddress'));
57
- const unicast = new Unicast('mDNS Unicast Server', 'udp4', false, undefined, MDNS_REFLECTOR_ADDRESS, MDNS_REFLECTOR_PORT);
58
- if (hasParameter('v') || hasParameter('verbose')) {
59
- mdnsIpv4.log.logLevel = "debug";
60
- mdnsIpv6.log.logLevel = "debug";
61
- unicast.log.logLevel = "debug";
62
- }
63
- else {
64
- mdnsIpv4.log.logLevel = "info";
65
- mdnsIpv6.log.logLevel = "info";
66
- unicast.log.logLevel = "info";
67
- }
68
- mdnsIpv4.listNetworkInterfaces();
69
- const filters = getStringArrayParameter('filter');
70
- if (filters) {
71
- mdnsIpv4.filters.push(...filters);
72
- mdnsIpv6.filters.push(...filters);
73
- }
59
+ let mdnsIpv4 = undefined;
60
+ let mdnsIpv6 = undefined;
61
+ let reflectorClient = undefined;
62
+ let reflectorServer = undefined;
74
63
  async function cleanupAndLogAndExit() {
75
- if (hasParameter('advertise')) {
76
- advertise(mdnsIpv4, 0);
77
- advertise(mdnsIpv6, 0);
78
- }
79
- await new Promise((resolve) => setTimeout(resolve, 250));
80
64
  clearInterval(mdnsIpv4QueryInterval);
81
65
  clearInterval(mdnsIpv6QueryInterval);
82
66
  clearInterval(mdnsIpv4AdvertiseInterval);
83
67
  clearInterval(mdnsIpv6AdvertiseInterval);
84
- mdnsIpv4.stop();
85
- mdnsIpv6.stop();
86
- unicast.stop();
68
+ if (hasParameter('advertise')) {
69
+ if (mdnsIpv4)
70
+ advertise(mdnsIpv4, 0);
71
+ if (mdnsIpv6)
72
+ advertise(mdnsIpv6, 0);
73
+ }
87
74
  await new Promise((resolve) => setTimeout(resolve, 250));
88
- mdnsIpv4.logDevices();
89
- mdnsIpv6.logDevices();
90
- process.exit(0);
75
+ mdnsIpv4?.stop();
76
+ mdnsIpv6?.stop();
77
+ mdnsIpv4?.logDevices();
78
+ mdnsIpv6?.logDevices();
79
+ await new Promise((resolve) => setTimeout(resolve, 250));
80
+ await reflectorClient?.stop();
81
+ await reflectorServer?.stop();
91
82
  }
92
83
  const query = (mdns) => {
93
84
  mdns.log.info('Sending mDNS query for services...');
@@ -125,141 +116,92 @@ Examples:
125
116
  { name: httpInstanceName, rtype: 16, rclass: 1 | 32768, ttl, rdata: txtRdata },
126
117
  { name: matterbridgeInstanceName, rtype: 16, rclass: 1 | 32768, ttl, rdata: txtRdata },
127
118
  ];
128
- try {
129
- const ipv4 = mdns.getIpv4InterfaceAddress(mdns.interfaceName);
130
- if (ipv4) {
131
- answers.push({ name: hostName, rtype: 1, rclass: 1 | 32768, ttl, rdata: mdns.encodeA(ipv4) });
119
+ const interfaces = os.networkInterfaces();
120
+ let interfaceInfos = mdns.interfaceName ? interfaces[mdns.interfaceName] : undefined;
121
+ if (!interfaceInfos) {
122
+ interfaceInfos = [];
123
+ for (const name of Object.keys(interfaces)) {
124
+ const infos = interfaces[name];
125
+ if (infos && infos.length > 0 && !infos[0].internal) {
126
+ interfaceInfos.push(...infos);
127
+ break;
128
+ }
132
129
  }
133
130
  }
134
- catch (error) {
135
- mdns.log.warn(`Error sending mDNS advertisement for matterbridge service A record: ${error.message}`);
136
- }
137
131
  try {
138
- const ipv6 = mdns.getIpv6InterfaceAddress(mdns.interfaceName);
139
- if (ipv6) {
140
- answers.push({ name: hostName, rtype: 28, rclass: 1 | 32768, ttl, rdata: mdns.encodeAAAA(ipv6) });
132
+ for (const info of interfaceInfos) {
133
+ if (info.family === 'IPv4' && !info.internal) {
134
+ const ipv4 = info.address;
135
+ answers.push({ name: hostName, rtype: 1, rclass: 1 | 32768, ttl, rdata: mdns.encodeA(ipv4) });
136
+ }
137
+ else if (info.family === 'IPv6' && !info.internal) {
138
+ const ipv6 = info.address;
139
+ answers.push({ name: hostName, rtype: 28, rclass: 1 | 32768, ttl, rdata: mdns.encodeAAAA(ipv6) });
140
+ }
141
141
  }
142
142
  }
143
143
  catch (error) {
144
- mdns.log.warn(`Error sending mDNS advertisement for matterbridge service AAAA record: ${error.message}`);
145
- }
146
- const response = mdns.sendResponse(answers);
147
- if (hasParameter('broadcast')) {
148
- try {
149
- const address = mdns.socketType === 'udp4' ? mdns.getIpv4InterfaceAddress(mdns.interfaceName) : mdns.getIpv6InterfaceAddress(mdns.interfaceName);
150
- const mask = mdns.socketType === 'udp4' ? mdns.getNetmask(address) : undefined;
151
- const broadcastAddress = mdns.socketType === 'udp4' ? mdns.getIpv4BroadcastAddress(address, mask) : mdns.getIpv6BroadcastAddress();
152
- mdns.log.info(`***Broadcasting mDNS advertisement for matterbridge service to ${broadcastAddress}...`);
153
- mdns.socket.send(response, 0, response.length, MDNS_MULTICAST_PORT, broadcastAddress, (error) => {
154
- if (error) {
155
- mdns.log.error(`Error broadcasting mDNS advertisement to ${broadcastAddress}: ${error.message}`);
156
- }
157
- else {
158
- mdns.log.info(`**mDNS advertisement broadcasted successfully to ${broadcastAddress}`);
159
- }
160
- });
161
- }
162
- catch (error) {
163
- mdns.log.error(`Error broadcasting mDNS advertisement: ${error.message}`);
164
- }
165
- }
166
- if (mdns.socketType === 'udp4' && hasParameter('localhost')) {
167
- try {
168
- mdns.log.info(`**Sending mDNS advertisement for matterbridge service to localhost...`);
169
- mdns.socket.send(response, 0, response.length, MDNS_REFLECTOR_PORT, MDNS_REFLECTOR_ADDRESS, (error) => {
170
- if (error) {
171
- mdns.log.error(`**Error sending mDNS advertisement to localhost: ${error.message}`);
172
- }
173
- else {
174
- mdns.log.info(`**mDNS advertisement sent successfully to localhost`);
175
- }
176
- });
177
- }
178
- catch (error) {
179
- mdns.log.error(`**Error sending mDNS advertisement to localhost: ${error.message}`);
180
- }
181
- }
182
- if (mdns.socketType === 'udp4' && getParameter('unicastIpv4')) {
183
- const unicastAddress = getParameter('unicastIpv4');
184
- try {
185
- mdns.log.info(`**Sending mDNS advertisement for matterbridge service to unicast ${unicastAddress}...`);
186
- mdns.socket.send(response, 0, response.length, MDNS_MULTICAST_PORT, unicastAddress, (error) => {
187
- if (error) {
188
- mdns.log.error(`Error sending mDNS advertisement to unicast ${unicastAddress}: ${error.message}`);
189
- }
190
- else {
191
- mdns.log.info(`**mDNS advertisement sent successfully to unicast ${unicastAddress}`);
192
- }
193
- });
194
- }
195
- catch (error) {
196
- mdns.log.error(`Error sending mDNS advertisement to unicast ${unicastAddress}: ${error.message}`);
197
- }
198
- }
199
- if (mdns.socketType === 'udp6' && getParameter('unicastIpv6')) {
200
- const unicastAddress = getParameter('unicastIpv6');
201
- try {
202
- mdns.log.info(`**Sending mDNS advertisement for matterbridge service to unicast ${unicastAddress}...`);
203
- mdns.socket.send(response, 0, response.length, MDNS_MULTICAST_PORT, unicastAddress, (error) => {
204
- if (error) {
205
- mdns.log.error(`Error sending mDNS advertisement to unicast ${unicastAddress}: ${error.message}`);
206
- }
207
- else {
208
- mdns.log.info(`**mDNS advertisement sent successfully to unicast ${unicastAddress}`);
209
- }
210
- });
211
- }
212
- catch (error) {
213
- mdns.log.error(`Error sending mDNS advertisement to unicast ${unicastAddress}: ${error.message}`);
214
- }
144
+ mdns.log.error(`Error encoding network interface addresses: ${error.message}`);
215
145
  }
146
+ const _response = mdns.sendResponse(answers);
216
147
  };
217
- process.on('SIGINT', async () => {
218
- await cleanupAndLogAndExit();
219
- });
220
- if (!hasParameter('noIpv4'))
148
+ if (!hasParameter('noIpv4') && !hasParameter('reflector-server') && !hasParameter('reflector-client')) {
149
+ 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'));
150
+ if (hasParameter('v') || hasParameter('verbose'))
151
+ mdnsIpv4.listNetworkInterfaces();
152
+ const filters = getStringArrayParameter('filter');
153
+ if (filters)
154
+ mdnsIpv4.filters.push(...filters);
221
155
  mdnsIpv4.start();
222
- mdnsIpv4.on('ready', (address) => {
223
- mdnsIpv4.log.info(`mdnsIpv4 server ready on ${address.family} ${address.address}:${address.port}`);
224
- if (hasParameter('advertise')) {
225
- advertise(mdnsIpv4);
226
- mdnsIpv4AdvertiseInterval = setInterval(() => {
156
+ mdnsIpv4.on('ready', (address) => {
157
+ mdnsIpv4?.log.info(`mdnsIpv4 server ready on ${address.family} ${address.address}:${address.port}`);
158
+ if (hasParameter('advertise')) {
227
159
  advertise(mdnsIpv4);
228
- }, getIntParameter('advertise') || 10000).unref();
229
- }
230
- if (hasParameter('query')) {
231
- query(mdnsIpv4);
232
- mdnsIpv4QueryInterval = setInterval(() => {
160
+ mdnsIpv4AdvertiseInterval = setInterval(() => advertise(mdnsIpv4), getIntParameter('advertise') || 10000).unref();
161
+ }
162
+ if (hasParameter('query')) {
233
163
  query(mdnsIpv4);
234
- }, getIntParameter('query') || 10000).unref();
235
- }
236
- });
237
- if (!hasParameter('noIpv6'))
164
+ mdnsIpv4QueryInterval = setInterval(() => query(mdnsIpv4), getIntParameter('query') || 10000).unref();
165
+ }
166
+ });
167
+ }
168
+ if (!hasParameter('noIpv6') && !hasParameter('reflector-server') && !hasParameter('reflector-client')) {
169
+ mdnsIpv6 = new Mdns('mDNS Server udp6', MDNS_MULTICAST_IPV6_ADDRESS, MDNS_MULTICAST_PORT, 'udp6', true, getParameter('interfaceName'), getParameter('ipv6InterfaceAddress') || '::', getParameter('outgoingIpv6InterfaceAddress'));
170
+ if (hasParameter('v') || hasParameter('verbose'))
171
+ mdnsIpv6.listNetworkInterfaces();
172
+ const filters = getStringArrayParameter('filter');
173
+ if (filters)
174
+ mdnsIpv6.filters.push(...filters);
238
175
  mdnsIpv6.start();
239
- mdnsIpv6.on('ready', (address) => {
240
- mdnsIpv6.log.info(`mdnsIpv6 server ready on ${address.family} ${address.address}:${address.port}`);
241
- if (hasParameter('advertise')) {
242
- advertise(mdnsIpv6);
243
- mdnsIpv6AdvertiseInterval = setInterval(() => {
176
+ mdnsIpv6.on('ready', (address) => {
177
+ mdnsIpv6?.log.info(`mdnsIpv6 server ready on ${address.family} ${address.address}:${address.port}`);
178
+ if (hasParameter('advertise')) {
244
179
  advertise(mdnsIpv6);
245
- }, getIntParameter('advertise') || 10000).unref();
246
- }
247
- if (hasParameter('query')) {
248
- query(mdnsIpv6);
249
- mdnsIpv6QueryInterval = setInterval(() => {
180
+ mdnsIpv6AdvertiseInterval = setInterval(() => advertise(mdnsIpv6), getIntParameter('advertise') || 10000).unref();
181
+ }
182
+ if (hasParameter('query')) {
250
183
  query(mdnsIpv6);
251
- }, getIntParameter('query') || 10000).unref();
252
- }
253
- });
254
- if (hasParameter('reflector'))
255
- unicast.start();
256
- unicast.on('bound', (address) => {
257
- unicast.log.info(`**Bound on ${address.family} ${address.address}:${address.port}`);
258
- });
259
- unicast.on('message', (msg, rinfo) => {
260
- unicast.log.info(`**Received message from ${rinfo.address}:${rinfo.port} - ${msg.length} bytes`);
184
+ mdnsIpv6QueryInterval = setInterval(() => query(mdnsIpv6), getIntParameter('query') || 10000).unref();
185
+ }
186
+ });
187
+ }
188
+ if (hasParameter('reflector-client')) {
189
+ reflectorClient = new MdnsReflectorClient();
190
+ await reflectorClient.start();
191
+ }
192
+ if (hasParameter('reflector-server')) {
193
+ reflectorServer = new MdnsReflectorServer();
194
+ await reflectorServer.start();
195
+ }
196
+ process.on('SIGINT', async () => {
197
+ await cleanupAndLogAndExit();
261
198
  });
262
- setTimeout(async () => {
199
+ process.on('SIGTERM', async () => {
263
200
  await cleanupAndLogAndExit();
264
- }, 600000).unref();
201
+ });
202
+ if (!hasParameter('no-timeout') && !hasParameter('reflector-server') && !hasParameter('reflector-client')) {
203
+ setTimeout(async () => {
204
+ await cleanupAndLogAndExit();
205
+ }, 600000).unref();
206
+ }
265
207
  }
@@ -631,21 +631,21 @@ export class Mdns extends Multicast {
631
631
  }
632
632
  return isQU ? `${classStr}|QU` : classStr;
633
633
  }
634
- logMdnsMessage(msg) {
635
- this.log.info(`Decoded mDNS message: ID ${MAGENTA}${msg.id}${nf}, QR ${GREEN}${msg.qr === 0 ? 'Query' : 'Response'}${nf}, OPCODE ${MAGENTA}${msg.opcode}${nf}, AA ${MAGENTA}${msg.aa}${nf}, TC ${MAGENTA}${msg.tc}${nf}, RD ${MAGENTA}${msg.rd}${nf}, RA ${MAGENTA}${msg.ra}${nf}, Z ${MAGENTA}${msg.z}${nf}, RCODE ${MAGENTA}${msg.rcode}${nf}, QDCount ${MAGENTA}${msg.qdCount}${nf}, ANCount ${MAGENTA}${msg.anCount}${nf}, NSCount ${MAGENTA}${msg.nsCount}${nf}, ARCount ${MAGENTA}${msg.arCount}${nf}`);
634
+ logMdnsMessage(msg, log = this.log, text = 'Decoded mDNS message') {
635
+ log.info(`${text}: ID ${MAGENTA}${msg.id}${nf}, QR ${GREEN}${msg.qr === 0 ? 'Query' : 'Response'}${nf}, OPCODE ${MAGENTA}${msg.opcode}${nf}, AA ${MAGENTA}${msg.aa}${nf}, TC ${MAGENTA}${msg.tc}${nf}, RD ${MAGENTA}${msg.rd}${nf}, RA ${MAGENTA}${msg.ra}${nf}, Z ${MAGENTA}${msg.z}${nf}, RCODE ${MAGENTA}${msg.rcode}${nf}, QDCount ${MAGENTA}${msg.qdCount}${nf}, ANCount ${MAGENTA}${msg.anCount}${nf}, NSCount ${MAGENTA}${msg.nsCount}${nf}, ARCount ${MAGENTA}${msg.arCount}${nf}`);
636
636
  msg.questions?.forEach((question) => {
637
- this.log.info(`Question: ${CYAN}${question.name}${nf} type ${idn}${this.dnsTypeToString(question.type)}${rs}${nf} class ${CYAN}${this.dnsQuestionClassToString(question.class)}${nf}`);
637
+ log.info(`Question: ${CYAN}${question.name}${nf} type ${idn}${this.dnsTypeToString(question.type)}${rs}${nf} class ${CYAN}${this.dnsQuestionClassToString(question.class)}${nf}`);
638
638
  });
639
639
  msg.answers?.forEach((answer) => {
640
- this.log.info(`Answer: ${CYAN}${answer.name}${nf} type ${idn}${this.dnsTypeToString(answer.type)}${rs}${nf} class ${CYAN}${this.dnsResponseClassToString(answer.class)}${nf} ttl ${CYAN}${answer.ttl}${nf} data ${CYAN}${answer.data}${nf}`);
640
+ log.info(`Answer: ${CYAN}${answer.name}${nf} type ${idn}${this.dnsTypeToString(answer.type)}${rs}${nf} class ${CYAN}${this.dnsResponseClassToString(answer.class)}${nf} ttl ${CYAN}${answer.ttl}${nf} data ${CYAN}${answer.data}${nf}`);
641
641
  });
642
642
  msg.authorities?.forEach((authority) => {
643
- this.log.info(`Authority: ${CYAN}${authority.name}${nf} type ${idn}${this.dnsTypeToString(authority.type)}${rs}${nf} class ${CYAN}${this.dnsResponseClassToString(authority.class)}${nf} ttl ${CYAN}${authority.ttl}${nf} data ${CYAN}${authority.data}${nf}`);
643
+ log.info(`Authority: ${CYAN}${authority.name}${nf} type ${idn}${this.dnsTypeToString(authority.type)}${rs}${nf} class ${CYAN}${this.dnsResponseClassToString(authority.class)}${nf} ttl ${CYAN}${authority.ttl}${nf} data ${CYAN}${authority.data}${nf}`);
644
644
  });
645
645
  msg.additionals?.forEach((additional) => {
646
- this.log.info(`Additional: ${CYAN}${additional.name}${nf} type ${idn}${this.dnsTypeToString(additional.type)}${rs}${nf} class ${CYAN}${this.dnsResponseClassToString(additional.class)}${nf} ttl ${CYAN}${additional.ttl}${nf} data ${CYAN}${additional.data}${nf}`);
646
+ log.info(`Additional: ${CYAN}${additional.name}${nf} type ${idn}${this.dnsTypeToString(additional.type)}${rs}${nf} class ${CYAN}${this.dnsResponseClassToString(additional.class)}${nf} ttl ${CYAN}${additional.ttl}${nf} data ${CYAN}${additional.data}${nf}`);
647
647
  });
648
- this.log.info(`---\n`);
648
+ log.info(`---\n`);
649
649
  }
650
650
  logDevices() {
651
651
  this.log.info(`Discovered query devices: ${MAGENTA}${this.deviceQueries.size}${nf}`);
@@ -0,0 +1,108 @@
1
+ import { AnsiLogger, BLUE, nt } from 'node-ansi-logger';
2
+ import { getStringArrayParameter, hasParameter } from '../utils/commandLine.js';
3
+ import { Mdns } from './mdns.js';
4
+ import { MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_IPV6_ADDRESS, MDNS_MULTICAST_PORT } from './multicast.js';
5
+ import { Unicast } from './unicast.js';
6
+ import { MDNS_REFLECTOR_ADDRESS, MDNS_REFLECTOR_BIND_ADDRESS_IPV4, MDNS_REFLECTOR_BIND_ADDRESS_IPV6, MDNS_REFLECTOR_HOST_DOCKER, MDNS_REFLECTOR_PORT } from './mdnsReflectorTypes.js';
7
+ export class MdnsReflectorClient {
8
+ verbose = hasParameter('v') || hasParameter('verbose');
9
+ debug = hasParameter('d') || hasParameter('debug') || hasParameter('v') || hasParameter('verbose');
10
+ silent = hasParameter('s') || hasParameter('silent');
11
+ log = new AnsiLogger({ logName: 'MdnsReflectorClient', logTimestampFormat: 4, logLevel: this.debug ? "debug" : this.silent ? "notice" : "info" });
12
+ mdnsIpv4 = new Mdns('mDNS udp4 Server', MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_PORT, 'udp4', true, undefined, MDNS_REFLECTOR_BIND_ADDRESS_IPV4);
13
+ mdnsIpv6 = new Mdns('mDNS udp6 Server', MDNS_MULTICAST_IPV6_ADDRESS, MDNS_MULTICAST_PORT, 'udp6', true, undefined, MDNS_REFLECTOR_BIND_ADDRESS_IPV6);
14
+ unicastIpv4 = new Unicast('mDNS udp4 Reflector Client', 'udp4', false, undefined, MDNS_REFLECTOR_BIND_ADDRESS_IPV4);
15
+ unicastIpv6 = new Unicast('mDNS udp6 Reflector Client', 'udp6', false, undefined, MDNS_REFLECTOR_BIND_ADDRESS_IPV6);
16
+ constructor() {
17
+ this.log.logNameColor = '\x1b[38;5;97m';
18
+ this.mdnsIpv4.log.logNameColor = '\x1b[38;5;97m';
19
+ this.mdnsIpv4.log.logLevel = "warn";
20
+ this.mdnsIpv6.log.logNameColor = '\x1b[38;5;97m';
21
+ this.mdnsIpv6.log.logLevel = "warn";
22
+ this.unicastIpv4.log.logNameColor = '\x1b[38;5;97m';
23
+ this.unicastIpv4.log.logLevel = "warn";
24
+ this.unicastIpv6.log.logNameColor = '\x1b[38;5;97m';
25
+ this.unicastIpv6.log.logLevel = "warn";
26
+ const filters = getStringArrayParameter('filter');
27
+ if (filters)
28
+ this.mdnsIpv4.filters.push(...filters);
29
+ if (filters)
30
+ this.mdnsIpv6.filters.push(...filters);
31
+ }
32
+ async start() {
33
+ this.log.notice('mDNS Reflector Client starting...');
34
+ this.mdnsIpv4.on('error', (err) => {
35
+ this.log.error(`mDNS udp4 Server error:\n${err.stack}`);
36
+ });
37
+ this.mdnsIpv6.on('error', (err) => {
38
+ this.log.error(`mDNS udp6 Server error:\n${err.stack}`);
39
+ });
40
+ this.unicastIpv4.on('error', (err) => {
41
+ this.log.error(`mDNS udp4 Reflector Client error:\n${err.stack}`);
42
+ });
43
+ this.unicastIpv6.on('error', (err) => {
44
+ this.log.error(`mDNS udp6 Reflector Client error:\n${err.stack}`);
45
+ });
46
+ const promises = [];
47
+ promises[0] = new Promise((resolve) => {
48
+ this.mdnsIpv4.once('bound', () => resolve());
49
+ this.mdnsIpv4.start();
50
+ });
51
+ promises[1] = new Promise((resolve) => {
52
+ this.mdnsIpv6.once('bound', () => resolve());
53
+ this.mdnsIpv6.start();
54
+ });
55
+ promises[2] = new Promise((resolve) => {
56
+ this.unicastIpv4.once('bound', () => resolve());
57
+ this.unicastIpv4.start();
58
+ });
59
+ promises[3] = new Promise((resolve) => {
60
+ this.unicastIpv6.once('bound', () => resolve());
61
+ this.unicastIpv6.start();
62
+ });
63
+ await Promise.all(promises);
64
+ 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`);
66
+ this.unicastIpv4.send(msg, MDNS_REFLECTOR_HOST_DOCKER, MDNS_REFLECTOR_PORT);
67
+ this.unicastIpv4.send(msg, MDNS_REFLECTOR_ADDRESS, MDNS_REFLECTOR_PORT);
68
+ });
69
+ 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`);
71
+ this.unicastIpv6.send(msg, MDNS_REFLECTOR_HOST_DOCKER, MDNS_REFLECTOR_PORT);
72
+ this.unicastIpv6.send(msg, MDNS_REFLECTOR_ADDRESS, MDNS_REFLECTOR_PORT);
73
+ });
74
+ 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()}`);
76
+ });
77
+ 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
+ });
80
+ this.log.notice('mDNS Reflector Client started.');
81
+ }
82
+ async stop() {
83
+ this.log.notice('mDNS Reflector Client stopping...');
84
+ const promises = [];
85
+ promises[0] = new Promise((resolve) => {
86
+ this.mdnsIpv4.once('closed', () => resolve());
87
+ this.mdnsIpv4.stop();
88
+ });
89
+ promises[1] = new Promise((resolve) => {
90
+ this.mdnsIpv6.once('closed', () => resolve());
91
+ this.mdnsIpv6.stop();
92
+ });
93
+ promises[2] = new Promise((resolve) => {
94
+ this.unicastIpv4.once('closed', () => resolve());
95
+ this.unicastIpv4.stop();
96
+ });
97
+ promises[3] = new Promise((resolve) => {
98
+ this.unicastIpv6.once('closed', () => resolve());
99
+ this.unicastIpv6.stop();
100
+ });
101
+ await Promise.all(promises);
102
+ this.mdnsIpv4.removeAllListeners();
103
+ this.mdnsIpv6.removeAllListeners();
104
+ this.unicastIpv4.removeAllListeners();
105
+ this.unicastIpv6.removeAllListeners();
106
+ this.log.notice('mDNS Reflector Client stopped.');
107
+ }
108
+ }
@@ -0,0 +1,253 @@
1
+ import os from 'node:os';
2
+ import { AnsiLogger, BLUE, nt } from 'node-ansi-logger';
3
+ import { hasParameter, getStringArrayParameter } from '../utils/commandLine.js';
4
+ import { Mdns } from './mdns.js';
5
+ import { MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_IPV6_ADDRESS, MDNS_MULTICAST_PORT } from './multicast.js';
6
+ import { Unicast } from './unicast.js';
7
+ import { MDNS_REFLECTOR_BIND_ADDRESS_IPV4, MDNS_REFLECTOR_BIND_ADDRESS_IPV6, MDNS_REFLECTOR_PORT } from './mdnsReflectorTypes.js';
8
+ export class MdnsReflectorServer {
9
+ verbose = hasParameter('v') || hasParameter('verbose');
10
+ debug = hasParameter('d') || hasParameter('debug') || hasParameter('v') || hasParameter('verbose');
11
+ silent = hasParameter('s') || hasParameter('silent');
12
+ log = new AnsiLogger({ logName: 'MdnsReflectorServer', logTimestampFormat: 4, logLevel: this.debug ? "debug" : this.silent ? "notice" : "info" });
13
+ mdnsIpv4 = new Mdns('mDNS udp4 Server', MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_PORT, 'udp4', true, undefined, MDNS_REFLECTOR_BIND_ADDRESS_IPV4);
14
+ mdnsIpv6 = new Mdns('mDNS udp6 Server', MDNS_MULTICAST_IPV6_ADDRESS, MDNS_MULTICAST_PORT, 'udp6', true, undefined, MDNS_REFLECTOR_BIND_ADDRESS_IPV6);
15
+ unicastIpv4 = new Unicast('mDNS udp4 Reflector Server', 'udp4', true, undefined, MDNS_REFLECTOR_BIND_ADDRESS_IPV4, MDNS_REFLECTOR_PORT);
16
+ unicastIpv6 = new Unicast('mDNS udp6 Reflector Server', 'udp6', true, undefined, MDNS_REFLECTOR_BIND_ADDRESS_IPV6, MDNS_REFLECTOR_PORT);
17
+ ipv4Clients = new Map();
18
+ ipv6Clients = new Map();
19
+ constructor() {
20
+ this.log.logNameColor = '\x1b[38;5;115m';
21
+ this.mdnsIpv4.log.logNameColor = '\x1b[38;5;115m';
22
+ this.mdnsIpv4.log.logLevel = "warn";
23
+ this.mdnsIpv6.log.logNameColor = '\x1b[38;5;115m';
24
+ this.mdnsIpv6.log.logLevel = "warn";
25
+ this.unicastIpv4.log.logNameColor = '\x1b[38;5;115m';
26
+ this.unicastIpv4.log.logLevel = "warn";
27
+ this.unicastIpv6.log.logNameColor = '\x1b[38;5;115m';
28
+ this.unicastIpv6.log.logLevel = "warn";
29
+ const filters = getStringArrayParameter('filter');
30
+ if (filters)
31
+ this.mdnsIpv4.filters.push(...filters);
32
+ if (filters)
33
+ this.mdnsIpv6.filters.push(...filters);
34
+ }
35
+ getBroadcastAddress(mdns) {
36
+ try {
37
+ const address = mdns.socketType === 'udp4' ? mdns.getIpv4InterfaceAddress(mdns.interfaceName) : mdns.getIpv6InterfaceAddress(mdns.interfaceName);
38
+ const mask = mdns.socketType === 'udp4' ? mdns.getNetmask(address) : undefined;
39
+ const broadcastAddress = mdns.socketType === 'udp4' ? mdns.getIpv4BroadcastAddress(address, mask) : mdns.getIpv6BroadcastAddress();
40
+ return broadcastAddress;
41
+ }
42
+ catch (error) {
43
+ mdns.log.error(`Error getting broadcast address: ${error.message}`);
44
+ }
45
+ }
46
+ upgradeAddress(msg) {
47
+ if (!msg || msg.length < 12)
48
+ return msg;
49
+ const preferredInterfaceName = this.mdnsIpv4.interfaceName ?? this.mdnsIpv6.interfaceName;
50
+ const interfaces = os.networkInterfaces();
51
+ const pickInterface = () => {
52
+ if (preferredInterfaceName) {
53
+ const preferred = interfaces[preferredInterfaceName];
54
+ if (preferred?.some((info) => info && !info.internal))
55
+ return preferredInterfaceName;
56
+ }
57
+ for (const [name, infos] of Object.entries(interfaces)) {
58
+ if (infos?.some((info) => info && !info.internal))
59
+ return name;
60
+ }
61
+ return undefined;
62
+ };
63
+ const selectedInterfaceName = pickInterface();
64
+ this.log.info(`**UpgradeAddress selected interface for address upgrade: ${selectedInterfaceName || 'N/A'}`);
65
+ const selectedInfos = selectedInterfaceName ? (interfaces[selectedInterfaceName] ?? []) : [];
66
+ const hostIpv4 = selectedInfos.find((info) => info && !info.internal && info.family === 'IPv4')?.address;
67
+ const hostIpv6List = (() => {
68
+ const set = new Set();
69
+ for (const info of selectedInfos) {
70
+ if (!info || info.internal || info.family !== 'IPv6')
71
+ continue;
72
+ const normalized = info.address.split('%')[0].toLowerCase();
73
+ if (normalized)
74
+ set.add(normalized);
75
+ }
76
+ return [...set];
77
+ })();
78
+ this.log.info(`**UpgradeAddress Host IPv4 for address upgrade: ${hostIpv4 || 'N/A'}`);
79
+ this.log.info(`**UpgradeAddress Host IPv6 for address upgrade: ${hostIpv6List.length > 0 ? hostIpv6List.join(', ') : 'N/A'}`);
80
+ if (!hostIpv4 && hostIpv6List.length === 0)
81
+ return msg;
82
+ const upgradedMsg = Buffer.from(msg);
83
+ const qdCount = upgradedMsg.readUInt16BE(4);
84
+ const anCount = upgradedMsg.readUInt16BE(6);
85
+ const nsCount = upgradedMsg.readUInt16BE(8);
86
+ const arCount = upgradedMsg.readUInt16BE(10);
87
+ let offset = 12;
88
+ try {
89
+ for (let i = 0; i < qdCount; i++) {
90
+ const qnameResult = this.mdnsIpv4.decodeDnsName(upgradedMsg, offset);
91
+ offset = qnameResult.newOffset;
92
+ offset += 4;
93
+ if (offset > upgradedMsg.length)
94
+ return msg;
95
+ }
96
+ const hostA = hostIpv4 ? this.mdnsIpv4.encodeA(hostIpv4) : undefined;
97
+ const hostAAAAs = hostIpv6List.map((ipv6) => this.mdnsIpv6.encodeAAAA(ipv6));
98
+ let hostAAAAIndex = 0;
99
+ const upgradeResourceRecords = (count) => {
100
+ for (let i = 0; i < count; i++) {
101
+ const nameResult = this.mdnsIpv4.decodeDnsName(upgradedMsg, offset);
102
+ offset = nameResult.newOffset;
103
+ if (offset + 10 > upgradedMsg.length)
104
+ return;
105
+ const type = upgradedMsg.readUInt16BE(offset);
106
+ offset += 2;
107
+ offset += 2;
108
+ offset += 4;
109
+ const rdlength = upgradedMsg.readUInt16BE(offset);
110
+ offset += 2;
111
+ const rdataOffset = offset;
112
+ const endOfRdata = rdataOffset + rdlength;
113
+ if (endOfRdata > upgradedMsg.length)
114
+ return;
115
+ if (type === 1 && rdlength === 4 && hostA) {
116
+ hostA.copy(upgradedMsg, rdataOffset);
117
+ }
118
+ else if (type === 28 && rdlength === 16 && hostAAAAs.length > 0) {
119
+ const hostAAAA = hostAAAAs[Math.min(hostAAAAIndex, hostAAAAs.length - 1)];
120
+ hostAAAA.copy(upgradedMsg, rdataOffset);
121
+ hostAAAAIndex++;
122
+ }
123
+ offset = endOfRdata;
124
+ }
125
+ };
126
+ upgradeResourceRecords(anCount);
127
+ upgradeResourceRecords(nsCount);
128
+ upgradeResourceRecords(arCount);
129
+ }
130
+ catch (error) {
131
+ this.log.error(`**UpgradeAddress failed to parse message: ${error.message}`);
132
+ return msg;
133
+ }
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'}`);
135
+ if (hasParameter('log-reflector-messages')) {
136
+ try {
137
+ let decodedMessage = this.mdnsIpv4.decodeMdnsMessage(msg);
138
+ this.mdnsIpv4.logMdnsMessage(decodedMessage, this.log, '**Original mDNS message');
139
+ decodedMessage = this.mdnsIpv4.decodeMdnsMessage(upgradedMsg);
140
+ this.mdnsIpv4.logMdnsMessage(decodedMessage, this.log, '**Upgraded mDNS message');
141
+ }
142
+ catch (error) {
143
+ this.log.error(`**UpgradeAddress failed to decode message: ${error.message}`);
144
+ }
145
+ }
146
+ return upgradedMsg;
147
+ }
148
+ async start() {
149
+ this.log.notice('mDNS Reflector Server starting...');
150
+ this.mdnsIpv4.on('error', (err) => {
151
+ this.log.error(`mDNS udp4 Server error:\n${err.stack}`);
152
+ });
153
+ this.mdnsIpv6.on('error', (err) => {
154
+ this.log.error(`mDNS udp6 Server error:\n${err.stack}`);
155
+ });
156
+ this.unicastIpv4.on('error', (err) => {
157
+ this.log.error(`mDNS udp4 Reflector Server error:\n${err.stack}`);
158
+ });
159
+ this.unicastIpv6.on('error', (err) => {
160
+ this.log.error(`mDNS udp6 Reflector Server error:\n${err.stack}`);
161
+ });
162
+ const promises = [];
163
+ promises[0] = new Promise((resolve) => {
164
+ this.mdnsIpv4.once('bound', () => resolve());
165
+ this.mdnsIpv4.start();
166
+ });
167
+ promises[1] = new Promise((resolve) => {
168
+ this.mdnsIpv6.once('bound', () => resolve());
169
+ this.mdnsIpv6.start();
170
+ });
171
+ promises[2] = new Promise((resolve) => {
172
+ this.unicastIpv4.once('bound', () => resolve());
173
+ this.unicastIpv4.start();
174
+ });
175
+ promises[3] = new Promise((resolve) => {
176
+ this.unicastIpv6.once('bound', () => resolve());
177
+ this.unicastIpv6.start();
178
+ });
179
+ await Promise.all(promises);
180
+ this.unicastIpv4.on('message', (msg, rinfo) => {
181
+ 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);
184
+ this.mdnsIpv4.send(upgradedMsg, MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_PORT);
185
+ if (hasParameter('broadcast')) {
186
+ const broadcastAddress = this.getBroadcastAddress(this.mdnsIpv4);
187
+ 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}`);
189
+ this.mdnsIpv4.send(upgradedMsg, broadcastAddress, MDNS_MULTICAST_PORT);
190
+ }
191
+ }
192
+ 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}`);
194
+ this.mdnsIpv4.send(upgradedMsg, 'localhost', MDNS_MULTICAST_PORT);
195
+ }
196
+ this.unicastIpv4.send(Buffer.from('mDNS Reflector Server reflected your message'), rinfo.address, rinfo.port);
197
+ });
198
+ this.unicastIpv6.on('message', (msg, rinfo) => {
199
+ 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);
202
+ this.mdnsIpv6.send(upgradedMsg, MDNS_MULTICAST_IPV6_ADDRESS, MDNS_MULTICAST_PORT);
203
+ if (hasParameter('broadcast')) {
204
+ const broadcastAddress = this.getBroadcastAddress(this.mdnsIpv6);
205
+ 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}`);
207
+ this.mdnsIpv6.send(upgradedMsg, broadcastAddress, MDNS_MULTICAST_PORT);
208
+ }
209
+ }
210
+ 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}`);
212
+ this.mdnsIpv6.send(upgradedMsg, 'localhost', MDNS_MULTICAST_PORT);
213
+ }
214
+ this.unicastIpv6.send(Buffer.from('mDNS Reflector Server reflected your message'), rinfo.address, rinfo.port);
215
+ });
216
+ this.log.notice('mDNS Reflector Server started.');
217
+ }
218
+ async stop() {
219
+ this.log.notice('mDNS Reflector Server stopping...');
220
+ for (const client of this.ipv4Clients.values()) {
221
+ this.log.debug(`Notifying ipv4 client ${client.address}:${client.port} about server stopping`);
222
+ this.unicastIpv4.send(Buffer.from('mDNS Reflector Server is stopping'), client.address, client.port);
223
+ }
224
+ for (const client of this.ipv6Clients.values()) {
225
+ this.log.debug(`Notifying ipv6 client ${client.address}:${client.port} about server stopping`);
226
+ this.unicastIpv6.send(Buffer.from('mDNS Reflector Server is stopping'), client.address, client.port);
227
+ }
228
+ await new Promise((resolve) => setTimeout(resolve, 100));
229
+ const promises = [];
230
+ promises[0] = new Promise((resolve) => {
231
+ this.mdnsIpv4.once('closed', () => resolve());
232
+ this.mdnsIpv4.stop();
233
+ });
234
+ promises[1] = new Promise((resolve) => {
235
+ this.mdnsIpv6.once('closed', () => resolve());
236
+ this.mdnsIpv6.stop();
237
+ });
238
+ promises[2] = new Promise((resolve) => {
239
+ this.unicastIpv4.once('closed', () => resolve());
240
+ this.unicastIpv4.stop();
241
+ });
242
+ promises[3] = new Promise((resolve) => {
243
+ this.unicastIpv6.once('closed', () => resolve());
244
+ this.unicastIpv6.stop();
245
+ });
246
+ await Promise.all(promises);
247
+ this.mdnsIpv4.removeAllListeners();
248
+ this.mdnsIpv6.removeAllListeners();
249
+ this.unicastIpv4.removeAllListeners();
250
+ this.unicastIpv6.removeAllListeners();
251
+ this.log.notice('mDNS Reflector Server stopped.');
252
+ }
253
+ }
@@ -0,0 +1,5 @@
1
+ export const MDNS_REFLECTOR_BIND_ADDRESS_IPV4 = '0.0.0.0';
2
+ export const MDNS_REFLECTOR_BIND_ADDRESS_IPV6 = '::';
3
+ export const MDNS_REFLECTOR_ADDRESS = 'localhost';
4
+ export const MDNS_REFLECTOR_HOST_DOCKER = 'host.docker.internal';
5
+ export const MDNS_REFLECTOR_PORT = 15353;
@@ -16,7 +16,7 @@ export function getParameter(name) {
16
16
  let markerIndex = commandArguments.indexOf(`-${name}`);
17
17
  if (markerIndex === -1)
18
18
  markerIndex = commandArguments.indexOf(`--${name}`);
19
- if (markerIndex === -1 || markerIndex + 1 === commandArguments.length)
19
+ if (markerIndex === -1 || markerIndex + 1 === commandArguments.length || commandArguments[markerIndex + 1].startsWith('-'))
20
20
  return undefined;
21
21
  return commandArguments[markerIndex + 1];
22
22
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.4.5-dev-20251225-742588e",
3
+ "version": "3.4.6-dev-20251228-e06f048",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "matterbridge",
9
- "version": "3.4.5-dev-20251225-742588e",
9
+ "version": "3.4.6-dev-20251228-e06f048",
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.5-dev-20251225-742588e",
3
+ "version": "3.4.6-dev-20251228-e06f048",
4
4
  "description": "Matterbridge plugin manager for Matter",
5
5
  "author": "https://github.com/Luligu",
6
6
  "license": "Apache-2.0",
@@ -1,2 +0,0 @@
1
- export const MDNS_REFLECTOR_ADDRESS = '127.0.0.1';
2
- export const MDNS_REFLECTOR_PORT = 15353;