From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=5.0 tests=DKIM_ADSP_CUSTOM_MED, DKIM_INVALID,DKIM_SIGNED,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,HTML_MESSAGE,MAILING_LIST_MULTI, NORMAL_HTTP_TO_IP,NUMERIC_HTTP_ADDR,RCVD_IN_DNSWL_MED, RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL,T_SCC_BODY_TEXT_LINE,WEIRD_PORT autolearn=ham autolearn_force=no version=3.4.4 Received: from second.openwall.net (second.openwall.net [193.110.157.125]) by inbox.vuxu.org (Postfix) with SMTP id 94040255E4 for ; Fri, 8 Mar 2024 04:34:58 +0100 (CET) Received: (qmail 22066 invoked by uid 550); 8 Mar 2024 03:30:57 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Reply-To: musl@lists.openwall.com Received: (qmail 22033 invoked from network); 8 Mar 2024 03:30:56 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1709868885; x=1710473685; darn=lists.openwall.com; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=ADqVmQ5T/jxEWbmUMzR2J5NVyO2QXa/dMTSTsa2HkW4=; b=YJfJznxUQK7u92OhEmogJSVYfOAYu3jFvLv36clrAqblfAmfgKlP2agJsxvOjRu77c 8A1PbrLYnwpwRLqZjiWpEjEJMuRr5GGYqS4fYlW2TAdQshJn8rstPVz0lxRDrQv1DScF cZFRp/d3yqhRFOyZtCFPnJyfUNsqjIrL41xMgDivKyLOoB6dd5vxRbx2hm84Zk1IsULe 1X6Ji70hpzKCpMchqowlPg7PJzfPR/3ZTbhg4lEAWWyJUyVyhhpTh9wyp7gvv/bEfdcY 4FRNmj4uKTL74Tmdg6cvQWTqNP6XiadgSrAZEFQKP0eDOpNg/80dkloSABMk6u1JOdys h5bw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1709868885; x=1710473685; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=ADqVmQ5T/jxEWbmUMzR2J5NVyO2QXa/dMTSTsa2HkW4=; b=beEq3COnL4y2W5RQ2yXU9P/CTGIMeRmyuvTAOkRidqZMu5lB52mnvj6eyRXdt8NAK5 a93OqW+E6WLppZue/vUMZR6TjG+DwNh3FDi6GosEH0ACy/OeCksHMV0qrQVhst4zC2LS AxhuyR67t+KdDVZXMeruv1lV/QRivMNiwSa+ZXvYiW0X59VmfsKNd+lDr/iVglD1pE/j INzQiGGzoJC0YYiUW3XWN1mS1A2Dawq1+6TZgs58S3+ZG+fxKko7wizyo1SzuNyf6c/E AtfVpPuDjFIcriOO2WD33+mS1jc6qxYrIOCrg72VwEGb1zU5sUxJBh4k5xRbhYDzPgAY 7V6A== X-Gm-Message-State: AOJu0YwQPlppics62VheQAl1hSGNbGp+Za6m9z+Go5CXblecQ4k5RuAk ff0lmp7d1hQmSB8WwzSat33MwGwHacwKW9F/OCnZsO6htDbOfsBi7cYcHywTLsFEqT8cT5/s0sp 72phRKbDN+g43n41HokT6kBwePQm09Idg5WU= X-Google-Smtp-Source: AGHT+IFJbr6Qvposiy05+bb+eiR7bidlXQeZXZYD375rYZMG8YSzZwfa4BOOI8xQIL70+BGEop697VzLBUNfVskPAEo= X-Received: by 2002:a19:7613:0:b0:513:40e4:9090 with SMTP id c19-20020a197613000000b0051340e49090mr2128535lff.28.1709868884479; Thu, 07 Mar 2024 19:34:44 -0800 (PST) MIME-Version: 1.0 References: <20240306161544.GH4163@brightrain.aerifal.cx> <20240307024316.GI4163@brightrain.aerifal.cx> <20240308000818.GJ4163@brightrain.aerifal.cx> <20240308025204.GK4163@brightrain.aerifal.cx> In-Reply-To: <20240308025204.GK4163@brightrain.aerifal.cx> From: David Schinazi Date: Thu, 7 Mar 2024 19:34:33 -0800 Message-ID: To: Rich Felker Cc: musl@lists.openwall.com Content-Type: multipart/alternative; boundary="00000000000078dfc106131ddf96" Subject: Re: [musl] mDNS in musl --00000000000078dfc106131ddf96 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable 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=E2=80=AFPM Rich Felker wrote: > On Thu, Mar 07, 2024 at 05:30:06PM -0800, David Schinazi wrote: > > On Thu, Mar 7, 2024 at 4:08=E2=80=AFPM Rich Felker wr= ote: > > > > > On Thu, Mar 07, 2024 at 02:50:53PM -0800, David Schinazi wrote: > > > > On Wed, Mar 6, 2024 at 6:42=E2=80=AFPM Rich Felker wrote: > > > > > > > > > On Wed, Mar 06, 2024 at 04:17:44PM -0800, David Schinazi wrote: > > > > > > As Jeffrey points out, when the IETF decided to standardize mDN= S, > > > 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 f= or > > > 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 rou= te > > > > > 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 networ= k > > > > > 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 an= d > 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 th= at > > > 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 DN= S > > > > 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 !=3D 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 us= e > > 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. I= n > > > IPv6, > > > > > the > > > > > > interface needs to be specified in the scope_id. So we'd need t= o > 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 indee= d > > > 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 V= Ms > > 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. W= e > > 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 wou= ld > > have sent the unicast query. Downside is that since all queries share t= he > > same socket, we'd bind everything to the interface of the first resolve= r, > > 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 thos= e > 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 kno= b > > > 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 t= o > > > 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 != =3D > > 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, nee= d > > 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.co= nf > > 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 en= ds > > 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 > --00000000000078dfc106131ddf96 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hmmm. The cleaner option with the new config option and su= pport for querying on all interfaces probably reaches a level of complexity= where running a resolver on=C2=A0localhost might be best. And I honestly a= gree with your point that overloading the config option isn't great des= ign. So perhaps "not doing it at all" is the answer then. I'l= l think about it some more, and discuss it with some mDNS experts at the ne= xt IETF meeting in a couple weeks. I'll report back if someone has a cl= ever idea that wouldn't violate the design principles we've discuss= ed in this thread. But if not, I want to say thanks for thinking through th= is with me.

