matterbridge 3.5.0 → 3.5.1-dev-20260121-22e98b4

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.
Files changed (328) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/bin/mb_coap.js +1 -1
  3. package/bin/mb_mdns.js +1 -1
  4. package/dist/broadcastServer.d.ts +0 -115
  5. package/dist/broadcastServer.js +1 -119
  6. package/dist/broadcastServerTypes.d.ts +0 -43
  7. package/dist/broadcastServerTypes.js +0 -24
  8. package/dist/cli.d.ts +1 -26
  9. package/dist/cli.js +2 -102
  10. package/dist/cliEmitter.d.ts +0 -36
  11. package/dist/cliEmitter.js +0 -37
  12. package/dist/cliHistory.d.ts +0 -42
  13. package/dist/cliHistory.js +1 -39
  14. package/dist/clusters/export.d.ts +0 -1
  15. package/dist/clusters/export.js +0 -2
  16. package/dist/deviceManager.d.ts +0 -108
  17. package/dist/deviceManager.js +2 -114
  18. package/dist/devices/airConditioner.d.ts +0 -75
  19. package/dist/devices/airConditioner.js +0 -57
  20. package/dist/devices/batteryStorage.d.ts +0 -43
  21. package/dist/devices/batteryStorage.js +1 -48
  22. package/dist/devices/cooktop.d.ts +0 -55
  23. package/dist/devices/cooktop.js +0 -56
  24. package/dist/devices/dishwasher.d.ts +0 -55
  25. package/dist/devices/dishwasher.js +0 -57
  26. package/dist/devices/evse.d.ts +0 -57
  27. package/dist/devices/evse.js +10 -74
  28. package/dist/devices/export.d.ts +0 -1
  29. package/dist/devices/export.js +0 -5
  30. package/dist/devices/extractorHood.d.ts +0 -41
  31. package/dist/devices/extractorHood.js +0 -43
  32. package/dist/devices/heatPump.d.ts +0 -43
  33. package/dist/devices/heatPump.js +2 -50
  34. package/dist/devices/laundryDryer.d.ts +0 -58
  35. package/dist/devices/laundryDryer.js +3 -62
  36. package/dist/devices/laundryWasher.d.ts +0 -64
  37. package/dist/devices/laundryWasher.js +4 -70
  38. package/dist/devices/microwaveOven.d.ts +1 -77
  39. package/dist/devices/microwaveOven.js +5 -88
  40. package/dist/devices/oven.d.ts +0 -82
  41. package/dist/devices/oven.js +0 -85
  42. package/dist/devices/refrigerator.d.ts +0 -100
  43. package/dist/devices/refrigerator.js +0 -102
  44. package/dist/devices/roboticVacuumCleaner.d.ts +0 -83
  45. package/dist/devices/roboticVacuumCleaner.js +9 -100
  46. package/dist/devices/solarPower.d.ts +0 -36
  47. package/dist/devices/solarPower.js +0 -38
  48. package/dist/devices/speaker.d.ts +0 -79
  49. package/dist/devices/speaker.js +0 -84
  50. package/dist/devices/temperatureControl.d.ts +0 -21
  51. package/dist/devices/temperatureControl.js +3 -24
  52. package/dist/devices/waterHeater.d.ts +0 -74
  53. package/dist/devices/waterHeater.js +2 -82
  54. package/dist/frontend.d.ts +0 -187
  55. package/dist/frontend.js +39 -505
  56. package/dist/frontendTypes.d.ts +0 -57
  57. package/dist/frontendTypes.js +0 -45
  58. package/dist/helpers.d.ts +0 -43
  59. package/dist/helpers.js +1 -54
  60. package/dist/index.d.ts +0 -23
  61. package/dist/index.js +0 -25
  62. package/dist/jestutils/export.d.ts +0 -1
  63. package/dist/jestutils/export.js +0 -1
  64. package/dist/jestutils/jestHelpers.d.ts +0 -255
  65. package/dist/jestutils/jestHelpers.js +14 -372
  66. package/dist/logger/export.d.ts +0 -1
  67. package/dist/logger/export.js +0 -1
  68. package/dist/matter/behaviors.d.ts +0 -1
  69. package/dist/matter/behaviors.js +0 -2
  70. package/dist/matter/clusters.d.ts +0 -1
  71. package/dist/matter/clusters.js +0 -2
  72. package/dist/matter/devices.d.ts +0 -1
  73. package/dist/matter/devices.js +0 -2
  74. package/dist/matter/endpoints.d.ts +0 -1
  75. package/dist/matter/endpoints.js +0 -2
  76. package/dist/matter/export.d.ts +0 -1
  77. package/dist/matter/export.js +0 -2
  78. package/dist/matter/types.d.ts +0 -1
  79. package/dist/matter/types.js +0 -2
  80. package/dist/matterNode.d.ts +0 -258
  81. package/dist/matterNode.js +9 -364
  82. package/dist/matterbridge.d.ts +0 -362
  83. package/dist/matterbridge.js +60 -860
  84. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -36
  85. package/dist/matterbridgeAccessoryPlatform.js +0 -38
  86. package/dist/matterbridgeBehaviors.d.ts +0 -24
  87. package/dist/matterbridgeBehaviors.js +5 -68
  88. package/dist/matterbridgeDeviceTypes.d.ts +0 -649
  89. package/dist/matterbridgeDeviceTypes.js +6 -673
  90. package/dist/matterbridgeDynamicPlatform.d.ts +0 -36
  91. package/dist/matterbridgeDynamicPlatform.js +0 -38
  92. package/dist/matterbridgeEndpoint.d.ts +2 -1332
  93. package/dist/matterbridgeEndpoint.js +94 -1459
  94. package/dist/matterbridgeEndpointHelpers.d.ts +0 -425
  95. package/dist/matterbridgeEndpointHelpers.js +21 -486
  96. package/dist/matterbridgeEndpointTypes.d.ts +0 -70
  97. package/dist/matterbridgeEndpointTypes.js +0 -25
  98. package/dist/matterbridgePlatform.d.ts +0 -425
  99. package/dist/matterbridgePlatform.js +2 -453
  100. package/dist/matterbridgeTypes.d.ts +0 -46
  101. package/dist/matterbridgeTypes.js +0 -26
  102. package/dist/mb_coap.d.ts +1 -0
  103. package/dist/{dgram/mb_coap.js → mb_coap.js} +3 -41
  104. package/dist/mb_mdns.d.ts +1 -0
  105. package/dist/{dgram/mb_mdns.js → mb_mdns.js} +37 -81
  106. package/dist/pluginManager.d.ts +0 -305
  107. package/dist/pluginManager.js +8 -345
  108. package/dist/shelly.d.ts +0 -157
  109. package/dist/shelly.js +7 -178
  110. package/dist/spawn.d.ts +1 -0
  111. package/dist/{utils/spawn.js → spawn.js} +3 -73
  112. package/dist/storage/export.d.ts +0 -1
  113. package/dist/storage/export.js +0 -1
  114. package/dist/update.d.ts +0 -75
  115. package/dist/update.js +7 -100
  116. package/dist/utils/export.d.ts +1 -13
  117. package/dist/utils/export.js +1 -13
  118. package/dist/workerGlobalPrefix.d.ts +0 -24
  119. package/dist/workerGlobalPrefix.js +6 -40
  120. package/dist/workerTypes.d.ts +0 -25
  121. package/dist/workerTypes.js +0 -24
  122. package/dist/workers.d.ts +0 -61
  123. package/dist/workers.js +4 -68
  124. package/npm-shrinkwrap.json +35 -5
  125. package/package.json +5 -5
  126. package/dist/broadcastServer.d.ts.map +0 -1
  127. package/dist/broadcastServer.js.map +0 -1
  128. package/dist/broadcastServerTypes.d.ts.map +0 -1
  129. package/dist/broadcastServerTypes.js.map +0 -1
  130. package/dist/cli.d.ts.map +0 -1
  131. package/dist/cli.js.map +0 -1
  132. package/dist/cliEmitter.d.ts.map +0 -1
  133. package/dist/cliEmitter.js.map +0 -1
  134. package/dist/cliHistory.d.ts.map +0 -1
  135. package/dist/cliHistory.js.map +0 -1
  136. package/dist/clusters/export.d.ts.map +0 -1
  137. package/dist/clusters/export.js.map +0 -1
  138. package/dist/deviceManager.d.ts.map +0 -1
  139. package/dist/deviceManager.js.map +0 -1
  140. package/dist/devices/airConditioner.d.ts.map +0 -1
  141. package/dist/devices/airConditioner.js.map +0 -1
  142. package/dist/devices/batteryStorage.d.ts.map +0 -1
  143. package/dist/devices/batteryStorage.js.map +0 -1
  144. package/dist/devices/cooktop.d.ts.map +0 -1
  145. package/dist/devices/cooktop.js.map +0 -1
  146. package/dist/devices/dishwasher.d.ts.map +0 -1
  147. package/dist/devices/dishwasher.js.map +0 -1
  148. package/dist/devices/evse.d.ts.map +0 -1
  149. package/dist/devices/evse.js.map +0 -1
  150. package/dist/devices/export.d.ts.map +0 -1
  151. package/dist/devices/export.js.map +0 -1
  152. package/dist/devices/extractorHood.d.ts.map +0 -1
  153. package/dist/devices/extractorHood.js.map +0 -1
  154. package/dist/devices/heatPump.d.ts.map +0 -1
  155. package/dist/devices/heatPump.js.map +0 -1
  156. package/dist/devices/laundryDryer.d.ts.map +0 -1
  157. package/dist/devices/laundryDryer.js.map +0 -1
  158. package/dist/devices/laundryWasher.d.ts.map +0 -1
  159. package/dist/devices/laundryWasher.js.map +0 -1
  160. package/dist/devices/microwaveOven.d.ts.map +0 -1
  161. package/dist/devices/microwaveOven.js.map +0 -1
  162. package/dist/devices/oven.d.ts.map +0 -1
  163. package/dist/devices/oven.js.map +0 -1
  164. package/dist/devices/refrigerator.d.ts.map +0 -1
  165. package/dist/devices/refrigerator.js.map +0 -1
  166. package/dist/devices/roboticVacuumCleaner.d.ts.map +0 -1
  167. package/dist/devices/roboticVacuumCleaner.js.map +0 -1
  168. package/dist/devices/solarPower.d.ts.map +0 -1
  169. package/dist/devices/solarPower.js.map +0 -1
  170. package/dist/devices/speaker.d.ts.map +0 -1
  171. package/dist/devices/speaker.js.map +0 -1
  172. package/dist/devices/temperatureControl.d.ts.map +0 -1
  173. package/dist/devices/temperatureControl.js.map +0 -1
  174. package/dist/devices/waterHeater.d.ts.map +0 -1
  175. package/dist/devices/waterHeater.js.map +0 -1
  176. package/dist/dgram/coap.d.ts +0 -205
  177. package/dist/dgram/coap.d.ts.map +0 -1
  178. package/dist/dgram/coap.js +0 -365
  179. package/dist/dgram/coap.js.map +0 -1
  180. package/dist/dgram/dgram.d.ts +0 -144
  181. package/dist/dgram/dgram.d.ts.map +0 -1
  182. package/dist/dgram/dgram.js +0 -363
  183. package/dist/dgram/dgram.js.map +0 -1
  184. package/dist/dgram/mb_coap.d.ts +0 -24
  185. package/dist/dgram/mb_coap.d.ts.map +0 -1
  186. package/dist/dgram/mb_coap.js.map +0 -1
  187. package/dist/dgram/mb_mdns.d.ts +0 -24
  188. package/dist/dgram/mb_mdns.d.ts.map +0 -1
  189. package/dist/dgram/mb_mdns.js.map +0 -1
  190. package/dist/dgram/mdns.d.ts +0 -371
  191. package/dist/dgram/mdns.d.ts.map +0 -1
  192. package/dist/dgram/mdns.js +0 -934
  193. package/dist/dgram/mdns.js.map +0 -1
  194. package/dist/dgram/multicast.d.ts +0 -67
  195. package/dist/dgram/multicast.d.ts.map +0 -1
  196. package/dist/dgram/multicast.js +0 -179
  197. package/dist/dgram/multicast.js.map +0 -1
  198. package/dist/dgram/unicast.d.ts +0 -64
  199. package/dist/dgram/unicast.d.ts.map +0 -1
  200. package/dist/dgram/unicast.js +0 -100
  201. package/dist/dgram/unicast.js.map +0 -1
  202. package/dist/frontend.d.ts.map +0 -1
  203. package/dist/frontend.js.map +0 -1
  204. package/dist/frontendTypes.d.ts.map +0 -1
  205. package/dist/frontendTypes.js.map +0 -1
  206. package/dist/helpers.d.ts.map +0 -1
  207. package/dist/helpers.js.map +0 -1
  208. package/dist/index.d.ts.map +0 -1
  209. package/dist/index.js.map +0 -1
  210. package/dist/jestutils/export.d.ts.map +0 -1
  211. package/dist/jestutils/export.js.map +0 -1
  212. package/dist/jestutils/jestHelpers.d.ts.map +0 -1
  213. package/dist/jestutils/jestHelpers.js.map +0 -1
  214. package/dist/logger/export.d.ts.map +0 -1
  215. package/dist/logger/export.js.map +0 -1
  216. package/dist/matter/behaviors.d.ts.map +0 -1
  217. package/dist/matter/behaviors.js.map +0 -1
  218. package/dist/matter/clusters.d.ts.map +0 -1
  219. package/dist/matter/clusters.js.map +0 -1
  220. package/dist/matter/devices.d.ts.map +0 -1
  221. package/dist/matter/devices.js.map +0 -1
  222. package/dist/matter/endpoints.d.ts.map +0 -1
  223. package/dist/matter/endpoints.js.map +0 -1
  224. package/dist/matter/export.d.ts.map +0 -1
  225. package/dist/matter/export.js.map +0 -1
  226. package/dist/matter/types.d.ts.map +0 -1
  227. package/dist/matter/types.js.map +0 -1
  228. package/dist/matterNode.d.ts.map +0 -1
  229. package/dist/matterNode.js.map +0 -1
  230. package/dist/matterbridge.d.ts.map +0 -1
  231. package/dist/matterbridge.js.map +0 -1
  232. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  233. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  234. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  235. package/dist/matterbridgeBehaviors.js.map +0 -1
  236. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  237. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  238. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  239. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  240. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  241. package/dist/matterbridgeEndpoint.js.map +0 -1
  242. package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
  243. package/dist/matterbridgeEndpointHelpers.js.map +0 -1
  244. package/dist/matterbridgeEndpointTypes.d.ts.map +0 -1
  245. package/dist/matterbridgeEndpointTypes.js.map +0 -1
  246. package/dist/matterbridgePlatform.d.ts.map +0 -1
  247. package/dist/matterbridgePlatform.js.map +0 -1
  248. package/dist/matterbridgeTypes.d.ts.map +0 -1
  249. package/dist/matterbridgeTypes.js.map +0 -1
  250. package/dist/pluginManager.d.ts.map +0 -1
  251. package/dist/pluginManager.js.map +0 -1
  252. package/dist/shelly.d.ts.map +0 -1
  253. package/dist/shelly.js.map +0 -1
  254. package/dist/storage/export.d.ts.map +0 -1
  255. package/dist/storage/export.js.map +0 -1
  256. package/dist/update.d.ts.map +0 -1
  257. package/dist/update.js.map +0 -1
  258. package/dist/utils/colorUtils.d.ts +0 -101
  259. package/dist/utils/colorUtils.d.ts.map +0 -1
  260. package/dist/utils/colorUtils.js +0 -282
  261. package/dist/utils/colorUtils.js.map +0 -1
  262. package/dist/utils/commandLine.d.ts +0 -66
  263. package/dist/utils/commandLine.d.ts.map +0 -1
  264. package/dist/utils/commandLine.js +0 -123
  265. package/dist/utils/commandLine.js.map +0 -1
  266. package/dist/utils/copyDirectory.d.ts +0 -35
  267. package/dist/utils/copyDirectory.d.ts.map +0 -1
  268. package/dist/utils/copyDirectory.js +0 -76
  269. package/dist/utils/copyDirectory.js.map +0 -1
  270. package/dist/utils/createDirectory.d.ts +0 -34
  271. package/dist/utils/createDirectory.d.ts.map +0 -1
  272. package/dist/utils/createDirectory.js +0 -54
  273. package/dist/utils/createDirectory.js.map +0 -1
  274. package/dist/utils/createZip.d.ts +0 -39
  275. package/dist/utils/createZip.d.ts.map +0 -1
  276. package/dist/utils/createZip.js +0 -114
  277. package/dist/utils/createZip.js.map +0 -1
  278. package/dist/utils/deepCopy.d.ts +0 -32
  279. package/dist/utils/deepCopy.d.ts.map +0 -1
  280. package/dist/utils/deepCopy.js +0 -79
  281. package/dist/utils/deepCopy.js.map +0 -1
  282. package/dist/utils/deepEqual.d.ts +0 -54
  283. package/dist/utils/deepEqual.d.ts.map +0 -1
  284. package/dist/utils/deepEqual.js +0 -129
  285. package/dist/utils/deepEqual.js.map +0 -1
  286. package/dist/utils/error.d.ts +0 -45
  287. package/dist/utils/error.d.ts.map +0 -1
  288. package/dist/utils/error.js +0 -54
  289. package/dist/utils/error.js.map +0 -1
  290. package/dist/utils/export.d.ts.map +0 -1
  291. package/dist/utils/export.js.map +0 -1
  292. package/dist/utils/format.d.ts +0 -53
  293. package/dist/utils/format.d.ts.map +0 -1
  294. package/dist/utils/format.js +0 -78
  295. package/dist/utils/format.js.map +0 -1
  296. package/dist/utils/hex.d.ts +0 -89
  297. package/dist/utils/hex.d.ts.map +0 -1
  298. package/dist/utils/hex.js +0 -242
  299. package/dist/utils/hex.js.map +0 -1
  300. package/dist/utils/inspector.d.ts +0 -87
  301. package/dist/utils/inspector.d.ts.map +0 -1
  302. package/dist/utils/inspector.js +0 -268
  303. package/dist/utils/inspector.js.map +0 -1
  304. package/dist/utils/isValid.d.ts +0 -103
  305. package/dist/utils/isValid.d.ts.map +0 -1
  306. package/dist/utils/isValid.js +0 -162
  307. package/dist/utils/isValid.js.map +0 -1
  308. package/dist/utils/network.d.ts +0 -141
  309. package/dist/utils/network.d.ts.map +0 -1
  310. package/dist/utils/network.js +0 -314
  311. package/dist/utils/network.js.map +0 -1
  312. package/dist/utils/spawn.d.ts +0 -33
  313. package/dist/utils/spawn.d.ts.map +0 -1
  314. package/dist/utils/spawn.js.map +0 -1
  315. package/dist/utils/tracker.d.ts +0 -108
  316. package/dist/utils/tracker.d.ts.map +0 -1
  317. package/dist/utils/tracker.js +0 -264
  318. package/dist/utils/tracker.js.map +0 -1
  319. package/dist/utils/wait.d.ts +0 -54
  320. package/dist/utils/wait.d.ts.map +0 -1
  321. package/dist/utils/wait.js +0 -125
  322. package/dist/utils/wait.js.map +0 -1
  323. package/dist/workerGlobalPrefix.d.ts.map +0 -1
  324. package/dist/workerGlobalPrefix.js.map +0 -1
  325. package/dist/workerTypes.d.ts.map +0 -1
  326. package/dist/workerTypes.js.map +0 -1
  327. package/dist/workers.d.ts.map +0 -1
  328. package/dist/workers.js.map +0 -1
