brutella / hap

The HomeKit Accessory Protocol (hap) implemented in Go
Apache License 2.0
345 stars 39 forks source link

dns-sd name conflict resolution leads to space in name, causing malformed host header and failure to pair #57

Closed bwesterb closed 1 month ago

bwesterb commented 4 months ago

First off: love this package! Recently I tried to re-pair an accessory. Pairing with the Home app times out. With the hkontroller example app it pairs successfully. I made a packet dump, and I found the following difference.

hkontroller sets an empty host header, whereas the Home app send Host: Incomfort_Gateway\0322._hap._tcp.local. Go's http server doesn't like that, responding with a 400 Bad Request: malformed Host header.

Now, I'm not sure who's at fault here. Btw, dns-sd -Z _hap._tcp local. returns

_hap._tcp                                       PTR     Incomfort_Gateway\0322._hap._tcp
Incomfort_Gateway\0322._hap._tcp                SRV     0 0 33133 BB804B1E71D9\0322.local. ; Replace with unicast FQDN of target host
Incomfort_Gateway\0322._hap._tcp                TXT     "c#=2" "ci=9" "ff=0" "id=BB:80:4B:1E:71:D9" "md=Incomfort Gateway" "pv=1.0" "s#=1" "sf=0" "sh=5oin+Q=="
bwesterb commented 2 months ago

This was on Linux. When tetsting on Mac, the advertisement is Incomfort_Gateway._hap._tcp (for some reason) and that does work. Not sure if it's OS or different network setup between the machines.

bwesterb commented 2 months ago

Related iOS misbehaviour radar: http://openradar.appspot.com/radar?id=4931940373233664

bwesterb commented 2 months ago

Mac vs Linux was a red herring. The crucial difference was that the Linux machine had two interfaces. For some reason this caused dnssd to retry and land on the name Incomfort_Gateway 2. This in turn hit the earlier mentioned iOS bug. Restricting to a single interfaces by setting Server.Ifaces fixes it. Surprisingly changing dnssd to use _2 (etc) instead of 2 doesn't work.

brutella commented 2 months ago

Surprisingly changing dnssd to use _2 (etc) instead of 2 doesn't work.

Are you sure about that? When you make that change, does the Home app send a different Host header – I expect it to be _2.

bwesterb commented 2 months ago

I didn't get to that point yet: dnssd would keep incrementing the counter and not land on a name it thinks is free.

brutella commented 1 month ago

Ok, so I've made two changes to dnssd, which should fix your issue.

  1. brutella/dnssd@64826ad5bebdb368802a976ced703497bc7457c6 Suffixes for hostname conflict resolution doesn't contain spaces anymore; instead of name 2 it will be name_2. This should prevent the issue that iOS sends a wrong http host header field as described in http://openradar.appspot.com/radar?id=4931940373233664
  2. brutella/dnssd@6f66c93b969dcf4bbaaa2bbeb5b829191cd0e5cf Hostname conflicts, because of multiple network interfaces, are now fixed.

Those changes are now in v0.0.34.

bwesterb commented 1 month ago

That fixed it. Thanks.