Cheers,
David

On Thu, Mar 7, = 2024 at 6:51=E2=80=AFPM Rich Felker <= dalias@libc.org> wrote:
On Thu, Mar 07, 2024 at 05:30:06PM -0800, David Schinazi wro= te:
> On Thu, Mar 7, 2024 at 4:08=E2=80=AFPM 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=E2=80=AFPM Rich Felker <dalias@libc.org> wro= te:
> > >
> > > > On Wed, Mar 06, 2024 at 04:17:44PM -0800, David Schinaz= i wrote:
> > > > > As Jeffrey points out, when the IETF decided to st= andardize mDNS,
> > they
> > > > > published it (RFC 6762) at the same time as the Sp= ecial-Use Domain
> > > > Registry
> > > > > (RFC 6761) which created a process for reserving d= omain names for
> > custom
> > > > > purposes, and ".local" was one of the in= itial 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 b= ut at the end of
> > the
> > > > day
> > > > > punycode won. Even Apple's implementation of g= etaddrinfo will perform
> > > > > punycode conversion for .local instead of sending = the UTF-8. So in
> > > > practice
> > > > > you wouldn't need to special-case anything her= e.
> > > >
> > > > 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 etherne= t? VPN links or other
> > > > > > sorts of tunnels? Just one local interface (w= hich 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 th= e default route
> > > > interface
> > > > > would be a good start, more on that below.
> > > >
> > > > This is really one thing that suggests a need for confi= gurability
> > > > outside of what libc might be able to offer. With norma= l DNS lookups,
> > > > they're something you can block off and prevent fro= m 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). Addi= ng mDNS that's
> > > > on-by-default and not configurable would make a vector = for network
> > > > traffic being generated that's probably not expecte= d 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. Con= ceptually,
> > > sending DNS to localhost is musl's IPC mechanism to a mo= re 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. Conver= sely, when
> > > there's a non-loopback IP configured in resolv.conf, the= n musl acts as a
> > > DNS stub resolver and the server in resolv.conf acts as a DN= S recursive
> > > resolver. In that scenario, sending the .local query over DN= S to that
> > other
> > > host violates the RFCs. This allows us to treat the configur= ed resolver
> > > address as an implicit configuration mechanism that allows u= s 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<= br> > > DNSSEC right (which requires validating nameserver on localhost).=
> > Inventing a knob that's an overload of an existing knob is st= ill
> > inventing a knob, just worse.
> >
>
> Sorry, I was suggesting the other way around: to only enable the mDNS = mode
> if resolver !=3D 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 globall= y unique
> and signed. In theory you could exchange DNSSEC keys out of band and u= se
> DNSSEC with mDNS, but I've never heard of anyone doing that. At th= at 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 ja= nky :-)

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<= br> 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 ingre= dient.
> > > > >
> > > > > 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. S= o we'd need to pull
> > > > that
> > > > > out of the kernel with rtnetlink.
> > > >
> > > > There's already code to enumerate interfaces, but i= t's a decent bit of
> > > > additional machinery to pull in as a dep for the stub r= esolver,
> > >
> > >
> > > Yeah we'd need lookup_name.c to include netlink.h - it&#= 39;s not huge though,
> > > netlink.c is 50 lines long and statically linked anyway righ= t?
> >
> > I was thinking in terms of using if_nameindex or something, but i= ndeed
> > 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 don= e this
> > way.
> >
> > BTW if there's a legacy ioctl that tells you the number of in= terfaces
> > (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 tha= t 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 s= cope 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 IP= v4 I'd just
> > use
> > > the default route interface.
> >
> > But the default route interface is almost surely *not* the LAN wh= ere
> > you expect .local things to live except in the case where there i= s
> > only one interface. If you have a network that's segmented in= to
> > separate LAN and outgoing interfaces, the LAN, not the route to t= he
> > 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 thi= s,
> > 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 rathe= r
> > 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 s= ocket to
> get a route lookup" trick. Let's say we're configured wit= h a nameserver
> that's not 127.0.0.1 (which is the case where I'd like to enab= le this)
> let's say the nameserver is set to 192.0.2.33, then today foobar.l= ocal
> 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 woul= d
> ensure that we send the mDNS traffic on the same interface where we wo= uld
> 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 re= solver,
> 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, b= ut for those I
> > > think it makes more sense to recommend running your own reso= lver on
> > > loopback (you'd need elevated privileges to make this wo= rk fully anyway).
> > > Coding wise, I think this would be pretty robust. The only b= reakage I
> > > foresee is cases where someone built a custom resolver that = runs on a
> > > different machine and somehow handles .local differently tha= n 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&= #39;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, timeo= ut,
> > retries, etc. in resolv.conf. This ensures that it doesn't be= come
> > attack surface/change-of-behavior in network environments where p= eers
> > are not supposed to be able to define network names.
> >
>
> That would work. I'm not sure who maintains the list of options th= ough.
> 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 m= ore).

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<= br> > > the "which interface(s)" problem by letting the answer = just be
> > "whichever one(s) the user configured" (with the defaul= t list being
> > empty). That way we wouldn't even need netlink, just if_namet= oindex to
> > convert interface name strings to scope ids, or alternatively (do= es
> > 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, becaus= e it
> would break for any non-static addresses like DHCP or v6 RAs. The inte= rface
> name would require walking the getifaddrs list to map it to a correspo= nding
> 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<= br> 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 "reso= lver !=3D
> 127.0.0.1" - very limited code size change, but only handles a sm= all 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 the= y
do want.

> (2) the cleaner option that involves more work - new config option, ne= ed
> multiple sockets - would be cleaner design-wise, but would change quit= e a
> bit more code
>
> Another aspect to consider is the fact that in a lot of cases resolv.c= onf
> 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 thi= ng 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
--00000000000078dfc106131ddf96--