Re: asr: support for RES_USE_DNSSEC

2017-02-27 Thread Peter J. Philipp
On Mon, Feb 27, 2017 at 11:14:13AM +0100, Jeremie Courreges-Anglas wrote:
> "Peter J. Philipp"  writes:
> 
> > On Mon, Feb 27, 2017 at 10:26:48AM +0100, Peter J. Philipp wrote:
> >> I had a patch somewhere for TSIG as well somewhere, give me some time to
> >> find it.  TSIG can secure the channel as well, but my implementation wasn't
> >> all that pretty.
> >
> > Here is the patch, it would need fixing up, and it only would work with BIND
> > nameservers currently :-(.
> >
> > http://marc.info/?l=openbsd-tech=145656997013119=2
> 
> Interesting.  I can't speak for others but I don't think that TSIG is
> a good solution.  Shared secrets don't buy us much, especially if we
> have to store them in /etc/resolv.conf.
> 
> -- 
> jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF  DDCC 0DFA 74AE 1524 E7EE

You're right.  If I may point you to RFC 4033 section 7 (not a long read) it
talks about securing this channel for stub resolvers.  It actually talks about
SIG(0) or TSIG (like my example, which isn't the best use).  And it talks about
IPSEC to secure the channel (another good way) but who can say that they have
an IPSEC tunnel to their nameserver especially when it's the ISP's?  Really
all that we're left with (if we want security) is a local recursive nameserver.

I think making the stub resolver security aware and validating would be a good
thing but it's not a 1 person effort unless you can invest 2-3 years into it
and work for a living on the side.  I'm open to help (still) and I know I'm
talking to the right people here, yet a group should form and a mandate be set
in place for this to work best.

Cheers,
-peter



Re: asr: support for RES_USE_DNSSEC

2017-02-27 Thread Jeremie Courreges-Anglas
"Peter J. Philipp"  writes:

> On Mon, Feb 27, 2017 at 10:26:48AM +0100, Peter J. Philipp wrote:
>> I had a patch somewhere for TSIG as well somewhere, give me some time to
>> find it.  TSIG can secure the channel as well, but my implementation wasn't
>> all that pretty.
>
> Here is the patch, it would need fixing up, and it only would work with BIND
> nameservers currently :-(.
>
> http://marc.info/?l=openbsd-tech=145656997013119=2

Interesting.  I can't speak for others but I don't think that TSIG is
a good solution.  Shared secrets don't buy us much, especially if we
have to store them in /etc/resolv.conf.

-- 
jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF  DDCC 0DFA 74AE 1524 E7EE



Re: asr: support for RES_USE_DNSSEC

2017-02-27 Thread Peter J. Philipp
On Mon, Feb 27, 2017 at 10:26:48AM +0100, Peter J. Philipp wrote:
> I had a patch somewhere for TSIG as well somewhere, give me some time to
> find it.  TSIG can secure the channel as well, but my implementation wasn't
> all that pretty.

Here is the patch, it would need fixing up, and it only would work with BIND
nameservers currently :-(.

http://marc.info/?l=openbsd-tech=145656997013119=2

Regards,

-peter



Re: asr: support for RES_USE_DNSSEC

2017-02-27 Thread Peter J. Philipp
On Mon, Feb 27, 2017 at 10:19:52AM +0100, Jeremie Courreges-Anglas wrote:
> > Thanks for considering my patch.  OpenBSD tremendously improves with this 
> > work of yours, I'm all for it!  However to make use of this DNSSEC mode, 
> > the channel to the recursive DNS server has to be absolutely secure (for DO 
> > or AD in a response).  
> 
> Yes, the assumption is that the resolver listed in /etc/resolv.conf is
> trusted, including the network in between.
> 
> The easiest method is to run unbound on 127.0.0.1 with
> "auto-trust-anchor-file".

I had a patch somewhere for TSIG as well somewhere, give me some time to
find it.  TSIG can secure the channel as well, but my implementation wasn't
all that pretty.

> > My looming question that noone wants to ask because it's a bit (a lot)
> > of work for the programmer(s) is: can we work toward the goal of a 
> > validating
> > dnssec resolver?
> 
> Please clarify: do you mean "stub resolver" here, ie the code that runs
> in libc?

Yes, that is what I mean.  That way the recursive dns server doesn't have to
be on the same box and answers are validated locally.

Regards,
-peter



Re: asr: support for RES_USE_DNSSEC

2017-02-27 Thread Jeremie Courreges-Anglas
"Peter J. Philipp"  writes:

> On Mon, Feb 27, 2017 at 12:35:33AM +0100, Jeremie Courreges-Anglas wrote:
>> Setting the AD flag for a query is possible, however those semantics are
>> newer than the EDNS0 extension.  As far as I know, rfc6840 introduced
>> AD=1 for queries in 2013, whereas rfc3225 specifies the DO flag since
>> 2001.
>> 
>>   https://tools.ietf.org/html/rfc3225
>>   https://tools.ietf.org/html/rfc6840#section-5.7
>> 
>> Also EDNS0 can give you more than 512 bytes on UDP (if the resolver
>> supports it).  So I thought I'd rather implement RES_USE_DNSSEC on top
>> of EDNS0.
>> 
>> -- 
>> jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF  DDCC 0DFA 74AE 1524 E7EE
>
> Jeremie & tech@,
>
> Thanks for considering my patch.  OpenBSD tremendously improves with this 
> work of yours, I'm all for it!  However to make use of this DNSSEC mode, 
> the channel to the recursive DNS server has to be absolutely secure (for DO 
> or AD in a response).  

Yes, the assumption is that the resolver listed in /etc/resolv.conf is
trusted, including the network in between.

The easiest method is to run unbound on 127.0.0.1 with
"auto-trust-anchor-file".

> My looming question that noone wants to ask because it's a bit (a lot)
> of work for the programmer(s) is: can we work toward the goal of a validating
> dnssec resolver?

Please clarify: do you mean "stub resolver" here, ie the code that runs
in libc?

-- 
jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF  DDCC 0DFA 74AE 1524 E7EE



Re: asr: support for RES_USE_DNSSEC

2017-02-27 Thread Peter J. Philipp
On Mon, Feb 27, 2017 at 12:35:33AM +0100, Jeremie Courreges-Anglas wrote:
> Setting the AD flag for a query is possible, however those semantics are
> newer than the EDNS0 extension.  As far as I know, rfc6840 introduced
> AD=1 for queries in 2013, whereas rfc3225 specifies the DO flag since
> 2001.
> 
>   https://tools.ietf.org/html/rfc3225
>   https://tools.ietf.org/html/rfc6840#section-5.7
> 
> Also EDNS0 can give you more than 512 bytes on UDP (if the resolver
> supports it).  So I thought I'd rather implement RES_USE_DNSSEC on top
> of EDNS0.
> 
> -- 
> jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF  DDCC 0DFA 74AE 1524 E7EE

Jeremie & tech@,

Thanks for considering my patch.  OpenBSD tremendously improves with this 
work of yours, I'm all for it!  However to make use of this DNSSEC mode, 
the channel to the recursive DNS server has to be absolutely secure (for DO 
or AD in a response).  

My looming question that noone wants to ask because it's a bit (a lot)
of work for the programmer(s) is: can we work toward the goal of a validating
dnssec resolver?  (I know it's a lot of work, we'd need a group and an 
architect perhaps, ultimately the RFC's are the guideline)  Luckily I'm
between projects outside of my main job and I think I can contribute a little.

Is any (DNS) security programmers interested in this?  I can come to Paris
for EuroBSDCon to get together for this matter, but I'd want to get started
earlier if we form a small group for that matter.

Regards,
-peter



Re: asr: support for RES_USE_DNSSEC

2017-02-27 Thread Gilles Chehade
On Mon, Feb 27, 2017 at 08:46:40AM +0100, Jeremie Courreges-Anglas wrote:
> Jeremie Courreges-Anglas  writes:
> 
> > This flag is useful for software that wants to rely on the resolver to
> > perform DNSSEC validation.  Among the use cases there are DANE and SSHFP
> > records, and the obvious interfaces that I think are useful are
> > res_mkquery and getrrsetbyname.  The latter still doesn't support
> > DNSSEC, another diff will follow.
> >
> > The first hunk is not supposed to be committed, it is only here for
> > basic testing (add "options dnssec" to resolv.conf).  Other testing
> > could involve postfix or exim.
> >
> > Since RES_USE_DNSSEC now actually adds an EDNS0 OPT record to the
> > outgoing packet, one can be concerned with problems with resolvers out
> > there.  Windows seems to have a way to disable EDNS0, I am not aware of
> > existing mechanisms elsewhere.
> >
> > Thoughts?  ok?
> 
> Reviewing the dnssec patch from Peter J. Philipp, I noticed that this
> first diff lacks hunks to amend the response flags check.  Initially
> I had - lazily - only removed the Z_MASK test.
> 
> Updated diff, that includes bits for asr_debug.c.  First hunk still here
> for basic testing.  Packets with the AD or CD flags are no longer
> discarded, given the new Z_MASK #define. (I don't see a reason to
> discard packets with the CD bit set, we should probably just ignore
> it.  I've kept things as is for the must-be-zero part.)
> 

ok gilles@

> Index: asr/asr.c
> ===
> RCS file: /d/cvs/src/lib/libc/asr/asr.c,v
> retrieving revision 1.56
> diff -u -p -r1.56 asr.c
> --- asr/asr.c 23 Feb 2017 17:04:02 -  1.56
> +++ asr/asr.c 27 Feb 2017 07:25:11 -
> @@ -597,6 +597,8 @@ pass0(char **tok, int n, struct asr_ctx 
>   ac->ac_options |= RES_USEVC;
>   else if (!strcmp(tok[i], "edns0"))
>   ac->ac_options |= RES_USE_EDNS0;
> + else if (!strcmp(tok[i], "dnssec"))
> + ac->ac_options |= RES_USE_DNSSEC;
>   else if ((!strncmp(tok[i], "ndots:", 6))) {
>   e = NULL;
>   d = strtonum(tok[i] + 6, 1, 16, );
> Index: asr/asr_debug.c
> ===
> RCS file: /d/cvs/src/lib/libc/asr/asr_debug.c,v
> retrieving revision 1.23
> diff -u -p -r1.23 asr_debug.c
> --- asr/asr_debug.c   17 Feb 2017 22:24:45 -  1.23
> +++ asr/asr_debug.c   27 Feb 2017 07:25:11 -
> @@ -37,7 +37,6 @@ static const char *print_rr(const struct
>  FILE *_asr_debug = NULL;
>  
>  #define OPCODE_SHIFT 11
> -#define Z_SHIFT   4
>  
>  static const char *
>  rcodetostr(uint16_t v)
> @@ -147,7 +146,7 @@ static const char *
>  print_header(const struct asr_dns_header *h, char *buf, size_t max)
>  {
>   snprintf(buf, max,
> - "id:0x%04x %s op:%i %s %s %s %s z:%i r:%s qd:%i an:%i ns:%i ar:%i",
> + "id:0x%04x %s op:%i %s %s %s %s z:%i %s %s r:%s qd:%i an:%i ns:%i 
> ar:%i",
>   ((int)h->id),
>   (h->flags & QR_MASK) ? "QR":"  ",
>   (int)(OPCODE(h->flags) >> OPCODE_SHIFT),
> @@ -155,7 +154,9 @@ print_header(const struct asr_dns_header
>   (h->flags & TC_MASK) ? "TC":"  ",
>   (h->flags & RD_MASK) ? "RD":"  ",
>   (h->flags & RA_MASK) ? "RA":"  ",
> - ((h->flags & Z_MASK) >> Z_SHIFT),
> + (h->flags & Z_MASK),
> + (h->flags & AD_MASK) ? "AD":"  ",
> + (h->flags & CD_MASK) ? "CD":"  ",
>   rcodetostr(RCODE(h->flags)),
>   h->qdcount, h->ancount, h->nscount, h->arcount);
>  
> Index: asr/asr_private.h
> ===
> RCS file: /d/cvs/src/lib/libc/asr/asr_private.h,v
> retrieving revision 1.43
> diff -u -p -r1.43 asr_private.h
> --- asr/asr_private.h 23 Feb 2017 17:04:02 -  1.43
> +++ asr/asr_private.h 27 Feb 2017 07:25:11 -
> @@ -23,7 +23,9 @@
>  #define TC_MASK  (0x1 <<  9)
>  #define RD_MASK  (0x1 <<  8)
>  #define RA_MASK  (0x1 <<  7)
> -#define Z_MASK   (0x7 <<  4)
> +#define Z_MASK   (0x1 <<  6)
> +#define AD_MASK  (0x1 <<  5)
> +#define CD_MASK  (0x1 <<  4)
>  #define RCODE_MASK   (0xf)
>  
>  #define OPCODE(v)((v) & OPCODE_MASK)
> @@ -297,7 +299,7 @@ __BEGIN_HIDDEN_DECLS
>  void _asr_pack_init(struct asr_pack *, char *, size_t);
>  int _asr_pack_header(struct asr_pack *, const struct asr_dns_header *);
>  int _asr_pack_query(struct asr_pack *, uint16_t, uint16_t, const char *);
> -int _asr_pack_edns0(struct asr_pack *, uint16_t);
> +int _asr_pack_edns0(struct asr_pack *, uint16_t, int);
>  void _asr_unpack_init(struct asr_unpack *, const char *, size_t);
>  int _asr_unpack_header(struct asr_unpack *, struct asr_dns_header *);
>  int 

Re: asr: support for RES_USE_DNSSEC

2017-02-26 Thread Jeremie Courreges-Anglas
Jeremie Courreges-Anglas  writes:

> This flag is useful for software that wants to rely on the resolver to
> perform DNSSEC validation.  Among the use cases there are DANE and SSHFP
> records, and the obvious interfaces that I think are useful are
> res_mkquery and getrrsetbyname.  The latter still doesn't support
> DNSSEC, another diff will follow.
>
> The first hunk is not supposed to be committed, it is only here for
> basic testing (add "options dnssec" to resolv.conf).  Other testing
> could involve postfix or exim.
>
> Since RES_USE_DNSSEC now actually adds an EDNS0 OPT record to the
> outgoing packet, one can be concerned with problems with resolvers out
> there.  Windows seems to have a way to disable EDNS0, I am not aware of
> existing mechanisms elsewhere.
>
> Thoughts?  ok?

Reviewing the dnssec patch from Peter J. Philipp, I noticed that this
first diff lacks hunks to amend the response flags check.  Initially
I had - lazily - only removed the Z_MASK test.

Updated diff, that includes bits for asr_debug.c.  First hunk still here
for basic testing.  Packets with the AD or CD flags are no longer
discarded, given the new Z_MASK #define. (I don't see a reason to
discard packets with the CD bit set, we should probably just ignore
it.  I've kept things as is for the must-be-zero part.)


Index: asr/asr.c
===
RCS file: /d/cvs/src/lib/libc/asr/asr.c,v
retrieving revision 1.56
diff -u -p -r1.56 asr.c
--- asr/asr.c   23 Feb 2017 17:04:02 -  1.56
+++ asr/asr.c   27 Feb 2017 07:25:11 -
@@ -597,6 +597,8 @@ pass0(char **tok, int n, struct asr_ctx 
ac->ac_options |= RES_USEVC;
else if (!strcmp(tok[i], "edns0"))
ac->ac_options |= RES_USE_EDNS0;
+   else if (!strcmp(tok[i], "dnssec"))
+   ac->ac_options |= RES_USE_DNSSEC;
else if ((!strncmp(tok[i], "ndots:", 6))) {
e = NULL;
d = strtonum(tok[i] + 6, 1, 16, );
Index: asr/asr_debug.c
===
RCS file: /d/cvs/src/lib/libc/asr/asr_debug.c,v
retrieving revision 1.23
diff -u -p -r1.23 asr_debug.c
--- asr/asr_debug.c 17 Feb 2017 22:24:45 -  1.23
+++ asr/asr_debug.c 27 Feb 2017 07:25:11 -
@@ -37,7 +37,6 @@ static const char *print_rr(const struct
 FILE *_asr_debug = NULL;
 
 #define OPCODE_SHIFT   11
-#define Z_SHIFT 4
 
 static const char *
 rcodetostr(uint16_t v)
@@ -147,7 +146,7 @@ static const char *
 print_header(const struct asr_dns_header *h, char *buf, size_t max)
 {
snprintf(buf, max,
-   "id:0x%04x %s op:%i %s %s %s %s z:%i r:%s qd:%i an:%i ns:%i ar:%i",
+   "id:0x%04x %s op:%i %s %s %s %s z:%i %s %s r:%s qd:%i an:%i ns:%i 
ar:%i",
((int)h->id),
(h->flags & QR_MASK) ? "QR":"  ",
(int)(OPCODE(h->flags) >> OPCODE_SHIFT),
@@ -155,7 +154,9 @@ print_header(const struct asr_dns_header
(h->flags & TC_MASK) ? "TC":"  ",
(h->flags & RD_MASK) ? "RD":"  ",
(h->flags & RA_MASK) ? "RA":"  ",
-   ((h->flags & Z_MASK) >> Z_SHIFT),
+   (h->flags & Z_MASK),
+   (h->flags & AD_MASK) ? "AD":"  ",
+   (h->flags & CD_MASK) ? "CD":"  ",
rcodetostr(RCODE(h->flags)),
h->qdcount, h->ancount, h->nscount, h->arcount);
 
Index: asr/asr_private.h
===
RCS file: /d/cvs/src/lib/libc/asr/asr_private.h,v
retrieving revision 1.43
diff -u -p -r1.43 asr_private.h
--- asr/asr_private.h   23 Feb 2017 17:04:02 -  1.43
+++ asr/asr_private.h   27 Feb 2017 07:25:11 -
@@ -23,7 +23,9 @@
 #define TC_MASK(0x1 <<  9)
 #define RD_MASK(0x1 <<  8)
 #define RA_MASK(0x1 <<  7)
-#define Z_MASK (0x7 <<  4)
+#define Z_MASK (0x1 <<  6)
+#define AD_MASK(0x1 <<  5)
+#define CD_MASK(0x1 <<  4)
 #define RCODE_MASK (0xf)
 
 #define OPCODE(v)  ((v) & OPCODE_MASK)
@@ -297,7 +299,7 @@ __BEGIN_HIDDEN_DECLS
 void _asr_pack_init(struct asr_pack *, char *, size_t);
 int _asr_pack_header(struct asr_pack *, const struct asr_dns_header *);
 int _asr_pack_query(struct asr_pack *, uint16_t, uint16_t, const char *);
-int _asr_pack_edns0(struct asr_pack *, uint16_t);
+int _asr_pack_edns0(struct asr_pack *, uint16_t, int);
 void _asr_unpack_init(struct asr_unpack *, const char *, size_t);
 int _asr_unpack_header(struct asr_unpack *, struct asr_dns_header *);
 int _asr_unpack_query(struct asr_unpack *, struct asr_dns_query *);
Index: asr/asr_utils.c
===
RCS file: /d/cvs/src/lib/libc/asr/asr_utils.c,v
retrieving revision 1.16
diff -u -p -r1.16 

Re: asr: support for RES_USE_DNSSEC

2017-02-26 Thread Jeremie Courreges-Anglas
"Peter J. Philipp"  writes:

> Hi,
>
> I'm not the best in reading patches, so I'm going to query you.  Does
> your patch check for the "AD" flag from the resolver?

The patch doesn't change anything here.  We don't look at that flag for
res_mkquery, the application is supposed to do so.  getrrsetbyname(3)
already checks the ad bit to set RRSET_VALIDATED.

> As basically a
> DNSSEC able recursive nameserver should set this meaning it has
> authenticated the data.  I wrote a patch for DNSSEC (possibly erroneous
> by comparing it to you) and posted it to #opensmtpd in hopes that eric
> would see it.  Much of that functionality is superfluous now but it does
> have an "AD_MASK" check.

You're right that we still need to handle the AD flag better, that part
was missing from my first diff.

> Here is my patch from last year, which I gave up on, feel free to cherry
> pick anything needed out of it.  You'll see some similarities but they
> are different enough to show two different peoples work.
>
> http://centroid.eu/private/dnssec.patch.txt

Setting the AD flag for a query is possible, however those semantics are
newer than the EDNS0 extension.  As far as I know, rfc6840 introduced
AD=1 for queries in 2013, whereas rfc3225 specifies the DO flag since
2001.

  https://tools.ietf.org/html/rfc3225
  https://tools.ietf.org/html/rfc6840#section-5.7

Also EDNS0 can give you more than 512 bytes on UDP (if the resolver
supports it).  So I thought I'd rather implement RES_USE_DNSSEC on top
of EDNS0.

-- 
jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF  DDCC 0DFA 74AE 1524 E7EE



Re: asr: support for RES_USE_DNSSEC

2017-02-26 Thread Jeremie Courreges-Anglas
Eric Faurot  writes:

> On Sat, Feb 25, 2017 at 07:24:48PM +0100, Jeremie Courreges-Anglas wrote:
>> Jeremie Courreges-Anglas  writes:
>> 
>> > This flag is useful for software that wants to rely on the resolver to
>> > perform DNSSEC validation.  Among the use cases there are DANE and SSHFP
>> > records, and the obvious interfaces that I think are useful are
>> > res_mkquery and getrrsetbyname.  The latter still doesn't support
>> > DNSSEC, another diff will follow.
>> 
>> Diff on top of the previous one.  I'd like to make getrrsetbyname(3)
>> "use" RES_USE_DNSSEC again.  This would improve support for ssh -o
>> VerifyHostKeyDNS (SSHFP records).
>> 
>> The "easy" way would be something like:
>> 
>> Index: getrrsetbyname_async.c
>> ===
>> RCS file: /d/cvs/src/lib/libc/asr/getrrsetbyname_async.c,v
>> retrieving revision 1.11
>> diff -u -p -p -u -r1.11 getrrsetbyname_async.c
>> --- getrrsetbyname_async.c   23 Feb 2017 17:04:02 -  1.11
>> +++ getrrsetbyname_async.c   25 Feb 2017 17:25:25 -
>> @@ -42,6 +42,7 @@ getrrsetbyname_async(const char *hostnam
>>  struct asr_query *as;
>>  
>>  ac = _asr_use_resolver(asr);
>> +ac->ac_options |= RES_USE_DNSSEC;
>>  if ((as = _asr_async_new(ac, ASR_GETRRSETBYNAME)) == NULL)
>>  goto abort; /* errno set */
>>  as->as_run = getrrsetbyname_async_run;
>> 
>> IIUC this means that we modify the thread-local resolver options used by
>> subsequent queries.  Cleaning up by resetting the flag before returning
>> doesn't work in all cases because you could have overlap between two
>> active getrrsetbyname_async and eg getaddrinfo_async contexts.
>
> Right. It has to be set a the query level.
>
>> The diff below instead adds an as_flags member to struct asr_query, and
>> merges the flags of the various union members.  struct rrset and struct
>> ni keep their flags member, as they are a different kind of flags.
>> A subset of as_flags is passed down to the child ASR_SEND subq, the only
>> flag that is inherited right now is ASYNC_DNSSEC, which allows
>> getrrsetbyname_async to communicate its intent.
>> 
>> That's a bit of churn for a small improvement, maybe there is a simpler
>> diff?
>>
>> Comments welcome.
>> 
>
> Well, I like the as_flags cleanup part of the diff. Internal flags should
> indeed be on the asr_query structure directly, so they are not confused
> with query-specific parameters.
>
> For the flags inheritance, I'm not so sure.  I would rather keep the current
> internal API for now, and set the flags explicitely for this specific case.

Fine with me, here's a diff to introduce as_flags only, still on top of
the RES_USE_DNSSEC diff.


diff -x CVS -pruN asr.1/asr.c asr/asr.c
--- asr.1/asr.c Sat Feb 25 17:57:40 2017
+++ asr/asr.c   Sun Feb 26 22:43:02 2017
@@ -244,7 +244,7 @@ _asr_async_free(struct asr_query *as)
case ASR_SEND:
if (as->as_fd != -1)
close(as->as_fd);
-   if (as->as.dns.obuf && !(as->as.dns.flags & ASYNC_EXTOBUF))
+   if (as->as.dns.obuf && !(as->as_flags & ASYNC_EXTOBUF))
free(as->as.dns.obuf);
if (as->as.dns.ibuf)
free(as->as.dns.ibuf);
diff -x CVS -pruN asr.1/asr_private.h asr/asr_private.h
--- asr.1/asr_private.h Sat Feb 25 17:57:40 2017
+++ asr/asr_private.h   Sun Feb 26 22:44:06 2017
@@ -165,6 +165,7 @@ struct asr_query {
int (*as_run)(struct asr_query *, struct asr_result *);
struct asr_ctx  *as_ctx;
int  as_type;
+   int  as_flags;
int  as_state;
 
/* cond */
@@ -183,7 +184,6 @@ struct asr_query {
 
union {
struct {
-   int  flags;
uint16_t reqid;
int  class;
int  type;
@@ -206,7 +206,6 @@ struct asr_query {
} dns;
 
struct {
-   int  flags;
int  class;
int  type;
char*name;
@@ -249,7 +248,6 @@ struct asr_query {
char*fqdn;
struct addrinfo *aifirst;
struct addrinfo *ailast;
-   int  flags;
} ai;
 
struct {
diff -x CVS -pruN asr.1/getaddrinfo_async.c asr/getaddrinfo_async.c
--- asr.1/getaddrinfo_async.c   Sat Feb 25 17:57:40 2017
+++ asr/getaddrinfo_async.c Sun Feb 26 22:43:02 2017
@@ -356,11 +356,11 @@ getaddrinfo_async_run(struct asr_query *as, struct asr
AS_FAMILY(as) : as->as.ai.hints.ai_family;
 
if (family == AF_INET &&
-   

Re: asr: support for RES_USE_DNSSEC

2017-02-26 Thread Eric Faurot
On Sat, Feb 25, 2017 at 11:17:37PM +0100, Peter J. Philipp wrote:
> Hi,
> 
> I'm not the best in reading patches, so I'm going to query you.  Does
> your patch check for the "AD" flag from the resolver?  As basically a
> DNSSEC able recursive nameserver should set this meaning it has
> authenticated the data.  I wrote a patch for DNSSEC (possibly erroneous
> by comparing it to you) and posted it to #opensmtpd in hopes that eric
> would see it.  Much of that functionality is superfluous now but it does
> have an "AD_MASK" check.
>
> Here is my patch from last year, which I gave up on, feel free to cherry
> pick anything needed out of it.  You'll see some similarities but they
> are different enough to show two different peoples work.

Sorry for not getting back to you about this diff at that time.
I'll have a look at it.

> http://centroid.eu/private/dnssec.patch.txt
> 
> Yours is a lot more complete of course.
> 
> Cheers,
> 
> -peter
> 



Re: asr: support for RES_USE_DNSSEC

2017-02-26 Thread Eric Faurot
On Sat, Feb 25, 2017 at 05:55:36PM +0100, Jeremie Courreges-Anglas wrote:
> 
> This flag is useful for software that wants to rely on the resolver to
> perform DNSSEC validation.  Among the use cases there are DANE and SSHFP
> records, and the obvious interfaces that I think are useful are
> res_mkquery and getrrsetbyname.  The latter still doesn't support
> DNSSEC, another diff will follow.
> 
> The first hunk is not supposed to be committed, it is only here for
> basic testing (add "options dnssec" to resolv.conf).  Other testing
> could involve postfix or exim.
> 
> Since RES_USE_DNSSEC now actually adds an EDNS0 OPT record to the
> outgoing packet, one can be concerned with problems with resolvers out
> there.  Windows seems to have a way to disable EDNS0, I am not aware of
> existing mechanisms elsewhere.
> 
> Thoughts?  ok?

Looks good.

ok eric@

> 
> Index: asr/asr.c
> ===
> RCS file: /d/cvs/src/lib/libc/asr/asr.c,v
> retrieving revision 1.56
> diff -u -p -r1.56 asr.c
> --- asr/asr.c 23 Feb 2017 17:04:02 -  1.56
> +++ asr/asr.c 25 Feb 2017 16:04:30 -
> @@ -597,6 +597,8 @@ pass0(char **tok, int n, struct asr_ctx 
>   ac->ac_options |= RES_USEVC;
>   else if (!strcmp(tok[i], "edns0"))
>   ac->ac_options |= RES_USE_EDNS0;
> + else if (!strcmp(tok[i], "dnssec"))
> + ac->ac_options |= RES_USE_DNSSEC;
>   else if ((!strncmp(tok[i], "ndots:", 6))) {
>   e = NULL;
>   d = strtonum(tok[i] + 6, 1, 16, );
> Index: asr/asr_private.h
> ===
> RCS file: /d/cvs/src/lib/libc/asr/asr_private.h,v
> retrieving revision 1.43
> diff -u -p -r1.43 asr_private.h
> --- asr/asr_private.h 23 Feb 2017 17:04:02 -  1.43
> +++ asr/asr_private.h 25 Feb 2017 14:45:16 -
> @@ -297,7 +297,7 @@ __BEGIN_HIDDEN_DECLS
>  void _asr_pack_init(struct asr_pack *, char *, size_t);
>  int _asr_pack_header(struct asr_pack *, const struct asr_dns_header *);
>  int _asr_pack_query(struct asr_pack *, uint16_t, uint16_t, const char *);
> -int _asr_pack_edns0(struct asr_pack *, uint16_t);
> +int _asr_pack_edns0(struct asr_pack *, uint16_t, int);
>  void _asr_unpack_init(struct asr_unpack *, const char *, size_t);
>  int _asr_unpack_header(struct asr_unpack *, struct asr_dns_header *);
>  int _asr_unpack_query(struct asr_unpack *, struct asr_dns_query *);
> Index: asr/asr_utils.c
> ===
> RCS file: /d/cvs/src/lib/libc/asr/asr_utils.c,v
> retrieving revision 1.16
> diff -u -p -r1.16 asr_utils.c
> --- asr/asr_utils.c   19 Feb 2017 12:02:30 -  1.16
> +++ asr/asr_utils.c   25 Feb 2017 16:06:01 -
> @@ -423,12 +423,19 @@ _asr_pack_query(struct asr_pack *p, uint
>  }
>  
>  int
> -_asr_pack_edns0(struct asr_pack *p, uint16_t pktsz)
> +_asr_pack_edns0(struct asr_pack *p, uint16_t pktsz, int dnssec_do)
>  {
> + DPRINT("asr EDNS0 pktsz:%hu dnssec:%s\n", pktsz,
> + dnssec_do ? "yes" : "no");
> +
>   pack_dname(p, "");  /* root */
>   pack_u16(p, T_OPT); /* OPT */
>   pack_u16(p, pktsz); /* UDP payload size */
> - pack_u32(p, 0); /* extended RCODE and flags */
> +
> + /* extended RCODE and flags */
> + pack_u16(p, 0);
> + pack_u16(p, dnssec_do ? DNS_MESSAGEEXTFLAG_DO : 0);
> +
>   pack_u16(p, 0); /* RDATA len */
>  
>   return (p->err) ? (-1) : (0);
> Index: asr/res_mkquery.c
> ===
> RCS file: /d/cvs/src/lib/libc/asr/res_mkquery.c,v
> retrieving revision 1.10
> diff -u -p -r1.10 res_mkquery.c
> --- asr/res_mkquery.c 18 Feb 2017 19:23:05 -  1.10
> +++ asr/res_mkquery.c 25 Feb 2017 14:45:16 -
> @@ -61,14 +61,15 @@ res_mkquery(int op, const char *dname, i
>   if (ac->ac_options & RES_RECURSE)
>   h.flags |= RD_MASK;
>   h.qdcount = 1;
> - if (ac->ac_options & RES_USE_EDNS0)
> + if (ac->ac_options & (RES_USE_EDNS0 | RES_USE_DNSSEC))
>   h.arcount = 1;
>  
>   _asr_pack_init(, buf, buflen);
>   _asr_pack_header(, );
>   _asr_pack_query(, type, class, dn);
> - if (ac->ac_options & RES_USE_EDNS0)
> - _asr_pack_edns0(, MAXPACKETSZ);
> + if (ac->ac_options & (RES_USE_EDNS0 | RES_USE_DNSSEC))
> + _asr_pack_edns0(, MAXPACKETSZ,
> + ac->ac_options & RES_USE_DNSSEC);
>  
>   _asr_ctx_unref(ac);
>  
> Index: asr/res_send_async.c
> ===
> RCS file: /d/cvs/src/lib/libc/asr/res_send_async.c,v
> retrieving revision 1.32
> diff -u -p -r1.32 res_send_async.c
> --- asr/res_send_async.c  18 Feb 2017 22:25:13 -  1.32
> +++ 

Re: asr: support for RES_USE_DNSSEC

2017-02-26 Thread Eric Faurot
On Sat, Feb 25, 2017 at 07:24:48PM +0100, Jeremie Courreges-Anglas wrote:
> Jeremie Courreges-Anglas  writes:
> 
> > This flag is useful for software that wants to rely on the resolver to
> > perform DNSSEC validation.  Among the use cases there are DANE and SSHFP
> > records, and the obvious interfaces that I think are useful are
> > res_mkquery and getrrsetbyname.  The latter still doesn't support
> > DNSSEC, another diff will follow.
> 
> Diff on top of the previous one.  I'd like to make getrrsetbyname(3)
> "use" RES_USE_DNSSEC again.  This would improve support for ssh -o
> VerifyHostKeyDNS (SSHFP records).
> 
> The "easy" way would be something like:
> 
> Index: getrrsetbyname_async.c
> ===
> RCS file: /d/cvs/src/lib/libc/asr/getrrsetbyname_async.c,v
> retrieving revision 1.11
> diff -u -p -p -u -r1.11 getrrsetbyname_async.c
> --- getrrsetbyname_async.c23 Feb 2017 17:04:02 -  1.11
> +++ getrrsetbyname_async.c25 Feb 2017 17:25:25 -
> @@ -42,6 +42,7 @@ getrrsetbyname_async(const char *hostnam
>   struct asr_query *as;
>  
>   ac = _asr_use_resolver(asr);
> + ac->ac_options |= RES_USE_DNSSEC;
>   if ((as = _asr_async_new(ac, ASR_GETRRSETBYNAME)) == NULL)
>   goto abort; /* errno set */
>   as->as_run = getrrsetbyname_async_run;
> 
> IIUC this means that we modify the thread-local resolver options used by
> subsequent queries.  Cleaning up by resetting the flag before returning
> doesn't work in all cases because you could have overlap between two
> active getrrsetbyname_async and eg getaddrinfo_async contexts.

Right. It has to be set a the query level.

> The diff below instead adds an as_flags member to struct asr_query, and
> merges the flags of the various union members.  struct rrset and struct
> ni keep their flags member, as they are a different kind of flags.
> A subset of as_flags is passed down to the child ASR_SEND subq, the only
> flag that is inherited right now is ASYNC_DNSSEC, which allows
> getrrsetbyname_async to communicate its intent.
> 
> That's a bit of churn for a small improvement, maybe there is a simpler
> diff?
>
> Comments welcome.
> 

Well, I like the as_flags cleanup part of the diff. Internal flags should
indeed be on the asr_query structure directly, so they are not confused
with query-specific parameters.

For the flags inheritance, I'm not so sure.  I would rather keep the current
internal API for now, and set the flags explicitely for this specific case.

Eric.

Index: getrrsetbyname_async.c
===
RCS file: /cvs/src/lib/libc/asr/getrrsetbyname_async.c,v
retrieving revision 1.11
diff -u -p -r1.11 getrrsetbyname_async.c
--- getrrsetbyname_async.c  23 Feb 2017 17:04:02 -  1.11
+++ getrrsetbyname_async.c  26 Feb 2017 09:33:47 -
@@ -104,6 +104,7 @@ getrrsetbyname_async_run(struct asr_quer
async_set_state(as, ASR_STATE_HALT);
break;
}
+   as->as_subq->as_flags |= ASYNC_DNSSEC;
 
async_set_state(as, ASR_STATE_SUBQUERY);
break;



Re: asr: support for RES_USE_DNSSEC

2017-02-25 Thread Peter J. Philipp
Hi,

I'm not the best in reading patches, so I'm going to query you.  Does
your patch check for the "AD" flag from the resolver?  As basically a
DNSSEC able recursive nameserver should set this meaning it has
authenticated the data.  I wrote a patch for DNSSEC (possibly erroneous
by comparing it to you) and posted it to #opensmtpd in hopes that eric
would see it.  Much of that functionality is superfluous now but it does
have an "AD_MASK" check.

Here is my patch from last year, which I gave up on, feel free to cherry
pick anything needed out of it.  You'll see some similarities but they
are different enough to show two different peoples work.

http://centroid.eu/private/dnssec.patch.txt

Yours is a lot more complete of course.

Cheers,

-peter

On 02/25/17 19:24, Jeremie Courreges-Anglas wrote:
> Jeremie Courreges-Anglas  writes:
>
>> This flag is useful for software that wants to rely on the resolver to
>> perform DNSSEC validation.  Among the use cases there are DANE and SSHFP
>> records, and the obvious interfaces that I think are useful are
>> res_mkquery and getrrsetbyname.  The latter still doesn't support
>> DNSSEC, another diff will follow.
> Diff on top of the previous one.  I'd like to make getrrsetbyname(3)
> "use" RES_USE_DNSSEC again.  This would improve support for ssh -o
> VerifyHostKeyDNS (SSHFP records).
>
> The "easy" way would be something like:
>
> Index: getrrsetbyname_async.c
> ===
> RCS file: /d/cvs/src/lib/libc/asr/getrrsetbyname_async.c,v
> retrieving revision 1.11
> diff -u -p -p -u -r1.11 getrrsetbyname_async.c
> --- getrrsetbyname_async.c23 Feb 2017 17:04:02 -  1.11
> +++ getrrsetbyname_async.c25 Feb 2017 17:25:25 -
> @@ -42,6 +42,7 @@ getrrsetbyname_async(const char *hostnam
>   struct asr_query *as;
>  
>   ac = _asr_use_resolver(asr);
> + ac->ac_options |= RES_USE_DNSSEC;
>   if ((as = _asr_async_new(ac, ASR_GETRRSETBYNAME)) == NULL)
>   goto abort; /* errno set */
>   as->as_run = getrrsetbyname_async_run;
>
> IIUC this means that we modify the thread-local resolver options used by
> subsequent queries.  Cleaning up by resetting the flag before returning
> doesn't work in all cases because you could have overlap between two
> active getrrsetbyname_async and eg getaddrinfo_async contexts.
>
> The diff below instead adds an as_flags member to struct asr_query, and
> merges the flags of the various union members.  struct rrset and struct
> ni keep their flags member, as they are a different kind of flags.
> A subset of as_flags is passed down to the child ASR_SEND subq, the only
> flag that is inherited right now is ASYNC_DNSSEC, which allows
> getrrsetbyname_async to communicate its intent.
>
> That's a bit of churn for a small improvement, maybe there is a simpler
> diff?
>
> Comments welcome.
>
>
> diff -pruN asr.1/asr.c asr/asr.c
> --- asr.1/asr.c   Sat Feb 25 17:57:40 2017
> +++ asr/asr.c Sat Feb 25 17:58:10 2017
> @@ -244,7 +244,7 @@ _asr_async_free(struct asr_query *as)
>   case ASR_SEND:
>   if (as->as_fd != -1)
>   close(as->as_fd);
> - if (as->as.dns.obuf && !(as->as.dns.flags & ASYNC_EXTOBUF))
> + if (as->as.dns.obuf && !(as->as_flags & ASYNC_EXTOBUF))
>   free(as->as.dns.obuf);
>   if (as->as.dns.ibuf)
>   free(as->as.dns.ibuf);
> diff -pruN asr.1/asr_private.h asr/asr_private.h
> --- asr.1/asr_private.h   Sat Feb 25 17:57:40 2017
> +++ asr/asr_private.h Sat Feb 25 18:12:23 2017
> @@ -156,15 +156,19 @@ struct asr {
>  #define  ASYNC_NODATA0x0100
>  #define  ASYNC_AGAIN 0x0200
>  
> +#define  ASYNC_DNSSEC0x1000
>  #define  ASYNC_EXTOBUF   0x2000
>  
>  #define  ASYNC_NO_INET   0x0001
>  #define  ASYNC_NO_INET6  0x0002
>  
> +#define  ASYNC_ASR_SEND_MASK (ASYNC_DNSSEC)
> +
>  struct asr_query {
>   int (*as_run)(struct asr_query *, struct asr_result *);
>   struct asr_ctx  *as_ctx;
>   int  as_type;
> + int  as_flags;
>   int  as_state;
>  
>   /* cond */
> @@ -183,7 +187,6 @@ struct asr_query {
>  
>   union {
>   struct {
> - int  flags;
>   uint16_t reqid;
>   int  class;
>   int  type;
> @@ -206,7 +209,6 @@ struct asr_query {
>   } dns;
>  
>   struct {
> - int  flags;
>   int  class;
>   int  type;
>   char*name;
> @@ -249,7 +251,6 @@ struct asr_query {
>   char*fqdn;
>   struct addrinfo 

Re: asr: support for RES_USE_DNSSEC

2017-02-25 Thread Denis Fondras
On Sat, Feb 25, 2017 at 07:24:48PM +0100, Jeremie Courreges-Anglas wrote:
> 
> > This flag is useful for software that wants to rely on the resolver to
> > perform DNSSEC validation.  Among the use cases there are DANE and SSHFP
> > records, and the obvious interfaces that I think are useful are
> > res_mkquery and getrrsetbyname.  The latter still doesn't support
> > DNSSEC, another diff will follow.
> 

Thank Jeremie for giving DNSSEC some love !



Re: asr: support for RES_USE_DNSSEC

2017-02-25 Thread Jeremie Courreges-Anglas
Jeremie Courreges-Anglas  writes:

> This flag is useful for software that wants to rely on the resolver to
> perform DNSSEC validation.  Among the use cases there are DANE and SSHFP
> records, and the obvious interfaces that I think are useful are
> res_mkquery and getrrsetbyname.  The latter still doesn't support
> DNSSEC, another diff will follow.

Diff on top of the previous one.  I'd like to make getrrsetbyname(3)
"use" RES_USE_DNSSEC again.  This would improve support for ssh -o
VerifyHostKeyDNS (SSHFP records).

The "easy" way would be something like:

Index: getrrsetbyname_async.c
===
RCS file: /d/cvs/src/lib/libc/asr/getrrsetbyname_async.c,v
retrieving revision 1.11
diff -u -p -p -u -r1.11 getrrsetbyname_async.c
--- getrrsetbyname_async.c  23 Feb 2017 17:04:02 -  1.11
+++ getrrsetbyname_async.c  25 Feb 2017 17:25:25 -
@@ -42,6 +42,7 @@ getrrsetbyname_async(const char *hostnam
struct asr_query *as;
 
ac = _asr_use_resolver(asr);
+   ac->ac_options |= RES_USE_DNSSEC;
if ((as = _asr_async_new(ac, ASR_GETRRSETBYNAME)) == NULL)
goto abort; /* errno set */
as->as_run = getrrsetbyname_async_run;

IIUC this means that we modify the thread-local resolver options used by
subsequent queries.  Cleaning up by resetting the flag before returning
doesn't work in all cases because you could have overlap between two
active getrrsetbyname_async and eg getaddrinfo_async contexts.

The diff below instead adds an as_flags member to struct asr_query, and
merges the flags of the various union members.  struct rrset and struct
ni keep their flags member, as they are a different kind of flags.
A subset of as_flags is passed down to the child ASR_SEND subq, the only
flag that is inherited right now is ASYNC_DNSSEC, which allows
getrrsetbyname_async to communicate its intent.

That's a bit of churn for a small improvement, maybe there is a simpler
diff?

Comments welcome.


diff -pruN asr.1/asr.c asr/asr.c
--- asr.1/asr.c Sat Feb 25 17:57:40 2017
+++ asr/asr.c   Sat Feb 25 17:58:10 2017
@@ -244,7 +244,7 @@ _asr_async_free(struct asr_query *as)
case ASR_SEND:
if (as->as_fd != -1)
close(as->as_fd);
-   if (as->as.dns.obuf && !(as->as.dns.flags & ASYNC_EXTOBUF))
+   if (as->as.dns.obuf && !(as->as_flags & ASYNC_EXTOBUF))
free(as->as.dns.obuf);
if (as->as.dns.ibuf)
free(as->as.dns.ibuf);
diff -pruN asr.1/asr_private.h asr/asr_private.h
--- asr.1/asr_private.h Sat Feb 25 17:57:40 2017
+++ asr/asr_private.h   Sat Feb 25 18:12:23 2017
@@ -156,15 +156,19 @@ struct asr {
 #defineASYNC_NODATA0x0100
 #defineASYNC_AGAIN 0x0200
 
+#defineASYNC_DNSSEC0x1000
 #defineASYNC_EXTOBUF   0x2000
 
 #defineASYNC_NO_INET   0x0001
 #defineASYNC_NO_INET6  0x0002
 
+#defineASYNC_ASR_SEND_MASK (ASYNC_DNSSEC)
+
 struct asr_query {
int (*as_run)(struct asr_query *, struct asr_result *);
struct asr_ctx  *as_ctx;
int  as_type;
+   int  as_flags;
int  as_state;
 
/* cond */
@@ -183,7 +187,6 @@ struct asr_query {
 
union {
struct {
-   int  flags;
uint16_t reqid;
int  class;
int  type;
@@ -206,7 +209,6 @@ struct asr_query {
} dns;
 
struct {
-   int  flags;
int  class;
int  type;
char*name;
@@ -249,7 +251,6 @@ struct asr_query {
char*fqdn;
struct addrinfo *aifirst;
struct addrinfo *ailast;
-   int  flags;
} ai;
 
struct {
@@ -319,7 +320,8 @@ int _asr_iter_db(struct asr_query *);
 int _asr_parse_namedb_line(FILE *, char **, int, char *, size_t);
 
 /* *_async.c */
-struct asr_query *_res_query_async_ctx(const char *, int, int, struct asr_ctx 
*);
+struct asr_query *_res_query_async_ctx(const char *, int, int,
+struct asr_ctx *, int);
 struct asr_query *_res_search_async_ctx(const char *, int, int, struct asr_ctx 
*);
 struct asr_query *_gethostbyaddr_async_ctx(const void *, socklen_t, int,
 struct asr_ctx *);
diff -pruN asr.1/getaddrinfo_async.c asr/getaddrinfo_async.c
--- asr.1/getaddrinfo_async.c   Sat Feb 25 17:57:40 2017
+++ asr/getaddrinfo_async.c Sat Feb 25 18:09:17 2017
@@ -356,18 +356,18 @@ getaddrinfo_async_run(struct asr_query *as, struct asr

asr: support for RES_USE_DNSSEC

2017-02-25 Thread Jeremie Courreges-Anglas

This flag is useful for software that wants to rely on the resolver to
perform DNSSEC validation.  Among the use cases there are DANE and SSHFP
records, and the obvious interfaces that I think are useful are
res_mkquery and getrrsetbyname.  The latter still doesn't support
DNSSEC, another diff will follow.

The first hunk is not supposed to be committed, it is only here for
basic testing (add "options dnssec" to resolv.conf).  Other testing
could involve postfix or exim.

Since RES_USE_DNSSEC now actually adds an EDNS0 OPT record to the
outgoing packet, one can be concerned with problems with resolvers out
there.  Windows seems to have a way to disable EDNS0, I am not aware of
existing mechanisms elsewhere.

Thoughts?  ok?


Index: asr/asr.c
===
RCS file: /d/cvs/src/lib/libc/asr/asr.c,v
retrieving revision 1.56
diff -u -p -r1.56 asr.c
--- asr/asr.c   23 Feb 2017 17:04:02 -  1.56
+++ asr/asr.c   25 Feb 2017 16:04:30 -
@@ -597,6 +597,8 @@ pass0(char **tok, int n, struct asr_ctx 
ac->ac_options |= RES_USEVC;
else if (!strcmp(tok[i], "edns0"))
ac->ac_options |= RES_USE_EDNS0;
+   else if (!strcmp(tok[i], "dnssec"))
+   ac->ac_options |= RES_USE_DNSSEC;
else if ((!strncmp(tok[i], "ndots:", 6))) {
e = NULL;
d = strtonum(tok[i] + 6, 1, 16, );
Index: asr/asr_private.h
===
RCS file: /d/cvs/src/lib/libc/asr/asr_private.h,v
retrieving revision 1.43
diff -u -p -r1.43 asr_private.h
--- asr/asr_private.h   23 Feb 2017 17:04:02 -  1.43
+++ asr/asr_private.h   25 Feb 2017 14:45:16 -
@@ -297,7 +297,7 @@ __BEGIN_HIDDEN_DECLS
 void _asr_pack_init(struct asr_pack *, char *, size_t);
 int _asr_pack_header(struct asr_pack *, const struct asr_dns_header *);
 int _asr_pack_query(struct asr_pack *, uint16_t, uint16_t, const char *);
-int _asr_pack_edns0(struct asr_pack *, uint16_t);
+int _asr_pack_edns0(struct asr_pack *, uint16_t, int);
 void _asr_unpack_init(struct asr_unpack *, const char *, size_t);
 int _asr_unpack_header(struct asr_unpack *, struct asr_dns_header *);
 int _asr_unpack_query(struct asr_unpack *, struct asr_dns_query *);
Index: asr/asr_utils.c
===
RCS file: /d/cvs/src/lib/libc/asr/asr_utils.c,v
retrieving revision 1.16
diff -u -p -r1.16 asr_utils.c
--- asr/asr_utils.c 19 Feb 2017 12:02:30 -  1.16
+++ asr/asr_utils.c 25 Feb 2017 16:06:01 -
@@ -423,12 +423,19 @@ _asr_pack_query(struct asr_pack *p, uint
 }
 
 int
-_asr_pack_edns0(struct asr_pack *p, uint16_t pktsz)
+_asr_pack_edns0(struct asr_pack *p, uint16_t pktsz, int dnssec_do)
 {
+   DPRINT("asr EDNS0 pktsz:%hu dnssec:%s\n", pktsz,
+   dnssec_do ? "yes" : "no");
+
pack_dname(p, "");  /* root */
pack_u16(p, T_OPT); /* OPT */
pack_u16(p, pktsz); /* UDP payload size */
-   pack_u32(p, 0); /* extended RCODE and flags */
+
+   /* extended RCODE and flags */
+   pack_u16(p, 0);
+   pack_u16(p, dnssec_do ? DNS_MESSAGEEXTFLAG_DO : 0);
+
pack_u16(p, 0); /* RDATA len */
 
return (p->err) ? (-1) : (0);
Index: asr/res_mkquery.c
===
RCS file: /d/cvs/src/lib/libc/asr/res_mkquery.c,v
retrieving revision 1.10
diff -u -p -r1.10 res_mkquery.c
--- asr/res_mkquery.c   18 Feb 2017 19:23:05 -  1.10
+++ asr/res_mkquery.c   25 Feb 2017 14:45:16 -
@@ -61,14 +61,15 @@ res_mkquery(int op, const char *dname, i
if (ac->ac_options & RES_RECURSE)
h.flags |= RD_MASK;
h.qdcount = 1;
-   if (ac->ac_options & RES_USE_EDNS0)
+   if (ac->ac_options & (RES_USE_EDNS0 | RES_USE_DNSSEC))
h.arcount = 1;
 
_asr_pack_init(, buf, buflen);
_asr_pack_header(, );
_asr_pack_query(, type, class, dn);
-   if (ac->ac_options & RES_USE_EDNS0)
-   _asr_pack_edns0(, MAXPACKETSZ);
+   if (ac->ac_options & (RES_USE_EDNS0 | RES_USE_DNSSEC))
+   _asr_pack_edns0(, MAXPACKETSZ,
+   ac->ac_options & RES_USE_DNSSEC);
 
_asr_ctx_unref(ac);
 
Index: asr/res_send_async.c
===
RCS file: /d/cvs/src/lib/libc/asr/res_send_async.c,v
retrieving revision 1.32
diff -u -p -r1.32 res_send_async.c
--- asr/res_send_async.c18 Feb 2017 22:25:13 -  1.32
+++ asr/res_send_async.c25 Feb 2017 14:45:16 -
@@ -377,14 +377,15 @@ setup_query(struct asr_query *as, const 
if (as->as_ctx->ac_options & RES_RECURSE)
h.flags |= RD_MASK;
h.qdcount = 1;
-   if