mailing list of musl libc
 help / color / mirror / code / Atom feed
* [musl] mDNS in musl
@ 2024-03-06  7:29 David Schinazi
  2024-03-06 16:15 ` Rich Felker
  2024-03-06 16:15 ` Markus Wichmann
  0 siblings, 2 replies; 32+ messages in thread
From: David Schinazi @ 2024-03-06  7:29 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 2244 bytes --]

Hi everyone,

I was debugging a network connectivity issue on Alpine and have tracked it
down to lack of support for mDNS in musl gethostbyname / getaddrinfo [1]. I
looked through the musl codebase to understand why, and it would be pretty
straightforward to fix. I'd be interested in writing a patch for this, so I
was wondering: would you be at all interested in potentially taking such a
patch?

Some more info on mDNS: all names that end in ".local" are reserved for use
by mDNS, and instead of sending them to the DNS resolver, they're sent
locally over multicast - and the machine with that name replies with its IP
address. It's used today to discover printers and pretty much everything in
home networks.

From looking through musl, both gethostbyname() and getaddrinfo() route
through __lookup_name(), which eventually calls name_from_dns(). From
looking at that function, the issue is that it doesn't treat .local
specifically - instead of sending those queries to multicast, it sends them
to the regularly configured DNS nameservers.

The fix would be to modify name_from_dns() [2] such that if `name` ends in
".local", then pass in a different conf variable to __res_msend_rc(). The
conf variable contains (amongst other things) the DNS nameservers to send
the query to. So, when the name ends in .local, instead of passing in the
regular nameservers, we pass the multicast addresses and ports dedicated to
mDNS (224.0.0.251:5353 and [ff02::fb]:5353).

And that's it! This implementation is compatible with the "One-Shot
Multicast DNS Queries" mode of the mDNS RFC [3]. (Other versions of libc
have a mode to send the query over dbus to avahi so that it can cache mDNS
results locally. But that's the more complicated "Continuous Multicast DNS
Querying" mode of the RFC, and we don't need that here.)

So what do you think, would you be interested in support for mDNS? (In case
it matters, I've made changes in getaddrinfo inside Apple's libc, so I'm
comfortable in this kind of code even though I have zero prior experience
with musl)

Thanks,
David


[1] https://wiki.alpinelinux.org/wiki/MDNS
[2] https://git.musl-libc.org/cgit/musl/tree/src/network/lookup_name.c#n143
[3] https://www.rfc-editor.org/rfc/rfc6762.html#section-5.1

[-- Attachment #2: Type: text/html, Size: 2838 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-06  7:29 [musl] mDNS in musl David Schinazi
@ 2024-03-06 16:15 ` Rich Felker
  2024-03-06 16:45   ` Jeffrey Walton
  2024-03-07  0:17   ` David Schinazi
  2024-03-06 16:15 ` Markus Wichmann
  1 sibling, 2 replies; 32+ messages in thread
From: Rich Felker @ 2024-03-06 16:15 UTC (permalink / raw)
  To: David Schinazi; +Cc: musl

On Tue, Mar 05, 2024 at 11:29:03PM -0800, David Schinazi wrote:
> Hi everyone,
> 
> I was debugging a network connectivity issue on Alpine and have tracked it
> down to lack of support for mDNS in musl gethostbyname / getaddrinfo [1]. I
> looked through the musl codebase to understand why, and it would be pretty
> straightforward to fix. I'd be interested in writing a patch for this, so I
> was wondering: would you be at all interested in potentially taking such a
> patch?
> 
> Some more info on mDNS: all names that end in ".local" are reserved for use
> by mDNS, and instead of sending them to the DNS resolver, they're sent
> locally over multicast - and the machine with that name replies with its IP
> address. It's used today to discover printers and pretty much everything in
> home networks.

Last I checked, .local is not actually reserved by any relevant
specification/authority. It was basically just appropriated by mDNS.
The protocol spoken is also not exactly DNS (for example, it uses raw
UTF-8 rather than IDN/punycode, which would need to be special-cased
once we support the latter).

There's also very much a policy matter of what "locally over
multicast" means (what the user wants it to mean). Which interfaces
should be queried? Wired and wireless ethernet? VPN links or other
sorts of tunnels? Just one local interface (which one to prioritize)
or all of them? Only if the network is "trusted"? Etc.

My view has always been that the right way to do something like this,
where there's no existing interface or contract/expectations for how
the libc stub resolver does it, is that it belongs in a resolver
speaking dns protocol on localhost. That way policy isn't baked-in to
individual executables (which may be static linked) but kept in a
place that's reasonable to have policy controls and where the user can
customize them.

> From looking through musl, both gethostbyname() and getaddrinfo() route
> through __lookup_name(), which eventually calls name_from_dns(). From
> looking at that function, the issue is that it doesn't treat .local
> specifically - instead of sending those queries to multicast, it sends them
> to the regularly configured DNS nameservers.
> 
> The fix would be to modify name_from_dns() [2] such that if `name` ends in
> ".local", then pass in a different conf variable to __res_msend_rc(). The
> conf variable contains (amongst other things) the DNS nameservers to send
> the query to. So, when the name ends in .local, instead of passing in the
> regular nameservers, we pass the multicast addresses and ports dedicated to
> mDNS (224.0.0.251:5353 and [ff02::fb]:5353).

When you do that, how do you control which interface(s) it goes over?
I think that's an important missing ingredient.

> And that's it! This implementation is compatible with the "One-Shot
> Multicast DNS Queries" mode of the mDNS RFC [3]. (Other versions of libc
> have a mode to send the query over dbus to avahi so that it can cache mDNS
> results locally. But that's the more complicated "Continuous Multicast DNS
> Querying" mode of the RFC, and we don't need that here.)
> 
> So what do you think, would you be interested in support for mDNS? (In case
> it matters, I've made changes in getaddrinfo inside Apple's libc, so I'm
> comfortable in this kind of code even though I have zero prior experience
> with musl)

If at some point there's a consensus on stub resolvers having an
expectation to support this themselves, and on untanging the details
like the above, and on "ownership" of the ".local" TLD, it might make
sense to have a resolv.conf option to do this. Unlike general unioning
of sources, which is really problematic, the mDNS stuff seems to be
putting the decision which source to use *before* making any queries,
which is a lot less problematic.

Rich

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-06  7:29 [musl] mDNS in musl David Schinazi
  2024-03-06 16:15 ` Rich Felker
@ 2024-03-06 16:15 ` Markus Wichmann
  1 sibling, 0 replies; 32+ messages in thread
From: Markus Wichmann @ 2024-03-06 16:15 UTC (permalink / raw)
  To: musl; +Cc: David Schinazi

Am Tue, Mar 05, 2024 at 11:29:03PM -0800 schrieb David Schinazi:
> [1] https://wiki.alpinelinux.org/wiki/MDNS

So is there something wrong with the solution presented in the wiki
page? Because that is generally the answer we recommend: If you want any
name resolution other than DNS, write a proxy that does what you want
and point resolv.conf to it. Similarly, if you want any user database
lookup other than local files, write an nscd proxy that does what you
want.

Reason for that is that that is the most generic way to support any
other name service besides DNS. It avoids the dependency on dynamic
loading that something like glibc's nsswitch would create, and would
avoid having multiple backends in libc. I really don't think anyone
wants to open that particular door. Once mDNS is in there, someone will
add NetBIOS, just you wait.

Ciao,
Markus

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-06 16:15 ` Rich Felker
@ 2024-03-06 16:45   ` Jeffrey Walton
  2024-03-07  0:17   ` David Schinazi
  1 sibling, 0 replies; 32+ messages in thread
From: Jeffrey Walton @ 2024-03-06 16:45 UTC (permalink / raw)
  To: musl; +Cc: David Schinazi

On Wed, Mar 6, 2024 at 11:15 AM Rich Felker <dalias@libc.org> wrote:
>
> On Tue, Mar 05, 2024 at 11:29:03PM -0800, David Schinazi wrote:
> >  [...]
> > Some more info on mDNS: all names that end in ".local" are reserved for use
> > by mDNS, and instead of sending them to the DNS resolver, they're sent
> > locally over multicast - and the machine with that name replies with its IP
> > address. It's used today to discover printers and pretty much everything in
> > home networks.
>
> Last I checked, .local is not actually reserved by any relevant
> specification/authority. It was basically just appropriated by mDNS.

It looks like IANA reserves it, and cites RFC 6762,
<https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml>.

Jeff

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-06 16:15 ` Rich Felker
  2024-03-06 16:45   ` Jeffrey Walton
@ 2024-03-07  0:17   ` David Schinazi
  2024-03-07  2:43     ` Rich Felker
  2024-03-08 15:31     ` Markus Wichmann
  1 sibling, 2 replies; 32+ messages in thread
From: David Schinazi @ 2024-03-07  0:17 UTC (permalink / raw)
  To: Rich Felker; +Cc: musl

[-- Attachment #1: Type: text/plain, Size: 7991 bytes --]

Thanks for the detailed responses, everyone!
I'm sending replies inline.
David

On Wed, Mar 6, 2024 at 8:15 AM Rich Felker <dalias@libc.org> wrote:

> On Tue, Mar 05, 2024 at 11:29:03PM -0800, David Schinazi wrote:
> > Hi everyone,
> >
> > I was debugging a network connectivity issue on Alpine and have tracked
> it
> > down to lack of support for mDNS in musl gethostbyname / getaddrinfo
> [1]. I
> > looked through the musl codebase to understand why, and it would be
> pretty
> > straightforward to fix. I'd be interested in writing a patch for this,
> so I
> > was wondering: would you be at all interested in potentially taking such
> a
> > patch?
> >
> > Some more info on mDNS: all names that end in ".local" are reserved for
> use
> > by mDNS, and instead of sending them to the DNS resolver, they're sent
> > locally over multicast - and the machine with that name replies with its
> IP
> > address. It's used today to discover printers and pretty much everything
> in
> > home networks.
>
> Last I checked, .local is not actually reserved by any relevant
> specification/authority. It was basically just appropriated by mDNS.
> The protocol spoken is also not exactly DNS (for example, it uses raw
> UTF-8 rather than IDN/punycode, which would need to be special-cased
> once we support the latter).
>

On Wed, Mar 6, 2024 at 8:45 AM Jeffrey Walton <noloader@gmail.com> wrote:

> It looks like IANA reserves it, and cites RFC 6762,
> <
> https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml
> >.


As Jeffrey points out, when the IETF decided to standardize mDNS, they
published it (RFC 6762) at the same time as the Special-Use Domain Registry
(RFC 6761) which created a process for reserving domain names for custom
purposes, and ".local" was one of the initial entries into that registry.
The UTF-8 vs punycode issue when it comes to mDNS and DNS is somewhat of a
mess. It was discussed in Section 16 of RFC 6762 but at the end of the day
punycode won. Even Apple's implementation of getaddrinfo will perform
punycode conversion for .local instead of sending the UTF-8. So in practice
you wouldn't need to special-case anything here.

There's also very much a policy matter of what "locally over
> multicast" means (what the user wants it to mean). Which interfaces
> should be queried? Wired and wireless ethernet? VPN links or other
> sorts of tunnels? Just one local interface (which one to prioritize)
> or all of them? Only if the network is "trusted"? Etc.
>

You're absolutely right. Most mDNS systems try all non-loopback non-p2p
multicast-supporting interfaces, but sending to the default route interface
would be a good start, more on that below.

My view has always been that the right way to do something like this,
> where there's no existing interface or contract/expectations for how
> the libc stub resolver does it, is that it belongs in a resolver
> speaking dns protocol on localhost. That way policy isn't baked-in to
> individual executables (which may be static linked) but kept in a
> place that's reasonable to have policy controls and where the user can
> customize them.
>

I agree that providing an option to have these policy decisions in
user-space makes a lot of sense. That's what glibc and Apple's libsystem
do, but that comes at a higher indirection cost. For components that don't
have as much flexibility though, it would be nice to be able to send these
queries without requiring additional software.

> From looking through musl, both gethostbyname() and getaddrinfo() route
> > through __lookup_name(), which eventually calls name_from_dns(). From
> > looking at that function, the issue is that it doesn't treat .local
> > specifically - instead of sending those queries to multicast, it sends
> them
> > to the regularly configured DNS nameservers.
> >
> > The fix would be to modify name_from_dns() [2] such that if `name` ends
> in
> > ".local", then pass in a different conf variable to __res_msend_rc(). The
> > conf variable contains (amongst other things) the DNS nameservers to send
> > the query to. So, when the name ends in .local, instead of passing in the
> > regular nameservers, we pass the multicast addresses and ports dedicated
> to
> > mDNS (224.0.0.251:5353 and [ff02::fb]:5353).
>
> When you do that, how do you control which interface(s) it goes over?
> I think that's an important missing ingredient.
>

You're absolutely right. In IPv4, sending to a link-local multicast address
like this will send it over the IPv4 default route interface. In IPv6, the
interface needs to be specified in the scope_id. So we'd need to pull that
out of the kernel with rtnetlink.

> And that's it! This implementation is compatible with the "One-Shot
> > Multicast DNS Queries" mode of the mDNS RFC [3]. (Other versions of libc
> > have a mode to send the query over dbus to avahi so that it can cache
> mDNS
> > results locally. But that's the more complicated "Continuous Multicast
> DNS
> > Querying" mode of the RFC, and we don't need that here.)
> >
> > So what do you think, would you be interested in support for mDNS? (In
> case
> > it matters, I've made changes in getaddrinfo inside Apple's libc, so I'm
> > comfortable in this kind of code even though I have zero prior experience
> > with musl)
>
> If at some point there's a consensus on stub resolvers having an
> expectation to support this themselves, and on untanging the details
> like the above, and on "ownership" of the ".local" TLD, it might make
> sense to have a resolv.conf option to do this.


So there's at least IETF consensus on these things. The ownership is
well-defined in RFC 6761, and the support by stub resolvers is discussed in
RFC 6762 Section 22.1 paragraph 3 <<Name resolution APIs and libraries
SHOULD recognize these names as special and SHOULD NOT send queries for
these names to their configured (unicast) caching DNS server(s).>>


> Unlike general unioning
> of sources, which is really problematic, the mDNS stuff seems to be
> putting the decision which source to use *before* making any queries,
> which is a lot less problematic.
>

I'm not familiar with what you mean by unioning here, are you referring to
interface selection, DNS name server selection, or something else?

On Wed, Mar 6, 2024 at 8:16 AM Markus Wichmann <nullplan@gmx.net> wrote:

> So is there something wrong with the solution presented in the wiki
> page? Because that is generally the answer we recommend: If you want any
> name resolution other than DNS, write a proxy that does what you want
> and point resolv.conf to it. Similarly, if you want any user database
> lookup other than local files, write an nscd proxy that does what you
> want.
>

That's certainly an option. Ideally I'd rather avoid adding additional
processes that can be failure points, when the stub can send these itself
with a very small modification.


> Reason for that is that that is the most generic way to support any
> other name service besides DNS. It avoids the dependency on dynamic
> loading that something like glibc's nsswitch would create, and would
> avoid having multiple backends in libc. I really don't think anyone
> wants to open that particular door. Once mDNS is in there, someone will
> add NetBIOS, just you wait.


I'm definitely supportive of the slippery slope argument, but I think
there's still a real line between mDNS and NetBIOS. mDNS uses a different
transport but lives inside the DNS namespace, whereas NetBIOS is really its
own thing - NetBIOS names aren't valid DNS hostnames.

Let me know what you think of the above. If you think of mDNS as its own
beast then I can see how including it wouldn't really make sense. But if
you see it as an actual part of the DNS, then it might be worth a small
code change :-)

Cheers,
David

[-- Attachment #2: Type: text/html, Size: 10479 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-07  0:17   ` David Schinazi
@ 2024-03-07  2:43     ` Rich Felker
  2024-03-07 22:50       ` David Schinazi
  2024-03-08 15:31     ` Markus Wichmann
  1 sibling, 1 reply; 32+ messages in thread
From: Rich Felker @ 2024-03-07  2:43 UTC (permalink / raw)
  To: David Schinazi; +Cc: musl

On Wed, Mar 06, 2024 at 04:17:44PM -0800, David Schinazi wrote:
> As Jeffrey points out, when the IETF decided to standardize mDNS, they
> published it (RFC 6762) at the same time as the Special-Use Domain Registry
> (RFC 6761) which created a process for reserving domain names for custom
> purposes, and ".local" was one of the initial entries into that registry.
> The UTF-8 vs punycode issue when it comes to mDNS and DNS is somewhat of a
> mess. It was discussed in Section 16 of RFC 6762 but at the end of the day
> punycode won. Even Apple's implementation of getaddrinfo will perform
> punycode conversion for .local instead of sending the UTF-8. So in practice
> you wouldn't need to special-case anything here.

OK, these are both really good news!

> There's also very much a policy matter of what "locally over
> > multicast" means (what the user wants it to mean). Which interfaces
> > should be queried? Wired and wireless ethernet? VPN links or other
> > sorts of tunnels? Just one local interface (which one to prioritize)
> > or all of them? Only if the network is "trusted"? Etc.
> >
> 
> You're absolutely right. Most mDNS systems try all non-loopback non-p2p
> multicast-supporting interfaces, but sending to the default route interface
> would be a good start, more on that below.

This is really one thing that suggests a need for configurability
outside of what libc might be able to offer. With normal DNS lookups,
they're something you can block off and prevent from going to the
network at all by policy (and in fact they don't go past the loopback
by default, in the absence of a resolv.conf file). Adding mDNS that's
on-by-default and not configurable would make a vector for network
traffic being generated that's probably not expected and that could be
a privacy leak.

> > When you do that, how do you control which interface(s) it goes over?
> > I think that's an important missing ingredient.
> 
> You're absolutely right. In IPv4, sending to a link-local multicast address
> like this will send it over the IPv4 default route interface. In IPv6, the
> interface needs to be specified in the scope_id. So we'd need to pull that
> out of the kernel with rtnetlink.

There's already code to enumerate interfaces, but it's a decent bit of
additional machinery to pull in as a dep for the stub resolver, and
it's not clear how to do it properly for IPv4 (do scope ids work with
v4-mapped addresses by any chance?)

Another issue you haven't mentioned: how does TCP fallback work with
mDNS? Or are answers too large for standard UDP replies just illegal?

> > Unlike general unioning
> > of sources, which is really problematic, the mDNS stuff seems to be
> > putting the decision which source to use *before* making any queries,
> > which is a lot less problematic.
> 
> I'm not familiar with what you mean by unioning here, are you referring to
> interface selection, DNS name server selection, or something else?

By unioning I just mean providing a view of the hostname space that's
the union of two or more sources of information (nameservers that
aren't just redundant sources for the same DNS root).

> > So is there something wrong with the solution presented in the wiki
> > page? Because that is generally the answer we recommend: If you want any
> > name resolution other than DNS, write a proxy that does what you want
> > and point resolv.conf to it. Similarly, if you want any user database
> > lookup other than local files, write an nscd proxy that does what you
> > want.
> 
> That's certainly an option. Ideally I'd rather avoid adding additional
> processes that can be failure points, when the stub can send these itself
> with a very small modification.

FWIW this is generally the approach musl takes. But if mDNS is
sufficiently standardized, intended to be supported in stub resolvers
by the standards, and doesn't have strong reasons not to do it, it
might be acceptable.

> > Reason for that is that that is the most generic way to support any
> > other name service besides DNS. It avoids the dependency on dynamic
> > loading that something like glibc's nsswitch would create, and would
> > avoid having multiple backends in libc. I really don't think anyone
> > wants to open that particular door. Once mDNS is in there, someone will
> > add NetBIOS, just you wait.
> 
> 
> I'm definitely supportive of the slippery slope argument, but I think
> there's still a real line between mDNS and NetBIOS. mDNS uses a different
> transport but lives inside the DNS namespace, whereas NetBIOS is really its
> own thing - NetBIOS names aren't valid DNS hostnames.
> 
> Let me know what you think of the above. If you think of mDNS as its own
> beast then I can see how including it wouldn't really make sense. But if
> you see it as an actual part of the DNS, then it might be worth a small
> code change :-)

I'm not worried about slippery slopes to NetBIOS. :-P I am concerned
about unwanted network traffic that can't be suppressed, privacy
leaks, inventing new configuration knobs, potentially pulling in more
code & more fragility, getting stuck supporting something that turns
out to have hidden problems we haven't thought about, etc.

Rich

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-07  2:43     ` Rich Felker
@ 2024-03-07 22:50       ` David Schinazi
  2024-03-08  0:08         ` Rich Felker
  0 siblings, 1 reply; 32+ messages in thread
From: David Schinazi @ 2024-03-07 22:50 UTC (permalink / raw)
  To: Rich Felker; +Cc: musl

[-- Attachment #1: Type: text/plain, Size: 8629 bytes --]

On Wed, Mar 6, 2024 at 6:42 PM Rich Felker <dalias@libc.org> wrote:

> On Wed, Mar 06, 2024 at 04:17:44PM -0800, David Schinazi wrote:
> > As Jeffrey points out, when the IETF decided to standardize mDNS, they
> > published it (RFC 6762) at the same time as the Special-Use Domain
> Registry
> > (RFC 6761) which created a process for reserving domain names for custom
> > purposes, and ".local" was one of the initial entries into that registry.
> > The UTF-8 vs punycode issue when it comes to mDNS and DNS is somewhat of
> a
> > mess. It was discussed in Section 16 of RFC 6762 but at the end of the
> day
> > punycode won. Even Apple's implementation of getaddrinfo will perform
> > punycode conversion for .local instead of sending the UTF-8. So in
> practice
> > you wouldn't need to special-case anything here.
>
> OK, these are both really good news!
>
> > There's also very much a policy matter of what "locally over
> > > multicast" means (what the user wants it to mean). Which interfaces
> > > should be queried? Wired and wireless ethernet? VPN links or other
> > > sorts of tunnels? Just one local interface (which one to prioritize)
> > > or all of them? Only if the network is "trusted"? Etc.
> > >
> >
> > You're absolutely right. Most mDNS systems try all non-loopback non-p2p
> > multicast-supporting interfaces, but sending to the default route
> interface
> > would be a good start, more on that below.
>
> This is really one thing that suggests a need for configurability
> outside of what libc might be able to offer. With normal DNS lookups,
> they're something you can block off and prevent from going to the
> network at all by policy (and in fact they don't go past the loopback
> by default, in the absence of a resolv.conf file). Adding mDNS that's
> on-by-default and not configurable would make a vector for network
> traffic being generated that's probably not expected and that could be
> a privacy leak.
>

Totally agree. I was thinking through this both in terms of RFCs and in
terms of minimal code changes, and had a potential idea. Conceptually,
sending DNS to localhost is musl's IPC mechanism to a more feature-rich
resolver running in user-space. So when that's happening, we don't want to
mess with it because that could cause a privacy leak. Conversely, when
there's a non-loopback IP configured in resolv.conf, then musl acts as a
DNS stub resolver and the server in resolv.conf acts as a DNS recursive
resolver. In that scenario, sending the .local query over DNS to that other
host violates the RFCs. This allows us to treat the configured resolver
address as an implicit configuration mechanism that allows us to
selectively enable this without impacting anyone doing their own DNS
locally.

> > When you do that, how do you control which interface(s) it goes over?
> > > I think that's an important missing ingredient.
> >
> > You're absolutely right. In IPv4, sending to a link-local multicast
> address
> > like this will send it over the IPv4 default route interface. In IPv6,
> the
> > interface needs to be specified in the scope_id. So we'd need to pull
> that
> > out of the kernel with rtnetlink.
>
> There's already code to enumerate interfaces, but it's a decent bit of
> additional machinery to pull in as a dep for the stub resolver,


Yeah we'd need lookup_name.c to include netlink.h - it's not huge though,
netlink.c is 50 lines long and statically linked anyway right?


> and
> it's not clear how to do it properly for IPv4 (do scope ids work with
> v4-mapped addresses by any chance?)
>

Scope IDs unfortunately don't work for IPv4. There's the SO_BINDTODEVICE
socket option, but that requires elevated privileges. For IPv4 I'd just use
the default route interface.

Another issue you haven't mentioned: how does TCP fallback work with
> mDNS? Or are answers too large for standard UDP replies just illegal?
>

Good point, I hadn't thought of that. That handling for mDNS is defined in
[1]. In the ephemeral query mode that we'd use here, it works the same as
for regular DNS: when you receive a response with the TC bit, retry the
query with TCP. The slight difference is that you send the TCP to the
address you got the response from (not to the multicast address that you
sent the original query to). From looking at the musl code, we'd need a
small tweak to __res_msend_rc() to use that address. Luckily that code
already looks at the sender address so we don't need any additional calls
to get it.

[1] https://www.rfc-editor.org/rfc/rfc6762#section-18.5

> > Unlike general unioning
> > > of sources, which is really problematic, the mDNS stuff seems to be
> > > putting the decision which source to use *before* making any queries,
> > > which is a lot less problematic.
> >
> > I'm not familiar with what you mean by unioning here, are you referring
> to
> > interface selection, DNS name server selection, or something else?
>
> By unioning I just mean providing a view of the hostname space that's
> the union of two or more sources of information (nameservers that
> aren't just redundant sources for the same DNS root).
>

Ah right. Yeah for mDNS the split is clean, that's part of why they
reserved .local for this.

> > So is there something wrong with the solution presented in the wiki
> > > page? Because that is generally the answer we recommend: If you want
> any
> > > name resolution other than DNS, write a proxy that does what you want
> > > and point resolv.conf to it. Similarly, if you want any user database
> > > lookup other than local files, write an nscd proxy that does what you
> > > want.
> >
> > That's certainly an option. Ideally I'd rather avoid adding additional
> > processes that can be failure points, when the stub can send these itself
> > with a very small modification.
>
> FWIW this is generally the approach musl takes. But if mDNS is
> sufficiently standardized, intended to be supported in stub resolvers
> by the standards, and doesn't have strong reasons not to do it, it
> might be acceptable.
>

Great!

> > Reason for that is that that is the most generic way to support any
> > > other name service besides DNS. It avoids the dependency on dynamic
> > > loading that something like glibc's nsswitch would create, and would
> > > avoid having multiple backends in libc. I really don't think anyone
> > > wants to open that particular door. Once mDNS is in there, someone will
> > > add NetBIOS, just you wait.
> >
> >
> > I'm definitely supportive of the slippery slope argument, but I think
> > there's still a real line between mDNS and NetBIOS. mDNS uses a different
> > transport but lives inside the DNS namespace, whereas NetBIOS is really
> its
> > own thing - NetBIOS names aren't valid DNS hostnames.
> >
> > Let me know what you think of the above. If you think of mDNS as its own
> > beast then I can see how including it wouldn't really make sense. But if
> > you see it as an actual part of the DNS, then it might be worth a small
> > code change :-)
>
> I'm not worried about slippery slopes to NetBIOS. :-P I am concerned
> about unwanted network traffic that can't be suppressed, privacy
> leaks, inventing new configuration knobs, potentially pulling in more
> code & more fragility, getting stuck supporting something that turns
> out to have hidden problems we haven't thought about, etc.
>

Those are great reasons, and I totally agree with those goals. If we scope
the problem down with the details higher up in this email, we have a way to
turn this off (set the resolver to localhost), we avoid privacy leaks in
cases where the traffic wasn't going out in the first place, we don't have
to add more configuration knobs because we're reusing an existing one, and
the amount of added code would be quite small. Limiting things to the
default interface isn't a full multi-network solution, but for those I
think it makes more sense to recommend running your own resolver on
loopback (you'd need elevated privileges to make this work fully anyway).
Coding wise, I think this would be pretty robust. The only breakage I
foresee is cases where someone built a custom resolver that runs on a
different machine and somehow handles .local differently than what the RFCs
say. That config sounds like a bad idea, and a violation of the RFCs, but
that doesn't mean there isn't someone somewhere who's doing it. So there's
a non-zero risk there. But to me that's manageable risk.

What do you think?

Thanks,
David

[-- Attachment #2: Type: text/html, Size: 10725 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-07 22:50       ` David Schinazi
@ 2024-03-08  0:08         ` Rich Felker
  2024-03-08  1:30           ` David Schinazi
  0 siblings, 1 reply; 32+ messages in thread
From: Rich Felker @ 2024-03-08  0:08 UTC (permalink / raw)
  To: David Schinazi; +Cc: musl

On Thu, Mar 07, 2024 at 02:50:53PM -0800, David Schinazi wrote:
> On Wed, Mar 6, 2024 at 6:42 PM Rich Felker <dalias@libc.org> wrote:
> 
> > On Wed, Mar 06, 2024 at 04:17:44PM -0800, David Schinazi wrote:
> > > As Jeffrey points out, when the IETF decided to standardize mDNS, they
> > > published it (RFC 6762) at the same time as the Special-Use Domain
> > Registry
> > > (RFC 6761) which created a process for reserving domain names for custom
> > > purposes, and ".local" was one of the initial entries into that registry.
> > > The UTF-8 vs punycode issue when it comes to mDNS and DNS is somewhat of
> > a
> > > mess. It was discussed in Section 16 of RFC 6762 but at the end of the
> > day
> > > punycode won. Even Apple's implementation of getaddrinfo will perform
> > > punycode conversion for .local instead of sending the UTF-8. So in
> > practice
> > > you wouldn't need to special-case anything here.
> >
> > OK, these are both really good news!
> >
> > > There's also very much a policy matter of what "locally over
> > > > multicast" means (what the user wants it to mean). Which interfaces
> > > > should be queried? Wired and wireless ethernet? VPN links or other
> > > > sorts of tunnels? Just one local interface (which one to prioritize)
> > > > or all of them? Only if the network is "trusted"? Etc.
> > > >
> > >
> > > You're absolutely right. Most mDNS systems try all non-loopback non-p2p
> > > multicast-supporting interfaces, but sending to the default route
> > interface
> > > would be a good start, more on that below.
> >
> > This is really one thing that suggests a need for configurability
> > outside of what libc might be able to offer. With normal DNS lookups,
> > they're something you can block off and prevent from going to the
> > network at all by policy (and in fact they don't go past the loopback
> > by default, in the absence of a resolv.conf file). Adding mDNS that's
> > on-by-default and not configurable would make a vector for network
> > traffic being generated that's probably not expected and that could be
> > a privacy leak.
> >
> 
> Totally agree. I was thinking through this both in terms of RFCs and in
> terms of minimal code changes, and had a potential idea. Conceptually,
> sending DNS to localhost is musl's IPC mechanism to a more feature-rich
> resolver running in user-space. So when that's happening, we don't want to
> mess with it because that could cause a privacy leak. Conversely, when
> there's a non-loopback IP configured in resolv.conf, then musl acts as a
> DNS stub resolver and the server in resolv.conf acts as a DNS recursive
> resolver. In that scenario, sending the .local query over DNS to that other
> host violates the RFCs. This allows us to treat the configured resolver
> address as an implicit configuration mechanism that allows us to
> selectively enable this without impacting anyone doing their own DNS
> locally.

This sounds like an odd overloading of one thing to have a very
different meaning, and would break builtin mDNS for anyone doing
DNSSEC right (which requires validating nameserver on localhost).
Inventing a knob that's an overload of an existing knob is still
inventing a knob, just worse.

> > > When you do that, how do you control which interface(s) it goes over?
> > > > I think that's an important missing ingredient.
> > >
> > > You're absolutely right. In IPv4, sending to a link-local multicast
> > address
> > > like this will send it over the IPv4 default route interface. In IPv6,
> > the
> > > interface needs to be specified in the scope_id. So we'd need to pull
> > that
> > > out of the kernel with rtnetlink.
> >
> > There's already code to enumerate interfaces, but it's a decent bit of
> > additional machinery to pull in as a dep for the stub resolver,
> 
> 
> Yeah we'd need lookup_name.c to include netlink.h - it's not huge though,
> netlink.c is 50 lines long and statically linked anyway right?

I was thinking in terms of using if_nameindex or something, but indeed
that's not desirable because it's allocating. So it looks like it
wouldn't share code but use netlink.c directly if it were done this
way.

BTW if there's a legacy ioctl that tells you the number of interfaces
(scope_ids), it sems like you could just iterate over the whole
numeric range without actually doing netlink enumeration.

> > and
> > it's not clear how to do it properly for IPv4 (do scope ids work with
> > v4-mapped addresses by any chance?)
> >
> 
> Scope IDs unfortunately don't work for IPv4. There's the SO_BINDTODEVICE
> socket option, but that requires elevated privileges. For IPv4 I'd just use
> the default route interface.

But the default route interface is almost surely *not* the LAN where
you expect .local things to live except in the case where there is
only one interface. If you have a network that's segmented into
separate LAN and outgoing interfaces, the LAN, not the route to the
public internet, is where you would want mDNS going.

With that said, SO_BINDTODEVICE is not the standard way to do this,
and the correct/standard way doesn't need root. What it does need is
binding to the local address on each device, which is still rather
undesirable because it means you need N sockets for N interfaces,
rather than one socket that can send/receive all addresses.

You answered for v4, but are you sure scope ids don't work for
*v4-mapped*? That is, IPv6 addresses of the form
::ffff:aaa.bbb.ccc.ddd. I guess I could check this. I'm not very
hopeful, but it would be excellent if this worked to send v4 multicast
to a particular interface.

> Another issue you haven't mentioned: how does TCP fallback work with
> > mDNS? Or are answers too large for standard UDP replies just illegal?
> >
> 
> Good point, I hadn't thought of that. That handling for mDNS is defined in
> [1]. In the ephemeral query mode that we'd use here, it works the same as
> for regular DNS: when you receive a response with the TC bit, retry the
> query with TCP. The slight difference is that you send the TCP to the
> address you got the response from (not to the multicast address that you
> sent the original query to). From looking at the musl code, we'd need a
> small tweak to __res_msend_rc() to use that address. Luckily that code
> already looks at the sender address so we don't need any additional calls
> to get it.

Yes, that's what I figured you might do. I guess that works reasonably
well.

> > > Reason for that is that that is the most generic way to support any
> > > > other name service besides DNS. It avoids the dependency on dynamic
> > > > loading that something like glibc's nsswitch would create, and would
> > > > avoid having multiple backends in libc. I really don't think anyone
> > > > wants to open that particular door. Once mDNS is in there, someone will
> > > > add NetBIOS, just you wait.
> > >
> > >
> > > I'm definitely supportive of the slippery slope argument, but I think
> > > there's still a real line between mDNS and NetBIOS. mDNS uses a different
> > > transport but lives inside the DNS namespace, whereas NetBIOS is really
> > its
> > > own thing - NetBIOS names aren't valid DNS hostnames.
> > >
> > > Let me know what you think of the above. If you think of mDNS as its own
> > > beast then I can see how including it wouldn't really make sense. But if
> > > you see it as an actual part of the DNS, then it might be worth a small
> > > code change :-)
> >
> > I'm not worried about slippery slopes to NetBIOS. :-P I am concerned
> > about unwanted network traffic that can't be suppressed, privacy
> > leaks, inventing new configuration knobs, potentially pulling in more
> > code & more fragility, getting stuck supporting something that turns
> > out to have hidden problems we haven't thought about, etc.
> >
> 
> Those are great reasons, and I totally agree with those goals. If we scope
> the problem down with the details higher up in this email, we have a way to
> turn this off (set the resolver to localhost), we avoid privacy leaks in
> cases where the traffic wasn't going out in the first place, we don't have
> to add more configuration knobs because we're reusing an existing one, and

As mentioned above, I don't think "reusing an existing one" is an
improvement.

> the amount of added code would be quite small. Limiting things to the
> default interface isn't a full multi-network solution, but for those I
> think it makes more sense to recommend running your own resolver on
> loopback (you'd need elevated privileges to make this work fully anyway).
> Coding wise, I think this would be pretty robust. The only breakage I
> foresee is cases where someone built a custom resolver that runs on a
> different machine and somehow handles .local differently than what the RFCs
> say. That config sounds like a bad idea, and a violation of the RFCs, but
> that doesn't mean there isn't someone somewhere who's doing it. So there's
> a non-zero risk there. But to me that's manageable risk.
> 
> What do you think?

I think a more reasonable approach might be requiring an explicit knob
to enable mDNS, in the form of an options field like ndots, timeout,
retries, etc. in resolv.conf. This ensures that it doesn't become
attack surface/change-of-behavior in network environments where peers
are not supposed to be able to define network names.

One further advantage of such an approach is that it could also solve
the "which interface(s)" problem by letting the answer just be
"whichever one(s) the user configured" (with the default list being
empty). That way we wouldn't even need netlink, just if_nametoindex to
convert interface name strings to scope ids, or alternatively (does
this work for v6 in the absence of an explicit scope_id?) one or more
local addresses to bind and send from.

Rich

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-08  0:08         ` Rich Felker
@ 2024-03-08  1:30           ` David Schinazi
  2024-03-08  2:06             ` David Schinazi
  2024-03-08  2:52             ` Rich Felker
  0 siblings, 2 replies; 32+ messages in thread
From: David Schinazi @ 2024-03-08  1:30 UTC (permalink / raw)
  To: Rich Felker; +Cc: musl

[-- Attachment #1: Type: text/plain, Size: 13959 bytes --]

On Thu, Mar 7, 2024 at 4:08 PM Rich Felker <dalias@libc.org> wrote:

> On Thu, Mar 07, 2024 at 02:50:53PM -0800, David Schinazi wrote:
> > On Wed, Mar 6, 2024 at 6:42 PM Rich Felker <dalias@libc.org> wrote:
> >
> > > On Wed, Mar 06, 2024 at 04:17:44PM -0800, David Schinazi wrote:
> > > > As Jeffrey points out, when the IETF decided to standardize mDNS,
> they
> > > > published it (RFC 6762) at the same time as the Special-Use Domain
> > > Registry
> > > > (RFC 6761) which created a process for reserving domain names for
> custom
> > > > purposes, and ".local" was one of the initial entries into that
> registry.
> > > > The UTF-8 vs punycode issue when it comes to mDNS and DNS is
> somewhat of
> > > a
> > > > mess. It was discussed in Section 16 of RFC 6762 but at the end of
> the
> > > day
> > > > punycode won. Even Apple's implementation of getaddrinfo will perform
> > > > punycode conversion for .local instead of sending the UTF-8. So in
> > > practice
> > > > you wouldn't need to special-case anything here.
> > >
> > > OK, these are both really good news!
> > >
> > > > There's also very much a policy matter of what "locally over
> > > > > multicast" means (what the user wants it to mean). Which interfaces
> > > > > should be queried? Wired and wireless ethernet? VPN links or other
> > > > > sorts of tunnels? Just one local interface (which one to
> prioritize)
> > > > > or all of them? Only if the network is "trusted"? Etc.
> > > > >
> > > >
> > > > You're absolutely right. Most mDNS systems try all non-loopback
> non-p2p
> > > > multicast-supporting interfaces, but sending to the default route
> > > interface
> > > > would be a good start, more on that below.
> > >
> > > This is really one thing that suggests a need for configurability
> > > outside of what libc might be able to offer. With normal DNS lookups,
> > > they're something you can block off and prevent from going to the
> > > network at all by policy (and in fact they don't go past the loopback
> > > by default, in the absence of a resolv.conf file). Adding mDNS that's
> > > on-by-default and not configurable would make a vector for network
> > > traffic being generated that's probably not expected and that could be
> > > a privacy leak.
> > >
> >
> > Totally agree. I was thinking through this both in terms of RFCs and in
> > terms of minimal code changes, and had a potential idea. Conceptually,
> > sending DNS to localhost is musl's IPC mechanism to a more feature-rich
> > resolver running in user-space. So when that's happening, we don't want
> to
> > mess with it because that could cause a privacy leak. Conversely, when
> > there's a non-loopback IP configured in resolv.conf, then musl acts as a
> > DNS stub resolver and the server in resolv.conf acts as a DNS recursive
> > resolver. In that scenario, sending the .local query over DNS to that
> other
> > host violates the RFCs. This allows us to treat the configured resolver
> > address as an implicit configuration mechanism that allows us to
> > selectively enable this without impacting anyone doing their own DNS
> > locally.
>
> This sounds like an odd overloading of one thing to have a very
> different meaning, and would break builtin mDNS for anyone doing
> DNSSEC right (which requires validating nameserver on localhost).
> Inventing a knob that's an overload of an existing knob is still
> inventing a knob, just worse.
>

Sorry, I was suggesting the other way around: to only enable the mDNS mode
if resolver != 127.0.0.1. But on the topic of DNSSEC, that doesn't really
make sense in the context of mDNS because the names aren't globally unique
and signed. In theory you could exchange DNSSEC keys out of band and use
DNSSEC with mDNS, but I've never heard of anyone doing that. At that point
people exchange TLS certificates out of band and use mTLS. But overall I
can't argue that overloading configs to mean multiple things is janky :-)

> > > When you do that, how do you control which interface(s) it goes over?
> > > > > I think that's an important missing ingredient.
> > > >
> > > > You're absolutely right. In IPv4, sending to a link-local multicast
> > > address
> > > > like this will send it over the IPv4 default route interface. In
> IPv6,
> > > the
> > > > interface needs to be specified in the scope_id. So we'd need to pull
> > > that
> > > > out of the kernel with rtnetlink.
> > >
> > > There's already code to enumerate interfaces, but it's a decent bit of
> > > additional machinery to pull in as a dep for the stub resolver,
> >
> >
> > Yeah we'd need lookup_name.c to include netlink.h - it's not huge though,
> > netlink.c is 50 lines long and statically linked anyway right?
>
> I was thinking in terms of using if_nameindex or something, but indeed
> that's not desirable because it's allocating. So it looks like it
> wouldn't share code but use netlink.c directly if it were done this
> way.
>
> BTW if there's a legacy ioctl that tells you the number of interfaces
> (scope_ids), it sems like you could just iterate over the whole
> numeric range without actually doing netlink enumeration.
>

That would also work. The main limitation I was working around was that you
can only pass around MAXNS (3) name servers around without making more
changes.

> > and
> > > it's not clear how to do it properly for IPv4 (do scope ids work with
> > > v4-mapped addresses by any chance?)
> > >
> >
> > Scope IDs unfortunately don't work for IPv4. There's the SO_BINDTODEVICE
> > socket option, but that requires elevated privileges. For IPv4 I'd just
> use
> > the default route interface.
>
> But the default route interface is almost surely *not* the LAN where
> you expect .local things to live except in the case where there is
> only one interface. If you have a network that's segmented into
> separate LAN and outgoing interfaces, the LAN, not the route to the
> public internet, is where you would want mDNS going.
>

In the case of a router, definitely. In the case of most end hosts or VMs
though, they often have only one or two routable interfaces, and the
default route is also the LAN.

With that said, SO_BINDTODEVICE is not the standard way to do this,
> and the correct/standard way doesn't need root. What it does need is
> binding to the local address on each device, which is still rather
> undesirable because it means you need N sockets for N interfaces,
> rather than one socket that can send/receive all addresses.
>

Oh you're absolutely right, I knew there was a non-privileged way to do
this but couldn't remember it earlier.

This is giving me an idea though: we could use the "connect UDP socket to
get a route lookup" trick. Let's say we're configured with a nameserver
that's not 127.0.0.1 (which is the case where I'd like to enable this)
let's say the nameserver is set to 192.0.2.33, then today foobar.local
would be sent to 192.0.2.33 over whichever interface has a route to it (in
most cases the default interface, but not always). We could open an
AF_INET/SOCK_DGRAM socket, connect it to 192.0.2.33:53, and then
use getsockname to get the local address - we then close that socket. We
can then create a new socket, bind it to that local address. That would
ensure that we send the mDNS traffic on the same interface where we would
have sent the unicast query. Downside is that since all queries share the
same socket, we'd bind everything to the interface of the first resolver,
or need multiple sockets.

You answered for v4, but are you sure scope ids don't work for
> *v4-mapped*? That is, IPv6 addresses of the form
> ::ffff:aaa.bbb.ccc.ddd. I guess I could check this. I'm not very
> hopeful, but it would be excellent if this worked to send v4 multicast
> to a particular interface.
>

Huh I hadn't thought of that, worth a try? RFC 4007 doesn't really allow
using scope IDs for globally routable addresses but I'm not sure if Linux
does.

> Another issue you haven't mentioned: how does TCP fallback work with
> > > mDNS? Or are answers too large for standard UDP replies just illegal?
> > >
> >
> > Good point, I hadn't thought of that. That handling for mDNS is defined
> in
> > [1]. In the ephemeral query mode that we'd use here, it works the same as
> > for regular DNS: when you receive a response with the TC bit, retry the
> > query with TCP. The slight difference is that you send the TCP to the
> > address you got the response from (not to the multicast address that you
> > sent the original query to). From looking at the musl code, we'd need a
> > small tweak to __res_msend_rc() to use that address. Luckily that code
> > already looks at the sender address so we don't need any additional calls
> > to get it.
>
> Yes, that's what I figured you might do. I guess that works reasonably
> well.
>
> > > > Reason for that is that that is the most generic way to support any
> > > > > other name service besides DNS. It avoids the dependency on dynamic
> > > > > loading that something like glibc's nsswitch would create, and
> would
> > > > > avoid having multiple backends in libc. I really don't think anyone
> > > > > wants to open that particular door. Once mDNS is in there, someone
> will
> > > > > add NetBIOS, just you wait.
> > > >
> > > >
> > > > I'm definitely supportive of the slippery slope argument, but I think
> > > > there's still a real line between mDNS and NetBIOS. mDNS uses a
> different
> > > > transport but lives inside the DNS namespace, whereas NetBIOS is
> really
> > > its
> > > > own thing - NetBIOS names aren't valid DNS hostnames.
> > > >
> > > > Let me know what you think of the above. If you think of mDNS as its
> own
> > > > beast then I can see how including it wouldn't really make sense.
> But if
> > > > you see it as an actual part of the DNS, then it might be worth a
> small
> > > > code change :-)
> > >
> > > I'm not worried about slippery slopes to NetBIOS. :-P I am concerned
> > > about unwanted network traffic that can't be suppressed, privacy
> > > leaks, inventing new configuration knobs, potentially pulling in more
> > > code & more fragility, getting stuck supporting something that turns
> > > out to have hidden problems we haven't thought about, etc.
> > >
> >
> > Those are great reasons, and I totally agree with those goals. If we
> scope
> > the problem down with the details higher up in this email, we have a way
> to
> > turn this off (set the resolver to localhost), we avoid privacy leaks in
> > cases where the traffic wasn't going out in the first place, we don't
> have
> > to add more configuration knobs because we're reusing an existing one,
> and
>
> As mentioned above, I don't think "reusing an existing one" is an
> improvement.
>

Fair, my goal was minimizing change size, but that's not the only goal.

> the amount of added code would be quite small. Limiting things to the
> > default interface isn't a full multi-network solution, but for those I
> > think it makes more sense to recommend running your own resolver on
> > loopback (you'd need elevated privileges to make this work fully anyway).
> > Coding wise, I think this would be pretty robust. The only breakage I
> > foresee is cases where someone built a custom resolver that runs on a
> > different machine and somehow handles .local differently than what the
> RFCs
> > say. That config sounds like a bad idea, and a violation of the RFCs, but
> > that doesn't mean there isn't someone somewhere who's doing it. So
> there's
> > a non-zero risk there. But to me that's manageable risk.
> >
> > What do you think?
>
> I think a more reasonable approach might be requiring an explicit knob
> to enable mDNS, in the form of an options field like ndots, timeout,
> retries, etc. in resolv.conf. This ensures that it doesn't become
> attack surface/change-of-behavior in network environments where peers
> are not supposed to be able to define network names.
>

That would work. I'm not sure who maintains the list of options though.
From a quick search it looks like they came out of 4.3BSD like many
networking features, but it's unclear if POSIX owns it or just no one does
(which would be the same, POSIX is not around as a standard body any more).

One further advantage of such an approach is that it could also solve
> the "which interface(s)" problem by letting the answer just be
> "whichever one(s) the user configured" (with the default list being
> empty). That way we wouldn't even need netlink, just if_nametoindex to
> convert interface name strings to scope ids, or alternatively (does
> this work for v6 in the absence of an explicit scope_id?) one or more
> local addresses to bind and send from.
>

I definitely would avoid putting local addresses in the config, because it
would break for any non-static addresses like DHCP or v6 RAs. The interface
name would require walking the getifaddrs list to map it to a corresponding
source address but it would work if the interface name is stable.

I guess we're looking at two ways to go about this:

(1) the simpler but less clean option - where we key off of "resolver !=
127.0.0.1" - very limited code size change, but only handles a small subset
of scenarios

(2) the cleaner option that involves more work - new config option, need
multiple sockets - would be cleaner design-wise, but would change quite a
bit more code

Another aspect to consider is the fact that in a lot of cases resolv.conf
is overwritten by various components like NetworkManager, so we'd need to
modify them to also understand the option.

I'm always in favor of doing the right thing, unless the right thing ends
up being so much effort that it doesn't happen. Then I'm a fan of doing the
easy thing ;-)

David

[-- Attachment #2: Type: text/html, Size: 17216 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-08  1:30           ` David Schinazi
@ 2024-03-08  2:06             ` David Schinazi
  2024-03-08  2:52             ` Rich Felker
  1 sibling, 0 replies; 32+ messages in thread
From: David Schinazi @ 2024-03-08  2:06 UTC (permalink / raw)
  To: Rich Felker; +Cc: musl

[-- Attachment #1: Type: text/plain, Size: 14639 bytes --]

Oh, one more thing: we might be able to use sendmsg and IP_PKTINFO to
select the outgoing interface for each send call instead of binding and
requiring multiple sockets.
David

On Thu, Mar 7, 2024 at 5:30 PM David Schinazi <dschinazi.ietf@gmail.com>
wrote:

>
>
> On Thu, Mar 7, 2024 at 4:08 PM Rich Felker <dalias@libc.org> wrote:
>
>> On Thu, Mar 07, 2024 at 02:50:53PM -0800, David Schinazi wrote:
>> > On Wed, Mar 6, 2024 at 6:42 PM Rich Felker <dalias@libc.org> wrote:
>> >
>> > > On Wed, Mar 06, 2024 at 04:17:44PM -0800, David Schinazi wrote:
>> > > > As Jeffrey points out, when the IETF decided to standardize mDNS,
>> they
>> > > > published it (RFC 6762) at the same time as the Special-Use Domain
>> > > Registry
>> > > > (RFC 6761) which created a process for reserving domain names for
>> custom
>> > > > purposes, and ".local" was one of the initial entries into that
>> registry.
>> > > > The UTF-8 vs punycode issue when it comes to mDNS and DNS is
>> somewhat of
>> > > a
>> > > > mess. It was discussed in Section 16 of RFC 6762 but at the end of
>> the
>> > > day
>> > > > punycode won. Even Apple's implementation of getaddrinfo will
>> perform
>> > > > punycode conversion for .local instead of sending the UTF-8. So in
>> > > practice
>> > > > you wouldn't need to special-case anything here.
>> > >
>> > > OK, these are both really good news!
>> > >
>> > > > There's also very much a policy matter of what "locally over
>> > > > > multicast" means (what the user wants it to mean). Which
>> interfaces
>> > > > > should be queried? Wired and wireless ethernet? VPN links or other
>> > > > > sorts of tunnels? Just one local interface (which one to
>> prioritize)
>> > > > > or all of them? Only if the network is "trusted"? Etc.
>> > > > >
>> > > >
>> > > > You're absolutely right. Most mDNS systems try all non-loopback
>> non-p2p
>> > > > multicast-supporting interfaces, but sending to the default route
>> > > interface
>> > > > would be a good start, more on that below.
>> > >
>> > > This is really one thing that suggests a need for configurability
>> > > outside of what libc might be able to offer. With normal DNS lookups,
>> > > they're something you can block off and prevent from going to the
>> > > network at all by policy (and in fact they don't go past the loopback
>> > > by default, in the absence of a resolv.conf file). Adding mDNS that's
>> > > on-by-default and not configurable would make a vector for network
>> > > traffic being generated that's probably not expected and that could be
>> > > a privacy leak.
>> > >
>> >
>> > Totally agree. I was thinking through this both in terms of RFCs and in
>> > terms of minimal code changes, and had a potential idea. Conceptually,
>> > sending DNS to localhost is musl's IPC mechanism to a more feature-rich
>> > resolver running in user-space. So when that's happening, we don't want
>> to
>> > mess with it because that could cause a privacy leak. Conversely, when
>> > there's a non-loopback IP configured in resolv.conf, then musl acts as a
>> > DNS stub resolver and the server in resolv.conf acts as a DNS recursive
>> > resolver. In that scenario, sending the .local query over DNS to that
>> other
>> > host violates the RFCs. This allows us to treat the configured resolver
>> > address as an implicit configuration mechanism that allows us to
>> > selectively enable this without impacting anyone doing their own DNS
>> > locally.
>>
>> This sounds like an odd overloading of one thing to have a very
>> different meaning, and would break builtin mDNS for anyone doing
>> DNSSEC right (which requires validating nameserver on localhost).
>> Inventing a knob that's an overload of an existing knob is still
>> inventing a knob, just worse.
>>
>
> Sorry, I was suggesting the other way around: to only enable the mDNS mode
> if resolver != 127.0.0.1. But on the topic of DNSSEC, that doesn't really
> make sense in the context of mDNS because the names aren't globally unique
> and signed. In theory you could exchange DNSSEC keys out of band and use
> DNSSEC with mDNS, but I've never heard of anyone doing that. At that point
> people exchange TLS certificates out of band and use mTLS. But overall I
> can't argue that overloading configs to mean multiple things is janky :-)
>
> > > > When you do that, how do you control which interface(s) it goes over?
>> > > > > I think that's an important missing ingredient.
>> > > >
>> > > > You're absolutely right. In IPv4, sending to a link-local multicast
>> > > address
>> > > > like this will send it over the IPv4 default route interface. In
>> IPv6,
>> > > the
>> > > > interface needs to be specified in the scope_id. So we'd need to
>> pull
>> > > that
>> > > > out of the kernel with rtnetlink.
>> > >
>> > > There's already code to enumerate interfaces, but it's a decent bit of
>> > > additional machinery to pull in as a dep for the stub resolver,
>> >
>> >
>> > Yeah we'd need lookup_name.c to include netlink.h - it's not huge
>> though,
>> > netlink.c is 50 lines long and statically linked anyway right?
>>
>> I was thinking in terms of using if_nameindex or something, but indeed
>> that's not desirable because it's allocating. So it looks like it
>> wouldn't share code but use netlink.c directly if it were done this
>> way.
>>
>> BTW if there's a legacy ioctl that tells you the number of interfaces
>> (scope_ids), it sems like you could just iterate over the whole
>> numeric range without actually doing netlink enumeration.
>>
>
> That would also work. The main limitation I was working around was that
> you can only pass around MAXNS (3) name servers around without making more
> changes.
>
> > > and
>> > > it's not clear how to do it properly for IPv4 (do scope ids work with
>> > > v4-mapped addresses by any chance?)
>> > >
>> >
>> > Scope IDs unfortunately don't work for IPv4. There's the SO_BINDTODEVICE
>> > socket option, but that requires elevated privileges. For IPv4 I'd just
>> use
>> > the default route interface.
>>
>> But the default route interface is almost surely *not* the LAN where
>> you expect .local things to live except in the case where there is
>> only one interface. If you have a network that's segmented into
>> separate LAN and outgoing interfaces, the LAN, not the route to the
>> public internet, is where you would want mDNS going.
>>
>
> In the case of a router, definitely. In the case of most end hosts or VMs
> though, they often have only one or two routable interfaces, and the
> default route is also the LAN.
>
> With that said, SO_BINDTODEVICE is not the standard way to do this,
>> and the correct/standard way doesn't need root. What it does need is
>> binding to the local address on each device, which is still rather
>> undesirable because it means you need N sockets for N interfaces,
>> rather than one socket that can send/receive all addresses.
>>
>
> Oh you're absolutely right, I knew there was a non-privileged way to do
> this but couldn't remember it earlier.
>
> This is giving me an idea though: we could use the "connect UDP socket to
> get a route lookup" trick. Let's say we're configured with a nameserver
> that's not 127.0.0.1 (which is the case where I'd like to enable this)
> let's say the nameserver is set to 192.0.2.33, then today foobar.local
> would be sent to 192.0.2.33 over whichever interface has a route to it (in
> most cases the default interface, but not always). We could open an
> AF_INET/SOCK_DGRAM socket, connect it to 192.0.2.33:53, and then
> use getsockname to get the local address - we then close that socket. We
> can then create a new socket, bind it to that local address. That would
> ensure that we send the mDNS traffic on the same interface where we would
> have sent the unicast query. Downside is that since all queries share the
> same socket, we'd bind everything to the interface of the first resolver,
> or need multiple sockets.
>
> You answered for v4, but are you sure scope ids don't work for
>> *v4-mapped*? That is, IPv6 addresses of the form
>> ::ffff:aaa.bbb.ccc.ddd. I guess I could check this. I'm not very
>> hopeful, but it would be excellent if this worked to send v4 multicast
>> to a particular interface.
>>
>
> Huh I hadn't thought of that, worth a try? RFC 4007 doesn't really allow
> using scope IDs for globally routable addresses but I'm not sure if Linux
> does.
>
> > Another issue you haven't mentioned: how does TCP fallback work with
>> > > mDNS? Or are answers too large for standard UDP replies just illegal?
>> > >
>> >
>> > Good point, I hadn't thought of that. That handling for mDNS is defined
>> in
>> > [1]. In the ephemeral query mode that we'd use here, it works the same
>> as
>> > for regular DNS: when you receive a response with the TC bit, retry the
>> > query with TCP. The slight difference is that you send the TCP to the
>> > address you got the response from (not to the multicast address that you
>> > sent the original query to). From looking at the musl code, we'd need a
>> > small tweak to __res_msend_rc() to use that address. Luckily that code
>> > already looks at the sender address so we don't need any additional
>> calls
>> > to get it.
>>
>> Yes, that's what I figured you might do. I guess that works reasonably
>> well.
>>
>> > > > Reason for that is that that is the most generic way to support any
>> > > > > other name service besides DNS. It avoids the dependency on
>> dynamic
>> > > > > loading that something like glibc's nsswitch would create, and
>> would
>> > > > > avoid having multiple backends in libc. I really don't think
>> anyone
>> > > > > wants to open that particular door. Once mDNS is in there,
>> someone will
>> > > > > add NetBIOS, just you wait.
>> > > >
>> > > >
>> > > > I'm definitely supportive of the slippery slope argument, but I
>> think
>> > > > there's still a real line between mDNS and NetBIOS. mDNS uses a
>> different
>> > > > transport but lives inside the DNS namespace, whereas NetBIOS is
>> really
>> > > its
>> > > > own thing - NetBIOS names aren't valid DNS hostnames.
>> > > >
>> > > > Let me know what you think of the above. If you think of mDNS as
>> its own
>> > > > beast then I can see how including it wouldn't really make sense.
>> But if
>> > > > you see it as an actual part of the DNS, then it might be worth a
>> small
>> > > > code change :-)
>> > >
>> > > I'm not worried about slippery slopes to NetBIOS. :-P I am concerned
>> > > about unwanted network traffic that can't be suppressed, privacy
>> > > leaks, inventing new configuration knobs, potentially pulling in more
>> > > code & more fragility, getting stuck supporting something that turns
>> > > out to have hidden problems we haven't thought about, etc.
>> > >
>> >
>> > Those are great reasons, and I totally agree with those goals. If we
>> scope
>> > the problem down with the details higher up in this email, we have a
>> way to
>> > turn this off (set the resolver to localhost), we avoid privacy leaks in
>> > cases where the traffic wasn't going out in the first place, we don't
>> have
>> > to add more configuration knobs because we're reusing an existing one,
>> and
>>
>> As mentioned above, I don't think "reusing an existing one" is an
>> improvement.
>>
>
> Fair, my goal was minimizing change size, but that's not the only goal.
>
> > the amount of added code would be quite small. Limiting things to the
>> > default interface isn't a full multi-network solution, but for those I
>> > think it makes more sense to recommend running your own resolver on
>> > loopback (you'd need elevated privileges to make this work fully
>> anyway).
>> > Coding wise, I think this would be pretty robust. The only breakage I
>> > foresee is cases where someone built a custom resolver that runs on a
>> > different machine and somehow handles .local differently than what the
>> RFCs
>> > say. That config sounds like a bad idea, and a violation of the RFCs,
>> but
>> > that doesn't mean there isn't someone somewhere who's doing it. So
>> there's
>> > a non-zero risk there. But to me that's manageable risk.
>> >
>> > What do you think?
>>
>> I think a more reasonable approach might be requiring an explicit knob
>> to enable mDNS, in the form of an options field like ndots, timeout,
>> retries, etc. in resolv.conf. This ensures that it doesn't become
>> attack surface/change-of-behavior in network environments where peers
>> are not supposed to be able to define network names.
>>
>
> That would work. I'm not sure who maintains the list of options though.
> From a quick search it looks like they came out of 4.3BSD like many
> networking features, but it's unclear if POSIX owns it or just no one does
> (which would be the same, POSIX is not around as a standard body any more).
>
> One further advantage of such an approach is that it could also solve
>> the "which interface(s)" problem by letting the answer just be
>> "whichever one(s) the user configured" (with the default list being
>> empty). That way we wouldn't even need netlink, just if_nametoindex to
>> convert interface name strings to scope ids, or alternatively (does
>> this work for v6 in the absence of an explicit scope_id?) one or more
>> local addresses to bind and send from.
>>
>
> I definitely would avoid putting local addresses in the config, because it
> would break for any non-static addresses like DHCP or v6 RAs. The interface
> name would require walking the getifaddrs list to map it to a corresponding
> source address but it would work if the interface name is stable.
>
> I guess we're looking at two ways to go about this:
>
> (1) the simpler but less clean option - where we key off of "resolver !=
> 127.0.0.1" - very limited code size change, but only handles a small subset
> of scenarios
>
> (2) the cleaner option that involves more work - new config option, need
> multiple sockets - would be cleaner design-wise, but would change quite a
> bit more code
>
> Another aspect to consider is the fact that in a lot of cases resolv.conf
> is overwritten by various components like NetworkManager, so we'd need to
> modify them to also understand the option.
>
> I'm always in favor of doing the right thing, unless the right thing ends
> up being so much effort that it doesn't happen. Then I'm a fan of doing the
> easy thing ;-)
>
> David
>

