...
 
Commits (9)
  • Evan Hunt's avatar
    update the acl system test to include a blackhole test case · 6b00e5f5
    Evan Hunt authored
    this ACL was previously untested, which allowed a regression to
    go undetected.
    
    (cherry picked from commit e3ee1380)
    6b00e5f5
  • Evan Hunt's avatar
    restore "blackhole" functionality · 952461b6
    Evan Hunt authored
    the blackhole ACL was accidentally disabled with respect to client
    queries during the netmgr conversion.
    
    in order to make this work for TCP, it was necessary to add a return
    code to the accept callback functions passed to isc_nm_listentcp() and
    isc_nm_listentcpdns().
    
    (cherry picked from commit 23c7373d)
    952461b6
  • Evan Hunt's avatar
    CHANGES, release note · 7a8e132c
    Evan Hunt authored
    (cherry picked from commit 08401e38)
    7a8e132c
  • Evan Hunt's avatar
    Merge branch '1936-blackhole-fix-v9_16' into 'v9_16' · f20bc90a
    Evan Hunt authored
    Resolve "blackhole ACL broken"
    
    See merge request !3776
    f20bc90a
  • Matthijs Mekking's avatar
    Move dst key printtime in separate function · 7915327a
    Matthijs Mekking authored
    I'd like to use the same functionality (pretty print the datetime
    of keytime metadata) in the 'rndc dnssec -status' command.  So it is
    better that this logic is done in a separate function.
    
    Since the stdtime.c code have differernt files for unix and win32,
    I think the "#ifdef WIN32" define can be dropped.
    
    (cherry picked from commit 9e03f8e8)
    7915327a
  • Matthijs Mekking's avatar
    Implement dummy 'rndc dnssec -status' command · 34a9c3f6
    Matthijs Mekking authored
    Add the code and documentation required to provide DNSSEC signing
    status through rndc.  This does not yet show any useful information,
    just provide the command that will output some dummy string.
    
    (cherry picked from commit e1ba1bea)
    34a9c3f6
  • Matthijs Mekking's avatar
    Output rndc dnssec -status · f1b3686c
    Matthijs Mekking authored
    Implement the 'rndc dnssec -status' command that will output
    some information about the key states, such as which policy is
    used for the zone, what keys are in use, and when rollover is
    scheduled.
    
    Add loose testing in the kasp system test, the actual times are
    already tested via key file inspection.
    
    (cherry picked from commit 19ce9ec1)
    f1b3686c
  • Matthijs Mekking's avatar
    Update notes, changes for #1612 · 2d9b282d
    Matthijs Mekking authored
    (cherry picked from commit e273b95a)
    2d9b282d
  • Matthijs Mekking's avatar
    Fix linking problem for #1612 · 752c779d
    Matthijs Mekking authored
    When a library is examined, an object file within it can be left out
    of the link if it does not provide symbols that the symbol table
    needs.  Introducing `isc_stdtime_tostring` caused a build failure for
    `update_test` because it now requires `libisc.a(stdtime.o)` and that
    also exports the `isc_stdtime_get` symbol, meaning we have a
    multiple definition error.
    
    Add a local version of `isc_stdtime_tostring`, so that the linker
    will not search for it in available object files.
    752c779d
