Giter Club home page Giter Club logo

Comments (17)

readybeginn avatar readybeginn commented on August 21, 2024 1

I'm also running VLANs. I use Pfsense and the Avahi package to provide mDNS. Awesome work @cbpowell!

from lutron-leap-js.

thenewwazoo avatar thenewwazoo commented on August 21, 2024 1

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.

thenewwazoo avatar thenewwazoo commented on August 21, 2024

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.

cbpowell avatar cbpowell commented on August 21, 2024

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.

thenewwazoo avatar thenewwazoo commented on August 21, 2024

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.

thenewwazoo avatar thenewwazoo commented on August 21, 2024

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.

thenewwazoo avatar thenewwazoo commented on August 21, 2024

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.

thenewwazoo avatar thenewwazoo commented on August 21, 2024

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.

thenewwazoo avatar thenewwazoo commented on August 21, 2024

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.

thenewwazoo avatar thenewwazoo commented on August 21, 2024

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.

thenewwazoo avatar thenewwazoo commented on August 21, 2024

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.

thenewwazoo avatar thenewwazoo commented on August 21, 2024

Alright, I unpublished 2.3.7.

from lutron-leap-js.

cbpowell avatar cbpowell commented on August 21, 2024

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.

thenewwazoo avatar thenewwazoo commented on August 21, 2024

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.

cbpowell avatar cbpowell commented on August 21, 2024

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.

cbpowell avatar cbpowell commented on August 21, 2024

Side note, those dig queries just don't seem to work across the OPNsense mdns repeater.

from lutron-leap-js.

thenewwazoo avatar thenewwazoo commented on August 21, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.