[-- Attachment #2: Type: text/html, Size: 17802 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-08  1:30           ` David Schinazi
  2024-03-08  2:06             ` David Schinazi
@ 2024-03-08  2:52             ` Rich Felker
  2024-03-08  3:34               ` David Schinazi
  1 sibling, 1 reply; 32+ messages in thread
From: Rich Felker @ 2024-03-08  2:52 UTC (permalink / raw)
  To: David Schinazi; +Cc: musl

On Thu, Mar 07, 2024 at 05:30:06PM -0800, David Schinazi wrote:
> On Thu, Mar 7, 2024 at 4:08 PM Rich Felker <dalias@libc.org> wrote:
> 
> > On Thu, Mar 07, 2024 at 02:50:53PM -0800, David Schinazi wrote:
> > > On Wed, Mar 6, 2024 at 6:42 PM Rich Felker <dalias@libc.org> wrote:
> > >
> > > > On Wed, Mar 06, 2024 at 04:17:44PM -0800, David Schinazi wrote:
> > > > > As Jeffrey points out, when the IETF decided to standardize mDNS,
> > they
> > > > > published it (RFC 6762) at the same time as the Special-Use Domain
> > > > Registry
> > > > > (RFC 6761) which created a process for reserving domain names for
> > custom
> > > > > purposes, and ".local" was one of the initial entries into that
> > registry.
> > > > > The UTF-8 vs punycode issue when it comes to mDNS and DNS is
> > somewhat of
> > > > a
> > > > > mess. It was discussed in Section 16 of RFC 6762 but at the end of
> > the
> > > > day
> > > > > punycode won. Even Apple's implementation of getaddrinfo will perform
> > > > > punycode conversion for .local instead of sending the UTF-8. So in
> > > > practice
> > > > > you wouldn't need to special-case anything here.
> > > >
> > > > OK, these are both really good news!
> > > >
> > > > > There's also very much a policy matter of what "locally over
> > > > > > multicast" means (what the user wants it to mean). Which interfaces
> > > > > > should be queried? Wired and wireless ethernet? VPN links or other
> > > > > > sorts of tunnels? Just one local interface (which one to
> > prioritize)
> > > > > > or all of them? Only if the network is "trusted"? Etc.
> > > > > >
> > > > >
> > > > > You're absolutely right. Most mDNS systems try all non-loopback
> > non-p2p
> > > > > multicast-supporting interfaces, but sending to the default route
> > > > interface
> > > > > would be a good start, more on that below.
> > > >
> > > > This is really one thing that suggests a need for configurability
> > > > outside of what libc might be able to offer. With normal DNS lookups,
> > > > they're something you can block off and prevent from going to the
> > > > network at all by policy (and in fact they don't go past the loopback
> > > > by default, in the absence of a resolv.conf file). Adding mDNS that's
> > > > on-by-default and not configurable would make a vector for network
> > > > traffic being generated that's probably not expected and that could be
> > > > a privacy leak.
> > > >
> > >
> > > Totally agree. I was thinking through this both in terms of RFCs and in
> > > terms of minimal code changes, and had a potential idea. Conceptually,
> > > sending DNS to localhost is musl's IPC mechanism to a more feature-rich
> > > resolver running in user-space. So when that's happening, we don't want
> > to
> > > mess with it because that could cause a privacy leak. Conversely, when
> > > there's a non-loopback IP configured in resolv.conf, then musl acts as a
> > > DNS stub resolver and the server in resolv.conf acts as a DNS recursive
> > > resolver. In that scenario, sending the .local query over DNS to that
> > other
> > > host violates the RFCs. This allows us to treat the configured resolver
> > > address as an implicit configuration mechanism that allows us to
> > > selectively enable this without impacting anyone doing their own DNS
> > > locally.
> >
> > This sounds like an odd overloading of one thing to have a very
> > different meaning, and would break builtin mDNS for anyone doing
> > DNSSEC right (which requires validating nameserver on localhost).
> > Inventing a knob that's an overload of an existing knob is still
> > inventing a knob, just worse.
> >
> 
> Sorry, I was suggesting the other way around: to only enable the mDNS mode
> if resolver != 127.0.0.1.

I understood that. It's still overloading a knob.

> But on the topic of DNSSEC, that doesn't really
> make sense in the context of mDNS because the names aren't globally unique
> and signed. In theory you could exchange DNSSEC keys out of band and use
> DNSSEC with mDNS, but I've never heard of anyone doing that. At that point
> people exchange TLS certificates out of band and use mTLS. But overall I
> can't argue that overloading configs to mean multiple things is janky :-)

I'm not talking about validating DNSSEC for .local (which seems
nonsensical, but I guess is actually something you could do with your
own trust anchor for .local that would prevent rogue devices on your
network from being able to answer mDNS).

I'm talking about how anyone properly validating DNSSEC for the global
DNS space has to have a nameserver on localhost, and how this would
prevent them from using mDNS (or, in effect, disincentivize setting up
DNSSEC validation since it would break your mDNS) via the builtin libc
stub resolver support and would require wiring up the validating
nameserver to it.

> > > > When you do that, how do you control which interface(s) it goes over?
> > > > > > I think that's an important missing ingredient.
> > > > >
> > > > > You're absolutely right. In IPv4, sending to a link-local multicast
> > > > address
> > > > > like this will send it over the IPv4 default route interface. In
> > IPv6,
> > > > the
> > > > > interface needs to be specified in the scope_id. So we'd need to pull
> > > > that
> > > > > out of the kernel with rtnetlink.
> > > >
> > > > There's already code to enumerate interfaces, but it's a decent bit of
> > > > additional machinery to pull in as a dep for the stub resolver,
> > >
> > >
> > > Yeah we'd need lookup_name.c to include netlink.h - it's not huge though,
> > > netlink.c is 50 lines long and statically linked anyway right?
> >
> > I was thinking in terms of using if_nameindex or something, but indeed
> > that's not desirable because it's allocating. So it looks like it
> > wouldn't share code but use netlink.c directly if it were done this
> > way.
> >
> > BTW if there's a legacy ioctl that tells you the number of interfaces
> > (scope_ids), it sems like you could just iterate over the whole
> > numeric range without actually doing netlink enumeration.
> 
> That would also work. The main limitation I was working around was that you
> can only pass around MAXNS (3) name servers around without making more
> changes.

Yes, there's no reason to assume the first 3 interfaces found would
suffice though. I think the way to handle this would be to treat the
multicast address as just one nameserver in the list, and have
__res_msend do whatever sort of iteration it needs to do when the
resolvconf structure indicates that it's for mDNS.

> > > > it's not clear how to do it properly for IPv4 (do scope ids work with
> > > > v4-mapped addresses by any chance?)
> > > >
> > >
> > > Scope IDs unfortunately don't work for IPv4. There's the SO_BINDTODEVICE
> > > socket option, but that requires elevated privileges. For IPv4 I'd just
> > use
> > > the default route interface.
> >
> > But the default route interface is almost surely *not* the LAN where
> > you expect .local things to live except in the case where there is
> > only one interface. If you have a network that's segmented into
> > separate LAN and outgoing interfaces, the LAN, not the route to the
> > public internet, is where you would want mDNS going.
> 
> In the case of a router, definitely. In the case of most end hosts or VMs
> though, they often have only one or two routable interfaces, and the
> default route is also the LAN.

Not necessarily a router; could just be a client device with multiple
routes. For example a default route that goes over a VPN and a LAN
route for accessing local machines.

> > With that said, SO_BINDTODEVICE is not the standard way to do this,
> > and the correct/standard way doesn't need root. What it does need is
> > binding to the local address on each device, which is still rather
> > undesirable because it means you need N sockets for N interfaces,
> > rather than one socket that can send/receive all addresses.
> 
> Oh you're absolutely right, I knew there was a non-privileged way to do
> this but couldn't remember it earlier.
> 
> This is giving me an idea though: we could use the "connect UDP socket to
> get a route lookup" trick. Let's say we're configured with a nameserver
> that's not 127.0.0.1 (which is the case where I'd like to enable this)
> let's say the nameserver is set to 192.0.2.33, then today foobar.local
> would be sent to 192.0.2.33 over whichever interface has a route to it (in
> most cases the default interface, but not always). We could open an
> AF_INET/SOCK_DGRAM socket, connect it to 192.0.2.33:53, and then
> use getsockname to get the local address - we then close that socket. We
> can then create a new socket, bind it to that local address. That would
> ensure that we send the mDNS traffic on the same interface where we would
> have sent the unicast query. Downside is that since all queries share the
> same socket, we'd bind everything to the interface of the first resolver,
> or need multiple sockets.

This again sounds like a bad "overloaded knob". Unless you're letting
DHCP overwrite your resolv.conf, there's no reason for the route to
the nameserver to match the LAN you want mDNS on.

> > the amount of added code would be quite small. Limiting things to the
> > > default interface isn't a full multi-network solution, but for those I
> > > think it makes more sense to recommend running your own resolver on
> > > loopback (you'd need elevated privileges to make this work fully anyway).
> > > Coding wise, I think this would be pretty robust. The only breakage I
> > > foresee is cases where someone built a custom resolver that runs on a
> > > different machine and somehow handles .local differently than what the
> > RFCs
> > > say. That config sounds like a bad idea, and a violation of the RFCs, but
> > > that doesn't mean there isn't someone somewhere who's doing it. So
> > there's
> > > a non-zero risk there. But to me that's manageable risk.
> > >
> > > What do you think?
> >
> > I think a more reasonable approach might be requiring an explicit knob
> > to enable mDNS, in the form of an options field like ndots, timeout,
> > retries, etc. in resolv.conf. This ensures that it doesn't become
> > attack surface/change-of-behavior in network environments where peers
> > are not supposed to be able to define network names.
> >
> 
> That would work. I'm not sure who maintains the list of options though.
> From a quick search it looks like they came out of 4.3BSD like many
> networking features, but it's unclear if POSIX owns it or just no one does
> (which would be the same, POSIX is not around as a standard body any more).

No one does. Basically anyone can freely add extensions, with the
caveat that if you have mutually incompatible extensions in
/etc/resolv.conf, someone using the same /etc with more than one stub
resolver implementation (like both musl and glibc) is going to have a
bad time.

If for example glibc were up for adding configuration for which
interfaces to do mdns on here, we could coordinate. But I suspect they
would put it in a config file specific to the nss module that does
mdns.

> One further advantage of such an approach is that it could also solve
> > the "which interface(s)" problem by letting the answer just be
> > "whichever one(s) the user configured" (with the default list being
> > empty). That way we wouldn't even need netlink, just if_nametoindex to
> > convert interface name strings to scope ids, or alternatively (does
> > this work for v6 in the absence of an explicit scope_id?) one or more
> > local addresses to bind and send from.
> >
> 
> I definitely would avoid putting local addresses in the config, because it
> would break for any non-static addresses like DHCP or v6 RAs. The interface
> name would require walking the getifaddrs list to map it to a corresponding
> source address but it would work if the interface name is stable.

I could see it being desirable to support both. For some folks, IP
addresses would be more stable; for others, interface names would.

Another variant would be letting you identify the network(s) to send
mDNS to via destination addresses, ala the "connect a UDP socket to
get a local address" technique you described above.

For IPv6 these are kinda equivalent. An address of fe80::%ifname (or
maybe fe80::1%ifname?) should let you specify "interface ifname" just
as a destination address.

I'm not necessarily saying we should do any or all of these, just that
they're possibilities to consider.

> I guess we're looking at two ways to go about this:
> 
> (1) the simpler but less clean option - where we key off of "resolver !=
> 127.0.0.1" - very limited code size change, but only handles a small subset
> of scenarios

I _really_ don't like this option. It violates least-surprise,
overloads one setting to mean something else based on a presumed usage
pattern, and worst of all, it makes a behavior whereby enabling DNSSEC
validation (by running your own validating nameserver on localhost)
breaks something else (mDNS) which will disincentivize DNSSEC
validation.

This is really the hidden cost of overloaded knobs in general: they
make situations where users are encouraged to change one setting in a
way they don't want because that's how they get the other thing they
do want.

> (2) the cleaner option that involves more work - new config option, need
> multiple sockets - would be cleaner design-wise, but would change quite a
> bit more code
> 
> Another aspect to consider is the fact that in a lot of cases resolv.conf
> is overwritten by various components like NetworkManager, so we'd need to
> modify them to also understand the option.

I think they already have support for pulling options from somewhere.
But that's a good question worth looking into: how you'd get the
necessary config in place, in the presence of
nm/dhdpcd/resolvconf/whatever overwriting resolv.conf.

> I'm always in favor of doing the right thing, unless the right thing ends
> up being so much effort that it doesn't happen. Then I'm a fan of doing the
> easy thing ;-)

Around here the fallback usually is "not doing it at all". :-p

Rich

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-08  2:52             ` Rich Felker
@ 2024-03-08  3:34               ` David Schinazi
  2024-03-08  3:47                 ` Rich Felker
  0 siblings, 1 reply; 32+ messages in thread
From: David Schinazi @ 2024-03-08  3:34 UTC (permalink / raw)
  To: Rich Felker; +Cc: musl

[-- Attachment #1: Type: text/plain, Size: 15818 bytes --]

Hmmm. The cleaner option with the new config option and support for
querying on all interfaces probably reaches a level of complexity where
running a resolver on localhost might be best. And I honestly agree with
your point that overloading the config option isn't great design. So
perhaps "not doing it at all" is the answer then. I'll think about it some
more, and discuss it with some mDNS experts at the next IETF meeting in a
couple weeks. I'll report back if someone has a clever idea that wouldn't
violate the design principles we've discussed in this thread. But if not, I
want to say thanks for thinking through this with me.

Cheers,
David

On Thu, Mar 7, 2024 at 6:51 PM Rich Felker <dalias@libc.org> wrote:

> On Thu, Mar 07, 2024 at 05:30:06PM -0800, David Schinazi wrote:
> > On Thu, Mar 7, 2024 at 4:08 PM Rich Felker <dalias@libc.org> wrote:
> >
> > > On Thu, Mar 07, 2024 at 02:50:53PM -0800, David Schinazi wrote:
> > > > On Wed, Mar 6, 2024 at 6:42 PM Rich Felker <dalias@libc.org> wrote:
> > > >
> > > > > On Wed, Mar 06, 2024 at 04:17:44PM -0800, David Schinazi wrote:
> > > > > > As Jeffrey points out, when the IETF decided to standardize mDNS,
> > > they
> > > > > > published it (RFC 6762) at the same time as the Special-Use
> Domain
> > > > > Registry
> > > > > > (RFC 6761) which created a process for reserving domain names for
> > > custom
> > > > > > purposes, and ".local" was one of the initial entries into that
> > > registry.
> > > > > > The UTF-8 vs punycode issue when it comes to mDNS and DNS is
> > > somewhat of
> > > > > a
> > > > > > mess. It was discussed in Section 16 of RFC 6762 but at the end
> of
> > > the
> > > > > day
> > > > > > punycode won. Even Apple's implementation of getaddrinfo will
> perform
> > > > > > punycode conversion for .local instead of sending the UTF-8. So
> in
> > > > > practice
> > > > > > you wouldn't need to special-case anything here.
> > > > >
> > > > > OK, these are both really good news!
> > > > >
> > > > > > There's also very much a policy matter of what "locally over
> > > > > > > multicast" means (what the user wants it to mean). Which
> interfaces
> > > > > > > should be queried? Wired and wireless ethernet? VPN links or
> other
> > > > > > > sorts of tunnels? Just one local interface (which one to
> > > prioritize)
> > > > > > > or all of them? Only if the network is "trusted"? Etc.
> > > > > > >
> > > > > >
> > > > > > You're absolutely right. Most mDNS systems try all non-loopback
> > > non-p2p
> > > > > > multicast-supporting interfaces, but sending to the default route
> > > > > interface
> > > > > > would be a good start, more on that below.
> > > > >
> > > > > This is really one thing that suggests a need for configurability
> > > > > outside of what libc might be able to offer. With normal DNS
> lookups,
> > > > > they're something you can block off and prevent from going to the
> > > > > network at all by policy (and in fact they don't go past the
> loopback
> > > > > by default, in the absence of a resolv.conf file). Adding mDNS
> that's
> > > > > on-by-default and not configurable would make a vector for network
> > > > > traffic being generated that's probably not expected and that
> could be
> > > > > a privacy leak.
> > > > >
> > > >
> > > > Totally agree. I was thinking through this both in terms of RFCs and
> in
> > > > terms of minimal code changes, and had a potential idea.
> Conceptually,
> > > > sending DNS to localhost is musl's IPC mechanism to a more
> feature-rich
> > > > resolver running in user-space. So when that's happening, we don't
> want
> > > to
> > > > mess with it because that could cause a privacy leak. Conversely,
> when
> > > > there's a non-loopback IP configured in resolv.conf, then musl acts
> as a
> > > > DNS stub resolver and the server in resolv.conf acts as a DNS
> recursive
> > > > resolver. In that scenario, sending the .local query over DNS to that
> > > other
> > > > host violates the RFCs. This allows us to treat the configured
> resolver
> > > > address as an implicit configuration mechanism that allows us to
> > > > selectively enable this without impacting anyone doing their own DNS
> > > > locally.
> > >
> > > This sounds like an odd overloading of one thing to have a very
> > > different meaning, and would break builtin mDNS for anyone doing
> > > DNSSEC right (which requires validating nameserver on localhost).
> > > Inventing a knob that's an overload of an existing knob is still
> > > inventing a knob, just worse.
> > >
> >
> > Sorry, I was suggesting the other way around: to only enable the mDNS
> mode
> > if resolver != 127.0.0.1.
>
> I understood that. It's still overloading a knob.
>
> > But on the topic of DNSSEC, that doesn't really
> > make sense in the context of mDNS because the names aren't globally
> unique
> > and signed. In theory you could exchange DNSSEC keys out of band and use
> > DNSSEC with mDNS, but I've never heard of anyone doing that. At that
> point
> > people exchange TLS certificates out of band and use mTLS. But overall I
> > can't argue that overloading configs to mean multiple things is janky :-)
>
> I'm not talking about validating DNSSEC for .local (which seems
> nonsensical, but I guess is actually something you could do with your
> own trust anchor for .local that would prevent rogue devices on your
> network from being able to answer mDNS).
>
> I'm talking about how anyone properly validating DNSSEC for the global
> DNS space has to have a nameserver on localhost, and how this would
> prevent them from using mDNS (or, in effect, disincentivize setting up
> DNSSEC validation since it would break your mDNS) via the builtin libc
> stub resolver support and would require wiring up the validating
> nameserver to it.
>
> > > > > When you do that, how do you control which interface(s) it goes
> over?
> > > > > > > I think that's an important missing ingredient.
> > > > > >
> > > > > > You're absolutely right. In IPv4, sending to a link-local
> multicast
> > > > > address
> > > > > > like this will send it over the IPv4 default route interface. In
> > > IPv6,
> > > > > the
> > > > > > interface needs to be specified in the scope_id. So we'd need to
> pull
> > > > > that
> > > > > > out of the kernel with rtnetlink.
> > > > >
> > > > > There's already code to enumerate interfaces, but it's a decent
> bit of
> > > > > additional machinery to pull in as a dep for the stub resolver,
> > > >
> > > >
> > > > Yeah we'd need lookup_name.c to include netlink.h - it's not huge
> though,
> > > > netlink.c is 50 lines long and statically linked anyway right?
> > >
> > > I was thinking in terms of using if_nameindex or something, but indeed
> > > that's not desirable because it's allocating. So it looks like it
> > > wouldn't share code but use netlink.c directly if it were done this
> > > way.
> > >
> > > BTW if there's a legacy ioctl that tells you the number of interfaces
> > > (scope_ids), it sems like you could just iterate over the whole
> > > numeric range without actually doing netlink enumeration.
> >
> > That would also work. The main limitation I was working around was that
> you
> > can only pass around MAXNS (3) name servers around without making more
> > changes.
>
> Yes, there's no reason to assume the first 3 interfaces found would
> suffice though. I think the way to handle this would be to treat the
> multicast address as just one nameserver in the list, and have
> __res_msend do whatever sort of iteration it needs to do when the
> resolvconf structure indicates that it's for mDNS.
>
> > > > > it's not clear how to do it properly for IPv4 (do scope ids work
> with
> > > > > v4-mapped addresses by any chance?)
> > > > >
> > > >
> > > > Scope IDs unfortunately don't work for IPv4. There's the
> SO_BINDTODEVICE
> > > > socket option, but that requires elevated privileges. For IPv4 I'd
> just
> > > use
> > > > the default route interface.
> > >
> > > But the default route interface is almost surely *not* the LAN where
> > > you expect .local things to live except in the case where there is
> > > only one interface. If you have a network that's segmented into
> > > separate LAN and outgoing interfaces, the LAN, not the route to the
> > > public internet, is where you would want mDNS going.
> >
> > In the case of a router, definitely. In the case of most end hosts or VMs
> > though, they often have only one or two routable interfaces, and the
> > default route is also the LAN.
>
> Not necessarily a router; could just be a client device with multiple
> routes. For example a default route that goes over a VPN and a LAN
> route for accessing local machines.
>
> > > With that said, SO_BINDTODEVICE is not the standard way to do this,
> > > and the correct/standard way doesn't need root. What it does need is
> > > binding to the local address on each device, which is still rather
> > > undesirable because it means you need N sockets for N interfaces,
> > > rather than one socket that can send/receive all addresses.
> >
> > Oh you're absolutely right, I knew there was a non-privileged way to do
> > this but couldn't remember it earlier.
> >
> > This is giving me an idea though: we could use the "connect UDP socket to
> > get a route lookup" trick. Let's say we're configured with a nameserver
> > that's not 127.0.0.1 (which is the case where I'd like to enable this)
> > let's say the nameserver is set to 192.0.2.33, then today foobar.local
> > would be sent to 192.0.2.33 over whichever interface has a route to it
> (in
> > most cases the default interface, but not always). We could open an
> > AF_INET/SOCK_DGRAM socket, connect it to 192.0.2.33:53, and then
> > use getsockname to get the local address - we then close that socket. We
> > can then create a new socket, bind it to that local address. That would
> > ensure that we send the mDNS traffic on the same interface where we would
> > have sent the unicast query. Downside is that since all queries share the
> > same socket, we'd bind everything to the interface of the first resolver,
> > or need multiple sockets.
>
> This again sounds like a bad "overloaded knob". Unless you're letting
> DHCP overwrite your resolv.conf, there's no reason for the route to
> the nameserver to match the LAN you want mDNS on.
>
> > > the amount of added code would be quite small. Limiting things to the
> > > > default interface isn't a full multi-network solution, but for those
> I
> > > > think it makes more sense to recommend running your own resolver on
> > > > loopback (you'd need elevated privileges to make this work fully
> anyway).
> > > > Coding wise, I think this would be pretty robust. The only breakage I
> > > > foresee is cases where someone built a custom resolver that runs on a
> > > > different machine and somehow handles .local differently than what
> the
> > > RFCs
> > > > say. That config sounds like a bad idea, and a violation of the
> RFCs, but
> > > > that doesn't mean there isn't someone somewhere who's doing it. So
> > > there's
> > > > a non-zero risk there. But to me that's manageable risk.
> > > >
> > > > What do you think?
> > >
> > > I think a more reasonable approach might be requiring an explicit knob
> > > to enable mDNS, in the form of an options field like ndots, timeout,
> > > retries, etc. in resolv.conf. This ensures that it doesn't become
> > > attack surface/change-of-behavior in network environments where peers
> > > are not supposed to be able to define network names.
> > >
> >
> > That would work. I'm not sure who maintains the list of options though.
> > From a quick search it looks like they came out of 4.3BSD like many
> > networking features, but it's unclear if POSIX owns it or just no one
> does
> > (which would be the same, POSIX is not around as a standard body any
> more).
>
> No one does. Basically anyone can freely add extensions, with the
> caveat that if you have mutually incompatible extensions in
> /etc/resolv.conf, someone using the same /etc with more than one stub
> resolver implementation (like both musl and glibc) is going to have a
> bad time.
>
> If for example glibc were up for adding configuration for which
> interfaces to do mdns on here, we could coordinate. But I suspect they
> would put it in a config file specific to the nss module that does
> mdns.
>
> > One further advantage of such an approach is that it could also solve
> > > the "which interface(s)" problem by letting the answer just be
> > > "whichever one(s) the user configured" (with the default list being
> > > empty). That way we wouldn't even need netlink, just if_nametoindex to
> > > convert interface name strings to scope ids, or alternatively (does
> > > this work for v6 in the absence of an explicit scope_id?) one or more
> > > local addresses to bind and send from.
> > >
> >
> > I definitely would avoid putting local addresses in the config, because
> it
> > would break for any non-static addresses like DHCP or v6 RAs. The
> interface
> > name would require walking the getifaddrs list to map it to a
> corresponding
> > source address but it would work if the interface name is stable.
>
> I could see it being desirable to support both. For some folks, IP
> addresses would be more stable; for others, interface names would.
>
> Another variant would be letting you identify the network(s) to send
> mDNS to via destination addresses, ala the "connect a UDP socket to
> get a local address" technique you described above.
>
> For IPv6 these are kinda equivalent. An address of fe80::%ifname (or
> maybe fe80::1%ifname?) should let you specify "interface ifname" just
> as a destination address.
>
> I'm not necessarily saying we should do any or all of these, just that
> they're possibilities to consider.
>
> > I guess we're looking at two ways to go about this:
> >
> > (1) the simpler but less clean option - where we key off of "resolver !=
> > 127.0.0.1" - very limited code size change, but only handles a small
> subset
> > of scenarios
>
> I _really_ don't like this option. It violates least-surprise,
> overloads one setting to mean something else based on a presumed usage
> pattern, and worst of all, it makes a behavior whereby enabling DNSSEC
> validation (by running your own validating nameserver on localhost)
> breaks something else (mDNS) which will disincentivize DNSSEC
> validation.
>
> This is really the hidden cost of overloaded knobs in general: they
> make situations where users are encouraged to change one setting in a
> way they don't want because that's how they get the other thing they
> do want.
>
> > (2) the cleaner option that involves more work - new config option, need
> > multiple sockets - would be cleaner design-wise, but would change quite a
> > bit more code
> >
> > Another aspect to consider is the fact that in a lot of cases resolv.conf
> > is overwritten by various components like NetworkManager, so we'd need to
> > modify them to also understand the option.
>
> I think they already have support for pulling options from somewhere.
> But that's a good question worth looking into: how you'd get the
> necessary config in place, in the presence of
> nm/dhdpcd/resolvconf/whatever overwriting resolv.conf.
>
> > I'm always in favor of doing the right thing, unless the right thing ends
> > up being so much effort that it doesn't happen. Then I'm a fan of doing
> the
> > easy thing ;-)
>
> Around here the fallback usually is "not doing it at all". :-p
>
> Rich
>

