F23 System Wide Change: Default Local DNS Resolver

Dan Williams dcbw at redhat.com
Thu Jun 18 16:14:49 UTC 2015


On Fri, 2015-06-12 at 14:32 -0400, Paul Wouters wrote:
> On Fri, 12 Jun 2015, Dan Williams wrote:
> 
> >> That is why HTTP redirection and DNS failure have to be detected by
> >> whatever is the "hot spot detector". Both items weigh in on triggering
> >> a hotspot logon window.
> >
> > Agreed.  But how does the DNS failure actually get relayed to the thing
> > doing the HTTP request, when unbound + DNSSEC is involved?  That's one
> > point I'm very unclear on.
> 
> In hotspot mode (dnssec-trigger's version of hotspot mode)
> /etc/resolv.conf contains the DHCP supplied DNS servers. Those are used
> to determine both the "DNS cleanliness" state, and is also used to fetch
> the fedoraproject hot spot detection page. The unbound DNS server, while
> running, is not used at all for anything, as resolv.conf does not point
> to it. Unfortunately, because this is not isolated to dnssec-triggerd,
> all applications doing DNS during this time get crap/dangerous DNS
> resolves, leading to add the bad certificate warning popups. And why I
> was hoping to isolate that with either a network namespace, or other
> solution that prevents us from requiring to affect the whole system
> by changing resolv.conf.
> 
> If selecting "cache only", then resolv.conf points to 127.0.0.1 and
> unbound is configured with a "DNS forwarder" for everything set to
> 127.0.0.127 so no DNS lookups ever leave the host.
> 
> >>> 1. NM connects to a new network
> >>> 2. NM updates DNS information
> >>
> >> I don't know what 2) means. If it means rewriting /etc/resolv.conf or
> >> the unbound forwarder configuration, we have already lost if the DNS
> >> was malicious (and/or a hotspot DNS)
> >
> > It means whatever "dns" action was set in NM, either writing
> > resolv.conf, not touching anything (dns=none), sending split DNS to
> > unbound (dns=unbound), or to dnsmasq (dns=dnsmasq), etc.  In this case
> > I'll presume dns=unbound.
> 
> Ahh thanks.
> 
> >> dnssec-trigger currently detects the difference by also checking for an
> >> http hotspot redirect using http://fedoraproject.org/static/hotspot.txt
> >> If no http redirect, then DNS is broken and it tries to work around it
> >> by becoming a full iterative resolver or doing DNS over TCP or DNS over
> >> TLS. and if it all fails, presents the "insecure or cache only" dialog.
> >
> > NM also checks for redirection.
> >
> > Though, what do you mean by "if no HTTP redirect, then DNS is broken"?
> 
> Sorry I meant "If no http redirect, and DNS is broken, then it tries to
> work around by ...". That is, when there is an http redirect, there is
> no point doing anything about DNS because after authenticating to the
> hotspot, DNS might turn out to be either fine or broken for other
> reasons.
> 
> >> 1) NM detects a new nework, but doesn't tell the applications that there
> >>     is network connectivity yet. So firefox won't throw HTTPS warnings
> >>     and pidgin/IM won't throw https warnings. Because as far as they know
> >>     the network is still down.
> >
> > Agreed.  Right now we have "connectivity" states, but they are all
> > determined after the interface is signaled as "connected".  We can do
> > some work here to indicate connectivity status on this interface before
> > indicating to applications that the interface is fully connected.
> 
> That would be awesome!
> 
> >> 2) NM/dnssec-trigger does the HTTP and DNS probing and prompting using
> >>     a dedicated container and any DNS requests in that container are
> >>     thrown away with the container once hotspot has been authenticated.
> >>     This would allow us to never have resolv.conf on the host be
> >>     different from 127.0.0.1. (currently, it needs to put in the hotspot
> >>     DNS servers for the hotspot logon, exposing other applications to
> >>     fake DNS)
> >
> > I'm not sure a container really needs to be involved as long as the DNS
> > resolution can be done without hitting resolv.conf.  That's not hugely
> > hard to do I think
> 
> True. In fact with unbound it is pretty trivial to do. The equivalent
> unbound python code for that would be:
> 
> import unbound
> 
> ctx = unbound.ub_ctx()
> ctx.resolvconf("/this/networks/respresentation/of/resolv.conf")

Hmm, that doesn't really allow for split DNS though since it uses the
resolv.conf format?  Ideally we could just send unbound a list of server
+domain, and then a fallback of server+"*" for anything not matching
that list.