@@ -1,934 +0,0 @@
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
- import { BLUE, CYAN, db, GREEN, idn, MAGENTA, nf, rs } from 'node-ansi-logger';
25
- // Utils imports
26
- import { hasParameter } from '../utils/commandLine.js';
27
- // Net imports
28
- import { Multicast } from './multicast.js';
29
- export var DnsRecordType;
30
- (function (DnsRecordType) {
31
- DnsRecordType[DnsRecordType["A"] = 1] = "A";
32
- DnsRecordType[DnsRecordType["NS"] = 2] = "NS";
33
- DnsRecordType[DnsRecordType["MD"] = 3] = "MD";
34
- DnsRecordType[DnsRecordType["MF"] = 4] = "MF";
35
- DnsRecordType[DnsRecordType["CNAME"] = 5] = "CNAME";
36
- DnsRecordType[DnsRecordType["SOA"] = 6] = "SOA";
37
- DnsRecordType[DnsRecordType["MB"] = 7] = "MB";
38
- DnsRecordType[DnsRecordType["MG"] = 8] = "MG";
39
- DnsRecordType[DnsRecordType["MR"] = 9] = "MR";
40
- DnsRecordType[DnsRecordType["NULL"] = 10] = "NULL";
41
- DnsRecordType[DnsRecordType["WKS"] = 11] = "WKS";
42
- DnsRecordType[DnsRecordType["PTR"] = 12] = "PTR";
43
- DnsRecordType[DnsRecordType["HINFO"] = 13] = "HINFO";
44
- DnsRecordType[DnsRecordType["MINFO"] = 14] = "MINFO";
45
- DnsRecordType[DnsRecordType["MX"] = 15] = "MX";
46
- DnsRecordType[DnsRecordType["TXT"] = 16] = "TXT";
47
- DnsRecordType[DnsRecordType["RP"] = 17] = "RP";
48
- DnsRecordType[DnsRecordType["AFSDB"] = 18] = "AFSDB";
49
- DnsRecordType[DnsRecordType["X25"] = 19] = "X25";
50
- DnsRecordType[DnsRecordType["ISDN"] = 20] = "ISDN";
51
- DnsRecordType[DnsRecordType["RT"] = 21] = "RT";
52
- DnsRecordType[DnsRecordType["NSAP"] = 22] = "NSAP";
53
- DnsRecordType[DnsRecordType["NSAP_PTR"] = 23] = "NSAP_PTR";
54
- DnsRecordType[DnsRecordType["SIG"] = 24] = "SIG";
55
- DnsRecordType[DnsRecordType["KEY"] = 25] = "KEY";
56
- DnsRecordType[DnsRecordType["PX"] = 26] = "PX";
57
- DnsRecordType[DnsRecordType["GPOS"] = 27] = "GPOS";
58
- DnsRecordType[DnsRecordType["AAAA"] = 28] = "AAAA";
59
- DnsRecordType[DnsRecordType["LOC"] = 29] = "LOC";
60
- DnsRecordType[DnsRecordType["NXT"] = 30] = "NXT";
61
- DnsRecordType[DnsRecordType["EID"] = 31] = "EID";
62
- DnsRecordType[DnsRecordType["NIMLOC"] = 32] = "NIMLOC";
63
- DnsRecordType[DnsRecordType["SRV"] = 33] = "SRV";
64
- DnsRecordType[DnsRecordType["ATMA"] = 34] = "ATMA";
65
- DnsRecordType[DnsRecordType["NAPTR"] = 35] = "NAPTR";
66
- DnsRecordType[DnsRecordType["KX"] = 36] = "KX";
67
- DnsRecordType[DnsRecordType["CERT"] = 37] = "CERT";
68
- DnsRecordType[DnsRecordType["A6"] = 38] = "A6";
69
- DnsRecordType[DnsRecordType["DNAME"] = 39] = "DNAME";
70
- DnsRecordType[DnsRecordType["SINK"] = 40] = "SINK";
71
- DnsRecordType[DnsRecordType["OPT"] = 41] = "OPT";
72
- DnsRecordType[DnsRecordType["APL"] = 42] = "APL";
73
- DnsRecordType[DnsRecordType["DS"] = 43] = "DS";
74
- DnsRecordType[DnsRecordType["SSHFP"] = 44] = "SSHFP";
75
- DnsRecordType[DnsRecordType["IPSECKEY"] = 45] = "IPSECKEY";
76
- DnsRecordType[DnsRecordType["RRSIG"] = 46] = "RRSIG";
77
- DnsRecordType[DnsRecordType["NSEC"] = 47] = "NSEC";
78
- DnsRecordType[DnsRecordType["DNSKEY"] = 48] = "DNSKEY";
79
- DnsRecordType[DnsRecordType["DHCID"] = 49] = "DHCID";
80
- DnsRecordType[DnsRecordType["NSEC3"] = 50] = "NSEC3";
81
- DnsRecordType[DnsRecordType["NSEC3PARAM"] = 51] = "NSEC3PARAM";
82
- DnsRecordType[DnsRecordType["TLSA"] = 52] = "TLSA";
83
- DnsRecordType[DnsRecordType["SMIMEA"] = 53] = "SMIMEA";
84
- DnsRecordType[DnsRecordType["HIP"] = 55] = "HIP";
85
- DnsRecordType[DnsRecordType["NINFO"] = 56] = "NINFO";
86
- DnsRecordType[DnsRecordType["RKEY"] = 57] = "RKEY";
87
- DnsRecordType[DnsRecordType["TALINK"] = 58] = "TALINK";
88
- DnsRecordType[DnsRecordType["CDS"] = 59] = "CDS";
89
- DnsRecordType[DnsRecordType["CDNSKEY"] = 60] = "CDNSKEY";
90
- DnsRecordType[DnsRecordType["OPENPGPKEY"] = 61] = "OPENPGPKEY";
91
- DnsRecordType[DnsRecordType["CSYNC"] = 62] = "CSYNC";
92
- DnsRecordType[DnsRecordType["ZONEMD"] = 63] = "ZONEMD";
93
- DnsRecordType[DnsRecordType["SVCB"] = 64] = "SVCB";
94
- DnsRecordType[DnsRecordType["HTTPS"] = 65] = "HTTPS";
95
- DnsRecordType[DnsRecordType["SPF"] = 99] = "SPF";
96
- DnsRecordType[DnsRecordType["UINFO"] = 100] = "UINFO";
97
- DnsRecordType[DnsRecordType["UID"] = 101] = "UID";
98
- DnsRecordType[DnsRecordType["GID"] = 102] = "GID";
99
- DnsRecordType[DnsRecordType["UNSPEC"] = 103] = "UNSPEC";
100
- DnsRecordType[DnsRecordType["NID"] = 104] = "NID";
101
- DnsRecordType[DnsRecordType["L32"] = 105] = "L32";
102
- DnsRecordType[DnsRecordType["L64"] = 106] = "L64";
103
- DnsRecordType[DnsRecordType["LP"] = 107] = "LP";
104
- DnsRecordType[DnsRecordType["EUI48"] = 108] = "EUI48";
105
- DnsRecordType[DnsRecordType["EUI64"] = 109] = "EUI64";
106
- DnsRecordType[DnsRecordType["TKEY"] = 249] = "TKEY";
107
- DnsRecordType[DnsRecordType["TSIG"] = 250] = "TSIG";
108
- DnsRecordType[DnsRecordType["IXFR"] = 251] = "IXFR";
109
- DnsRecordType[DnsRecordType["AXFR"] = 252] = "AXFR";
110
- DnsRecordType[DnsRecordType["MAILB"] = 253] = "MAILB";
111
- DnsRecordType[DnsRecordType["MAILA"] = 254] = "MAILA";
112
- DnsRecordType[DnsRecordType["ANY"] = 255] = "ANY";
113
- DnsRecordType[DnsRecordType["URI"] = 256] = "URI";
114
- DnsRecordType[DnsRecordType["CAA"] = 257] = "CAA";
115
- DnsRecordType[DnsRecordType["AVC"] = 258] = "AVC";
116
- DnsRecordType[DnsRecordType["DOA"] = 259] = "DOA";
117
- DnsRecordType[DnsRecordType["AMTRELAY"] = 260] = "AMTRELAY";
118
- DnsRecordType[DnsRecordType["ZONEVERSION"] = 261] = "ZONEVERSION";
119
- // 262-32767 are unassigned/reserved
120
- DnsRecordType[DnsRecordType["TA"] = 32768] = "TA";
121
- DnsRecordType[DnsRecordType["DLV"] = 32769] = "DLV";
122
- })(DnsRecordType || (DnsRecordType = {}));
123
- export var DnsClass;
124
- (function (DnsClass) {
125
- DnsClass[DnsClass["IN"] = 1] = "IN";
126
- DnsClass[DnsClass["CH"] = 3] = "CH";
127
- DnsClass[DnsClass["HS"] = 4] = "HS";
128
- DnsClass[DnsClass["ANY"] = 255] = "ANY";
129
- })(DnsClass || (DnsClass = {}));
130
- export var DnsClassFlag;
131
- (function (DnsClassFlag) {
132
- DnsClassFlag[DnsClassFlag["FLUSH"] = 32768] = "FLUSH";
133
- // eslint-disable-next-line @typescript-eslint/no-duplicate-enum-values
134
- DnsClassFlag[DnsClassFlag["QU"] = 32768] = "QU";
135
- })(DnsClassFlag || (DnsClassFlag = {}));
136
- /**
137
- * Checks if a given message is an mDNS message.
138
- *
139
- * @param {Buffer} message - The message buffer to check.
140
- * @returns {boolean} True if the message is an mDNS message, false otherwise.
141
- */
142
- export function isMdns(message) {
143
- if (!message || message.length < 12)
144
- return false;
145
- const id = message.readUInt16BE(0);
146
- return id === 0;
147
- }
148
- /**
149
- * Checks if a given mDNS message is a query.
150
- *
151
- * @param {Buffer} message - The mDNS message buffer to check.
152
- * @returns {boolean} True if the message is a query, false otherwise.
153
- */
154
- export function isMdnsQuery(message) {
155
- if (message.length < 12)
156
- return false;
157
- const id = message.readUInt16BE(0);
158
- const flags = message.readUInt16BE(2);
159
- const qr = (flags & 0x8000) >> 15; // Bit 15: 0=query, 1=response.
160
- return id == 0 && qr === 0;
161
- }
162
- /**
163
- * Checks if a given mDNS message is a query.
164
- *
165
- * @param {Buffer} message - The mDNS message buffer to check.
166
- * @returns {boolean} True if the message is a query, false otherwise.
167
- */
168
- export function isMdnsResponse(message) {
169
- if (message.length < 12)
170
- return false;
171
- const id = message.readUInt16BE(0);
172
- const flags = message.readUInt16BE(2);
173
- const qr = (flags & 0x8000) >> 15; // Bit 15: 0=query, 1=response.
174
- return id == 0 && qr === 1;
175
- }
176
- export class Mdns extends Multicast {
177
- deviceQueries = new Map();
178
- deviceResponses = new Map();
179
- filters = [];
180
- /**
181
- * Creates an instance of the Mdns class.
182
- *
183
- * @param {string} name - The internal name of the mDNS server for the logs.
184
- * @param {string} multicastAddress - The multicast address for mDNS (i.e. 224.0.0.251 for udp4 or ff02::fb for udp6).
185
- * @param {number} multicastPort - The port for mDNS (i.e. 5353).
186
- * @param {('udp4' | 'udp6')} socketType - The type of socket to create (either 'udp4' or 'udp6').
187
- * @param {boolean} [reuseAddr] - Whether to reuse the address. Defaults to true.
188
- * @param {string} [interfaceName] - The optional name of the network interface to use.
189
- * @param {string} [interfaceAddress] - The optional IP address of the network interface to use.
190
- * @param {string} [outgoingInterfaceAddress] - The address of the outgoing network interface.
191
- */
192
- constructor(name, multicastAddress, multicastPort, socketType, reuseAddr = true, interfaceName, interfaceAddress, outgoingInterfaceAddress) {
193
- super(name, multicastAddress, multicastPort, socketType, reuseAddr, interfaceName, interfaceAddress, outgoingInterfaceAddress);
194
- }
195
- onQuery(rinfo, _query) {
196
- this.log.debug(`mDNS query received from ${BLUE}${rinfo.family}${db} ${BLUE}${rinfo.address}${db}:${BLUE}${rinfo.port}${db}`);
197
- }
198
- onResponse(rinfo, _response) {
199
- this.log.debug(`mDNS response received from ${BLUE}${rinfo.family}${db} ${BLUE}${rinfo.address}${db}:${BLUE}${rinfo.port}${db}`);
200
- }
201
- onMessage(msg, rinfo) {
202
- if (this.filters.length === 0)
203
- this.log.info(`Dgram mDNS server received a mDNS message from ${BLUE}${rinfo.family}${nf} ${BLUE}${rinfo.address}${nf}:${BLUE}${rinfo.port}${nf}`);
204
- try {
205
- const result = this.decodeMdnsMessage(msg);
206
- if (result.qr === 0) {
207
- this.deviceQueries.set(rinfo.address, { rinfo, query: result });
208
- this.onQuery(rinfo, result);
209
- }
210
- else {
211
- const ptr = result.answers?.find((record) => record.name === '_shelly._tcp.local' && record.type === 12 /* DnsRecordType.PTR */) ||
212
- result.answers?.find((record) => record.name === '_http._tcp.local' && record.type === 12 /* DnsRecordType.PTR */) ||
213
- result.answers?.find((record) => record.type === 12 /* DnsRecordType.PTR */) ||
214
- result.answers?.find((record) => record.type === 16 /* DnsRecordType.TXT */) ||
215
- result.answers
216
- ? result.answers[0]
217
- : undefined; // Fallback to the first answer if no PTR or TXT found
218
- this.deviceResponses.set(rinfo.address, { rinfo, response: result, dataPTR: ptr?.type === 12 /* DnsRecordType.PTR */ ? ptr?.data : ptr?.name });
219
- this.onResponse(rinfo, result);
220
- }
221
- // Apply filters if any
222
- if (this.filters.length > 0) {
223
- this.log.debug(`mDNS message filtered out by filters: ${this.filters.join(', ')}`);
224
- for (const filter of this.filters) {
225
- const foundInQuestions = result.questions?.some((q) => q.name.includes(filter));
226
- const foundInAnswers = result.answers?.some((a) => a.name.includes(filter) || a.data.includes(filter));
227
- const foundInAdditionals = result.additionals?.some((a) => a.name.includes(filter) || a.data.includes(filter));
228
- if (foundInQuestions || foundInAnswers || foundInAdditionals) {
229
- this.log.info(`Dgram mDNS server received a mDNS message from ${BLUE}${rinfo.family}${nf} ${BLUE}${rinfo.address}${nf}:${BLUE}${rinfo.port}${nf}`);
230
- this.logMdnsMessage(result);
231
- return;
232
- }
233
- }
234
- this.log.debug(`mDNS message does not match any filter, ignoring.`);
235
- return;
236
- }
237
- this.logMdnsMessage(result);
238
- }
239
- catch (error) {
240
- this.log.error(`Error decoding mDNS message: ${error instanceof Error ? error.message : error}`);
241
- }
242
- }
243
- /**
244
- * Decodes an mDNS message, including the header, question section, answer section,
245
- * authority section, and additional section.
246
- *
247
- * @param {Buffer} msg - The raw mDNS message buffer.
248
- * @returns {MdnsMessage} An object representing the decoded mDNS message.
249
- * @throws {Error} if the message is too short.
250
- */
251
- decodeMdnsMessage(msg) {
252
- if (msg.length < 12) {
253
- throw new Error('mDNS message too short');
254
- }
255
- const id = msg.readUInt16BE(0);
256
- const flags = msg.readUInt16BE(2);
257
- const qr = (flags & 0x8000) >> 15; // Bit 15: 0=query, 1=response (QR = Query/Response).
258
- const opcode = (flags & 0x7800) >> 11; // Bits 14-11 (OPCODE: kind of query; in mDNS this is typically 0 = standard query).
259
- const aa = Boolean(flags & 0x0400); // Bit 10 (AA: Authoritative Answer; sender claims authority for the name).
260
- const tc = Boolean(flags & 0x0200); // Bit 9 (TC: TrunCation; message was truncated due to length limits).
261
- const rd = Boolean(flags & 0x0100); // Bit 8 (RD: Recursion Desired; usually 0 in mDNS).
262
- const ra = Boolean(flags & 0x0080); // Bit 7 (RA: Recursion Available; meaningful for recursive resolvers, usually 0 in mDNS).
263
- const z = (flags & 0x0070) >> 4; // Bits 6-4 (Z: reserved in DNS; should be 0 in classic DNS/mDNS).
264
- const rcode = flags & 0x000f; // Bits 3-0 (RCODE: Response Code; 0 = NoError, 3 = NXDomain, etc).
265
- const qdCount = msg.readUInt16BE(4);
266
- const anCount = msg.readUInt16BE(6);
267
- const nsCount = msg.readUInt16BE(8);
268
- const arCount = msg.readUInt16BE(10);
269
- const mdnsMessage = {
270
- id,
271
- qr,
272
- opcode,
273
- aa,
274
- tc,
275
- rd,
276
- ra,
277
- z,
278
- rcode,
279
- qdCount,
280
- anCount,
281
- nsCount,
282
- arCount,
283
- questions: [],
284
- answers: [],
285
- authorities: [],
286
- additionals: [],
287
- };
288
- let offset = 12;
289
- // Decode the question section.
290
- for (let i = 0; i < qdCount; i++) {
291
- const qnameResult = this.decodeDnsName(msg, offset);
292
- const qname = qnameResult.name;
293
- offset = qnameResult.newOffset;
294
- const qtype = msg.readUInt16BE(offset);
295
- offset += 2;
296
- const qclass = msg.readUInt16BE(offset);
297
- offset += 2;
298
- mdnsMessage.questions?.push({ name: qname, type: qtype, class: qclass });
299
- }
300
- // Decode the answer section.
301
- for (let i = 0; i < anCount; i++) {
302
- const rrResult = this.decodeResourceRecord(msg, offset);
303
- mdnsMessage.answers?.push(rrResult.record);
304
- offset = rrResult.newOffset;
305
- }
306
- // Decode the authority (NS) section.
307
- for (let i = 0; i < nsCount; i++) {
308
- const rrResult = this.decodeResourceRecord(msg, offset);
309
- mdnsMessage.authorities?.push(rrResult.record);
310
- offset = rrResult.newOffset;
311
- }
312
- // Decode the additional records section.
313
- for (let i = 0; i < arCount; i++) {
314
- const rrResult = this.decodeResourceRecord(msg, offset);
315
- mdnsMessage.additionals?.push(rrResult.record);
316
- offset = rrResult.newOffset;
317
- }
318
- return mdnsMessage;
319
- }
320
- /**
321
- * Decodes a DNS name from a buffer, handling compression.
322
- *
323
- * @param {Buffer} msg - The full mDNS message buffer.
324
- * @param {number} offset - The offset at which the DNS name starts.
325
- * @returns {{ name: string; newOffset: number }} An object with the decoded name and the new offset.
326
- * @throws {Error} if the offset exceeds the buffer length or too many iterations are performed.
327
- */
328
- decodeDnsName(msg, offset) {
329
- const labels = [];
330
- let jumped = false;
331
- let originalOffset = offset;
332
- let iterations = 0; // Prevent infinite loops
333
- while (true) {
334
- // Safety guard: prevent infinite loops in malformed messages.
335
- if (iterations++ > 1000) {
336
- throw new Error('Too many iterations while decoding DNS name. Possible malformed message.');
337
- }
338
- // Check that offset is within buffer bounds.
339
- if (offset >= msg.length) {
340
- throw new Error('Offset exceeds buffer length while decoding DNS name.');
341
- }
342
- const len = msg.readUInt8(offset);
343
- if (len === 0) {
344
- offset++;
345
- break;
346
- }
347
- // Check for pointer (first two bits are 11)
348
- if ((len & 0xc0) === 0xc0) {
349
- // Ensure the pointer has two bytes available.
350
- if (offset + 1 >= msg.length) {
351
- throw new Error('Incomplete pointer encountered while decoding DNS name.');
352
- }
353
- const pointer = ((len & 0x3f) << 8) | msg.readUInt8(offset + 1);
354
- if (!jumped) {
355
- originalOffset = offset + 2;
356
- }
357
- offset = pointer;
358
- jumped = true;
359
- continue;
360
- }
361
- offset++;
362
- // Check that the label length doesn't go beyond the buffer.
363
- if (offset + len > msg.length) {
364
- throw new Error('Label length exceeds buffer bounds while decoding DNS name.');
365
- }
366
- labels.push(msg.toString('utf8', offset, offset + len));
367
- offset += len;
368
- }
369
- return { name: labels.join('.'), newOffset: jumped ? originalOffset : offset };
370
- }
371
- /**
372
- * Encodes a domain name into the DNS label format.
373
- *
374
- * For example, "example.local" becomes:
375
- * [7] "example" [5] "local" [0]
376
- *
377
- * @param {string} name - The domain name to encode.
378
- * @returns {Buffer} The encoded domain name as a Buffer.
379
- */
380
- encodeDnsName(name) {
381
- const labels = name.split('.');
382
- const buffers = labels.map((label) => {
383
- const lenBuf = Buffer.alloc(1);
384
- lenBuf.writeUInt8(label.length, 0);
385
- return Buffer.concat([lenBuf, Buffer.from(label)]);
386
- });
387
- // Append the null byte to terminate the name.
388
- return Buffer.concat([...buffers, Buffer.from([0])]);
389
- }
390
- /**
391
- * Encodes TXT record RDATA.
392
- *
393
- * In DNS/mDNS, TXT RDATA is a sequence of one or more <character-string>,
394
- * each encoded as: [length byte][UTF-8 bytes].
395
- *
396
- * @param {string[]} txt - Array of TXT entries, e.g. ["key=value", "path=/"].
397
- * @returns {Buffer} Encoded TXT RDATA.
398
- * @throws {Error} If any entry exceeds 255 bytes.
399
- *
400
- * @example
401
- * const txtRdata = mdns.encodeTxtRdata(['txtvers=1', 'path=/']);
402
- * mdns.sendResponse([
403
- * { name: 'example._http._tcp.local', rtype: DnsRecordType.TXT, rclass: DnsClass.IN | DnsClassFlag.FLUSH, ttl: 120, rdata: txtRdata },
404
- * ]);
405
- */
406
- encodeTxtRdata(txt) {
407
- const parts = txt.map((entry) => {
408
- const value = Buffer.from(entry, 'utf8');
409
- if (value.length > 255)
410
- throw new Error(`TXT entry too long: ${entry}`);
411
- return Buffer.concat([Buffer.from([value.length]), value]);
412
- });
413
- return Buffer.concat(parts);
414
- }
415
- /**
416
- * Encodes SRV record RDATA.
417
- *
418
- * SRV RDATA layout (RFC 2782):
419
- * - priority (2 bytes)
420
- * - weight (2 bytes)
421
- * - port (2 bytes)
422
- * - target (DNS name)
423
- *
424
- * @param {number} priority - SRV priority.
425
- * @param {number} weight - SRV weight.
426
- * @param {number} port - Service port.
427
- * @param {string} target - Target hostname (e.g. "matterbridge.local").
428
- * @returns {Buffer} Encoded SRV RDATA.
429
- */
430
- encodeSrvRdata(priority, weight, port, target) {
431
- const fixed = Buffer.alloc(6);
432
- fixed.writeUInt16BE(priority, 0);
433
- fixed.writeUInt16BE(weight, 2);
434
- fixed.writeUInt16BE(port, 4);
435
- return Buffer.concat([fixed, this.encodeDnsName(target)]);
436
- }
437
- /**
438
- * Encodes an IPv4 address for an A record RDATA (4 bytes).
439
- *
440
- * @param {string} ipv4 - IPv4 address, e.g. "192.168.1.10".
441
- * @returns {Buffer} 4-byte buffer.
442
- * @throws {Error} If the address is not a valid dotted-quad.
443
- */
444
- encodeA(ipv4) {
445
- const parts = ipv4.split('.').map((p) => Number(p));
446
- if (parts.length !== 4 || parts.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) {
447
- throw new Error(`Invalid IPv4 address: ${ipv4}`);
448
- }
449
- return Buffer.from(parts);
450
- }
451
- /**
452
- * Encodes an IPv6 address for an AAAA record RDATA (16 bytes).
453
- *
454
- * Supports the "::" zero-compression form and ignores an optional scope id
455
- * suffix (e.g. "fe80::1%12" or "fe80::1%eth0").
456
- *
457
- * @param {string} ipv6WithOptionalScope - IPv6 address (optionally with scope id).
458
- * @returns {Buffer} 16-byte buffer.
459
- * @throws {Error} If the address is not a valid IPv6 literal.
460
- */
461
- encodeAAAA(ipv6WithOptionalScope) {
462
- const ipv6 = ipv6WithOptionalScope.split('%')[0];
463
- // Expand IPv6 to 8 groups of 16-bit words.
464
- const [left, right] = ipv6.split('::');
465
- const leftParts = left ? left.split(':').filter(Boolean) : [];
466
- const rightParts = right ? right.split(':').filter(Boolean) : [];
467
- if (ipv6.includes('::')) {
468
- const missing = 8 - (leftParts.length + rightParts.length);
469
- if (missing < 0)
470
- throw new Error(`Invalid IPv6 address: ${ipv6WithOptionalScope}`);
471
- const groups = [...leftParts, ...Array(missing).fill('0'), ...rightParts];
472
- return Buffer.from(groups.flatMap((g) => {
473
- const word = parseInt(g, 16);
474
- if (!Number.isFinite(word) || word < 0 || word > 0xffff) {
475
- throw new Error(`Invalid IPv6 group: ${g}`);
476
- }
477
- return [(word >> 8) & 0xff, word & 0xff];
478
- }));
479
- }
480
- const groups = ipv6.split(':');
481
- if (groups.length !== 8)
482
- throw new Error(`Invalid IPv6 address: ${ipv6WithOptionalScope}`);
483
- return Buffer.from(groups.flatMap((g) => {
484
- if (!g)
485
- throw new Error(`Invalid IPv6 group: ${g}`);
486
- const word = parseInt(g, 16);
487
- if (!Number.isFinite(word) || word < 0 || word > 0xffff)
488
- throw new Error(`Invalid IPv6 group: ${g}`);
489
- return [(word >> 8) & 0xff, word & 0xff];
490
- }));
491
- }
492
- /**
493
- * Decodes a DNS resource record.
494
- *
495
- * @param {Buffer} msg - The full mDNS message buffer.
496
- * @param {number} offset - The offset at which the resource record starts.
497
- * @returns {{ record: MdnsRecord; newOffset: number }} An object containing the decoded record and the new offset.
498
- */
499
- decodeResourceRecord(msg, offset) {
500
- // Decode the NAME field (which may be compressed)
501
- const nameResult = this.decodeDnsName(msg, offset);
502
- const name = nameResult.name;
503
- offset = nameResult.newOffset;
504
- // Read TYPE (16 bits), CLASS (16 bits), TTL (32 bits), and RDLENGTH (16 bits)
505
- const type = msg.readUInt16BE(offset);
506
- offset += 2;
507
- const rrclass = msg.readUInt16BE(offset);
508
- offset += 2;
509
- const ttl = msg.readUInt32BE(offset);
510
- offset += 4;
511
- const rdlength = msg.readUInt16BE(offset);
512
- offset += 2;
513
- let data = '';
514
- if (type === 12 /* DnsRecordType.PTR */) {
515
- // PTR record (type 12): decode its RDATA as a domain name.
516
- const ptrResult = this.decodeDnsName(msg, offset);
517
- data = ptrResult.name;
518
- offset += rdlength;
519
- }
520
- else if (type === 16 /* DnsRecordType.TXT */) {
521
- // TXT record: may consist of one or more length-prefixed strings.
522
- const txtStrings = [];
523
- const end = offset + rdlength;
524
- while (offset < end) {
525
- const txtLen = msg[offset];
526
- offset++;
527
- const txt = msg.slice(offset, offset + txtLen).toString('utf8');
528
- txtStrings.push(txt);
529
- offset += txtLen;
530
- }
531
- data = txtStrings.join(', ');
532
- }
533
- else if (type === 33 /* DnsRecordType.SRV */) {
534
- // SRV record (type === 33): consists of 2 bytes for priority, 2 for weight, 2 for port, followed by the target domain name.
535
- const priority = msg.readUInt16BE(offset);
536
- const weight = msg.readUInt16BE(offset + 2);
537
- const port = msg.readUInt16BE(offset + 4);
538
- offset += 6;
539
- const srvTargetResult = this.decodeDnsName(msg, offset);
540
- data = JSON.stringify({
541
- priority,
542
- weight,
543
- port,
544
- target: srvTargetResult.name,
545
- });
546
- offset = srvTargetResult.newOffset;
547
- }
548
- else if (type === 1 /* DnsRecordType.A */) {
549
- // A record (type 1): an IPv4 address stored in 4 bytes.
550
- const ipBytes = msg.slice(offset, offset + 4);
551
- data = Array.from(ipBytes).join('.');
552
- offset += 4;
553
- }
554
- else if (type === 28 /* DnsRecordType.AAAA */) {
555
- // AAAA record (type 28): IPv6 address stored in 16 bytes.
556
- const ipBytes = msg.slice(offset, offset + 16);
557
- // Convert the 16 bytes into an IPv6 address string (colon-separated)
558
- const ipv6Parts = [];
559
- for (let i = 0; i < 16; i += 2) {
560
- ipv6Parts.push(ipBytes.readUInt16BE(i).toString(16));
561
- }
562
- data = ipv6Parts.join(':');
563
- offset += 16;
564
- }
565
- else if (type === 47 /* DnsRecordType.NSEC */) {
566
- // NSEC record: RDATA consists of:
567
- // - Next Domain Name (in DNS label format)
568
- // - Type Bit Maps (variable length)
569
- const { name: nextDomain, newOffset } = this.decodeDnsName(msg, offset);
570
- const nextDomainLength = newOffset - offset;
571
- offset = newOffset;
572
- // Calculate the remaining length for the type bit maps.
573
- const bitmapLength = rdlength - nextDomainLength;
574
- const bitmapData = msg.slice(offset, offset + bitmapLength);
575
- const types = [];
576
- let bitmapOffset = 0;
577
- while (bitmapOffset < bitmapData.length) {
578
- const windowBlock = bitmapData[bitmapOffset];
579
- const windowLength = bitmapData[bitmapOffset + 1];
580
- bitmapOffset += 2;
581
- for (let i = 0; i < windowLength; i++) {
582
- const octet = bitmapData[bitmapOffset + i];
583
- for (let bit = 0; bit < 8; bit++) {
584
- if (octet & (0x80 >> bit)) {
585
- const typeCode = windowBlock * 256 + i * 8 + bit;
586
- types.push(this.dnsTypeToString(typeCode));
587
- }
588
- }
589
- }
590
- bitmapOffset += windowLength;
591
- }
592
- data = JSON.stringify({
593
- nextDomain,
594
- types,
595
- });
596
- offset += bitmapLength;
597
- }
598
- else {
599
- // Fall back
600
- data = msg.slice(offset, offset + rdlength).toString('hex');
601
- offset += rdlength;
602
- }
603
- return {
604
- record: { name, type, class: rrclass, ttl, data },
605
- newOffset: offset,
606
- };
607
- }
608
- /**
609
- * Sends a DNS query with multiple questions.
610
- *
611
- * @param {Array<{ name: string; type: number; class: number; unicastResponse?: boolean }>} questions - Array of questions
612
- * to include in the query.
613
- * @returns {Buffer<ArrayBuffer>} The constructed query buffer.
614
- *
615
- * @remarks
616
- * Each question should have a name (e.g., "_http._tcp.local"), type (e.g., DnsRecordType.PTR), class (e.g., DnsClass.IN),
617
- * and an optional unicastResponse flag (this will add the DnsClassFlag.QU flag to the query).
618
- */
619
- sendQuery(questions) {
620
- const header = Buffer.alloc(12);
621
- header.writeUInt16BE(0, 0); // ID
622
- header.writeUInt16BE(0, 2); // Flags
623
- header.writeUInt16BE(questions.length, 4); // QDCOUNT
624
- header.writeUInt16BE(0, 6); // ANCOUNT
625
- header.writeUInt16BE(0, 8); // NSCOUNT
626
- header.writeUInt16BE(0, 10); // ARCOUNT
627
- const questionBuffers = questions.map(({ name, type: qtype, class: qclass, unicastResponse = false }) => {
628
- const qname = this.encodeDnsName(name);
629
- const qfields = Buffer.alloc(4);
630
- qfields.writeUInt16BE(qtype, 0);
631
- qfields.writeUInt16BE(unicastResponse ? qclass | 32768 /* DnsClassFlag.QU */ : qclass, 2);
632
- return Buffer.concat([qname, qfields]);
633
- });
634
- const query = Buffer.concat([header, ...questionBuffers]);
635
- if (hasParameter('v') || hasParameter('verbose')) {
636
- const decoded = this.decodeMdnsMessage(query);
637
- this.logMdnsMessage(decoded, undefined, 'Sending query mDNS message');
638
- }
639
- this.socket.send(query, 0, query.length, this.multicastPort, this.multicastAddress, (error) => {
640
- if (error) {
641
- this.log.error(`Dgram mDNS server failed to send query message: ${error instanceof Error ? error.message : error}`);
642
- this.emit('error', error);
643
- }
644
- else {
645
- this.log.debug(`Dgram mDNS server sent query message`);
646
- this.emit('sent', query, this.multicastAddress, this.multicastPort);
647
- }
648
- });
649
- return query;
650
- }
651
- /**
652
- * Constructs an mDNS response packet and sends it to the multicast address and port.
653
- *
654
- * @param {Array<{ name: string; rtype: number; rclass: number; ttl: number; rdata: Buffer }>} answers - Array of answer records.
655
- * @returns {Buffer<ArrayBuffer>} The constructed response buffer.
656
- *
657
- * @example
658
- * const ptrRdata = mdnsIpv4.encodeDnsName('matterbridge._http._tcp.local');
659
- * mdnsIpv4.sendResponse([{ name: '_http._tcp.local', rtype: DnsRecordType.PTR, rclass: DnsClass.IN, ttl: 120, rdata: ptrRdata }]);
660
- */
661
- sendResponse(answers) {
662
- if (!Array.isArray(answers) || answers.length === 0) {
663
- throw new Error('sendResponse requires a non-empty answers array');
664
- }
665
- // Create a 12-byte DNS header.
666
- const header = Buffer.alloc(12);
667
- header.writeUInt16BE(0, 0); // ID is set to 0 in mDNS.
668
- // Set flags: QR (response) bit and AA (authoritative answer) bit.
669
- header.writeUInt16BE(0x8400, 2);
670
- header.writeUInt16BE(0, 4); // QDCOUNT: 0 questions in response.
671
- header.writeUInt16BE(answers.length, 6); // ANCOUNT: number of answer records.
672
- header.writeUInt16BE(0, 8); // NSCOUNT: 0 authority records.
673
- header.writeUInt16BE(0, 10); // ARCOUNT: 0 additional records.
674
- const answerBuffers = answers.map(({ name, rtype, rclass, ttl, rdata }) => {
675
- // Encode the domain name in DNS label format.
676
- const aname = this.encodeDnsName(name);
677
- // Prepare the fixed part of the answer record:
678
- // - 2 bytes for qtype,
679
- // - 2 bytes for qclass,
680
- // - 4 bytes for TTL,
681
- // - 2 bytes for RDLENGTH (length of the rdata).
682
- const answerFixed = Buffer.alloc(10);
683
- answerFixed.writeUInt16BE(rtype, 0); // Record type.
684
- answerFixed.writeUInt16BE(rclass, 2); // Record class.
685
- answerFixed.writeUInt32BE(ttl, 4); // Time-to-live.
686
- answerFixed.writeUInt16BE(rdata.length, 8); // RDLENGTH.
687
- // Concatenate the answer: encoded name, fixed fields, and resource data.
688
- return Buffer.concat([aname, answerFixed, rdata]);
689
- });
690
- // Concatenate header and answers to form the complete mDNS response packet.
691
- const response = Buffer.concat([header, ...answerBuffers]);
692
- if (hasParameter('v') || hasParameter('verbose')) {
693
- const decoded = this.decodeMdnsMessage(response);
694
- this.logMdnsMessage(decoded, undefined, 'Sending response mDNS message');
695
- }
696
- // Send the response packet via the socket.
697
- this.socket.send(response, 0, response.length, this.multicastPort, this.multicastAddress, (error) => {
698
- if (error) {
699
- this.log.error(`Dgram mDNS server failed to send response message: ${error instanceof Error ? error.message : error}`);
700
- this.emit('error', error);
701
- }
702
- else {
703
- this.log.debug(`Dgram mDNS server sent response message`);
704
- this.emit('sent', response, this.multicastAddress, this.multicastPort);
705
- }
706
- });
707
- return response;
708
- }
709
- /**
710
- * Converts a DNS record type numeric value to its string representation.
711
- *
712
- * @param {number} type - The numeric DNS record type.
713
- * @returns {string} The string representation of the record type.
714
- */
715
- dnsTypeToString(type) {
716
- const typeMap = {
717
- [1 /* DnsRecordType.A */]: 'A',
718
- [2 /* DnsRecordType.NS */]: 'NS',
719
- [3 /* DnsRecordType.MD */]: 'MD',
720
- [4 /* DnsRecordType.MF */]: 'MF',
721
- [5 /* DnsRecordType.CNAME */]: 'CNAME',
722
- [6 /* DnsRecordType.SOA */]: 'SOA',
723
- [7 /* DnsRecordType.MB */]: 'MB',
724
- [8 /* DnsRecordType.MG */]: 'MG',
725
- [9 /* DnsRecordType.MR */]: 'MR',
726
- [10 /* DnsRecordType.NULL */]: 'NULL',
727
- [11 /* DnsRecordType.WKS */]: 'WKS',
728
- [12 /* DnsRecordType.PTR */]: 'PTR',
729
- [13 /* DnsRecordType.HINFO */]: 'HINFO',
730
- [14 /* DnsRecordType.MINFO */]: 'MINFO',
731
- [15 /* DnsRecordType.MX */]: 'MX',
732
- [16 /* DnsRecordType.TXT */]: 'TXT',
733
- [17 /* DnsRecordType.RP */]: 'RP',
734
- [18 /* DnsRecordType.AFSDB */]: 'AFSDB',
735
- [19 /* DnsRecordType.X25 */]: 'X25',
736
- [20 /* DnsRecordType.ISDN */]: 'ISDN',
737
- [21 /* DnsRecordType.RT */]: 'RT',
738
- [22 /* DnsRecordType.NSAP */]: 'NSAP',
739
- [23 /* DnsRecordType.NSAP_PTR */]: 'NSAP_PTR',
740
- [24 /* DnsRecordType.SIG */]: 'SIG',
741
- [25 /* DnsRecordType.KEY */]: 'KEY',
742
- [26 /* DnsRecordType.PX */]: 'PX',
743
- [27 /* DnsRecordType.GPOS */]: 'GPOS',
744
- [28 /* DnsRecordType.AAAA */]: 'AAAA',
745
- [29 /* DnsRecordType.LOC */]: 'LOC',
746
- [30 /* DnsRecordType.NXT */]: 'NXT',
747
- [31 /* DnsRecordType.EID */]: 'EID',
748
- [32 /* DnsRecordType.NIMLOC */]: 'NIMLOC',
749
- [33 /* DnsRecordType.SRV */]: 'SRV',
750
- [34 /* DnsRecordType.ATMA */]: 'ATMA',
751
- [35 /* DnsRecordType.NAPTR */]: 'NAPTR',
752
- [36 /* DnsRecordType.KX */]: 'KX',
753
- [37 /* DnsRecordType.CERT */]: 'CERT',
754
- [38 /* DnsRecordType.A6 */]: 'A6',
755
- [39 /* DnsRecordType.DNAME */]: 'DNAME',
756
- [40 /* DnsRecordType.SINK */]: 'SINK',
757
- [41 /* DnsRecordType.OPT */]: 'OPT',
758
- [42 /* DnsRecordType.APL */]: 'APL',
759
- [43 /* DnsRecordType.DS */]: 'DS',
760
- [44 /* DnsRecordType.SSHFP */]: 'SSHFP',
761
- [45 /* DnsRecordType.IPSECKEY */]: 'IPSECKEY',
762
- [46 /* DnsRecordType.RRSIG */]: 'RRSIG',
763
- [47 /* DnsRecordType.NSEC */]: 'NSEC',
764
- [48 /* DnsRecordType.DNSKEY */]: 'DNSKEY',
765
- [49 /* DnsRecordType.DHCID */]: 'DHCID',
766
- [50 /* DnsRecordType.NSEC3 */]: 'NSEC3',
767
- [51 /* DnsRecordType.NSEC3PARAM */]: 'NSEC3PARAM',
768
- [52 /* DnsRecordType.TLSA */]: 'TLSA',
769
- [53 /* DnsRecordType.SMIMEA */]: 'SMIMEA',
770
- [55 /* DnsRecordType.HIP */]: 'HIP',
771
- [56 /* DnsRecordType.NINFO */]: 'NINFO',
772
- [57 /* DnsRecordType.RKEY */]: 'RKEY',
773
- [58 /* DnsRecordType.TALINK */]: 'TALINK',
774
- [59 /* DnsRecordType.CDS */]: 'CDS',
775
- [60 /* DnsRecordType.CDNSKEY */]: 'CDNSKEY',
776
- [61 /* DnsRecordType.OPENPGPKEY */]: 'OPENPGPKEY',
777
- [62 /* DnsRecordType.CSYNC */]: 'CSYNC',
778
- [63 /* DnsRecordType.ZONEMD */]: 'ZONEMD',
779
- [64 /* DnsRecordType.SVCB */]: 'SVCB',
780
- [65 /* DnsRecordType.HTTPS */]: 'HTTPS',
781
- [99 /* DnsRecordType.SPF */]: 'SPF',
782
- [100 /* DnsRecordType.UINFO */]: 'UINFO',
783
- [101 /* DnsRecordType.UID */]: 'UID',
784
- [102 /* DnsRecordType.GID */]: 'GID',
785
- [103 /* DnsRecordType.UNSPEC */]: 'UNSPEC',
786
- [104 /* DnsRecordType.NID */]: 'NID',
787
- [105 /* DnsRecordType.L32 */]: 'L32',
788
- [106 /* DnsRecordType.L64 */]: 'L64',
789
- [107 /* DnsRecordType.LP */]: 'LP',
790
- [108 /* DnsRecordType.EUI48 */]: 'EUI48',
791
- [109 /* DnsRecordType.EUI64 */]: 'EUI64',
792
- [249 /* DnsRecordType.TKEY */]: 'TKEY',
793
- [250 /* DnsRecordType.TSIG */]: 'TSIG',
794
- [251 /* DnsRecordType.IXFR */]: 'IXFR',
795
- [252 /* DnsRecordType.AXFR */]: 'AXFR',
796
- [253 /* DnsRecordType.MAILB */]: 'MAILB',
797
- [254 /* DnsRecordType.MAILA */]: 'MAILA',
798
- [255 /* DnsRecordType.ANY */]: 'ANY',
799
- [256 /* DnsRecordType.URI */]: 'URI',
800
- [257 /* DnsRecordType.CAA */]: 'CAA',
801
- [258 /* DnsRecordType.AVC */]: 'AVC',
802
- [259 /* DnsRecordType.DOA */]: 'DOA',
803
- [260 /* DnsRecordType.AMTRELAY */]: 'AMTRELAY',
804
- [261 /* DnsRecordType.ZONEVERSION */]: 'ZONEVERSION',
805
- [32768 /* DnsRecordType.TA */]: 'TA',
806
- [32769 /* DnsRecordType.DLV */]: 'DLV',
807
- };
808
- return typeMap[type] ?? `TYPE${type}`;
809
- }
810
- /**
811
- * Converts a DNS response class numeric value to its string representation.
812
- *
813
- * @param {number} cls - The numeric DNS class.
814
- * @returns {string} The string representation of the DNS class.
815
- */
816
- dnsResponseClassToString(cls) {
817
- const isFlush = !!(cls & 32768 /* DnsClassFlag.FLUSH */);
818
- const baseClass = cls & 0x7fff;
819
- let classStr;
820
- switch (baseClass) {
821
- case 1 /* DnsClass.IN */:
822
- classStr = 'IN';
823
- break;
824
- case 3 /* DnsClass.CH */:
825
- classStr = 'CH';
826
- break;
827
- case 4 /* DnsClass.HS */:
828
- classStr = 'HS';
829
- break;
830
- case 255 /* DnsClass.ANY */:
831
- classStr = 'ANY';
832
- break;
833
- default:
834
- classStr = `CLASS${baseClass}`;
835
- }
836
- return isFlush ? `${classStr}|FLUSH` : classStr;
837
- }
838
- /**
839
- * Converts a DNS question class to a human-readable string.
840
- * Adds support for mDNS QU (unicast-response) bit.
841
- *
842
- * @param {number} cls - The numeric question class.
843
- * @returns {string} The string representation, e.g. "IN|QU"
844
- */
845
- dnsQuestionClassToString(cls) {
846
- const isQU = !!(cls & 32768 /* DnsClassFlag.QU */);
847
- const baseClass = cls & 0x7fff;
848
- let classStr;
849
- switch (baseClass) {
850
- case 1 /* DnsClass.IN */:
851
- classStr = 'IN';
852
- break;
853
- case 3 /* DnsClass.CH */:
854
- classStr = 'CH';
855
- break;
856
- case 4 /* DnsClass.HS */:
857
- classStr = 'HS';
858
- break;
859
- case 255 /* DnsClass.ANY */:
860
- classStr = 'ANY';
861
- break;
862
- default:
863
- classStr = `CLASS${baseClass}`;
864
- }
865
- return isQU ? `${classStr}|QU` : classStr;
866
- }
867
- /**
868
- * Logs the decoded mDNS message header.
869
- *
870
- * @param {MdnsMessage} msg - The mDNS message header object.
871
- * @param {AnsiLogger} [log] - The logger to use (defaults to this.log).
872
- * @param {string} [text] - Optional additional text to include in the log.
873
- */
874
- logMdnsMessage(msg, log = this.log, text = 'Decoded mDNS message') {
875
- 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}`);
876
- msg.questions?.forEach((question) => {
877
- log.info(`Question: ${CYAN}${question.name}${nf} type ${idn}${this.dnsTypeToString(question.type)}${rs}${nf} class ${CYAN}${this.dnsQuestionClassToString(question.class)}${nf}`);
878
- });
879
- msg.answers?.forEach((answer) => {
880
- 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}`);
881
- });
882
- msg.authorities?.forEach((authority) => {
883
- 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}`);
884
- });
885
- msg.additionals?.forEach((additional) => {
886
- 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}`);
887
- });
888
- log.info(`---\n`);
889
- }
890
- /**
891
- * Logs the discovered devices from the mDNS queries and responses.
892
- */
893
- logDevices() {
894
- this.log.info(`Discovered query devices: ${MAGENTA}${this.deviceQueries.size}${nf}`);
895
- // Collect devices into an array
896
- const deviceQueryArray = Array.from(this.deviceQueries.entries());
897
- // Sort the array by numeric value of the IP address
898
- deviceQueryArray.sort(([addressA], [addressB]) => {
899
- const partsA = addressA.split('.').map(Number);
900
- const partsB = addressB.split('.').map(Number);
901
- for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
902
- const diff = (partsA[i] || 0) - (partsB[i] || 0);
903
- if (diff !== 0)
904
- return diff;
905
- }
906
- // istanbul ignore next
907
- return 0;
908
- });
909
- // Log the sorted devices
910
- deviceQueryArray.forEach(([rinfo, response]) => {
911
- this.log.info(`- ${MAGENTA}${rinfo}${nf} family ${BLUE}${response.rinfo.family}${nf} address ${BLUE}${response.rinfo.address}${nf} port ${BLUE}${response.rinfo.port}${nf}`);
912
- });
913
- this.log.info(`Discovered response devices: ${MAGENTA}${this.deviceResponses.size}${nf}`);
914
- // Collect devices into an array
915
- const deviceResponseArray = Array.from(this.deviceResponses.entries());
916
- // Sort the array by numeric value of the IP address
917
- deviceResponseArray.sort(([addressA], [addressB]) => {
918
- const partsA = addressA.split(/[:.]/).map((part) => parseInt(part, 16));
919
- const partsB = addressB.split(/[:.]/).map((part) => parseInt(part, 16));
920
- for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
921
- const diff = (partsA[i] || 0) - (partsB[i] || 0);
922
- if (diff !== 0)
923
- return diff;
924
- }
925
- // istanbul ignore next
926
- return 0;
927
- });
928
- // Log the sorted devices
929
- deviceResponseArray.forEach(([rinfo, response]) => {
930
- 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}`);
931
- });
932
- }
933
- }
934
- //# sourceMappingURL=mdns.js.map