[-- Attachment #2: Type: text/html, Size: 18783 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-08  3:34               ` David Schinazi
@ 2024-03-08  3:47                 ` Rich Felker
  2024-03-08  4:47                   ` David Schinazi
  0 siblings, 1 reply; 32+ messages in thread
From: Rich Felker @ 2024-03-08  3:47 UTC (permalink / raw)
  To: David Schinazi; +Cc: musl

On Thu, Mar 07, 2024 at 07:34:33PM -0800, David Schinazi wrote:
> Hmmm. The cleaner option with the new config option and support for
> querying on all interfaces probably reaches a level of complexity where
> running a resolver on localhost might be best. And I honestly agree with
> your point that overloading the config option isn't great design. So
> perhaps "not doing it at all" is the answer then. I'll think about it some
> more, and discuss it with some mDNS experts at the next IETF meeting in a
> couple weeks. I'll report back if someone has a clever idea that wouldn't
> violate the design principles we've discussed in this thread. But if not, I
> want to say thanks for thinking through this with me.

I don't think the conclusion of this thread is necessarily "don't".
The right form of config option, especially if there's consensus on
what it should look like, is a very viable path, and the IP_PKTINFO
thing you found makes the implementation a lot simpler.

Having input from experts on the mDNS side would be most welcome and
sounds like a good next step to figuring out if this makes sense.

Rich

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-08  3:47                 ` Rich Felker
@ 2024-03-08  4:47                   ` David Schinazi
  2024-03-08 13:31                     ` Rich Felker
  0 siblings, 1 reply; 32+ messages in thread
From: David Schinazi @ 2024-03-08  4:47 UTC (permalink / raw)
  To: Rich Felker; +Cc: musl

[-- Attachment #1: Type: text/plain, Size: 2193 bytes --]

Thanks. How would you feel about the following potential configuration
design?
* Add a new configuration option "send_mdns_unicast"
* When true, use the current behavior
* When false, send the query on all non-loopback non-p2p interfaces
* Have send_mdns_unicast default to false

I was thinking through how to pick interfaces, looked up what other mDNS
libraries do, and pretty much all of them don't allow configuring
interfaces, whereas Avahi exposes allow-interfaces and deny-interfaces. I'm
leaning towards not making this configurable to reduce complexity. I think
that anyone interested in that level of config is probably using Avahi
anyway.

Additionally this design has two nice properties: the default behavior is
RFC-compliant, and it means that for my use-case I don't need to change the
config file, which was a big part of my motivation for doing this inside of
musl in the first place :-)

David

On Thu, Mar 7, 2024 at 7:47 PM Rich Felker <dalias@libc.org> wrote:

> On Thu, Mar 07, 2024 at 07:34:33PM -0800, David Schinazi wrote:
> > Hmmm. The cleaner option with the new config option and support for
> > querying on all interfaces probably reaches a level of complexity where
> > running a resolver on localhost might be best. And I honestly agree with
> > your point that overloading the config option isn't great design. So
> > perhaps "not doing it at all" is the answer then. I'll think about it
> some
> > more, and discuss it with some mDNS experts at the next IETF meeting in a
> > couple weeks. I'll report back if someone has a clever idea that wouldn't
> > violate the design principles we've discussed in this thread. But if
> not, I
> > want to say thanks for thinking through this with me.
>
> I don't think the conclusion of this thread is necessarily "don't".
> The right form of config option, especially if there's consensus on
> what it should look like, is a very viable path, and the IP_PKTINFO
> thing you found makes the implementation a lot simpler.
>
> Having input from experts on the mDNS side would be most welcome and
> sounds like a good next step to figuring out if this makes sense.
>
> Rich
>

[-- Attachment #2: Type: text/html, Size: 2694 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-08  4:47                   ` David Schinazi
@ 2024-03-08 13:31                     ` Rich Felker
  2024-03-08 19:15                       ` David Schinazi
  0 siblings, 1 reply; 32+ messages in thread
From: Rich Felker @ 2024-03-08 13:31 UTC (permalink / raw)
  To: David Schinazi; +Cc: musl

On Thu, Mar 07, 2024 at 08:47:20PM -0800, David Schinazi wrote:
> Thanks. How would you feel about the following potential configuration
> design?
> * Add a new configuration option "send_mdns_unicast"
> * When true, use the current behavior
> * When false, send the query on all non-loopback non-p2p interfaces
> * Have send_mdns_unicast default to false
> 
> I was thinking through how to pick interfaces, looked up what other mDNS
> libraries do, and pretty much all of them don't allow configuring
> interfaces, whereas Avahi exposes allow-interfaces and deny-interfaces. I'm
> leaning towards not making this configurable to reduce complexity. I think
> that anyone interested in that level of config is probably using Avahi
> anyway.
> 
> Additionally this design has two nice properties: the default behavior is
> RFC-compliant, and it means that for my use-case I don't need to change the
> config file, which was a big part of my motivation for doing this inside of
> musl in the first place :-)

As discussed in this thread, I don't think so. The biggest problems I
initially brought up were increased information leakage in the default
configuration and inability to control where the traffic goes when you
do want it on. The above proposal just reverts to the initial, except
for providing a way to opt-out.

For the most part, mDNS is very much a "home user, personal device on
trusted network" thing. Not only do you not want it to default on
because a lot of systems will be network servers on networks where
it's not meaningful (and can be a weakness that aids attackers in
lateral movement), but you also don't want it on when connected to
public wifi. For example if you have an open browser tab to
http://mything.local, and migrate to an untrusted network (with your
laptop, tablet, phone, whatever), now your browser will be leaking
private data (likely at least session auth tokens, maybe more) to
whoever answers the mDNS query for mything.local.

Windows has a setting when you add wifi networks for whether they're
treated as private/trusted or public. I would guess it controls
whether mDNS is used, among other things like SMB scanning or
whatever. The same really belongs in a network configurator for
Linux-based personal devices.

Fortunately, I think an approach where you opt-in particular
interfaces/source-addresses, rather than send everywhere by default,
has lower implementation cost and complexity on top of being the safe
thing to do. So none of the above should be taken as a "no" for the
functionality, just a no for "on by default and send everywhere".

Regarding untrusted networks, one thing I hadn't considered yet is
that a network configurator probably needs a way to setup resolv.conf
such that .local queries temp-fail rather than perma-fail (as they
would if you just sent the query to public dns) to use during certain
race windows while switching networks. IOW "send .local queries to
configured nameservers" and "treat .local specially but with an empty
list of interfaces to send to" should be distinct configurations.

Rich

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-07  0:17   ` David Schinazi
  2024-03-07  2:43     ` Rich Felker
@ 2024-03-08 15:31     ` Markus Wichmann
  2024-03-08 17:22       ` Rich Felker
  1 sibling, 1 reply; 32+ messages in thread
From: Markus Wichmann @ 2024-03-08 15:31 UTC (permalink / raw)
  To: musl; +Cc: David Schinazi

Am Wed, Mar 06, 2024 at 04:17:44PM -0800 schrieb David Schinazi:
> I'm definitely supportive of the slippery slope argument, but I think
> there's still a real line between mDNS and NetBIOS. mDNS uses a different
> transport but lives inside the DNS namespace, whereas NetBIOS is really its
> own thing - NetBIOS names aren't valid DNS hostnames.
>

One thing that came to me after thinking about it: This really puts a
wrenchs in the works of the "just proxy it" argument.  Not for mDNS, but
more generally for further possible backends for the list of hosts. If
you want to support a backend that supports names that DNS can't, then
proxying isn't a solution.

We may have to look into integrating nscd support into the search for
host names. We already have it for passwd queries, after all. And then
of course there are all the attendant questions:
- Do we query nscd always or only with some config option?
- Do we query nscd after DNS or vice-versa? Is this not a policy
  question?
- Is nscd failure authoritative?
&c., &c.

Ciao,
Markus

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-08 15:31     ` Markus Wichmann
@ 2024-03-08 17:22       ` Rich Felker
  0 siblings, 0 replies; 32+ messages in thread
From: Rich Felker @ 2024-03-08 17:22 UTC (permalink / raw)
  To: Markus Wichmann; +Cc: musl, David Schinazi

On Fri, Mar 08, 2024 at 04:31:02PM +0100, Markus Wichmann wrote:
> Am Wed, Mar 06, 2024 at 04:17:44PM -0800 schrieb David Schinazi:
> > I'm definitely supportive of the slippery slope argument, but I think
> > there's still a real line between mDNS and NetBIOS. mDNS uses a different
> > transport but lives inside the DNS namespace, whereas NetBIOS is really its
> > own thing - NetBIOS names aren't valid DNS hostnames.
> 
> One thing that came to me after thinking about it: This really puts a
> wrenchs in the works of the "just proxy it" argument.  Not for mDNS, but
> more generally for further possible backends for the list of hosts. If
> you want to support a backend that supports names that DNS can't, then
> proxying isn't a solution.

Who said we want support for names that DNS can't support?

> We may have to look into integrating nscd support into the search for
> host names. We already have it for passwd queries, after all. And then
> of course there are all the attendant questions:
> - Do we query nscd always or only with some config option?
> - Do we query nscd after DNS or vice-versa? Is this not a policy
>   question?
> - Is nscd failure authoritative?
> &c., &c.

The nscd wire format for hostnames is just bad. For example it can't
convey scope_id in IPv6 results, while musl's /etc/hosts
implementation can and does, making it actually useful for link-local
addresses. Maybe it could be extended, but I don't see any point in
worrying about this until there's a concrete need, which has not been
shown.

