matterbridge 3.4.7 → 3.5.0-dev-20260113-29ad318
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 +10 -0
- package/dist/broadcastServer.d.ts +0 -115
- package/dist/broadcastServer.js +0 -117
- package/dist/broadcastServerTypes.d.ts +0 -43
- package/dist/broadcastServerTypes.js +0 -24
- package/dist/cli.d.ts +0 -24
- package/dist/cli.js +1 -97
- package/dist/cliEmitter.d.ts +0 -36
- package/dist/cliEmitter.js +0 -37
- package/dist/cliHistory.d.ts +0 -42
- package/dist/cliHistory.js +0 -38
- package/dist/clusters/export.d.ts +0 -1
- package/dist/clusters/export.js +0 -2
- package/dist/deviceManager.d.ts +0 -108
- package/dist/deviceManager.js +1 -113
- package/dist/devices/airConditioner.d.ts +0 -75
- package/dist/devices/airConditioner.js +0 -57
- package/dist/devices/batteryStorage.d.ts +0 -43
- package/dist/devices/batteryStorage.js +1 -48
- package/dist/devices/cooktop.d.ts +0 -55
- package/dist/devices/cooktop.js +0 -56
- package/dist/devices/dishwasher.d.ts +0 -55
- package/dist/devices/dishwasher.js +0 -57
- package/dist/devices/evse.d.ts +0 -57
- package/dist/devices/evse.js +10 -74
- package/dist/devices/export.d.ts +0 -1
- package/dist/devices/export.js +0 -5
- package/dist/devices/extractorHood.d.ts +0 -41
- package/dist/devices/extractorHood.js +0 -43
- package/dist/devices/heatPump.d.ts +0 -43
- package/dist/devices/heatPump.js +2 -50
- package/dist/devices/laundryDryer.d.ts +0 -58
- package/dist/devices/laundryDryer.js +3 -62
- package/dist/devices/laundryWasher.d.ts +0 -64
- package/dist/devices/laundryWasher.js +4 -70
- package/dist/devices/microwaveOven.d.ts +1 -77
- package/dist/devices/microwaveOven.js +5 -88
- package/dist/devices/oven.d.ts +0 -82
- package/dist/devices/oven.js +0 -85
- package/dist/devices/refrigerator.d.ts +0 -100
- package/dist/devices/refrigerator.js +0 -102
- package/dist/devices/roboticVacuumCleaner.d.ts +0 -83
- package/dist/devices/roboticVacuumCleaner.js +9 -100
- package/dist/devices/solarPower.d.ts +0 -36
- package/dist/devices/solarPower.js +0 -38
- package/dist/devices/speaker.d.ts +0 -79
- package/dist/devices/speaker.js +0 -84
- package/dist/devices/temperatureControl.d.ts +0 -21
- package/dist/devices/temperatureControl.js +3 -24
- package/dist/devices/waterHeater.d.ts +0 -74
- package/dist/devices/waterHeater.js +2 -82
- package/dist/dgram/coap.d.ts +0 -171
- package/dist/dgram/coap.js +13 -126
- package/dist/dgram/dgram.d.ts +0 -99
- package/dist/dgram/dgram.js +2 -114
- package/dist/dgram/mb_coap.d.ts +0 -23
- package/dist/dgram/mb_coap.js +3 -41
- package/dist/dgram/mb_mdns.d.ts +0 -23
- package/dist/dgram/mb_mdns.js +24 -80
- package/dist/dgram/mdns.d.ts +4 -187
- package/dist/dgram/mdns.js +139 -371
- package/dist/dgram/multicast.d.ts +0 -49
- package/dist/dgram/multicast.js +1 -62
- package/dist/dgram/unicast.d.ts +0 -53
- package/dist/dgram/unicast.js +0 -60
- package/dist/frontend.d.ts +0 -187
- package/dist/frontend.js +38 -485
- package/dist/frontendTypes.d.ts +0 -57
- package/dist/frontendTypes.js +0 -45
- package/dist/helpers.d.ts +0 -43
- package/dist/helpers.js +0 -53
- package/dist/index.d.ts +0 -23
- package/dist/index.js +0 -25
- package/dist/jestutils/export.d.ts +0 -1
- package/dist/jestutils/export.js +0 -1
- package/dist/jestutils/jestHelpers.d.ts +0 -255
- package/dist/jestutils/jestHelpers.js +14 -371
- package/dist/logger/export.d.ts +0 -1
- package/dist/logger/export.js +0 -1
- package/dist/matter/behaviors.d.ts +0 -1
- package/dist/matter/behaviors.js +0 -2
- package/dist/matter/clusters.d.ts +0 -1
- package/dist/matter/clusters.js +0 -2
- package/dist/matter/devices.d.ts +0 -1
- package/dist/matter/devices.js +0 -2
- package/dist/matter/endpoints.d.ts +0 -1
- package/dist/matter/endpoints.js +0 -2
- package/dist/matter/export.d.ts +0 -1
- package/dist/matter/export.js +0 -3
- package/dist/matter/types.d.ts +0 -1
- package/dist/matter/types.js +0 -3
- package/dist/matterNode.d.ts +0 -258
- package/dist/matterNode.js +8 -369
- package/dist/matterbridge.d.ts +0 -353
- package/dist/matterbridge.js +46 -824
- package/dist/matterbridgeAccessoryPlatform.d.ts +0 -36
- package/dist/matterbridgeAccessoryPlatform.js +0 -38
- package/dist/matterbridgeBehaviors.d.ts +0 -24
- package/dist/matterbridgeBehaviors.js +5 -68
- package/dist/matterbridgeDeviceTypes.d.ts +0 -603
- package/dist/matterbridgeDeviceTypes.js +14 -635
- package/dist/matterbridgeDynamicPlatform.d.ts +0 -36
- package/dist/matterbridgeDynamicPlatform.js +0 -38
- package/dist/matterbridgeEndpoint.d.ts +0 -1332
- package/dist/matterbridgeEndpoint.js +53 -1457
- package/dist/matterbridgeEndpointHelpers.d.ts +0 -425
- package/dist/matterbridgeEndpointHelpers.js +20 -483
- package/dist/matterbridgeEndpointTypes.d.ts +0 -70
- package/dist/matterbridgeEndpointTypes.js +0 -25
- package/dist/matterbridgePlatform.d.ts +0 -425
- package/dist/matterbridgePlatform.js +1 -451
- package/dist/matterbridgeTypes.d.ts +0 -46
- package/dist/matterbridgeTypes.js +0 -26
- package/dist/pluginManager.d.ts +0 -305
- package/dist/pluginManager.js +5 -341
- package/dist/shelly.d.ts +0 -157
- package/dist/shelly.js +7 -178
- package/dist/storage/export.d.ts +0 -1
- package/dist/storage/export.js +0 -1
- package/dist/update.d.ts +0 -75
- package/dist/update.js +1 -93
- package/dist/utils/colorUtils.d.ts +0 -77
- package/dist/utils/colorUtils.js +2 -97
- package/dist/utils/commandLine.d.ts +0 -60
- package/dist/utils/commandLine.js +0 -60
- package/dist/utils/copyDirectory.d.ts +0 -33
- package/dist/utils/copyDirectory.js +0 -37
- package/dist/utils/createDirectory.d.ts +0 -32
- package/dist/utils/createDirectory.js +0 -33
- package/dist/utils/createZip.d.ts +0 -38
- package/dist/utils/createZip.js +2 -47
- package/dist/utils/deepCopy.d.ts +0 -31
- package/dist/utils/deepCopy.js +0 -39
- package/dist/utils/deepEqual.d.ts +0 -53
- package/dist/utils/deepEqual.js +1 -72
- package/dist/utils/error.d.ts +0 -42
- package/dist/utils/error.js +0 -42
- package/dist/utils/export.d.ts +0 -1
- package/dist/utils/export.js +0 -1
- package/dist/utils/format.d.ts +0 -49
- package/dist/utils/format.js +0 -49
- package/dist/utils/hex.d.ts +0 -85
- package/dist/utils/hex.js +0 -124
- package/dist/utils/inspector.d.ts +0 -63
- package/dist/utils/inspector.js +1 -69
- package/dist/utils/isValid.d.ts +0 -93
- package/dist/utils/isValid.js +0 -93
- package/dist/utils/network.d.ts +0 -116
- package/dist/utils/network.js +5 -126
- package/dist/utils/spawn.d.ts +0 -32
- package/dist/utils/spawn.js +1 -71
- package/dist/utils/tracker.d.ts +0 -56
- package/dist/utils/tracker.js +1 -64
- package/dist/utils/wait.d.ts +0 -51
- package/dist/utils/wait.js +8 -60
- package/dist/workerGlobalPrefix.d.ts +0 -24
- package/dist/workerGlobalPrefix.js +5 -37
- package/dist/workerTypes.d.ts +0 -25
- package/dist/workerTypes.js +0 -24
- package/dist/workers.d.ts +0 -61
- package/dist/workers.js +4 -68
- package/npm-shrinkwrap.json +1500 -11420
- package/package.json +10 -7
- package/dist/broadcastServer.d.ts.map +0 -1
- package/dist/broadcastServer.js.map +0 -1
- package/dist/broadcastServerTypes.d.ts.map +0 -1
- package/dist/broadcastServerTypes.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/cliEmitter.d.ts.map +0 -1
- package/dist/cliEmitter.js.map +0 -1
- package/dist/cliHistory.d.ts.map +0 -1
- package/dist/cliHistory.js.map +0 -1
- package/dist/clusters/export.d.ts.map +0 -1
- package/dist/clusters/export.js.map +0 -1
- package/dist/deviceManager.d.ts.map +0 -1
- package/dist/deviceManager.js.map +0 -1
- package/dist/devices/airConditioner.d.ts.map +0 -1
- package/dist/devices/airConditioner.js.map +0 -1
- package/dist/devices/batteryStorage.d.ts.map +0 -1
- package/dist/devices/batteryStorage.js.map +0 -1
- package/dist/devices/cooktop.d.ts.map +0 -1
- package/dist/devices/cooktop.js.map +0 -1
- package/dist/devices/dishwasher.d.ts.map +0 -1
- package/dist/devices/dishwasher.js.map +0 -1
- package/dist/devices/evse.d.ts.map +0 -1
- package/dist/devices/evse.js.map +0 -1
- package/dist/devices/export.d.ts.map +0 -1
- package/dist/devices/export.js.map +0 -1
- package/dist/devices/extractorHood.d.ts.map +0 -1
- package/dist/devices/extractorHood.js.map +0 -1
- package/dist/devices/heatPump.d.ts.map +0 -1
- package/dist/devices/heatPump.js.map +0 -1
- package/dist/devices/laundryDryer.d.ts.map +0 -1
- package/dist/devices/laundryDryer.js.map +0 -1
- package/dist/devices/laundryWasher.d.ts.map +0 -1
- package/dist/devices/laundryWasher.js.map +0 -1
- package/dist/devices/microwaveOven.d.ts.map +0 -1
- package/dist/devices/microwaveOven.js.map +0 -1
- package/dist/devices/oven.d.ts.map +0 -1
- package/dist/devices/oven.js.map +0 -1
- package/dist/devices/refrigerator.d.ts.map +0 -1
- package/dist/devices/refrigerator.js.map +0 -1
- package/dist/devices/roboticVacuumCleaner.d.ts.map +0 -1
- package/dist/devices/roboticVacuumCleaner.js.map +0 -1
- package/dist/devices/solarPower.d.ts.map +0 -1
- package/dist/devices/solarPower.js.map +0 -1
- package/dist/devices/speaker.d.ts.map +0 -1
- package/dist/devices/speaker.js.map +0 -1
- package/dist/devices/temperatureControl.d.ts.map +0 -1
- package/dist/devices/temperatureControl.js.map +0 -1
- package/dist/devices/waterHeater.d.ts.map +0 -1
- package/dist/devices/waterHeater.js.map +0 -1
- package/dist/dgram/coap.d.ts.map +0 -1
- package/dist/dgram/coap.js.map +0 -1
- package/dist/dgram/dgram.d.ts.map +0 -1
- package/dist/dgram/dgram.js.map +0 -1
- package/dist/dgram/mb_coap.d.ts.map +0 -1
- package/dist/dgram/mb_coap.js.map +0 -1
- package/dist/dgram/mb_mdns.d.ts.map +0 -1
- package/dist/dgram/mb_mdns.js.map +0 -1
- package/dist/dgram/mdns.d.ts.map +0 -1
- package/dist/dgram/mdns.js.map +0 -1
- package/dist/dgram/multicast.d.ts.map +0 -1
- package/dist/dgram/multicast.js.map +0 -1
- package/dist/dgram/unicast.d.ts.map +0 -1
- package/dist/dgram/unicast.js.map +0 -1
- package/dist/frontend.d.ts.map +0 -1
- package/dist/frontend.js.map +0 -1
- package/dist/frontendTypes.d.ts.map +0 -1
- package/dist/frontendTypes.js.map +0 -1
- package/dist/helpers.d.ts.map +0 -1
- package/dist/helpers.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/jestutils/export.d.ts.map +0 -1
- package/dist/jestutils/export.js.map +0 -1
- package/dist/jestutils/jestHelpers.d.ts.map +0 -1
- package/dist/jestutils/jestHelpers.js.map +0 -1
- package/dist/logger/export.d.ts.map +0 -1
- package/dist/logger/export.js.map +0 -1
- package/dist/matter/behaviors.d.ts.map +0 -1
- package/dist/matter/behaviors.js.map +0 -1
- package/dist/matter/clusters.d.ts.map +0 -1
- package/dist/matter/clusters.js.map +0 -1
- package/dist/matter/devices.d.ts.map +0 -1
- package/dist/matter/devices.js.map +0 -1
- package/dist/matter/endpoints.d.ts.map +0 -1
- package/dist/matter/endpoints.js.map +0 -1
- package/dist/matter/export.d.ts.map +0 -1
- package/dist/matter/export.js.map +0 -1
- package/dist/matter/types.d.ts.map +0 -1
- package/dist/matter/types.js.map +0 -1
- package/dist/matterNode.d.ts.map +0 -1
- package/dist/matterNode.js.map +0 -1
- package/dist/matterbridge.d.ts.map +0 -1
- package/dist/matterbridge.js.map +0 -1
- package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
- package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
- package/dist/matterbridgeBehaviors.d.ts.map +0 -1
- package/dist/matterbridgeBehaviors.js.map +0 -1
- package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
- package/dist/matterbridgeDeviceTypes.js.map +0 -1
- package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
- package/dist/matterbridgeDynamicPlatform.js.map +0 -1
- package/dist/matterbridgeEndpoint.d.ts.map +0 -1
- package/dist/matterbridgeEndpoint.js.map +0 -1
- package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
- package/dist/matterbridgeEndpointHelpers.js.map +0 -1
- package/dist/matterbridgeEndpointTypes.d.ts.map +0 -1
- package/dist/matterbridgeEndpointTypes.js.map +0 -1
- package/dist/matterbridgePlatform.d.ts.map +0 -1
- package/dist/matterbridgePlatform.js.map +0 -1
- package/dist/matterbridgeTypes.d.ts.map +0 -1
- package/dist/matterbridgeTypes.js.map +0 -1
- package/dist/pluginManager.d.ts.map +0 -1
- package/dist/pluginManager.js.map +0 -1
- package/dist/shelly.d.ts.map +0 -1
- package/dist/shelly.js.map +0 -1
- package/dist/storage/export.d.ts.map +0 -1
- package/dist/storage/export.js.map +0 -1
- package/dist/update.d.ts.map +0 -1
- package/dist/update.js.map +0 -1
- package/dist/utils/colorUtils.d.ts.map +0 -1
- package/dist/utils/colorUtils.js.map +0 -1
- package/dist/utils/commandLine.d.ts.map +0 -1
- package/dist/utils/commandLine.js.map +0 -1
- package/dist/utils/copyDirectory.d.ts.map +0 -1
- package/dist/utils/copyDirectory.js.map +0 -1
- package/dist/utils/createDirectory.d.ts.map +0 -1
- package/dist/utils/createDirectory.js.map +0 -1
- package/dist/utils/createZip.d.ts.map +0 -1
- package/dist/utils/createZip.js.map +0 -1
- package/dist/utils/deepCopy.d.ts.map +0 -1
- package/dist/utils/deepCopy.js.map +0 -1
- package/dist/utils/deepEqual.d.ts.map +0 -1
- package/dist/utils/deepEqual.js.map +0 -1
- package/dist/utils/error.d.ts.map +0 -1
- package/dist/utils/error.js.map +0 -1
- package/dist/utils/export.d.ts.map +0 -1
- package/dist/utils/export.js.map +0 -1
- package/dist/utils/format.d.ts.map +0 -1
- package/dist/utils/format.js.map +0 -1
- package/dist/utils/hex.d.ts.map +0 -1
- package/dist/utils/hex.js.map +0 -1
- package/dist/utils/inspector.d.ts.map +0 -1
- package/dist/utils/inspector.js.map +0 -1
- package/dist/utils/isValid.d.ts.map +0 -1
- package/dist/utils/isValid.js.map +0 -1
- package/dist/utils/network.d.ts.map +0 -1
- package/dist/utils/network.js.map +0 -1
- package/dist/utils/spawn.d.ts.map +0 -1
- package/dist/utils/spawn.js.map +0 -1
- package/dist/utils/tracker.d.ts.map +0 -1
- package/dist/utils/tracker.js.map +0 -1
- package/dist/utils/wait.d.ts.map +0 -1
- package/dist/utils/wait.js.map +0 -1
- package/dist/workerGlobalPrefix.d.ts.map +0 -1
- package/dist/workerGlobalPrefix.js.map +0 -1
- package/dist/workerTypes.d.ts.map +0 -1
- package/dist/workerTypes.js.map +0 -1
- package/dist/workers.d.ts.map +0 -1
- package/dist/workers.js.map +0 -1
- package/frontend/index.html +0 -15
- package/frontend/package-lock.json +0 -7553
- package/packages/dgram/LICENSE +0 -202
- package/packages/dgram/dist/coap.d.ts +0 -205
- package/packages/dgram/dist/coap.d.ts.map +0 -1
- package/packages/dgram/dist/coap.js +0 -365
- package/packages/dgram/dist/coap.js.map +0 -1
- package/packages/dgram/dist/dgram.d.ts +0 -144
- package/packages/dgram/dist/dgram.d.ts.map +0 -1
- package/packages/dgram/dist/dgram.js +0 -367
- package/packages/dgram/dist/dgram.js.map +0 -1
- package/packages/dgram/dist/export.d.ts +0 -6
- package/packages/dgram/dist/export.d.ts.map +0 -1
- package/packages/dgram/dist/export.js +0 -6
- package/packages/dgram/dist/export.js.map +0 -1
- package/packages/dgram/dist/mdns.d.ts +0 -371
- package/packages/dgram/dist/mdns.d.ts.map +0 -1
- package/packages/dgram/dist/mdns.js +0 -934
- package/packages/dgram/dist/mdns.js.map +0 -1
- package/packages/dgram/dist/multicast.d.ts +0 -67
- package/packages/dgram/dist/multicast.d.ts.map +0 -1
- package/packages/dgram/dist/multicast.js +0 -180
- package/packages/dgram/dist/multicast.js.map +0 -1
- package/packages/dgram/dist/unicast.d.ts +0 -64
- package/packages/dgram/dist/unicast.d.ts.map +0 -1
- package/packages/dgram/dist/unicast.js +0 -100
- package/packages/dgram/dist/unicast.js.map +0 -1
- package/packages/dgram/package.json +0 -110
- package/packages/jest-utils/LICENSE +0 -202
- package/packages/jest-utils/dist/export.d.ts +0 -2
- package/packages/jest-utils/dist/export.d.ts.map +0 -1
- package/packages/jest-utils/dist/export.js +0 -2
- package/packages/jest-utils/dist/export.js.map +0 -1
- package/packages/jest-utils/dist/jestHelpers.d.ts +0 -77
- package/packages/jest-utils/dist/jestHelpers.d.ts.map +0 -1
- package/packages/jest-utils/dist/jestHelpers.js +0 -138
- package/packages/jest-utils/dist/jestHelpers.js.map +0 -1
- package/packages/jest-utils/package.json +0 -109
- package/packages/utils/LICENSE +0 -202
- package/packages/utils/dist/colorUtils.d.ts +0 -101
- package/packages/utils/dist/colorUtils.d.ts.map +0 -1
- package/packages/utils/dist/colorUtils.js +0 -282
- package/packages/utils/dist/colorUtils.js.map +0 -1
- package/packages/utils/dist/commandLine.d.ts +0 -66
- package/packages/utils/dist/commandLine.d.ts.map +0 -1
- package/packages/utils/dist/commandLine.js +0 -123
- package/packages/utils/dist/commandLine.js.map +0 -1
- package/packages/utils/dist/copyDirectory.d.ts +0 -35
- package/packages/utils/dist/copyDirectory.d.ts.map +0 -1
- package/packages/utils/dist/copyDirectory.js +0 -76
- package/packages/utils/dist/copyDirectory.js.map +0 -1
- package/packages/utils/dist/createDirectory.d.ts +0 -34
- package/packages/utils/dist/createDirectory.d.ts.map +0 -1
- package/packages/utils/dist/createDirectory.js +0 -54
- package/packages/utils/dist/createDirectory.js.map +0 -1
- package/packages/utils/dist/createZip.d.ts +0 -39
- package/packages/utils/dist/createZip.d.ts.map +0 -1
- package/packages/utils/dist/createZip.js +0 -114
- package/packages/utils/dist/createZip.js.map +0 -1
- package/packages/utils/dist/deepCopy.d.ts +0 -32
- package/packages/utils/dist/deepCopy.d.ts.map +0 -1
- package/packages/utils/dist/deepCopy.js +0 -79
- package/packages/utils/dist/deepCopy.js.map +0 -1
- package/packages/utils/dist/deepEqual.d.ts +0 -54
- package/packages/utils/dist/deepEqual.d.ts.map +0 -1
- package/packages/utils/dist/deepEqual.js +0 -130
- package/packages/utils/dist/deepEqual.js.map +0 -1
- package/packages/utils/dist/error.d.ts +0 -45
- package/packages/utils/dist/error.d.ts.map +0 -1
- package/packages/utils/dist/error.js +0 -54
- package/packages/utils/dist/error.js.map +0 -1
- package/packages/utils/dist/export.d.ts +0 -16
- package/packages/utils/dist/export.d.ts.map +0 -1
- package/packages/utils/dist/export.js +0 -16
- package/packages/utils/dist/export.js.map +0 -1
- package/packages/utils/dist/format.d.ts +0 -53
- package/packages/utils/dist/format.d.ts.map +0 -1
- package/packages/utils/dist/format.js +0 -78
- package/packages/utils/dist/format.js.map +0 -1
- package/packages/utils/dist/githubVersion.d.ts +0 -43
- package/packages/utils/dist/githubVersion.d.ts.map +0 -1
- package/packages/utils/dist/githubVersion.js +0 -70
- package/packages/utils/dist/githubVersion.js.map +0 -1
- package/packages/utils/dist/hex.d.ts +0 -89
- package/packages/utils/dist/hex.d.ts.map +0 -1
- package/packages/utils/dist/hex.js +0 -242
- package/packages/utils/dist/hex.js.map +0 -1
- package/packages/utils/dist/inspector.d.ts +0 -87
- package/packages/utils/dist/inspector.d.ts.map +0 -1
- package/packages/utils/dist/inspector.js +0 -268
- package/packages/utils/dist/inspector.js.map +0 -1
- package/packages/utils/dist/isValid.d.ts +0 -103
- package/packages/utils/dist/isValid.d.ts.map +0 -1
- package/packages/utils/dist/isValid.js +0 -162
- package/packages/utils/dist/isValid.js.map +0 -1
- package/packages/utils/dist/network.d.ts +0 -105
- package/packages/utils/dist/network.d.ts.map +0 -1
- package/packages/utils/dist/network.js +0 -201
- package/packages/utils/dist/network.js.map +0 -1
- package/packages/utils/dist/npmRoot.d.ts +0 -29
- package/packages/utils/dist/npmRoot.d.ts.map +0 -1
- package/packages/utils/dist/npmRoot.js +0 -41
- package/packages/utils/dist/npmRoot.js.map +0 -1
- package/packages/utils/dist/npmVersion.d.ts +0 -33
- package/packages/utils/dist/npmVersion.d.ts.map +0 -1
- package/packages/utils/dist/npmVersion.js +0 -76
- package/packages/utils/dist/npmVersion.js.map +0 -1
- package/packages/utils/dist/tracker.d.ts +0 -108
- package/packages/utils/dist/tracker.d.ts.map +0 -1
- package/packages/utils/dist/tracker.js +0 -264
- package/packages/utils/dist/tracker.js.map +0 -1
- package/packages/utils/dist/wait.d.ts +0 -54
- package/packages/utils/dist/wait.d.ts.map +0 -1
- package/packages/utils/dist/wait.js +0 -125
- package/packages/utils/dist/wait.js.map +0 -1
- package/packages/utils/package.json +0 -110
- package/packages/vitest-utils/LICENSE +0 -202
- package/packages/vitest-utils/dist/export.d.ts +0 -2
- package/packages/vitest-utils/dist/export.d.ts.map +0 -1
- package/packages/vitest-utils/dist/export.js +0 -2
- package/packages/vitest-utils/dist/export.js.map +0 -1
- package/packages/vitest-utils/dist/vitestHelpers.d.ts +0 -58
- package/packages/vitest-utils/dist/vitestHelpers.d.ts.map +0 -1
- package/packages/vitest-utils/dist/vitestHelpers.js +0 -119
- package/packages/vitest-utils/dist/vitestHelpers.js.map +0 -1
- package/packages/vitest-utils/package.json +0 -109
|
@@ -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 '@matterbridge/utils';
|
|
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
|