Commit ce67023a authored by Mark Andrews's avatar Mark Andrews

4152. [func] Implement DNS COOKIE option. This replaces the

                        experimental SIT option of BIND 9.10.  The following
                        named.conf directives are avaliable: send-cookie,
                        cookie-secret, cookie-algorithm and nocookie-udp-size.
                        The following dig options are available:
                        +[no]cookie[=value] and +[no]badcookie.  [RT #39928]
parent aa3bffca
4152. [func] Implement DNS COOKIE option. This replaces the
experimental SIT option of BIND 9.10. The following
named.conf directives are avaliable: send-cookie,
cookie-secret, cookie-algorithm and nocookie-udp-size.
The following dig options are available:
+[no]cookie[=value] and +[no]badcookie. [RT #39928]
4151. [bug] 'rndc flush' could cause a deadlock. [RT #39835]
4150. [bug] win32: listen-on-v6 { any; }; was not working. Apply
......
......@@ -35,6 +35,7 @@
#include <dns/masterdump.h>
#include <dns/message.h>
#include <dns/name.h>
#include <dns/rcode.h>
#include <dns/rdata.h>
#include <dns/rdataset.h>
#include <dns/rdatatype.h>
......@@ -61,9 +62,7 @@ static char *argv0;
static int addresscount = 0;
static char domainopt[DNS_NAME_MAXTEXT];
#ifdef ISC_PLATFORM_USESIT
static char sitvalue[256];
#endif
static char hexcookie[81];
static isc_boolean_t short_form = ISC_FALSE, printcmd = ISC_TRUE,
ip6_int = ISC_FALSE, plusquest = ISC_FALSE, pluscomm = ISC_FALSE,
......@@ -92,43 +91,21 @@ static const char * const opcodetext[] = {
"RESERVED15"
};
/*% return code text */
static const char * const rcodetext[] = {
"NOERROR",
"FORMERR",
"SERVFAIL",
"NXDOMAIN",
"NOTIMP",
"REFUSED",
"YXDOMAIN",
"YXRRSET",
"NXRRSET",
"NOTAUTH",
"NOTZONE",
"RESERVED11",
"RESERVED12",
"RESERVED13",
"RESERVED14",
"RESERVED15",
"BADVERS"
};
static const char *
rcode_totext(dns_rcode_t rcode) {
static char buf[64];
isc_buffer_t b;
isc_result_t result;
/*% safe rcodetext[] */
static char *
rcode_totext(dns_rcode_t rcode)
{
static char buf[sizeof("?65535")];
union {
const char *consttext;
char *deconsttext;
} totext;
if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
snprintf(buf, sizeof(buf), "?%u", rcode);
totext.deconsttext = buf;
} else
totext.consttext = rcodetext[rcode];
return totext.deconsttext;
memset(buf, 0, sizeof(buf));
isc_buffer_init(&b, buf + 1, sizeof(buf) - 2);
result = dns_rcode_totext(rcode, &b);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (strspn(buf + 1, "0123456789") == strlen(buf + 1)) {
buf[0] = '?';
return(buf);
}
return (buf + 1);
}
/*% print usage */
......@@ -233,9 +210,8 @@ help(void) {
" +[no]expire (Request time to expire)\n"
" +[no]nsid (Request Name Server ID)\n"
" +[no]header-only (Send query without a question section)\n"
#ifdef ISC_PLATFORM_USESIT
" +[no]sit (Request a Source Identity Token)\n"
#endif
" +[no]badcookie (Retry BADCOOKIE responses)\n"
" +[no]cookie (Add a COOKIE option to the request)\n"
#ifdef DIG_SIGCHASE
" +[no]sigchase (Chase DNSSEC signatures)\n"
" +trusted-key=#### (Trusted Key when chasing DNSSEC sigs)\n"
......@@ -767,9 +743,7 @@ plus_option(char *option, isc_boolean_t is_batchfile,
char *cmd, *value, *ptr, *code;
isc_uint32_t num;
isc_boolean_t state = ISC_TRUE;
#if defined(DIG_SIGCHASE) || defined(ISC_PLATFORM_USESIT)
size_t n;
#endif
strncpy(option_store, option, sizeof(option_store));
option_store[sizeof(option_store)-1]=0;
......@@ -846,6 +820,10 @@ plus_option(char *option, isc_boolean_t is_batchfile,
break;
case 'b':
switch (cmd[1]) {
case 'a':/* badcookie */
FULLCHECK("badcookie");
lookup->besteffort = state;
break;
case 'e':/* besteffort */
FULLCHECK("besteffort");
lookup->besteffort = state;
......@@ -889,10 +867,30 @@ plus_option(char *option, isc_boolean_t is_batchfile,
printcmd = state;
break;
case 'o': /* comments */
FULLCHECK("comments");
lookup->comments = state;
if (lookup == default_lookup)
pluscomm = state;
switch (cmd[2]) {
case 'm':
FULLCHECK("comments");
lookup->comments = state;
if (lookup == default_lookup)
pluscomm = state;
break;
case 'o': /* cookie */
FULLCHECK("cookie");
if (state && lookup->edns == -1)
lookup->edns = 0;
lookup->sendcookie = state;
if (value != NULL) {
n = strlcpy(hexcookie, value,
sizeof(hexcookie));
if (n >= sizeof(hexcookie))
fatal("COOKIE data too large");
lookup->cookie = hexcookie;
} else
lookup->cookie = NULL;
break;
default:
goto invalid_option;
}
break;
case 'r':
FULLCHECK("crypto");
......@@ -1222,36 +1220,12 @@ plus_option(char *option, isc_boolean_t is_batchfile,
goto invalid_option;
}
break;
#if defined(DIG_SIGCHASE) || defined(ISC_PLATFORM_USESIT)
case 'i':
switch (cmd[2]) {
#ifdef DIG_SIGCHASE
case 'g': /* sigchase */
FULLCHECK("sigchase");
lookup->sigchase = state;
if (lookup->sigchase)
lookup->dnssec = ISC_TRUE;
break;
#endif
#ifdef ISC_PLATFORM_USESIT
case 't': /* sit */
FULLCHECK("sit");
if (state && lookup->edns == -1)
lookup->edns = 0;
lookup->sit = state;
if (value != NULL) {
n = strlcpy(sitvalue, value,
sizeof(sitvalue));
if (n >= sizeof(sitvalue))
fatal("SIT data too large");
lookup->sitvalue = sitvalue;
} else
lookup->sitvalue = NULL;
break;
#endif
default:
goto invalid_option;
}
case 'i': /* sigchase */
FULLCHECK("sigchase");
lookup->sigchase = state;
if (lookup->sigchase)
lookup->dnssec = ISC_TRUE;
break;
#endif
case 'p': /* split */
......@@ -1353,6 +1327,7 @@ plus_option(char *option, isc_boolean_t is_batchfile,
lookup->section_authority = ISC_TRUE;
lookup->section_question = ISC_FALSE;
lookup->dnssec = ISC_TRUE;
lookup->sendcookie = ISC_TRUE;
usesearch = ISC_FALSE;
}
break;
......@@ -1789,6 +1764,7 @@ parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only,
default_lookup = make_empty_lookup();
default_lookup->adflag = ISC_TRUE;
default_lookup->edns = 0;
default_lookup->sendcookie = ISC_TRUE;
#ifndef NOPOSIX
/*
......
......@@ -219,49 +219,49 @@
<variablelist>
<varlistentry>
<term>-4</term>
<listitem>
<term>-4</term>
<listitem>
<para>
Use IPv4 only.
</para>
</listitem>
</listitem>
</varlistentry>
<varlistentry>
<term>-6</term>
<listitem>
<term>-6</term>
<listitem>
<para>
Use IPv6 only.
</para>
</listitem>
</listitem>
</varlistentry>
<varlistentry>
<term>-b <replaceable class="parameter">address<optional>#port</optional></replaceable></term>
<listitem>
<term>-b <replaceable class="parameter">address<optional>#port</optional></replaceable></term>
<listitem>
<para>
Set the source IP address of the query.
The <parameter>address</parameter> must be a valid address on
one of the host's network interfaces, or "0.0.0.0" or "::". An
optional port may be specified by appending "#&lt;port&gt;"
</para>
</listitem>
</listitem>
</varlistentry>
<varlistentry>
<term>-c <replaceable class="parameter">class</replaceable></term>
<listitem>
<term>-c <replaceable class="parameter">class</replaceable></term>
<listitem>
<para>
Set the query class. The
default <parameter>class</parameter> is IN; other classes
are HS for Hesiod records or CH for Chaosnet records.
</para>
</listitem>
</listitem>
</varlistentry>
<varlistentry>
<term>-f <replaceable class="parameter">file</replaceable></term>
<listitem>
<term>-f <replaceable class="parameter">file</replaceable></term>
<listitem>
<para>
Batch mode: <command>dig</command> reads a list of lookup
requests to process from the
......@@ -270,23 +270,23 @@
presented as queries to
<command>dig</command> using the command-line interface.
</para>
</listitem>
</listitem>
</varlistentry>
<varlistentry>
<term>-i</term>
<listitem>
<term>-i</term>
<listitem>
<para>
Do reverse IPv6 lookups using the obsolete RFC1886 IP6.INT
domain, which is no longer in use. Obsolete bit string
label queries (RFC2874) are not attempted.
</para>
</listitem>
</listitem>
</varlistentry>
<varlistentry>
<term>-k <replaceable class="parameter">keyfile</replaceable></term>
<listitem>
<term>-k <replaceable class="parameter">keyfile</replaceable></term>
<listitem>
<para>
Sign queries using TSIG using a key read from the given file.
Key files can be generated using
......@@ -300,45 +300,45 @@
and <command>server</command> statements in
<filename>named.conf</filename>.
</para>
</listitem>
</listitem>
</varlistentry>
<varlistentry>
<term>-m</term>
<listitem>
<term>-m</term>
<listitem>
<para>
Enable memory usage debugging.
<!-- It enables ISC_MEM_DEBUGTRACE and ISC_MEM_DEBUGRECORD
documented in include/isc/mem.h -->
</para>
</listitem>
</listitem>
</varlistentry>
<varlistentry>
<term>-p <replaceable class="parameter">port</replaceable></term>
<listitem>
<term>-p <replaceable class="parameter">port</replaceable></term>
<listitem>
<para>
Send the query to a non-standard port on the server,
instead of the defaut port 53. This option would be used
to test a name server that has been configured to listen
for queries on a non-standard port number.
</para>
</listitem>
</listitem>
</varlistentry>
<varlistentry>
<term>-q <replaceable class="parameter">name</replaceable></term>
<listitem>
<term>-q <replaceable class="parameter">name</replaceable></term>
<listitem>
<para>
The domain name to query. This is useful to distinguish
the <parameter>name</parameter> from other arguments.
</para>
</listitem>
</listitem>
</varlistentry>
<varlistentry>
<term>-t <replaceable class="parameter">type</replaceable></term>
<listitem>
<term>-t <replaceable class="parameter">type</replaceable></term>
<listitem>
<para>
The resource record type to query. It can be any valid query type
which is
......@@ -352,21 +352,21 @@
record was
<parameter>N</parameter>.
</para>
</listitem>
</listitem>
</varlistentry>
<varlistentry>
<term>-v</term>
<listitem>
<term>-v</term>
<listitem>
<para>
Print the version number and exit.
</para>
</listitem>
</listitem>
</varlistentry>
<varlistentry>
<term>-x <replaceable class="parameter">addr</replaceable></term>
<listitem>
<term>-x <replaceable class="parameter">addr</replaceable></term>
<listitem>
<para>
Simplified reverse lookups, for mapping addresses to
names. The <parameter>addr</parameter> is an IPv4 address
......@@ -383,12 +383,12 @@
IP6.ARPA domain (but see also the <option>-i</option>
option).
</para>
</listitem>
</listitem>
</varlistentry>
<varlistentry>
<term>-y <replaceable class="parameter"><optional>hmac:</optional>keyname:secret</replaceable></term>
<listitem>
<term>-y <replaceable class="parameter"><optional>hmac:</optional>keyname:secret</replaceable></term>
<listitem>
<para>
Sign queries using TSIG with the given authentication key.
<parameter>keyname</parameter> is the name of the key, and
......@@ -407,11 +407,11 @@
a command line argument in clear text. This may be visible
in the output from
<citerefentry>
<refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum>
<refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum>
</citerefentry>
or in a history file maintained by the user's shell.
</para>
</listitem>
</listitem>
</varlistentry>
</variablelist>
......@@ -517,6 +517,16 @@
</listitem>
</varlistentry>
<varlistentry>
<term><option>+[no]badcookie</option></term>
<listitem>
<para>
Retry lookup with the new server cookie if a
BADCOOKIE response is received.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>+[no]besteffort</option></term>
<listitem>
......@@ -585,6 +595,23 @@
</listitem>
</varlistentry>
<varlistentry>
<term><option>+[no]cookie<optional>=####</optional></option></term>
<listitem>
<para>
Send a COOKIE EDNS option, with optional
value. Replaying a COOKIE from a previous response will
allow the server to identify a previous client. The
default is <option>+cookie</option>.
</para>
<para>
<command>+cookie</command> is also set when +trace
is set to better emulate the default queries from a
nameserver.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>+[no]crypto</option></term>
<listitem>
......@@ -952,19 +979,6 @@
</listitem>
</varlistentry>
<varlistentry>
<term><option>+[no]sit<optional>=####</optional></option></term>
<listitem>
<para>
Send a Source Identity Token EDNS option, with optional
value. Replaying a SIT from a previous response will
allow the server to identify a previous client. The
default is <option>+nosit</option>. Currently using
experimental value 65001 for the option code.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>+split=W</option></term>
<listitem>
......
......@@ -149,9 +149,7 @@ int ndots = -1;
int tries = 3;
int lookup_counter = 0;
#ifdef ISC_PLATFORM_USESIT
static char sitvalue[256];
#endif
static char servercookie[256];
#ifdef WITH_IDN
static void initialize_idn(void);
......@@ -792,9 +790,9 @@ make_empty_lookup(void) {
looknew->expire = ISC_FALSE;
looknew->nsid = ISC_FALSE;
looknew->header_only = ISC_FALSE;
#ifdef ISC_PLATFORM_USESIT
looknew->sit = ISC_FALSE;
#endif
looknew->sendcookie = ISC_FALSE;
looknew->seenbadcookie = ISC_FALSE;
looknew->badcookie = ISC_TRUE;
#ifdef DIG_SIGCHASE
looknew->sigchase = ISC_FALSE;
#if DIG_SIGCHASE_TD
......@@ -833,9 +831,7 @@ make_empty_lookup(void) {
looknew->done_as_is = ISC_FALSE;
looknew->need_search = ISC_FALSE;
looknew->ecs_addr = NULL;
#ifdef ISC_PLATFORM_USESIT
looknew->sitvalue = NULL;
#endif
looknew->cookie = NULL;
looknew->ednsopts = NULL;
looknew->ednsoptscnt = 0;
looknew->ednsneg = ISC_TRUE;
......@@ -891,10 +887,10 @@ clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) {
looknew->expire = lookold->expire;
looknew->nsid = lookold->nsid;
looknew->header_only = lookold->header_only;
#ifdef ISC_PLATFORM_USESIT
looknew->sit = lookold->sit;
looknew->sitvalue = lookold->sitvalue;
#endif
looknew->sendcookie = lookold->sendcookie;
looknew->seenbadcookie = lookold->seenbadcookie;
looknew->badcookie = lookold->badcookie;
looknew->cookie = lookold->cookie;
looknew->ednsopts = lookold->ednsopts;
looknew->ednsoptscnt = lookold->ednsoptscnt;
looknew->ednsneg = lookold->ednsneg;
......@@ -1575,7 +1571,7 @@ save_opt(dig_lookup_t *lookup, char *code, char *value) {
/*%
* Add EDNS0 option record to a message. Currently, the only supported
* options are UDP buffer size, the DO bit, and EDNS options
* (e.g., NSID, SIT, client-subnet)
* (e.g., NSID, COOKIE, client-subnet)
*/
static void
add_opt(dns_message_t *msg, isc_uint16_t udpsize, isc_uint16_t edns,
......@@ -2174,14 +2170,12 @@ insert_soa(dig_lookup_t *lookup) {
dns_message_addname(lookup->sendmsg, soaname, DNS_SECTION_AUTHORITY);
}
#ifdef ISC_PLATFORM_USESIT
static void
compute_cookie(unsigned char *clientcookie, size_t len) {
/* XXXMPA need to fix, should be per server. */
INSIST(len >= 8U);
memmove(clientcookie, cookie_secret, 8);
}
#endif
/*%
* Setup the supplied lookup structure, making it ready to start sending
......@@ -2200,9 +2194,7 @@ setup_lookup(dig_lookup_t *lookup) {
dns_compress_t cctx;
char store[MXNAME];
char ecsbuf[20];
#ifdef ISC_PLATFORM_USESIT
char sitbuf[256];
#endif
char cookiebuf[256];
#ifdef WITH_IDN
idn_result_t mr;
char utf8_textname[MXNAME], utf8_origin[MXNAME], idn_textname[MXNAME];
......@@ -2534,13 +2526,13 @@ setup_lookup(dig_lookup_t *lookup) {
i++;
}
#ifdef ISC_PLATFORM_USESIT
if (lookup->sit) {
if (lookup->sendcookie) {
INSIST(i < DNS_EDNSOPTIONS);
opts[i].code = DNS_OPT_SIT;
if (lookup->sitvalue != NULL) {
isc_buffer_init(&b, sitbuf, sizeof(sitbuf));
result = isc_hex_decodestring(lookup->sitvalue,
opts[i].code = DNS_OPT_COOKIE;
if (lookup->cookie != NULL) {
isc_buffer_init(&b, cookiebuf,
sizeof(cookiebuf));
result = isc_hex_decodestring(lookup->cookie,
&b);
check_result(result, "isc_hex_decodestring");
opts[i].value = isc_buffer_base(&b);
......@@ -2552,7 +2544,6 @@ setup_lookup(dig_lookup_t *lookup) {
}
i++;
}
#endif
if (lookup->expire) {
INSIST(i < DNS_EDNSOPTIONS);
......@@ -3411,56 +3402,53 @@ check_for_more_data(dig_query_t *query, dns_message_t *msg,
return (ISC_TRUE);
}
#ifdef ISC_PLATFORM_USESIT
static void
process_sit(dig_lookup_t *l, dns_message_t *msg,
isc_buffer_t *optbuf, size_t optlen)
process_cookie(dig_lookup_t *l, dns_message_t *msg,
isc_buffer_t *optbuf, size_t optlen)
{
char bb[256];
isc_buffer_t hexbuf;
size_t len;
const unsigned char *sit;
isc_boolean_t copysit;
const unsigned char *sent;
isc_boolean_t copy = ISC_TRUE;
isc_result_t result;
if (l->sitvalue != NULL) {
if (l->cookie != NULL) {
isc_buffer_init(&hexbuf, bb, sizeof(bb));
result = isc_hex_decodestring(l->sitvalue, &hexbuf);
result = isc_hex_decodestring(l->cookie, &hexbuf);
check_result(result, "isc_hex_decodestring");
sit = isc_buffer_base(&hexbuf);
sent = isc_buffer_base(&hexbuf);
len = isc_buffer_usedlength(&hexbuf);
copysit = ISC_FALSE;
} else {
sit = cookie;
sent = cookie;
len = sizeof(cookie);
copysit = ISC_TRUE;
}
INSIST(msg->sitok == 0 && msg->sitbad == 0);
INSIST(msg->cc_ok == 0 && msg->cc_bad == 0);
if (optlen >= len && optlen >= 8U) {
if (memcmp(isc_buffer_current(optbuf), sit, 8) == 0) {
msg->sitok = 1;
if (memcmp(isc_buffer_current(optbuf), sent, 8) == 0) {
msg->cc_ok = 1;
} else {
printf(";; Warning: SIT client cookie mismatch\n");
msg->sitbad = 1;
copysit = ISC_FALSE;
printf(";; Warning: Client COOKIE mismatch\n");
msg->cc_bad = 1;
copy = ISC_FALSE;
}
} else {
printf(";; Warning: SIT bad token (too short)\n");
msg->sitbad = 1;
copysit = ISC_FALSE;
printf(";; Warning: COOKIE bad token (too short)\n");