Rich

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-08 13:31                     ` Rich Felker
@ 2024-03-08 19:15                       ` David Schinazi
  2024-03-08 20:31                         ` Rich Felker
  0 siblings, 1 reply; 32+ messages in thread
From: David Schinazi @ 2024-03-08 19:15 UTC (permalink / raw)
  To: Rich Felker; +Cc: musl

[-- Attachment #1: Type: text/plain, Size: 6039 bytes --]

On Fri, Mar 8, 2024 at 5:30 AM Rich Felker <dalias@libc.org> wrote:

> On Thu, Mar 07, 2024 at 08:47:20PM -0800, David Schinazi wrote:
> > Thanks. How would you feel about the following potential configuration
> > design?
> > * Add a new configuration option "send_mdns_unicast"
> > * When true, use the current behavior
> > * When false, send the query on all non-loopback non-p2p interfaces
> > * Have send_mdns_unicast default to false
> >
> > I was thinking through how to pick interfaces, looked up what other mDNS
> > libraries do, and pretty much all of them don't allow configuring
> > interfaces, whereas Avahi exposes allow-interfaces and deny-interfaces.
> I'm
> > leaning towards not making this configurable to reduce complexity. I
> think
> > that anyone interested in that level of config is probably using Avahi
> > anyway.
> >
> > Additionally this design has two nice properties: the default behavior is
> > RFC-compliant, and it means that for my use-case I don't need to change
> the
> > config file, which was a big part of my motivation for doing this inside
> of
> > musl in the first place :-)
>
> As discussed in this thread, I don't think so. The biggest problems I
> initially brought up were increased information leakage in the default
> configuration and inability to control where the traffic goes when you
> do want it on. The above proposal just reverts to the initial, except
> for providing a way to opt-out.
>
> For the most part, mDNS is very much a "home user, personal device on
> trusted network" thing. Not only do you not want it to default on
> because a lot of systems will be network servers on networks where
> it's not meaningful (and can be a weakness that aids attackers in
> lateral movement), but you also don't want it on when connected to
> public wifi. For example if you have an open browser tab to
> http://mything.local, and migrate to an untrusted network (with your
> laptop, tablet, phone, whatever), now your browser will be leaking
> private data (likely at least session auth tokens, maybe more) to
> whoever answers the mDNS query for mything.local.
>

That's not quite right. The security properties of mDNS and DNS are the
same. DNS is inherently insecure, regardless of unicast vs multicast. If
I'm on a coffee shop Wi-Fi, all my DNS queries are sent in the clear to
whatever IP address the DHCP server gave me. So the stack has to deal with
the fact that any DNS response can be spoofed. The most widely used
solution is TLS: a successful DNS hijack can prevent you from accessing a
TLS service, but can't impersonate it. That's true of both mDNS and regular
unicast DNS. As an example, all Apple devices have mDNS enabled on all
interfaces, with no security impact - the features that rely on it
(AirDrop, AirPlay, contact sharing, etc) all use mTLS to ensure they're
talking to the right device regardless of the correctness of DNS. (Printing
remains completely insecure, but that's also independent of DNS - your
coffee shop Wi-Fi access point can attack you at the IP layer too). One
might think that DNSSEC could save us here, but it doesn't. DNSSEC was
unfortunately built with a fundamental design flaw: it requires you to
trust all resolvers on the path, including recursive resolvers. So even if
you ask for DNSSEC validation of the DNS records for www.example.com, your
coffee shop DNS recursive resolver can tell you "I checked, and example.com
does not support DNSSEC, here's the IP address for www.example.com though"
and you have to accept it. The world has accepted that DNS can be spoofed,
deployed TLS in applications, and moved on. The important remaining bit was
improving the privacy of DNS, and that was solved by DNS-over-TLS,
DNS-over-HTTPS, and DNS-over-QUIC - all of which don't provide DNS
integrity checking end-to-end but allow you to encrypt your DNS packets
between the client and trusted recursive resolver. Going back to your
example, http://mything.local is only safe on trusted networks regardless
of changes in the DNS stack because the coffee shop router can inspect and
modify your HTTP request and response. The issue here is that unencrypted
http is insecure, not the DNS.

Windows has a setting when you add wifi networks for whether they're
> treated as private/trusted or public. I would guess it controls
> whether mDNS is used, among other things like SMB scanning or
> whatever. The same really belongs in a network configurator for
> Linux-based personal devices.
>
> Fortunately, I think an approach where you opt-in particular
> interfaces/source-addresses, rather than send everywhere by default,
> has lower implementation cost and complexity on top of being the safe
> thing to do. So none of the above should be taken as a "no" for the
> functionality, just a no for "on by default and send everywhere".
>

And that's totally fair. If your argument is that "defaults should reflect
the previous behavior", then I can't argue. That said, I disagree that this
is measurably safer.

Regarding untrusted networks, one thing I hadn't considered yet is
> that a network configurator probably needs a way to setup resolv.conf
> such that .local queries temp-fail rather than perma-fail (as they
> would if you just sent the query to public dns) to use during certain
> race windows while switching networks. IOW "send .local queries to
> configured nameservers" and "treat .local specially but with an empty
> list of interfaces to send to" should be distinct configurations.
>

Yeah, caching negative results in DNS has been a tricky thing from the
start. You probably could hack something by installing a fake SOA record
for .local. in your recursive resolver running on localhost. But the
RFC-compliant answer is for stub resolvers to treat it specially and know
that those often never get an answer (musl doesn't cache DNS results so in
a way we're avoiding this problem altogether at the stub resolver).

David

[-- Attachment #2: Type: text/html, Size: 7208 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-08 19:15                       ` David Schinazi
@ 2024-03-08 20:31                         ` Rich Felker
  2024-03-08 21:55                           ` David Schinazi
  0 siblings, 1 reply; 32+ messages in thread
From: Rich Felker @ 2024-03-08 20:31 UTC (permalink / raw)
  To: David Schinazi; +Cc: musl

On Fri, Mar 08, 2024 at 11:15:52AM -0800, David Schinazi wrote:
> On Fri, Mar 8, 2024 at 5:30 AM Rich Felker <dalias@libc.org> wrote:
> 
> > On Thu, Mar 07, 2024 at 08:47:20PM -0800, David Schinazi wrote:
> > > Thanks. How would you feel about the following potential configuration
> > > design?
> > > * Add a new configuration option "send_mdns_unicast"
> > > * When true, use the current behavior
> > > * When false, send the query on all non-loopback non-p2p interfaces
> > > * Have send_mdns_unicast default to false
> > >
> > > I was thinking through how to pick interfaces, looked up what other mDNS
> > > libraries do, and pretty much all of them don't allow configuring
> > > interfaces, whereas Avahi exposes allow-interfaces and deny-interfaces.
> > I'm
> > > leaning towards not making this configurable to reduce complexity. I
> > think
> > > that anyone interested in that level of config is probably using Avahi
> > > anyway.
> > >
> > > Additionally this design has two nice properties: the default behavior is
> > > RFC-compliant, and it means that for my use-case I don't need to change
> > the
> > > config file, which was a big part of my motivation for doing this inside
> > of
> > > musl in the first place :-)
> >
> > As discussed in this thread, I don't think so. The biggest problems I
> > initially brought up were increased information leakage in the default
> > configuration and inability to control where the traffic goes when you
> > do want it on. The above proposal just reverts to the initial, except
> > for providing a way to opt-out.
> >
> > For the most part, mDNS is very much a "home user, personal device on
> > trusted network" thing. Not only do you not want it to default on
> > because a lot of systems will be network servers on networks where
> > it's not meaningful (and can be a weakness that aids attackers in
> > lateral movement), but you also don't want it on when connected to
> > public wifi. For example if you have an open browser tab to
> > http://mything.local, and migrate to an untrusted network (with your
> > laptop, tablet, phone, whatever), now your browser will be leaking
> > private data (likely at least session auth tokens, maybe more) to
> > whoever answers the mDNS query for mything.local.
> 
> That's not quite right. The security properties of mDNS and DNS are the
> same. DNS is inherently insecure, regardless of unicast vs multicast. If
> I'm on a coffee shop Wi-Fi, all my DNS queries are sent in the clear to
> whatever IP address the DHCP server gave me.

That's not the case. Connections to non-mDNS hosts are authenticated
by TLS with certificates issued on the basis of ownership of the
domain name. That's not possible with mDNS hostnames, so they'll
either be no-TLS or self-signed certs. That's why the above attack is
possible. It was also possible with normal DNS in the bad old days of
http://, but that time is long gone.

> So the stack has to deal with
> the fact that any DNS response can be spoofed.

That's also not possible with DNSSEC, but only helps if you're
validating it.

> The most widely used
> solution is TLS: a successful DNS hijack can prevent you from accessing a
> TLS service, but can't impersonate it. That's true of both mDNS and regular
> unicast DNS. As an example, all Apple devices have mDNS enabled on all
> interfaces, with no security impact - the features that rely on it
> (AirDrop, AirPlay, contact sharing, etc) all use mTLS to ensure they're
> talking to the right device regardless of the correctness of DNS. (Printing
> remains completely insecure, but that's also independent of DNS - your
> coffee shop Wi-Fi access point can attack you at the IP layer too). One
> might think that DNSSEC could save us here, but it doesn't. DNSSEC was
> unfortunately built with a fundamental design flaw: it requires you to
> trust all resolvers on the path, including recursive resolvers. So even if
> you ask for DNSSEC validation of the DNS records for www.example.com, your
> coffee shop DNS recursive resolver can tell you "I checked, and example.com
> does not support DNSSEC, here's the IP address for www.example.com though"
> and you have to accept it.

This is a completely false but somehow persistent myth about DNSSEC.
You cannot lie that a zone does not support DNSSEC. The only way to
claim a zone does not support DNSSEC is with a signature chain from
the DNS root proving the nonexistence of the DS records for the
delegation. Without that, the reply is BOGUS and will be ignored as if
there was no reply at all.

> > Windows has a setting when you add wifi networks for whether they're
> > treated as private/trusted or public. I would guess it controls
> > whether mDNS is used, among other things like SMB scanning or
> > whatever. The same really belongs in a network configurator for
> > Linux-based personal devices.
> >
> > Fortunately, I think an approach where you opt-in particular
> > interfaces/source-addresses, rather than send everywhere by default,
> > has lower implementation cost and complexity on top of being the safe
> > thing to do. So none of the above should be taken as a "no" for the
> > functionality, just a no for "on by default and send everywhere".
> >
> 
> And that's totally fair. If your argument is that "defaults should reflect
> the previous behavior", then I can't argue. That said, I disagree that this
> is measurably safer.

Per above, your disagreement seems to be based at least in part on
misinformation.

> > Regarding untrusted networks, one thing I hadn't considered yet is
> > that a network configurator probably needs a way to setup resolv.conf
> > such that .local queries temp-fail rather than perma-fail (as they
> > would if you just sent the query to public dns) to use during certain
> > race windows while switching networks. IOW "send .local queries to
> > configured nameservers" and "treat .local specially but with an empty
> > list of interfaces to send to" should be distinct configurations.
> 
> Yeah, caching negative results in DNS has been a tricky thing from the
> start. You probably could hack something by installing a fake SOA record
> for .local. in your recursive resolver running on localhost. But the
> RFC-compliant answer is for stub resolvers to treat it specially and know
> that those often never get an answer (musl doesn't cache DNS results so in
> a way we're avoiding this problem altogether at the stub resolver).

The problem here is not about caching, just about clients using a
response. You want a task (like a browser with open tabs) trying to
contact the site to get a tempfail rather than NxDomain which might
make it stop trying. But you probably want NxDomain if mDNS has been
disabled entirely, so that every .local lookup doesn't hang 5 seconds
or whatever before saying "inconclusive".

Rich

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-08 20:31                         ` Rich Felker
@ 2024-03-08 21:55                           ` David Schinazi
  2024-03-08 22:54                             ` Rich Felker
  0 siblings, 1 reply; 32+ messages in thread
From: David Schinazi @ 2024-03-08 21:55 UTC (permalink / raw)
  To: Rich Felker; +Cc: musl

[-- Attachment #1: Type: text/plain, Size: 10431 bytes --]

On Fri, Mar 8, 2024 at 12:31 PM Rich Felker <dalias@libc.org> wrote:

> On Fri, Mar 08, 2024 at 11:15:52AM -0800, David Schinazi wrote:
> > On Fri, Mar 8, 2024 at 5:30 AM Rich Felker <dalias@libc.org> wrote:
> >
> > > On Thu, Mar 07, 2024 at 08:47:20PM -0800, David Schinazi wrote:
> > > > Thanks. How would you feel about the following potential
> configuration
> > > > design?
> > > > * Add a new configuration option "send_mdns_unicast"
> > > > * When true, use the current behavior
> > > > * When false, send the query on all non-loopback non-p2p interfaces
> > > > * Have send_mdns_unicast default to false
> > > >
> > > > I was thinking through how to pick interfaces, looked up what other
> mDNS
> > > > libraries do, and pretty much all of them don't allow configuring
> > > > interfaces, whereas Avahi exposes allow-interfaces and
> deny-interfaces.
> > > I'm
> > > > leaning towards not making this configurable to reduce complexity. I
> > > think
> > > > that anyone interested in that level of config is probably using
> Avahi
> > > > anyway.
> > > >
> > > > Additionally this design has two nice properties: the default
> behavior is
> > > > RFC-compliant, and it means that for my use-case I don't need to
> change
> > > the
> > > > config file, which was a big part of my motivation for doing this
> inside
> > > of
> > > > musl in the first place :-)
> > >
> > > As discussed in this thread, I don't think so. The biggest problems I
> > > initially brought up were increased information leakage in the default
> > > configuration and inability to control where the traffic goes when you
> > > do want it on. The above proposal just reverts to the initial, except
> > > for providing a way to opt-out.
> > >
> > > For the most part, mDNS is very much a "home user, personal device on
> > > trusted network" thing. Not only do you not want it to default on
> > > because a lot of systems will be network servers on networks where
> > > it's not meaningful (and can be a weakness that aids attackers in
> > > lateral movement), but you also don't want it on when connected to
> > > public wifi. For example if you have an open browser tab to
> > > http://mything.local, and migrate to an untrusted network (with your
> > > laptop, tablet, phone, whatever), now your browser will be leaking
> > > private data (likely at least session auth tokens, maybe more) to
> > > whoever answers the mDNS query for mything.local.
> >
> > That's not quite right. The security properties of mDNS and DNS are the
> > same. DNS is inherently insecure, regardless of unicast vs multicast. If
> > I'm on a coffee shop Wi-Fi, all my DNS queries are sent in the clear to
> > whatever IP address the DHCP server gave me.
>
> That's not the case. Connections to non-mDNS hosts are authenticated
> by TLS with certificates issued on the basis of ownership of the
> domain name. That's not possible with mDNS hostnames, so they'll
> either be no-TLS or self-signed certs. That's why the above attack is
> possible. It was also possible with normal DNS in the bad old days of
> http://, but that time is long gone.
>

Apologies for being pedantic, but that's not true. The ability to get TLS
certificates for a domain name that you own is a property of the WebPKI,
not a property of TLS. What you wrote is true, but only in the context of a
Web browser with an unmodified root certificate store. The features I
mentioned above don't use the WebPKI, they have a separate root of trust.
For example, some of those Apple features exchange TLS certificates via an
out-of-band mechanism such as Apple trusted servers. Another example is the
Apple Watch: when you first pair a new Apple Watch with an iPhone, they
exchange ed25519 public keys. Then any time the watch wants to transfer a
large file to/from the phone, it'll connect to Wi-Fi, use mDNS to find the
phone, and set up an IKEv2/IPsec tunnel that then protects the exchange.
It's resilient to any attacks at the mDNS level.

You're absolutely right that the security of Web requests using local
connectivity is completely broken by the lack of WebPKI certificates for
those. But sending the DNS query over multicast as opposed to unencrypted
unicast to an untrusted DNS server doesn't change the security properties.
In your example above, the open tab to http://mything.local will send that
query to the recursive resolver - and if that's the one received by DHCP
then that server can reply with its own address and receive your auth
tokens. One potential fix here is to configure your resolv.conf to
localhost and then apply policy in that local resolver. But in practice,
application developers don't rely on security at that layer, they assume
that DNS is unsafe and implement encryption in userspace with some out of
band trust mechanism.

> So the stack has to deal with
> > the fact that any DNS response can be spoofed.
>
> That's also not possible with DNSSEC, but only helps if you're
> validating it.
>
> > The most widely used
> > solution is TLS: a successful DNS hijack can prevent you from accessing a
> > TLS service, but can't impersonate it. That's true of both mDNS and
> regular
> > unicast DNS. As an example, all Apple devices have mDNS enabled on all
> > interfaces, with no security impact - the features that rely on it
> > (AirDrop, AirPlay, contact sharing, etc) all use mTLS to ensure they're
> > talking to the right device regardless of the correctness of DNS.
> (Printing
> > remains completely insecure, but that's also independent of DNS - your
> > coffee shop Wi-Fi access point can attack you at the IP layer too). One
> > might think that DNSSEC could save us here, but it doesn't. DNSSEC was
> > unfortunately built with a fundamental design flaw: it requires you to
> > trust all resolvers on the path, including recursive resolvers. So even
> if
> > you ask for DNSSEC validation of the DNS records for www.example.com,
> your
> > coffee shop DNS recursive resolver can tell you "I checked, and
> example.com
> > does not support DNSSEC, here's the IP address for www.example.com
> though"
> > and you have to accept it.
>
> This is a completely false but somehow persistent myth about DNSSEC.
> You cannot lie that a zone does not support DNSSEC. The only way to
> claim a zone does not support DNSSEC is with a signature chain from
> the DNS root proving the nonexistence of the DS records for the
> delegation. Without that, the reply is BOGUS and will be ignored as if
> there was no reply at all.
>

I was talking about the case where the recursive resolver does the
validation, which is what's deployed in practice today. What you wrote is
only true if the client does the DNSSEC validation itself. Most clients
don't do that today, because too many domains are just misconfigured and
broken. Eric Rescorla (the editor of the TLS RFCs) wrote a great blog post
about this:

https://educatedguesswork.org/posts/dns-security-dnssec/#validation-at-the-endpoint-versus-the-recursive

> > Windows has a setting when you add wifi networks for whether they're
> > > treated as private/trusted or public. I would guess it controls
> > > whether mDNS is used, among other things like SMB scanning or
> > > whatever. The same really belongs in a network configurator for
> > > Linux-based personal devices.
> > >
> > > Fortunately, I think an approach where you opt-in particular
> > > interfaces/source-addresses, rather than send everywhere by default,
> > > has lower implementation cost and complexity on top of being the safe
> > > thing to do. So none of the above should be taken as a "no" for the
> > > functionality, just a no for "on by default and send everywhere".
> > >
> >
> > And that's totally fair. If your argument is that "defaults should
> reflect
> > the previous behavior", then I can't argue. That said, I disagree that
> this
> > is measurably safer.
>
> Per above, your disagreement seems to be based at least in part on
> misinformation.
>

There are many topics that I am incredibly under-informed or misinformed
on. And to be honest, the intricacies of the Linux kernel syscall API is
definitely one of them. Internet standards as they relate to security and
DNS though, I do know a few things about. It's kind of my job :-)

> > Regarding untrusted networks, one thing I hadn't considered yet is
> > > that a network configurator probably needs a way to setup resolv.conf
> > > such that .local queries temp-fail rather than perma-fail (as they
> > > would if you just sent the query to public dns) to use during certain
> > > race windows while switching networks. IOW "send .local queries to
> > > configured nameservers" and "treat .local specially but with an empty
> > > list of interfaces to send to" should be distinct configurations.
> >
> > Yeah, caching negative results in DNS has been a tricky thing from the
> > start. You probably could hack something by installing a fake SOA record
> > for .local. in your recursive resolver running on localhost. But the
> > RFC-compliant answer is for stub resolvers to treat it specially and know
> > that those often never get an answer (musl doesn't cache DNS results so
> in
> > a way we're avoiding this problem altogether at the stub resolver).
>
> The problem here is not about caching, just about clients using a
> response. You want a task (like a browser with open tabs) trying to
> contact the site to get a tempfail rather than NxDomain which might
> make it stop trying. But you probably want NxDomain if mDNS has been
> disabled entirely, so that every .local lookup doesn't hang 5 seconds
> or whatever before saying "inconclusive".
>

I'm assuming that by tempfail you mean EAI_AGAIN. The two browsers that
I've written code in don't use that (Chrome just treats it the same as a
resolution failure and will automatically refresh the tab on a network
change; Safari doesn't use getaddrinfo and instead relies on an
asynchronous DNS API that adds results as they come in - I wrote that
algorithm up in RFC 8305). All that said, synchronous blocking APIs like
getaddrinfo need to eventually return even if no one replies, so EAI_AGAIN
makes sense in that case - whereas if .local is blocked by policy then
immediately returning EAI_NONAME is best.

David

[-- Attachment #2: Type: text/html, Size: 12759 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-08 21:55                           ` David Schinazi
@ 2024-03-08 22:54                             ` Rich Felker
  2024-03-08 23:44                               ` David Schinazi
  2024-03-09  0:23                               ` Jeffrey Walton
  0 siblings, 2 replies; 32+ messages in thread
From: Rich Felker @ 2024-03-08 22:54 UTC (permalink / raw)
  To: David Schinazi; +Cc: musl

On Fri, Mar 08, 2024 at 01:55:18PM -0800, David Schinazi wrote:
> On Fri, Mar 8, 2024 at 12:31 PM Rich Felker <dalias@libc.org> wrote:
> 
> > On Fri, Mar 08, 2024 at 11:15:52AM -0800, David Schinazi wrote:
> > > On Fri, Mar 8, 2024 at 5:30 AM Rich Felker <dalias@libc.org> wrote:
> > >
> > > > On Thu, Mar 07, 2024 at 08:47:20PM -0800, David Schinazi wrote:
> > > > > Thanks. How would you feel about the following potential
> > configuration
> > > > > design?
> > > > > * Add a new configuration option "send_mdns_unicast"
> > > > > * When true, use the current behavior
> > > > > * When false, send the query on all non-loopback non-p2p interfaces
> > > > > * Have send_mdns_unicast default to false
> > > > >
> > > > > I was thinking through how to pick interfaces, looked up what other
> > mDNS
> > > > > libraries do, and pretty much all of them don't allow configuring
> > > > > interfaces, whereas Avahi exposes allow-interfaces and
> > deny-interfaces.
> > > > I'm
> > > > > leaning towards not making this configurable to reduce complexity. I
> > > > think
> > > > > that anyone interested in that level of config is probably using
> > Avahi
> > > > > anyway.
> > > > >
> > > > > Additionally this design has two nice properties: the default
> > behavior is
> > > > > RFC-compliant, and it means that for my use-case I don't need to
> > change
> > > > the
> > > > > config file, which was a big part of my motivation for doing this
> > inside
> > > > of
> > > > > musl in the first place :-)
> > > >
> > > > As discussed in this thread, I don't think so. The biggest problems I
> > > > initially brought up were increased information leakage in the default
> > > > configuration and inability to control where the traffic goes when you
> > > > do want it on. The above proposal just reverts to the initial, except
> > > > for providing a way to opt-out.
> > > >
> > > > For the most part, mDNS is very much a "home user, personal device on
> > > > trusted network" thing. Not only do you not want it to default on
> > > > because a lot of systems will be network servers on networks where
> > > > it's not meaningful (and can be a weakness that aids attackers in
> > > > lateral movement), but you also don't want it on when connected to
> > > > public wifi. For example if you have an open browser tab to
> > > > http://mything.local, and migrate to an untrusted network (with your
> > > > laptop, tablet, phone, whatever), now your browser will be leaking
> > > > private data (likely at least session auth tokens, maybe more) to
> > > > whoever answers the mDNS query for mything.local.
> > >
> > > That's not quite right. The security properties of mDNS and DNS are the
> > > same. DNS is inherently insecure, regardless of unicast vs multicast. If
> > > I'm on a coffee shop Wi-Fi, all my DNS queries are sent in the clear to
> > > whatever IP address the DHCP server gave me.
> >
> > That's not the case. Connections to non-mDNS hosts are authenticated
> > by TLS with certificates issued on the basis of ownership of the
> > domain name. That's not possible with mDNS hostnames, so they'll
> > either be no-TLS or self-signed certs. That's why the above attack is
> > possible. It was also possible with normal DNS in the bad old days of
> > http://, but that time is long gone.
> 
> Apologies for being pedantic, but that's not true. The ability to get TLS
> certificates for a domain name that you own is a property of the WebPKI,
> not a property of TLS. What you wrote is true, but only in the context of a
> Web browser with an unmodified root certificate store. The features I
> mentioned above don't use the WebPKI, they have a separate root of trust.
> For example, some of those Apple features exchange TLS certificates via an
> out-of-band mechanism such as Apple trusted servers. Another example is the
> Apple Watch: when you first pair a new Apple Watch with an iPhone, they
> exchange ed25519 public keys. Then any time the watch wants to transfer a
> large file to/from the phone, it'll connect to Wi-Fi, use mDNS to find the
> phone, and set up an IKEv2/IPsec tunnel that then protects the exchange.
> It's resilient to any attacks at the mDNS level.
> 
> You're absolutely right that the security of Web requests using local
> connectivity is completely broken by the lack of WebPKI certificates for
> those. But sending the DNS query over multicast as opposed to unencrypted
> unicast to an untrusted DNS server doesn't change the security properties.
> In your example above, the open tab to http://mything.local will send that
> query to the recursive resolver - and if that's the one received by DHCP
> then that server can reply with its own address and receive your auth
> tokens. One potential fix here is to configure your resolv.conf to
> localhost and then apply policy in that local resolver. But in practice,
> application developers don't rely on security at that layer, they assume
> that DNS is unsafe and implement encryption in userspace with some out of
> band trust mechanism.

My specific example was http://mything.local in a web browser, which
is the way you access lots of mDNS-enabled things in the absence of a
specific software ecosystem like Apple's. Since we're talking about
musl which would be running on Linux or a Linux-syscall-compatible
environment, without Apple apps, I think that's the main way anyone
would be using hypothetical mDNS support. And indeed this is the way
you access many printers, 3D printers, IP cameras, etc.

Maybe at some point we'll have a good framework for authenticating
this kind of usage with certificates (probably certificate pinning on
first use, with good UX, is the only easy solution), but at present,
mDNS devices on the .local zone get accessed with plain http:// all
the time, and this means it's unsafe to do mDNS on
public/untrusted/hostile networks.

> > So the stack has to deal with
> > > the fact that any DNS response can be spoofed.
> >
> > That's also not possible with DNSSEC, but only helps if you're
> > validating it.
> >
> > > The most widely used
> > > solution is TLS: a successful DNS hijack can prevent you from accessing a
> > > TLS service, but can't impersonate it. That's true of both mDNS and
> > regular
> > > unicast DNS. As an example, all Apple devices have mDNS enabled on all
> > > interfaces, with no security impact - the features that rely on it
> > > (AirDrop, AirPlay, contact sharing, etc) all use mTLS to ensure they're
> > > talking to the right device regardless of the correctness of DNS.
> > (Printing
> > > remains completely insecure, but that's also independent of DNS - your
> > > coffee shop Wi-Fi access point can attack you at the IP layer too). One
> > > might think that DNSSEC could save us here, but it doesn't. DNSSEC was
> > > unfortunately built with a fundamental design flaw: it requires you to
> > > trust all resolvers on the path, including recursive resolvers. So even
> > if
> > > you ask for DNSSEC validation of the DNS records for www.example.com,
> > your
> > > coffee shop DNS recursive resolver can tell you "I checked, and
> > example.com
> > > does not support DNSSEC, here's the IP address for www.example.com
> > though"
> > > and you have to accept it.
> >
> > This is a completely false but somehow persistent myth about DNSSEC.
> > You cannot lie that a zone does not support DNSSEC. The only way to
> > claim a zone does not support DNSSEC is with a signature chain from
> > the DNS root proving the nonexistence of the DS records for the
> > delegation. Without that, the reply is BOGUS and will be ignored as if
> > there was no reply at all.
> 
> I was talking about the case where the recursive resolver does the
> validation, which is what's deployed in practice today. What you wrote is
> only true if the client does the DNSSEC validation itself. Most clients
> don't do that today, because too many domains are just misconfigured and
> broken. Eric Rescorla (the editor of the TLS RFCs) wrote a great blog post
> about this:

The consensus of folks in the stub resolver space (at least glibc+musl
and I would assume the BSDs as well) is that the way you do DNSSEC
validation is by having a validating caching proxy or full recursive
resolver on localhost. Doing validation in the stub resolver is not
viable because it may be static-linked, where it would not be able to
be updated with new algorithms, root-of-trust, etc. This is one of the
reasons our go-to response for new functionality wanted in the stub
resolver is "do it in a nameserver on localhost" -- because you
already need that to do DNSSEC.

It really did not sound like you were talking about trusting the
recursive, though. You called it a "fundamental design flaw", which it
is not, and said it requires you to "trust all resolvers on the path",
which it does not. It only requires you to trust the immediate
resolver you are interacting with (and not even that if you put the
validation in the stub resolver, but there are good reasons not to do
that, as above). A pure-proxying server that relies on upstream
recursives can do full DNSSEC validation. Dnsmasq is a canonical
example. I believe systemd-resolvd also does it.

> > > Regarding untrusted networks, one thing I hadn't considered yet is
> > > > that a network configurator probably needs a way to setup resolv.conf
> > > > such that .local queries temp-fail rather than perma-fail (as they
> > > > would if you just sent the query to public dns) to use during certain
> > > > race windows while switching networks. IOW "send .local queries to
> > > > configured nameservers" and "treat .local specially but with an empty
> > > > list of interfaces to send to" should be distinct configurations.
> > >
> > > Yeah, caching negative results in DNS has been a tricky thing from the
> > > start. You probably could hack something by installing a fake SOA record
> > > for .local. in your recursive resolver running on localhost. But the
> > > RFC-compliant answer is for stub resolvers to treat it specially and know
> > > that those often never get an answer (musl doesn't cache DNS results so
> > in
> > > a way we're avoiding this problem altogether at the stub resolver).
> >
> > The problem here is not about caching, just about clients using a
> > response. You want a task (like a browser with open tabs) trying to
> > contact the site to get a tempfail rather than NxDomain which might
> > make it stop trying. But you probably want NxDomain if mDNS has been
> > disabled entirely, so that every .local lookup doesn't hang 5 seconds
> > or whatever before saying "inconclusive".
> 
> I'm assuming that by tempfail you mean EAI_AGAIN. The two browsers that
> I've written code in don't use that (Chrome just treats it the same as a
> resolution failure and will automatically refresh the tab on a network
> change; Safari doesn't use getaddrinfo and instead relies on an
> asynchronous DNS API that adds results as they come in - I wrote that
> algorithm up in RFC 8305). All that said, synchronous blocking APIs like
> getaddrinfo need to eventually return even if no one replies, so EAI_AGAIN
> makes sense in that case - whereas if .local is blocked by policy then
> immediately returning EAI_NONAME is best.

Right. Even if applications don't currently distinguish them well,
returning EAI_AGAIN vs EAI_NONAME is meaningful and enables them to do
the right thing.

Rich

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-08 22:54                             ` Rich Felker
@ 2024-03-08 23:44                               ` David Schinazi
  2024-03-21  9:21                                 ` David Schinazi
  2024-03-09  0:23                               ` Jeffrey Walton
  1 sibling, 1 reply; 32+ messages in thread
From: David Schinazi @ 2024-03-08 23:44 UTC (permalink / raw)
  To: Rich Felker; +Cc: musl

[-- Attachment #1: Type: text/plain, Size: 17450 bytes --]

On Fri, Mar 8, 2024 at 2:54 PM Rich Felker <dalias@libc.org> wrote:

> On Fri, Mar 08, 2024 at 01:55:18PM -0800, David Schinazi wrote:
> > On Fri, Mar 8, 2024 at 12:31 PM Rich Felker <dalias@libc.org> wrote:
> >
> > > On Fri, Mar 08, 2024 at 11:15:52AM -0800, David Schinazi wrote:
> > > > On Fri, Mar 8, 2024 at 5:30 AM Rich Felker <dalias@libc.org> wrote:
> > > >
> > > > > On Thu, Mar 07, 2024 at 08:47:20PM -0800, David Schinazi wrote:
> > > > > > Thanks. How would you feel about the following potential
> > > configuration
> > > > > > design?
> > > > > > * Add a new configuration option "send_mdns_unicast"
> > > > > > * When true, use the current behavior
> > > > > > * When false, send the query on all non-loopback non-p2p
> interfaces
> > > > > > * Have send_mdns_unicast default to false
> > > > > >
> > > > > > I was thinking through how to pick interfaces, looked up what
> other
> > > mDNS
> > > > > > libraries do, and pretty much all of them don't allow configuring
> > > > > > interfaces, whereas Avahi exposes allow-interfaces and
> > > deny-interfaces.
> > > > > I'm
> > > > > > leaning towards not making this configurable to reduce
> complexity. I
> > > > > think
> > > > > > that anyone interested in that level of config is probably using
> > > Avahi
> > > > > > anyway.
> > > > > >
> > > > > > Additionally this design has two nice properties: the default
> > > behavior is
> > > > > > RFC-compliant, and it means that for my use-case I don't need to
> > > change
> > > > > the
> > > > > > config file, which was a big part of my motivation for doing this
> > > inside
> > > > > of
> > > > > > musl in the first place :-)
> > > > >
> > > > > As discussed in this thread, I don't think so. The biggest
> problems I
> > > > > initially brought up were increased information leakage in the
> default
> > > > > configuration and inability to control where the traffic goes when
> you
> > > > > do want it on. The above proposal just reverts to the initial,
> except
> > > > > for providing a way to opt-out.
> > > > >
> > > > > For the most part, mDNS is very much a "home user, personal device
> on
> > > > > trusted network" thing. Not only do you not want it to default on
> > > > > because a lot of systems will be network servers on networks where
> > > > > it's not meaningful (and can be a weakness that aids attackers in
> > > > > lateral movement), but you also don't want it on when connected to
> > > > > public wifi. For example if you have an open browser tab to
> > > > > http://mything.local, and migrate to an untrusted network (with
> your
> > > > > laptop, tablet, phone, whatever), now your browser will be leaking
> > > > > private data (likely at least session auth tokens, maybe more) to
> > > > > whoever answers the mDNS query for mything.local.
> > > >
> > > > That's not quite right. The security properties of mDNS and DNS are
> the
> > > > same. DNS is inherently insecure, regardless of unicast vs
> multicast. If
> > > > I'm on a coffee shop Wi-Fi, all my DNS queries are sent in the clear
> to
> > > > whatever IP address the DHCP server gave me.
> > >
> > > That's not the case. Connections to non-mDNS hosts are authenticated
> > > by TLS with certificates issued on the basis of ownership of the
> > > domain name. That's not possible with mDNS hostnames, so they'll
> > > either be no-TLS or self-signed certs. That's why the above attack is
> > > possible. It was also possible with normal DNS in the bad old days of
> > > http://, but that time is long gone.
> >
> > Apologies for being pedantic, but that's not true. The ability to get TLS
> > certificates for a domain name that you own is a property of the WebPKI,
> > not a property of TLS. What you wrote is true, but only in the context
> of a
> > Web browser with an unmodified root certificate store. The features I
> > mentioned above don't use the WebPKI, they have a separate root of trust.
> > For example, some of those Apple features exchange TLS certificates via
> an
> > out-of-band mechanism such as Apple trusted servers. Another example is
> the
> > Apple Watch: when you first pair a new Apple Watch with an iPhone, they
> > exchange ed25519 public keys. Then any time the watch wants to transfer a
> > large file to/from the phone, it'll connect to Wi-Fi, use mDNS to find
> the
> > phone, and set up an IKEv2/IPsec tunnel that then protects the exchange.
> > It's resilient to any attacks at the mDNS level.
> >
> > You're absolutely right that the security of Web requests using local
> > connectivity is completely broken by the lack of WebPKI certificates for
> > those. But sending the DNS query over multicast as opposed to unencrypted
> > unicast to an untrusted DNS server doesn't change the security
> properties.
> > In your example above, the open tab to http://mything.local will send
> that
> > query to the recursive resolver - and if that's the one received by DHCP
> > then that server can reply with its own address and receive your auth
> > tokens. One potential fix here is to configure your resolv.conf to
> > localhost and then apply policy in that local resolver. But in practice,
> > application developers don't rely on security at that layer, they assume
> > that DNS is unsafe and implement encryption in userspace with some out of
> > band trust mechanism.
>
> My specific example was http://mything.local in a web browser, which
> is the way you access lots of mDNS-enabled things in the absence of a
> specific software ecosystem like Apple's. Since we're talking about
> musl which would be running on Linux or a Linux-syscall-compatible
> environment, without Apple apps, I think that's the main way anyone
> would be using hypothetical mDNS support. And indeed this is the way
> you access many printers, 3D printers, IP cameras, etc.
>

I have multiple services at home that use HTTP and mDNS to communicate
with. But they're built knowing that unencrypted HTTP is unsafe. For
example, one of my servers doesn't have any authentication - my browser
just uses unauthenticated GETs, POSTs and WebSockets. If I leave the tab
open and go to a coffee shop, my browser might send that GET to a server I
don't trust but that request won't carry any sensitive information. Another
of my servers uses TLS with self-signed certs, so every time I want to
communicate with it, I need to click through my browser's "this is unsafe"
interstitial to get to the page. If I switch networks, the browser will
send me the warning again and I'll know not to click through when I'm not
at home. In both of those cases, the security is handled (or not handled at
all) at the application layer.

Maybe at some point we'll have a good framework for authenticating
> this kind of usage with certificates (probably certificate pinning on
> first use, with good UX, is the only easy solution),


Trust on first use works, or even better there are emerging solutions that
leverage codes printed on devices and PAKEs so that a device on the
untrusted network can't even hijack the first connection without having
access to that code. The leading one for home automation is Matter [1].
Coincidentally, it also leverages mDNS for discovery, and doesn't rely on
security at the DNS level.

[1] https://csa-iot.org/all-solutions/matter/

but at present,
> mDNS devices on the .local zone get accessed with plain http:// all
> the time, and this means it's unsafe to do mDNS on
> public/untrusted/hostile networks.
>

The notion of something being "unsafe" (and security in general) is
predicated on the existence of a threat model. It's unsafe to use
unencrypted HTTP to your bank when your threat model includes someone on
the coffee shop Wi-Fi trying to steal your bank credentials. Conversely,
it's safe for me to print to this coffee shop printer if my threat model
assumes that I'm ok with the owner of the coffee shop seeing my document.
Another example is Chromecast which also uses mDNS: from Chrome on a Linux
laptop, I can cast YouTube videos to the TV in this coffee shop. That's
safe because I trust the network with the YouTube link I'm telling the TV
to play. mDNS is not in and of itself safe or unsafe. It converts
names into addresses, and what you do with those addresses can potentially
be unsafe.

That doesn't mean that every single use of mDNS on untrusted networks is
safe. If someone builds a web page that sends valuable secrets over
unencrypted HTTP to a .local name, then you have a security problem. But my
point is that this security problem needs to be solved at the application
layer and not at the DNS layer. That said, I agree that having a way to
disable mDNS on a machine is a good idea, because there probably are users
out there that are stuck with applications that for some reason decided to
rely on DNS being secure.

In terms of the tradeoff between usability and security, the default to me
lies with default-enabling mDNS on all interfaces as Apple and Avahi do.
But this tradeoff is between two metrics that can't be quantified one
against the other for all possible uses, so I totally understand if your
opinion for musl is that the tradeoff there is different than in other
situations. You know your users better than I do.

> > So the stack has to deal with
> > > > the fact that any DNS response can be spoofed.
> > >
> > > That's also not possible with DNSSEC, but only helps if you're
> > > validating it.
> > >
> > > > The most widely used
> > > > solution is TLS: a successful DNS hijack can prevent you from
> accessing a
> > > > TLS service, but can't impersonate it. That's true of both mDNS and
> > > regular
> > > > unicast DNS. As an example, all Apple devices have mDNS enabled on
> all
> > > > interfaces, with no security impact - the features that rely on it
> > > > (AirDrop, AirPlay, contact sharing, etc) all use mTLS to ensure
> they're
> > > > talking to the right device regardless of the correctness of DNS.
> > > (Printing
> > > > remains completely insecure, but that's also independent of DNS -
> your
> > > > coffee shop Wi-Fi access point can attack you at the IP layer too).
> One
> > > > might think that DNSSEC could save us here, but it doesn't. DNSSEC
> was
> > > > unfortunately built with a fundamental design flaw: it requires you
> to
> > > > trust all resolvers on the path, including recursive resolvers. So
> even
> > > if
> > > > you ask for DNSSEC validation of the DNS records for www.example.com
> ,
> > > your
> > > > coffee shop DNS recursive resolver can tell you "I checked, and
> > > example.com
> > > > does not support DNSSEC, here's the IP address for www.example.com
> > > though"
> > > > and you have to accept it.
> > >
> > > This is a completely false but somehow persistent myth about DNSSEC.
> > > You cannot lie that a zone does not support DNSSEC. The only way to
> > > claim a zone does not support DNSSEC is with a signature chain from
> > > the DNS root proving the nonexistence of the DS records for the
> > > delegation. Without that, the reply is BOGUS and will be ignored as if
> > > there was no reply at all.
> >
> > I was talking about the case where the recursive resolver does the
> > validation, which is what's deployed in practice today. What you wrote is
> > only true if the client does the DNSSEC validation itself. Most clients
> > don't do that today, because too many domains are just misconfigured and
> > broken. Eric Rescorla (the editor of the TLS RFCs) wrote a great blog
> post
> > about this:
>
> The consensus of folks in the stub resolver space (at least glibc+musl
> and I would assume the BSDs as well) is that the way you do DNSSEC
> validation is by having a validating caching proxy or full recursive
> resolver on localhost. Doing validation in the stub resolver is not
> viable because it may be static-linked, where it would not be able to
> be updated with new algorithms, root-of-trust, etc.


No disagreement there. By "client" I meant the client device as a whole,
and by "recursive resolver" I meant "the DNS server you got from DHCP".
Running a DNSSEC-validating recursive resolver on the client device falls
into what I meant by "if the client does the DNSSEC validation itself".
Sorry for being unclear.


> This is one of the
> reasons our go-to response for new functionality wanted in the stub
> resolver is "do it in a nameserver on localhost" -- because you
> already need that to do DNSSEC.
>

That makes sense. I wasn't working with the assumption that DNSSEC was a
requirement.

It really did not sound like you were talking about trusting the
> recursive, though. You called it a "fundamental design flaw", which it
> is not, and said it requires you to "trust all resolvers on the path",
> which it does not. It only requires you to trust the immediate
> resolver you are interacting with (and not even that if you put the
> validation in the stub resolver, but there are good reasons not to do
> that, as above). A pure-proxying server that relies on upstream
> recursives can do full DNSSEC validation. Dnsmasq is a canonical
> example. I believe systemd-resolvd also does it.
>

That's fair, and I apologize for overstating my point. I absolutely agree
that if you run a validating recursive resolver locally, then the attack I
described isn't possible. When DNSSEC was designed, it was intended to be
deployed in the model I described, where the validating recursive resolver
is not on-device. And that's how it is still mostly deployed today because
almost all general-purpose client devices do not validate locally. My
mental model is very focused around consumer devices where folks buy them
and use them without ever changing default settings. That might be a
portion of musl users, but you clearly also have advanced users that do
things differently.

> > > Regarding untrusted networks, one thing I hadn't considered yet is
> > > > > that a network configurator probably needs a way to setup
> resolv.conf
> > > > > such that .local queries temp-fail rather than perma-fail (as they
> > > > > would if you just sent the query to public dns) to use during
> certain
> > > > > race windows while switching networks. IOW "send .local queries to
> > > > > configured nameservers" and "treat .local specially but with an
> empty
> > > > > list of interfaces to send to" should be distinct configurations.
> > > >
> > > > Yeah, caching negative results in DNS has been a tricky thing from
> the
> > > > start. You probably could hack something by installing a fake SOA
> record
> > > > for .local. in your recursive resolver running on localhost. But the
> > > > RFC-compliant answer is for stub resolvers to treat it specially and
> know
> > > > that those often never get an answer (musl doesn't cache DNS results
> so
> > > in
> > > > a way we're avoiding this problem altogether at the stub resolver).
> > >
> > > The problem here is not about caching, just about clients using a
> > > response. You want a task (like a browser with open tabs) trying to
> > > contact the site to get a tempfail rather than NxDomain which might
> > > make it stop trying. But you probably want NxDomain if mDNS has been
> > > disabled entirely, so that every .local lookup doesn't hang 5 seconds
> > > or whatever before saying "inconclusive".
> >
> > I'm assuming that by tempfail you mean EAI_AGAIN. The two browsers that
> > I've written code in don't use that (Chrome just treats it the same as a
> > resolution failure and will automatically refresh the tab on a network
> > change; Safari doesn't use getaddrinfo and instead relies on an
> > asynchronous DNS API that adds results as they come in - I wrote that
> > algorithm up in RFC 8305). All that said, synchronous blocking APIs like
> > getaddrinfo need to eventually return even if no one replies, so
> EAI_AGAIN
> > makes sense in that case - whereas if .local is blocked by policy then
> > immediately returning EAI_NONAME is best.
>
> Right. Even if applications don't currently distinguish them well,
> returning EAI_AGAIN vs EAI_NONAME is meaningful and enables them to do
> the right thing.
>

Agreed.

Thinking back to our discussion about whether to disable mDNS when the
resolver is on localhost. I still agree that from an ergonomics
perspective, using configs to mean multiple things isn't great. But
focusing just on the security properties for a second: if resolv.conf is
configured to an IP address that is routed over a given non-loopback
interface, the current status quo is to send the .local query unsecured
over that interface. So if we were to, in that specific scenario, instead
send the query over multicast, but only on that interface - then we
wouldn't measurably change the security properties of the system. In
practice there is a slight difference where now you can be attacked by any
device on the network as opposed to only by the router on that network, but
I'd argue that there's no meaningful threat model that distinguishes
between those two attacks. So that would be a safe default option. But
again, your points about least surprise are still valid, so if you object
to that on those grounds I can't disagree.

David

[-- Attachment #2: Type: text/html, Size: 21409 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-08 22:54                             ` Rich Felker
  2024-03-08 23:44                               ` David Schinazi
@ 2024-03-09  0:23                               ` Jeffrey Walton
  1 sibling, 0 replies; 32+ messages in thread
From: Jeffrey Walton @ 2024-03-09  0:23 UTC (permalink / raw)
  To: musl; +Cc: David Schinazi

On Fri, Mar 8, 2024 at 5:54 PM Rich Felker <dalias@libc.org> wrote:
>
> On Fri, Mar 08, 2024 at 01:55:18PM -0800, David Schinazi wrote:
> > On Fri, Mar 8, 2024 at 12:31 PM Rich Felker <dalias@libc.org> wrote:
> >
> > > On Fri, Mar 08, 2024 at 11:15:52AM -0800, David Schinazi wrote:
> > > > On Fri, Mar 8, 2024 at 5:30 AM Rich Felker <dalias@libc.org> wrote:
> > > >
> > > > > On Thu, Mar 07, 2024 at 08:47:20PM -0800, David Schinazi wrote:
> > > > > > Thanks. How would you feel about the following potential
> > > configuration
> > > > > > design?
> > > > > > * Add a new configuration option "send_mdns_unicast"
> > > > > > * When true, use the current behavior
> > > > > > * When false, send the query on all non-loopback non-p2p interfaces
> > > > > > * Have send_mdns_unicast default to false
> > > > > >
> > > > > > I was thinking through how to pick interfaces, looked up what other
> > > mDNS
> > > > > > libraries do, and pretty much all of them don't allow configuring
> > > > > > interfaces, whereas Avahi exposes allow-interfaces and
> > > deny-interfaces.
> > > > > I'm
> > > > > > leaning towards not making this configurable to reduce complexity. I
> > > > > think
> > > > > > that anyone interested in that level of config is probably using
> > > Avahi
> > > > > > anyway.
> > > > > >
> > > > > > Additionally this design has two nice properties: the default
> > > behavior is
> > > > > > RFC-compliant, and it means that for my use-case I don't need to
> > > change
> > > > > the
> > > > > > config file, which was a big part of my motivation for doing this
> > > inside
> > > > > of
> > > > > > musl in the first place :-)
> > > > >
> > > > > As discussed in this thread, I don't think so. The biggest problems I
> > > > > initially brought up were increased information leakage in the default
> > > > > configuration and inability to control where the traffic goes when you
> > > > > do want it on. The above proposal just reverts to the initial, except
> > > > > for providing a way to opt-out.
> > > > >
> > > > > For the most part, mDNS is very much a "home user, personal device on
> > > > > trusted network" thing. Not only do you not want it to default on
> > > > > because a lot of systems will be network servers on networks where
> > > > > it's not meaningful (and can be a weakness that aids attackers in
> > > > > lateral movement), but you also don't want it on when connected to
> > > > > public wifi. For example if you have an open browser tab to
> > > > > http://mything.local, and migrate to an untrusted network (with your
> > > > > laptop, tablet, phone, whatever), now your browser will be leaking
> > > > > private data (likely at least session auth tokens, maybe more) to
> > > > > whoever answers the mDNS query for mything.local.
> > > >
> > > > That's not quite right. The security properties of mDNS and DNS are the
> > > > same. DNS is inherently insecure, regardless of unicast vs multicast. If
> > > > I'm on a coffee shop Wi-Fi, all my DNS queries are sent in the clear to
> > > > whatever IP address the DHCP server gave me.
> > >
> > > That's not the case. Connections to non-mDNS hosts are authenticated
> > > by TLS with certificates issued on the basis of ownership of the
> > > domain name. That's not possible with mDNS hostnames, so they'll
> > > either be no-TLS or self-signed certs. That's why the above attack is
> > > possible. It was also possible with normal DNS in the bad old days of
> > > http://, but that time is long gone.
> >
> > Apologies for being pedantic, but that's not true. The ability to get TLS
> > certificates for a domain name that you own is a property of the WebPKI,
> > not a property of TLS. What you wrote is true, but only in the context of a
> > Web browser with an unmodified root certificate store. The features I
> > mentioned above don't use the WebPKI, they have a separate root of trust.
> > For example, some of those Apple features exchange TLS certificates via an
> > out-of-band mechanism such as Apple trusted servers. Another example is the
> > Apple Watch: when you first pair a new Apple Watch with an iPhone, they
> > exchange ed25519 public keys. Then any time the watch wants to transfer a
> > large file to/from the phone, it'll connect to Wi-Fi, use mDNS to find the
> > phone, and set up an IKEv2/IPsec tunnel that then protects the exchange.
> > It's resilient to any attacks at the mDNS level.
> >
> > You're absolutely right that the security of Web requests using local
> > connectivity is completely broken by the lack of WebPKI certificates for
> > those. But sending the DNS query over multicast as opposed to unencrypted
> > unicast to an untrusted DNS server doesn't change the security properties.
> > In your example above, the open tab to http://mything.local will send that
> > query to the recursive resolver - and if that's the one received by DHCP
> > then that server can reply with its own address and receive your auth
> > tokens. One potential fix here is to configure your resolv.conf to
> > localhost and then apply policy in that local resolver. But in practice,
> > application developers don't rely on security at that layer, they assume
> > that DNS is unsafe and implement encryption in userspace with some out of
> > band trust mechanism.
>
> My specific example was http://mything.local in a web browser, which
> is the way you access lots of mDNS-enabled things in the absence of a
> specific software ecosystem like Apple's. Since we're talking about
> musl which would be running on Linux or a Linux-syscall-compatible
> environment, without Apple apps, I think that's the main way anyone
> would be using hypothetical mDNS support. And indeed this is the way
> you access many printers, 3D printers, IP cameras, etc.
>
> Maybe at some point we'll have a good framework for authenticating
> this kind of usage with certificates (probably certificate pinning on
> first use, with good UX, is the only easy solution), but at present,
> mDNS devices on the .local zone get accessed with plain http:// all
> the time, and this means it's unsafe to do mDNS on
> public/untrusted/hostile networks.

