matterbridge 3.4.7-dev-20260104-6b10cee → 3.4.7-dev-20260112-a00b2bf
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 +6 -1
- package/README.md +5 -1
- package/dist/broadcastServer.d.ts +29 -0
- package/dist/broadcastServerTypes.d.ts +798 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cliEmitter.d.ts +14 -0
- package/dist/cliHistory.d.ts +6 -0
- package/dist/clusters/export.d.ts +1 -0
- package/dist/deviceManager.d.ts +27 -0
- package/dist/devices/airConditioner.d.ts +23 -0
- package/dist/devices/batteryStorage.d.ts +5 -0
- package/dist/devices/cooktop.d.ts +6 -0
- package/dist/devices/dishwasher.d.ts +16 -0
- package/dist/devices/evse.d.ts +19 -0
- package/dist/devices/export.d.ts +16 -0
- package/dist/devices/extractorHood.d.ts +5 -0
- package/dist/devices/heatPump.d.ts +4 -0
- package/dist/devices/laundryDryer.d.ts +9 -0
- package/dist/devices/laundryWasher.d.ts +17 -0
- package/dist/devices/microwaveOven.d.ts +92 -0
- package/dist/devices/oven.d.ts +23 -0
- package/dist/devices/refrigerator.d.ts +18 -0
- package/dist/devices/roboticVacuumCleaner.d.ts +29 -0
- package/dist/devices/solarPower.d.ts +4 -0
- package/dist/devices/speaker.d.ts +8 -0
- package/dist/devices/temperatureControl.d.ts +145 -0
- package/dist/devices/waterHeater.d.ts +37 -0
- package/dist/dgram/coap.d.ts +34 -0
- package/dist/dgram/dgram.d.ts +45 -0
- package/dist/dgram/dgram.js +4 -1
- package/dist/dgram/mb_coap.d.ts +1 -0
- package/dist/dgram/mb_coap.js +1 -2
- package/dist/dgram/mb_mdns.d.ts +1 -0
- package/dist/dgram/mb_mdns.js +39 -50
- package/dist/dgram/mdns.d.ts +188 -0
- package/dist/dgram/multicast.d.ts +18 -0
- package/dist/dgram/unicast.d.ts +11 -0
- package/dist/frontend.d.ts +58 -0
- package/dist/frontendTypes.d.ts +472 -0
- package/dist/helpers.d.ts +5 -0
- package/dist/index.d.ts +11 -0
- package/dist/jestutils/export.d.ts +1 -0
- package/dist/jestutils/jestHelpers.d.ts +90 -0
- package/dist/logger/export.d.ts +1 -0
- package/dist/matter/behaviors.d.ts +1 -0
- package/dist/matter/clusters.d.ts +1 -0
- package/dist/matter/devices.d.ts +1 -0
- package/dist/matter/endpoints.d.ts +1 -0
- package/dist/matter/export.d.ts +4 -0
- package/dist/matter/types.d.ts +2 -0
- package/dist/matterNode.d.ts +84 -0
- package/dist/matterbridge.d.ts +152 -0
- package/dist/matterbridgeAccessoryPlatform.d.ts +5 -0
- package/dist/matterbridgeBehaviors.d.ts +2380 -0
- package/dist/matterbridgeDeviceTypes.d.ts +95 -0
- package/dist/matterbridgeDynamicPlatform.d.ts +5 -0
- package/dist/matterbridgeEndpoint.d.ts +175 -0
- package/dist/matterbridgeEndpointHelpers.d.ts +362 -0
- package/dist/matterbridgeEndpointTypes.d.ts +96 -0
- package/dist/matterbridgePlatform.d.ts +114 -0
- package/dist/matterbridgeTypes.d.ts +206 -0
- package/dist/pluginManager.d.ts +67 -0
- package/dist/shelly.d.ts +24 -0
- package/dist/storage/export.d.ts +1 -0
- package/dist/update.d.ts +9 -0
- package/dist/utils/colorUtils.d.ts +24 -0
- package/dist/utils/commandLine.d.ts +6 -0
- package/dist/utils/copyDirectory.d.ts +2 -0
- package/dist/utils/createDirectory.d.ts +2 -0
- package/dist/utils/createZip.d.ts +1 -0
- package/dist/utils/deepCopy.d.ts +1 -0
- package/dist/utils/deepEqual.d.ts +1 -0
- package/dist/utils/error.d.ts +3 -0
- package/dist/utils/export.d.ts +12 -0
- package/dist/utils/format.d.ts +4 -0
- package/dist/utils/hex.d.ts +4 -0
- package/dist/utils/inspector.d.ts +24 -0
- package/dist/utils/isValid.d.ts +10 -0
- package/dist/utils/network.d.ts +25 -0
- package/dist/utils/spawn.d.ts +1 -0
- package/dist/utils/tracker.d.ts +52 -0
- package/dist/utils/wait.d.ts +3 -0
- package/dist/workerGlobalPrefix.d.ts +1 -0
- package/dist/workerTypes.d.ts +27 -0
- package/dist/workers.d.ts +8 -0
- package/npm-shrinkwrap.json +904 -131
- package/package.json +9 -2
- package/packages/dgram/dist/coap.d.ts +34 -0
- package/packages/dgram/dist/coap.js +252 -0
- package/packages/dgram/dist/dgram.d.ts +45 -0
- package/packages/dgram/dist/dgram.js +255 -0
- package/packages/dgram/dist/export.d.ts +5 -0
- package/packages/dgram/dist/export.js +5 -0
- package/packages/dgram/dist/mdns.d.ts +188 -0
- package/packages/dgram/dist/mdns.js +702 -0
- package/packages/dgram/dist/multicast.d.ts +18 -0
- package/packages/dgram/dist/multicast.js +119 -0
- package/packages/dgram/dist/unicast.d.ts +11 -0
- package/packages/dgram/dist/unicast.js +40 -0
- package/packages/dgram/package.json +106 -0
- package/packages/jest-utils/LICENSE +202 -0
- package/packages/jest-utils/bmc-button.svg +22 -0
- package/packages/jest-utils/dist/export.d.ts +1 -0
- package/packages/jest-utils/dist/export.js +1 -0
- package/packages/jest-utils/matterbridge.svg +50 -0
- package/packages/{mb-lib-test → jest-utils}/package.json +12 -10
- package/packages/utils/LICENSE +202 -0
- package/packages/utils/bmc-button.svg +22 -0
- package/packages/utils/dist/colorUtils.d.ts +24 -0
- package/packages/utils/dist/colorUtils.js +187 -0
- package/packages/utils/dist/commandLine.d.ts +6 -0
- package/packages/utils/dist/commandLine.js +63 -0
- package/packages/utils/dist/copyDirectory.d.ts +2 -0
- package/packages/utils/dist/copyDirectory.js +39 -0
- package/packages/utils/dist/createDirectory.d.ts +2 -0
- package/packages/utils/dist/createDirectory.js +21 -0
- package/packages/utils/dist/createZip.d.ts +1 -0
- package/packages/utils/dist/createZip.js +69 -0
- package/packages/utils/dist/deepCopy.d.ts +1 -0
- package/packages/utils/dist/deepCopy.js +40 -0
- package/packages/utils/dist/deepEqual.d.ts +1 -0
- package/packages/utils/dist/deepEqual.js +58 -0
- package/packages/utils/dist/error.d.ts +3 -0
- package/packages/utils/dist/error.js +12 -0
- package/packages/utils/dist/export.d.ts +15 -0
- package/packages/utils/dist/export.js +15 -0
- package/packages/utils/dist/format.d.ts +4 -0
- package/packages/utils/dist/format.js +29 -0
- package/packages/utils/dist/githubVersion.d.ts +11 -0
- package/packages/utils/dist/githubVersion.js +37 -0
- package/packages/utils/dist/hex.d.ts +4 -0
- package/packages/utils/dist/hex.js +118 -0
- package/packages/utils/dist/inspector.d.ts +24 -0
- package/packages/utils/dist/inspector.js +200 -0
- package/packages/utils/dist/isValid.d.ts +10 -0
- package/packages/utils/dist/isValid.js +69 -0
- package/packages/utils/dist/network.d.ts +12 -0
- package/packages/utils/dist/network.js +105 -0
- package/packages/utils/dist/npmRoot.d.ts +1 -0
- package/packages/utils/dist/npmRoot.js +13 -0
- package/packages/utils/dist/npmVersion.d.ts +1 -0
- package/packages/utils/dist/npmVersion.js +43 -0
- package/packages/utils/dist/tracker.d.ts +52 -0
- package/packages/utils/dist/tracker.js +201 -0
- package/packages/utils/dist/wait.d.ts +3 -0
- package/packages/utils/dist/wait.js +73 -0
- package/packages/utils/matterbridge.svg +50 -0
- package/packages/utils/package.json +106 -0
- package/packages/vitest-utils/LICENSE +202 -0
- package/packages/vitest-utils/bmc-button.svg +22 -0
- package/packages/vitest-utils/dist/export.d.ts +1 -0
- package/packages/vitest-utils/dist/export.js +1 -0
- package/packages/vitest-utils/matterbridge.svg +50 -0
- package/packages/vitest-utils/package.json +108 -0
- package/reflector/Reflector.md +17 -8
- package/dist/dgram/mdnsReflectorClient.js +0 -176
- package/dist/dgram/mdnsReflectorServer.js +0 -301
- package/dist/dgram/mdnsReflectorTypes.js +0 -5
- package/packages/mb-lib-test/dist/module.d.ts +0 -2
- package/packages/mb-lib-test/dist/module.js +0 -2
- /package/packages/{mb-lib-test → dgram}/LICENSE +0 -0
- /package/packages/{mb-lib-test → dgram}/bmc-button.svg +0 -0
- /package/packages/{mb-lib-test → dgram}/matterbridge.svg +0 -0
- /package/packages/{mb-lib-test/dist/jestutils → jest-utils/dist}/jestHelpers.d.ts +0 -0
- /package/packages/{mb-lib-test/dist/jestutils → jest-utils/dist}/jestHelpers.js +0 -0
- /package/packages/{mb-lib-test/dist/vitestutils → vitest-utils/dist}/vitestHelpers.d.ts +0 -0
- /package/packages/{mb-lib-test/dist/vitestutils → vitest-utils/dist}/vitestHelpers.js +0 -0
|
@@ -0,0 +1,702 @@
|
|
|
1
|
+
import { BLUE, CYAN, db, GREEN, idn, MAGENTA, nf, rs } from 'node-ansi-logger';
|
|
2
|
+
import { hasParameter } from '@matterbridge/utils';
|
|
3
|
+
import { Multicast } from './multicast.js';
|
|
4
|
+
export var DnsRecordType;
|
|
5
|
+
(function (DnsRecordType) {
|
|
6
|
+
DnsRecordType[DnsRecordType["A"] = 1] = "A";
|
|
7
|
+
DnsRecordType[DnsRecordType["NS"] = 2] = "NS";
|
|
8
|
+
DnsRecordType[DnsRecordType["MD"] = 3] = "MD";
|
|
9
|
+
DnsRecordType[DnsRecordType["MF"] = 4] = "MF";
|
|
10
|
+
DnsRecordType[DnsRecordType["CNAME"] = 5] = "CNAME";
|
|
11
|
+
DnsRecordType[DnsRecordType["SOA"] = 6] = "SOA";
|
|
12
|
+
DnsRecordType[DnsRecordType["MB"] = 7] = "MB";
|
|
13
|
+
DnsRecordType[DnsRecordType["MG"] = 8] = "MG";
|
|
14
|
+
DnsRecordType[DnsRecordType["MR"] = 9] = "MR";
|
|
15
|
+
DnsRecordType[DnsRecordType["NULL"] = 10] = "NULL";
|
|
16
|
+
DnsRecordType[DnsRecordType["WKS"] = 11] = "WKS";
|
|
17
|
+
DnsRecordType[DnsRecordType["PTR"] = 12] = "PTR";
|
|
18
|
+
DnsRecordType[DnsRecordType["HINFO"] = 13] = "HINFO";
|
|
19
|
+
DnsRecordType[DnsRecordType["MINFO"] = 14] = "MINFO";
|
|
20
|
+
DnsRecordType[DnsRecordType["MX"] = 15] = "MX";
|
|
21
|
+
DnsRecordType[DnsRecordType["TXT"] = 16] = "TXT";
|
|
22
|
+
DnsRecordType[DnsRecordType["RP"] = 17] = "RP";
|
|
23
|
+
DnsRecordType[DnsRecordType["AFSDB"] = 18] = "AFSDB";
|
|
24
|
+
DnsRecordType[DnsRecordType["X25"] = 19] = "X25";
|
|
25
|
+
DnsRecordType[DnsRecordType["ISDN"] = 20] = "ISDN";
|
|
26
|
+
DnsRecordType[DnsRecordType["RT"] = 21] = "RT";
|
|
27
|
+
DnsRecordType[DnsRecordType["NSAP"] = 22] = "NSAP";
|
|
28
|
+
DnsRecordType[DnsRecordType["NSAP_PTR"] = 23] = "NSAP_PTR";
|
|
29
|
+
DnsRecordType[DnsRecordType["SIG"] = 24] = "SIG";
|
|
30
|
+
DnsRecordType[DnsRecordType["KEY"] = 25] = "KEY";
|
|
31
|
+
DnsRecordType[DnsRecordType["PX"] = 26] = "PX";
|
|
32
|
+
DnsRecordType[DnsRecordType["GPOS"] = 27] = "GPOS";
|
|
33
|
+
DnsRecordType[DnsRecordType["AAAA"] = 28] = "AAAA";
|
|
34
|
+
DnsRecordType[DnsRecordType["LOC"] = 29] = "LOC";
|
|
35
|
+
DnsRecordType[DnsRecordType["NXT"] = 30] = "NXT";
|
|
36
|
+
DnsRecordType[DnsRecordType["EID"] = 31] = "EID";
|
|
37
|
+
DnsRecordType[DnsRecordType["NIMLOC"] = 32] = "NIMLOC";
|
|
38
|
+
DnsRecordType[DnsRecordType["SRV"] = 33] = "SRV";
|
|
39
|
+
DnsRecordType[DnsRecordType["ATMA"] = 34] = "ATMA";
|
|
40
|
+
DnsRecordType[DnsRecordType["NAPTR"] = 35] = "NAPTR";
|
|
41
|
+
DnsRecordType[DnsRecordType["KX"] = 36] = "KX";
|
|
42
|
+
DnsRecordType[DnsRecordType["CERT"] = 37] = "CERT";
|
|
43
|
+
DnsRecordType[DnsRecordType["A6"] = 38] = "A6";
|
|
44
|
+
DnsRecordType[DnsRecordType["DNAME"] = 39] = "DNAME";
|
|
45
|
+
DnsRecordType[DnsRecordType["SINK"] = 40] = "SINK";
|
|
46
|
+
DnsRecordType[DnsRecordType["OPT"] = 41] = "OPT";
|
|
47
|
+
DnsRecordType[DnsRecordType["APL"] = 42] = "APL";
|
|
48
|
+
DnsRecordType[DnsRecordType["DS"] = 43] = "DS";
|
|
49
|
+
DnsRecordType[DnsRecordType["SSHFP"] = 44] = "SSHFP";
|
|
50
|
+
DnsRecordType[DnsRecordType["IPSECKEY"] = 45] = "IPSECKEY";
|
|
51
|
+
DnsRecordType[DnsRecordType["RRSIG"] = 46] = "RRSIG";
|
|
52
|
+
DnsRecordType[DnsRecordType["NSEC"] = 47] = "NSEC";
|
|
53
|
+
DnsRecordType[DnsRecordType["DNSKEY"] = 48] = "DNSKEY";
|
|
54
|
+
DnsRecordType[DnsRecordType["DHCID"] = 49] = "DHCID";
|
|
55
|
+
DnsRecordType[DnsRecordType["NSEC3"] = 50] = "NSEC3";
|
|
56
|
+
DnsRecordType[DnsRecordType["NSEC3PARAM"] = 51] = "NSEC3PARAM";
|
|
57
|
+
DnsRecordType[DnsRecordType["TLSA"] = 52] = "TLSA";
|
|
58
|
+
DnsRecordType[DnsRecordType["SMIMEA"] = 53] = "SMIMEA";
|
|
59
|
+
DnsRecordType[DnsRecordType["HIP"] = 55] = "HIP";
|
|
60
|
+
DnsRecordType[DnsRecordType["NINFO"] = 56] = "NINFO";
|
|
61
|
+
DnsRecordType[DnsRecordType["RKEY"] = 57] = "RKEY";
|
|
62
|
+
DnsRecordType[DnsRecordType["TALINK"] = 58] = "TALINK";
|
|
63
|
+
DnsRecordType[DnsRecordType["CDS"] = 59] = "CDS";
|
|
64
|
+
DnsRecordType[DnsRecordType["CDNSKEY"] = 60] = "CDNSKEY";
|
|
65
|
+
DnsRecordType[DnsRecordType["OPENPGPKEY"] = 61] = "OPENPGPKEY";
|
|
66
|
+
DnsRecordType[DnsRecordType["CSYNC"] = 62] = "CSYNC";
|
|
67
|
+
DnsRecordType[DnsRecordType["ZONEMD"] = 63] = "ZONEMD";
|
|
68
|
+
DnsRecordType[DnsRecordType["SVCB"] = 64] = "SVCB";
|
|
69
|
+
DnsRecordType[DnsRecordType["HTTPS"] = 65] = "HTTPS";
|
|
70
|
+
DnsRecordType[DnsRecordType["SPF"] = 99] = "SPF";
|
|
71
|
+
DnsRecordType[DnsRecordType["UINFO"] = 100] = "UINFO";
|
|
72
|
+
DnsRecordType[DnsRecordType["UID"] = 101] = "UID";
|
|
73
|
+
DnsRecordType[DnsRecordType["GID"] = 102] = "GID";
|
|
74
|
+
DnsRecordType[DnsRecordType["UNSPEC"] = 103] = "UNSPEC";
|
|
75
|
+
DnsRecordType[DnsRecordType["NID"] = 104] = "NID";
|
|
76
|
+
DnsRecordType[DnsRecordType["L32"] = 105] = "L32";
|
|
77
|
+
DnsRecordType[DnsRecordType["L64"] = 106] = "L64";
|
|
78
|
+
DnsRecordType[DnsRecordType["LP"] = 107] = "LP";
|
|
79
|
+
DnsRecordType[DnsRecordType["EUI48"] = 108] = "EUI48";
|
|
80
|
+
DnsRecordType[DnsRecordType["EUI64"] = 109] = "EUI64";
|
|
81
|
+
DnsRecordType[DnsRecordType["TKEY"] = 249] = "TKEY";
|
|
82
|
+
DnsRecordType[DnsRecordType["TSIG"] = 250] = "TSIG";
|
|
83
|
+
DnsRecordType[DnsRecordType["IXFR"] = 251] = "IXFR";
|
|
84
|
+
DnsRecordType[DnsRecordType["AXFR"] = 252] = "AXFR";
|
|
85
|
+
DnsRecordType[DnsRecordType["MAILB"] = 253] = "MAILB";
|
|
86
|
+
DnsRecordType[DnsRecordType["MAILA"] = 254] = "MAILA";
|
|
87
|
+
DnsRecordType[DnsRecordType["ANY"] = 255] = "ANY";
|
|
88
|
+
DnsRecordType[DnsRecordType["URI"] = 256] = "URI";
|
|
89
|
+
DnsRecordType[DnsRecordType["CAA"] = 257] = "CAA";
|
|
90
|
+
DnsRecordType[DnsRecordType["AVC"] = 258] = "AVC";
|
|
91
|
+
DnsRecordType[DnsRecordType["DOA"] = 259] = "DOA";
|
|
92
|
+
DnsRecordType[DnsRecordType["AMTRELAY"] = 260] = "AMTRELAY";
|
|
93
|
+
DnsRecordType[DnsRecordType["ZONEVERSION"] = 261] = "ZONEVERSION";
|
|
94
|
+
DnsRecordType[DnsRecordType["TA"] = 32768] = "TA";
|
|
95
|
+
DnsRecordType[DnsRecordType["DLV"] = 32769] = "DLV";
|
|
96
|
+
})(DnsRecordType || (DnsRecordType = {}));
|
|
97
|
+
export var DnsClass;
|
|
98
|
+
(function (DnsClass) {
|
|
99
|
+
DnsClass[DnsClass["IN"] = 1] = "IN";
|
|
100
|
+
DnsClass[DnsClass["CH"] = 3] = "CH";
|
|
101
|
+
DnsClass[DnsClass["HS"] = 4] = "HS";
|
|
102
|
+
DnsClass[DnsClass["ANY"] = 255] = "ANY";
|
|
103
|
+
})(DnsClass || (DnsClass = {}));
|
|
104
|
+
export var DnsClassFlag;
|
|
105
|
+
(function (DnsClassFlag) {
|
|
106
|
+
DnsClassFlag[DnsClassFlag["FLUSH"] = 32768] = "FLUSH";
|
|
107
|
+
DnsClassFlag[DnsClassFlag["QU"] = 32768] = "QU";
|
|
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
|
+
}
|
|
131
|
+
export class Mdns extends Multicast {
|
|
132
|
+
deviceQueries = new Map();
|
|
133
|
+
deviceResponses = new Map();
|
|
134
|
+
filters = [];
|
|
135
|
+
constructor(name, multicastAddress, multicastPort, socketType, reuseAddr = true, interfaceName, interfaceAddress, outgoingInterfaceAddress) {
|
|
136
|
+
super(name, multicastAddress, multicastPort, socketType, reuseAddr, interfaceName, interfaceAddress, outgoingInterfaceAddress);
|
|
137
|
+
}
|
|
138
|
+
onQuery(rinfo, _query) {
|
|
139
|
+
this.log.debug(`mDNS query received from ${BLUE}${rinfo.family}${db} ${BLUE}${rinfo.address}${db}:${BLUE}${rinfo.port}${db}`);
|
|
140
|
+
}
|
|
141
|
+
onResponse(rinfo, _response) {
|
|
142
|
+
this.log.debug(`mDNS response received from ${BLUE}${rinfo.family}${db} ${BLUE}${rinfo.address}${db}:${BLUE}${rinfo.port}${db}`);
|
|
143
|
+
}
|
|
144
|
+
onMessage(msg, rinfo) {
|
|
145
|
+
if (this.filters.length === 0)
|
|
146
|
+
this.log.info(`Dgram mDNS server received a mDNS message from ${BLUE}${rinfo.family}${nf} ${BLUE}${rinfo.address}${nf}:${BLUE}${rinfo.port}${nf}`);
|
|
147
|
+
try {
|
|
148
|
+
const result = this.decodeMdnsMessage(msg);
|
|
149
|
+
if (result.qr === 0) {
|
|
150
|
+
this.deviceQueries.set(rinfo.address, { rinfo, query: result });
|
|
151
|
+
this.onQuery(rinfo, result);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
const ptr = result.answers?.find((record) => record.name === '_shelly._tcp.local' && record.type === 12) ||
|
|
155
|
+
result.answers?.find((record) => record.name === '_http._tcp.local' && record.type === 12) ||
|
|
156
|
+
result.answers?.find((record) => record.type === 12) ||
|
|
157
|
+
result.answers?.find((record) => record.type === 16) ||
|
|
158
|
+
result.answers
|
|
159
|
+
? result.answers[0]
|
|
160
|
+
: undefined;
|
|
161
|
+
this.deviceResponses.set(rinfo.address, { rinfo, response: result, dataPTR: ptr?.type === 12 ? ptr?.data : ptr?.name });
|
|
162
|
+
this.onResponse(rinfo, result);
|
|
163
|
+
}
|
|
164
|
+
if (this.filters.length > 0) {
|
|
165
|
+
this.log.debug(`mDNS message filtered out by filters: ${this.filters.join(', ')}`);
|
|
166
|
+
for (const filter of this.filters) {
|
|
167
|
+
const foundInQuestions = result.questions?.some((q) => q.name.includes(filter));
|
|
168
|
+
const foundInAnswers = result.answers?.some((a) => a.name.includes(filter) || a.data.includes(filter));
|
|
169
|
+
const foundInAdditionals = result.additionals?.some((a) => a.name.includes(filter) || a.data.includes(filter));
|
|
170
|
+
if (foundInQuestions || foundInAnswers || foundInAdditionals) {
|
|
171
|
+
this.log.info(`Dgram mDNS server received a mDNS message from ${BLUE}${rinfo.family}${nf} ${BLUE}${rinfo.address}${nf}:${BLUE}${rinfo.port}${nf}`);
|
|
172
|
+
this.logMdnsMessage(result);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
this.log.debug(`mDNS message does not match any filter, ignoring.`);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
this.logMdnsMessage(result);
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
this.log.error(`Error decoding mDNS message: ${error instanceof Error ? error.message : error}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
decodeMdnsMessage(msg) {
|
|
186
|
+
if (msg.length < 12) {
|
|
187
|
+
throw new Error('mDNS message too short');
|
|
188
|
+
}
|
|
189
|
+
const id = msg.readUInt16BE(0);
|
|
190
|
+
const flags = msg.readUInt16BE(2);
|
|
191
|
+
const qr = (flags & 0x8000) >> 15;
|
|
192
|
+
const opcode = (flags & 0x7800) >> 11;
|
|
193
|
+
const aa = Boolean(flags & 0x0400);
|
|
194
|
+
const tc = Boolean(flags & 0x0200);
|
|
195
|
+
const rd = Boolean(flags & 0x0100);
|
|
196
|
+
const ra = Boolean(flags & 0x0080);
|
|
197
|
+
const z = (flags & 0x0070) >> 4;
|
|
198
|
+
const rcode = flags & 0x000f;
|
|
199
|
+
const qdCount = msg.readUInt16BE(4);
|
|
200
|
+
const anCount = msg.readUInt16BE(6);
|
|
201
|
+
const nsCount = msg.readUInt16BE(8);
|
|
202
|
+
const arCount = msg.readUInt16BE(10);
|
|
203
|
+
const mdnsMessage = {
|
|
204
|
+
id,
|
|
205
|
+
qr,
|
|
206
|
+
opcode,
|
|
207
|
+
aa,
|
|
208
|
+
tc,
|
|
209
|
+
rd,
|
|
210
|
+
ra,
|
|
211
|
+
z,
|
|
212
|
+
rcode,
|
|
213
|
+
qdCount,
|
|
214
|
+
anCount,
|
|
215
|
+
nsCount,
|
|
216
|
+
arCount,
|
|
217
|
+
questions: [],
|
|
218
|
+
answers: [],
|
|
219
|
+
authorities: [],
|
|
220
|
+
additionals: [],
|
|
221
|
+
};
|
|
222
|
+
let offset = 12;
|
|
223
|
+
for (let i = 0; i < qdCount; i++) {
|
|
224
|
+
const qnameResult = this.decodeDnsName(msg, offset);
|
|
225
|
+
const qname = qnameResult.name;
|
|
226
|
+
offset = qnameResult.newOffset;
|
|
227
|
+
const qtype = msg.readUInt16BE(offset);
|
|
228
|
+
offset += 2;
|
|
229
|
+
const qclass = msg.readUInt16BE(offset);
|
|
230
|
+
offset += 2;
|
|
231
|
+
mdnsMessage.questions?.push({ name: qname, type: qtype, class: qclass });
|
|
232
|
+
}
|
|
233
|
+
for (let i = 0; i < anCount; i++) {
|
|
234
|
+
const rrResult = this.decodeResourceRecord(msg, offset);
|
|
235
|
+
mdnsMessage.answers?.push(rrResult.record);
|
|
236
|
+
offset = rrResult.newOffset;
|
|
237
|
+
}
|
|
238
|
+
for (let i = 0; i < nsCount; i++) {
|
|
239
|
+
const rrResult = this.decodeResourceRecord(msg, offset);
|
|
240
|
+
mdnsMessage.authorities?.push(rrResult.record);
|
|
241
|
+
offset = rrResult.newOffset;
|
|
242
|
+
}
|
|
243
|
+
for (let i = 0; i < arCount; i++) {
|
|
244
|
+
const rrResult = this.decodeResourceRecord(msg, offset);
|
|
245
|
+
mdnsMessage.additionals?.push(rrResult.record);
|
|
246
|
+
offset = rrResult.newOffset;
|
|
247
|
+
}
|
|
248
|
+
return mdnsMessage;
|
|
249
|
+
}
|
|
250
|
+
decodeDnsName(msg, offset) {
|
|
251
|
+
const labels = [];
|
|
252
|
+
let jumped = false;
|
|
253
|
+
let originalOffset = offset;
|
|
254
|
+
let iterations = 0;
|
|
255
|
+
while (true) {
|
|
256
|
+
if (iterations++ > 1000) {
|
|
257
|
+
throw new Error('Too many iterations while decoding DNS name. Possible malformed message.');
|
|
258
|
+
}
|
|
259
|
+
if (offset >= msg.length) {
|
|
260
|
+
throw new Error('Offset exceeds buffer length while decoding DNS name.');
|
|
261
|
+
}
|
|
262
|
+
const len = msg.readUInt8(offset);
|
|
263
|
+
if (len === 0) {
|
|
264
|
+
offset++;
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
if ((len & 0xc0) === 0xc0) {
|
|
268
|
+
if (offset + 1 >= msg.length) {
|
|
269
|
+
throw new Error('Incomplete pointer encountered while decoding DNS name.');
|
|
270
|
+
}
|
|
271
|
+
const pointer = ((len & 0x3f) << 8) | msg.readUInt8(offset + 1);
|
|
272
|
+
if (!jumped) {
|
|
273
|
+
originalOffset = offset + 2;
|
|
274
|
+
}
|
|
275
|
+
offset = pointer;
|
|
276
|
+
jumped = true;
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
offset++;
|
|
280
|
+
if (offset + len > msg.length) {
|
|
281
|
+
throw new Error('Label length exceeds buffer bounds while decoding DNS name.');
|
|
282
|
+
}
|
|
283
|
+
labels.push(msg.toString('utf8', offset, offset + len));
|
|
284
|
+
offset += len;
|
|
285
|
+
}
|
|
286
|
+
return { name: labels.join('.'), newOffset: jumped ? originalOffset : offset };
|
|
287
|
+
}
|
|
288
|
+
encodeDnsName(name) {
|
|
289
|
+
const labels = name.split('.');
|
|
290
|
+
const buffers = labels.map((label) => {
|
|
291
|
+
const lenBuf = Buffer.alloc(1);
|
|
292
|
+
lenBuf.writeUInt8(label.length, 0);
|
|
293
|
+
return Buffer.concat([lenBuf, Buffer.from(label)]);
|
|
294
|
+
});
|
|
295
|
+
return Buffer.concat([...buffers, Buffer.from([0])]);
|
|
296
|
+
}
|
|
297
|
+
encodeTxtRdata(txt) {
|
|
298
|
+
const parts = txt.map((entry) => {
|
|
299
|
+
const value = Buffer.from(entry, 'utf8');
|
|
300
|
+
if (value.length > 255)
|
|
301
|
+
throw new Error(`TXT entry too long: ${entry}`);
|
|
302
|
+
return Buffer.concat([Buffer.from([value.length]), value]);
|
|
303
|
+
});
|
|
304
|
+
return Buffer.concat(parts);
|
|
305
|
+
}
|
|
306
|
+
encodeSrvRdata(priority, weight, port, target) {
|
|
307
|
+
const fixed = Buffer.alloc(6);
|
|
308
|
+
fixed.writeUInt16BE(priority, 0);
|
|
309
|
+
fixed.writeUInt16BE(weight, 2);
|
|
310
|
+
fixed.writeUInt16BE(port, 4);
|
|
311
|
+
return Buffer.concat([fixed, this.encodeDnsName(target)]);
|
|
312
|
+
}
|
|
313
|
+
encodeA(ipv4) {
|
|
314
|
+
const parts = ipv4.split('.').map((p) => Number(p));
|
|
315
|
+
if (parts.length !== 4 || parts.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) {
|
|
316
|
+
throw new Error(`Invalid IPv4 address: ${ipv4}`);
|
|
317
|
+
}
|
|
318
|
+
return Buffer.from(parts);
|
|
319
|
+
}
|
|
320
|
+
encodeAAAA(ipv6WithOptionalScope) {
|
|
321
|
+
const ipv6 = ipv6WithOptionalScope.split('%')[0];
|
|
322
|
+
const [left, right] = ipv6.split('::');
|
|
323
|
+
const leftParts = left ? left.split(':').filter(Boolean) : [];
|
|
324
|
+
const rightParts = right ? right.split(':').filter(Boolean) : [];
|
|
325
|
+
if (ipv6.includes('::')) {
|
|
326
|
+
const missing = 8 - (leftParts.length + rightParts.length);
|
|
327
|
+
if (missing < 0)
|
|
328
|
+
throw new Error(`Invalid IPv6 address: ${ipv6WithOptionalScope}`);
|
|
329
|
+
const groups = [...leftParts, ...Array(missing).fill('0'), ...rightParts];
|
|
330
|
+
return Buffer.from(groups.flatMap((g) => {
|
|
331
|
+
const word = parseInt(g, 16);
|
|
332
|
+
if (!Number.isFinite(word) || word < 0 || word > 0xffff) {
|
|
333
|
+
throw new Error(`Invalid IPv6 group: ${g}`);
|
|
334
|
+
}
|
|
335
|
+
return [(word >> 8) & 0xff, word & 0xff];
|
|
336
|
+
}));
|
|
337
|
+
}
|
|
338
|
+
const groups = ipv6.split(':');
|
|
339
|
+
if (groups.length !== 8)
|
|
340
|
+
throw new Error(`Invalid IPv6 address: ${ipv6WithOptionalScope}`);
|
|
341
|
+
return Buffer.from(groups.flatMap((g) => {
|
|
342
|
+
if (!g)
|
|
343
|
+
throw new Error(`Invalid IPv6 group: ${g}`);
|
|
344
|
+
const word = parseInt(g, 16);
|
|
345
|
+
if (!Number.isFinite(word) || word < 0 || word > 0xffff)
|
|
346
|
+
throw new Error(`Invalid IPv6 group: ${g}`);
|
|
347
|
+
return [(word >> 8) & 0xff, word & 0xff];
|
|
348
|
+
}));
|
|
349
|
+
}
|
|
350
|
+
decodeResourceRecord(msg, offset) {
|
|
351
|
+
const nameResult = this.decodeDnsName(msg, offset);
|
|
352
|
+
const name = nameResult.name;
|
|
353
|
+
offset = nameResult.newOffset;
|
|
354
|
+
const type = msg.readUInt16BE(offset);
|
|
355
|
+
offset += 2;
|
|
356
|
+
const rrclass = msg.readUInt16BE(offset);
|
|
357
|
+
offset += 2;
|
|
358
|
+
const ttl = msg.readUInt32BE(offset);
|
|
359
|
+
offset += 4;
|
|
360
|
+
const rdlength = msg.readUInt16BE(offset);
|
|
361
|
+
offset += 2;
|
|
362
|
+
let data = '';
|
|
363
|
+
if (type === 12) {
|
|
364
|
+
const ptrResult = this.decodeDnsName(msg, offset);
|
|
365
|
+
data = ptrResult.name;
|
|
366
|
+
offset += rdlength;
|
|
367
|
+
}
|
|
368
|
+
else if (type === 16) {
|
|
369
|
+
const txtStrings = [];
|
|
370
|
+
const end = offset + rdlength;
|
|
371
|
+
while (offset < end) {
|
|
372
|
+
const txtLen = msg[offset];
|
|
373
|
+
offset++;
|
|
374
|
+
const txt = msg.slice(offset, offset + txtLen).toString('utf8');
|
|
375
|
+
txtStrings.push(txt);
|
|
376
|
+
offset += txtLen;
|
|
377
|
+
}
|
|
378
|
+
data = txtStrings.join(', ');
|
|
379
|
+
}
|
|
380
|
+
else if (type === 33) {
|
|
381
|
+
const priority = msg.readUInt16BE(offset);
|
|
382
|
+
const weight = msg.readUInt16BE(offset + 2);
|
|
383
|
+
const port = msg.readUInt16BE(offset + 4);
|
|
384
|
+
offset += 6;
|
|
385
|
+
const srvTargetResult = this.decodeDnsName(msg, offset);
|
|
386
|
+
data = JSON.stringify({
|
|
387
|
+
priority,
|
|
388
|
+
weight,
|
|
389
|
+
port,
|
|
390
|
+
target: srvTargetResult.name,
|
|
391
|
+
});
|
|
392
|
+
offset = srvTargetResult.newOffset;
|
|
393
|
+
}
|
|
394
|
+
else if (type === 1) {
|
|
395
|
+
const ipBytes = msg.slice(offset, offset + 4);
|
|
396
|
+
data = Array.from(ipBytes).join('.');
|
|
397
|
+
offset += 4;
|
|
398
|
+
}
|
|
399
|
+
else if (type === 28) {
|
|
400
|
+
const ipBytes = msg.slice(offset, offset + 16);
|
|
401
|
+
const ipv6Parts = [];
|
|
402
|
+
for (let i = 0; i < 16; i += 2) {
|
|
403
|
+
ipv6Parts.push(ipBytes.readUInt16BE(i).toString(16));
|
|
404
|
+
}
|
|
405
|
+
data = ipv6Parts.join(':');
|
|
406
|
+
offset += 16;
|
|
407
|
+
}
|
|
408
|
+
else if (type === 47) {
|
|
409
|
+
const { name: nextDomain, newOffset } = this.decodeDnsName(msg, offset);
|
|
410
|
+
const nextDomainLength = newOffset - offset;
|
|
411
|
+
offset = newOffset;
|
|
412
|
+
const bitmapLength = rdlength - nextDomainLength;
|
|
413
|
+
const bitmapData = msg.slice(offset, offset + bitmapLength);
|
|
414
|
+
const types = [];
|
|
415
|
+
let bitmapOffset = 0;
|
|
416
|
+
while (bitmapOffset < bitmapData.length) {
|
|
417
|
+
const windowBlock = bitmapData[bitmapOffset];
|
|
418
|
+
const windowLength = bitmapData[bitmapOffset + 1];
|
|
419
|
+
bitmapOffset += 2;
|
|
420
|
+
for (let i = 0; i < windowLength; i++) {
|
|
421
|
+
const octet = bitmapData[bitmapOffset + i];
|
|
422
|
+
for (let bit = 0; bit < 8; bit++) {
|
|
423
|
+
if (octet & (0x80 >> bit)) {
|
|
424
|
+
const typeCode = windowBlock * 256 + i * 8 + bit;
|
|
425
|
+
types.push(this.dnsTypeToString(typeCode));
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
bitmapOffset += windowLength;
|
|
430
|
+
}
|
|
431
|
+
data = JSON.stringify({
|
|
432
|
+
nextDomain,
|
|
433
|
+
types,
|
|
434
|
+
});
|
|
435
|
+
offset += bitmapLength;
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
data = msg.slice(offset, offset + rdlength).toString('hex');
|
|
439
|
+
offset += rdlength;
|
|
440
|
+
}
|
|
441
|
+
return {
|
|
442
|
+
record: { name, type, class: rrclass, ttl, data },
|
|
443
|
+
newOffset: offset,
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
sendQuery(questions) {
|
|
447
|
+
const header = Buffer.alloc(12);
|
|
448
|
+
header.writeUInt16BE(0, 0);
|
|
449
|
+
header.writeUInt16BE(0, 2);
|
|
450
|
+
header.writeUInt16BE(questions.length, 4);
|
|
451
|
+
header.writeUInt16BE(0, 6);
|
|
452
|
+
header.writeUInt16BE(0, 8);
|
|
453
|
+
header.writeUInt16BE(0, 10);
|
|
454
|
+
const questionBuffers = questions.map(({ name, type: qtype, class: qclass, unicastResponse = false }) => {
|
|
455
|
+
const qname = this.encodeDnsName(name);
|
|
456
|
+
const qfields = Buffer.alloc(4);
|
|
457
|
+
qfields.writeUInt16BE(qtype, 0);
|
|
458
|
+
qfields.writeUInt16BE(unicastResponse ? qclass | 32768 : qclass, 2);
|
|
459
|
+
return Buffer.concat([qname, qfields]);
|
|
460
|
+
});
|
|
461
|
+
const query = Buffer.concat([header, ...questionBuffers]);
|
|
462
|
+
if (hasParameter('v') || hasParameter('verbose')) {
|
|
463
|
+
const decoded = this.decodeMdnsMessage(query);
|
|
464
|
+
this.logMdnsMessage(decoded, undefined, 'Sending query mDNS message');
|
|
465
|
+
}
|
|
466
|
+
this.socket.send(query, 0, query.length, this.multicastPort, this.multicastAddress, (error) => {
|
|
467
|
+
if (error) {
|
|
468
|
+
this.log.error(`Dgram mDNS server failed to send query message: ${error instanceof Error ? error.message : error}`);
|
|
469
|
+
this.emit('error', error);
|
|
470
|
+
}
|
|
471
|
+
else {
|
|
472
|
+
this.log.debug(`Dgram mDNS server sent query message`);
|
|
473
|
+
this.emit('sent', query, this.multicastAddress, this.multicastPort);
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
return query;
|
|
477
|
+
}
|
|
478
|
+
sendResponse(answers) {
|
|
479
|
+
if (!Array.isArray(answers) || answers.length === 0) {
|
|
480
|
+
throw new Error('sendResponse requires a non-empty answers array');
|
|
481
|
+
}
|
|
482
|
+
const header = Buffer.alloc(12);
|
|
483
|
+
header.writeUInt16BE(0, 0);
|
|
484
|
+
header.writeUInt16BE(0x8400, 2);
|
|
485
|
+
header.writeUInt16BE(0, 4);
|
|
486
|
+
header.writeUInt16BE(answers.length, 6);
|
|
487
|
+
header.writeUInt16BE(0, 8);
|
|
488
|
+
header.writeUInt16BE(0, 10);
|
|
489
|
+
const answerBuffers = answers.map(({ name, rtype, rclass, ttl, rdata }) => {
|
|
490
|
+
const aname = this.encodeDnsName(name);
|
|
491
|
+
const answerFixed = Buffer.alloc(10);
|
|
492
|
+
answerFixed.writeUInt16BE(rtype, 0);
|
|
493
|
+
answerFixed.writeUInt16BE(rclass, 2);
|
|
494
|
+
answerFixed.writeUInt32BE(ttl, 4);
|
|
495
|
+
answerFixed.writeUInt16BE(rdata.length, 8);
|
|
496
|
+
return Buffer.concat([aname, answerFixed, rdata]);
|
|
497
|
+
});
|
|
498
|
+
const response = Buffer.concat([header, ...answerBuffers]);
|
|
499
|
+
if (hasParameter('v') || hasParameter('verbose')) {
|
|
500
|
+
const decoded = this.decodeMdnsMessage(response);
|
|
501
|
+
this.logMdnsMessage(decoded, undefined, 'Sending response mDNS message');
|
|
502
|
+
}
|
|
503
|
+
this.socket.send(response, 0, response.length, this.multicastPort, this.multicastAddress, (error) => {
|
|
504
|
+
if (error) {
|
|
505
|
+
this.log.error(`Dgram mDNS server failed to send response message: ${error instanceof Error ? error.message : error}`);
|
|
506
|
+
this.emit('error', error);
|
|
507
|
+
}
|
|
508
|
+
else {
|
|
509
|
+
this.log.debug(`Dgram mDNS server sent response message`);
|
|
510
|
+
this.emit('sent', response, this.multicastAddress, this.multicastPort);
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
return response;
|
|
514
|
+
}
|
|
515
|
+
dnsTypeToString(type) {
|
|
516
|
+
const typeMap = {
|
|
517
|
+
[1]: 'A',
|
|
518
|
+
[2]: 'NS',
|
|
519
|
+
[3]: 'MD',
|
|
520
|
+
[4]: 'MF',
|
|
521
|
+
[5]: 'CNAME',
|
|
522
|
+
[6]: 'SOA',
|
|
523
|
+
[7]: 'MB',
|
|
524
|
+
[8]: 'MG',
|
|
525
|
+
[9]: 'MR',
|
|
526
|
+
[10]: 'NULL',
|
|
527
|
+
[11]: 'WKS',
|
|
528
|
+
[12]: 'PTR',
|
|
529
|
+
[13]: 'HINFO',
|
|
530
|
+
[14]: 'MINFO',
|
|
531
|
+
[15]: 'MX',
|
|
532
|
+
[16]: 'TXT',
|
|
533
|
+
[17]: 'RP',
|
|
534
|
+
[18]: 'AFSDB',
|
|
535
|
+
[19]: 'X25',
|
|
536
|
+
[20]: 'ISDN',
|
|
537
|
+
[21]: 'RT',
|
|
538
|
+
[22]: 'NSAP',
|
|
539
|
+
[23]: 'NSAP_PTR',
|
|
540
|
+
[24]: 'SIG',
|
|
541
|
+
[25]: 'KEY',
|
|
542
|
+
[26]: 'PX',
|
|
543
|
+
[27]: 'GPOS',
|
|
544
|
+
[28]: 'AAAA',
|
|
545
|
+
[29]: 'LOC',
|
|
546
|
+
[30]: 'NXT',
|
|
547
|
+
[31]: 'EID',
|
|
548
|
+
[32]: 'NIMLOC',
|
|
549
|
+
[33]: 'SRV',
|
|
550
|
+
[34]: 'ATMA',
|
|
551
|
+
[35]: 'NAPTR',
|
|
552
|
+
[36]: 'KX',
|
|
553
|
+
[37]: 'CERT',
|
|
554
|
+
[38]: 'A6',
|
|
555
|
+
[39]: 'DNAME',
|
|
556
|
+
[40]: 'SINK',
|
|
557
|
+
[41]: 'OPT',
|
|
558
|
+
[42]: 'APL',
|
|
559
|
+
[43]: 'DS',
|
|
560
|
+
[44]: 'SSHFP',
|
|
561
|
+
[45]: 'IPSECKEY',
|
|
562
|
+
[46]: 'RRSIG',
|
|
563
|
+
[47]: 'NSEC',
|
|
564
|
+
[48]: 'DNSKEY',
|
|
565
|
+
[49]: 'DHCID',
|
|
566
|
+
[50]: 'NSEC3',
|
|
567
|
+
[51]: 'NSEC3PARAM',
|
|
568
|
+
[52]: 'TLSA',
|
|
569
|
+
[53]: 'SMIMEA',
|
|
570
|
+
[55]: 'HIP',
|
|
571
|
+
[56]: 'NINFO',
|
|
572
|
+
[57]: 'RKEY',
|
|
573
|
+
[58]: 'TALINK',
|
|
574
|
+
[59]: 'CDS',
|
|
575
|
+
[60]: 'CDNSKEY',
|
|
576
|
+
[61]: 'OPENPGPKEY',
|
|
577
|
+
[62]: 'CSYNC',
|
|
578
|
+
[63]: 'ZONEMD',
|
|
579
|
+
[64]: 'SVCB',
|
|
580
|
+
[65]: 'HTTPS',
|
|
581
|
+
[99]: 'SPF',
|
|
582
|
+
[100]: 'UINFO',
|
|
583
|
+
[101]: 'UID',
|
|
584
|
+
[102]: 'GID',
|
|
585
|
+
[103]: 'UNSPEC',
|
|
586
|
+
[104]: 'NID',
|
|
587
|
+
[105]: 'L32',
|
|
588
|
+
[106]: 'L64',
|
|
589
|
+
[107]: 'LP',
|
|
590
|
+
[108]: 'EUI48',
|
|
591
|
+
[109]: 'EUI64',
|
|
592
|
+
[249]: 'TKEY',
|
|
593
|
+
[250]: 'TSIG',
|
|
594
|
+
[251]: 'IXFR',
|
|
595
|
+
[252]: 'AXFR',
|
|
596
|
+
[253]: 'MAILB',
|
|
597
|
+
[254]: 'MAILA',
|
|
598
|
+
[255]: 'ANY',
|
|
599
|
+
[256]: 'URI',
|
|
600
|
+
[257]: 'CAA',
|
|
601
|
+
[258]: 'AVC',
|
|
602
|
+
[259]: 'DOA',
|
|
603
|
+
[260]: 'AMTRELAY',
|
|
604
|
+
[261]: 'ZONEVERSION',
|
|
605
|
+
[32768]: 'TA',
|
|
606
|
+
[32769]: 'DLV',
|
|
607
|
+
};
|
|
608
|
+
return typeMap[type] ?? `TYPE${type}`;
|
|
609
|
+
}
|
|
610
|
+
dnsResponseClassToString(cls) {
|
|
611
|
+
const isFlush = !!(cls & 32768);
|
|
612
|
+
const baseClass = cls & 0x7fff;
|
|
613
|
+
let classStr;
|
|
614
|
+
switch (baseClass) {
|
|
615
|
+
case 1:
|
|
616
|
+
classStr = 'IN';
|
|
617
|
+
break;
|
|
618
|
+
case 3:
|
|
619
|
+
classStr = 'CH';
|
|
620
|
+
break;
|
|
621
|
+
case 4:
|
|
622
|
+
classStr = 'HS';
|
|
623
|
+
break;
|
|
624
|
+
case 255:
|
|
625
|
+
classStr = 'ANY';
|
|
626
|
+
break;
|
|
627
|
+
default:
|
|
628
|
+
classStr = `CLASS${baseClass}`;
|
|
629
|
+
}
|
|
630
|
+
return isFlush ? `${classStr}|FLUSH` : classStr;
|
|
631
|
+
}
|
|
632
|
+
dnsQuestionClassToString(cls) {
|
|
633
|
+
const isQU = !!(cls & 32768);
|
|
634
|
+
const baseClass = cls & 0x7fff;
|
|
635
|
+
let classStr;
|
|
636
|
+
switch (baseClass) {
|
|
637
|
+
case 1:
|
|
638
|
+
classStr = 'IN';
|
|
639
|
+
break;
|
|
640
|
+
case 3:
|
|
641
|
+
classStr = 'CH';
|
|
642
|
+
break;
|
|
643
|
+
case 4:
|
|
644
|
+
classStr = 'HS';
|
|
645
|
+
break;
|
|
646
|
+
case 255:
|
|
647
|
+
classStr = 'ANY';
|
|
648
|
+
break;
|
|
649
|
+
default:
|
|
650
|
+
classStr = `CLASS${baseClass}`;
|
|
651
|
+
}
|
|
652
|
+
return isQU ? `${classStr}|QU` : classStr;
|
|
653
|
+
}
|
|
654
|
+
logMdnsMessage(msg, log = this.log, text = 'Decoded mDNS message') {
|
|
655
|
+
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}`);
|
|
656
|
+
msg.questions?.forEach((question) => {
|
|
657
|
+
log.info(`Question: ${CYAN}${question.name}${nf} type ${idn}${this.dnsTypeToString(question.type)}${rs}${nf} class ${CYAN}${this.dnsQuestionClassToString(question.class)}${nf}`);
|
|
658
|
+
});
|
|
659
|
+
msg.answers?.forEach((answer) => {
|
|
660
|
+
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}`);
|
|
661
|
+
});
|
|
662
|
+
msg.authorities?.forEach((authority) => {
|
|
663
|
+
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}`);
|
|
664
|
+
});
|
|
665
|
+
msg.additionals?.forEach((additional) => {
|
|
666
|
+
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}`);
|
|
667
|
+
});
|
|
668
|
+
log.info(`---\n`);
|
|
669
|
+
}
|
|
670
|
+
logDevices() {
|
|
671
|
+
this.log.info(`Discovered query devices: ${MAGENTA}${this.deviceQueries.size}${nf}`);
|
|
672
|
+
const deviceQueryArray = Array.from(this.deviceQueries.entries());
|
|
673
|
+
deviceQueryArray.sort(([addressA], [addressB]) => {
|
|
674
|
+
const partsA = addressA.split('.').map(Number);
|
|
675
|
+
const partsB = addressB.split('.').map(Number);
|
|
676
|
+
for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
|
|
677
|
+
const diff = (partsA[i] || 0) - (partsB[i] || 0);
|
|
678
|
+
if (diff !== 0)
|
|
679
|
+
return diff;
|
|
680
|
+
}
|
|
681
|
+
return 0;
|
|
682
|
+
});
|
|
683
|
+
deviceQueryArray.forEach(([rinfo, response]) => {
|
|
684
|
+
this.log.info(`- ${MAGENTA}${rinfo}${nf} family ${BLUE}${response.rinfo.family}${nf} address ${BLUE}${response.rinfo.address}${nf} port ${BLUE}${response.rinfo.port}${nf}`);
|
|
685
|
+
});
|
|
686
|
+
this.log.info(`Discovered response devices: ${MAGENTA}${this.deviceResponses.size}${nf}`);
|
|
687
|
+
const deviceResponseArray = Array.from(this.deviceResponses.entries());
|
|
688
|
+
deviceResponseArray.sort(([addressA], [addressB]) => {
|
|
689
|
+
const partsA = addressA.split(/[:.]/).map((part) => parseInt(part, 16));
|
|
690
|
+
const partsB = addressB.split(/[:.]/).map((part) => parseInt(part, 16));
|
|
691
|
+
for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
|
|
692
|
+
const diff = (partsA[i] || 0) - (partsB[i] || 0);
|
|
693
|
+
if (diff !== 0)
|
|
694
|
+
return diff;
|
|
695
|
+
}
|
|
696
|
+
return 0;
|
|
697
|
+
});
|
|
698
|
+
deviceResponseArray.forEach(([rinfo, response]) => {
|
|
699
|
+
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}`);
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
}
|