matterbridge 3.1.6 → 3.1.7-dev-20250723-8e073ce
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 +33 -0
- package/README-DOCKER.md +3 -3
- package/bin/mb_coap.js +2 -0
- package/bin/mb_mdns.js +2 -0
- package/dist/cli.js +2 -91
- package/dist/cliEmitter.js +0 -30
- package/dist/clusters/export.js +0 -2
- package/dist/defaultConfigSchema.js +0 -24
- package/dist/deviceManager.js +1 -94
- package/dist/devices/batteryStorage.js +1 -48
- package/dist/devices/dishwasher.js +3 -78
- package/dist/devices/evse.js +10 -74
- package/dist/devices/export.js +0 -2
- package/dist/devices/extractorHood.js +0 -42
- package/dist/devices/heatPump.js +2 -50
- package/dist/devices/laundryDryer.js +6 -83
- package/dist/devices/laundryWasher.js +7 -91
- package/dist/devices/roboticVacuumCleaner.js +7 -93
- package/dist/devices/solarPower.js +0 -38
- package/dist/devices/waterHeater.js +2 -82
- package/dist/dgram/coap.js +252 -0
- package/dist/dgram/dgram.js +2 -113
- package/dist/dgram/mb_coap.js +52 -0
- package/dist/dgram/mb_mdns.js +60 -0
- package/dist/dgram/mdns.js +135 -380
- package/dist/dgram/multicast.js +7 -64
- package/dist/dgram/unicast.js +0 -54
- package/dist/frontend.js +21 -435
- package/dist/globalMatterbridge.js +0 -47
- package/dist/helpers.js +0 -53
- package/dist/index.js +1 -30
- package/dist/logger/export.js +0 -1
- package/dist/matter/behaviors.js +0 -2
- package/dist/matter/clusters.js +0 -2
- package/dist/matter/devices.js +0 -2
- package/dist/matter/endpoints.js +0 -2
- package/dist/matter/export.js +0 -3
- package/dist/matter/types.js +0 -3
- package/dist/matterbridge.js +50 -804
- package/dist/matterbridgeAccessoryPlatform.js +0 -36
- package/dist/matterbridgeBehaviors.js +5 -65
- package/dist/matterbridgeDeviceTypes.js +15 -579
- package/dist/matterbridgeDynamicPlatform.js +0 -36
- package/dist/matterbridgeEndpoint.js +51 -1191
- package/dist/matterbridgeEndpointHelpers.js +13 -322
- package/dist/matterbridgePlatform.js +0 -233
- package/dist/matterbridgeTypes.js +0 -25
- package/dist/pluginManager.js +3 -249
- package/dist/shelly.js +7 -168
- package/dist/storage/export.js +0 -1
- package/dist/update.js +0 -54
- package/dist/utils/colorUtils.js +2 -263
- package/dist/utils/commandLine.js +0 -54
- package/dist/utils/copyDirectory.js +1 -38
- package/dist/utils/createDirectory.js +0 -33
- package/dist/utils/createZip.js +2 -47
- package/dist/utils/deepCopy.js +0 -39
- package/dist/utils/deepEqual.js +1 -72
- package/dist/utils/error.js +0 -41
- package/dist/utils/export.js +0 -1
- package/dist/utils/hex.js +0 -58
- package/dist/utils/isvalid.js +0 -101
- package/dist/utils/network.js +5 -81
- package/dist/utils/spawn.js +0 -40
- package/dist/utils/wait.js +9 -62
- package/npm-shrinkwrap.json +5 -3
- package/package.json +4 -3
- package/dist/cli.d.ts +0 -26
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/cliEmitter.d.ts +0 -34
- package/dist/cliEmitter.d.ts.map +0 -1
- package/dist/cliEmitter.js.map +0 -1
- package/dist/clusters/export.d.ts +0 -2
- package/dist/clusters/export.d.ts.map +0 -1
- package/dist/clusters/export.js.map +0 -1
- package/dist/defaultConfigSchema.d.ts +0 -28
- package/dist/defaultConfigSchema.d.ts.map +0 -1
- package/dist/defaultConfigSchema.js.map +0 -1
- package/dist/deviceManager.d.ts +0 -112
- package/dist/deviceManager.d.ts.map +0 -1
- package/dist/deviceManager.js.map +0 -1
- package/dist/devices/batteryStorage.d.ts +0 -48
- package/dist/devices/batteryStorage.d.ts.map +0 -1
- package/dist/devices/batteryStorage.js.map +0 -1
- package/dist/devices/dishwasher.d.ts +0 -91
- package/dist/devices/dishwasher.d.ts.map +0 -1
- package/dist/devices/dishwasher.js.map +0 -1
- package/dist/devices/evse.d.ts +0 -75
- package/dist/devices/evse.d.ts.map +0 -1
- package/dist/devices/evse.js.map +0 -1
- package/dist/devices/export.d.ts +0 -11
- package/dist/devices/export.d.ts.map +0 -1
- package/dist/devices/export.js.map +0 -1
- package/dist/devices/extractorHood.d.ts +0 -46
- package/dist/devices/extractorHood.d.ts.map +0 -1
- package/dist/devices/extractorHood.js.map +0 -1
- package/dist/devices/heatPump.d.ts +0 -47
- package/dist/devices/heatPump.d.ts.map +0 -1
- package/dist/devices/heatPump.js.map +0 -1
- package/dist/devices/laundryDryer.d.ts +0 -87
- package/dist/devices/laundryDryer.d.ts.map +0 -1
- package/dist/devices/laundryDryer.js.map +0 -1
- package/dist/devices/laundryWasher.d.ts +0 -242
- package/dist/devices/laundryWasher.d.ts.map +0 -1
- package/dist/devices/laundryWasher.js.map +0 -1
- package/dist/devices/roboticVacuumCleaner.d.ts +0 -112
- package/dist/devices/roboticVacuumCleaner.d.ts.map +0 -1
- package/dist/devices/roboticVacuumCleaner.js.map +0 -1
- package/dist/devices/solarPower.d.ts +0 -40
- package/dist/devices/solarPower.d.ts.map +0 -1
- package/dist/devices/solarPower.js.map +0 -1
- package/dist/devices/waterHeater.d.ts +0 -111
- package/dist/devices/waterHeater.d.ts.map +0 -1
- package/dist/devices/waterHeater.js.map +0 -1
- package/dist/dgram/dgram.d.ts +0 -140
- package/dist/dgram/dgram.d.ts.map +0 -1
- package/dist/dgram/dgram.js.map +0 -1
- package/dist/dgram/mdns.d.ts +0 -288
- package/dist/dgram/mdns.d.ts.map +0 -1
- package/dist/dgram/mdns.js.map +0 -1
- package/dist/dgram/multicast.d.ts +0 -65
- package/dist/dgram/multicast.d.ts.map +0 -1
- package/dist/dgram/multicast.js.map +0 -1
- package/dist/dgram/unicast.d.ts +0 -56
- package/dist/dgram/unicast.d.ts.map +0 -1
- package/dist/dgram/unicast.js.map +0 -1
- package/dist/frontend.d.ts +0 -304
- package/dist/frontend.d.ts.map +0 -1
- package/dist/frontend.js.map +0 -1
- package/dist/globalMatterbridge.d.ts +0 -59
- package/dist/globalMatterbridge.d.ts.map +0 -1
- package/dist/globalMatterbridge.js.map +0 -1
- package/dist/helpers.d.ts +0 -48
- package/dist/helpers.d.ts.map +0 -1
- package/dist/helpers.js.map +0 -1
- package/dist/index.d.ts +0 -33
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/logger/export.d.ts +0 -2
- package/dist/logger/export.d.ts.map +0 -1
- package/dist/logger/export.js.map +0 -1
- package/dist/matter/behaviors.d.ts +0 -2
- package/dist/matter/behaviors.d.ts.map +0 -1
- package/dist/matter/behaviors.js.map +0 -1
- package/dist/matter/clusters.d.ts +0 -2
- package/dist/matter/clusters.d.ts.map +0 -1
- package/dist/matter/clusters.js.map +0 -1
- package/dist/matter/devices.d.ts +0 -2
- package/dist/matter/devices.d.ts.map +0 -1
- package/dist/matter/devices.js.map +0 -1
- package/dist/matter/endpoints.d.ts +0 -2
- package/dist/matter/endpoints.d.ts.map +0 -1
- package/dist/matter/endpoints.js.map +0 -1
- package/dist/matter/export.d.ts +0 -5
- package/dist/matter/export.d.ts.map +0 -1
- package/dist/matter/export.js.map +0 -1
- package/dist/matter/types.d.ts +0 -3
- package/dist/matter/types.d.ts.map +0 -1
- package/dist/matter/types.js.map +0 -1
- package/dist/matterbridge.d.ts +0 -460
- package/dist/matterbridge.d.ts.map +0 -1
- package/dist/matterbridge.js.map +0 -1
- package/dist/matterbridgeAccessoryPlatform.d.ts +0 -42
- package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
- package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
- package/dist/matterbridgeBehaviors.d.ts +0 -1351
- package/dist/matterbridgeBehaviors.d.ts.map +0 -1
- package/dist/matterbridgeBehaviors.js.map +0 -1
- package/dist/matterbridgeDeviceTypes.d.ts +0 -709
- package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
- package/dist/matterbridgeDeviceTypes.js.map +0 -1
- package/dist/matterbridgeDynamicPlatform.d.ts +0 -42
- package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
- package/dist/matterbridgeDynamicPlatform.js.map +0 -1
- package/dist/matterbridgeEndpoint.d.ts +0 -1328
- package/dist/matterbridgeEndpoint.d.ts.map +0 -1
- package/dist/matterbridgeEndpoint.js.map +0 -1
- package/dist/matterbridgeEndpointHelpers.d.ts +0 -3198
- package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
- package/dist/matterbridgeEndpointHelpers.js.map +0 -1
- package/dist/matterbridgePlatform.d.ts +0 -310
- package/dist/matterbridgePlatform.d.ts.map +0 -1
- package/dist/matterbridgePlatform.js.map +0 -1
- package/dist/matterbridgeTypes.d.ts +0 -195
- package/dist/matterbridgeTypes.d.ts.map +0 -1
- package/dist/matterbridgeTypes.js.map +0 -1
- package/dist/pluginManager.d.ts +0 -270
- package/dist/pluginManager.d.ts.map +0 -1
- package/dist/pluginManager.js.map +0 -1
- package/dist/shelly.d.ts +0 -174
- package/dist/shelly.d.ts.map +0 -1
- package/dist/shelly.js.map +0 -1
- package/dist/storage/export.d.ts +0 -2
- package/dist/storage/export.d.ts.map +0 -1
- package/dist/storage/export.js.map +0 -1
- package/dist/update.d.ts +0 -59
- package/dist/update.d.ts.map +0 -1
- package/dist/update.js.map +0 -1
- package/dist/utils/colorUtils.d.ts +0 -117
- package/dist/utils/colorUtils.d.ts.map +0 -1
- package/dist/utils/colorUtils.js.map +0 -1
- package/dist/utils/commandLine.d.ts +0 -59
- package/dist/utils/commandLine.d.ts.map +0 -1
- package/dist/utils/commandLine.js.map +0 -1
- package/dist/utils/copyDirectory.d.ts +0 -33
- package/dist/utils/copyDirectory.d.ts.map +0 -1
- package/dist/utils/copyDirectory.js.map +0 -1
- package/dist/utils/createDirectory.d.ts +0 -34
- package/dist/utils/createDirectory.d.ts.map +0 -1
- package/dist/utils/createDirectory.js.map +0 -1
- package/dist/utils/createZip.d.ts +0 -39
- package/dist/utils/createZip.d.ts.map +0 -1
- package/dist/utils/createZip.js.map +0 -1
- package/dist/utils/deepCopy.d.ts +0 -32
- package/dist/utils/deepCopy.d.ts.map +0 -1
- package/dist/utils/deepCopy.js.map +0 -1
- package/dist/utils/deepEqual.d.ts +0 -54
- package/dist/utils/deepEqual.d.ts.map +0 -1
- package/dist/utils/deepEqual.js.map +0 -1
- package/dist/utils/error.d.ts +0 -44
- package/dist/utils/error.d.ts.map +0 -1
- package/dist/utils/error.js.map +0 -1
- package/dist/utils/export.d.ts +0 -12
- package/dist/utils/export.d.ts.map +0 -1
- package/dist/utils/export.js.map +0 -1
- package/dist/utils/hex.d.ts +0 -49
- package/dist/utils/hex.d.ts.map +0 -1
- package/dist/utils/hex.js.map +0 -1
- package/dist/utils/isvalid.d.ts +0 -103
- package/dist/utils/isvalid.d.ts.map +0 -1
- package/dist/utils/isvalid.js.map +0 -1
- package/dist/utils/network.d.ts +0 -74
- package/dist/utils/network.d.ts.map +0 -1
- package/dist/utils/network.js.map +0 -1
- package/dist/utils/spawn.d.ts +0 -33
- package/dist/utils/spawn.d.ts.map +0 -1
- package/dist/utils/spawn.js.map +0 -1
- package/dist/utils/wait.d.ts +0 -56
- package/dist/utils/wait.d.ts.map +0 -1
- package/dist/utils/wait.js.map +0 -1
package/dist/dgram/mdns.js
CHANGED
|
@@ -1,30 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @description This file contains the class Mdns.
|
|
3
|
-
* @file mdns.ts
|
|
4
|
-
* @author Luca Liguori
|
|
5
|
-
* @created 2025-03-22
|
|
6
|
-
* @version 1.0.0
|
|
7
|
-
* @license Apache-2.0
|
|
8
|
-
*
|
|
9
|
-
* Copyright 2025, 2026, 2027 Luca Liguori.
|
|
10
|
-
*
|
|
11
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
12
|
-
* you may not use this file except in compliance with the License.
|
|
13
|
-
* You may obtain a copy of the License at
|
|
14
|
-
*
|
|
15
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
16
|
-
*
|
|
17
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
18
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
19
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
20
|
-
* See the License for the specific language governing permissions and
|
|
21
|
-
* limitations under the License.
|
|
22
|
-
*/
|
|
23
|
-
// AnsiLogger imports
|
|
24
1
|
import { BLUE, CYAN, db, er, GREEN, idn, MAGENTA, nf, rs } from 'node-ansi-logger';
|
|
25
|
-
|
|
26
|
-
import { MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_IPV6_ADDRESS, MDNS_MULTICAST_PORT, Multicast } from './multicast.js';
|
|
27
|
-
// Node.js imports
|
|
2
|
+
import { Multicast } from './multicast.js';
|
|
28
3
|
export var DnsRecordType;
|
|
29
4
|
(function (DnsRecordType) {
|
|
30
5
|
DnsRecordType[DnsRecordType["A"] = 1] = "A";
|
|
@@ -115,7 +90,6 @@ export var DnsRecordType;
|
|
|
115
90
|
DnsRecordType[DnsRecordType["DOA"] = 259] = "DOA";
|
|
116
91
|
DnsRecordType[DnsRecordType["AMTRELAY"] = 260] = "AMTRELAY";
|
|
117
92
|
DnsRecordType[DnsRecordType["ZONEVERSION"] = 261] = "ZONEVERSION";
|
|
118
|
-
// 262-32767 are unassigned/reserved
|
|
119
93
|
DnsRecordType[DnsRecordType["TA"] = 32768] = "TA";
|
|
120
94
|
DnsRecordType[DnsRecordType["DLV"] = 32769] = "DLV";
|
|
121
95
|
})(DnsRecordType || (DnsRecordType = {}));
|
|
@@ -129,23 +103,11 @@ export var DnsClass;
|
|
|
129
103
|
export var DnsClassFlag;
|
|
130
104
|
(function (DnsClassFlag) {
|
|
131
105
|
DnsClassFlag[DnsClassFlag["FLUSH"] = 32768] = "FLUSH";
|
|
132
|
-
// eslint-disable-next-line @typescript-eslint/no-duplicate-enum-values
|
|
133
106
|
DnsClassFlag[DnsClassFlag["QU"] = 32768] = "QU";
|
|
134
107
|
})(DnsClassFlag || (DnsClassFlag = {}));
|
|
135
108
|
export class Mdns extends Multicast {
|
|
136
109
|
deviceQueries = new Map();
|
|
137
110
|
deviceResponses = new Map();
|
|
138
|
-
/**
|
|
139
|
-
* Creates an instance of the Mdns class.
|
|
140
|
-
*
|
|
141
|
-
* @param {string} name - The internal name of the mDNS server for the logs.
|
|
142
|
-
* @param {string} multicastAddress - The multicast address for mDNS (i.e. 224.0.0.251 for udp4 or ff02::fb for udp6).
|
|
143
|
-
* @param {number} multicastPort - The port for mDNS (i.e. 5353).
|
|
144
|
-
* @param {('udp4' | 'udp6')} socketType - The type of socket to create (either 'udp4' or 'udp6').
|
|
145
|
-
* @param {boolean} [reuseAddr] - Whether to reuse the address. Defaults to true.
|
|
146
|
-
* @param {string} [interfaceName] - The optional name of the network interface to use.
|
|
147
|
-
* @param {string} [interfaceAddress] - The optional IP address of the network interface to use.
|
|
148
|
-
*/
|
|
149
111
|
constructor(name, multicastAddress, multicastPort, socketType, reuseAddr = true, interfaceName, interfaceAddress) {
|
|
150
112
|
super(name, multicastAddress, multicastPort, socketType, reuseAddr, interfaceName, interfaceAddress);
|
|
151
113
|
}
|
|
@@ -164,9 +126,9 @@ export class Mdns extends Multicast {
|
|
|
164
126
|
this.onQuery(rinfo, result);
|
|
165
127
|
}
|
|
166
128
|
else {
|
|
167
|
-
const ptr = result.answers?.find((record) => record.name === '_shelly._tcp.local' && record.type === 12
|
|
168
|
-
result.answers?.find((record) => record.name === '_http._tcp.local' && record.type === 12
|
|
169
|
-
result.answers?.find((record) => record.type === 12
|
|
129
|
+
const ptr = result.answers?.find((record) => record.name === '_shelly._tcp.local' && record.type === 12) ||
|
|
130
|
+
result.answers?.find((record) => record.name === '_http._tcp.local' && record.type === 12) ||
|
|
131
|
+
result.answers?.find((record) => record.type === 12);
|
|
170
132
|
this.deviceResponses.set(rinfo.address, { rinfo, response: result, dataPTR: ptr?.data });
|
|
171
133
|
this.onResponse(rinfo, result);
|
|
172
134
|
}
|
|
@@ -176,28 +138,20 @@ export class Mdns extends Multicast {
|
|
|
176
138
|
this.log.error(`Error decoding mDNS message: ${error instanceof Error ? error.message : error}`);
|
|
177
139
|
}
|
|
178
140
|
}
|
|
179
|
-
/**
|
|
180
|
-
* Decodes an mDNS message, including the header, question section, answer section,
|
|
181
|
-
* authority section, and additional section.
|
|
182
|
-
*
|
|
183
|
-
* @param {Buffer} msg - The raw mDNS message buffer.
|
|
184
|
-
* @returns {MdnsMessage} An object representing the decoded mDNS message.
|
|
185
|
-
* @throws Error if the message is too short.
|
|
186
|
-
*/
|
|
187
141
|
decodeMdnsMessage(msg) {
|
|
188
142
|
if (msg.length < 12) {
|
|
189
143
|
throw new Error('mDNS message too short');
|
|
190
144
|
}
|
|
191
145
|
const id = msg.readUInt16BE(0);
|
|
192
146
|
const flags = msg.readUInt16BE(2);
|
|
193
|
-
const qr = (flags & 0x8000) >> 15;
|
|
194
|
-
const opcode = (flags & 0x7800) >> 11;
|
|
195
|
-
const aa = Boolean(flags & 0x0400);
|
|
196
|
-
const tc = Boolean(flags & 0x0200);
|
|
197
|
-
const rd = Boolean(flags & 0x0100);
|
|
198
|
-
const ra = Boolean(flags & 0x0080);
|
|
199
|
-
const z = (flags & 0x0070) >> 4;
|
|
200
|
-
const rcode = flags & 0x000f;
|
|
147
|
+
const qr = (flags & 0x8000) >> 15;
|
|
148
|
+
const opcode = (flags & 0x7800) >> 11;
|
|
149
|
+
const aa = Boolean(flags & 0x0400);
|
|
150
|
+
const tc = Boolean(flags & 0x0200);
|
|
151
|
+
const rd = Boolean(flags & 0x0100);
|
|
152
|
+
const ra = Boolean(flags & 0x0080);
|
|
153
|
+
const z = (flags & 0x0070) >> 4;
|
|
154
|
+
const rcode = flags & 0x000f;
|
|
201
155
|
const qdCount = msg.readUInt16BE(4);
|
|
202
156
|
const anCount = msg.readUInt16BE(6);
|
|
203
157
|
const nsCount = msg.readUInt16BE(8);
|
|
@@ -222,7 +176,6 @@ export class Mdns extends Multicast {
|
|
|
222
176
|
additionals: [],
|
|
223
177
|
};
|
|
224
178
|
let offset = 12;
|
|
225
|
-
// Decode the question section.
|
|
226
179
|
for (let i = 0; i < qdCount; i++) {
|
|
227
180
|
const qnameResult = this.decodeDnsName(msg, offset);
|
|
228
181
|
const qname = qnameResult.name;
|
|
@@ -233,19 +186,16 @@ export class Mdns extends Multicast {
|
|
|
233
186
|
offset += 2;
|
|
234
187
|
mdnsMessage.questions?.push({ name: qname, type: qtype, class: qclass });
|
|
235
188
|
}
|
|
236
|
-
// Decode the answer section.
|
|
237
189
|
for (let i = 0; i < anCount; i++) {
|
|
238
190
|
const rrResult = this.decodeResourceRecord(msg, offset);
|
|
239
191
|
mdnsMessage.answers?.push(rrResult.record);
|
|
240
192
|
offset = rrResult.newOffset;
|
|
241
193
|
}
|
|
242
|
-
// Decode the authority (NS) section.
|
|
243
194
|
for (let i = 0; i < nsCount; i++) {
|
|
244
195
|
const rrResult = this.decodeResourceRecord(msg, offset);
|
|
245
196
|
mdnsMessage.authorities?.push(rrResult.record);
|
|
246
197
|
offset = rrResult.newOffset;
|
|
247
198
|
}
|
|
248
|
-
// Decode the additional records section.
|
|
249
199
|
for (let i = 0; i < arCount; i++) {
|
|
250
200
|
const rrResult = this.decodeResourceRecord(msg, offset);
|
|
251
201
|
mdnsMessage.additionals?.push(rrResult.record);
|
|
@@ -253,25 +203,15 @@ export class Mdns extends Multicast {
|
|
|
253
203
|
}
|
|
254
204
|
return mdnsMessage;
|
|
255
205
|
}
|
|
256
|
-
/**
|
|
257
|
-
* Decodes a DNS name from a buffer, handling compression.
|
|
258
|
-
*
|
|
259
|
-
* @param {Buffer} msg - The full mDNS message buffer.
|
|
260
|
-
* @param {number} offset - The offset at which the DNS name starts.
|
|
261
|
-
* @returns {{ name: string; newOffset: number }} An object with the decoded name and the new offset.
|
|
262
|
-
* @throws Error if the offset exceeds the buffer length or too many iterations are performed.
|
|
263
|
-
*/
|
|
264
206
|
decodeDnsName(msg, offset) {
|
|
265
207
|
const labels = [];
|
|
266
208
|
let jumped = false;
|
|
267
209
|
let originalOffset = offset;
|
|
268
|
-
let iterations = 0;
|
|
210
|
+
let iterations = 0;
|
|
269
211
|
while (true) {
|
|
270
|
-
// Safety guard: prevent infinite loops in malformed messages.
|
|
271
212
|
if (iterations++ > 1000) {
|
|
272
213
|
throw new Error('Too many iterations while decoding DNS name. Possible malformed message.');
|
|
273
214
|
}
|
|
274
|
-
// Check that offset is within buffer bounds.
|
|
275
215
|
if (offset >= msg.length) {
|
|
276
216
|
throw new Error('Offset exceeds buffer length while decoding DNS name.');
|
|
277
217
|
}
|
|
@@ -280,9 +220,7 @@ export class Mdns extends Multicast {
|
|
|
280
220
|
offset++;
|
|
281
221
|
break;
|
|
282
222
|
}
|
|
283
|
-
// Check for pointer (first two bits are 11)
|
|
284
223
|
if ((len & 0xc0) === 0xc0) {
|
|
285
|
-
// Ensure the pointer has two bytes available.
|
|
286
224
|
if (offset + 1 >= msg.length) {
|
|
287
225
|
throw new Error('Incomplete pointer encountered while decoding DNS name.');
|
|
288
226
|
}
|
|
@@ -295,7 +233,6 @@ export class Mdns extends Multicast {
|
|
|
295
233
|
continue;
|
|
296
234
|
}
|
|
297
235
|
offset++;
|
|
298
|
-
// Check that the label length doesn't go beyond the buffer.
|
|
299
236
|
if (offset + len > msg.length) {
|
|
300
237
|
throw new Error('Label length exceeds buffer bounds while decoding DNS name.');
|
|
301
238
|
}
|
|
@@ -304,15 +241,6 @@ export class Mdns extends Multicast {
|
|
|
304
241
|
}
|
|
305
242
|
return { name: labels.join('.'), newOffset: jumped ? originalOffset : offset };
|
|
306
243
|
}
|
|
307
|
-
/**
|
|
308
|
-
* Encodes a domain name into the DNS label format.
|
|
309
|
-
*
|
|
310
|
-
* For example, "example.local" becomes:
|
|
311
|
-
* [7] "example" [5] "local" [0]
|
|
312
|
-
*
|
|
313
|
-
* @param {string} name - The domain name to encode.
|
|
314
|
-
* @returns {Buffer} The encoded domain name as a Buffer.
|
|
315
|
-
*/
|
|
316
244
|
encodeDnsName(name) {
|
|
317
245
|
const labels = name.split('.');
|
|
318
246
|
const buffers = labels.map((label) => {
|
|
@@ -320,22 +248,12 @@ export class Mdns extends Multicast {
|
|
|
320
248
|
lenBuf.writeUInt8(label.length, 0);
|
|
321
249
|
return Buffer.concat([lenBuf, Buffer.from(label)]);
|
|
322
250
|
});
|
|
323
|
-
// Append the null byte to terminate the name.
|
|
324
251
|
return Buffer.concat([...buffers, Buffer.from([0])]);
|
|
325
252
|
}
|
|
326
|
-
/**
|
|
327
|
-
* Decodes a DNS resource record.
|
|
328
|
-
*
|
|
329
|
-
* @param {Buffer} msg - The full mDNS message buffer.
|
|
330
|
-
* @param {number} offset - The offset at which the resource record starts.
|
|
331
|
-
* @returns {{ record: MdnsRecord; newOffset: number }} An object containing the decoded record and the new offset.
|
|
332
|
-
*/
|
|
333
253
|
decodeResourceRecord(msg, offset) {
|
|
334
|
-
// Decode the NAME field (which may be compressed)
|
|
335
254
|
const nameResult = this.decodeDnsName(msg, offset);
|
|
336
255
|
const name = nameResult.name;
|
|
337
256
|
offset = nameResult.newOffset;
|
|
338
|
-
// Read TYPE (16 bits), CLASS (16 bits), TTL (32 bits), and RDLENGTH (16 bits)
|
|
339
257
|
const type = msg.readUInt16BE(offset);
|
|
340
258
|
offset += 2;
|
|
341
259
|
const rrclass = msg.readUInt16BE(offset);
|
|
@@ -345,14 +263,12 @@ export class Mdns extends Multicast {
|
|
|
345
263
|
const rdlength = msg.readUInt16BE(offset);
|
|
346
264
|
offset += 2;
|
|
347
265
|
let data = '';
|
|
348
|
-
if (type === 12
|
|
349
|
-
// PTR record (type 12): decode its RDATA as a domain name.
|
|
266
|
+
if (type === 12) {
|
|
350
267
|
const ptrResult = this.decodeDnsName(msg, offset);
|
|
351
268
|
data = ptrResult.name;
|
|
352
269
|
offset += rdlength;
|
|
353
270
|
}
|
|
354
|
-
else if (type === 16
|
|
355
|
-
// TXT record: may consist of one or more length-prefixed strings.
|
|
271
|
+
else if (type === 16) {
|
|
356
272
|
const txtStrings = [];
|
|
357
273
|
const end = offset + rdlength;
|
|
358
274
|
while (offset < end) {
|
|
@@ -364,8 +280,7 @@ export class Mdns extends Multicast {
|
|
|
364
280
|
}
|
|
365
281
|
data = txtStrings.join(', ');
|
|
366
282
|
}
|
|
367
|
-
else if (type === 33
|
|
368
|
-
// SRV record (type === 33): consists of 2 bytes for priority, 2 for weight, 2 for port, followed by the target domain name.
|
|
283
|
+
else if (type === 33) {
|
|
369
284
|
const priority = msg.readUInt16BE(offset);
|
|
370
285
|
const weight = msg.readUInt16BE(offset + 2);
|
|
371
286
|
const port = msg.readUInt16BE(offset + 4);
|
|
@@ -379,16 +294,13 @@ export class Mdns extends Multicast {
|
|
|
379
294
|
});
|
|
380
295
|
offset = srvTargetResult.newOffset;
|
|
381
296
|
}
|
|
382
|
-
else if (type === 1
|
|
383
|
-
// A record (type 1): an IPv4 address stored in 4 bytes.
|
|
297
|
+
else if (type === 1) {
|
|
384
298
|
const ipBytes = msg.slice(offset, offset + 4);
|
|
385
299
|
data = Array.from(ipBytes).join('.');
|
|
386
300
|
offset += 4;
|
|
387
301
|
}
|
|
388
|
-
else if (type === 28
|
|
389
|
-
// AAAA record (type 28): IPv6 address stored in 16 bytes.
|
|
302
|
+
else if (type === 28) {
|
|
390
303
|
const ipBytes = msg.slice(offset, offset + 16);
|
|
391
|
-
// Convert the 16 bytes into an IPv6 address string (colon-separated)
|
|
392
304
|
const ipv6Parts = [];
|
|
393
305
|
for (let i = 0; i < 16; i += 2) {
|
|
394
306
|
ipv6Parts.push(ipBytes.readUInt16BE(i).toString(16));
|
|
@@ -396,14 +308,10 @@ export class Mdns extends Multicast {
|
|
|
396
308
|
data = ipv6Parts.join(':');
|
|
397
309
|
offset += 16;
|
|
398
310
|
}
|
|
399
|
-
else if (type === 47
|
|
400
|
-
// NSEC record: RDATA consists of:
|
|
401
|
-
// - Next Domain Name (in DNS label format)
|
|
402
|
-
// - Type Bit Maps (variable length)
|
|
311
|
+
else if (type === 47) {
|
|
403
312
|
const { name: nextDomain, newOffset } = this.decodeDnsName(msg, offset);
|
|
404
313
|
const nextDomainLength = newOffset - offset;
|
|
405
314
|
offset = newOffset;
|
|
406
|
-
// Calculate the remaining length for the type bit maps.
|
|
407
315
|
const bitmapLength = rdlength - nextDomainLength;
|
|
408
316
|
const bitmapData = msg.slice(offset, offset + bitmapLength);
|
|
409
317
|
const types = [];
|
|
@@ -430,7 +338,6 @@ export class Mdns extends Multicast {
|
|
|
430
338
|
offset += bitmapLength;
|
|
431
339
|
}
|
|
432
340
|
else {
|
|
433
|
-
// Fall back
|
|
434
341
|
data = msg.slice(offset, offset + rdlength).toString('hex');
|
|
435
342
|
offset += rdlength;
|
|
436
343
|
}
|
|
@@ -439,28 +346,19 @@ export class Mdns extends Multicast {
|
|
|
439
346
|
newOffset: offset,
|
|
440
347
|
};
|
|
441
348
|
}
|
|
442
|
-
/**
|
|
443
|
-
* Sends a DNS query with multiple questions.
|
|
444
|
-
*
|
|
445
|
-
* @param {Array<{ name: string; type: number; class: number; unicastResponse?: boolean }>} questions - Array of questions
|
|
446
|
-
*
|
|
447
|
-
* @remarks
|
|
448
|
-
* Each question should have a name (e.g., "_http._tcp.local"), type (e.g., DnsRecordType.PTR), class (e.g., DnsClass.IN),
|
|
449
|
-
* and an optional unicastResponse flag (this will add the DnsClassFlag.QU flag to the query).
|
|
450
|
-
*/
|
|
451
349
|
sendQuery(questions) {
|
|
452
350
|
const header = Buffer.alloc(12);
|
|
453
|
-
header.writeUInt16BE(0, 0);
|
|
454
|
-
header.writeUInt16BE(0, 2);
|
|
455
|
-
header.writeUInt16BE(questions.length, 4);
|
|
456
|
-
header.writeUInt16BE(0, 6);
|
|
457
|
-
header.writeUInt16BE(0, 8);
|
|
458
|
-
header.writeUInt16BE(0, 10);
|
|
351
|
+
header.writeUInt16BE(0, 0);
|
|
352
|
+
header.writeUInt16BE(0, 2);
|
|
353
|
+
header.writeUInt16BE(questions.length, 4);
|
|
354
|
+
header.writeUInt16BE(0, 6);
|
|
355
|
+
header.writeUInt16BE(0, 8);
|
|
356
|
+
header.writeUInt16BE(0, 10);
|
|
459
357
|
const questionBuffers = questions.map(({ name, type: qtype, class: qclass, unicastResponse = false }) => {
|
|
460
358
|
const qname = this.encodeDnsName(name);
|
|
461
359
|
const qfields = Buffer.alloc(4);
|
|
462
360
|
qfields.writeUInt16BE(qtype, 0);
|
|
463
|
-
qfields.writeUInt16BE(unicastResponse ? qclass | 32768
|
|
361
|
+
qfields.writeUInt16BE(unicastResponse ? qclass | 32768 : qclass, 2);
|
|
464
362
|
return Buffer.concat([qname, qfields]);
|
|
465
363
|
});
|
|
466
364
|
const query = Buffer.concat([header, ...questionBuffers]);
|
|
@@ -480,46 +378,22 @@ export class Mdns extends Multicast {
|
|
|
480
378
|
}
|
|
481
379
|
});
|
|
482
380
|
}
|
|
483
|
-
/**
|
|
484
|
-
* Constructs an mDNS response packet and sends it to the multicast address and port.
|
|
485
|
-
*
|
|
486
|
-
* @param {string} name - The domain name being responded to (e.g., "example.local").
|
|
487
|
-
* @param {number} rtype - The response type (e.g., 1 for A, 28 for AAAA, etc.).
|
|
488
|
-
* @param {number} rclass - The response class (typically 1 for IN).
|
|
489
|
-
* @param {number} ttl - The time-to-live for the answer record.
|
|
490
|
-
* @param {Buffer} rdata - The resource data for the response (e.g., 4 bytes for an A record IPv4 address).
|
|
491
|
-
*
|
|
492
|
-
* @example
|
|
493
|
-
* const ptrRdata = mdnsIpv4.encodeDnsName('matterbridge._http._tcp.local');
|
|
494
|
-
* mdnsIpv4.sendResponse('_http._tcp.local', DnsRecordType.PTR, DnsClass.IN, 120, ptrRdata);
|
|
495
|
-
*/
|
|
496
381
|
sendResponse(name, rtype, rclass, ttl, rdata) {
|
|
497
|
-
// Create a 12-byte DNS header.
|
|
498
382
|
const header = Buffer.alloc(12);
|
|
499
|
-
header.writeUInt16BE(0, 0);
|
|
500
|
-
// Set flags: QR (response) bit and AA (authoritative answer) bit.
|
|
383
|
+
header.writeUInt16BE(0, 0);
|
|
501
384
|
header.writeUInt16BE(0x8400, 2);
|
|
502
|
-
header.writeUInt16BE(0, 4);
|
|
503
|
-
header.writeUInt16BE(1, 6);
|
|
504
|
-
header.writeUInt16BE(0, 8);
|
|
505
|
-
header.writeUInt16BE(0, 10);
|
|
506
|
-
// Encode the domain name in DNS label format.
|
|
385
|
+
header.writeUInt16BE(0, 4);
|
|
386
|
+
header.writeUInt16BE(1, 6);
|
|
387
|
+
header.writeUInt16BE(0, 8);
|
|
388
|
+
header.writeUInt16BE(0, 10);
|
|
507
389
|
const aname = this.encodeDnsName(name);
|
|
508
|
-
// Prepare the fixed part of the answer record:
|
|
509
|
-
// - 2 bytes for qtype,
|
|
510
|
-
// - 2 bytes for qclass,
|
|
511
|
-
// - 4 bytes for TTL,
|
|
512
|
-
// - 2 bytes for RDLENGTH (length of the rdata).
|
|
513
390
|
const answerFixed = Buffer.alloc(10);
|
|
514
|
-
answerFixed.writeUInt16BE(rtype, 0);
|
|
515
|
-
answerFixed.writeUInt16BE(rclass, 2);
|
|
516
|
-
answerFixed.writeUInt32BE(ttl, 4);
|
|
517
|
-
answerFixed.writeUInt16BE(rdata.length, 8);
|
|
518
|
-
// Concatenate the answer: encoded name, fixed fields, and resource data.
|
|
391
|
+
answerFixed.writeUInt16BE(rtype, 0);
|
|
392
|
+
answerFixed.writeUInt16BE(rclass, 2);
|
|
393
|
+
answerFixed.writeUInt32BE(ttl, 4);
|
|
394
|
+
answerFixed.writeUInt16BE(rdata.length, 8);
|
|
519
395
|
const answer = Buffer.concat([aname, answerFixed, rdata]);
|
|
520
|
-
// Concatenate header and answer to form the complete mDNS response packet.
|
|
521
396
|
const response = Buffer.concat([header, answer]);
|
|
522
|
-
// Send the response packet via the socket.
|
|
523
397
|
this.socket.send(response, 0, response.length, this.multicastPort, this.multicastAddress, (error) => {
|
|
524
398
|
if (error) {
|
|
525
399
|
this.log.error(`Dgram mDNS server failed to send response message for ${MAGENTA}${name}${er} type ${MAGENTA}${this.dnsTypeToString(rtype)}${er} class ${MAGENTA}${this.dnsResponseClassToString(rclass)}${er} ttl ${MAGENTA}${ttl}${er}: ${error instanceof Error ? error.message : error}`);
|
|
@@ -531,128 +405,116 @@ export class Mdns extends Multicast {
|
|
|
531
405
|
}
|
|
532
406
|
});
|
|
533
407
|
}
|
|
534
|
-
/**
|
|
535
|
-
* Converts a DNS record type numeric value to its string representation.
|
|
536
|
-
*
|
|
537
|
-
* @param {number} type - The numeric DNS record type.
|
|
538
|
-
* @returns {string} The string representation of the record type.
|
|
539
|
-
*/
|
|
540
408
|
dnsTypeToString(type) {
|
|
541
409
|
const typeMap = {
|
|
542
|
-
[1
|
|
543
|
-
[2
|
|
544
|
-
[3
|
|
545
|
-
[4
|
|
546
|
-
[5
|
|
547
|
-
[6
|
|
548
|
-
[7
|
|
549
|
-
[8
|
|
550
|
-
[9
|
|
551
|
-
[10
|
|
552
|
-
[11
|
|
553
|
-
[12
|
|
554
|
-
[13
|
|
555
|
-
[14
|
|
556
|
-
[15
|
|
557
|
-
[16
|
|
558
|
-
[17
|
|
559
|
-
[18
|
|
560
|
-
[19
|
|
561
|
-
[20
|
|
562
|
-
[21
|
|
563
|
-
[22
|
|
564
|
-
[23
|
|
565
|
-
[24
|
|
566
|
-
[25
|
|
567
|
-
[26
|
|
568
|
-
[27
|
|
569
|
-
[28
|
|
570
|
-
[29
|
|
571
|
-
[30
|
|
572
|
-
[31
|
|
573
|
-
[32
|
|
574
|
-
[33
|
|
575
|
-
[34
|
|
576
|
-
[35
|
|
577
|
-
[36
|
|
578
|
-
[37
|
|
579
|
-
[38
|
|
580
|
-
[39
|
|
581
|
-
[40
|
|
582
|
-
[41
|
|
583
|
-
[42
|
|
584
|
-
[43
|
|
585
|
-
[44
|
|
586
|
-
[45
|
|
587
|
-
[46
|
|
588
|
-
[47
|
|
589
|
-
[48
|
|
590
|
-
[49
|
|
591
|
-
[50
|
|
592
|
-
[51
|
|
593
|
-
[52
|
|
594
|
-
[53
|
|
595
|
-
[55
|
|
596
|
-
[56
|
|
597
|
-
[57
|
|
598
|
-
[58
|
|
599
|
-
[59
|
|
600
|
-
[60
|
|
601
|
-
[61
|
|
602
|
-
[62
|
|
603
|
-
[63
|
|
604
|
-
[64
|
|
605
|
-
[65
|
|
606
|
-
[99
|
|
607
|
-
[100
|
|
608
|
-
[101
|
|
609
|
-
[102
|
|
610
|
-
[103
|
|
611
|
-
[104
|
|
612
|
-
[105
|
|
613
|
-
[106
|
|
614
|
-
[107
|
|
615
|
-
[108
|
|
616
|
-
[109
|
|
617
|
-
[249
|
|
618
|
-
[250
|
|
619
|
-
[251
|
|
620
|
-
[252
|
|
621
|
-
[253
|
|
622
|
-
[254
|
|
623
|
-
[255
|
|
624
|
-
[256
|
|
625
|
-
[257
|
|
626
|
-
[258
|
|
627
|
-
[259
|
|
628
|
-
[260
|
|
629
|
-
[261
|
|
630
|
-
[32768
|
|
631
|
-
[32769
|
|
410
|
+
[1]: 'A',
|
|
411
|
+
[2]: 'NS',
|
|
412
|
+
[3]: 'MD',
|
|
413
|
+
[4]: 'MF',
|
|
414
|
+
[5]: 'CNAME',
|
|
415
|
+
[6]: 'SOA',
|
|
416
|
+
[7]: 'MB',
|
|
417
|
+
[8]: 'MG',
|
|
418
|
+
[9]: 'MR',
|
|
419
|
+
[10]: 'NULL',
|
|
420
|
+
[11]: 'WKS',
|
|
421
|
+
[12]: 'PTR',
|
|
422
|
+
[13]: 'HINFO',
|
|
423
|
+
[14]: 'MINFO',
|
|
424
|
+
[15]: 'MX',
|
|
425
|
+
[16]: 'TXT',
|
|
426
|
+
[17]: 'RP',
|
|
427
|
+
[18]: 'AFSDB',
|
|
428
|
+
[19]: 'X25',
|
|
429
|
+
[20]: 'ISDN',
|
|
430
|
+
[21]: 'RT',
|
|
431
|
+
[22]: 'NSAP',
|
|
432
|
+
[23]: 'NSAP_PTR',
|
|
433
|
+
[24]: 'SIG',
|
|
434
|
+
[25]: 'KEY',
|
|
435
|
+
[26]: 'PX',
|
|
436
|
+
[27]: 'GPOS',
|
|
437
|
+
[28]: 'AAAA',
|
|
438
|
+
[29]: 'LOC',
|
|
439
|
+
[30]: 'NXT',
|
|
440
|
+
[31]: 'EID',
|
|
441
|
+
[32]: 'NIMLOC',
|
|
442
|
+
[33]: 'SRV',
|
|
443
|
+
[34]: 'ATMA',
|
|
444
|
+
[35]: 'NAPTR',
|
|
445
|
+
[36]: 'KX',
|
|
446
|
+
[37]: 'CERT',
|
|
447
|
+
[38]: 'A6',
|
|
448
|
+
[39]: 'DNAME',
|
|
449
|
+
[40]: 'SINK',
|
|
450
|
+
[41]: 'OPT',
|
|
451
|
+
[42]: 'APL',
|
|
452
|
+
[43]: 'DS',
|
|
453
|
+
[44]: 'SSHFP',
|
|
454
|
+
[45]: 'IPSECKEY',
|
|
455
|
+
[46]: 'RRSIG',
|
|
456
|
+
[47]: 'NSEC',
|
|
457
|
+
[48]: 'DNSKEY',
|
|
458
|
+
[49]: 'DHCID',
|
|
459
|
+
[50]: 'NSEC3',
|
|
460
|
+
[51]: 'NSEC3PARAM',
|
|
461
|
+
[52]: 'TLSA',
|
|
462
|
+
[53]: 'SMIMEA',
|
|
463
|
+
[55]: 'HIP',
|
|
464
|
+
[56]: 'NINFO',
|
|
465
|
+
[57]: 'RKEY',
|
|
466
|
+
[58]: 'TALINK',
|
|
467
|
+
[59]: 'CDS',
|
|
468
|
+
[60]: 'CDNSKEY',
|
|
469
|
+
[61]: 'OPENPGPKEY',
|
|
470
|
+
[62]: 'CSYNC',
|
|
471
|
+
[63]: 'ZONEMD',
|
|
472
|
+
[64]: 'SVCB',
|
|
473
|
+
[65]: 'HTTPS',
|
|
474
|
+
[99]: 'SPF',
|
|
475
|
+
[100]: 'UINFO',
|
|
476
|
+
[101]: 'UID',
|
|
477
|
+
[102]: 'GID',
|
|
478
|
+
[103]: 'UNSPEC',
|
|
479
|
+
[104]: 'NID',
|
|
480
|
+
[105]: 'L32',
|
|
481
|
+
[106]: 'L64',
|
|
482
|
+
[107]: 'LP',
|
|
483
|
+
[108]: 'EUI48',
|
|
484
|
+
[109]: 'EUI64',
|
|
485
|
+
[249]: 'TKEY',
|
|
486
|
+
[250]: 'TSIG',
|
|
487
|
+
[251]: 'IXFR',
|
|
488
|
+
[252]: 'AXFR',
|
|
489
|
+
[253]: 'MAILB',
|
|
490
|
+
[254]: 'MAILA',
|
|
491
|
+
[255]: 'ANY',
|
|
492
|
+
[256]: 'URI',
|
|
493
|
+
[257]: 'CAA',
|
|
494
|
+
[258]: 'AVC',
|
|
495
|
+
[259]: 'DOA',
|
|
496
|
+
[260]: 'AMTRELAY',
|
|
497
|
+
[261]: 'ZONEVERSION',
|
|
498
|
+
[32768]: 'TA',
|
|
499
|
+
[32769]: 'DLV',
|
|
632
500
|
};
|
|
633
501
|
return typeMap[type] ?? `TYPE${type}`;
|
|
634
502
|
}
|
|
635
|
-
/**
|
|
636
|
-
* Converts a DNS response class numeric value to its string representation.
|
|
637
|
-
*
|
|
638
|
-
* @param {number} cls - The numeric DNS class.
|
|
639
|
-
* @returns {string} The string representation of the DNS class.
|
|
640
|
-
*/
|
|
641
503
|
dnsResponseClassToString(cls) {
|
|
642
|
-
const isFlush = !!(cls & 32768
|
|
504
|
+
const isFlush = !!(cls & 32768);
|
|
643
505
|
const baseClass = cls & 0x7fff;
|
|
644
506
|
let classStr;
|
|
645
507
|
switch (baseClass) {
|
|
646
|
-
case 1
|
|
508
|
+
case 1:
|
|
647
509
|
classStr = 'IN';
|
|
648
510
|
break;
|
|
649
|
-
case 3
|
|
511
|
+
case 3:
|
|
650
512
|
classStr = 'CH';
|
|
651
513
|
break;
|
|
652
|
-
case 4
|
|
514
|
+
case 4:
|
|
653
515
|
classStr = 'HS';
|
|
654
516
|
break;
|
|
655
|
-
case 255
|
|
517
|
+
case 255:
|
|
656
518
|
classStr = 'ANY';
|
|
657
519
|
break;
|
|
658
520
|
default:
|
|
@@ -660,28 +522,21 @@ export class Mdns extends Multicast {
|
|
|
660
522
|
}
|
|
661
523
|
return isFlush ? `${classStr}|FLUSH` : classStr;
|
|
662
524
|
}
|
|
663
|
-
/**
|
|
664
|
-
* Converts a DNS question class to a human-readable string.
|
|
665
|
-
* Adds support for mDNS QU (unicast-response) bit.
|
|
666
|
-
*
|
|
667
|
-
* @param {number} cls - The numeric question class.
|
|
668
|
-
* @returns {string} The string representation, e.g. "IN|QU"
|
|
669
|
-
*/
|
|
670
525
|
dnsQuestionClassToString(cls) {
|
|
671
|
-
const isQU = !!(cls & 32768
|
|
526
|
+
const isQU = !!(cls & 32768);
|
|
672
527
|
const baseClass = cls & 0x7fff;
|
|
673
528
|
let classStr;
|
|
674
529
|
switch (baseClass) {
|
|
675
|
-
case 1
|
|
530
|
+
case 1:
|
|
676
531
|
classStr = 'IN';
|
|
677
532
|
break;
|
|
678
|
-
case 3
|
|
533
|
+
case 3:
|
|
679
534
|
classStr = 'CH';
|
|
680
535
|
break;
|
|
681
|
-
case 4
|
|
536
|
+
case 4:
|
|
682
537
|
classStr = 'HS';
|
|
683
538
|
break;
|
|
684
|
-
case 255
|
|
539
|
+
case 255:
|
|
685
540
|
classStr = 'ANY';
|
|
686
541
|
break;
|
|
687
542
|
default:
|
|
@@ -689,11 +544,6 @@ export class Mdns extends Multicast {
|
|
|
689
544
|
}
|
|
690
545
|
return isQU ? `${classStr}|QU` : classStr;
|
|
691
546
|
}
|
|
692
|
-
/**
|
|
693
|
-
* Logs the decoded mDNS message header.
|
|
694
|
-
*
|
|
695
|
-
* @param {MdnsMessage} msg - The mDNS message header object.
|
|
696
|
-
*/
|
|
697
547
|
logMdnsMessage(msg) {
|
|
698
548
|
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}`);
|
|
699
549
|
msg.questions?.forEach((question) => {
|
|
@@ -710,14 +560,9 @@ export class Mdns extends Multicast {
|
|
|
710
560
|
});
|
|
711
561
|
this.log.info(`---\n`);
|
|
712
562
|
}
|
|
713
|
-
/**
|
|
714
|
-
* Logs the discovered devices from the mDNS queries and responses.
|
|
715
|
-
*/
|
|
716
563
|
logDevices() {
|
|
717
564
|
this.log.info(`Discovered query devices: ${MAGENTA}${this.deviceQueries.size}${nf}`);
|
|
718
|
-
// Collect devices into an array
|
|
719
565
|
const deviceQueryArray = Array.from(this.deviceQueries.entries());
|
|
720
|
-
// Sort the array by numeric value of the IP address
|
|
721
566
|
deviceQueryArray.sort(([addressA], [addressB]) => {
|
|
722
567
|
const partsA = addressA.split('.').map(Number);
|
|
723
568
|
const partsB = addressB.split('.').map(Number);
|
|
@@ -726,17 +571,13 @@ export class Mdns extends Multicast {
|
|
|
726
571
|
if (diff !== 0)
|
|
727
572
|
return diff;
|
|
728
573
|
}
|
|
729
|
-
// istanbul ignore next
|
|
730
574
|
return 0;
|
|
731
575
|
});
|
|
732
|
-
// Log the sorted devices
|
|
733
576
|
deviceQueryArray.forEach(([rinfo, response]) => {
|
|
734
577
|
this.log.info(`- ${MAGENTA}${rinfo}${nf} family ${BLUE}${response.rinfo.family}${nf} address ${BLUE}${response.rinfo.address}${nf} port ${BLUE}${response.rinfo.port}${nf}`);
|
|
735
578
|
});
|
|
736
579
|
this.log.info(`Discovered response devices: ${MAGENTA}${this.deviceResponses.size}${nf}`);
|
|
737
|
-
// Collect devices into an array
|
|
738
580
|
const deviceResponseArray = Array.from(this.deviceResponses.entries());
|
|
739
|
-
// Sort the array by numeric value of the IP address
|
|
740
581
|
deviceResponseArray.sort(([addressA], [addressB]) => {
|
|
741
582
|
const partsA = addressA.split(/[:.]/).map((part) => parseInt(part, 16));
|
|
742
583
|
const partsB = addressB.split(/[:.]/).map((part) => parseInt(part, 16));
|
|
@@ -745,96 +586,10 @@ export class Mdns extends Multicast {
|
|
|
745
586
|
if (diff !== 0)
|
|
746
587
|
return diff;
|
|
747
588
|
}
|
|
748
|
-
// istanbul ignore next
|
|
749
589
|
return 0;
|
|
750
590
|
});
|
|
751
|
-
// Log the sorted devices
|
|
752
591
|
deviceResponseArray.forEach(([rinfo, response]) => {
|
|
753
592
|
this.log.info(`- ${MAGENTA}${rinfo}${nf} family ${BLUE}${response.rinfo.family}${nf} address ${BLUE}${response.rinfo.address}${nf} port ${BLUE}${response.rinfo.port}${nf} PTR ${GREEN}${response.dataPTR}${nf}`);
|
|
754
593
|
});
|
|
755
594
|
}
|
|
756
595
|
}
|
|
757
|
-
// CLI entry point for manual testing: node dist/dgram/mdns.js --mdns-udp4 --mdns-udp6 --mdns-query
|
|
758
|
-
// istanbul ignore next if
|
|
759
|
-
if (process.argv.includes('--mdns-udp4') || process.argv.includes('--mdns-udp6')) {
|
|
760
|
-
// const mdnsIpv4 = new Mdns('mDNS Server udp4', MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_PORT, 'udp4', true, 'Loopback Pseudo-Interface 1', '127.0.0.1');
|
|
761
|
-
// const mdnsIpv6 = new Mdns('mDNS Server udp6', MDNS_MULTICAST_IPV6_ADDRESS, MDNS_MULTICAST_PORT, 'udp6', true, 'Loopback Pseudo-Interface 1', '::1');
|
|
762
|
-
const mdnsIpv4 = new Mdns('mDNS Server udp4', MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_PORT, 'udp4', true, undefined, '0.0.0.0');
|
|
763
|
-
const mdnsIpv6 = new Mdns('mDNS Server udp6', MDNS_MULTICAST_IPV6_ADDRESS, MDNS_MULTICAST_PORT, 'udp6', true, undefined, '::');
|
|
764
|
-
mdnsIpv6.listNetworkInterfaces();
|
|
765
|
-
/**
|
|
766
|
-
* Cleanup and log device information before exiting.
|
|
767
|
-
*/
|
|
768
|
-
function cleanupAndLogAndExit() {
|
|
769
|
-
if (process.argv.includes('--mdns-udp4'))
|
|
770
|
-
mdnsIpv4.stop();
|
|
771
|
-
if (process.argv.includes('--mdns-udp6'))
|
|
772
|
-
mdnsIpv6.stop();
|
|
773
|
-
if (process.argv.includes('--mdns-udp4'))
|
|
774
|
-
mdnsIpv4.logDevices();
|
|
775
|
-
if (process.argv.includes('--mdns-udp6'))
|
|
776
|
-
mdnsIpv6.logDevices();
|
|
777
|
-
// eslint-disable-next-line n/no-process-exit
|
|
778
|
-
process.exit(0);
|
|
779
|
-
}
|
|
780
|
-
/**
|
|
781
|
-
* Queries mDNS services over UDP IPv4 and sends a response for a specific service instance.
|
|
782
|
-
* This function sends a query for Shelly, HTTP, and services, and responds with the appropriate PTR records.
|
|
783
|
-
*/
|
|
784
|
-
const queryUdp4 = () => {
|
|
785
|
-
mdnsIpv4.sendQuery([
|
|
786
|
-
{ name: '_matter._tcp.local', type: 12 /* DnsRecordType.PTR */, class: 1 /* DnsClass.IN */, unicastResponse: false },
|
|
787
|
-
{ name: '_shelly._tcp.local', type: 12 /* DnsRecordType.PTR */, class: 1 /* DnsClass.IN */, unicastResponse: false },
|
|
788
|
-
{ name: '_http._tcp.local', type: 12 /* DnsRecordType.PTR */, class: 1 /* DnsClass.IN */, unicastResponse: false },
|
|
789
|
-
{ name: '_services._dns-sd._udp.local', type: 12 /* DnsRecordType.PTR */, class: 1 /* DnsClass.IN */, unicastResponse: false },
|
|
790
|
-
]);
|
|
791
|
-
const ptrRdata = mdnsIpv4.encodeDnsName('matterbridge._http._tcp.local');
|
|
792
|
-
mdnsIpv4.sendResponse('_http._tcp.local', 12 /* DnsRecordType.PTR */, 1 /* DnsClass.IN */, 120, ptrRdata);
|
|
793
|
-
};
|
|
794
|
-
/**
|
|
795
|
-
* Queries mDNS services over UDP IPv6 and sends a response for a specific service instance.
|
|
796
|
-
* This function sends a query for Shelly, HTTP, and services, and responds with the appropriate PTR records.
|
|
797
|
-
*/
|
|
798
|
-
const queryUdp6 = () => {
|
|
799
|
-
mdnsIpv6.sendQuery([
|
|
800
|
-
{ name: '_matter._tcp.local', type: 12 /* DnsRecordType.PTR */, class: 1 /* DnsClass.IN */, unicastResponse: true },
|
|
801
|
-
{ name: '_shelly._tcp.local', type: 12 /* DnsRecordType.PTR */, class: 1 /* DnsClass.IN */, unicastResponse: true },
|
|
802
|
-
{ name: '_http._tcp.local', type: 12 /* DnsRecordType.PTR */, class: 1 /* DnsClass.IN */, unicastResponse: true },
|
|
803
|
-
{ name: '_services._dns-sd._udp.local', type: 12 /* DnsRecordType.PTR */, class: 1 /* DnsClass.IN */, unicastResponse: true },
|
|
804
|
-
]);
|
|
805
|
-
const ptrRdata = mdnsIpv6.encodeDnsName('matterbridge._http._tcp.local');
|
|
806
|
-
mdnsIpv6.sendResponse('_http._tcp.local', 12 /* DnsRecordType.PTR */, 1 /* DnsClass.IN */, 120, ptrRdata);
|
|
807
|
-
};
|
|
808
|
-
// Handle Ctrl+C (SIGINT) to stop and log devices
|
|
809
|
-
process.on('SIGINT', () => {
|
|
810
|
-
cleanupAndLogAndExit();
|
|
811
|
-
});
|
|
812
|
-
if (process.argv.includes('--mdns-udp4')) {
|
|
813
|
-
mdnsIpv4.start();
|
|
814
|
-
mdnsIpv4.on('ready', (address) => {
|
|
815
|
-
mdnsIpv4.log.info(`mdnsIpv4 server ready on ${address.family} ${address.address}:${address.port}`);
|
|
816
|
-
if (!process.argv.includes('--mdns-query'))
|
|
817
|
-
return; // Skip querying if --mdns-query is not specified
|
|
818
|
-
queryUdp4();
|
|
819
|
-
setInterval(() => {
|
|
820
|
-
queryUdp4();
|
|
821
|
-
}, 10000).unref();
|
|
822
|
-
});
|
|
823
|
-
}
|
|
824
|
-
if (process.argv.includes('--mdns-udp6')) {
|
|
825
|
-
mdnsIpv6.start();
|
|
826
|
-
mdnsIpv6.on('ready', (address) => {
|
|
827
|
-
mdnsIpv6.log.info(`mdnsIpv6 server ready on ${address.family} ${address.address}:${address.port}`);
|
|
828
|
-
if (!process.argv.includes('--mdns-query'))
|
|
829
|
-
return; // Skip querying if --mdns-query is not specified
|
|
830
|
-
queryUdp6();
|
|
831
|
-
setInterval(() => {
|
|
832
|
-
queryUdp6();
|
|
833
|
-
}, 10000).unref();
|
|
834
|
-
});
|
|
835
|
-
}
|
|
836
|
-
setTimeout(() => {
|
|
837
|
-
cleanupAndLogAndExit();
|
|
838
|
-
}, 600000); // 10 minutes timeout to exit if no activity
|
|
839
|
-
}
|
|
840
|
-
//# sourceMappingURL=mdns.js.map
|