One comment about pinning. I think host key pinning is a great
security control. Key continuity is a better security property than
key rotation.

Unfortunately, the CA/Browser Forum and IETF are moving the other way.
They are hostile to pinning, they are actively working against it by
using short-lived intermediate CA certificates, by not providing key
rollover hints in existing certificates, and recommending a new key
for each end-entity (host) certificate.

I was very disappointed to see the IETF get onboard with the
CA/Browser Forum. It looks like the IETF has been captured again.

So pinning may not be a viable solution when the time comes.

Jeff

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-08 23:44                               ` David Schinazi
@ 2024-03-21  9:21                                 ` David Schinazi
  2024-03-21 12:07                                   ` Rich Felker
  0 siblings, 1 reply; 32+ messages in thread
From: David Schinazi @ 2024-03-21  9:21 UTC (permalink / raw)
  To: Rich Felker; +Cc: musl

[-- Attachment #1: Type: text/plain, Size: 18896 bytes --]

Hi,

Earlier today at IETF, I discussed this topic with Stuart Cheshire, the
creator of mDNS. From his perspective, implementing a simpler option in
musl makes a lot of sense. Even though querying mDNS on a single interface
is not comprehensive, it'll work for the majority of uses while minimizing
implementation complexity. Using the UDP connect() trick to find the
interface corresponding to the configured resolver and then sending
multicast only on that interface will work and provide reasonable security
properties. He recommends using the IP_MULTICAST_IF / IPV6_MULTICAST_IF
socket options to select an interface, as that's what mDNSResponder does on
Linux. Additionally, he feels strongly that this should be enabled by
default, since the whole point of zero-configuration networking was for
things to work without requiring user configuration.

Thanks,
David

On Sat, Mar 9, 2024 at 9:44 AM David Schinazi <dschinazi.ietf@gmail.com>
wrote:

>
>
> On Fri, Mar 8, 2024 at 2:54 PM Rich Felker <dalias@libc.org> wrote:
>
>> On Fri, Mar 08, 2024 at 01:55:18PM -0800, David Schinazi wrote:
>> > On Fri, Mar 8, 2024 at 12:31 PM Rich Felker <dalias@libc.org> wrote:
>> >
>> > > On Fri, Mar 08, 2024 at 11:15:52AM -0800, David Schinazi wrote:
>> > > > On Fri, Mar 8, 2024 at 5:30 AM Rich Felker <dalias@libc.org> wrote:
>> > > >
>> > > > > On Thu, Mar 07, 2024 at 08:47:20PM -0800, David Schinazi wrote:
>> > > > > > Thanks. How would you feel about the following potential
>> > > configuration
>> > > > > > design?
>> > > > > > * Add a new configuration option "send_mdns_unicast"
>> > > > > > * When true, use the current behavior
>> > > > > > * When false, send the query on all non-loopback non-p2p
>> interfaces
>> > > > > > * Have send_mdns_unicast default to false
>> > > > > >
>> > > > > > I was thinking through how to pick interfaces, looked up what
>> other
>> > > mDNS
>> > > > > > libraries do, and pretty much all of them don't allow
>> configuring
>> > > > > > interfaces, whereas Avahi exposes allow-interfaces and
>> > > deny-interfaces.
>> > > > > I'm
>> > > > > > leaning towards not making this configurable to reduce
>> complexity. I
>> > > > > think
>> > > > > > that anyone interested in that level of config is probably using
>> > > Avahi
>> > > > > > anyway.
>> > > > > >
>> > > > > > Additionally this design has two nice properties: the default
>> > > behavior is
>> > > > > > RFC-compliant, and it means that for my use-case I don't need to
>> > > change
>> > > > > the
>> > > > > > config file, which was a big part of my motivation for doing
>> this
>> > > inside
>> > > > > of
>> > > > > > musl in the first place :-)
>> > > > >
>> > > > > As discussed in this thread, I don't think so. The biggest
>> problems I
>> > > > > initially brought up were increased information leakage in the
>> default
>> > > > > configuration and inability to control where the traffic goes
>> when you
>> > > > > do want it on. The above proposal just reverts to the initial,
>> except
>> > > > > for providing a way to opt-out.
>> > > > >
>> > > > > For the most part, mDNS is very much a "home user, personal
>> device on
>> > > > > trusted network" thing. Not only do you not want it to default on
>> > > > > because a lot of systems will be network servers on networks where
>> > > > > it's not meaningful (and can be a weakness that aids attackers in
>> > > > > lateral movement), but you also don't want it on when connected to
>> > > > > public wifi. For example if you have an open browser tab to
>> > > > > http://mything.local, and migrate to an untrusted network (with
>> your
>> > > > > laptop, tablet, phone, whatever), now your browser will be leaking
>> > > > > private data (likely at least session auth tokens, maybe more) to
>> > > > > whoever answers the mDNS query for mything.local.
>> > > >
>> > > > That's not quite right. The security properties of mDNS and DNS are
>> the
>> > > > same. DNS is inherently insecure, regardless of unicast vs
>> multicast. If
>> > > > I'm on a coffee shop Wi-Fi, all my DNS queries are sent in the
>> clear to
>> > > > whatever IP address the DHCP server gave me.
>> > >
>> > > That's not the case. Connections to non-mDNS hosts are authenticated
>> > > by TLS with certificates issued on the basis of ownership of the
>> > > domain name. That's not possible with mDNS hostnames, so they'll
>> > > either be no-TLS or self-signed certs. That's why the above attack is
>> > > possible. It was also possible with normal DNS in the bad old days of
>> > > http://, but that time is long gone.
>> >
>> > Apologies for being pedantic, but that's not true. The ability to get
>> TLS
>> > certificates for a domain name that you own is a property of the WebPKI,
>> > not a property of TLS. What you wrote is true, but only in the context
>> of a
>> > Web browser with an unmodified root certificate store. The features I
>> > mentioned above don't use the WebPKI, they have a separate root of
>> trust.
>> > For example, some of those Apple features exchange TLS certificates via
>> an
>> > out-of-band mechanism such as Apple trusted servers. Another example is
>> the
>> > Apple Watch: when you first pair a new Apple Watch with an iPhone, they
>> > exchange ed25519 public keys. Then any time the watch wants to transfer
>> a
>> > large file to/from the phone, it'll connect to Wi-Fi, use mDNS to find
>> the
>> > phone, and set up an IKEv2/IPsec tunnel that then protects the exchange.
>> > It's resilient to any attacks at the mDNS level.
>> >
>> > You're absolutely right that the security of Web requests using local
>> > connectivity is completely broken by the lack of WebPKI certificates for
>> > those. But sending the DNS query over multicast as opposed to
>> unencrypted
>> > unicast to an untrusted DNS server doesn't change the security
>> properties.
>> > In your example above, the open tab to http://mything.local will send
>> that
>> > query to the recursive resolver - and if that's the one received by DHCP
>> > then that server can reply with its own address and receive your auth
>> > tokens. One potential fix here is to configure your resolv.conf to
>> > localhost and then apply policy in that local resolver. But in practice,
>> > application developers don't rely on security at that layer, they assume
>> > that DNS is unsafe and implement encryption in userspace with some out
>> of
>> > band trust mechanism.
>>
>> My specific example was http://mything.local in a web browser, which
>> is the way you access lots of mDNS-enabled things in the absence of a
>> specific software ecosystem like Apple's. Since we're talking about
>> musl which would be running on Linux or a Linux-syscall-compatible
>> environment, without Apple apps, I think that's the main way anyone
>> would be using hypothetical mDNS support. And indeed this is the way
>> you access many printers, 3D printers, IP cameras, etc.
>>
>
> I have multiple services at home that use HTTP and mDNS to communicate
> with. But they're built knowing that unencrypted HTTP is unsafe. For
> example, one of my servers doesn't have any authentication - my browser
> just uses unauthenticated GETs, POSTs and WebSockets. If I leave the tab
> open and go to a coffee shop, my browser might send that GET to a server I
> don't trust but that request won't carry any sensitive information. Another
> of my servers uses TLS with self-signed certs, so every time I want to
> communicate with it, I need to click through my browser's "this is unsafe"
> interstitial to get to the page. If I switch networks, the browser will
> send me the warning again and I'll know not to click through when I'm not
> at home. In both of those cases, the security is handled (or not handled at
> all) at the application layer.
>
> Maybe at some point we'll have a good framework for authenticating
>> this kind of usage with certificates (probably certificate pinning on
>> first use, with good UX, is the only easy solution),
>
>
> Trust on first use works, or even better there are emerging solutions that
> leverage codes printed on devices and PAKEs so that a device on the
> untrusted network can't even hijack the first connection without having
> access to that code. The leading one for home automation is Matter [1].
> Coincidentally, it also leverages mDNS for discovery, and doesn't rely on
> security at the DNS level.
>
> [1] https://csa-iot.org/all-solutions/matter/
>
> but at present,
>> mDNS devices on the .local zone get accessed with plain http:// all
>> the time, and this means it's unsafe to do mDNS on
>> public/untrusted/hostile networks.
>>
>
> The notion of something being "unsafe" (and security in general) is
> predicated on the existence of a threat model. It's unsafe to use
> unencrypted HTTP to your bank when your threat model includes someone on
> the coffee shop Wi-Fi trying to steal your bank credentials. Conversely,
> it's safe for me to print to this coffee shop printer if my threat model
> assumes that I'm ok with the owner of the coffee shop seeing my document.
> Another example is Chromecast which also uses mDNS: from Chrome on a Linux
> laptop, I can cast YouTube videos to the TV in this coffee shop. That's
> safe because I trust the network with the YouTube link I'm telling the TV
> to play. mDNS is not in and of itself safe or unsafe. It converts
> names into addresses, and what you do with those addresses can potentially
> be unsafe.
>
> That doesn't mean that every single use of mDNS on untrusted networks is
> safe. If someone builds a web page that sends valuable secrets over
> unencrypted HTTP to a .local name, then you have a security problem. But my
> point is that this security problem needs to be solved at the application
> layer and not at the DNS layer. That said, I agree that having a way to
> disable mDNS on a machine is a good idea, because there probably are users
> out there that are stuck with applications that for some reason decided to
> rely on DNS being secure.
>
> In terms of the tradeoff between usability and security, the default to me
> lies with default-enabling mDNS on all interfaces as Apple and Avahi do.
> But this tradeoff is between two metrics that can't be quantified one
> against the other for all possible uses, so I totally understand if your
> opinion for musl is that the tradeoff there is different than in other
> situations. You know your users better than I do.
>
> > > So the stack has to deal with
>> > > > the fact that any DNS response can be spoofed.
>> > >
>> > > That's also not possible with DNSSEC, but only helps if you're
>> > > validating it.
>> > >
>> > > > The most widely used
>> > > > solution is TLS: a successful DNS hijack can prevent you from
>> accessing a
>> > > > TLS service, but can't impersonate it. That's true of both mDNS and
>> > > regular
>> > > > unicast DNS. As an example, all Apple devices have mDNS enabled on
>> all
>> > > > interfaces, with no security impact - the features that rely on it
>> > > > (AirDrop, AirPlay, contact sharing, etc) all use mTLS to ensure
>> they're
>> > > > talking to the right device regardless of the correctness of DNS.
>> > > (Printing
>> > > > remains completely insecure, but that's also independent of DNS -
>> your
>> > > > coffee shop Wi-Fi access point can attack you at the IP layer too).
>> One
>> > > > might think that DNSSEC could save us here, but it doesn't. DNSSEC
>> was
>> > > > unfortunately built with a fundamental design flaw: it requires you
>> to
>> > > > trust all resolvers on the path, including recursive resolvers. So
>> even
>> > > if
>> > > > you ask for DNSSEC validation of the DNS records for
>> www.example.com,
>> > > your
>> > > > coffee shop DNS recursive resolver can tell you "I checked, and
>> > > example.com
>> > > > does not support DNSSEC, here's the IP address for www.example.com
>> > > though"
>> > > > and you have to accept it.
>> > >
>> > > This is a completely false but somehow persistent myth about DNSSEC.
>> > > You cannot lie that a zone does not support DNSSEC. The only way to
>> > > claim a zone does not support DNSSEC is with a signature chain from
>> > > the DNS root proving the nonexistence of the DS records for the
>> > > delegation. Without that, the reply is BOGUS and will be ignored as if
>> > > there was no reply at all.
>> >
>> > I was talking about the case where the recursive resolver does the
>> > validation, which is what's deployed in practice today. What you wrote
>> is
>> > only true if the client does the DNSSEC validation itself. Most clients
>> > don't do that today, because too many domains are just misconfigured and
>> > broken. Eric Rescorla (the editor of the TLS RFCs) wrote a great blog
>> post
>> > about this:
>>
>> The consensus of folks in the stub resolver space (at least glibc+musl
>> and I would assume the BSDs as well) is that the way you do DNSSEC
>> validation is by having a validating caching proxy or full recursive
>> resolver on localhost. Doing validation in the stub resolver is not
>> viable because it may be static-linked, where it would not be able to
>> be updated with new algorithms, root-of-trust, etc.
>
>
> No disagreement there. By "client" I meant the client device as a whole,
> and by "recursive resolver" I meant "the DNS server you got from DHCP".
> Running a DNSSEC-validating recursive resolver on the client device falls
> into what I meant by "if the client does the DNSSEC validation itself".
> Sorry for being unclear.
>
>
>> This is one of the
>> reasons our go-to response for new functionality wanted in the stub
>> resolver is "do it in a nameserver on localhost" -- because you
>> already need that to do DNSSEC.
>>
>
> That makes sense. I wasn't working with the assumption that DNSSEC was a
> requirement.
>
> It really did not sound like you were talking about trusting the
>> recursive, though. You called it a "fundamental design flaw", which it
>> is not, and said it requires you to "trust all resolvers on the path",
>> which it does not. It only requires you to trust the immediate
>> resolver you are interacting with (and not even that if you put the
>> validation in the stub resolver, but there are good reasons not to do
>> that, as above). A pure-proxying server that relies on upstream
>> recursives can do full DNSSEC validation. Dnsmasq is a canonical
>> example. I believe systemd-resolvd also does it.
>>
>
> That's fair, and I apologize for overstating my point. I absolutely agree
> that if you run a validating recursive resolver locally, then the attack I
> described isn't possible. When DNSSEC was designed, it was intended to be
> deployed in the model I described, where the validating recursive resolver
> is not on-device. And that's how it is still mostly deployed today because
> almost all general-purpose client devices do not validate locally. My
> mental model is very focused around consumer devices where folks buy them
> and use them without ever changing default settings. That might be a
> portion of musl users, but you clearly also have advanced users that do
> things differently.
>
> > > > Regarding untrusted networks, one thing I hadn't considered yet is
>> > > > > that a network configurator probably needs a way to setup
>> resolv.conf
>> > > > > such that .local queries temp-fail rather than perma-fail (as they
>> > > > > would if you just sent the query to public dns) to use during
>> certain
>> > > > > race windows while switching networks. IOW "send .local queries to
>> > > > > configured nameservers" and "treat .local specially but with an
>> empty
>> > > > > list of interfaces to send to" should be distinct configurations.
>> > > >
>> > > > Yeah, caching negative results in DNS has been a tricky thing from
>> the
>> > > > start. You probably could hack something by installing a fake SOA
>> record
>> > > > for .local. in your recursive resolver running on localhost. But the
>> > > > RFC-compliant answer is for stub resolvers to treat it specially
>> and know
>> > > > that those often never get an answer (musl doesn't cache DNS
>> results so
>> > > in
>> > > > a way we're avoiding this problem altogether at the stub resolver).
>> > >
>> > > The problem here is not about caching, just about clients using a
>> > > response. You want a task (like a browser with open tabs) trying to
>> > > contact the site to get a tempfail rather than NxDomain which might
>> > > make it stop trying. But you probably want NxDomain if mDNS has been
>> > > disabled entirely, so that every .local lookup doesn't hang 5 seconds
>> > > or whatever before saying "inconclusive".
>> >
>> > I'm assuming that by tempfail you mean EAI_AGAIN. The two browsers that
>> > I've written code in don't use that (Chrome just treats it the same as a
>> > resolution failure and will automatically refresh the tab on a network
>> > change; Safari doesn't use getaddrinfo and instead relies on an
>> > asynchronous DNS API that adds results as they come in - I wrote that
>> > algorithm up in RFC 8305). All that said, synchronous blocking APIs like
>> > getaddrinfo need to eventually return even if no one replies, so
>> EAI_AGAIN
>> > makes sense in that case - whereas if .local is blocked by policy then
>> > immediately returning EAI_NONAME is best.
>>
>> Right. Even if applications don't currently distinguish them well,
>> returning EAI_AGAIN vs EAI_NONAME is meaningful and enables them to do
>> the right thing.
>>
>
> Agreed.
>
> Thinking back to our discussion about whether to disable mDNS when the
> resolver is on localhost. I still agree that from an ergonomics
> perspective, using configs to mean multiple things isn't great. But
> focusing just on the security properties for a second: if resolv.conf is
> configured to an IP address that is routed over a given non-loopback
> interface, the current status quo is to send the .local query unsecured
> over that interface. So if we were to, in that specific scenario, instead
> send the query over multicast, but only on that interface - then we
> wouldn't measurably change the security properties of the system. In
> practice there is a slight difference where now you can be attacked by any
> device on the network as opposed to only by the router on that network, but
> I'd argue that there's no meaningful threat model that distinguishes
> between those two attacks. So that would be a safe default option. But
> again, your points about least surprise are still valid, so if you object
> to that on those grounds I can't disagree.
>
> David
>

[-- Attachment #2: Type: text/html, Size: 22745 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-21  9:21                                 ` David Schinazi
@ 2024-03-21 12:07                                   ` Rich Felker
  2024-03-21 13:50                                     ` David Schinazi
  0 siblings, 1 reply; 32+ messages in thread
