Re: Opportunistic DoT for unwind(8)

2019-11-02 Thread Remi Locherer
On Sat, Nov 02, 2019 at 08:20:08AM +0100, Otto Moerbeek wrote:
> On Fri, Nov 01, 2019 at 10:43:27PM +0100, Remi Locherer wrote:
> 
> > On Fri, Nov 01, 2019 at 09:53:28PM +0100, Florian Obser wrote:
> > > On Fri, Nov 01, 2019 at 09:45:37PM +0100, Florian Obser wrote:
> > > > On Fri, Nov 01, 2019 at 09:35:07PM +0100, Remi Locherer wrote:
> > > > > On Thu, Oct 31, 2019 at 08:14:04PM +0100, Otto Moerbeek wrote:
> > > > > > Hi,
> > > > > > 
> > > > > > So here's a new diff that incorporates the bug fix mentioned plus
> > > > > > debug printf line changes suggested by Stuart.
> > > > > > 
> > > > > > Please note that this is a diff on top of very recent current, i.e.
> > > > > > florian's work he committed today. That means that you need to be
> > > > > > up-to-date (including a recent libc update that was committed a few
> > > > > > days ago) to be able to test this version.
> > > > > 
> > > > > I upgraded to a snapshot from today, updated the source and applied
> > > > > your diff. Then I did the same test as last time using pf to block 
> > > > > port 53
> > > > > (block return out log inet proto {tcp udp} to !9.9.9.9 port 53).
> > > > > 
> > > > > Result: the non functional type asr is selected instead of the 
> > > > > forwarder.
> > > > > 
> > > > > $ doas unwindctl status 
> > > > > captive portal is unknown
> > > > > 
> > > > > selected type status
> > > > >  recursor dead
> > > > > forwarder validating (OppDoT)
> > > > >  dhcp unknown (OppDoT)
> > > > >*  asr dead
> > > > > $
> > > > > $ getent hosts undeadly.org
> > > > > $ echo $?
> > > > > 2
> > > > > $ dig +short undeadly.org @9.9.9.9
> > > > > 94.142.241.173
> > > > > $
> > > > > 
> > > > > Without your patch unwind behaves similar regarding the type 
> > > > > selection:
> > > > > 
> > > > > $ doas unwindctl status 
> > > > > captive portal is unknown
> > > > 
> > > > ^ you are creating a not supported configuration.
> > > > 
> > > > When we are behind a captive portal or don't know yet if we are behind
> > > > a captive portal resolving is forced to asr.
> > > > 
> > > > That might not be very wise if asr is dead but I currently don't see
> > > > how this can happen in practice except with a well aimed foot-gun.
> > > 
> > > Actually, I have an idea how this can happen in practice, please try this:
> > > 
> > > diff --git resolver.c resolver.c
> > > index f59860a5e98..5bbc63f60fa 100644
> > > --- resolver.c
> > > +++ resolver.c
> > > @@ -1282,7 +1282,8 @@ best_resolver(void)
> > >  
> > >   if (captive_portal_state == PORTAL_UNKNOWN || captive_portal_state ==
> > >   BEHIND) {
> > > - if (resolvers[UW_RES_ASR] != NULL) {
> > > + if (resolvers[UW_RES_ASR] != NULL && resolvers[UW_RES_ASR]->
> > > +state != DEAD) {
> > >   res = resolvers[UW_RES_ASR];
> > >   goto out;
> > >   }
> > > 
> > > 
> > 
> > Yes, this makes unwind cope with this situation:
> > 
> > $ unwindctl status 
> > not behind captive portal
> > 
> > selected type status
> >  recursor dead
> >*forwarder validating
> >  dhcp dead
> >   asr dead
> > $
> > 
> > OK remi@
> > 
> 
> And with my diff on top of that?

Yes, now it works as expected.

OK remi@
 



Re: Opportunistic DoT for unwind(8)

2019-11-02 Thread Otto Moerbeek
On Fri, Nov 01, 2019 at 10:43:27PM +0100, Remi Locherer wrote:

> On Fri, Nov 01, 2019 at 09:53:28PM +0100, Florian Obser wrote:
> > On Fri, Nov 01, 2019 at 09:45:37PM +0100, Florian Obser wrote:
> > > On Fri, Nov 01, 2019 at 09:35:07PM +0100, Remi Locherer wrote:
> > > > On Thu, Oct 31, 2019 at 08:14:04PM +0100, Otto Moerbeek wrote:
> > > > > Hi,
> > > > > 
> > > > > So here's a new diff that incorporates the bug fix mentioned plus
> > > > > debug printf line changes suggested by Stuart.
> > > > > 
> > > > > Please note that this is a diff on top of very recent current, i.e.
> > > > > florian's work he committed today. That means that you need to be
> > > > > up-to-date (including a recent libc update that was committed a few
> > > > > days ago) to be able to test this version.
> > > > 
> > > > I upgraded to a snapshot from today, updated the source and applied
> > > > your diff. Then I did the same test as last time using pf to block port 
> > > > 53
> > > > (block return out log inet proto {tcp udp} to !9.9.9.9 port 53).
> > > > 
> > > > Result: the non functional type asr is selected instead of the 
> > > > forwarder.
> > > > 
> > > > $ doas unwindctl status 
> > > > captive portal is unknown
> > > > 
> > > > selected type status
> > > >  recursor dead
> > > > forwarder validating (OppDoT)
> > > >  dhcp unknown (OppDoT)
> > > >*  asr dead
> > > > $
> > > > $ getent hosts undeadly.org
> > > > $ echo $?
> > > > 2
> > > > $ dig +short undeadly.org @9.9.9.9
> > > > 94.142.241.173
> > > > $
> > > > 
> > > > Without your patch unwind behaves similar regarding the type selection:
> > > > 
> > > > $ doas unwindctl status 
> > > > captive portal is unknown
> > > 
> > > ^ you are creating a not supported configuration.
> > > 
> > > When we are behind a captive portal or don't know yet if we are behind
> > > a captive portal resolving is forced to asr.
> > > 
> > > That might not be very wise if asr is dead but I currently don't see
> > > how this can happen in practice except with a well aimed foot-gun.
> > 
> > Actually, I have an idea how this can happen in practice, please try this:
> > 
> > diff --git resolver.c resolver.c
> > index f59860a5e98..5bbc63f60fa 100644
> > --- resolver.c
> > +++ resolver.c
> > @@ -1282,7 +1282,8 @@ best_resolver(void)
> >  
> > if (captive_portal_state == PORTAL_UNKNOWN || captive_portal_state ==
> > BEHIND) {
> > -   if (resolvers[UW_RES_ASR] != NULL) {
> > +   if (resolvers[UW_RES_ASR] != NULL && resolvers[UW_RES_ASR]->
> > +state != DEAD) {
> > res = resolvers[UW_RES_ASR];
> > goto out;
> > }
> > 
> > 
> 
> Yes, this makes unwind cope with this situation:
> 
> $ unwindctl status 
> not behind captive portal
> 
> selected type status
>  recursor dead
>*forwarder validating
>  dhcp dead
>   asr dead
> $
> 
> OK remi@
> 

And with my diff on top of that?

-Otto



Re: Opportunistic DoT for unwind(8)

2019-11-01 Thread Remi Locherer
On Fri, Nov 01, 2019 at 09:53:28PM +0100, Florian Obser wrote:
> On Fri, Nov 01, 2019 at 09:45:37PM +0100, Florian Obser wrote:
> > On Fri, Nov 01, 2019 at 09:35:07PM +0100, Remi Locherer wrote:
> > > On Thu, Oct 31, 2019 at 08:14:04PM +0100, Otto Moerbeek wrote:
> > > > Hi,
> > > > 
> > > > So here's a new diff that incorporates the bug fix mentioned plus
> > > > debug printf line changes suggested by Stuart.
> > > > 
> > > > Please note that this is a diff on top of very recent current, i.e.
> > > > florian's work he committed today. That means that you need to be
> > > > up-to-date (including a recent libc update that was committed a few
> > > > days ago) to be able to test this version.
> > > 
> > > I upgraded to a snapshot from today, updated the source and applied
> > > your diff. Then I did the same test as last time using pf to block port 53
> > > (block return out log inet proto {tcp udp} to !9.9.9.9 port 53).
> > > 
> > > Result: the non functional type asr is selected instead of the forwarder.
> > > 
> > > $ doas unwindctl status 
> > > captive portal is unknown
> > > 
> > > selected type status
> > >  recursor dead
> > > forwarder validating (OppDoT)
> > >  dhcp unknown (OppDoT)
> > >*  asr dead
> > > $
> > > $ getent hosts undeadly.org
> > > $ echo $?
> > > 2
> > > $ dig +short undeadly.org @9.9.9.9
> > > 94.142.241.173
> > > $
> > > 
> > > Without your patch unwind behaves similar regarding the type selection:
> > > 
> > > $ doas unwindctl status 
> > > captive portal is unknown
> > 
> > ^ you are creating a not supported configuration.
> > 
> > When we are behind a captive portal or don't know yet if we are behind
> > a captive portal resolving is forced to asr.
> > 
> > That might not be very wise if asr is dead but I currently don't see
> > how this can happen in practice except with a well aimed foot-gun.
> 
> Actually, I have an idea how this can happen in practice, please try this:
> 
> diff --git resolver.c resolver.c
> index f59860a5e98..5bbc63f60fa 100644
> --- resolver.c
> +++ resolver.c
> @@ -1282,7 +1282,8 @@ best_resolver(void)
>  
>   if (captive_portal_state == PORTAL_UNKNOWN || captive_portal_state ==
>   BEHIND) {
> - if (resolvers[UW_RES_ASR] != NULL) {
> + if (resolvers[UW_RES_ASR] != NULL && resolvers[UW_RES_ASR]->
> +state != DEAD) {
>   res = resolvers[UW_RES_ASR];
>   goto out;
>   }
> 
> 

Yes, this makes unwind cope with this situation:

$ unwindctl status 
not behind captive portal

selected type status
 recursor dead
   *forwarder validating
 dhcp dead
  asr dead
$

OK remi@



Re: Opportunistic DoT for unwind(8)

2019-11-01 Thread Florian Obser
On Fri, Nov 01, 2019 at 09:45:37PM +0100, Florian Obser wrote:
> On Fri, Nov 01, 2019 at 09:35:07PM +0100, Remi Locherer wrote:
> > On Thu, Oct 31, 2019 at 08:14:04PM +0100, Otto Moerbeek wrote:
> > > Hi,
> > > 
> > > So here's a new diff that incorporates the bug fix mentioned plus
> > > debug printf line changes suggested by Stuart.
> > > 
> > > Please note that this is a diff on top of very recent current, i.e.
> > > florian's work he committed today. That means that you need to be
> > > up-to-date (including a recent libc update that was committed a few
> > > days ago) to be able to test this version.
> > 
> > I upgraded to a snapshot from today, updated the source and applied
> > your diff. Then I did the same test as last time using pf to block port 53
> > (block return out log inet proto {tcp udp} to !9.9.9.9 port 53).
> > 
> > Result: the non functional type asr is selected instead of the forwarder.
> > 
> > $ doas unwindctl status 
> > captive portal is unknown
> > 
> > selected type status
> >  recursor dead
> > forwarder validating (OppDoT)
> >  dhcp unknown (OppDoT)
> >*  asr dead
> > $
> > $ getent hosts undeadly.org
> > $ echo $?
> > 2
> > $ dig +short undeadly.org @9.9.9.9
> > 94.142.241.173
> > $
> > 
> > Without your patch unwind behaves similar regarding the type selection:
> > 
> > $ doas unwindctl status 
> > captive portal is unknown
> 
> ^ you are creating a not supported configuration.
> 
> When we are behind a captive portal or don't know yet if we are behind
> a captive portal resolving is forced to asr.
> 
> That might not be very wise if asr is dead but I currently don't see
> how this can happen in practice except with a well aimed foot-gun.

Actually, I have an idea how this can happen in practice, please try this:

diff --git resolver.c resolver.c
index f59860a5e98..5bbc63f60fa 100644
--- resolver.c
+++ resolver.c
@@ -1282,7 +1282,8 @@ best_resolver(void)
 
if (captive_portal_state == PORTAL_UNKNOWN || captive_portal_state ==
BEHIND) {
-   if (resolvers[UW_RES_ASR] != NULL) {
+   if (resolvers[UW_RES_ASR] != NULL && resolvers[UW_RES_ASR]->
+state != DEAD) {
res = resolvers[UW_RES_ASR];
goto out;
}


> 
> > 
> > selected type status
> >  recursor dead
> > forwarder validating
> >  dhcp dead
> >*  asr dead
> > $
> > 
> 
> -- 
> I'm not entirely sure you are real.
> 

-- 
I'm not entirely sure you are real.



Re: Opportunistic DoT for unwind(8)

2019-11-01 Thread Florian Obser
On Fri, Nov 01, 2019 at 09:35:07PM +0100, Remi Locherer wrote:
> On Thu, Oct 31, 2019 at 08:14:04PM +0100, Otto Moerbeek wrote:
> > Hi,
> > 
> > So here's a new diff that incorporates the bug fix mentioned plus
> > debug printf line changes suggested by Stuart.
> > 
> > Please note that this is a diff on top of very recent current, i.e.
> > florian's work he committed today. That means that you need to be
> > up-to-date (including a recent libc update that was committed a few
> > days ago) to be able to test this version.
> 
> I upgraded to a snapshot from today, updated the source and applied
> your diff. Then I did the same test as last time using pf to block port 53
> (block return out log inet proto {tcp udp} to !9.9.9.9 port 53).
> 
> Result: the non functional type asr is selected instead of the forwarder.
> 
> $ doas unwindctl status 
> captive portal is unknown
> 
> selected type status
>  recursor dead
> forwarder validating (OppDoT)
>  dhcp unknown (OppDoT)
>*  asr dead
> $
> $ getent hosts undeadly.org
> $ echo $?
> 2
> $ dig +short undeadly.org @9.9.9.9
> 94.142.241.173
> $
> 
> Without your patch unwind behaves similar regarding the type selection:
> 
> $ doas unwindctl status 
> captive portal is unknown

^ you are creating a not supported configuration.

When we are behind a captive portal or don't know yet if we are behind
a captive portal resolving is forced to asr.

That might not be very wise if asr is dead but I currently don't see
how this can happen in practice except with a well aimed foot-gun.

> 
> selected type status
>  recursor dead
> forwarder validating
>  dhcp dead
>*  asr dead
> $
> 

-- 
I'm not entirely sure you are real.



Re: Opportunistic DoT for unwind(8)

2019-11-01 Thread Remi Locherer
On Thu, Oct 31, 2019 at 08:14:04PM +0100, Otto Moerbeek wrote:
> Hi,
> 
> So here's a new diff that incorporates the bug fix mentioned plus
> debug printf line changes suggested by Stuart.
> 
> Please note that this is a diff on top of very recent current, i.e.
> florian's work he committed today. That means that you need to be
> up-to-date (including a recent libc update that was committed a few
> days ago) to be able to test this version.

I upgraded to a snapshot from today, updated the source and applied
your diff. Then I did the same test as last time using pf to block port 53
(block return out log inet proto {tcp udp} to !9.9.9.9 port 53).

Result: the non functional type asr is selected instead of the forwarder.

$ doas unwindctl status 
captive portal is unknown

selected type status
 recursor dead
forwarder validating (OppDoT)
 dhcp unknown (OppDoT)
   *  asr dead
$
$ getent hosts undeadly.org
$ echo $?
2
$ dig +short undeadly.org @9.9.9.9
94.142.241.173
$

Without your patch unwind behaves similar regarding the type selection:

$ doas unwindctl status 
captive portal is unknown

selected type status
 recursor dead
forwarder validating
 dhcp dead
   *  asr dead
$



Re: Opportunistic DoT for unwind(8)

2019-10-31 Thread Otto Moerbeek
Hi,

So here's a new diff that incorporates the bug fix mentioned plus
debug printf line changes suggested by Stuart.

Please note that this is a diff on top of very recent current, i.e.
florian's work he committed today. That means that you need to be
up-to-date (including a recent libc update that was committed a few
days ago) to be able to test this version.

-Otto

Index: sbin/unwind/parse.y
===
RCS file: /cvs/src/sbin/unwind/parse.y,v
retrieving revision 1.12
diff -u -p -r1.12 parse.y
--- sbin/unwind/parse.y 31 Oct 2019 12:51:43 -  1.12
+++ sbin/unwind/parse.y 31 Oct 2019 16:32:27 -
@@ -84,7 +84,6 @@ intcheck_pref_uniq(enum uw_resolver_ty
 
 static struct uw_conf  *conf;
 static int  errors;
-static struct uw_forwarder *uw_forwarder;
 
 voidclear_config(struct uw_conf *xconf);
 struct sockaddr_storage*host_ip(const char *);
@@ -287,7 +286,9 @@ forwarderopts_l : forwarderopts_l forwa
 
 forwarderoptsl : STRING port authname dot {
int ret, port;
+   struct uw_forwarder *uw_fwd;
struct sockaddr_storage *ss;
+
if ((ss = host_ip($1)) == NULL) {
yyerror("%s is not an ip-address", $1);
free($1);
@@ -305,37 +306,53 @@ forwarderoptsl: STRING port authname d
else
port = $2;
 
-   if ((uw_forwarder = calloc(1,
-   sizeof(*uw_forwarder))) == NULL)
+   if ($3 != NULL && $4 == 0) {
+   yyerror("authentication name can only "
+   "be used with DoT");
+   free($1);
+   YYERROR;
+   }
+
+
+   if ((uw_fwd = calloc(1,
+   sizeof(*uw_fwd))) == NULL)
err(1, NULL);
 
-   if ($3 == NULL)
-   ret = snprintf(uw_forwarder->name,
-   sizeof(uw_forwarder->name),
-   "%s@%d", $1, port);
-   else
-   ret = snprintf(uw_forwarder->name,
-   sizeof(uw_forwarder->name),
-   "%s@%d#%s", $1, port, $3);
+   if ($4 == DOT) {
+   if ($3 == NULL)
+   ret = snprintf(uw_fwd->name,
+   sizeof(uw_fwd->name),
+   "%s@%d", $1, port);
+   else
+   ret = snprintf(uw_fwd->name,
+   sizeof(uw_fwd->name),
+   "%s@%d#%s", $1, port, $3);
+   } else {
+   uw_fwd->port = $2;
+   /* complete string wil be done later */
+   ret = snprintf(uw_fwd->name,
+   sizeof(uw_fwd->name), "%s", $1);
+   }
if (ret < 0 || (size_t)ret >=
-   sizeof(uw_forwarder->name)) {
-   free(uw_forwarder);
+   sizeof(uw_fwd->name)) {
+   free(uw_fwd);
yyerror("forwarder %s too long", $1);
free($1);
YYERROR;
}
-   free($1);
 
if ($4 == DOT)
SIMPLEQ_INSERT_TAIL(
&conf->uw_dot_forwarder_list,
-   uw_forwarder, entry);
-   else
+   uw_fwd, entry);
+   else {
SIMPLEQ_INSERT_TAIL(
&conf->uw_forwarder_list,
-   uw_forwarder, entry);
+   uw_fwd, entry);
+

Re: Opportunistic DoT for unwind(8)

2019-10-31 Thread Florian Obser
On Thu, Oct 31, 2019 at 10:04:07AM +, Stuart Henderson wrote:

> Writing as a note to myself to check later when I have more time as
> much as anything, is there a hold-off on re-checking if there is a
> cert failure (or indeed if DoT port isn't answered), or does it
> re-check for every query sent upstream. Also are there excessive
> delays if port 853 packets are dropped rather than rejected.
> 

Checking a resolving strategy is decoupled from using a strategy.

The global variable
struct uw_resolver  *resolvers[UW_RES_NONE];
stores the available resolving strategy contexts.

best_resolvers() picks the best one according to res_state
(VALIDATING > RESOLVING > DEAD) while also consindering the
preference (default or from unwind.conf).

check_resolver / check_resolver_done are running non blocking via
libevent and set res_state in the the resolvers list.
So the checking never blocks resolving.

When a strategy is found to be DEAD we do an exponatial back-off
stopping saturating at ~ 17 minutes (1024 seconds).

(re-)checks are triggered when
- we got a SERVFAIL for a query
- we created a new resolver (config reload, new dhcp forwarders)
- we got past a captive portal
- we got a RTM_IFINFO on the routing socket (interface going up /down)

This is of course the most important part of unwind, resolving stuff
is trivial from unwind's point of view, just hand it of to libunbound.
Finding out to which libunbound is the tough part. There is still room
for improvement.

-- 
I'm not entirely sure you are real.



Re: Opportunistic DoT for unwind(8)

2019-10-31 Thread Stuart Henderson
On 2019/10/31 10:18, Otto Moerbeek wrote:
> On Wed, Oct 30, 2019 at 08:51:00PM +, Stuart Henderson wrote:
> 
> > - unwind doesn't have keepalives, so it's a new TCP session and TLS
> > handshake for every query, which can be bad in some cases (and could get
> > expensive with metered mobile data connections). for this reason it
> > would be helpful to have a way to disable it (though I suppose "block
> > out proto tcp to port 853" works at a pinch).
> 
> unwind should cache thogh, can you observe that?

Yes, it does cache. (for "every query" I meant "every query sent to
the forwarder")

> > - several of the public DNS providers do include their IP in the certificate
> > so they could be validated even when picking them up opportunistically.
> > though I suppose with unwind this doesn't make a lot of difference as
> > it's just going to fallback to cleartext if TLS fails.
> 
> For any Dot mode the validity of the cert is checked, for OppDot the
> trust check is only: is the cert signed by a trusted CA. We do not
> know which DoT providers include a cert with an IP address, so we
> cannot force a check for that. Besides that, I could not get
> libunbound to accept a authentication IP like 9.9.9.9, only a name
> like "quad9.net".

Writing as a note to myself to check later when I have more time as
much as anything, is there a hold-off on re-checking if there is a
cert failure (or indeed if DoT port isn't answered), or does it
re-check for every query sent upstream. Also are there excessive
delays if port 853 packets are dropped rather than rejected.



Re: Opportunistic DoT for unwind(8)

2019-10-31 Thread Otto Moerbeek
On Wed, Oct 30, 2019 at 08:51:00PM +, Stuart Henderson wrote:

> On 2019/10/30 15:57, Otto Moerbeek wrote:
> > Hi,
> > 
> > I got *very* little feedback on this request for testing.
> > 
> > If not enough enough testing is done, I'll either abandon the diff or
> > commit it as-is, introducing bugs that could have been prevented. Both
> > are not good. So get going!
> > 
> > -Otto
> > 
> 
> I'm pointing it at a local dnsdist box via "forwarders { $ip_address }"
> and querying unwind while watching tcpdump, I see it correctly using
> TCP/853, and status correctly says
> 
> $ unwindctl status
> captive portal is unchecked
> 
> selected type status
>*forwarder validating (OppDoT)
>  recursor validating
> 
> 
> 

Thanks for testing.

> Comments:
> 
> - unwind doesn't have keepalives, so it's a new TCP session and TLS
> handshake for every query, which can be bad in some cases (and could get
> expensive with metered mobile data connections). for this reason it
> would be helpful to have a way to disable it (though I suppose "block
> out proto tcp to port 853" works at a pinch).

unwind should cache thogh, can you observe that?

> 
> - several of the public DNS providers do include their IP in the certificate
> so they could be validated even when picking them up opportunistically.
> though I suppose with unwind this doesn't make a lot of difference as
> it's just going to fallback to cleartext if TLS fails.

For any Dot mode the validity of the cert is checked, for OppDot the
trust check is only: is the cert signed by a trusted CA. We do not
know which DoT providers include a cert with an IP address, so we
cannot force a check for that. Besides that, I could not get
libunbound to accept a authentication IP like 9.9.9.9, only a name
like "quad9.net".

> 
> - might be useful to show OppDoT in the "best_resolver" line in debug logs?
> 
> 
> 
> Sample config from the dnsdist server below for anyone interested, this
> is for 1.40rc5 but I think it'll work with the current ports version
> (1.3.3) if you remove the addDOHLocal line.
> 
> --snip-
> addACL('0.0.0.0/0')
> addACL('::/0')
> newServer({address="44.33.22.11", name="upstream"})
> addLocal('11.22.33.44:53',{doTCP=true, reusePort=true})
> addTLSLocal("11.22.33.44", "/etc/ssl/xx.fullchain.pem", 
> "/etc/ssl/private/xx.key",{ doTCP=true, reusePort=true })
> addDOHLocal("11.22.33.44:5343", "/etc/ssl/xx.fullchain.pem", 
> "/etc/ssl/private/xx.key", "/", {doTCP=true, reusePort=true})
> pc = newPacketCache(1, {maxTTL=86400, minTTL=0, temporaryFailureTTL=60, 
> staleTTL=60, dontAge=false})
> getPool(""):setCache(pc)
> --snip--
> 

Yes , that should work indeed.

-Otto





Re: Opportunistic DoT for unwind(8)

2019-10-31 Thread Otto Moerbeek
On Wed, Oct 30, 2019 at 11:46:36PM +0100, Remi Locherer wrote:

> Hi Otto,
> 
> On Wed, Oct 30, 2019 at 03:57:15PM +0100, Otto Moerbeek wrote:
> > Hi,
> > 
> > I got *very* little feedback on this request for testing.
> > 
> > If not enough enough testing is done, I'll either abandon the diff or
> > commit it as-is, introducing bugs that could have been prevented. Both
> > are not good. So get going!
> > 
> > -Otto
> > 
> 
> I applied your diff and tried with the following config:
> 
> $ unwind -nv
> preference { recursor DoT forwarder dhcp }
> forwarder {
> 9.9.9.9
> }
> captive portal {
> url "http://captive.apple.com/";
> expected status 200
> expected response 
> "SuccessSuccess"
> auto yes
> }
> block list "/etc/unwind_blocklist.txt"
> $
> 
> To force unwind to use 9.9.9.9 I tested with this pf rules:
> 
> $ doas pfctl -sr 
> doas (r...@typhoon.relo.ch) password: 
> block return log all
> pass log all flags S/SA
> pass out log on egress inet from (vether0:network) to any flags S/SA nat-to 
> (egress:0) round-robin
> block return in on ! lo0 proto tcp from any to any port 6000:6010
> block return out log inet proto tcp from any to ! 9.9.9.9 port = 53
> block return out log inet proto udp from any to ! 9.9.9.9 port = 53
> block return out log inet6 proto tcp from any to any port = 53
> block return out log inet6 proto udp from any to any port = 53
> block return out log proto tcp all user = 55
> block return out log proto udp all user = 55
> $
> 
> As expected I can now query 9.9.9.9 but 8.8.8.8 fails:
> 
> $ dig +short undeadly.org @9.9.9.9
> 94.142.241.173
> typhoon ..c/examples$ dig +short undeadly.org @8.8.8.8 
> ;; connection timed out; no servers could be reached
> $
> 
> I expected that unwind would choose 9.9.9.9 with OppDoT. But unwind
> selects dhcp which is correctly displayed as dead:
> 
> $ unwindctl status 
> captive portal is unknown
> 
> selected type status
>  recursor dead
> forwarder validating
>* dhcp dead
> $
> 
> Port 853 on 9.9.9.9 is not blocked:
> 
> $ nc -zv 9.9.9.9 853
> Connection to 9.9.9.9 853 port [tcp/domain-s] succeeded!
> $ nc -zv -u 9.9.9.9 853
> Connection to 9.9.9.9 853 port [udp/domain-s] succeeded!
> $
> 
> Did I do something wrong in unwind.conf?
> 
> Remi

No, you found a bug that happens if the recursor is found dead. In
that case it would switch off OppDot for forwarders as well. Next
version of the diff will have a fix.


As for the unwindctl thing, I could not reproduce that one. Dould it
be that you did not build and install usr.sbin/unwindctl? It looks
like the messaging between unwind and unwindctl is off.

-Otto



Re: Opportunistic DoT for unwind(8)

2019-10-30 Thread Remi Locherer
Hi Otto,

On Wed, Oct 30, 2019 at 03:57:15PM +0100, Otto Moerbeek wrote:
> Hi,
> 
> I got *very* little feedback on this request for testing.
> 
> If not enough enough testing is done, I'll either abandon the diff or
> commit it as-is, introducing bugs that could have been prevented. Both
> are not good. So get going!
> 
>   -Otto
> 

I applied your diff and tried with the following config:

$ unwind -nv
preference { recursor DoT forwarder dhcp }
forwarder {
9.9.9.9
}
captive portal {
url "http://captive.apple.com/";
expected status 200
expected response 
"SuccessSuccess"
auto yes
}
block list "/etc/unwind_blocklist.txt"
$

To force unwind to use 9.9.9.9 I tested with this pf rules:

$ doas pfctl -sr 
doas (r...@typhoon.relo.ch) password: 
block return log all
pass log all flags S/SA
pass out log on egress inet from (vether0:network) to any flags S/SA nat-to 
(egress:0) round-robin
block return in on ! lo0 proto tcp from any to any port 6000:6010
block return out log inet proto tcp from any to ! 9.9.9.9 port = 53
block return out log inet proto udp from any to ! 9.9.9.9 port = 53
block return out log inet6 proto tcp from any to any port = 53
block return out log inet6 proto udp from any to any port = 53
block return out log proto tcp all user = 55
block return out log proto udp all user = 55
$

As expected I can now query 9.9.9.9 but 8.8.8.8 fails:

$ dig +short undeadly.org @9.9.9.9
94.142.241.173
typhoon ..c/examples$ dig +short undeadly.org @8.8.8.8 
;; connection timed out; no servers could be reached
$

I expected that unwind would choose 9.9.9.9 with OppDoT. But unwind
selects dhcp which is correctly displayed as dead:

$ unwindctl status 
captive portal is unknown

selected type status
 recursor dead
forwarder validating
   * dhcp dead
$

Port 853 on 9.9.9.9 is not blocked:

$ nc -zv 9.9.9.9 853
Connection to 9.9.9.9 853 port [tcp/domain-s] succeeded!
$ nc -zv -u 9.9.9.9 853
Connection to 9.9.9.9 853 port [udp/domain-s] succeeded!
$

Did I do something wrong in unwind.conf?

Remi



Re: Opportunistic DoT for unwind(8)

2019-10-30 Thread Stuart Henderson
On 2019/10/30 15:57, Otto Moerbeek wrote:
> Hi,
> 
> I got *very* little feedback on this request for testing.
> 
> If not enough enough testing is done, I'll either abandon the diff or
> commit it as-is, introducing bugs that could have been prevented. Both
> are not good. So get going!
> 
>   -Otto
> 

I'm pointing it at a local dnsdist box via "forwarders { $ip_address }"
and querying unwind while watching tcpdump, I see it correctly using
TCP/853, and status correctly says

$ unwindctl status
captive portal is unchecked

selected type status
   *forwarder validating (OppDoT)
 recursor validating



Comments:

- unwind doesn't have keepalives, so it's a new TCP session and TLS
handshake for every query, which can be bad in some cases (and could get
expensive with metered mobile data connections). for this reason it
would be helpful to have a way to disable it (though I suppose "block
out proto tcp to port 853" works at a pinch).

- several of the public DNS providers do include their IP in the certificate
so they could be validated even when picking them up opportunistically.
though I suppose with unwind this doesn't make a lot of difference as
it's just going to fallback to cleartext if TLS fails.

- might be useful to show OppDoT in the "best_resolver" line in debug logs?



Sample config from the dnsdist server below for anyone interested, this
is for 1.40rc5 but I think it'll work with the current ports version
(1.3.3) if you remove the addDOHLocal line.

--snip-
addACL('0.0.0.0/0')
addACL('::/0')
newServer({address="44.33.22.11", name="upstream"})
addLocal('11.22.33.44:53',{doTCP=true, reusePort=true})
addTLSLocal("11.22.33.44", "/etc/ssl/xx.fullchain.pem", 
"/etc/ssl/private/xx.key",{ doTCP=true, reusePort=true })
addDOHLocal("11.22.33.44:5343", "/etc/ssl/xx.fullchain.pem", 
"/etc/ssl/private/xx.key", "/", {doTCP=true, reusePort=true})
pc = newPacketCache(1, {maxTTL=86400, minTTL=0, temporaryFailureTTL=60, 
staleTTL=60, dontAge=false})
getPool(""):setCache(pc)
--snip--



Re: Opportunistic DoT for unwind(8)

2019-10-30 Thread Matthias Schmidt
Hi Otto,

* Otto Moerbeek wrote:
> Hi,
> 
> I got *very* little feedback on this request for testing.
> 
> If not enough enough testing is done, I'll either abandon the diff or
> commit it as-is, introducing bugs that could have been prevented. Both
> are not good. So get going!

I have your diff running for a couple of days and I can at least confirm
that it doesn't break an existing setup.  I have several upstream DoT
servers configured but no opportunistic DoT setup.

HTH and cheers

Matthias



Re: Opportunistic DoT for unwind(8)

2019-10-30 Thread Otto Moerbeek
Hi,

I got *very* little feedback on this request for testing.

If not enough enough testing is done, I'll either abandon the diff or
commit it as-is, introducing bugs that could have been prevented. Both
are not good. So get going!

-Otto



Re: Opportunistic DoT for unwind(8)

2019-10-24 Thread Stuart Henderson
On 2019/10/24 11:48, Paul de Weerd wrote:
> The downside of using your own resolver (e.g. by running unbound on
> your laptop), its traffic is more easily tied to a specific user.
> There's an anonymizing power in using a bigger (shared) resolver (with
> the downside that you then give your queries to a resolver that's
> probably outside of your control - different risks and all that)

And the downside of using a shared non-ISP resolver is that CDNs or
services using geolocation on the DNS requests won't have information about
your network location, so you may end up served by a suboptimal server or
CDN node (in the worst case you may end up with a very unsuitable one,
for example perhaps from a country halfway around the world).

The notable exception here of course is where the CDN also runs their own
public DNS resolver (hi Cloudflare!).



Re: Opportunistic DoT for unwind(8)

2019-10-24 Thread Otto Moerbeek
On Thu, Oct 24, 2019 at 12:24:22PM +0200, Otto Moerbeek wrote:

> On Thu, Oct 24, 2019 at 11:27:24AM +0100, Kevin Chadwick wrote:
> 
> > 
> > > The purpose of unwind is to provide secure DNS services even when
> > > the available nameservers are broken or filtered like in many hotels.
> > > To do that, it prefers DNSSEC whenever possible and changes to do
> > > resolving by itself if needed.
> > > 
> > > DNSSEC only offers integrity and authenticity.  To protect
> > > eavesdropping on the requests in transit, encryption is needed, as
> > > offered by e.g. DNS over TLS (DoT) and DNS over HTTP (DoT). unwind
> > 
> > Before I jump aboard with DNSSECs failings in mind on my own networks rather
> > than the mentioned hotel scenario. I believe but I am still not certain that
> > services like PowerDNS have secure channels to the main primary DNS servers 
> > that
> > apparently do not scale for the rest of us? Otherwise I worry that the 
> > network
> > security target is a more singular centralised target compared to e.g. 
> > unbound.
> > 
> 
> Guess what the default config of unwind does: it runs a local resolver
> and learns from DHCP. It will select either one, with DNSSEC working
> preferred. DNSSEC operations if sometimes blocked by crappy
> middleware. Unwind's resolver is basically a buit-in simple unbound,
> the code uses libunbound. 
> 
> So the default config of unwind addresss both your concerns.
> 
>   -Otto
> 

To elaborate: unwind checks if DNSSEC works on any source and switches
back to non-validation if needed. The whole point of unwind is that it
will try to provide the best DNS service possibe in any circumstance. 

-Otto



Re: Opportunistic DoT for unwind(8)

2019-10-24 Thread Otto Moerbeek
On Thu, Oct 24, 2019 at 11:27:24AM +0100, Kevin Chadwick wrote:

> 
> > The purpose of unwind is to provide secure DNS services even when
> > the available nameservers are broken or filtered like in many hotels.
> > To do that, it prefers DNSSEC whenever possible and changes to do
> > resolving by itself if needed.
> > 
> > DNSSEC only offers integrity and authenticity.  To protect
> > eavesdropping on the requests in transit, encryption is needed, as
> > offered by e.g. DNS over TLS (DoT) and DNS over HTTP (DoT). unwind
> 
> Before I jump aboard with DNSSECs failings in mind on my own networks rather
> than the mentioned hotel scenario. I believe but I am still not certain that
> services like PowerDNS have secure channels to the main primary DNS servers 
> that
> apparently do not scale for the rest of us? Otherwise I worry that the network
> security target is a more singular centralised target compared to e.g. 
> unbound.
> 

Guess what the default config of unwind does: it runs a local resolver
and learns from DHCP. It will select either one, with DNSSEC working
preferred. DNSSEC operations if sometimes blocked by crappy
middleware. Unwind's resolver is basically a buit-in simple unbound,
the code uses libunbound. 

So the default config of unwind addresss both your concerns.

-Otto



Re: Opportunistic DoT for unwind(8)

2019-10-24 Thread Paul de Weerd
On Thu, Oct 24, 2019 at 11:27:24AM +0100, Kevin Chadwick wrote:
| 
| > The purpose of unwind is to provide secure DNS services even when
| > the available nameservers are broken or filtered like in many hotels.
| > To do that, it prefers DNSSEC whenever possible and changes to do
| > resolving by itself if needed.
| > 
| > DNSSEC only offers integrity and authenticity.  To protect
| > eavesdropping on the requests in transit, encryption is needed, as
| > offered by e.g. DNS over TLS (DoT) and DNS over HTTP (DoT). unwind
| 
| Before I jump aboard with DNSSECs failings in mind on my own networks rather
| than the mentioned hotel scenario. I believe but I am still not certain that
| services like PowerDNS have secure channels to the main primary DNS servers 
that
| apparently do not scale for the rest of us? Otherwise I worry that the network
| security target is a more singular centralised target compared to e.g. 
unbound.

These solutions (DoT / DoH, or the older DNSCrypt) encrypt DNS queries
from client to resolver, authorities are not available through these
protocols (yet).

This topic of DNS has lots of different attack vectors and risks
associated with it.  Slowly but surely, things are improving .. but
there's no big-bang solution that gets rid of all the issues in one
go.

If you want to use encrypted DNS from your client to your own resolver
then you can also do that.  Unbound is in base, look at the
tls-service-* and tls-port: options in unbound.conf(5).

The downside of using your own resolver (e.g. by running unbound on
your laptop), its traffic is more easily tied to a specific user.
There's an anonymizing power in using a bigger (shared) resolver (with
the downside that you then give your queries to a resolver that's
probably outside of your control - different risks and all that)

If you don't want to trust the freely available PowerDNS recursor then
that's your prerogative; it's just an easy option that's available
should you wish to test Otto's diff.

Cheers,

Paul 'WEiRD' de Weerd

-- 
>[<++>-]<+++.>+++[<-->-]<.>+++[<+
+++>-]<.>++[<>-]<+.--.[-]
 http://www.weirdnet.nl/ 



Re: Opportunistic DoT for unwind(8)

2019-10-24 Thread Kevin Chadwick


> The purpose of unwind is to provide secure DNS services even when
> the available nameservers are broken or filtered like in many hotels.
> To do that, it prefers DNSSEC whenever possible and changes to do
> resolving by itself if needed.
> 
> DNSSEC only offers integrity and authenticity.  To protect
> eavesdropping on the requests in transit, encryption is needed, as
> offered by e.g. DNS over TLS (DoT) and DNS over HTTP (DoT). unwind

Before I jump aboard with DNSSECs failings in mind on my own networks rather
than the mentioned hotel scenario. I believe but I am still not certain that
services like PowerDNS have secure channels to the main primary DNS servers that
apparently do not scale for the rest of us? Otherwise I worry that the network
security target is a more singular centralised target compared to e.g. unbound.



Re: Opportunistic DoT for unwind(8)

2019-10-23 Thread Otto Moerbeek
On Wed, Oct 23, 2019 at 02:40:53PM +0200, Otto Moerbeek wrote:

> Hi,
> 
> The patch below add opportunistic DoT to unwind.  Some background
> info:
> 
> The purpose of unwind is to provide secure DNS services even when
> the available nameservers are broken or filtered like in many hotels.
> To do that, it prefers DNSSEC whenever possible and changes to do
> resolving by itself if needed.
> 
> DNSSEC only offers integrity and authenticity.  To protect
> eavesdropping on the requests in transit, encryption is needed, as
> offered by e.g. DNS over TLS (DoT) and DNS over HTTP (DoT). unwind

That second DoT should be DoH.

> already supports DoT for forwarders but only when explicitly
> configured to do so.
> 
> This diff makes unwind try DoT for forwarders and nameservers learned
> via DHCP and fall back to plaintext if it does not work.
> 
> Which DoT servers to use for testing? Most quad-whatever open DNS
> resolvers like 9.9.9.9 support DoT so you can specify them as a
> forwarder.  But please note the privacy policies and realize they see
> all your DNS queries.  You might consider reading [1] which offers DoT
> on 136.144.215.158 as well and has a good privacy policy and is in

Not that the mentioned privacy page talsk about DoH and does not
mention DoT, but the IP does offer DoT.

[1] https://powerdns.org/doh/privacy.html

-Otto




Re: Opportunistic DoT for unwind(8)

2019-10-23 Thread Otto Moerbeek
On Wed, Oct 23, 2019 at 02:40:53PM +0200, Otto Moerbeek wrote:

> [1] https://doh.powerdns.org/doh/privacy.html

Should be https://powerdns.org/doh/privacy.html



Opportunistic DoT for unwind(8)

2019-10-23 Thread Otto Moerbeek
Hi,

The patch below add opportunistic DoT to unwind.  Some background
info:

The purpose of unwind is to provide secure DNS services even when
the available nameservers are broken or filtered like in many hotels.
To do that, it prefers DNSSEC whenever possible and changes to do
resolving by itself if needed.

DNSSEC only offers integrity and authenticity.  To protect
eavesdropping on the requests in transit, encryption is needed, as
offered by e.g. DNS over TLS (DoT) and DNS over HTTP (DoT). unwind
already supports DoT for forwarders but only when explicitly
configured to do so.

This diff makes unwind try DoT for forwarders and nameservers learned
via DHCP and fall back to plaintext if it does not work.

Which DoT servers to use for testing? Most quad-whatever open DNS
resolvers like 9.9.9.9 support DoT so you can specify them as a
forwarder.  But please note the privacy policies and realize they see
all your DNS queries.  You might consider reading [1] which offers DoT
on 136.144.215.158 as well and has a good privacy policy and is in
Dutch jurisdiction.  If you do want to run DoT yourself there's
dnsdist in ports.  Some ISPs offer DoT as well.

How to test?


Apply the diff in /usr/src and rebuild sbin/unwind and usr.sbin/unwindctl.

- read the unwind(8) man page about changing dhclient.conf if you use
  DHCP (this is not related to this diff but important anyway).
- make sure that if you have an existing working setup it does not
  break with this diff.
- check if DoT is used when appriopiate by using the unwindctl command.

Even if you do not want to run DoT at least make sure existing stuff
does not break.  I might need to add a config option to tune the
always on behaviour of opportunistic DoT, but only want to do that if
I have evidence it is needed.

Happy testing!

-Otto

[1] https://doh.powerdns.org/doh/privacy.html


Index: sbin/unwind/parse.y
===
RCS file: /cvs/src/sbin/unwind/parse.y,v
retrieving revision 1.11
diff -u -p -r1.11 parse.y
--- sbin/unwind/parse.y 21 Oct 2019 07:16:09 -  1.11
+++ sbin/unwind/parse.y 23 Oct 2019 12:28:42 -
@@ -84,7 +84,6 @@ intcheck_pref_uniq(enum uw_resolver_ty
 
 static struct uw_conf  *conf;
 static int  errors;
-static struct uw_forwarder *uw_forwarder;
 
 voidclear_config(struct uw_conf *xconf);
 struct sockaddr_storage*host_ip(const char *);
@@ -286,7 +285,9 @@ forwarderopts_l : forwarderopts_l forwa
 
 forwarderoptsl : STRING port authname dot {
int ret, port;
+   struct uw_forwarder *uw_fwd;
struct sockaddr_storage *ss;
+
if ((ss = host_ip($1)) == NULL) {
yyerror("%s is not an ip-address", $1);
free($1);
@@ -304,37 +305,53 @@ forwarderoptsl: STRING port authname d
else
port = $2;
 
-   if ((uw_forwarder = calloc(1,
-   sizeof(*uw_forwarder))) == NULL)
+   if ($3 != NULL && $4 == 0) {
+   yyerror("authentication name can only "
+   "be used with DoT");
+   free($1);
+   YYERROR;
+   }
+
+
+   if ((uw_fwd = calloc(1,
+   sizeof(*uw_fwd))) == NULL)
err(1, NULL);
 
-   if ($3 == NULL)
-   ret = snprintf(uw_forwarder->name,
-   sizeof(uw_forwarder->name),
-   "%s@%d", $1, port);
-   else
-   ret = snprintf(uw_forwarder->name,
-   sizeof(uw_forwarder->name),
-   "%s@%d#%s", $1, port, $3);
+   if ($4 == DOT) {
+   if ($3 == NULL)
+   ret = snprintf(uw_fwd->name,
+   sizeof(uw_fwd->name),
+   "%s@%d", $1, port);
+   else
+   ret = snprintf(uw_fwd->name,
+   sizeof(uw_fwd->name),
+   "%s@%d#%s", $1, port, $3);
+   } else {
+   uw_f