From 4800ca87ad31ec59c6eae0bac12a15d995808af7 Mon Sep 17 00:00:00 2001 From: Eike Ahmels Date: Thu, 19 May 2022 12:39:08 +0200 Subject: [PATCH 1/3] refactoring mdns request parsing mdns responses now doenst rely on the url starting with "elrs" and its not supporting multiple elrs answers in a response --- src/api/src/services/MulticastDns/index.ts | 171 +++++++++++---------- 1 file changed, 94 insertions(+), 77 deletions(-) diff --git a/src/api/src/services/MulticastDns/index.ts b/src/api/src/services/MulticastDns/index.ts index a35c55d4e..68d327249 100644 --- a/src/api/src/services/MulticastDns/index.ts +++ b/src/api/src/services/MulticastDns/index.ts @@ -1,6 +1,7 @@ import { Service } from 'typedi'; import * as http from 'http'; import makeMdns, { ResponsePacket } from 'multicast-dns'; +import { SrvAnswer, StringAnswer, TxtAnswer } from 'dns-packet'; import MulticastDnsInformation from '../../models/MulticastDnsInformation'; import { LoggerService } from '../../logger'; import MulticastDnsEventType from '../../models/enum/MulticastDnsEventType'; @@ -120,88 +121,104 @@ export default class MulticastDnsService { // check if any of the answers on the response have a name that starts with // 'elrs_', which indicates that it is an elers device - const isElrs = !!items.find((item: any) => item.name.startsWith('elrs_')); - - if (isElrs) { - const txtResponse: any = items.find((answer) => answer.type === 'TXT'); - - const aResponse: any = items.find((answer) => answer.type === 'A'); - - const srvResponse: any = items.find((answer) => answer.type === 'SRV'); + const txtResponses: TxtAnswer[] = items.filter( + (answer) => answer.type === 'TXT' + ) as TxtAnswer[]; + + txtResponses.forEach((item) => { + let options: UserDefine[] = []; + let version = ''; + let target = ''; + let type = ''; + let vendor = ''; + let deviceName = ''; + + if (Array.isArray(item.data)) { + item.data.forEach((i) => { + if (i instanceof Buffer) { + const dataItem = i.toString('utf-8'); + const delimPos = dataItem.indexOf('='); + const key = dataItem.substring(0, delimPos); + const value = dataItem.substring(delimPos + 1); + + switch (key) { + case 'options': + options = this.parseOptions(value); + break; + case 'version': + version = value; + break; + case 'target': + target = value; + break; + case 'type': + type = value; + break; + case 'vendor': + vendor = value; + break; + case 'device': + deviceName = value; + break; + default: + break; + } + } + }); + } - if (txtResponse && aResponse && srvResponse) { - const dns: string = srvResponse.data?.target; - const port: number = srvResponse.data?.port; - const ip: string = aResponse.data; - const name: string = txtResponse.name?.substring( - 0, - txtResponse.name.indexOf('.') - ); - let options: UserDefine[] = []; - let version = ''; - let target = ''; - let type = ''; - let vendor = ''; - let deviceName = ''; - - if (Array.isArray(txtResponse.data)) { - txtResponse.data.forEach((item: any) => { - if (item instanceof Buffer) { - const dataItem = item.toString('utf-8'); - const delimPos = dataItem.indexOf('='); - const key = dataItem.substring(0, delimPos); - const value = dataItem.substring(delimPos + 1); - - switch (key) { - case 'options': - options = this.parseOptions(value); - break; - case 'version': - version = value; - break; - case 'target': - target = value; - break; - case 'type': - type = value; - break; - case 'vendor': - vendor = value; - break; - case 'device': - deviceName = value; - break; - default: - break; + if (vendor === 'elrs') { + const name = item.name?.substring(0, item.name.indexOf('.')); + + const srvResponses: SrvAnswer[] = items.filter( + (answer) => answer.type === 'SRV' + ) as SrvAnswer[]; + + const srvResponse: SrvAnswer | undefined = srvResponses.find((i) => { + return i.name.startsWith(name); + }); + + if (srvResponse) { + const dns: string = srvResponse.data?.target; + const port: number = srvResponse.data?.port; + + if (srvResponse) { + const aResponse: StringAnswer | undefined = items.find( + (answer) => + answer.type === 'A' && answer.name === srvResponse.data.target + ) as StringAnswer; + + if (aResponse) { + const ip: string = aResponse.data; + + const mdnsInformation: MulticastDnsInformation = { + name, + dns, + ip, + options, + version, + target, + type, + vendor, + port, + deviceName, + }; + + if (!this.devices[name]) { + this.devices[name] = mdnsInformation; + this.notifications.sendDeviceAdded(mdnsInformation); + } else if ( + JSON.stringify(this.devices[name]) !== + JSON.stringify(mdnsInformation) + ) { + this.devices[name] = mdnsInformation; + this.notifications.sendDeviceUpdated(mdnsInformation); } } - }); - } - - const mdnsInformation: MulticastDnsInformation = { - name, - dns, - ip, - options, - version, - target, - type, - vendor, - port, - deviceName, - }; - - if (!this.devices[name]) { - this.devices[name] = mdnsInformation; - this.notifications.sendDeviceAdded(mdnsInformation); - } else if ( - JSON.stringify(this.devices[name]) !== JSON.stringify(mdnsInformation) - ) { - this.devices[name] = mdnsInformation; - this.notifications.sendDeviceUpdated(mdnsInformation); + } } } - } + }); } private removeDevice(name: string) { From 4cf5bb5766df56bc7de9a3255daa311cf6a6fe32 Mon Sep 17 00:00:00 2001 From: Eike Ahmels Date: Thu, 19 May 2022 12:39:08 +0200 Subject: [PATCH 2/3] refactoring mdns request parsing mdns responses now doenst rely on the url starting with "elrs" and its now supporting multiple elrs answers in a response --- src/api/src/services/MulticastDns/index.ts | 171 +++++++++++---------- 1 file changed, 94 insertions(+), 77 deletions(-) diff --git a/src/api/src/services/MulticastDns/index.ts b/src/api/src/services/MulticastDns/index.ts index a35c55d4e..68d327249 100644 --- a/src/api/src/services/MulticastDns/index.ts +++ b/src/api/src/services/MulticastDns/index.ts @@ -1,6 +1,7 @@ import { Service } from 'typedi'; import * as http from 'http'; import makeMdns, { ResponsePacket } from 'multicast-dns'; +import { SrvAnswer, StringAnswer, TxtAnswer } from 'dns-packet'; import MulticastDnsInformation from '../../models/MulticastDnsInformation'; import { LoggerService } from '../../logger'; import MulticastDnsEventType from '../../models/enum/MulticastDnsEventType'; @@ -120,88 +121,104 @@ export default class MulticastDnsService { // check if any of the answers on the response have a name that starts with // 'elrs_', which indicates that it is an elers device - const isElrs = !!items.find((item: any) => item.name.startsWith('elrs_')); - - if (isElrs) { - const txtResponse: any = items.find((answer) => answer.type === 'TXT'); - - const aResponse: any = items.find((answer) => answer.type === 'A'); - - const srvResponse: any = items.find((answer) => answer.type === 'SRV'); + const txtResponses: TxtAnswer[] = items.filter( + (answer) => answer.type === 'TXT' + ) as TxtAnswer[]; + + txtResponses.forEach((item) => { + let options: UserDefine[] = []; + let version = ''; + let target = ''; + let type = ''; + let vendor = ''; + let deviceName = ''; + + if (Array.isArray(item.data)) { + item.data.forEach((i) => { + if (i instanceof Buffer) { + const dataItem = i.toString('utf-8'); + const delimPos = dataItem.indexOf('='); + const key = dataItem.substring(0, delimPos); + const value = dataItem.substring(delimPos + 1); + + switch (key) { + case 'options': + options = this.parseOptions(value); + break; + case 'version': + version = value; + break; + case 'target': + target = value; + break; + case 'type': + type = value; + break; + case 'vendor': + vendor = value; + break; + case 'device': + deviceName = value; + break; + default: + break; + } + } + }); + } - if (txtResponse && aResponse && srvResponse) { - const dns: string = srvResponse.data?.target; - const port: number = srvResponse.data?.port; - const ip: string = aResponse.data; - const name: string = txtResponse.name?.substring( - 0, - txtResponse.name.indexOf('.') - ); - let options: UserDefine[] = []; - let version = ''; - let target = ''; - let type = ''; - let vendor = ''; - let deviceName = ''; - - if (Array.isArray(txtResponse.data)) { - txtResponse.data.forEach((item: any) => { - if (item instanceof Buffer) { - const dataItem = item.toString('utf-8'); - const delimPos = dataItem.indexOf('='); - const key = dataItem.substring(0, delimPos); - const value = dataItem.substring(delimPos + 1); - - switch (key) { - case 'options': - options = this.parseOptions(value); - break; - case 'version': - version = value; - break; - case 'target': - target = value; - break; - case 'type': - type = value; - break; - case 'vendor': - vendor = value; - break; - case 'device': - deviceName = value; - break; - default: - break; + if (vendor === 'elrs') { + const name = item.name?.substring(0, item.name.indexOf('.')); + + const srvResponses: SrvAnswer[] = items.filter( + (answer) => answer.type === 'SRV' + ) as SrvAnswer[]; + + const srvResponse: SrvAnswer | undefined = srvResponses.find((i) => { + return i.name.startsWith(name); + }); + + if (srvResponse) { + const dns: string = srvResponse.data?.target; + const port: number = srvResponse.data?.port; + + if (srvResponse) { + const aResponse: StringAnswer | undefined = items.find( + (answer) => + answer.type === 'A' && answer.name === srvResponse.data.target + ) as StringAnswer; + + if (aResponse) { + const ip: string = aResponse.data; + + const mdnsInformation: MulticastDnsInformation = { + name, + dns, + ip, + options, + version, + target, + type, + vendor, + port, + deviceName, + }; + + if (!this.devices[name]) { + this.devices[name] = mdnsInformation; + this.notifications.sendDeviceAdded(mdnsInformation); + } else if ( + JSON.stringify(this.devices[name]) !== + JSON.stringify(mdnsInformation) + ) { + this.devices[name] = mdnsInformation; + this.notifications.sendDeviceUpdated(mdnsInformation); } } - }); - } - - const mdnsInformation: MulticastDnsInformation = { - name, - dns, - ip, - options, - version, - target, - type, - vendor, - port, - deviceName, - }; - - if (!this.devices[name]) { - this.devices[name] = mdnsInformation; - this.notifications.sendDeviceAdded(mdnsInformation); - } else if ( - JSON.stringify(this.devices[name]) !== JSON.stringify(mdnsInformation) - ) { - this.devices[name] = mdnsInformation; - this.notifications.sendDeviceUpdated(mdnsInformation); + } } } - } + }); } private removeDevice(name: string) { From d6a364e92995266735102e695740c4ffadb26782 Mon Sep 17 00:00:00 2001 From: Eike Ahmels Date: Fri, 20 May 2022 07:35:56 +0200 Subject: [PATCH 3/3] changed from filter to find since mdns answers are single --- src/api/src/services/MulticastDns/index.ts | 89 ++++++++++------------ 1 file changed, 42 insertions(+), 47 deletions(-) diff --git a/src/api/src/services/MulticastDns/index.ts b/src/api/src/services/MulticastDns/index.ts index 68d327249..14db82569 100644 --- a/src/api/src/services/MulticastDns/index.ts +++ b/src/api/src/services/MulticastDns/index.ts @@ -119,13 +119,11 @@ export default class MulticastDnsService { private handleMulticastDnsResponse(response: ResponsePacket) { const items = [...response.answers, ...response.additionals]; - // check if any of the answers on the response have a name that starts with - // 'elrs_', which indicates that it is an elers device - const txtResponses: TxtAnswer[] = items.filter( + const txtResponse: TxtAnswer = items.find( (answer) => answer.type === 'TXT' - ) as TxtAnswer[]; + ) as TxtAnswer; - txtResponses.forEach((item) => { + if (txtResponse) { let options: UserDefine[] = []; let version = ''; let target = ''; @@ -133,8 +131,8 @@ export default class MulticastDnsService { let vendor = ''; let deviceName = ''; - if (Array.isArray(item.data)) { - item.data.forEach((i) => { + if (Array.isArray(txtResponse.data)) { + txtResponse.data.forEach((i) => { if (i instanceof Buffer) { const dataItem = i.toString('utf-8'); const delimPos = dataItem.indexOf('='); @@ -168,57 +166,54 @@ export default class MulticastDnsService { } if (vendor === 'elrs') { - const name = item.name?.substring(0, item.name.indexOf('.')); + const name = txtResponse.name?.substring( + 0, + txtResponse.name.indexOf('.') + ); - const srvResponses: SrvAnswer[] = items.filter( + const srvResponse: SrvAnswer = items.find( (answer) => answer.type === 'SRV' - ) as SrvAnswer[]; - - const srvResponse: SrvAnswer | undefined = srvResponses.find((i) => { - return i.name.startsWith(name); - }); + ) as SrvAnswer; if (srvResponse) { const dns: string = srvResponse.data?.target; const port: number = srvResponse.data?.port; - if (srvResponse) { - const aResponse: StringAnswer | undefined = items.find( - (answer) => - answer.type === 'A' && answer.name === srvResponse.data.target - ) as StringAnswer; - - if (aResponse) { - const ip: string = aResponse.data; - - const mdnsInformation: MulticastDnsInformation = { - name, - dns, - ip, - options, - version, - target, - type, - vendor, - port, - deviceName, - }; - - if (!this.devices[name]) { - this.devices[name] = mdnsInformation; - this.notifications.sendDeviceAdded(mdnsInformation); - } else if ( - JSON.stringify(this.devices[name]) !== - JSON.stringify(mdnsInformation) - ) { - this.devices[name] = mdnsInformation; - this.notifications.sendDeviceUpdated(mdnsInformation); - } + const aResponse: StringAnswer = items.find( + (answer) => + answer.type === 'A' && answer.name === srvResponse.data.target + ) as StringAnswer; + + if (aResponse) { + const ip: string = aResponse.data; + + const mdnsInformation: MulticastDnsInformation = { + name, + dns, + ip, + options, + version, + target, + type, + vendor, + port, + deviceName, + }; + + if (!this.devices[name]) { + this.devices[name] = mdnsInformation; + this.notifications.sendDeviceAdded(mdnsInformation); + } else if ( + JSON.stringify(this.devices[name]) !== + JSON.stringify(mdnsInformation) + ) { + this.devices[name] = mdnsInformation; + this.notifications.sendDeviceUpdated(mdnsInformation); } } } } - }); + } } private removeDevice(name: string) {