From: Rich Felker @ 2024-03-21 12:07 UTC (permalink / raw)
  To: David Schinazi; +Cc: musl

On Thu, Mar 21, 2024 at 07:21:05PM +1000, David Schinazi wrote:
> Hi,
> 
> Earlier today at IETF, I discussed this topic with Stuart Cheshire, the
> creator of mDNS. From his perspective, implementing a simpler option in
> musl makes a lot of sense. Even though querying mDNS on a single interface
> is not comprehensive, it'll work for the majority of uses while minimizing
> implementation complexity. Using the UDP connect() trick to find the
> interface corresponding to the configured resolver and then sending
> multicast only on that interface will work and provide reasonable security
> properties. He recommends using the IP_MULTICAST_IF / IPV6_MULTICAST_IF
> socket options to select an interface, as that's what mDNSResponder does on
> Linux. Additionally, he feels strongly that this should be enabled by
> default, since the whole point of zero-configuration networking was for
> things to work without requiring user configuration.

Again, most of these choices are *not workable*. They have already
been rejected.

If you want this to happen, let's please work on something that has
not been rejected.

1. Why on-by-default was rejected:

musl is not only or even mostly used in a desktop user configuration
where mDNS makes sense. It's used in lots of places where silently
starting (after upgrade) to query other devices on a network and
accepting answers from them is unexpected and hostile behavior. Yes,
"on by default" makes sense on an end-user desktop system connected to
a *private* network. This would be a default of the particular OS
using musl and its network configurator, not of musl itself. (And
AFAIK mDNS is not even "on my default" on Windows unless the connected
network is marked as private.)

2. Why deciding what network to query based on the interface of the
configured resolver is rejected:

In a proper DNSSEC-validating setup, the configured resolver is
127.0.0.1 or ::1. This would disable mDNS entirely, forcing you to
essentially *switch DNSSEC off if you want mDNS*. It was already
explained why this is very bad.

Single-interface query has not been rejected, but I don't see any
reason to limit mDNS to a single interface. That doesn't make it
particularly simpler or anything. If you're able to select the
interface, it's just as easy to allow selecting a reasonable number of
interfaces.

The particular implementation mechanisms we've discussed, including
possibly identifying the interface(s) to send to via where a
particular address would be routed, seem overall good.


> On Sat, Mar 9, 2024 at 9:44 AM David Schinazi <dschinazi.ietf@gmail..com>
> wrote:
> 
> >
> >
> > On Fri, Mar 8, 2024 at 2:54 PM Rich Felker <dalias@libc.org> wrote:
> >
> >> On Fri, Mar 08, 2024 at 01:55:18PM -0800, David Schinazi wrote:
> >> > On Fri, Mar 8, 2024 at 12:31 PM Rich Felker <dalias@libc.org> wrote:
> >> >
> >> > > On Fri, Mar 08, 2024 at 11:15:52AM -0800, David Schinazi wrote:
> >> > > > On Fri, Mar 8, 2024 at 5:30 AM Rich Felker <dalias@libc.org> wrote:
> >> > > >
> >> > > > > On Thu, Mar 07, 2024 at 08:47:20PM -0800, David Schinazi wrote:
> >> > > > > > Thanks. How would you feel about the following potential
> >> > > configuration
> >> > > > > > design?
> >> > > > > > * Add a new configuration option "send_mdns_unicast"
> >> > > > > > * When true, use the current behavior
> >> > > > > > * When false, send the query on all non-loopback non-p2p
> >> interfaces
> >> > > > > > * Have send_mdns_unicast default to false
> >> > > > > >
> >> > > > > > I was thinking through how to pick interfaces, looked up what
> >> other
> >> > > mDNS
> >> > > > > > libraries do, and pretty much all of them don't allow
> >> configuring
> >> > > > > > interfaces, whereas Avahi exposes allow-interfaces and
> >> > > deny-interfaces.
> >> > > > > I'm
> >> > > > > > leaning towards not making this configurable to reduce
> >> complexity. I
> >> > > > > think
> >> > > > > > that anyone interested in that level of config is probably using
> >> > > Avahi
> >> > > > > > anyway.
> >> > > > > >
> >> > > > > > Additionally this design has two nice properties: the default
> >> > > behavior is
> >> > > > > > RFC-compliant, and it means that for my use-case I don't need to
> >> > > change
> >> > > > > the
> >> > > > > > config file, which was a big part of my motivation for doing
> >> this
> >> > > inside
> >> > > > > of
> >> > > > > > musl in the first place :-)
> >> > > > >
> >> > > > > As discussed in this thread, I don't think so. The biggest
> >> problems I
> >> > > > > initially brought up were increased information leakage in the
> >> default
> >> > > > > configuration and inability to control where the traffic goes
> >> when you
> >> > > > > do want it on. The above proposal just reverts to the initial,
> >> except
> >> > > > > for providing a way to opt-out.
> >> > > > >
> >> > > > > For the most part, mDNS is very much a "home user, personal
> >> device on
> >> > > > > trusted network" thing. Not only do you not want it to default on
> >> > > > > because a lot of systems will be network servers on networks where
> >> > > > > it's not meaningful (and can be a weakness that aids attackers in
> >> > > > > lateral movement), but you also don't want it on when connected to
> >> > > > > public wifi. For example if you have an open browser tab to
> >> > > > > http://mything.local, and migrate to an untrusted network (with
> >> your
> >> > > > > laptop, tablet, phone, whatever), now your browser will be leaking
> >> > > > > private data (likely at least session auth tokens, maybe more) to
> >> > > > > whoever answers the mDNS query for mything.local.
> >> > > >
> >> > > > That's not quite right. The security properties of mDNS and DNS are
> >> the
> >> > > > same. DNS is inherently insecure, regardless of unicast vs
> >> multicast. If
> >> > > > I'm on a coffee shop Wi-Fi, all my DNS queries are sent in the
> >> clear to
> >> > > > whatever IP address the DHCP server gave me.
> >> > >
> >> > > That's not the case. Connections to non-mDNS hosts are authenticated
> >> > > by TLS with certificates issued on the basis of ownership of the
> >> > > domain name. That's not possible with mDNS hostnames, so they'll
> >> > > either be no-TLS or self-signed certs. That's why the above attack is
> >> > > possible. It was also possible with normal DNS in the bad old days of
> >> > > http://, but that time is long gone.
> >> >
> >> > Apologies for being pedantic, but that's not true. The ability to get
> >> TLS
> >> > certificates for a domain name that you own is a property of the WebPKI,
> >> > not a property of TLS. What you wrote is true, but only in the context
> >> of a
> >> > Web browser with an unmodified root certificate store. The features I
> >> > mentioned above don't use the WebPKI, they have a separate root of
> >> trust.
> >> > For example, some of those Apple features exchange TLS certificates via
> >> an
> >> > out-of-band mechanism such as Apple trusted servers. Another example is
> >> the
> >> > Apple Watch: when you first pair a new Apple Watch with an iPhone, they
> >> > exchange ed25519 public keys. Then any time the watch wants to transfer
> >> a
> >> > large file to/from the phone, it'll connect to Wi-Fi, use mDNS to find
> >> the
> >> > phone, and set up an IKEv2/IPsec tunnel that then protects the exchange.
> >> > It's resilient to any attacks at the mDNS level.
> >> >
> >> > You're absolutely right that the security of Web requests using local
> >> > connectivity is completely broken by the lack of WebPKI certificates for
> >> > those. But sending the DNS query over multicast as opposed to
> >> unencrypted
> >> > unicast to an untrusted DNS server doesn't change the security
> >> properties.
> >> > In your example above, the open tab to http://mything.local will send
> >> that
> >> > query to the recursive resolver - and if that's the one received by DHCP
> >> > then that server can reply with its own address and receive your auth
> >> > tokens. One potential fix here is to configure your resolv.conf to
> >> > localhost and then apply policy in that local resolver. But in practice,
> >> > application developers don't rely on security at that layer, they assume
> >> > that DNS is unsafe and implement encryption in userspace with some out
> >> of
> >> > band trust mechanism.
> >>
> >> My specific example was http://mything.local in a web browser, which
> >> is the way you access lots of mDNS-enabled things in the absence of a
> >> specific software ecosystem like Apple's. Since we're talking about
> >> musl which would be running on Linux or a Linux-syscall-compatible
> >> environment, without Apple apps, I think that's the main way anyone
> >> would be using hypothetical mDNS support. And indeed this is the way
> >> you access many printers, 3D printers, IP cameras, etc.
> >>
> >
> > I have multiple services at home that use HTTP and mDNS to communicate
> > with. But they're built knowing that unencrypted HTTP is unsafe. For
> > example, one of my servers doesn't have any authentication - my browser
> > just uses unauthenticated GETs, POSTs and WebSockets. If I leave the tab
> > open and go to a coffee shop, my browser might send that GET to a server I
> > don't trust but that request won't carry any sensitive information. Another
> > of my servers uses TLS with self-signed certs, so every time I want to
> > communicate with it, I need to click through my browser's "this is unsafe"
> > interstitial to get to the page. If I switch networks, the browser will
> > send me the warning again and I'll know not to click through when I'm not
> > at home. In both of those cases, the security is handled (or not handled at
> > all) at the application layer.
> >
> > Maybe at some point we'll have a good framework for authenticating
> >> this kind of usage with certificates (probably certificate pinning on
> >> first use, with good UX, is the only easy solution),
> >
> >
> > Trust on first use works, or even better there are emerging solutions that
> > leverage codes printed on devices and PAKEs so that a device on the
> > untrusted network can't even hijack the first connection without having
> > access to that code. The leading one for home automation is Matter [1].
> > Coincidentally, it also leverages mDNS for discovery, and doesn't rely on
> > security at the DNS level.
> >
> > [1] https://csa-iot.org/all-solutions/matter/
> >
> > but at present,
> >> mDNS devices on the .local zone get accessed with plain http:// all
> >> the time, and this means it's unsafe to do mDNS on
> >> public/untrusted/hostile networks.
> >>
> >
> > The notion of something being "unsafe" (and security in general) is
> > predicated on the existence of a threat model. It's unsafe to use
> > unencrypted HTTP to your bank when your threat model includes someone on
> > the coffee shop Wi-Fi trying to steal your bank credentials. Conversely,
> > it's safe for me to print to this coffee shop printer if my threat model
> > assumes that I'm ok with the owner of the coffee shop seeing my document.
> > Another example is Chromecast which also uses mDNS: from Chrome on a Linux
> > laptop, I can cast YouTube videos to the TV in this coffee shop. That's
> > safe because I trust the network with the YouTube link I'm telling the TV
> > to play. mDNS is not in and of itself safe or unsafe. It converts
> > names into addresses, and what you do with those addresses can potentially
> > be unsafe.
> >
> > That doesn't mean that every single use of mDNS on untrusted networks is
> > safe. If someone builds a web page that sends valuable secrets over
> > unencrypted HTTP to a .local name, then you have a security problem. But my
> > point is that this security problem needs to be solved at the application
> > layer and not at the DNS layer. That said, I agree that having a way to
> > disable mDNS on a machine is a good idea, because there probably are users
> > out there that are stuck with applications that for some reason decided to
> > rely on DNS being secure.
> >
> > In terms of the tradeoff between usability and security, the default to me
> > lies with default-enabling mDNS on all interfaces as Apple and Avahi do.
> > But this tradeoff is between two metrics that can't be quantified one
> > against the other for all possible uses, so I totally understand if your
> > opinion for musl is that the tradeoff there is different than in other
> > situations. You know your users better than I do.
> >
> > > > So the stack has to deal with
> >> > > > the fact that any DNS response can be spoofed.
> >> > >
> >> > > That's also not possible with DNSSEC, but only helps if you're
> >> > > validating it.
> >> > >
> >> > > > The most widely used
> >> > > > solution is TLS: a successful DNS hijack can prevent you from
> >> accessing a
> >> > > > TLS service, but can't impersonate it. That's true of both mDNS and
> >> > > regular
> >> > > > unicast DNS. As an example, all Apple devices have mDNS enabled on
> >> all
> >> > > > interfaces, with no security impact - the features that rely on it
> >> > > > (AirDrop, AirPlay, contact sharing, etc) all use mTLS to ensure
> >> they're
> >> > > > talking to the right device regardless of the correctness of DNS.
> >> > > (Printing
> >> > > > remains completely insecure, but that's also independent of DNS -
> >> your
> >> > > > coffee shop Wi-Fi access point can attack you at the IP layer too)..
> >> One
> >> > > > might think that DNSSEC could save us here, but it doesn't. DNSSEC
> >> was
> >> > > > unfortunately built with a fundamental design flaw: it requires you
> >> to
> >> > > > trust all resolvers on the path, including recursive resolvers. So
> >> even
> >> > > if
> >> > > > you ask for DNSSEC validation of the DNS records for
> >> www.example.com,
> >> > > your
> >> > > > coffee shop DNS recursive resolver can tell you "I checked, and
> >> > > example.com
> >> > > > does not support DNSSEC, here's the IP address for www.example.com
> >> > > though"
> >> > > > and you have to accept it.
> >> > >
> >> > > This is a completely false but somehow persistent myth about DNSSEC.
> >> > > You cannot lie that a zone does not support DNSSEC. The only way to
> >> > > claim a zone does not support DNSSEC is with a signature chain from
> >> > > the DNS root proving the nonexistence of the DS records for the
> >> > > delegation. Without that, the reply is BOGUS and will be ignored as if
> >> > > there was no reply at all.
> >> >
> >> > I was talking about the case where the recursive resolver does the
> >> > validation, which is what's deployed in practice today. What you wrote
> >> is
> >> > only true if the client does the DNSSEC validation itself. Most clients
> >> > don't do that today, because too many domains are just misconfigured and
> >> > broken. Eric Rescorla (the editor of the TLS RFCs) wrote a great blog
> >> post
> >> > about this:
> >>
> >> The consensus of folks in the stub resolver space (at least glibc+musl
> >> and I would assume the BSDs as well) is that the way you do DNSSEC
> >> validation is by having a validating caching proxy or full recursive
> >> resolver on localhost. Doing validation in the stub resolver is not
> >> viable because it may be static-linked, where it would not be able to
> >> be updated with new algorithms, root-of-trust, etc.
> >
> >
> > No disagreement there. By "client" I meant the client device as a whole,
> > and by "recursive resolver" I meant "the DNS server you got from DHCP".
> > Running a DNSSEC-validating recursive resolver on the client device falls
> > into what I meant by "if the client does the DNSSEC validation itself".
> > Sorry for being unclear.
> >
> >
> >> This is one of the
> >> reasons our go-to response for new functionality wanted in the stub
> >> resolver is "do it in a nameserver on localhost" -- because you
> >> already need that to do DNSSEC.
> >>
> >
> > That makes sense. I wasn't working with the assumption that DNSSEC was a
> > requirement.
> >
> > It really did not sound like you were talking about trusting the
> >> recursive, though. You called it a "fundamental design flaw", which it
> >> is not, and said it requires you to "trust all resolvers on the path",
> >> which it does not. It only requires you to trust the immediate
> >> resolver you are interacting with (and not even that if you put the
> >> validation in the stub resolver, but there are good reasons not to do
> >> that, as above). A pure-proxying server that relies on upstream
> >> recursives can do full DNSSEC validation. Dnsmasq is a canonical
> >> example. I believe systemd-resolvd also does it.
> >>
> >
> > That's fair, and I apologize for overstating my point. I absolutely agree
> > that if you run a validating recursive resolver locally, then the attack I
> > described isn't possible. When DNSSEC was designed, it was intended to be
> > deployed in the model I described, where the validating recursive resolver
> > is not on-device. And that's how it is still mostly deployed today because
> > almost all general-purpose client devices do not validate locally. My
> > mental model is very focused around consumer devices where folks buy them
> > and use them without ever changing default settings. That might be a
> > portion of musl users, but you clearly also have advanced users that do
> > things differently.
> >
> > > > > Regarding untrusted networks, one thing I hadn't considered yet is
> >> > > > > that a network configurator probably needs a way to setup
> >> resolv.conf
> >> > > > > such that .local queries temp-fail rather than perma-fail (as they
> >> > > > > would if you just sent the query to public dns) to use during
> >> certain
> >> > > > > race windows while switching networks. IOW "send .local queries to
> >> > > > > configured nameservers" and "treat .local specially but with an
> >> empty
> >> > > > > list of interfaces to send to" should be distinct configurations..
> >> > > >
> >> > > > Yeah, caching negative results in DNS has been a tricky thing from
> >> the
> >> > > > start. You probably could hack something by installing a fake SOA
> >> record
> >> > > > for .local. in your recursive resolver running on localhost. But the
> >> > > > RFC-compliant answer is for stub resolvers to treat it specially
> >> and know
> >> > > > that those often never get an answer (musl doesn't cache DNS
> >> results so
> >> > > in
> >> > > > a way we're avoiding this problem altogether at the stub resolver)..
> >> > >
> >> > > The problem here is not about caching, just about clients using a
> >> > > response. You want a task (like a browser with open tabs) trying to
> >> > > contact the site to get a tempfail rather than NxDomain which might
> >> > > make it stop trying. But you probably want NxDomain if mDNS has been
> >> > > disabled entirely, so that every .local lookup doesn't hang 5 seconds
> >> > > or whatever before saying "inconclusive".
> >> >
> >> > I'm assuming that by tempfail you mean EAI_AGAIN. The two browsers that
> >> > I've written code in don't use that (Chrome just treats it the same as a
> >> > resolution failure and will automatically refresh the tab on a network
> >> > change; Safari doesn't use getaddrinfo and instead relies on an
> >> > asynchronous DNS API that adds results as they come in - I wrote that
> >> > algorithm up in RFC 8305). All that said, synchronous blocking APIs like
> >> > getaddrinfo need to eventually return even if no one replies, so
> >> EAI_AGAIN
> >> > makes sense in that case - whereas if .local is blocked by policy then
> >> > immediately returning EAI_NONAME is best.
> >>
> >> Right. Even if applications don't currently distinguish them well,
> >> returning EAI_AGAIN vs EAI_NONAME is meaningful and enables them to do
> >> the right thing.
> >>
> >
> > Agreed.
> >
> > Thinking back to our discussion about whether to disable mDNS when the
> > resolver is on localhost. I still agree that from an ergonomics
> > perspective, using configs to mean multiple things isn't great. But
> > focusing just on the security properties for a second: if resolv.conf is
> > configured to an IP address that is routed over a given non-loopback
> > interface, the current status quo is to send the .local query unsecured
> > over that interface. So if we were to, in that specific scenario, instead
> > send the query over multicast, but only on that interface - then we
> > wouldn't measurably change the security properties of the system. In
> > practice there is a slight difference where now you can be attacked by any
> > device on the network as opposed to only by the router on that network, but
> > I'd argue that there's no meaningful threat model that distinguishes
> > between those two attacks. So that would be a safe default option. But
> > again, your points about least surprise are still valid, so if you object
> > to that on those grounds I can't disagree.
> >
> > David
> >

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-21 12:07                                   ` Rich Felker
@ 2024-03-21 13:50                                     ` David Schinazi
  2024-03-21 17:45                                       ` Luca Barbato
  2024-03-21 19:35                                       ` Rich Felker
  0 siblings, 2 replies; 32+ messages in thread
From: David Schinazi @ 2024-03-21 13:50 UTC (permalink / raw)
  To: Rich Felker; +Cc: musl

[-- Attachment #1: Type: text/plain, Size: 23219 bytes --]

My apologies, it wasn't clear to me that these options had been formally
rejected, I'm not familiar with the musl process. Unfortunately, the choice
of off-by-default doesn't follow the relevant standards and, more
importantly for me, doesn't solve the use case that got me interested in
working on this. Your choice is reasonable, and I respect it, but given
that it no longer solves an issue for me, I won't be able to spend time
writing code for this. If you do end up moving forward with mDNS, I'm happy
to help answer any questions about the mDNS specifications if you find that
helpful.

Best of luck, and thank you for all the work you do.
David

On Thu, Mar 21, 2024 at 10:07 PM Rich Felker <dalias@libc.org> wrote:

> On Thu, Mar 21, 2024 at 07:21:05PM +1000, David Schinazi wrote:
> > Hi,
> >
> > Earlier today at IETF, I discussed this topic with Stuart Cheshire, the
> > creator of mDNS. From his perspective, implementing a simpler option in
> > musl makes a lot of sense. Even though querying mDNS on a single
> interface
> > is not comprehensive, it'll work for the majority of uses while
> minimizing
> > implementation complexity. Using the UDP connect() trick to find the
> > interface corresponding to the configured resolver and then sending
> > multicast only on that interface will work and provide reasonable
> security
> > properties. He recommends using the IP_MULTICAST_IF / IPV6_MULTICAST_IF
> > socket options to select an interface, as that's what mDNSResponder does
> on
> > Linux. Additionally, he feels strongly that this should be enabled by
> > default, since the whole point of zero-configuration networking was for
> > things to work without requiring user configuration.
>
> Again, most of these choices are *not workable*. They have already
> been rejected.
>
> If you want this to happen, let's please work on something that has
> not been rejected.
>
> 1. Why on-by-default was rejected:
>
> musl is not only or even mostly used in a desktop user configuration
> where mDNS makes sense. It's used in lots of places where silently
> starting (after upgrade) to query other devices on a network and
> accepting answers from them is unexpected and hostile behavior. Yes,
> "on by default" makes sense on an end-user desktop system connected to
> a *private* network. This would be a default of the particular OS
> using musl and its network configurator, not of musl itself. (And
> AFAIK mDNS is not even "on my default" on Windows unless the connected
> network is marked as private.)
>
> 2. Why deciding what network to query based on the interface of the
> configured resolver is rejected:
>
> In a proper DNSSEC-validating setup, the configured resolver is
> 127.0.0.1 or ::1. This would disable mDNS entirely, forcing you to
> essentially *switch DNSSEC off if you want mDNS*. It was already
> explained why this is very bad.
>
> Single-interface query has not been rejected, but I don't see any
> reason to limit mDNS to a single interface. That doesn't make it
> particularly simpler or anything. If you're able to select the
> interface, it's just as easy to allow selecting a reasonable number of
> interfaces.
>
> The particular implementation mechanisms we've discussed, including
> possibly identifying the interface(s) to send to via where a
> particular address would be routed, seem overall good.
>
>
> > On Sat, Mar 9, 2024 at 9:44 AM David Schinazi <dschinazi.ietf@gmail.
> .com>
> > wrote:
> >
> > >
> > >
> > > On Fri, Mar 8, 2024 at 2:54 PM Rich Felker <dalias@libc.org> wrote:
> > >
> > >> On Fri, Mar 08, 2024 at 01:55:18PM -0800, David Schinazi wrote:
> > >> > On Fri, Mar 8, 2024 at 12:31 PM Rich Felker <dalias@libc.org>
> wrote:
> > >> >
> > >> > > On Fri, Mar 08, 2024 at 11:15:52AM -0800, David Schinazi wrote:
> > >> > > > On Fri, Mar 8, 2024 at 5:30 AM Rich Felker <dalias@libc.org>
> wrote:
> > >> > > >
> > >> > > > > On Thu, Mar 07, 2024 at 08:47:20PM -0800, David Schinazi
> wrote:
> > >> > > > > > Thanks. How would you feel about the following potential
> > >> > > configuration
> > >> > > > > > design?
> > >> > > > > > * Add a new configuration option "send_mdns_unicast"
> > >> > > > > > * When true, use the current behavior
> > >> > > > > > * When false, send the query on all non-loopback non-p2p
> > >> interfaces
> > >> > > > > > * Have send_mdns_unicast default to false
> > >> > > > > >
> > >> > > > > > I was thinking through how to pick interfaces, looked up
> what
> > >> other
> > >> > > mDNS
> > >> > > > > > libraries do, and pretty much all of them don't allow
> > >> configuring
> > >> > > > > > interfaces, whereas Avahi exposes allow-interfaces and
> > >> > > deny-interfaces.
> > >> > > > > I'm
> > >> > > > > > leaning towards not making this configurable to reduce
> > >> complexity. I
> > >> > > > > think
> > >> > > > > > that anyone interested in that level of config is probably
> using
> > >> > > Avahi
> > >> > > > > > anyway.
> > >> > > > > >
> > >> > > > > > Additionally this design has two nice properties: the
> default
> > >> > > behavior is
> > >> > > > > > RFC-compliant, and it means that for my use-case I don't
> need to
> > >> > > change
> > >> > > > > the
> > >> > > > > > config file, which was a big part of my motivation for doing
> > >> this
> > >> > > inside
> > >> > > > > of
> > >> > > > > > musl in the first place :-)
> > >> > > > >
> > >> > > > > As discussed in this thread, I don't think so. The biggest
> > >> problems I
> > >> > > > > initially brought up were increased information leakage in the
> > >> default
> > >> > > > > configuration and inability to control where the traffic goes
> > >> when you
> > >> > > > > do want it on. The above proposal just reverts to the initial,
> > >> except
> > >> > > > > for providing a way to opt-out.
> > >> > > > >
> > >> > > > > For the most part, mDNS is very much a "home user, personal
> > >> device on
> > >> > > > > trusted network" thing. Not only do you not want it to
> default on
> > >> > > > > because a lot of systems will be network servers on networks
> where
> > >> > > > > it's not meaningful (and can be a weakness that aids
> attackers in
> > >> > > > > lateral movement), but you also don't want it on when
> connected to
> > >> > > > > public wifi. For example if you have an open browser tab to
> > >> > > > > http://mything.local, and migrate to an untrusted network
> (with
> > >> your
> > >> > > > > laptop, tablet, phone, whatever), now your browser will be
> leaking
> > >> > > > > private data (likely at least session auth tokens, maybe
> more) to
> > >> > > > > whoever answers the mDNS query for mything.local.
> > >> > > >
> > >> > > > That's not quite right. The security properties of mDNS and DNS
> are
> > >> the
> > >> > > > same. DNS is inherently insecure, regardless of unicast vs
> > >> multicast. If
> > >> > > > I'm on a coffee shop Wi-Fi, all my DNS queries are sent in the
> > >> clear to
> > >> > > > whatever IP address the DHCP server gave me.
> > >> > >
> > >> > > That's not the case. Connections to non-mDNS hosts are
> authenticated
> > >> > > by TLS with certificates issued on the basis of ownership of the
> > >> > > domain name. That's not possible with mDNS hostnames, so they'll
> > >> > > either be no-TLS or self-signed certs. That's why the above
> attack is
> > >> > > possible. It was also possible with normal DNS in the bad old
> days of
> > >> > > http://, but that time is long gone.
> > >> >
> > >> > Apologies for being pedantic, but that's not true. The ability to
> get
> > >> TLS
> > >> > certificates for a domain name that you own is a property of the
> WebPKI,
> > >> > not a property of TLS. What you wrote is true, but only in the
> context
> > >> of a
> > >> > Web browser with an unmodified root certificate store. The features
> I
> > >> > mentioned above don't use the WebPKI, they have a separate root of
> > >> trust.
> > >> > For example, some of those Apple features exchange TLS certificates
> via
> > >> an
> > >> > out-of-band mechanism such as Apple trusted servers. Another
> example is
> > >> the
> > >> > Apple Watch: when you first pair a new Apple Watch with an iPhone,
> they
> > >> > exchange ed25519 public keys. Then any time the watch wants to
> transfer
> > >> a
> > >> > large file to/from the phone, it'll connect to Wi-Fi, use mDNS to
> find
> > >> the
> > >> > phone, and set up an IKEv2/IPsec tunnel that then protects the
> exchange.
> > >> > It's resilient to any attacks at the mDNS level.
> > >> >
> > >> > You're absolutely right that the security of Web requests using
> local
> > >> > connectivity is completely broken by the lack of WebPKI
> certificates for
> > >> > those. But sending the DNS query over multicast as opposed to
> > >> unencrypted
> > >> > unicast to an untrusted DNS server doesn't change the security
> > >> properties.
> > >> > In your example above, the open tab to http://mything.local will
> send
> > >> that
> > >> > query to the recursive resolver - and if that's the one received by
> DHCP
> > >> > then that server can reply with its own address and receive your
> auth
> > >> > tokens. One potential fix here is to configure your resolv.conf to
> > >> > localhost and then apply policy in that local resolver. But in
> practice,
> > >> > application developers don't rely on security at that layer, they
> assume
> > >> > that DNS is unsafe and implement encryption in userspace with some
> out
> > >> of
> > >> > band trust mechanism.
> > >>
> > >> My specific example was http://mything.local in a web browser, which
> > >> is the way you access lots of mDNS-enabled things in the absence of a
> > >> specific software ecosystem like Apple's. Since we're talking about
> > >> musl which would be running on Linux or a Linux-syscall-compatible
> > >> environment, without Apple apps, I think that's the main way anyone
> > >> would be using hypothetical mDNS support. And indeed this is the way
> > >> you access many printers, 3D printers, IP cameras, etc.
> > >>
> > >
> > > I have multiple services at home that use HTTP and mDNS to communicate
> > > with. But they're built knowing that unencrypted HTTP is unsafe. For
> > > example, one of my servers doesn't have any authentication - my browser
> > > just uses unauthenticated GETs, POSTs and WebSockets. If I leave the
> tab
> > > open and go to a coffee shop, my browser might send that GET to a
> server I
> > > don't trust but that request won't carry any sensitive information.
> Another
> > > of my servers uses TLS with self-signed certs, so every time I want to
> > > communicate with it, I need to click through my browser's "this is
> unsafe"
> > > interstitial to get to the page. If I switch networks, the browser will
> > > send me the warning again and I'll know not to click through when I'm
> not
> > > at home. In both of those cases, the security is handled (or not
> handled at
> > > all) at the application layer.
> > >
> > > Maybe at some point we'll have a good framework for authenticating
> > >> this kind of usage with certificates (probably certificate pinning on
> > >> first use, with good UX, is the only easy solution),
> > >
> > >
> > > Trust on first use works, or even better there are emerging solutions
> that
> > > leverage codes printed on devices and PAKEs so that a device on the
> > > untrusted network can't even hijack the first connection without having
> > > access to that code. The leading one for home automation is Matter [1].
> > > Coincidentally, it also leverages mDNS for discovery, and doesn't rely
> on
> > > security at the DNS level.
> > >
> > > [1] https://csa-iot.org/all-solutions/matter/
> > >
> > > but at present,
> > >> mDNS devices on the .local zone get accessed with plain http:// all
> > >> the time, and this means it's unsafe to do mDNS on
> > >> public/untrusted/hostile networks.
> > >>
> > >
> > > The notion of something being "unsafe" (and security in general) is
> > > predicated on the existence of a threat model. It's unsafe to use
> > > unencrypted HTTP to your bank when your threat model includes someone
> on
> > > the coffee shop Wi-Fi trying to steal your bank credentials.
> Conversely,
> > > it's safe for me to print to this coffee shop printer if my threat
> model
> > > assumes that I'm ok with the owner of the coffee shop seeing my
> document.
> > > Another example is Chromecast which also uses mDNS: from Chrome on a
> Linux
> > > laptop, I can cast YouTube videos to the TV in this coffee shop. That's
> > > safe because I trust the network with the YouTube link I'm telling the
> TV
> > > to play. mDNS is not in and of itself safe or unsafe. It converts
> > > names into addresses, and what you do with those addresses can
> potentially
> > > be unsafe.
> > >
> > > That doesn't mean that every single use of mDNS on untrusted networks
> is
> > > safe. If someone builds a web page that sends valuable secrets over
> > > unencrypted HTTP to a .local name, then you have a security problem.
> But my
> > > point is that this security problem needs to be solved at the
> application
> > > layer and not at the DNS layer. That said, I agree that having a way to
> > > disable mDNS on a machine is a good idea, because there probably are
> users
> > > out there that are stuck with applications that for some reason
> decided to
> > > rely on DNS being secure.
> > >
> > > In terms of the tradeoff between usability and security, the default
> to me
> > > lies with default-enabling mDNS on all interfaces as Apple and Avahi
> do.
> > > But this tradeoff is between two metrics that can't be quantified one
> > > against the other for all possible uses, so I totally understand if
> your
> > > opinion for musl is that the tradeoff there is different than in other
> > > situations. You know your users better than I do.
> > >
> > > > > So the stack has to deal with
> > >> > > > the fact that any DNS response can be spoofed.
> > >> > >
> > >> > > That's also not possible with DNSSEC, but only helps if you're
> > >> > > validating it.
> > >> > >
> > >> > > > The most widely used
> > >> > > > solution is TLS: a successful DNS hijack can prevent you from
> > >> accessing a
> > >> > > > TLS service, but can't impersonate it. That's true of both mDNS
> and
> > >> > > regular
> > >> > > > unicast DNS. As an example, all Apple devices have mDNS enabled
> on
> > >> all
> > >> > > > interfaces, with no security impact - the features that rely on
> it
> > >> > > > (AirDrop, AirPlay, contact sharing, etc) all use mTLS to ensure
> > >> they're
> > >> > > > talking to the right device regardless of the correctness of
> DNS.
> > >> > > (Printing
> > >> > > > remains completely insecure, but that's also independent of DNS
> -
> > >> your
> > >> > > > coffee shop Wi-Fi access point can attack you at the IP layer
> too)..
> > >> One
> > >> > > > might think that DNSSEC could save us here, but it doesn't.
> DNSSEC
> > >> was
> > >> > > > unfortunately built with a fundamental design flaw: it requires
> you
> > >> to
> > >> > > > trust all resolvers on the path, including recursive resolvers.
> So
> > >> even
> > >> > > if
> > >> > > > you ask for DNSSEC validation of the DNS records for
> > >> www.example.com,
> > >> > > your
> > >> > > > coffee shop DNS recursive resolver can tell you "I checked, and
> > >> > > example.com
> > >> > > > does not support DNSSEC, here's the IP address for
> www.example.com
> > >> > > though"
> > >> > > > and you have to accept it.
> > >> > >
> > >> > > This is a completely false but somehow persistent myth about
> DNSSEC.
> > >> > > You cannot lie that a zone does not support DNSSEC. The only way
> to
> > >> > > claim a zone does not support DNSSEC is with a signature chain
> from
> > >> > > the DNS root proving the nonexistence of the DS records for the
> > >> > > delegation. Without that, the reply is BOGUS and will be ignored
> as if
> > >> > > there was no reply at all.
> > >> >
> > >> > I was talking about the case where the recursive resolver does the
> > >> > validation, which is what's deployed in practice today. What you
> wrote
> > >> is
> > >> > only true if the client does the DNSSEC validation itself. Most
> clients
> > >> > don't do that today, because too many domains are just
> misconfigured and
> > >> > broken. Eric Rescorla (the editor of the TLS RFCs) wrote a great
> blog
> > >> post
> > >> > about this:
> > >>
> > >> The consensus of folks in the stub resolver space (at least glibc+musl
> > >> and I would assume the BSDs as well) is that the way you do DNSSEC
> > >> validation is by having a validating caching proxy or full recursive
> > >> resolver on localhost. Doing validation in the stub resolver is not
> > >> viable because it may be static-linked, where it would not be able to
> > >> be updated with new algorithms, root-of-trust, etc.
> > >
> > >
> > > No disagreement there. By "client" I meant the client device as a
> whole,
> > > and by "recursive resolver" I meant "the DNS server you got from DHCP".
> > > Running a DNSSEC-validating recursive resolver on the client device
> falls
> > > into what I meant by "if the client does the DNSSEC validation itself".
> > > Sorry for being unclear.
> > >
> > >
> > >> This is one of the
> > >> reasons our go-to response for new functionality wanted in the stub
> > >> resolver is "do it in a nameserver on localhost" -- because you
> > >> already need that to do DNSSEC.
> > >>
> > >
> > > That makes sense. I wasn't working with the assumption that DNSSEC was
> a
> > > requirement.
> > >
> > > It really did not sound like you were talking about trusting the
> > >> recursive, though. You called it a "fundamental design flaw", which it
> > >> is not, and said it requires you to "trust all resolvers on the path",
> > >> which it does not. It only requires you to trust the immediate
> > >> resolver you are interacting with (and not even that if you put the
> > >> validation in the stub resolver, but there are good reasons not to do
> > >> that, as above). A pure-proxying server that relies on upstream
> > >> recursives can do full DNSSEC validation. Dnsmasq is a canonical
> > >> example. I believe systemd-resolvd also does it.
> > >>
> > >
> > > That's fair, and I apologize for overstating my point. I absolutely
> agree
> > > that if you run a validating recursive resolver locally, then the
> attack I
> > > described isn't possible. When DNSSEC was designed, it was intended to
> be
> > > deployed in the model I described, where the validating recursive
> resolver
> > > is not on-device. And that's how it is still mostly deployed today
> because
> > > almost all general-purpose client devices do not validate locally. My
> > > mental model is very focused around consumer devices where folks buy
> them
> > > and use them without ever changing default settings. That might be a
> > > portion of musl users, but you clearly also have advanced users that do
> > > things differently.
> > >
> > > > > > Regarding untrusted networks, one thing I hadn't considered yet
> is
> > >> > > > > that a network configurator probably needs a way to setup
> > >> resolv.conf
> > >> > > > > such that .local queries temp-fail rather than perma-fail (as
> they
> > >> > > > > would if you just sent the query to public dns) to use during
> > >> certain
> > >> > > > > race windows while switching networks. IOW "send .local
> queries to
> > >> > > > > configured nameservers" and "treat .local specially but with
> an
> > >> empty
> > >> > > > > list of interfaces to send to" should be distinct
> configurations..
> > >> > > >
> > >> > > > Yeah, caching negative results in DNS has been a tricky thing
> from
> > >> the
> > >> > > > start. You probably could hack something by installing a fake
> SOA
> > >> record
> > >> > > > for .local. in your recursive resolver running on localhost.
> But the
> > >> > > > RFC-compliant answer is for stub resolvers to treat it specially
> > >> and know
> > >> > > > that those often never get an answer (musl doesn't cache DNS
> > >> results so
> > >> > > in
> > >> > > > a way we're avoiding this problem altogether at the stub
> resolver)..
> > >> > >
> > >> > > The problem here is not about caching, just about clients using a
> > >> > > response. You want a task (like a browser with open tabs) trying
> to
> > >> > > contact the site to get a tempfail rather than NxDomain which
> might
> > >> > > make it stop trying. But you probably want NxDomain if mDNS has
> been
> > >> > > disabled entirely, so that every .local lookup doesn't hang 5
> seconds
> > >> > > or whatever before saying "inconclusive".
> > >> >
> > >> > I'm assuming that by tempfail you mean EAI_AGAIN. The two browsers
> that
> > >> > I've written code in don't use that (Chrome just treats it the same
> as a
> > >> > resolution failure and will automatically refresh the tab on a
> network
> > >> > change; Safari doesn't use getaddrinfo and instead relies on an
> > >> > asynchronous DNS API that adds results as they come in - I wrote
> that
> > >> > algorithm up in RFC 8305). All that said, synchronous blocking APIs
> like
> > >> > getaddrinfo need to eventually return even if no one replies, so
> > >> EAI_AGAIN
> > >> > makes sense in that case - whereas if .local is blocked by policy
> then
> > >> > immediately returning EAI_NONAME is best.
> > >>
> > >> Right. Even if applications don't currently distinguish them well,
> > >> returning EAI_AGAIN vs EAI_NONAME is meaningful and enables them to do
> > >> the right thing.
> > >>
> > >
> > > Agreed.
> > >
> > > Thinking back to our discussion about whether to disable mDNS when the
> > > resolver is on localhost. I still agree that from an ergonomics
> > > perspective, using configs to mean multiple things isn't great. But
> > > focusing just on the security properties for a second: if resolv.conf
> is
> > > configured to an IP address that is routed over a given non-loopback
> > > interface, the current status quo is to send the .local query unsecured
> > > over that interface. So if we were to, in that specific scenario,
> instead
> > > send the query over multicast, but only on that interface - then we
> > > wouldn't measurably change the security properties of the system. In
> > > practice there is a slight difference where now you can be attacked by
> any
> > > device on the network as opposed to only by the router on that
> network, but
> > > I'd argue that there's no meaningful threat model that distinguishes
> > > between those two attacks. So that would be a safe default option. But
> > > again, your points about least surprise are still valid, so if you
> object
> > > to that on those grounds I can't disagree.
> > >
> > > David
> > >
>