5452. [bug] The "blackhole" ACL was accidentally disabled with
respect to client queries. [GL #1936]
5451. [func] Add 'rndc dnssec -status' command. [GL #1612]
5449. [bug] Fix a socket shutdown race in netmgr udp. [GL #1938]
5448. [bug] Fix a race condition in isc__nm_tcpdns_send().
......
......@@ -209,6 +209,8 @@ named_control_docommand(isccc_sexpr_t *message, bool readonly,
result = named_server_changezone(named_g_server, cmdline, text);
} else if (command_compare(command, NAMED_COMMAND_DELZONE)) {
result = named_server_delzone(named_g_server, lex, text);
} else if (command_compare(command, NAMED_COMMAND_DNSSEC)) {
result = named_server_dnssec(named_g_server, lex, text);
} else if (command_compare(command, NAMED_COMMAND_DNSTAP) ||
command_compare(command, NAMED_COMMAND_DNSTAPREOPEN))
{
......
......@@ -61,6 +61,7 @@
#define NAMED_COMMAND_SHOWZONE "showzone"
#define NAMED_COMMAND_SYNC "sync"
#define NAMED_COMMAND_SIGNING "signing"
#define NAMED_COMMAND_DNSSEC "dnssec"
#define NAMED_COMMAND_ZONESTATUS "zonestatus"
#define NAMED_COMMAND_NTA "nta"
#define NAMED_COMMAND_TESTGEN "testgen"
......
......@@ -333,6 +333,13 @@ isc_result_t
named_server_signing(named_server_t *server, isc_lex_t *lex,
isc_buffer_t **text);
/*%
* Lists the DNSSEC status for a given zone.
*/
isc_result_t
named_server_dnssec(named_server_t *server, isc_lex_t *lex,
isc_buffer_t **text);
/*%
* Lists status information for a given zone (e.g., name, type, files,
* load time, expiry, etc).
......
......@@ -58,6 +58,7 @@
#include <dns/dlz.h>
#include <dns/dns64.h>
#include <dns/dnsrps.h>
#include <dns/dnssec.h>
#include <dns/dyndb.h>
#include <dns/events.h>
#include <dns/fixedname.h>
......@@ -65,6 +66,7 @@
#include <dns/geoip.h>
#include <dns/journal.h>
#include <dns/kasp.h>
#include <dns/keymgr.h>
#include <dns/keytable.h>
#include <dns/keyvalues.h>
#include <dns/lib.h>
......@@ -14465,6 +14467,83 @@ cleanup:
return (result);
}
isc_result_t
named_server_dnssec(named_server_t *server, isc_lex_t *lex,
isc_buffer_t **text) {
isc_result_t result = ISC_R_SUCCESS;
dns_zone_t *zone = NULL;
dns_kasp_t *kasp = NULL;
dns_dnsseckeylist_t keys;
dns_dnsseckey_t *key;
const char *ptr;
/* variables for -status */
char output[BUFSIZ];
isc_stdtime_t now;
isc_time_t timenow;
const char *dir;
/* Skip the command name. */
ptr = next_token(lex, text);
if (ptr == NULL) {
return (ISC_R_UNEXPECTEDEND);
}
/* Find out what we are to do. */
ptr = next_token(lex, text);
if (ptr == NULL) {
return (ISC_R_UNEXPECTEDEND);
}
if (strcasecmp(ptr, "-status") != 0) {
return (DNS_R_SYNTAX);
}
ISC_LIST_INIT(keys);
CHECK(zone_from_args(server, lex, NULL, &zone, NULL, text, false));
if (zone == NULL) {
CHECK(ISC_R_UNEXPECTEDEND);
}
kasp = dns_zone_getkasp(zone);
if (kasp == NULL) {
CHECK(putstr(text, "zone does not have dnssec-policy"));
CHECK(putnull(text));
goto cleanup;
}
/* -status */
TIME_NOW(&timenow);
now = isc_time_seconds(&timenow);
dir = dns_zone_getkeydirectory(zone);
LOCK(&kasp->lock);
result = dns_dnssec_findmatchingkeys(dns_zone_getorigin(zone), dir, now,
dns_zone_getmctx(zone), &keys);
UNLOCK(&kasp->lock);
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
goto cleanup;
}
LOCK(&kasp->lock);
dns_keymgr_status(kasp, &keys, now, &output[0], sizeof(output));
UNLOCK(&kasp->lock);
CHECK(putstr(text, output));
CHECK(putnull(text));
cleanup:
while (!ISC_LIST_EMPTY(keys)) {
key = ISC_LIST_HEAD(keys);
ISC_LIST_UNLINK(keys, key, link);
dns_dnsseckey_destroy(dns_zone_getmctx(zone), &key);
}
if (zone != NULL) {
dns_zone_detach(&zone);
}
return (result);
}
static isc_result_t
putmem(isc_buffer_t **b, const char *str, size_t len) {
isc_result_t result;
......
......@@ -104,6 +104,9 @@ command is one of the following:\n\
Add zone to given view. Requires allow-new-zones option.\n\
delzone [-clean] zone [class [view]]\n\
Removes zone from given view.\n\
dnssec -status zone [class [view]]\n\
Show the DNSSEC signing state for the specified zone.\n\
Requires the zone to have a dnssec-policy.\n\
dnstap -reopen\n\
Close, truncate and re-open the DNSTAP output file.\n\
dnstap -roll count\n\
......
......@@ -162,6 +162,10 @@ Currently supported commands are:
See also ``rndc addzone`` and ``rndc modzone``.
``dnssec`` [**-status** *zone* [*class* [*view*]]
Show the DNSSEC signing state for the specified zone. Requires the
zone to have a "dnssec-policy".
``dnstap`` ( **-reopen** | **-roll** [*number*] )
Close and re-open DNSTAP output files. ``rndc dnstap -reopen`` allows
the output file to be renamed externally, so that :manpage:`named(8)` can
......
......@@ -31,6 +31,7 @@ options {
ixfr-from-differences yes;
check-integrity no;
allow-query-on { 10.53.0.2; };
blackhole { 10.53.0.8; };
};
key one {
......
......@@ -144,6 +144,26 @@ $DIG -p ${PORT} +tcp soa example. \
@10.53.0.2 -b 10.53.0.3 > dig.out.${t}
grep "status: NOERROR" dig.out.${t} > /dev/null 2>&1 || { echo_i "test $t failed" ; status=1; }
echo_i "testing blackhole ACL processing"
t=`expr $t + 1`
ret=0
$DIG -p ${PORT} +tcp soa example. \
@10.53.0.2 -b 10.53.0.3 > dig.out.1.${t}
grep "status: NOERROR" dig.out.1.${t} > /dev/null 2>&1 || ret=1
$DIG -p ${PORT} +tcp soa example. \
@10.53.0.2 -b 10.53.0.8 > dig.out.2.${t}
grep "status: NOERROR" dig.out.2.${t} > /dev/null 2>&1 && ret=1
grep "communications error" dig.out.2.${t} > /dev/null 2>&1 || ret=1
$DIG -p ${PORT} soa example. \
@10.53.0.2 -b 10.53.0.3 > dig.out.3.${t}
grep "status: NOERROR" dig.out.3.${t} > /dev/null 2>&1 || ret=1
$DIG -p ${PORT} soa example. \
@10.53.0.2 -b 10.53.0.8 > dig.out.4.${t}
grep "status: NOERROR" dig.out.4.${t} > /dev/null 2>&1 && ret=1
grep "connection timed out" dig.out.4.${t} > /dev/null 2>&1 || ret=1
[ $ret -eq 0 ] || echo_i "failed"
status=`expr $status + $ret`
# AXFR tests against ns3
echo_i "testing allow-transfer ACLs against ns3 (no existing zones)"
......
......@@ -24,4 +24,5 @@ rm -f ns*/managed-keys.bind
rm -f ns*/*.mkeys
rm -f ns*/zones ns*/*.db.infile
rm -f *.created published.test* retired.test*
rm -f rndc.dnssec.status.out.*
rm -f python.out.*
......@@ -11,6 +11,15 @@
// NS4
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
key "sha1" {
algorithm "hmac-sha1";
secret "FrSt77yPTFx6hTs4i2tKLB9LmE0=";
......
......@@ -11,6 +11,15 @@
// NS5
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
key "sha1" {
algorithm "hmac-sha1";
secret "FrSt77yPTFx6hTs4i2tKLB9LmE0=";
......
This diff is collapsed.
......@@ -162,6 +162,10 @@ back. To remove it permanently, it must also be removed from
.sp
See also \fBrndc addzone\fP and \fBrndc modzone\fP\&.
.TP
\fBdnssec\fP [\fB\-status\fP \fIzone\fP [\fIclass\fP [\fIview\fP]]
Show the DNSSEC signing state for the specified zone. Requires the
zone to have a "dnssec\-policy".
.TP
\fBdnstap\fP ( \fB\-reopen\fP | \fB\-roll\fP [\fInumber\fP] )
Close and re\-open DNSTAP output files. \fBrndc dnstap \-reopen\fP allows
the output file to be renamed externally, so that \fBnamed(8)\fP can
......
......@@ -29,7 +29,9 @@ New Features
Feature Changes
~~~~~~~~~~~~~~~
- None.
- New ``rndc`` command ``rndc dnssec -status`` that shows the current
DNSSEC policy and keys in use, the key states and rollover status.
[GL #1612]
Bug Fixes
~~~~~~~~~
......@@ -52,3 +54,8 @@ Bug Fixes
unsupported algorithm appeared earlier in the DNSKEY RRset than a
supported algorithm. It could also stop if it detected a malformed
public key. [GL #1689]
- The ``blackhole`` ACL was inadvertently disabled with respect to
client queries. Blocked IP addresses were not used for upstream
queries but queries from those addresses could still be answered.
[GL #1936]
......@@ -1906,7 +1906,6 @@ printtime(const dst_key_t *key, int type, const char *tag, FILE *stream) {
isc_result_t result;
char output[26]; /* Minimum buffer as per ctime_r() specification. */
isc_stdtime_t when;
time_t t;
char utc[sizeof("YYYYMMDDHHSSMM")];
isc_buffer_t b;
isc_region_t r;
......@@ -1916,18 +1915,7 @@ printtime(const dst_key_t *key, int type, const char *tag, FILE *stream) {
return;
}
/* time_t and isc_stdtime_t might be different sizes */
t = when;
#ifdef WIN32
if (ctime_s(output, sizeof(output), &t) != 0) {
goto error;
}
#else /* ifdef WIN32 */
if (ctime_r(&t, output) == NULL) {
goto error;
}
#endif /* ifdef WIN32 */
isc_stdtime_tostring(when, output, sizeof(output));
isc_buffer_init(&b, utc, sizeof(utc));
result = dns_time32_totext(when, &b);
if (result != ISC_R_SUCCESS) {
......
......@@ -51,6 +51,23 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
*\li On error, keypool is unchanged
*/
void
dns_keymgr_status(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
isc_stdtime_t now, char *out, size_t out_len);
/*%<
* Retrieve the status of given 'kasp' policy and keys in the
* 'keyring' and store the printable output in the 'out' buffer.
*
* Requires:
*\li 'kasp' is not NULL.
*\li 'keyring' is not NULL.
*\li 'out' is not NULL.
*
* Returns:
*\li Printable status in 'out'.
*
*/
ISC_LANG_ENDDECLS
#endif /* DNS_KEYMGR_H */
......@@ -1841,3 +1841,204 @@ failure:
return (result);
}
static void
keytime_status(dst_key_t *key, isc_stdtime_t now, isc_buffer_t *buf,
const char *pre, int ks, int kt) {
char timestr[26]; /* Minimal buf as per ctime_r() spec. */
isc_result_t ret;
isc_stdtime_t when = 0;
dst_key_state_t state;
isc_buffer_printf(buf, "%s", pre);
(void)dst_key_getstate(key, ks, &state);
ret = dst_key_gettime(key, kt, &when);
if (state == RUMOURED || state == OMNIPRESENT) {
isc_buffer_printf(buf, "yes - since ");
} else if (now < when) {
isc_buffer_printf(buf, "no - scheduled ");
} else {
isc_buffer_printf(buf, "no\n");
return;
}
if (ret == ISC_R_SUCCESS) {
isc_stdtime_tostring(when, timestr, sizeof(timestr));
isc_buffer_printf(buf, "%s\n", timestr);
}
}
static void
rollover_status(dns_dnsseckey_t *dkey, dns_kasp_t *kasp, isc_stdtime_t now,
isc_buffer_t *buf, bool zsk) {
char timestr[26]; /* Minimal buf as per ctime_r() spec. */
isc_result_t ret = ISC_R_SUCCESS;
isc_stdtime_t active_time = 0;
dst_key_state_t state = NA, goal = NA;
int rrsig, active, retire;
dst_key_t *key = dkey->key;
if (zsk) {
rrsig = DST_KEY_ZRRSIG;
active = DST_TIME_ACTIVATE;
retire = DST_TIME_INACTIVE;
} else {
rrsig = DST_KEY_KRRSIG;
active = DST_TIME_PUBLISH;
retire = DST_TIME_DELETE;
}
isc_buffer_printf(buf, "\n");
(void)dst_key_getstate(key, DST_KEY_GOAL, &goal);
(void)dst_key_getstate(key, rrsig, &state);
(void)dst_key_gettime(key, active, &active_time);
if (active_time == 0) {
// only interested in keys that were once active.
return;
}
if (goal == HIDDEN && (state == UNRETENTIVE || state == HIDDEN)) {
isc_stdtime_t remove_time = 0;
// is the key removed yet?
state = NA;
(void)dst_key_getstate(key, DST_KEY_DNSKEY, &state);
if (state == RUMOURED || state == OMNIPRESENT) {
ret = dst_key_gettime(key, DST_TIME_DELETE,
&remove_time);
if (ret == ISC_R_SUCCESS) {
isc_buffer_printf(buf, " Key is retired, will "
"be removed on ");
isc_stdtime_tostring(remove_time, timestr,
sizeof(timestr));
isc_buffer_printf(buf, "%s", timestr);
}
} else {
isc_buffer_printf(
buf, " Key has been removed from the zone");
}
} else {
isc_stdtime_t retire_time = 0;
uint32_t lifetime = 0;
(void)dst_key_getnum(key, DST_NUM_LIFETIME, &lifetime);
ret = dst_key_gettime(key, retire, &retire_time);
if (ret == ISC_R_SUCCESS) {
if (now < retire_time) {
if (goal == OMNIPRESENT) {
isc_buffer_printf(buf,
" Next rollover "
"scheduled on ");
retire_time = keymgr_prepublication_time(
dkey, kasp, lifetime, now);
} else {
isc_buffer_printf(
buf, " Key will retire on ");
}
} else {
isc_buffer_printf(buf,
" Rollover is due since ");
}
isc_stdtime_tostring(retire_time, timestr,
sizeof(timestr));
isc_buffer_printf(buf, "%s", timestr);
} else {
isc_buffer_printf(buf, " No rollover scheduled");
}
}
isc_buffer_printf(buf, "\n");
}
static void
keystate_status(dst_key_t *key, isc_buffer_t *buf, const char *pre, int ks) {
dst_key_state_t state = NA;
(void)dst_key_getstate(key, ks, &state);
switch (state) {
case HIDDEN:
isc_buffer_printf(buf, " - %shidden\n", pre);
break;
case RUMOURED:
isc_buffer_printf(buf, " - %srumoured\n", pre);
break;
case OMNIPRESENT:
isc_buffer_printf(buf, " - %somnipresent\n", pre);
break;
case UNRETENTIVE:
isc_buffer_printf(buf, " - %sunretentive\n", pre);
break;
case NA:
default:
/* print nothing */
break;
}
}
void
dns_keymgr_status(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
isc_stdtime_t now, char *out, size_t out_len) {
isc_buffer_t buf;
char timestr[26]; /* Minimal buf as per ctime_r() spec. */
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(keyring != NULL);
REQUIRE(out != NULL);
isc_buffer_init(&buf, out, out_len);
// policy name
isc_buffer_printf(&buf, "dnssec-policy: %s\n", dns_kasp_getname(kasp));
isc_buffer_printf(&buf, "current time: ");
isc_stdtime_tostring(now, timestr, sizeof(timestr));
isc_buffer_printf(&buf, "%s\n", timestr);
for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring); dkey != NULL;
dkey = ISC_LIST_NEXT(dkey, link))
{
char algstr[DNS_NAME_FORMATSIZE];
bool ksk = false, zsk = false;
if (dst_key_is_unused(dkey->key)) {
continue;
}
// key data
dst_key_getbool(dkey->key, DST_BOOL_KSK, &ksk);
dst_key_getbool(dkey->key, DST_BOOL_ZSK, &zsk);
dns_secalg_format((dns_secalg_t)dst_key_alg(dkey->key), algstr,
sizeof(algstr));
isc_buffer_printf(&buf, "\nkey: %d (%s), %s\n",
dst_key_id(dkey->key), algstr,
keymgr_keyrole(dkey->key));
// publish status
keytime_status(dkey->key, now, &buf,
" published: ", DST_KEY_DNSKEY,
DST_TIME_PUBLISH);
// signing status
if (ksk) {
keytime_status(dkey->key, now, &buf,
" key signing: ", DST_KEY_KRRSIG,
DST_TIME_PUBLISH);
}
if (zsk) {
keytime_status(dkey->key, now, &buf,
" zone signing: ", DST_KEY_ZRRSIG,
DST_TIME_ACTIVATE);
}
// rollover status
rollover_status(dkey, kasp, now, &buf, zsk);
// key states
keystate_status(dkey->key, &buf,
"goal: ", DST_KEY_GOAL);
keystate_status(dkey->key, &buf,
"dnskey: ", DST_KEY_DNSKEY);
keystate_status(dkey->key, &buf,
"ds: ", DST_KEY_DS);
keystate_status(dkey->key, &buf,
"zone rrsig: ", DST_KEY_ZRRSIG);
keystate_status(dkey->key, &buf,
"key rrsig: ", DST_KEY_KRRSIG);
}
}
......@@ -75,11 +75,34 @@ set_mystdtime(int year, int month, int day) {
mystdtime = timegm(&tm);
}
/*
* Override isc_stdtime_get() from lib/isc/[unix/win32]/stdtime.c
* with our own for testing purposes.
*/
void
isc_stdtime_get(isc_stdtime_t *now) {
*now = mystdtime;
}
/*
* Because update_test.o requires dns_update_*() symbols, the linker is able
* to resolve them using libdns.a(update.o). That object has other symbol
* dependencies (dst_key_*()), so it pulls libdns.a(dst_api.o).
* That object file requires the isc_stdtime_tostring() symbol.
*
* Define a local version here so that we don't have to depend on
* libisc.a(stdtime.o). If isc_stdtime_tostring() would be left undefined,
* the linker has to get the required object file, and that will result in a
* multiple definition error because the isc_stdtime_get() symbol exported
* there is already in the exported list.
*/
void
isc_stdtime_tostring(isc_stdtime_t t, char* out, size_t outlen) {
UNUSED(t);
UNUSED(out);
UNUSED(outlen);
}
/* simple increment by 1 */
static void
increment_test(void **state) {
......
......@@ -472,6 +472,7 @@ dns_keydata_fromdnskey
dns_keydata_todnskey
dns_keyflags_fromtext
dns_keymgr_run
dns_keymgr_status
dns_keynode_dsset
dns_keynode_initial
dns_keynode_managed
......
......@@ -24,6 +24,47 @@ typedef enum {
NMEV_SHUTDOWN
} isc_nm_eventtype;
typedef void (*isc_nm_recv_cb_t)(isc_nmhandle_t *handle, isc_region_t *region,
void *cbarg);
/*%<
* Callback function to be used when receiving a packet.
*
* 'handle' the handle that can be used to send back the answer.
* 'region' contains the received data. It will be freed after
* return by caller.
* 'cbarg' the callback argument passed to isc_nm_listenudp(),
* isc_nm_listentcpdns(), or isc_nm_read().
*/
typedef isc_result_t (*isc_nm_accept_cb_t)(isc_nmhandle_t *handle,
isc_result_t result, void *cbarg);
/*%<
* Callback function to be used when accepting a connection. (This differs
* from isc_nm_cb_t below in that it returns a result code.)
*
* 'handle' the handle that can be used to send back the answer.
* 'eresult' the result of the event.
* 'cbarg' the callback argument passed to isc_nm_listentcp() or
* isc_nm_listentcpdns().
*/
typedef void (*isc_nm_cb_t)(isc_nmhandle_t *handle, isc_result_t result,
void *cbarg);
/*%<
* Callback function for other network completion events (send, connect).
*
* 'handle' the handle on which the event took place.
* 'eresult' the result of the event.
* 'cbarg' the callback argument passed to isc_nm_send(),
* isc_nm_tcp_connect(), or isc_nm_listentcp()
*/
typedef void (*isc_nm_opaquecb_t)(void *arg);
/*%<
* Opaque callback function, used for isc_nmhandle 'reset' and 'free'
* callbacks.
*/
isc_nm_t *
isc_nm_start(isc_mem_t *mctx, uint32_t workers);
/*%<
......@@ -102,8 +143,6 @@ isc_nmhandle_getdata(isc_nmhandle_t *handle);
void *
isc_nmhandle_getextra(isc_nmhandle_t *handle);
typedef void (*isc_nm_opaquecb_t)(void *arg);
bool
isc_nmhandle_is_stream(isc_nmhandle_t *handle);
......@@ -135,30 +174,6 @@ isc_nmhandle_netmgr(isc_nmhandle_t *handle);
* Return a pointer to the netmgr object for the given handle.
*/
typedef void (*isc_nm_recv_cb_t)(isc_nmhandle_t *handle, isc_region_t *region,
void *cbarg);
/*%<
* Callback function to be used when receiving a packet.
*
* 'handle' the handle that can be used to send back the answer.
* 'region' contains the received data. It will be freed after
* return by caller.
* 'cbarg' the callback argument passed to isc_nm_listenudp(),
* isc_nm_listentcpdns(), or isc_nm_read().
*/
typedef void (*isc_nm_cb_t)(isc_nmhandle_t *handle, isc_result_t result,
void *cbarg);
/*%<
* Callback function for other network completion events (send, connect,
* accept).
*
* 'handle' the handle on which the event took place.
* 'result' the result of the event.
* 'cbarg' the callback argument passed to isc_nm_send(),
* isc_nm_tcp_connect(), or isc_nm_listentcp()
*/
isc_result_t
isc_nm_listenudp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
void *cbarg, size_t extrasize, isc_nmsocket_t **sockp);
......@@ -227,9 +242,10 @@ isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
*/
isc_result_t
isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_cb_t cb,
void *cbarg, size_t extrahandlesize, int backlog,
isc_quota_t *quota, isc_nmsocket_t **sockp);
isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface,
isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
size_t extrahandlesize, int backlog, isc_quota_t *quota,
isc_nmsocket_t **sockp);
/*%<
* Start listening for raw messages over the TCP interface 'iface', using
* net manager 'mgr'.
......@@ -237,8 +253,8 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_cb_t cb,
* On success, 'sockp' will be updated to contain a new listening TCP
* socket.
*
* When a message is received on the socket, 'cb' will be called with 'cbarg'
* as its argument.
* When connection is accepted on the socket, 'accept_cb' will be called with
* 'accept_cbarg' as its argument. The callback is expected to start a read.
*
* When handles are allocated for the socket, 'extrasize' additional bytes
* will be allocated along with the handle for an associated object.
......@@ -253,9 +269,9 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_cb_t cb,
isc_result_t
isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
void *cbarg, isc_nm_cb_t accept_cb, void *accept_cbarg,
size_t extrahandlesize, int backlog, isc_quota_t *quota,
isc_nmsocket_t **sockp);
void *cbarg, isc_nm_accept_cb_t accept_cb,
void *accept_cbarg, size_t extrahandlesize, int backlog,
isc_quota_t *quota, isc_nmsocket_t **sockp);
/*%<
* Start listening for DNS messages over the TCP interface 'iface', using
* net manager 'mgr'.
......@@ -269,7 +285,7 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
* When a complete DNS message is received on the socket, 'cb' will be
* called with 'cbarg' as its argument.
*
* When a new TCP connection is accepted, 'accept_cb' will be called
* When a new TCPDNS connection is accepted, 'accept_cb' will be called
* with 'accept_cbarg' as its argument.
*
* When handles are allocated for the socket, 'extrasize' additional bytes
......
......@@ -158,7 +158,7 @@ typedef enum isc__netievent_type {
*/
typedef union {
isc_nm_recv_cb_t recv;
isc_nm_cb_t accept;
isc_nm_accept_cb_t accept;
} isc__nm_readcb_t;
typedef union {
......@@ -168,7 +168,7 @@ typedef union {
typedef union {
isc_nm_recv_cb_t recv;
isc_nm_cb_t accept;
isc_nm_accept_cb_t accept;
isc_nm_cb_t send;
isc_nm_cb_t connect;
} isc__nm_cb_t;
......
......@@ -160,9 +160,10 @@ tcp_connect_cb(uv_connect_t *uvreq, int status) {
}
isc_result_t
isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_cb_t cb,
void *cbarg, size_t extrahandlesize, int backlog,
isc_quota_t *quota, isc_nmsocket_t **sockp) {
isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface,
isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
size_t extrahandlesize, int backlog, isc_quota_t *quota,
isc_nmsocket_t **sockp) {
isc_nmsocket_t *nsock = NULL;
isc__netievent_tcplisten_t *ievent = NULL;
......@@ -170,8 +171,8 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_cb_t cb,
nsock = isc_mem_get(mgr->mctx, sizeof(*nsock));
isc__nmsocket_init(nsock, mgr, isc_nm_tcplistener, iface);
nsock->rcb.accept = cb;
nsock->rcbarg = cbarg;
nsock->accept_cb.accept = accept_cb;
nsock->accept_cbarg = accept_cbarg;
nsock->extrahandlesize = extrahandlesize;
nsock->backlog = backlog;
nsock->result = ISC_R_SUCCESS;
......@@ -383,9 +384,9 @@ isc__nm_async_tcpchildaccept(isc__networker_t *worker, isc__netievent_t *ev0) {
handle = isc__nmhandle_get(csock, NULL, &local);
INSIST(ssock->rcb.accept != NULL);
INSIST(ssock->accept_cb.accept != NULL);
csock->read_timeout = ssock->mgr->init;
ssock->rcb.accept(handle, ISC_R_SUCCESS, ssock->rcbarg);
ssock->accept_cb.accept(handle, ISC_R_SUCCESS, ssock->accept_cbarg);
isc_nmsocket_detach(&csock);
return;
......
......@@ -98,7 +98,7 @@ dnstcp_readtimeout(uv_timer_t *timer) {
/*
* Accept callback for TCP-DNS connection.
*/
static void
static isc_result_t
dnslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
isc_nmsocket_t *dnslistensock = (isc_nmsocket_t *)cbarg;
isc_nmsocket_t *dnssock = NULL;
......@@ -106,14 +106,16 @@ dnslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
REQUIRE(VALID_NMSOCK(dnslistensock));
REQUIRE(dnslistensock->type == isc_nm_tcpdnslistener);
/* If accept() was unnsuccessful we can't do anything */
if (result != ISC_R_SUCCESS) {
return;
return (result);
}
if (dnslistensock->accept_cb.accept != NULL) {
dnslistensock->accept_cb.accept(handle, ISC_R_SUCCESS,
dnslistensock->accept_cbarg);
result = dnslistensock->accept_cb.accept(
handle, ISC_R_SUCCESS, dnslistensock->accept_cbarg);
if (result != ISC_R_SUCCESS) {
return (result);
}
}
/* We need to create a 'wrapper' dnssocket for this connection */
......@@ -137,6 +139,8 @@ dnslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
dnssock->read_timeout, 0);
isc_nm_read(handle, dnslisten_readcb, dnssock);
return (ISC_R_SUCCESS);
}
/*
......@@ -283,9 +287,9 @@ dnslisten_readcb(isc_nmhandle_t *handle, isc_region_t *region, void *arg) {
*/
isc_result_t
isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
void *cbarg, isc_nm_cb_t accept_cb, void *accept_cbarg,
size_t extrahandlesize, int backlog, isc_quota_t *quota,
isc_nmsocket_t **sockp) {
void *cbarg, isc_nm_accept_cb_t accept_cb,
void *accept_cbarg, size_t extrahandlesize, int backlog,
isc_quota_t *quota, isc_nmsocket_t **sockp) {
/* A 'wrapper' socket object with outer set to true TCP socket */
isc_nmsocket_t *dnslistensock = isc_mem_get(mgr->mctx,
sizeof(*dnslistensock));
......
......@@ -15,6 +15,7 @@
/*! \file */
#include <inttypes.h>
#include <stdlib.h>
#include <isc/lang.h>
......@@ -37,6 +38,20 @@ isc_stdtime_get(isc_stdtime_t *t);
*\li 't' is a valid pointer.
*/
void
isc_stdtime_tostring(isc_stdtime_t t, char *out, size_t outlen);
/*
* Convert 't' into a null-terminated string of the form
* "Wed Jun 30 21:49:08 1993". Store the string in the 'out'
* buffer.
*
* Requires:
*
* 't' is a valid time.
* 'out' is a valid pointer.
* 'outlen' is at least 26.
*/
#define isc_stdtime_convert32(t, t32p) (*(t32p) = t)
/*
* Convert the standard time to its 32-bit version.
......
......@@ -49,3 +49,18 @@ isc_stdtime_get(isc_stdtime_t *t) {
*t = (isc_stdtime_t)ts.tv_sec;
}
void
isc_stdtime_tostring(isc_stdtime_t t, char *out, size_t outlen) {
time_t when;
REQUIRE(out != NULL);
REQUIRE(outlen >= 26);
UNUSED(outlen);
/* time_t and isc_stdtime_t might be different sizes */
when = t;
INSIST((ctime_r(&when, out) != NULL));
*(out + strlen(out) - 1) = '\0';
}
......@@ -13,6 +13,7 @@
#define ISC_STDTIME_H 1
#include <inttypes.h>
#include <stdlib.h>
#include <isc/lang.h>
......@@ -35,6 +36,20 @@ isc_stdtime_get(isc_stdtime_t *t);
* 't' is a valid pointer.
*/
void
isc_stdtime_tostring(isc_stdtime_t t, char *out, size_t outlen);
/*
* Convert 't' into a null-terminated string of the form
* "Wed Jun 30 21:49:08 1993". Store the string in the 'out'
* buffer.
*
* Requires:
*
* 't' is a valid time.
* 'out' is a valid pointer.
* 'outlen' is at least 26.
*/
#define isc_stdtime_convert32(t, t32p) (*(t32p) = t)
/*
* Convert the standard time to its 32-bit version.
......
......@@ -606,6 +606,7 @@ isc_stdio_sync
isc_stdio_tell
isc_stdio_write
isc_stdtime_get
isc_stdtime_tostring
isc_string_strerror_r
isc_symtab_count
isc_symtab_create
......
......@@ -25,3 +25,17 @@ isc_stdtime_get(isc_stdtime_t *t) {
(void)_time32(t);
}
void
isc_stdtime_tostring(isc_stdtime_t t, char *out, size_t outlen) {
time_t when;
REQUIRE(out != NULL);
/* Minimum buffer as per ctime_r() specification. */
REQUIRE(outlen >= 26);
/* time_t and isc_stdtime_t might be different sizes */
when = t;
INSIST((ctime_s(out, outlen, &when) == 0));
*(out + strlen(out) - 1) = '\0';
}
......@@ -1617,7 +1617,6 @@ ns__client_put_cb(void *client0) {
void
ns__client_request(isc_nmhandle_t *handle, isc_region_t *region, void *arg) {
ns_client_t *client;
bool newclient = false;
ns_clientmgr_t *mgr;
ns_interface_t *ifp;
isc_result_t result;
......@@ -1714,29 +1713,23 @@ ns__client_request(isc_nmhandle_t *handle, isc_region_t *region, void *arg) {
}
#endif /* if NS_CLIENT_DROPPORT */
env = ns_interfacemgr_getaclenv(client->manager->interface->mgr);
if (client->sctx->blackholeacl != NULL &&
(dns_acl_match(&netaddr, NULL, client->sctx->blackholeacl, env,
&match, NULL) == ISC_R_SUCCESS) &&
match > 0)
{
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),
"dropped request: blackholed peer");
isc_task_unpause(client->task);
return;
}
ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT,
ISC_LOG_DEBUG(3), "%s request",
TCP_CLIENT(client) ? "TCP" : "UDP");
/*
* Check the blackhole ACL for UDP only, since TCP is done in
* client_newconn.
*/
env = ns_interfacemgr_getaclenv(client->manager->interface->mgr);
if (newclient) {
if (client->sctx->blackholeacl != NULL &&
(dns_acl_match(&netaddr, NULL, client->sctx->blackholeacl,
env, &match, NULL) == ISC_R_SUCCESS) &&
match > 0)
{
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),
"blackholed UDP datagram");
isc_task_unpause(client->task);
return;
}
}
result = dns_message_peekheader(buffer, &id, &flags);
if (result != ISC_R_SUCCESS) {
/*
......@@ -2197,17 +2190,36 @@ ns__client_request(isc_nmhandle_t *handle, isc_region_t *region, void *arg) {
isc_task_unpause(client->task);
}
void
isc_result_t
ns__client_tcpconn(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
ns_server_t *sctx = (ns_server_t *)arg;
ns_interface_t *ifp = (ns_interface_t *)arg;
dns_aclenv_t *env = ns_interfacemgr_getaclenv(ifp->mgr);
ns_server_t *sctx = ns_interfacemgr_getserver(ifp->mgr);
unsigned int tcpquota;
isc_sockaddr_t peeraddr;
isc_netaddr_t netaddr;
int match;
UNUSED(handle);
UNUSED(result);
if (handle != NULL) {
peeraddr = isc_nmhandle_peeraddr(handle);
isc_netaddr_fromsockaddr(&netaddr, &peeraddr);
if (sctx->blackholeacl != NULL &&
(dns_acl_match(&netaddr, NULL, sctx->blackholeacl, env,
&match, NULL) == ISC_R_SUCCESS) &&
match > 0)
{
return (ISC_R_CONNREFUSED);
}
}
tcpquota = isc_quota_getused(&sctx->tcpquota);
ns_stats_update_if_greater(sctx->nsstats, ns_statscounter_tcphighwater,
tcpquota);
return (ISC_R_SUCCESS);
}
static void
......
......@@ -475,7 +475,7 @@ ns__client_request(isc_nmhandle_t *handle, isc_region_t *region, void *arg);
* (Not intended for use outside this module and associated tests.)
*/
void
isc_result_t
ns__client_tcpconn(isc_nmhandle_t *handle, isc_result_t result, void *arg);
/*%<
......
......@@ -197,6 +197,12 @@ ns_interfacemgr_dumprecursing(FILE *f, ns_interfacemgr_t *mgr);
bool
ns_interfacemgr_listeningon(ns_interfacemgr_t *mgr, const isc_sockaddr_t *addr);
ns_server_t *
ns_interfacemgr_getserver(ns_interfacemgr_t *mgr);
/*%<
* Returns the ns_server object associated with the interface manager.
*/
ns_interface_t *
ns__interfacemgr_getif(ns_interfacemgr_t *mgr);
ns_interface_t *
......
......@@ -467,7 +467,7 @@ ns_interface_listentcp(ns_interface_t *ifp) {
result = isc_nm_listentcpdns(
ifp->mgr->nm, (isc_nmiface_t *)&ifp->addr, ns__client_request,
ifp, ns__client_tcpconn, ifp->mgr->sctx, sizeof(ns_client_t),
ifp, ns__client_tcpconn, ifp, sizeof(ns_client_t),
ifp->mgr->backlog, &ifp->mgr->sctx->tcpquota,
&ifp->tcplistensocket);
if (result != ISC_R_SUCCESS) {
......@@ -481,7 +481,12 @@ ns_interface_listentcp(ns_interface_t *ifp) {
* this is necessary because we are adding to the TCP quota just
* by listening.
*/
ns__client_tcpconn(NULL, ISC_R_SUCCESS, ifp->mgr->sctx);
result = ns__client_tcpconn(NULL, ISC_R_SUCCESS, ifp);
if (result != ISC_R_SUCCESS) {
isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
"connecting TCP socket: %s",
isc_result_totext(result));
}
#if 0
#ifndef ISC_ALLOW_MAPPED
......@@ -1267,6 +1272,13 @@ ns_interfacemgr_listeningon(ns_interfacemgr_t *mgr,
return (result);
}
ns_server_t *
ns_interfacemgr_getserver(ns_interfacemgr_t *mgr) {
REQUIRE(NS_INTERFACEMGR_VALID(mgr));
return (mgr->sctx);
}
ns_interface_t *
ns__interfacemgr_getif(ns_interfacemgr_t *mgr) {
ns_interface_t *head;
......
......@@ -55,6 +55,7 @@ ns_interfacemgr_create
ns_interfacemgr_detach
ns_interfacemgr_dumprecursing
ns_interfacemgr_getaclenv
ns_interfacemgr_getserver
ns_interfacemgr_islistening
ns_interfacemgr_listeningon
ns_interfacemgr_scan
......