> any resolve calls made will use the non-system resolv.conf's nameserver
> addresses.
> 
> So the hotspot check could be:
> 
> ctx = unbound.ub_ctx()
> ctx.add_ta_file(rootanchor) # DNSSEC root key
> ctx.resolvconf("/this/networks/respresentation/of/resolv.conf")
> status, result = ctx.resolve("fedoraproject.org", unbound.RR_TYPE_A)
> if not result.havedata or not result.secure:
>  	# we're captive because fedoraproject.org is DNSSEC signed and
>  	# we got an error (forged) response
>  	# Redo query with a non-DNSSEC cache to get forged A record to
>  	# authenticate to the hotspot
>  	insecurectx = unbound.ub_ctx()
>  	insecurectx.resolvconf("/this/networks/respresentation/of/resolv.conf")
>  	status, result = insecurectx.resolve("fedoraproject.org", unbound.RR_TYPE_A)
>  	if result.havedata:
>  		addr = result.data.address_list[0]
>  		# give addr to the captive portal logon HTTP engine
>  	insecurectx.ub_close()
> else:
>  	if result.havedata:
>  		# check for HTTP interception - we might still be captive
>  		addr = result.data.address_list[0]
>  		# give addr to the captive portal logon HTTP engine
> ctx.ub_close()

Ok, so as I asked about earlier, the connectivity checking is a two-step
process then:

1) look up the IP address of your connectivity server using DNS, and if
the result is insecure then you know your DNS is hijacked (eg,
hotspot/portal) or your local DNS server is utterly broken

2) if #1 succeeded then continue to the HTTP connectivity check

> Things are a little tricker because the hotspot likely stupidly uses
> even more DNS calls to build up the logon page, so whatever the http
> rendering agent is (eg xdg-open or firefox or whatever) needs to keep
> using this unbound cache and not fall back to the system default one.

Yeah, whatever thing handles the logon (GNOME Shell, etc) would have to
have a method to inject nameservers that the web sub-process would use
exclusively instead of the system namesevers.  Then the process would go
something like this:

0) resolve.conf/unbound/whatever DNS is unpopulated
1) NetworkManager looks up connectivity server IP address
2) NetworkManager does the connectivity check using that IP address
3) assuming either #1 or #2 fails, NM signals HOTSPOT connectivity state
and provides the DNS information via the API, including any DHCP/WISPR
information received from the network
4) Hotspot agent (GNOME Shell, KDE, whatever) sees the HOTSPOT state,
reads the DNS servers, and spawns a sandboxed web browser using the
preliminary DNS servers
5) User completes hotspot logon or rejection, user agent signals that
hotspot operations complete
6) NetworkManager re-does connectivity checks, and assuming the result
is "success", indicates CONNECTED connectivity state

or something like that.  But these steps could be split out into a
small, single-purpose connectivityd that used information from NM/other
sources and was triggered by NM/other sources, and then NM wouldn't have
to do it.  NM could still proxy the state since NM would know when to
trigger connectivity checks anyway.  But I digress.

> > Then once the hotspot login is completed, we must re-do the connectivity
> > check to ensure that we do indeed have access to the full internet.  If
> > we do, then we can finally signal "connected".  If it fails again, then
> > we either show the hotspot login window again, or somehow indicate that
> > hotspot login failed.
> 
> > Note that none of this mentions DNS to the user at all yet...  so what
> > happens if the hotspot login succeeds, we get connectivity to the
> > internet, but the hotspot DNS doesn't support DNSSEC correctly?
> 
> If HTTP is no longer redirected (dnssec-trigger keeps probing while you
> pull your credit card out), it assumes you have successfully authenticated
> to the hotspot. It re-tests the supplied DNS servers. If these are still
>   determined to be too broken for using DNSSEC (eg too old bind,
> dnsmasq) it tries to (silently) become a full itterative nameservers,
> eg it will not use any forwards and do all the DNS work itself. If this
> also fails, for example because the network blocks port 53 to all but
> its own DNS servers,  dnssec-trigger tries the other modes of DNS over
> TCP/SSL. If any of this works the user isn't even consulted. Only when
> all of this fails do we need to contact the user and ask them to go
> "insecure" or "cache only"

This is the part that I feel like unbound should do, or if not unbound
then whatever local caching nameserver we do have.  Perhaps that's
already built into unbound and only controlled by dnssec-trigger, but it
seems like something more integral to the resolver than outside of it?

Dan



More information about the devel mailing list