[-- Attachment #2: Type: text/html, Size: 29411 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-21 13:50                                     ` David Schinazi
@ 2024-03-21 17:45                                       ` Luca Barbato
  2024-03-21 19:35                                       ` Rich Felker
  1 sibling, 0 replies; 32+ messages in thread
From: Luca Barbato @ 2024-03-21 17:45 UTC (permalink / raw)
  To: musl

On 21/03/24 14:50, David Schinazi wrote:
> My apologies, it wasn't clear to me that these options had been formally 
> rejected, I'm not familiar with the musl process. Unfortunately, the 
> choice of off-by-default doesn't follow the relevant standards and, more 
> importantly for me, doesn't solve the use case that got me interested in 
> working on this.

Keep in mind that distributions do and will change the default behavior 
of software components as they see fit anyway so if your use-case is 
having a desktop oriented distribution using musl support mDNS out of 
box, having the feature default off in musl would not make impossible 
having the distro default having it on.

lu

PS: which are the stakeholders contacted while the relevant standards 
brought in such hazardous default?


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-21 13:50                                     ` David Schinazi
  2024-03-21 17:45                                       ` Luca Barbato
@ 2024-03-21 19:35                                       ` Rich Felker
  2024-03-22  0:10                                         ` David Schinazi
  1 sibling, 1 reply; 32+ messages in thread
From: Rich Felker @ 2024-03-21 19:35 UTC (permalink / raw)
  To: David Schinazi; +Cc: musl

On Thu, Mar 21, 2024 at 11:50:21PM +1000, David Schinazi wrote:
> My apologies, it wasn't clear to me that these options had been formally
> rejected,

I don't like to use harsh words like "rejected", but from the
beginning my part in this conversation has been about what properties
an mDNS implementation for musl's stub resolver would need to have as
preconditions to make it acceptable for inclusion. My hope was that,
out of bringing the topic to the IETF meeting, we'd have some ideas
for recommended forms for the necessary configuration controls that
might be suitable for multiple implementations to adopt and aid in
interoperability, not for you to come back using it as an
appeal-to-authority to disregard the issues already raised.

> I'm not familiar with the musl process. Unfortunately, the choice
> of off-by-default doesn't follow the relevant standards and, more
> importantly for me, doesn't solve the use case that got me interested in

Along with what Luca noted, the relevant standards are about how a
system behaves, not about the mechanisms of a particular part of that
system.

> working on this. Your choice is reasonable, and I respect it, but given
> that it no longer solves an issue for me, I won't be able to spend time
> writing code for this. If you do end up moving forward with mDNS, I'm happy
> to help answer any questions about the mDNS specifications if you find that
> helpful.

That's fine. I'm not in any hurry to make decisions or write code
here, but I'd still be happy to hear from others who want this to
happen for fleshing out whether it makes sense and if so, how the
configuration should work.



> Best of luck, and thank you for all the work you do.
> David
> 
> On Thu, Mar 21, 2024 at 10:07 PM Rich Felker <dalias@libc.org> wrote:
> 
> > On Thu, Mar 21, 2024 at 07:21:05PM +1000, David Schinazi wrote:
> > > Hi,
> > >
> > > Earlier today at IETF, I discussed this topic with Stuart Cheshire, the
> > > creator of mDNS. From his perspective, implementing a simpler option in
> > > musl makes a lot of sense. Even though querying mDNS on a single
> > interface
> > > is not comprehensive, it'll work for the majority of uses while
> > minimizing
> > > implementation complexity. Using the UDP connect() trick to find the
> > > interface corresponding to the configured resolver and then sending
> > > multicast only on that interface will work and provide reasonable
> > security
> > > properties. He recommends using the IP_MULTICAST_IF / IPV6_MULTICAST_IF
> > > socket options to select an interface, as that's what mDNSResponder does
> > on
> > > Linux. Additionally, he feels strongly that this should be enabled by
> > > default, since the whole point of zero-configuration networking was for
> > > things to work without requiring user configuration.
> >
> > Again, most of these choices are *not workable*. They have already
> > been rejected.
> >
> > If you want this to happen, let's please work on something that has
> > not been rejected.
> >
> > 1. Why on-by-default was rejected:
> >
> > musl is not only or even mostly used in a desktop user configuration
> > where mDNS makes sense. It's used in lots of places where silently
> > starting (after upgrade) to query other devices on a network and
> > accepting answers from them is unexpected and hostile behavior. Yes,
> > "on by default" makes sense on an end-user desktop system connected to
> > a *private* network. This would be a default of the particular OS
> > using musl and its network configurator, not of musl itself. (And
> > AFAIK mDNS is not even "on my default" on Windows unless the connected
> > network is marked as private.)
> >
> > 2. Why deciding what network to query based on the interface of the
> > configured resolver is rejected:
> >
> > In a proper DNSSEC-validating setup, the configured resolver is
> > 127.0.0.1 or ::1. This would disable mDNS entirely, forcing you to
> > essentially *switch DNSSEC off if you want mDNS*. It was already
> > explained why this is very bad.
> >
> > Single-interface query has not been rejected, but I don't see any
> > reason to limit mDNS to a single interface. That doesn't make it
> > particularly simpler or anything. If you're able to select the
> > interface, it's just as easy to allow selecting a reasonable number of
> > interfaces.
> >
> > The particular implementation mechanisms we've discussed, including
> > possibly identifying the interface(s) to send to via where a
> > particular address would be routed, seem overall good.
> >
> >
> > > On Sat, Mar 9, 2024 at 9:44 AM David Schinazi <dschinazi.ietf@gmail.
> > .com>
> > > wrote:
> > >
> > > >
> > > >
> > > > On Fri, Mar 8, 2024 at 2:54 PM Rich Felker <dalias@libc.org> wrote:
> > > >
> > > >> On Fri, Mar 08, 2024 at 01:55:18PM -0800, David Schinazi wrote:
> > > >> > On Fri, Mar 8, 2024 at 12:31 PM Rich Felker <dalias@libc.org>
> > wrote:
> > > >> >
> > > >> > > On Fri, Mar 08, 2024 at 11:15:52AM -0800, David Schinazi wrote:
> > > >> > > > On Fri, Mar 8, 2024 at 5:30 AM Rich Felker <dalias@libc.org>
> > wrote:
> > > >> > > >
> > > >> > > > > On Thu, Mar 07, 2024 at 08:47:20PM -0800, David Schinazi
> > wrote:
> > > >> > > > > > Thanks. How would you feel about the following potential
> > > >> > > configuration
> > > >> > > > > > design?
> > > >> > > > > > * Add a new configuration option "send_mdns_unicast"
> > > >> > > > > > * When true, use the current behavior
> > > >> > > > > > * When false, send the query on all non-loopback non-p2p
> > > >> interfaces
> > > >> > > > > > * Have send_mdns_unicast default to false
> > > >> > > > > >
> > > >> > > > > > I was thinking through how to pick interfaces, looked up
> > what
> > > >> other
> > > >> > > mDNS
> > > >> > > > > > libraries do, and pretty much all of them don't allow
> > > >> configuring
> > > >> > > > > > interfaces, whereas Avahi exposes allow-interfaces and
> > > >> > > deny-interfaces.
> > > >> > > > > I'm
> > > >> > > > > > leaning towards not making this configurable to reduce
> > > >> complexity. I
> > > >> > > > > think
> > > >> > > > > > that anyone interested in that level of config is probably
> > using
> > > >> > > Avahi
> > > >> > > > > > anyway.
> > > >> > > > > >
> > > >> > > > > > Additionally this design has two nice properties: the
> > default
> > > >> > > behavior is
> > > >> > > > > > RFC-compliant, and it means that for my use-case I don't
> > need to
> > > >> > > change
> > > >> > > > > the
> > > >> > > > > > config file, which was a big part of my motivation for doing
> > > >> this
> > > >> > > inside
> > > >> > > > > of
> > > >> > > > > > musl in the first place :-)
> > > >> > > > >
> > > >> > > > > As discussed in this thread, I don't think so. The biggest
> > > >> problems I
> > > >> > > > > initially brought up were increased information leakage in the
> > > >> default
> > > >> > > > > configuration and inability to control where the traffic goes
> > > >> when you
> > > >> > > > > do want it on. The above proposal just reverts to the initial,
> > > >> except
> > > >> > > > > for providing a way to opt-out.
> > > >> > > > >
> > > >> > > > > For the most part, mDNS is very much a "home user, personal
> > > >> device on
> > > >> > > > > trusted network" thing. Not only do you not want it to
> > default on
> > > >> > > > > because a lot of systems will be network servers on networks
> > where
> > > >> > > > > it's not meaningful (and can be a weakness that aids
> > attackers in
> > > >> > > > > lateral movement), but you also don't want it on when
> > connected to
> > > >> > > > > public wifi. For example if you have an open browser tab to
> > > >> > > > > http://mything.local, and migrate to an untrusted network
> > (with
> > > >> your
> > > >> > > > > laptop, tablet, phone, whatever), now your browser will be
> > leaking
> > > >> > > > > private data (likely at least session auth tokens, maybe
> > more) to
> > > >> > > > > whoever answers the mDNS query for mything.local.
> > > >> > > >
> > > >> > > > That's not quite right. The security properties of mDNS and DNS
> > are
> > > >> the
> > > >> > > > same. DNS is inherently insecure, regardless of unicast vs
> > > >> multicast. If
> > > >> > > > I'm on a coffee shop Wi-Fi, all my DNS queries are sent in the
> > > >> clear to
> > > >> > > > whatever IP address the DHCP server gave me.
> > > >> > >
> > > >> > > That's not the case. Connections to non-mDNS hosts are
> > authenticated
> > > >> > > by TLS with certificates issued on the basis of ownership of the
> > > >> > > domain name. That's not possible with mDNS hostnames, so they'll
> > > >> > > either be no-TLS or self-signed certs. That's why the above
> > attack is
> > > >> > > possible. It was also possible with normal DNS in the bad old
> > days of
> > > >> > > http://, but that time is long gone.
> > > >> >
> > > >> > Apologies for being pedantic, but that's not true. The ability to
> > get
> > > >> TLS
> > > >> > certificates for a domain name that you own is a property of the
> > WebPKI,
> > > >> > not a property of TLS. What you wrote is true, but only in the
> > context
> > > >> of a
> > > >> > Web browser with an unmodified root certificate store. The features
> > I
> > > >> > mentioned above don't use the WebPKI, they have a separate root of
> > > >> trust.
> > > >> > For example, some of those Apple features exchange TLS certificates
> > via
> > > >> an
> > > >> > out-of-band mechanism such as Apple trusted servers. Another
> > example is
> > > >> the
> > > >> > Apple Watch: when you first pair a new Apple Watch with an iPhone,
> > they
> > > >> > exchange ed25519 public keys. Then any time the watch wants to
> > transfer
> > > >> a
> > > >> > large file to/from the phone, it'll connect to Wi-Fi, use mDNS to
> > find
> > > >> the
> > > >> > phone, and set up an IKEv2/IPsec tunnel that then protects the
> > exchange.
> > > >> > It's resilient to any attacks at the mDNS level.
> > > >> >
> > > >> > You're absolutely right that the security of Web requests using
> > local
> > > >> > connectivity is completely broken by the lack of WebPKI
> > certificates for
> > > >> > those. But sending the DNS query over multicast as opposed to
> > > >> unencrypted
> > > >> > unicast to an untrusted DNS server doesn't change the security
> > > >> properties.
> > > >> > In your example above, the open tab to http://mything.local will
> > send
> > > >> that
> > > >> > query to the recursive resolver - and if that's the one received by
> > DHCP
> > > >> > then that server can reply with its own address and receive your
> > auth
> > > >> > tokens. One potential fix here is to configure your resolv.conf to
> > > >> > localhost and then apply policy in that local resolver. But in
> > practice,
> > > >> > application developers don't rely on security at that layer, they
> > assume
> > > >> > that DNS is unsafe and implement encryption in userspace with some
> > out
> > > >> of
> > > >> > band trust mechanism.
> > > >>
> > > >> My specific example was http://mything.local in a web browser, which
> > > >> is the way you access lots of mDNS-enabled things in the absence of a
> > > >> specific software ecosystem like Apple's. Since we're talking about
> > > >> musl which would be running on Linux or a Linux-syscall-compatible
> > > >> environment, without Apple apps, I think that's the main way anyone
> > > >> would be using hypothetical mDNS support. And indeed this is the way
> > > >> you access many printers, 3D printers, IP cameras, etc.
> > > >>
> > > >
> > > > I have multiple services at home that use HTTP and mDNS to communicate
> > > > with. But they're built knowing that unencrypted HTTP is unsafe. For
> > > > example, one of my servers doesn't have any authentication - my browser
> > > > just uses unauthenticated GETs, POSTs and WebSockets. If I leave the
> > tab
> > > > open and go to a coffee shop, my browser might send that GET to a
> > server I
> > > > don't trust but that request won't carry any sensitive information.
> > Another
> > > > of my servers uses TLS with self-signed certs, so every time I want to
> > > > communicate with it, I need to click through my browser's "this is
> > unsafe"
> > > > interstitial to get to the page. If I switch networks, the browser will
> > > > send me the warning again and I'll know not to click through when I'm
> > not
> > > > at home. In both of those cases, the security is handled (or not
> > handled at
> > > > all) at the application layer.
> > > >
> > > > Maybe at some point we'll have a good framework for authenticating
> > > >> this kind of usage with certificates (probably certificate pinning on
> > > >> first use, with good UX, is the only easy solution),
> > > >
> > > >
> > > > Trust on first use works, or even better there are emerging solutions
> > that
> > > > leverage codes printed on devices and PAKEs so that a device on the
> > > > untrusted network can't even hijack the first connection without having
> > > > access to that code. The leading one for home automation is Matter [1].
> > > > Coincidentally, it also leverages mDNS for discovery, and doesn't rely
> > on
> > > > security at the DNS level.
> > > >
> > > > [1] https://csa-iot.org/all-solutions/matter/
> > > >
> > > > but at present,
> > > >> mDNS devices on the .local zone get accessed with plain http:// all
> > > >> the time, and this means it's unsafe to do mDNS on
> > > >> public/untrusted/hostile networks.
> > > >>
> > > >
> > > > The notion of something being "unsafe" (and security in general) is
> > > > predicated on the existence of a threat model. It's unsafe to use
> > > > unencrypted HTTP to your bank when your threat model includes someone
> > on
> > > > the coffee shop Wi-Fi trying to steal your bank credentials.
> > Conversely,
> > > > it's safe for me to print to this coffee shop printer if my threat
> > model
> > > > assumes that I'm ok with the owner of the coffee shop seeing my
> > document.
> > > > Another example is Chromecast which also uses mDNS: from Chrome on a
> > Linux
> > > > laptop, I can cast YouTube videos to the TV in this coffee shop. That's
> > > > safe because I trust the network with the YouTube link I'm telling the
> > TV
> > > > to play. mDNS is not in and of itself safe or unsafe. It converts
> > > > names into addresses, and what you do with those addresses can
> > potentially
> > > > be unsafe.
> > > >
> > > > That doesn't mean that every single use of mDNS on untrusted networks
> > is
> > > > safe. If someone builds a web page that sends valuable secrets over
> > > > unencrypted HTTP to a .local name, then you have a security problem.
> > But my
> > > > point is that this security problem needs to be solved at the
> > application
> > > > layer and not at the DNS layer. That said, I agree that having a way to
> > > > disable mDNS on a machine is a good idea, because there probably are
> > users
> > > > out there that are stuck with applications that for some reason
> > decided to
> > > > rely on DNS being secure.
> > > >
> > > > In terms of the tradeoff between usability and security, the default
> > to me
> > > > lies with default-enabling mDNS on all interfaces as Apple and Avahi
> > do.
> > > > But this tradeoff is between two metrics that can't be quantified one
> > > > against the other for all possible uses, so I totally understand if
> > your
> > > > opinion for musl is that the tradeoff there is different than in other
> > > > situations. You know your users better than I do.
> > > >
> > > > > > So the stack has to deal with
> > > >> > > > the fact that any DNS response can be spoofed.
> > > >> > >
> > > >> > > That's also not possible with DNSSEC, but only helps if you're
> > > >> > > validating it.
> > > >> > >
> > > >> > > > The most widely used
> > > >> > > > solution is TLS: a successful DNS hijack can prevent you from
> > > >> accessing a
> > > >> > > > TLS service, but can't impersonate it. That's true of both mDNS
> > and
> > > >> > > regular
> > > >> > > > unicast DNS. As an example, all Apple devices have mDNS enabled
> > on
> > > >> all
> > > >> > > > interfaces, with no security impact - the features that rely on
> > it
> > > >> > > > (AirDrop, AirPlay, contact sharing, etc) all use mTLS to ensure
> > > >> they're
> > > >> > > > talking to the right device regardless of the correctness of
> > DNS.
> > > >> > > (Printing
> > > >> > > > remains completely insecure, but that's also independent of DNS
> > -
> > > >> your
> > > >> > > > coffee shop Wi-Fi access point can attack you at the IP layer
> > too)..
> > > >> One
> > > >> > > > might think that DNSSEC could save us here, but it doesn't.
> > DNSSEC
> > > >> was
> > > >> > > > unfortunately built with a fundamental design flaw: it requires
> > you
> > > >> to
> > > >> > > > trust all resolvers on the path, including recursive resolvers..
> > So
> > > >> even
> > > >> > > if
> > > >> > > > you ask for DNSSEC validation of the DNS records for
> > > >> www.example.com,
> > > >> > > your
> > > >> > > > coffee shop DNS recursive resolver can tell you "I checked, and
> > > >> > > example.com
> > > >> > > > does not support DNSSEC, here's the IP address for
> > www.example.com
> > > >> > > though"
> > > >> > > > and you have to accept it.
> > > >> > >
> > > >> > > This is a completely false but somehow persistent myth about
> > DNSSEC.
> > > >> > > You cannot lie that a zone does not support DNSSEC. The only way
> > to
> > > >> > > claim a zone does not support DNSSEC is with a signature chain
> > from
> > > >> > > the DNS root proving the nonexistence of the DS records for the
> > > >> > > delegation. Without that, the reply is BOGUS and will be ignored
> > as if
> > > >> > > there was no reply at all.
> > > >> >
> > > >> > I was talking about the case where the recursive resolver does the
> > > >> > validation, which is what's deployed in practice today. What you
> > wrote
> > > >> is
> > > >> > only true if the client does the DNSSEC validation itself. Most
> > clients
> > > >> > don't do that today, because too many domains are just
> > misconfigured and
> > > >> > broken. Eric Rescorla (the editor of the TLS RFCs) wrote a great
> > blog
> > > >> post
> > > >> > about this:
> > > >>
> > > >> The consensus of folks in the stub resolver space (at least glibc+musl
> > > >> and I would assume the BSDs as well) is that the way you do DNSSEC
> > > >> validation is by having a validating caching proxy or full recursive
> > > >> resolver on localhost. Doing validation in the stub resolver is not
> > > >> viable because it may be static-linked, where it would not be able to
> > > >> be updated with new algorithms, root-of-trust, etc.
> > > >
> > > >
> > > > No disagreement there. By "client" I meant the client device as a
> > whole,
> > > > and by "recursive resolver" I meant "the DNS server you got from DHCP".
> > > > Running a DNSSEC-validating recursive resolver on the client device
> > falls
> > > > into what I meant by "if the client does the DNSSEC validation itself".
> > > > Sorry for being unclear.
> > > >
> > > >
> > > >> This is one of the
> > > >> reasons our go-to response for new functionality wanted in the stub
> > > >> resolver is "do it in a nameserver on localhost" -- because you
> > > >> already need that to do DNSSEC.
> > > >>
> > > >
> > > > That makes sense. I wasn't working with the assumption that DNSSEC was
> > a
> > > > requirement.
> > > >
> > > > It really did not sound like you were talking about trusting the
> > > >> recursive, though. You called it a "fundamental design flaw", which it
> > > >> is not, and said it requires you to "trust all resolvers on the path",
> > > >> which it does not. It only requires you to trust the immediate
> > > >> resolver you are interacting with (and not even that if you put the
> > > >> validation in the stub resolver, but there are good reasons not to do
> > > >> that, as above). A pure-proxying server that relies on upstream
> > > >> recursives can do full DNSSEC validation. Dnsmasq is a canonical
> > > >> example. I believe systemd-resolvd also does it.
> > > >>
> > > >
> > > > That's fair, and I apologize for overstating my point. I absolutely
> > agree
> > > > that if you run a validating recursive resolver locally, then the
> > attack I
> > > > described isn't possible. When DNSSEC was designed, it was intended to
> > be
> > > > deployed in the model I described, where the validating recursive
> > resolver
> > > > is not on-device. And that's how it is still mostly deployed today
> > because
> > > > almost all general-purpose client devices do not validate locally. My
> > > > mental model is very focused around consumer devices where folks buy
> > them
> > > > and use them without ever changing default settings. That might be a
> > > > portion of musl users, but you clearly also have advanced users that do
> > > > things differently.
> > > >
> > > > > > > Regarding untrusted networks, one thing I hadn't considered yet
> > is
> > > >> > > > > that a network configurator probably needs a way to setup
> > > >> resolv.conf
> > > >> > > > > such that .local queries temp-fail rather than perma-fail (as
> > they
> > > >> > > > > would if you just sent the query to public dns) to use during
> > > >> certain
> > > >> > > > > race windows while switching networks. IOW "send .local
> > queries to
> > > >> > > > > configured nameservers" and "treat .local specially but with
> > an
> > > >> empty
> > > >> > > > > list of interfaces to send to" should be distinct
> > configurations..
> > > >> > > >
> > > >> > > > Yeah, caching negative results in DNS has been a tricky thing
> > from
> > > >> the
> > > >> > > > start. You probably could hack something by installing a fake
> > SOA
> > > >> record
> > > >> > > > for .local. in your recursive resolver running on localhost.
> > But the
> > > >> > > > RFC-compliant answer is for stub resolvers to treat it specially
> > > >> and know
> > > >> > > > that those often never get an answer (musl doesn't cache DNS
> > > >> results so
> > > >> > > in
> > > >> > > > a way we're avoiding this problem altogether at the stub
> > resolver)..
> > > >> > >
> > > >> > > The problem here is not about caching, just about clients using a
> > > >> > > response. You want a task (like a browser with open tabs) trying
> > to
> > > >> > > contact the site to get a tempfail rather than NxDomain which
> > might
> > > >> > > make it stop trying. But you probably want NxDomain if mDNS has
> > been
> > > >> > > disabled entirely, so that every .local lookup doesn't hang 5
> > seconds
> > > >> > > or whatever before saying "inconclusive".
> > > >> >
> > > >> > I'm assuming that by tempfail you mean EAI_AGAIN. The two browsers
> > that
> > > >> > I've written code in don't use that (Chrome just treats it the same
> > as a
> > > >> > resolution failure and will automatically refresh the tab on a
> > network
> > > >> > change; Safari doesn't use getaddrinfo and instead relies on an
> > > >> > asynchronous DNS API that adds results as they come in - I wrote
> > that
> > > >> > algorithm up in RFC 8305). All that said, synchronous blocking APIs
> > like
> > > >> > getaddrinfo need to eventually return even if no one replies, so
> > > >> EAI_AGAIN
> > > >> > makes sense in that case - whereas if .local is blocked by policy
> > then
> > > >> > immediately returning EAI_NONAME is best.
> > > >>
> > > >> Right. Even if applications don't currently distinguish them well,
> > > >> returning EAI_AGAIN vs EAI_NONAME is meaningful and enables them to do
> > > >> the right thing.
> > > >>
> > > >
> > > > Agreed.
> > > >
> > > > Thinking back to our discussion about whether to disable mDNS when the
> > > > resolver is on localhost. I still agree that from an ergonomics
> > > > perspective, using configs to mean multiple things isn't great. But
> > > > focusing just on the security properties for a second: if resolv.conf
> > is
> > > > configured to an IP address that is routed over a given non-loopback
> > > > interface, the current status quo is to send the .local query unsecured
> > > > over that interface. So if we were to, in that specific scenario,
> > instead
> > > > send the query over multicast, but only on that interface - then we
> > > > wouldn't measurably change the security properties of the system. In
> > > > practice there is a slight difference where now you can be attacked by
> > any
> > > > device on the network as opposed to only by the router on that
> > network, but
> > > > I'd argue that there's no meaningful threat model that distinguishes
> > > > between those two attacks. So that would be a safe default option. But
> > > > again, your points about least surprise are still valid, so if you
> > object
> > > > to that on those grounds I can't disagree.
> > > >
> > > > David
> > > >
> >

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-21 19:35                                       ` Rich Felker
@ 2024-03-22  0:10                                         ` David Schinazi
  2024-03-22  0:29                                           ` Tomas Volf
  0 siblings, 1 reply; 32+ messages in thread
From: David Schinazi @ 2024-03-22  0:10 UTC (permalink / raw)
  To: Rich Felker; +Cc: musl

[-- Attachment #1: Type: text/plain, Size: 29104 bytes --]

On Fri, Mar 22, 2024 at 3:46 AM Luca Barbato <lu_zero@gentoo.org> wrote:

>
> Keep in mind that distributions do and will change the default behavior
> of software components as they see fit anyway so if your use-case is
> having a desktop oriented distribution using musl support mDNS out of
> box, having the feature default off in musl would not make impossible
> having the distro default having it on.
>

That's a good point. My use case is a docker container with Alpine Linux.
It has a single interface and /etc/resolv.conf contains a single DNS name
server on the local network.

lu
>
> PS: which are the stakeholders contacted while the relevant standards
> brought in such hazardous default?


These RFCs went through the IETF Standards Track process, so the entire
IETF community was consulted when this was finalized around 2011-2012.

I'd like to understand why you think this is hazardous though. mDNS only
applies to host names under .local - those names are not covered by DNSSEC,
and therefore any queries for them are always sent completely insecure.
Sending those queries over the wire to the configured DNS resolver has very
similar security properties to sending them over the wire as multicast.

On Fri, Mar 22, 2024 at 5:35 AM Rich Felker <dalias@libc.org> wrote:

> On Thu, Mar 21, 2024 at 11:50:21PM +1000, David Schinazi wrote:
> > My apologies, it wasn't clear to me that these options had been formally
> > rejected,
>
> I don't like to use harsh words like "rejected", but from the
> beginning my part in this conversation has been about what properties
> an mDNS implementation for musl's stub resolver would need to have as
> preconditions to make it acceptable for inclusion. My hope was that,
> out of bringing the topic to the IETF meeting, we'd have some ideas
> for recommended forms for the necessary configuration controls that
> might be suitable for multiple implementations to adopt and aid in
> interoperability, not for you to come back using it as an
> appeal-to-authority to disregard the issues already raised.
>

My apologies, this wasn't intended as an appeal to authority. And to
highlight what I mentioned in my previous email, if you have unique
deployment constraints it's perfectly reasonable to do other things like
change default behavior. I was confirming what the specifications say - you
don't have to follow them. I wasn't trying to disregard the previous
points, please see my emails from March 9 that discuss security and threat
models. I think the preconditions you've laid out stem from a view of the
security properties of DNS that don't match my understanding. We're
operating with different assumptions and I don't think we've reached a
point of understanding where the difference lies.

> I'm not familiar with the musl process. Unfortunately, the choice
> > of off-by-default doesn't follow the relevant standards and, more
> > importantly for me, doesn't solve the use case that got me interested in
>
> Along with what Luca noted, the relevant standards are about how a
> system behaves, not about the mechanisms of a particular part of that
> system.
>

Not really, no. RFC 6762 Section 22.1 paragraph 3 applies to "Name
resolution APIs and libraries", not to operating systems. But to be clear
it's a SHOULD, so not doing anything is not in violation of the spec per se.

> working on this. Your choice is reasonable, and I respect it, but given
> > that it no longer solves an issue for me, I won't be able to spend time
> > writing code for this. If you do end up moving forward with mDNS, I'm
> happy
> > to help answer any questions about the mDNS specifications if you find
> that
> > helpful.
>
> That's fine. I'm not in any hurry to make decisions or write code
> here, but I'd still be happy to hear from others who want this to
> happen for fleshing out whether it makes sense and if so, how the
> configuration should work.
>
>
>
> > Best of luck, and thank you for all the work you do.
> > David
> >
> > On Thu, Mar 21, 2024 at 10:07 PM Rich Felker <dalias@libc.org> wrote:
> >
> > > On Thu, Mar 21, 2024 at 07:21:05PM +1000, David Schinazi wrote:
> > > > Hi,
> > > >
> > > > Earlier today at IETF, I discussed this topic with Stuart Cheshire,
> the
> > > > creator of mDNS. From his perspective, implementing a simpler option
> in
> > > > musl makes a lot of sense. Even though querying mDNS on a single
> > > interface
> > > > is not comprehensive, it'll work for the majority of uses while
> > > minimizing
> > > > implementation complexity. Using the UDP connect() trick to find the
> > > > interface corresponding to the configured resolver and then sending
> > > > multicast only on that interface will work and provide reasonable
> > > security
> > > > properties. He recommends using the IP_MULTICAST_IF /
> IPV6_MULTICAST_IF
> > > > socket options to select an interface, as that's what mDNSResponder
> does
> > > on
> > > > Linux. Additionally, he feels strongly that this should be enabled by
> > > > default, since the whole point of zero-configuration networking was
> for
> > > > things to work without requiring user configuration.
> > >
> > > Again, most of these choices are *not workable*. They have already
> > > been rejected.
> > >
> > > If you want this to happen, let's please work on something that has
> > > not been rejected.
> > >
> > > 1. Why on-by-default was rejected:
> > >
> > > musl is not only or even mostly used in a desktop user configuration
> > > where mDNS makes sense. It's used in lots of places where silently
> > > starting (after upgrade) to query other devices on a network and
> > > accepting answers from them is unexpected and hostile behavior. Yes,
> > > "on by default" makes sense on an end-user desktop system connected to
> > > a *private* network. This would be a default of the particular OS
> > > using musl and its network configurator, not of musl itself. (And
> > > AFAIK mDNS is not even "on my default" on Windows unless the connected
> > > network is marked as private.)
> > >
> > > 2. Why deciding what network to query based on the interface of the
> > > configured resolver is rejected:
> > >
> > > In a proper DNSSEC-validating setup, the configured resolver is
> > > 127.0.0.1 or ::1. This would disable mDNS entirely, forcing you to
> > > essentially *switch DNSSEC off if you want mDNS*. It was already
> > > explained why this is very bad.
> > >
> > > Single-interface query has not been rejected, but I don't see any
> > > reason to limit mDNS to a single interface. That doesn't make it
> > > particularly simpler or anything. If you're able to select the
> > > interface, it's just as easy to allow selecting a reasonable number of
> > > interfaces.
> > >
> > > The particular implementation mechanisms we've discussed, including
> > > possibly identifying the interface(s) to send to via where a
> > > particular address would be routed, seem overall good.
> > >
> > >
> > > > On Sat, Mar 9, 2024 at 9:44 AM David Schinazi <dschinazi.ietf@gmail.
> > > .com>
> > > > wrote:
> > > >
> > > > >
> > > > >
> > > > > On Fri, Mar 8, 2024 at 2:54 PM Rich Felker <dalias@libc.org>
> wrote:
> > > > >
> > > > >> On Fri, Mar 08, 2024 at 01:55:18PM -0800, David Schinazi wrote:
> > > > >> > On Fri, Mar 8, 2024 at 12:31 PM Rich Felker <dalias@libc.org>
> > > wrote:
> > > > >> >
> > > > >> > > On Fri, Mar 08, 2024 at 11:15:52AM -0800, David Schinazi
> wrote:
> > > > >> > > > On Fri, Mar 8, 2024 at 5:30 AM Rich Felker <dalias@libc.org
> >
> > > wrote:
> > > > >> > > >
> > > > >> > > > > On Thu, Mar 07, 2024 at 08:47:20PM -0800, David Schinazi
> > > wrote:
> > > > >> > > > > > Thanks. How would you feel about the following potential
> > > > >> > > configuration
> > > > >> > > > > > design?
> > > > >> > > > > > * Add a new configuration option "send_mdns_unicast"
> > > > >> > > > > > * When true, use the current behavior
> > > > >> > > > > > * When false, send the query on all non-loopback non-p2p
> > > > >> interfaces
> > > > >> > > > > > * Have send_mdns_unicast default to false
> > > > >> > > > > >
> > > > >> > > > > > I was thinking through how to pick interfaces, looked up
> > > what
> > > > >> other
> > > > >> > > mDNS
> > > > >> > > > > > libraries do, and pretty much all of them don't allow
> > > > >> configuring
> > > > >> > > > > > interfaces, whereas Avahi exposes allow-interfaces and
> > > > >> > > deny-interfaces.
> > > > >> > > > > I'm
> > > > >> > > > > > leaning towards not making this configurable to reduce
> > > > >> complexity. I
> > > > >> > > > > think
> > > > >> > > > > > that anyone interested in that level of config is
> probably
> > > using
> > > > >> > > Avahi
> > > > >> > > > > > anyway.
> > > > >> > > > > >
> > > > >> > > > > > Additionally this design has two nice properties: the
> > > default
> > > > >> > > behavior is
> > > > >> > > > > > RFC-compliant, and it means that for my use-case I don't
> > > need to
> > > > >> > > change
> > > > >> > > > > the
> > > > >> > > > > > config file, which was a big part of my motivation for
> doing
> > > > >> this
> > > > >> > > inside
> > > > >> > > > > of
> > > > >> > > > > > musl in the first place :-)
> > > > >> > > > >
> > > > >> > > > > As discussed in this thread, I don't think so. The biggest
> > > > >> problems I
> > > > >> > > > > initially brought up were increased information leakage
> in the
> > > > >> default
> > > > >> > > > > configuration and inability to control where the traffic
> goes
> > > > >> when you
> > > > >> > > > > do want it on. The above proposal just reverts to the
> initial,
> > > > >> except
> > > > >> > > > > for providing a way to opt-out.
> > > > >> > > > >
> > > > >> > > > > For the most part, mDNS is very much a "home user,
> personal
> > > > >> device on
> > > > >> > > > > trusted network" thing. Not only do you not want it to
> > > default on
> > > > >> > > > > because a lot of systems will be network servers on
> networks
> > > where
> > > > >> > > > > it's not meaningful (and can be a weakness that aids
> > > attackers in
> > > > >> > > > > lateral movement), but you also don't want it on when
> > > connected to
> > > > >> > > > > public wifi. For example if you have an open browser tab
> to
> > > > >> > > > > http://mything.local, and migrate to an untrusted network
> > > (with
> > > > >> your
> > > > >> > > > > laptop, tablet, phone, whatever), now your browser will be
> > > leaking
> > > > >> > > > > private data (likely at least session auth tokens, maybe
> > > more) to
> > > > >> > > > > whoever answers the mDNS query for mything.local.
> > > > >> > > >
> > > > >> > > > That's not quite right. The security properties of mDNS and
> DNS
> > > are
> > > > >> the
> > > > >> > > > same. DNS is inherently insecure, regardless of unicast vs
> > > > >> multicast. If
> > > > >> > > > I'm on a coffee shop Wi-Fi, all my DNS queries are sent in
> the
> > > > >> clear to
> > > > >> > > > whatever IP address the DHCP server gave me.
> > > > >> > >
> > > > >> > > That's not the case. Connections to non-mDNS hosts are
> > > authenticated
> > > > >> > > by TLS with certificates issued on the basis of ownership of
> the
> > > > >> > > domain name. That's not possible with mDNS hostnames, so
> they'll
> > > > >> > > either be no-TLS or self-signed certs. That's why the above
> > > attack is
> > > > >> > > possible. It was also possible with normal DNS in the bad old
> > > days of
> > > > >> > > http://, but that time is long gone.
> > > > >> >
> > > > >> > Apologies for being pedantic, but that's not true. The ability
> to
> > > get
> > > > >> TLS
> > > > >> > certificates for a domain name that you own is a property of the
> > > WebPKI,
> > > > >> > not a property of TLS. What you wrote is true, but only in the
> > > context
> > > > >> of a
> > > > >> > Web browser with an unmodified root certificate store. The
> features
> > > I
> > > > >> > mentioned above don't use the WebPKI, they have a separate root
> of
> > > > >> trust.
> > > > >> > For example, some of those Apple features exchange TLS
> certificates
> > > via
> > > > >> an
> > > > >> > out-of-band mechanism such as Apple trusted servers. Another
> > > example is
> > > > >> the
> > > > >> > Apple Watch: when you first pair a new Apple Watch with an
> iPhone,
> > > they
> > > > >> > exchange ed25519 public keys. Then any time the watch wants to
> > > transfer
> > > > >> a
> > > > >> > large file to/from the phone, it'll connect to Wi-Fi, use mDNS
> to
> > > find
> > > > >> the
> > > > >> > phone, and set up an IKEv2/IPsec tunnel that then protects the
> > > exchange.
> > > > >> > It's resilient to any attacks at the mDNS level.
> > > > >> >
> > > > >> > You're absolutely right that the security of Web requests using
> > > local
> > > > >> > connectivity is completely broken by the lack of WebPKI
> > > certificates for
> > > > >> > those. But sending the DNS query over multicast as opposed to
> > > > >> unencrypted
> > > > >> > unicast to an untrusted DNS server doesn't change the security
> > > > >> properties.
> > > > >> > In your example above, the open tab to http://mything.local
> will
> > > send
> > > > >> that
> > > > >> > query to the recursive resolver - and if that's the one
> received by
> > > DHCP
> > > > >> > then that server can reply with its own address and receive your
> > > auth
> > > > >> > tokens. One potential fix here is to configure your resolv.conf
> to
> > > > >> > localhost and then apply policy in that local resolver. But in
> > > practice,
> > > > >> > application developers don't rely on security at that layer,
> they
> > > assume
> > > > >> > that DNS is unsafe and implement encryption in userspace with
> some
> > > out
> > > > >> of
> > > > >> > band trust mechanism.
> > > > >>
> > > > >> My specific example was http://mything.local in a web browser,
> which
> > > > >> is the way you access lots of mDNS-enabled things in the absence
> of a
> > > > >> specific software ecosystem like Apple's. Since we're talking
> about
> > > > >> musl which would be running on Linux or a Linux-syscall-compatible
> > > > >> environment, without Apple apps, I think that's the main way
> anyone
> > > > >> would be using hypothetical mDNS support. And indeed this is the
> way
> > > > >> you access many printers, 3D printers, IP cameras, etc.
> > > > >>
> > > > >
> > > > > I have multiple services at home that use HTTP and mDNS to
> communicate
> > > > > with. But they're built knowing that unencrypted HTTP is unsafe.
> For
> > > > > example, one of my servers doesn't have any authentication - my
> browser
> > > > > just uses unauthenticated GETs, POSTs and WebSockets. If I leave
> the
> > > tab
> > > > > open and go to a coffee shop, my browser might send that GET to a
> > > server I
> > > > > don't trust but that request won't carry any sensitive information.
> > > Another
> > > > > of my servers uses TLS with self-signed certs, so every time I
> want to
> > > > > communicate with it, I need to click through my browser's "this is
> > > unsafe"
> > > > > interstitial to get to the page. If I switch networks, the browser
> will
> > > > > send me the warning again and I'll know not to click through when
> I'm
> > > not
> > > > > at home. In both of those cases, the security is handled (or not
> > > handled at
> > > > > all) at the application layer.
> > > > >
> > > > > Maybe at some point we'll have a good framework for authenticating
> > > > >> this kind of usage with certificates (probably certificate
> pinning on
> > > > >> first use, with good UX, is the only easy solution),
> > > > >
> > > > >
> > > > > Trust on first use works, or even better there are emerging
> solutions
> > > that
> > > > > leverage codes printed on devices and PAKEs so that a device on the
> > > > > untrusted network can't even hijack the first connection without
> having
> > > > > access to that code. The leading one for home automation is Matter
> [1].
> > > > > Coincidentally, it also leverages mDNS for discovery, and doesn't
> rely
> > > on
> > > > > security at the DNS level.
> > > > >
> > > > > [1] https://csa-iot.org/all-solutions/matter/
> > > > >
> > > > > but at present,
> > > > >> mDNS devices on the .local zone get accessed with plain http://
> all
> > > > >> the time, and this means it's unsafe to do mDNS on
> > > > >> public/untrusted/hostile networks.
> > > > >>
> > > > >
> > > > > The notion of something being "unsafe" (and security in general) is
> > > > > predicated on the existence of a threat model. It's unsafe to use
> > > > > unencrypted HTTP to your bank when your threat model includes
> someone
> > > on
> > > > > the coffee shop Wi-Fi trying to steal your bank credentials.
> > > Conversely,
> > > > > it's safe for me to print to this coffee shop printer if my threat
> > > model
> > > > > assumes that I'm ok with the owner of the coffee shop seeing my
> > > document.
> > > > > Another example is Chromecast which also uses mDNS: from Chrome on
> a
> > > Linux
> > > > > laptop, I can cast YouTube videos to the TV in this coffee shop.
> That's
> > > > > safe because I trust the network with the YouTube link I'm telling
> the
> > > TV
> > > > > to play. mDNS is not in and of itself safe or unsafe. It converts
> > > > > names into addresses, and what you do with those addresses can
> > > potentially
> > > > > be unsafe.
> > > > >
> > > > > That doesn't mean that every single use of mDNS on untrusted
> networks
> > > is
> > > > > safe. If someone builds a web page that sends valuable secrets over
> > > > > unencrypted HTTP to a .local name, then you have a security
> problem.
> > > But my
> > > > > point is that this security problem needs to be solved at the
> > > application
> > > > > layer and not at the DNS layer. That said, I agree that having a
> way to
> > > > > disable mDNS on a machine is a good idea, because there probably
> are
> > > users
> > > > > out there that are stuck with applications that for some reason
> > > decided to
> > > > > rely on DNS being secure.
> > > > >
> > > > > In terms of the tradeoff between usability and security, the
> default
> > > to me
> > > > > lies with default-enabling mDNS on all interfaces as Apple and
> Avahi
> > > do.
> > > > > But this tradeoff is between two metrics that can't be quantified
> one
> > > > > against the other for all possible uses, so I totally understand if
> > > your
> > > > > opinion for musl is that the tradeoff there is different than in
> other
> > > > > situations. You know your users better than I do.
> > > > >
> > > > > > > So the stack has to deal with
> > > > >> > > > the fact that any DNS response can be spoofed.
> > > > >> > >
> > > > >> > > That's also not possible with DNSSEC, but only helps if you're
> > > > >> > > validating it.
> > > > >> > >
> > > > >> > > > The most widely used
> > > > >> > > > solution is TLS: a successful DNS hijack can prevent you
> from
> > > > >> accessing a
> > > > >> > > > TLS service, but can't impersonate it. That's true of both
> mDNS
> > > and
> > > > >> > > regular
> > > > >> > > > unicast DNS. As an example, all Apple devices have mDNS
> enabled
> > > on
> > > > >> all
> > > > >> > > > interfaces, with no security impact - the features that
> rely on
> > > it
> > > > >> > > > (AirDrop, AirPlay, contact sharing, etc) all use mTLS to
> ensure
> > > > >> they're
> > > > >> > > > talking to the right device regardless of the correctness of
> > > DNS.
> > > > >> > > (Printing
> > > > >> > > > remains completely insecure, but that's also independent of
> DNS
> > > -
> > > > >> your
> > > > >> > > > coffee shop Wi-Fi access point can attack you at the IP
> layer
> > > too)..
> > > > >> One
> > > > >> > > > might think that DNSSEC could save us here, but it doesn't.
> > > DNSSEC
> > > > >> was
> > > > >> > > > unfortunately built with a fundamental design flaw: it
> requires
> > > you
> > > > >> to
> > > > >> > > > trust all resolvers on the path, including recursive
> resolvers..
> > > So
> > > > >> even
> > > > >> > > if
> > > > >> > > > you ask for DNSSEC validation of the DNS records for
> > > > >> www.example.com,
> > > > >> > > your
> > > > >> > > > coffee shop DNS recursive resolver can tell you "I checked,
> and
> > > > >> > > example.com
> > > > >> > > > does not support DNSSEC, here's the IP address for
> > > www.example.com
> > > > >> > > though"
> > > > >> > > > and you have to accept it.
> > > > >> > >
> > > > >> > > This is a completely false but somehow persistent myth about
> > > DNSSEC.
> > > > >> > > You cannot lie that a zone does not support DNSSEC. The only
> way
> > > to
> > > > >> > > claim a zone does not support DNSSEC is with a signature chain
> > > from
> > > > >> > > the DNS root proving the nonexistence of the DS records for
> the
> > > > >> > > delegation. Without that, the reply is BOGUS and will be
> ignored
> > > as if
> > > > >> > > there was no reply at all.
> > > > >> >
> > > > >> > I was talking about the case where the recursive resolver does
> the
> > > > >> > validation, which is what's deployed in practice today. What you
> > > wrote
> > > > >> is
> > > > >> > only true if the client does the DNSSEC validation itself. Most
> > > clients
> > > > >> > don't do that today, because too many domains are just
> > > misconfigured and
> > > > >> > broken. Eric Rescorla (the editor of the TLS RFCs) wrote a great
> > > blog
> > > > >> post
> > > > >> > about this:
> > > > >>
> > > > >> The consensus of folks in the stub resolver space (at least
> glibc+musl
> > > > >> and I would assume the BSDs as well) is that the way you do DNSSEC
> > > > >> validation is by having a validating caching proxy or full
> recursive
> > > > >> resolver on localhost. Doing validation in the stub resolver is
> not
> > > > >> viable because it may be static-linked, where it would not be
> able to
> > > > >> be updated with new algorithms, root-of-trust, etc.
> > > > >
> > > > >
> > > > > No disagreement there. By "client" I meant the client device as a
> > > whole,
> > > > > and by "recursive resolver" I meant "the DNS server you got from
> DHCP".
> > > > > Running a DNSSEC-validating recursive resolver on the client device
> > > falls
> > > > > into what I meant by "if the client does the DNSSEC validation
> itself".
> > > > > Sorry for being unclear.
> > > > >
> > > > >
> > > > >> This is one of the
> > > > >> reasons our go-to response for new functionality wanted in the
> stub
> > > > >> resolver is "do it in a nameserver on localhost" -- because you
> > > > >> already need that to do DNSSEC.
> > > > >>
> > > > >
> > > > > That makes sense. I wasn't working with the assumption that DNSSEC
> was
> > > a
> > > > > requirement.
> > > > >
> > > > > It really did not sound like you were talking about trusting the
> > > > >> recursive, though. You called it a "fundamental design flaw",
> which it
> > > > >> is not, and said it requires you to "trust all resolvers on the
> path",
> > > > >> which it does not. It only requires you to trust the immediate
> > > > >> resolver you are interacting with (and not even that if you put
> the
> > > > >> validation in the stub resolver, but there are good reasons not
> to do
> > > > >> that, as above). A pure-proxying server that relies on upstream
> > > > >> recursives can do full DNSSEC validation. Dnsmasq is a canonical
> > > > >> example. I believe systemd-resolvd also does it.
> > > > >>
> > > > >
> > > > > That's fair, and I apologize for overstating my point. I absolutely
> > > agree
> > > > > that if you run a validating recursive resolver locally, then the
> > > attack I
> > > > > described isn't possible. When DNSSEC was designed, it was
> intended to
> > > be
> > > > > deployed in the model I described, where the validating recursive
> > > resolver
> > > > > is not on-device. And that's how it is still mostly deployed today
> > > because
> > > > > almost all general-purpose client devices do not validate locally.
> My
> > > > > mental model is very focused around consumer devices where folks
> buy
> > > them
> > > > > and use them without ever changing default settings. That might be
> a
> > > > > portion of musl users, but you clearly also have advanced users
> that do
> > > > > things differently.
> > > > >
> > > > > > > > Regarding untrusted networks, one thing I hadn't considered
> yet
> > > is
> > > > >> > > > > that a network configurator probably needs a way to setup
> > > > >> resolv.conf
> > > > >> > > > > such that .local queries temp-fail rather than perma-fail
> (as
> > > they
> > > > >> > > > > would if you just sent the query to public dns) to use
> during
> > > > >> certain
> > > > >> > > > > race windows while switching networks. IOW "send .local
> > > queries to
> > > > >> > > > > configured nameservers" and "treat .local specially but
> with
> > > an
> > > > >> empty
> > > > >> > > > > list of interfaces to send to" should be distinct
> > > configurations..
> > > > >> > > >
> > > > >> > > > Yeah, caching negative results in DNS has been a tricky
> thing
> > > from
> > > > >> the
> > > > >> > > > start. You probably could hack something by installing a
> fake
> > > SOA
> > > > >> record
> > > > >> > > > for .local. in your recursive resolver running on localhost.
> > > But the
> > > > >> > > > RFC-compliant answer is for stub resolvers to treat it
> specially
> > > > >> and know
> > > > >> > > > that those often never get an answer (musl doesn't cache DNS
> > > > >> results so
> > > > >> > > in
> > > > >> > > > a way we're avoiding this problem altogether at the stub
> > > resolver)..
> > > > >> > >
> > > > >> > > The problem here is not about caching, just about clients
> using a
> > > > >> > > response. You want a task (like a browser with open tabs)
> trying
> > > to
> > > > >> > > contact the site to get a tempfail rather than NxDomain which
> > > might
> > > > >> > > make it stop trying. But you probably want NxDomain if mDNS
> has
> > > been
> > > > >> > > disabled entirely, so that every .local lookup doesn't hang 5
> > > seconds
> > > > >> > > or whatever before saying "inconclusive".
> > > > >> >
> > > > >> > I'm assuming that by tempfail you mean EAI_AGAIN. The two
> browsers
> > > that
> > > > >> > I've written code in don't use that (Chrome just treats it the
> same
> > > as a
> > > > >> > resolution failure and will automatically refresh the tab on a
> > > network
> > > > >> > change; Safari doesn't use getaddrinfo and instead relies on an
> > > > >> > asynchronous DNS API that adds results as they come in - I wrote
> > > that
> > > > >> > algorithm up in RFC 8305). All that said, synchronous blocking
> APIs
> > > like
> > > > >> > getaddrinfo need to eventually return even if no one replies, so
> > > > >> EAI_AGAIN
> > > > >> > makes sense in that case - whereas if .local is blocked by
> policy
> > > then
> > > > >> > immediately returning EAI_NONAME is best.
> > > > >>
> > > > >> Right. Even if applications don't currently distinguish them well,
> > > > >> returning EAI_AGAIN vs EAI_NONAME is meaningful and enables them
> to do
> > > > >> the right thing.
> > > > >>
> > > > >
> > > > > Agreed.
> > > > >
> > > > > Thinking back to our discussion about whether to disable mDNS when
> the
> > > > > resolver is on localhost. I still agree that from an ergonomics
> > > > > perspective, using configs to mean multiple things isn't great. But
> > > > > focusing just on the security properties for a second: if
> resolv.conf
> > > is
> > > > > configured to an IP address that is routed over a given
> non-loopback
> > > > > interface, the current status quo is to send the .local query
> unsecured
> > > > > over that interface. So if we were to, in that specific scenario,
> > > instead
> > > > > send the query over multicast, but only on that interface - then we
> > > > > wouldn't measurably change the security properties of the system.
> In
> > > > > practice there is a slight difference where now you can be
> attacked by
> > > any
> > > > > device on the network as opposed to only by the router on that
> > > network, but
> > > > > I'd argue that there's no meaningful threat model that
> distinguishes
> > > > > between those two attacks. So that would be a safe default option.
> But
> > > > > again, your points about least surprise are still valid, so if you
> > > object
> > > > > to that on those grounds I can't disagree.
> > > > >
> > > > > David
> > > > >
> > >
>

[-- Attachment #2: Type: text/html, Size: 39714 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-22  0:10                                         ` David Schinazi
@ 2024-03-22  0:29                                           ` Tomas Volf
  2024-03-22  0:36                                             ` David Schinazi
  2024-03-22  0:38                                             ` Rich Felker
  0 siblings, 2 replies; 32+ messages in thread
From: Tomas Volf @ 2024-03-22  0:29 UTC (permalink / raw)
  To: musl; +Cc: Rich Felker

[-- Attachment #1: Type: text/plain, Size: 1234 bytes --]

On 2024-03-22 10:10:29 +1000, David Schinazi wrote:
> > PS: which are the stakeholders contacted while the relevant standards
> > brought in such hazardous default?
>
>
> These RFCs went through the IETF Standards Track process, so the entire
> IETF community was consulted when this was finalized around 2011-2012.
>
> I'd like to understand why you think this is hazardous though. mDNS only
> applies to host names under .local - those names are not covered by DNSSEC,
> and therefore any queries for them are always sent completely insecure.
> Sending those queries over the wire to the configured DNS resolver has very
> similar security properties to sending them over the wire as multicast.

Please ignore my comment from the peanut gallery if it is totally off, but is it
not a difference between being able to do MitM (for regular non-DNSSEC DNS) and
just being on the same network (multicast)?  So the former only router/gateway
can do, the latter anyone able to respond to the multicast?  Assuming my
understanding is correct, that does not seem "very similar security properties".

Have a nice day,
Tomas Volf

--
There are only two hard things in Computer Science:
cache invalidation, naming things and off-by-one errors.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-22  0:29                                           ` Tomas Volf
@ 2024-03-22  0:36                                             ` David Schinazi
  2024-03-22  0:38                                             ` Rich Felker
  1 sibling, 0 replies; 32+ messages in thread
