Comments (17)
I'm also running VLANs. I use Pfsense and the Avahi package to provide mDNS. Awesome work @cbpowell!
from lutron-leap-js.
I'm still reading through this (excellent!) report, but I just have to take a moment and wonder
65535 - 1 + 1
what the hell was I thinking when I wrote that? 😆
Okay, back to reading...
from lutron-leap-js.
I'm going to take some notes here while I work through this:
- The
_id
value is the DNS query transaction ID, which can be used to tie a specific response to a specific request. When I send broadcast DNS queries for SRV records, I get responses with a random ID as expected (and no warnings from dig), so it looks like the mDNS responder in the bridge is behaving correctly. I'm not sure about this, though. - I specify port 0 because, when mdns uses it, it instructs the operating system to bind to a random port. Turns out, that's not compliant with the RFC (see the last para in 5.2)!
- Setting the transaction ID (should) obviates the need to filter response packets as you've done. Filtering based on record type, etc, explains why you can trigger discovery with unrelated queries.
- The logic that follows is, I think, based on working around/with the previous changes. I don't see any async/timing issues because the response handler is hooked up before the query is issued, as expected. Issuing a query after receiving an unknown response is probably not the best approach.
I suspect something in your stack is inspecting (and maybe altering) mDNS responses as they come back by re-writing the transaction ID and/or refusing to pass packets with a malformed source port.
I'll get a change out right now to fix the source port bug. Can you share the script you're using to test multicast-dns
? I'd love to see if I can reproduce the qid 0 weirdness.
from lutron-leap-js.
Sure thing - sorry I should have just done that yesterday. The code is in this gist. With a preceding npm install multicast-dns
to install it in the running directory.
Absolutely makes sense on the unique _id
value to distinguish the specific query. I admit I thought mDNS generally worked with broad, non-specific queries (because there certainly seem to be a lot flying around on my network!), but that could certainly be exploited to do some DNS spoofing.
What's weird with the _id
value is 0 (edit) even if I put my laptop on my IoT VLAN with the bridge and run that script, I still get responses with _id
values of 0. Also weird is that in the script, the filtering approach catches the first/original query response that the plugin with the same code seems to miss.
from lutron-leap-js.
Super weird. The internet appears to disagree about whether mDNS should have a qid of 0, but I can't find anything in the spec saying it must be. What's weirder is that I can reproduce your results, even directly on my RPi running Homebridge, which means the current code should never work, right?
from lutron-leap-js.
Ah, okay, here we go, from RFC 6762 section 18.1:
Multicast DNS implementations SHOULD listen for unsolicited responses issued by hosts booting up (or waking up from sleep or otherwise joining the network). Since these unsolicited responses may contain a useful answer to a question for which the querier is currently awaiting an answer, Multicast DNS implementations SHOULD examine all received Multicast DNS response messages for useful answers, without regard to the contents of the ID field or the Question Section. In Multicast DNS, knowing which particular query message (if any) is responsible for eliciting a particular response message is less interesting than knowing whether the response message contains useful information.
...
In multicast query messages, the Query Identifier SHOULD be set to zero on transmission.In multicast responses, including unsolicited multicast responses, the Query Identifier MUST be set to zero on transmission, and MUST be ignored on reception.
In legacy unicast response messages generated specifically in response to a particular (unicast or multicast) query, the Query Identifier MUST match the ID from the query message.
from lutron-leap-js.
Ah, here we go, from RFC 6762 section 6.7:
If the source UDP port in a received Multicast DNS query is not port 5353, this indicates that the querier originating the query is a simple resolver such as described in Section 5.1, "One-Shot Multicast DNS Queries", which does not fully implement all of Multicast DNS. In this case, the Multicast DNS responder MUST send a UDP response directly back to the querier, via unicast, to the query packet's source IP address and port. This unicast response MUST be a conventional unicast response as would be generated by a conventional Unicast DNS server; for example, it MUST repeat the query ID and the question given in the query message.
from lutron-leap-js.
Okay, got it.
In the original code, I set the source port to 0, which causes mDNS responders to behave as though the requestor wants a "Legacy unicast response".
from lutron-leap-js.
Check out this gist.
I get the following output:
$ node node_modules/multicast-dns/lutron.js
ID for match: 33361
got a response packet w/ id: 33361
got a response packet w/ id: 0
packet WOULD have matched
^C
from lutron-leap-js.
Okay, so the behavior here is broken in the case of multiple bridges, as I could get multiple responses for the query for Lutron Status._lutron._tcp.local
. In that case, the query is not closed when I get one response, and I am not guaranteed to even get a response from the same bridge that announced itself.
from lutron-leap-js.
I'm going to have to think about this, and probably refactor how discovery works (again 😆). The DNS-SD library I use only looks for PTR records, but the SRV record contains the bridge ID. Maybe asking for PTR records is redundant, and I could possibly only ask for SRV records, but I'm not sure what the implications of that would be w.r.t. DNS-SD (does DNS-SD require PTR record requests or something?).
At the very least, I need to back out my most recent change, I think, as I'm relying on having the port set in order for the qid to work.
from lutron-leap-js.
Alright, I unpublished 2.3.7.
from lutron-leap-js.
Oh man, as a quick response - I'm at work and it's killing me that I can't reply and work on it live! I had done some Wireshark investigation since yesterday too, but I don't think I uncovered anything that you didn't also just describe.
When you request a SRV you do also get an A record with the IP in the additionals
item, so would that be enough to also extract the IP? Instead of requesting the PTRs separately? (Maybe that's not proper usage of DNS-SD, like you say).
from lutron-leap-js.
It looks like I do get an A record along with the SRV response:
$ dig @224.0.0.251 -p 5353 -t srv 'Lutron\032Status._lutron._tcp.local.'
; <<>> DiG 9.10.6 <<>> @224.0.0.251 -p 5353 -t srv Lutron\032Status._lutron._tcp.local.
; (1 server found)
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 23810
;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 2
;; QUESTION SECTION:
;Lutron\032Status._lutron._tcp.local. IN SRV
;; ANSWER SECTION:
Lutron\032Status._lutron._tcp.local. 10 IN SRV 0 0 22 Lutron-032e7e88.local.
;; ADDITIONAL SECTION:
Lutron-032e7e88.local. 10 IN A 192.168.1.151
Lutron-032e7e88.local. 10 IN AAAA fe80::9270:65ff:fee3:8f25
from lutron-leap-js.
Yep same with the mdns-resolver script:
ID for match: 52572
got a response packet w/ id: 0
packet WOULD have matched: {
id: 0,
type: 'response',
flags: 1024,
flag_qr: true,
opcode: 'QUERY',
flag_aa: true,
flag_tc: false,
flag_rd: false,
flag_ra: false,
flag_z: false,
flag_ad: false,
flag_cd: false,
rcode: 'NOERROR',
questions: [],
answers: [
{
name: 'Lutron Status._lutron._tcp.local',
type: 'SRV',
ttl: 120,
class: 'IN',
flush: true,
data: [Object]
}
],
authorities: [],
additionals: [
{
name: 'Lutron-01e510eb.local',
type: 'A',
ttl: 120,
class: 'IN',
flush: true,
data: '10.7.20.41'
},
{
name: 'Lutron-01e510eb.local',
type: 'AAAA',
ttl: 120,
class: 'IN',
flush: true,
data: 'fe80::8a4a:eaff:fefd:6b4b'
},
{
name: 'Lutron-01e510eb.local',
type: 'NSEC',
ttl: 120,
class: 'IN',
flush: true,
data: [Object]
},
{
name: 'Lutron Status._lutron._tcp.local',
type: 'NSEC',
ttl: 120,
class: 'IN',
flush: true,
data: [Object]
}
]
}
from lutron-leap-js.
Side note, those dig queries just don't seem to work across the OPNsense mdns repeater.
from lutron-leap-js.
Yeah, I'd actually expect they wouldn't since it's not well-formed mDNS. Send a packet (using my gist above) with qid zero and source port 5353, and I bet it repeats it.
from lutron-leap-js.
Related Issues (20)
- MultipleLinkDefinition body type HOT 1
- OneAreaStatus body type HOT 9
- MultipleAreaStatus body type HOT 1
- OneAreaSceneDefinition body type HOT 1
- OnePresetDefinition body type HOT 1
- Has this been tested with RadioRA3 Sunnata Dimmers and Keypads? HOT 3
- Support new Homeworks QSX LEAP varient HOT 35
- Support for Sunnata 4 buttton keypad and RA2 fan via the RA3 hub? HOT 4
- Control devices? HOT 3
- Homeworks QSX support HOT 2
- 3.4.x NPM packages contain code not in repo
- MultipleAreaDefinition body type HOT 1
- Question: Where to get information about LEAP protocol? HOT 1
- OneAreaDefinition body type HOT 1
- OneControlStationDefinition body type HOT 1
- OneProjectDefinition body type HOT 1
- OneLinkNodeDefinition body type HOT 1
- MultipleZoneStatus body type HOT 1
- Support zone subscriptions HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from lutron-leap-js.