From: David Schinazi @ 2024-03-22  0:36 UTC (permalink / raw)
  To: musl, Rich Felker

[-- Attachment #1: Type: text/plain, Size: 1712 bytes --]

From an ability to respond to the query, you're absolutely right. Sending
all your DNS queries to multicast would be a bad idea. But this is specific
to .local, where any use of .local is aware of the fact that it is sent
unprotected over multicast and plans accordingly at the application layer.
David

On Fri, Mar 22, 2024 at 10:31 AM Tomas Volf <~@wolfsden.cz> wrote:

> On 2024-03-22 10:10:29 +1000, David Schinazi wrote:
> > > PS: which are the stakeholders contacted while the relevant standards
> > > brought in such hazardous default?
> >
> >
> > These RFCs went through the IETF Standards Track process, so the entire
> > IETF community was consulted when this was finalized around 2011-2012.
> >
> > I'd like to understand why you think this is hazardous though. mDNS only
> > applies to host names under .local - those names are not covered by
> DNSSEC,
> > and therefore any queries for them are always sent completely insecure.
> > Sending those queries over the wire to the configured DNS resolver has
> very
> > similar security properties to sending them over the wire as multicast.
>
> Please ignore my comment from the peanut gallery if it is totally off, but
> is it
> not a difference between being able to do MitM (for regular non-DNSSEC
> DNS) and
> just being on the same network (multicast)?  So the former only
> router/gateway
> can do, the latter anyone able to respond to the multicast?  Assuming my
> understanding is correct, that does not seem "very similar security
> properties".
>
> Have a nice day,
> Tomas Volf
>
> --
> There are only two hard things in Computer Science:
> cache invalidation, naming things and off-by-one errors.
>

[-- Attachment #2: Type: text/html, Size: 2082 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [musl] mDNS in musl
  2024-03-22  0:29                                           ` Tomas Volf
  2024-03-22  0:36                                             ` David Schinazi
@ 2024-03-22  0:38                                             ` Rich Felker
  1 sibling, 0 replies; 32+ messages in thread
From: Rich Felker @ 2024-03-22  0:38 UTC (permalink / raw)
  To: musl

On Fri, Mar 22, 2024 at 01:29:43AM +0100, Tomas Volf wrote:
> On 2024-03-22 10:10:29 +1000, David Schinazi wrote:
> > > PS: which are the stakeholders contacted while the relevant standards
> > > brought in such hazardous default?
> >
> >
> > These RFCs went through the IETF Standards Track process, so the entire
> > IETF community was consulted when this was finalized around 2011-2012.
> >
> > I'd like to understand why you think this is hazardous though. mDNS only
> > applies to host names under .local - those names are not covered by DNSSEC,
> > and therefore any queries for them are always sent completely insecure.
> > Sending those queries over the wire to the configured DNS resolver has very
> > similar security properties to sending them over the wire as multicast.
> 
> Please ignore my comment from the peanut gallery if it is totally off, but is it
> not a difference between being able to do MitM (for regular non-DNSSEC DNS) and
> just being on the same network (multicast)?  So the former only router/gateway
> can do, the latter anyone able to respond to the multicast?  Assuming my
> understanding is correct, that does not seem "very similar security properties".

On lots of networks, root on any device attached to the local network
segment can hijack/mitm unauthenticated traffic (mac spoofing, arp
shenanigans, etc.), but indeed with intelligent switches that restrict
what addresses can be used by what physical ports, or with various
bridged interface configurations, etc. it's possible to have a setup
where untrusted devices attached to the network can't do that. So,
whether there's a difference depends on how hardened your network
layer is.

Rich

^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2024-03-22  0:38 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-03-06  7:29 [musl] mDNS in musl David Schinazi
2024-03-06 16:15 ` Rich Felker
2024-03-06 16:45   ` Jeffrey Walton
2024-03-07  0:17   ` David Schinazi
2024-03-07  2:43     ` Rich Felker
2024-03-07 22:50       ` David Schinazi
2024-03-08  0:08         ` Rich Felker
2024-03-08  1:30           ` David Schinazi
2024-03-08  2:06             ` David Schinazi
2024-03-08  2:52             ` Rich Felker
2024-03-08  3:34               ` David Schinazi
2024-03-08  3:47                 ` Rich Felker
2024-03-08  4:47                   ` David Schinazi
2024-03-08 13:31                     ` Rich Felker
2024-03-08 19:15                       ` David Schinazi
2024-03-08 20:31                         ` Rich Felker
2024-03-08 21:55                           ` David Schinazi
2024-03-08 22:54                             ` Rich Felker
2024-03-08 23:44                               ` David Schinazi
2024-03-21  9:21                                 ` David Schinazi
2024-03-21 12:07                                   ` Rich Felker
2024-03-21 13:50                                     ` David Schinazi
2024-03-21 17:45                                       ` Luca Barbato
2024-03-21 19:35                                       ` Rich Felker
2024-03-22  0:10                                         ` David Schinazi
2024-03-22  0:29                                           ` Tomas Volf
2024-03-22  0:36                                             ` David Schinazi
2024-03-22  0:38                                             ` Rich Felker
2024-03-09  0:23                               ` Jeffrey Walton
2024-03-08 15:31     ` Markus Wichmann
2024-03-08 17:22       ` Rich Felker
2024-03-06 16:15 ` Markus Wichmann

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).