qstate->env->cfg->ipsecmod_max_ttl;
qstate->return_msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(
qstate->return_msg->rep->ttl);
+ qstate->return_msg->rep->serve_expired_ttl = qstate->return_msg->rep->ttl +
+ qstate->env->cfg->serve_expired_ttl;
}
}
}
* EDNS0 OPT RR in the additional section appended on sending it out),
* so the total number of RRsets is an_numrrsets. */
new_rep = construct_reply_info_base(region, rep->flags,
- rep->qdcount, rep->ttl, rep->prefetch_ttl, an_numrrsets,
- 0, 0, an_numrrsets, sec_status_insecure);
+ rep->qdcount, rep->ttl, rep->prefetch_ttl,
+ rep->serve_expired_ttl, an_numrrsets, 0, 0, an_numrrsets,
+ sec_status_insecure);
if(!new_rep)
return NULL;
if(!reply_info_alloc_rrset_keys(new_rep, NULL, region))
c.fd = -1;
c.buffer = sldns_buffer_new(runtime->bufsize);
c.type = comm_udp;
- if(pend->transport == transport_tcp)
+ if(pend->transport == transport_tcp) {
c.type = comm_tcp;
+ c.tcp_timeout_msec = 30000;
+ c.tcp_keepalive = runtime->tcp_seen_keepalive;
+ }
fill_buffer_with_reply(c.buffer, entry, pend->pkt, pend->pkt_len,
pend->tcp_pkt_counter);
repinfo.c = &c;
else runtime->answer_list = ans->next;
if(!ans->next)
runtime->answer_last = prev;
+ if(ans->repinfo.c->tcp_keepalive)
+ runtime->tcp_seen_keepalive = 1;
delete_replay_answer(ans);
return;
} else {
repinfo.c->fd = -1;
repinfo.c->ev = (struct internal_event*)runtime;
repinfo.c->buffer = sldns_buffer_new(runtime->bufsize);
- if(todo->match->match_transport == transport_tcp)
+ if(todo->match->match_transport == transport_tcp) {
repinfo.c->type = comm_tcp;
- else repinfo.c->type = comm_udp;
+ repinfo.c->tcp_timeout_msec = 30000;
+ repinfo.c->tcp_keepalive = runtime->tcp_seen_keepalive;
+ } else
+ repinfo.c->type = comm_udp;
fill_buffer_with_reply(repinfo.c->buffer, todo->match, NULL, 0, 0);
log_info("testbound: incoming QUERY");
log_pkt("query pkt", todo->match->reply_list->reply_pkt,
cb = p->callback;
c.buffer = sldns_buffer_new(runtime->bufsize);
c.type = comm_udp;
- if(p->transport == transport_tcp)
+ if(p->transport == transport_tcp) {
c.type = comm_tcp;
+ c.tcp_timeout_msec = 30000;
+ c.tcp_keepalive = runtime->tcp_seen_keepalive;
+ }
if(todo->evt_type == repevt_back_reply && todo->match) {
fill_buffer_with_reply(c.buffer, todo->match, p->pkt,
p->pkt_len, p->tcp_pkt_counter);
struct listen_dnsport*
listen_create(struct comm_base* base, struct listen_port* ATTR_UNUSED(ports),
size_t bufsize, int ATTR_UNUSED(tcp_accept_count),
+ int ATTR_UNUSED(tcp_idle_timeout),
+ struct tcl_list* ATTR_UNUSED(tcp_conn_limit),
void* ATTR_UNUSED(sslctx), struct dt_env* ATTR_UNUSED(dtenv),
comm_point_callback_type* cb, void* cb_arg)
{
/** the current time in microseconds */
struct timeval now_tv;
+ /** has TCP connection seen a keepalive? */
+ int tcp_seen_keepalive;
+
/** signal handler callback */
void (*sig_cb)(int, void*);
/** signal handler user arg */
.RB [ \-unsh ]
.RB [ \-f
.IR ipaddr[@port] ]
+.RB [ \-d
+.IR secs ]
.I name
.I type
.I class
.TP
.B \-f \fIipaddr[@port]
Specify the server to send the queries to. If not specified localhost (127.0.0.1) is used.
+.TP
+.B \-d \fIsecs
+Delay after the connection before sending query. This tests the timeout
+on the other side, eg. if shorter the connection is closed.
.SH "EXAMPLES"
.LP
Some examples of use.
#include <getopt.h>
#endif
#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
#include "util/locks.h"
#include "util/log.h"
#include "util/net_help.h"
printf("-f server what ipaddr@portnr to send the queries to\n");
printf("-u use UDP. No retries are attempted.\n");
printf("-n do not wait for an answer.\n");
+ printf("-d secs delay after connection before sending query\n");
printf("-s use ssl\n");
printf("-h this help text\n");
exit(1);
/** send the TCP queries and print answers */
static void
-send_em(const char* svr, int udp, int usessl, int noanswer, int num, char** qs)
+send_em(const char* svr, int udp, int usessl, int noanswer, int delay,
+ int num, char** qs)
{
sldns_buffer* buf = sldns_buffer_new(65553);
int fd = open_svr(svr, udp);
}
}
for(i=0; i<num; i+=3) {
+ if (delay != 0) {
+#ifdef HAVE_SLEEP
+ sleep((unsigned)delay);
+#else
+ Sleep(delay*1000);
+#endif
+ }
printf("\nNext query is %s %s %s\n", qs[i], qs[i+1], qs[i+2]);
write_q(fd, udp, ssl, buf, (uint16_t)get_random(), qs[i],
qs[i+1], qs[i+2]);
int udp = 0;
int noanswer = 0;
int usessl = 0;
+ int delay = 0;
#ifdef USE_WINSOCK
WSADATA wsa_data;
if(argc == 1) {
usage(argv);
}
- while( (c=getopt(argc, argv, "f:hnsu")) != -1) {
+ while( (c=getopt(argc, argv, "f:hnsud:")) != -1) {
switch(c) {
case 'f':
svr = optarg;
case 's':
usessl = 1;
break;
+ case 'd':
+ if(atoi(optarg)==0 && strcmp(optarg,"0")!=0) {
+ printf("error parsing delay, "
+ "number expected: %s\n", optarg);
+ return 1;
+ }
+ delay = atoi(optarg);
+ break;
case 'h':
case '?':
default:
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
#endif
}
- send_em(svr, udp, usessl, noanswer, argc, argv);
+ send_em(svr, udp, usessl, noanswer, delay, argc, argv);
checklock_stop();
#ifdef USE_WINSOCK
WSACleanup();
/* just an RRSIG rrset with nothing else, 2 rrsigs */
"z5.example.com. 3600 IN RRSIG A 8 3 10200 20170612005010 20170515005010 42393 nlnetlabs.nl. NhEDrHkuIgHkjWhDRVsGOIJWZpSs+QdduilWFe5d+/ZhOheLJbaTYD5w6+ZZ3yPh1tNud+jlg+GyiOSVapLEO31swDCIarL1UfRjRSpxxDCHGag5Zu+S4hF+KURxO3cJk8jLBELMQyRuMRHoKrw/wsiLGVu1YpAyAPPMcjFBNbk=\n"
"z5.example.com. 3600 IN RRSIG A 8 3 10200 20170612005010 20170515005010 12345 nlnetlabs.nl. NhEDrHkuIgHkjWhDRVsGOIJWZpSs+QdduilWFe5d+/ZhOheLJbaTYD5w6+ZZ3yPh1tNud+jlg+GyiOSVapLEO31swDCIarL1UfRjRSpxxDCHGag5Zu+S4hF+KURxO3cJk8jLBELMQyRuMRHoKrw/wsiLGVu1YpAyAPPMcjFBNbk=\n"
-#if 0 /* comparison of file does not work on this part because duplicates */
+#if 1 /* comparison of file does not work on this part because duplicates */
/* are removed and the rrsets are reordered */
+"end_of_check.z6.example.com. 3600 IN A 10.0.0.10\n"
/* first rrsig, then A record */
"z6.example.com. 3600 IN RRSIG A 8 3 10200 20170612005010 20170515005010 42393 nlnetlabs.nl. NhEDrHkuIgHkjWhDRVsGOIJWZpSs+QdduilWFe5d+/ZhOheLJbaTYD5w6+ZZ3yPh1tNud+jlg+GyiOSVapLEO31swDCIarL1UfRjRSpxxDCHGag5Zu+S4hF+KURxO3cJk8jLBELMQyRuMRHoKrw/wsiLGVu1YpAyAPPMcjFBNbk=\n"
"z6.example.com. 3600 IN A 10.0.0.10\n"
"z9.example.com. 3600 IN A 10.0.0.10\n"
"z9.example.com. 3600 IN RRSIG A 8 3 10200 20170612005010 20170515005010 42393 nlnetlabs.nl. NhEDrHkuIgHkjWhDRVsGOIJWZpSs+QdduilWFe5d+/ZhOheLJbaTYD5w6+ZZ3yPh1tNud+jlg+GyiOSVapLEO31swDCIarL1UfRjRSpxxDCHGag5Zu+S4hF+KURxO3cJk8jLBELMQyRuMRHoKrw/wsiLGVu1YpAyAPPMcjFBNbk=\n"
"z9.example.com. 3600 IN RRSIG A 8 3 10200 20170612005010 20170515005010 42393 nlnetlabs.nl. NhEDrHkuIgHkjWhDRVsGOIJWZpSs+QdduilWFe5d+/ZhOheLJbaTYD5w6+ZZ3yPh1tNud+jlg+GyiOSVapLEO31swDCIarL1UfRjRSpxxDCHGag5Zu+S4hF+KURxO3cJk8jLBELMQyRuMRHoKrw/wsiLGVu1YpAyAPPMcjFBNbk=\n"
+/* different covered types, first RRSIGs then, RRs, then another RRSIG */
+"zz10.example.com. 3600 IN RRSIG AAAA 8 3 10200 20170612005010 20170515005010 42393 nlnetlabs.nl. NhEDrHkuIgHkjWhDRVsGOIJWZpSs+QdduilWFe5d+/ZhOheLJbaTYD5w6+ZZ3yPh1tNud+jlg+GyiOSVapLEO31swDCIarL1UfRjRSpxxDCHGag5Zu+S4hF+KURxO3cJk8jLBELMQyRuMRHoKrw/wsiLGVu1YpAyAPPMcjFBNbk=\n"
+"zz10.example.com. 3600 IN RRSIG A 8 3 10200 20170612005010 20170515005010 42393 nlnetlabs.nl. NhEDrHkuIgHkjWhDRVsGOIJWZpSs+QdduilWFe5d+/ZhOheLJbaTYD5w6+ZZ3yPh1tNud+jlg+GyiOSVapLEO31swDCIarL1UfRjRSpxxDCHGag5Zu+S4hF+KURxO3cJk8jLBELMQyRuMRHoKrw/wsiLGVu1YpAyAPPMcjFBNbk=\n"
+"zz10.example.com. 3600 IN A 10.0.0.10\n"
+"zz10.example.com. 3600 IN RRSIG CNAME 8 3 10200 20170612005010 20170515005010 42393 nlnetlabs.nl. NhEDrHkuIgHkjWhDRVsGOIJWZpSs+QdduilWFe5d+/ZhOheLJbaTYD5w6+ZZ3yPh1tNud+jlg+GyiOSVapLEO31swDCIarL1UfRjRSpxxDCHGag5Zu+S4hF+KURxO3cJk8jLBELMQyRuMRHoKrw/wsiLGVu1YpAyAPPMcjFBNbk=\n"
+"zz10.example.com. 3600 IN AAAA ::11\n"
#endif /* if0 for duplicates and reordering */
;
cp2 = fgets(buf2, (int)sizeof(buf2), i2);
if((!cp1 && !feof(i1)) || (!cp2 && !feof(i2)))
fatal_exit("fgets failed: %s", strerror(errno));
+ if(strncmp(buf1, "end_of_check", 12) == 0) {
+ fclose(i1);
+ fclose(i2);
+ return;
+ }
if(strcmp(buf1, buf2) != 0) {
log_info("in files %s and %s:%d", f1, f2, line);
log_info("'%s'", buf1);
log_info("'%s'", buf2);
- fatal_exit("files are not eqaul");
+ fatal_exit("files are not equal");
}
}
unit_assert(feof(i1) && feof(i2));
free(back);
}
+#define xstr(s) str(s)
+#define str(s) #s
+
+#define SRCDIRSTR xstr(SRCDIR)
+
/** read rrs to and from string, to and from wireformat */
static void
rr_tests(void)
{
- rr_test_file("testdata/test_ldnsrr.1", "testdata/test_ldnsrr.c1");
- rr_test_file("testdata/test_ldnsrr.2", "testdata/test_ldnsrr.c2");
- rr_test_file("testdata/test_ldnsrr.3", "testdata/test_ldnsrr.c3");
- rr_test_file("testdata/test_ldnsrr.4", "testdata/test_ldnsrr.c4");
- rr_test_file("testdata/test_ldnsrr.5", "testdata/test_ldnsrr.c5");
+ rr_test_file(SRCDIRSTR "/testdata/test_ldnsrr.1",
+ SRCDIRSTR "/testdata/test_ldnsrr.c1");
+ rr_test_file(SRCDIRSTR "/testdata/test_ldnsrr.2",
+ SRCDIRSTR "/testdata/test_ldnsrr.c2");
+ rr_test_file(SRCDIRSTR "/testdata/test_ldnsrr.3",
+ SRCDIRSTR "/testdata/test_ldnsrr.c3");
+ rr_test_file(SRCDIRSTR "/testdata/test_ldnsrr.4",
+ SRCDIRSTR "/testdata/test_ldnsrr.c4");
+ rr_test_file(SRCDIRSTR "/testdata/test_ldnsrr.5",
+ SRCDIRSTR "/testdata/test_ldnsrr.c5");
}
void
#include "util/rtt.h"
#include "util/timehist.h"
+#include "iterator/iterator.h"
#include "libunbound/unbound.h"
/** test RTT code */
static void
rtt_test(void)
{
- int init = 376;
+ int init = UNKNOWN_SERVER_NICENESS;
int i;
struct rtt_info r;
unit_show_func("util/rtt.c", "rtt_timeout");
fclose(in);
}
+#define xstr(s) str(s)
+#define str(s) #s
+
+#define SRCDIRSTR xstr(SRCDIR)
+
void msgparse_test(void)
{
time_t origttl = MAX_NEG_TTL;
unit_show_feature("message parse");
simpletest(pkt, &alloc, out);
/* plain hex dumps, like pcat */
- testfromfile(pkt, &alloc, out, "testdata/test_packets.1");
- testfromfile(pkt, &alloc, out, "testdata/test_packets.2");
- testfromfile(pkt, &alloc, out, "testdata/test_packets.3");
+ testfromfile(pkt, &alloc, out, SRCDIRSTR "/testdata/test_packets.1");
+ testfromfile(pkt, &alloc, out, SRCDIRSTR "/testdata/test_packets.2");
+ testfromfile(pkt, &alloc, out, SRCDIRSTR "/testdata/test_packets.3");
/* like from drill -w - */
- testfromdrillfile(pkt, &alloc, out, "testdata/test_packets.4");
- testfromdrillfile(pkt, &alloc, out, "testdata/test_packets.5");
+ testfromdrillfile(pkt, &alloc, out, SRCDIRSTR "/testdata/test_packets.4");
+ testfromdrillfile(pkt, &alloc, out, SRCDIRSTR "/testdata/test_packets.5");
matches_nolocation = 1; /* RR order not important for the next test */
- testfromdrillfile(pkt, &alloc, out, "testdata/test_packets.6");
+ testfromdrillfile(pkt, &alloc, out, SRCDIRSTR "/testdata/test_packets.6");
check_rrsigs = 1;
- testfromdrillfile(pkt, &alloc, out, "testdata/test_packets.7");
+ testfromdrillfile(pkt, &alloc, out, SRCDIRSTR "/testdata/test_packets.7");
check_rrsigs = 0;
matches_nolocation = 0;
check_formerr_gone = 1;
- testfromdrillfile(pkt, &alloc, out, "testdata/test_packets.8");
+ testfromdrillfile(pkt, &alloc, out, SRCDIRSTR "/testdata/test_packets.8");
check_formerr_gone = 0;
check_rrsigs = 1;
check_nosameness = 1;
- testfromdrillfile(pkt, &alloc, out, "testdata/test_packets.9");
+ testfromdrillfile(pkt, &alloc, out, SRCDIRSTR "/testdata/test_packets.9");
check_nosameness = 0;
check_rrsigs = 0;
sldns_buffer_free(buf);
}
+#define xstr(s) str(s)
+#define str(s) #s
+
+#define SRCDIRSTR xstr(SRCDIR)
+
void
verify_test(void)
{
unit_show_feature("signature verify");
#ifdef USE_SHA1
- verifytest_file("testdata/test_signatures.1", "20070818005004");
+ verifytest_file(SRCDIRSTR "/testdata/test_signatures.1", "20070818005004");
#endif
#if defined(USE_DSA) && defined(USE_SHA1)
- verifytest_file("testdata/test_signatures.2", "20080414005004");
- verifytest_file("testdata/test_signatures.3", "20080416005004");
- verifytest_file("testdata/test_signatures.4", "20080416005004");
- verifytest_file("testdata/test_signatures.5", "20080416005004");
- verifytest_file("testdata/test_signatures.6", "20080416005004");
- verifytest_file("testdata/test_signatures.7", "20070829144150");
+ verifytest_file(SRCDIRSTR "/testdata/test_signatures.2", "20080414005004");
+ verifytest_file(SRCDIRSTR "/testdata/test_signatures.3", "20080416005004");
+ verifytest_file(SRCDIRSTR "/testdata/test_signatures.4", "20080416005004");
+ verifytest_file(SRCDIRSTR "/testdata/test_signatures.5", "20080416005004");
+ verifytest_file(SRCDIRSTR "/testdata/test_signatures.6", "20080416005004");
+ verifytest_file(SRCDIRSTR "/testdata/test_signatures.7", "20070829144150");
#endif /* USE_DSA */
#ifdef USE_SHA1
- verifytest_file("testdata/test_signatures.8", "20070829144150");
+ verifytest_file(SRCDIRSTR "/testdata/test_signatures.8", "20070829144150");
#endif
#if (defined(HAVE_EVP_SHA256) || defined(HAVE_NSS) || defined(HAVE_NETTLE)) && defined(USE_SHA2)
- verifytest_file("testdata/test_sigs.rsasha256", "20070829144150");
+ verifytest_file(SRCDIRSTR "/testdata/test_sigs.rsasha256", "20070829144150");
# ifdef USE_SHA1
- verifytest_file("testdata/test_sigs.sha1_and_256", "20070829144150");
+ verifytest_file(SRCDIRSTR "/testdata/test_sigs.sha1_and_256", "20070829144150");
# endif
- verifytest_file("testdata/test_sigs.rsasha256_draft", "20090101000000");
+ verifytest_file(SRCDIRSTR "/testdata/test_sigs.rsasha256_draft", "20090101000000");
#endif
#if (defined(HAVE_EVP_SHA512) || defined(HAVE_NSS) || defined(HAVE_NETTLE)) && defined(USE_SHA2)
- verifytest_file("testdata/test_sigs.rsasha512_draft", "20070829144150");
- verifytest_file("testdata/test_signatures.9", "20171215000000");
+ verifytest_file(SRCDIRSTR "/testdata/test_sigs.rsasha512_draft", "20070829144150");
+ verifytest_file(SRCDIRSTR "/testdata/test_signatures.9", "20171215000000");
#endif
#ifdef USE_SHA1
- verifytest_file("testdata/test_sigs.hinfo", "20090107100022");
- verifytest_file("testdata/test_sigs.revoked", "20080414005004");
+ verifytest_file(SRCDIRSTR "/testdata/test_sigs.hinfo", "20090107100022");
+ verifytest_file(SRCDIRSTR "/testdata/test_sigs.revoked", "20080414005004");
#endif
#ifdef USE_GOST
if(sldns_key_EVP_load_gost_id())
- verifytest_file("testdata/test_sigs.gost", "20090807060504");
+ verifytest_file(SRCDIRSTR "/testdata/test_sigs.gost", "20090807060504");
else printf("Warning: skipped GOST, openssl does not provide gost.\n");
#endif
#ifdef USE_ECDSA
/* test for support in case we use libNSS and ECC is removed */
if(dnskey_algo_id_is_supported(LDNS_ECDSAP256SHA256)) {
- verifytest_file("testdata/test_sigs.ecdsa_p256", "20100908100439");
- verifytest_file("testdata/test_sigs.ecdsa_p384", "20100908100439");
+ verifytest_file(SRCDIRSTR "/testdata/test_sigs.ecdsa_p256", "20100908100439");
+ verifytest_file(SRCDIRSTR "/testdata/test_sigs.ecdsa_p384", "20100908100439");
}
- dstest_file("testdata/test_ds.sha384");
+ dstest_file(SRCDIRSTR "/testdata/test_ds.sha384");
#endif
#ifdef USE_ED25519
if(dnskey_algo_id_is_supported(LDNS_ED25519)) {
- verifytest_file("testdata/test_sigs.ed25519", "20170530140439");
+ verifytest_file(SRCDIRSTR "/testdata/test_sigs.ed25519", "20170530140439");
}
#endif
#ifdef USE_ED448
if(dnskey_algo_id_is_supported(LDNS_ED448)) {
- verifytest_file("testdata/test_sigs.ed448", "20180408143630");
+ verifytest_file(SRCDIRSTR "/testdata/test_sigs.ed448", "20180408143630");
}
#endif
#ifdef USE_SHA1
- dstest_file("testdata/test_ds.sha1");
+ dstest_file(SRCDIRSTR "/testdata/test_ds.sha1");
#endif
nsectest();
- nsec3_hash_test("testdata/test_nsec3_hash.1");
+ nsec3_hash_test(SRCDIRSTR "/testdata/test_nsec3_hash.1");
}
--- /dev/null
+/*
+ * util/edns.c - handle base EDNS options.
+ *
+ * Copyright (c) 2018, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file contains functions for base EDNS options.
+ */
+
+#include "config.h"
+
+#include "util/config_file.h"
+#include "util/netevent.h"
+#include "util/regional.h"
+#include "util/data/msgparse.h"
+#include "util/data/msgreply.h"
+
+static int edns_keepalive(struct edns_data* edns_out, struct edns_data* edns_in,
+ struct comm_point* c, struct regional* region)
+{
+ if(c->type == comm_udp)
+ return 1;
+
+ /* To respond with a Keepalive option, the client connection
+ * must have received one message with a TCP Keepalive EDNS option,
+ * and that option must have 0 length data. Subsequent messages
+ * sent on that connection will have a TCP Keepalive option.
+ */
+ if(c->tcp_keepalive ||
+ edns_opt_list_find(edns_in->opt_list, LDNS_EDNS_KEEPALIVE)) {
+ int keepalive = c->tcp_timeout_msec / 100;
+ uint8_t data[2];
+ data[0] = (uint8_t)((keepalive >> 8) & 0xff);
+ data[1] = (uint8_t)(keepalive & 0xff);
+ if(!edns_opt_list_append(&edns_out->opt_list, LDNS_EDNS_KEEPALIVE,
+ sizeof(data), data, region))
+ return 0;
+ c->tcp_keepalive = 1;
+ }
+ return 1;
+}
+
+int apply_edns_options(struct edns_data* edns_out, struct edns_data* edns_in,
+ struct config_file* cfg, struct comm_point* c, struct regional* region)
+{
+ if(cfg->do_tcp_keepalive &&
+ !edns_keepalive(edns_out, edns_in, c, region))
+ return 0;
+
+ return 1;
+}
--- /dev/null
+/*
+ * util/edns.h - handle base EDNS options.
+ *
+ * Copyright (c) 2018, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file contains functions for base EDNS options.
+ */
+
+#ifndef UTIL_EDNS_H
+#define UTIL_EDNS_H
+
+struct edns_data;
+struct config_file;
+struct comm_point;
+struct regional;
+
+/**
+ * Apply common EDNS options.
+ *
+ * @param edns_out: initialised edns information with outbound edns.
+ * @param edns_in: initialised edns information with received edns.
+ * @param cfg: configuration.
+ * @param c: comm channel.
+ * @param region: the region to allocate the edns options in.
+ */
+int apply_edns_options(struct edns_data* edns_out, struct edns_data* edns_in,
+ struct config_file* cfg, struct comm_point* c, struct regional* region);
+
+#endif
*/
#include "config.h"
#include "util/rtt.h"
+#include "iterator/iterator.h"
/* overwritten by config: infra_cache_min_rtt: */
int RTT_MIN_TIMEOUT = 50;
rtt_init(struct rtt_info* rtt)
{
rtt->srtt = 0;
- rtt->rttvar = 94;
+ rtt->rttvar = UNKNOWN_SERVER_NICENESS/4;
rtt->rto = calc_rto(rtt);
/* default value from the book is 0 + 4*0.75 = 3 seconds */
/* first RTO is 0 + 4*0.094 = 0.376 seconds */
--- /dev/null
+/*
+ * daemon/tcp_conn_limit.c - client TCP connection limit storage for the server.
+ *
+ * Copyright (c) 2018, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file helps the server discard excess TCP connections.
+ */
+#include "config.h"
+#include "util/regional.h"
+#include "util/log.h"
+#include "util/config_file.h"
+#include "util/net_help.h"
+#include "util/tcp_conn_limit.h"
+#include "services/localzone.h"
+#include "sldns/str2wire.h"
+
+struct tcl_list*
+tcl_list_create(void)
+{
+ struct tcl_list* tcl = (struct tcl_list*)calloc(1,
+ sizeof(struct tcl_list));
+ if(!tcl)
+ return NULL;
+ tcl->region = regional_create();
+ if(!tcl->region) {
+ tcl_list_delete(tcl);
+ return NULL;
+ }
+ return tcl;
+}
+
+static void
+tcl_list_free_node(rbnode_type* node, void* ATTR_UNUSED(arg))
+{
+ struct tcl_addr* n = (struct tcl_addr*) node;
+ lock_quick_destroy(&n->lock);
+#ifdef THREADS_DISABLED
+ (void)n;
+#endif
+}
+
+void
+tcl_list_delete(struct tcl_list* tcl)
+{
+ if(!tcl)
+ return;
+ traverse_postorder(&tcl->tree, tcl_list_free_node, NULL);
+ regional_destroy(tcl->region);
+ free(tcl);
+}
+
+/** insert new address into tcl_list structure */
+static struct tcl_addr*
+tcl_list_insert(struct tcl_list* tcl, struct sockaddr_storage* addr,
+ socklen_t addrlen, int net, uint32_t limit,
+ int complain_duplicates)
+{
+ struct tcl_addr* node = regional_alloc_zero(tcl->region,
+ sizeof(struct tcl_addr));
+ if(!node)
+ return NULL;
+ lock_quick_init(&node->lock);
+ node->limit = limit;
+ if(!addr_tree_insert(&tcl->tree, &node->node, addr, addrlen, net)) {
+ if(complain_duplicates)
+ verbose(VERB_QUERY, "duplicate tcl address ignored.");
+ }
+ return node;
+}
+
+/** apply tcl_list string */
+static int
+tcl_list_str_cfg(struct tcl_list* tcl, const char* str, const char* s2,
+ int complain_duplicates)
+{
+ struct sockaddr_storage addr;
+ int net;
+ socklen_t addrlen;
+ uint32_t limit;
+ if(atoi(s2) < 0) {
+ log_err("bad connection limit %s", s2);
+ return 0;
+ }
+ limit = (uint32_t)atoi(s2);
+ if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
+ log_err("cannot parse connection limit netblock: %s", str);
+ return 0;
+ }
+ if(!tcl_list_insert(tcl, &addr, addrlen, net, limit,
+ complain_duplicates)) {
+ log_err("out of memory");
+ return 0;
+ }
+ return 1;
+}
+
+/** read tcl_list config */
+static int
+read_tcl_list(struct tcl_list* tcl, struct config_file* cfg)
+{
+ struct config_str2list* p;
+ for(p = cfg->tcp_connection_limits; p; p = p->next) {
+ log_assert(p->str && p->str2);
+ if(!tcl_list_str_cfg(tcl, p->str, p->str2, 1))
+ return 0;
+ }
+ return 1;
+}
+
+int
+tcl_list_apply_cfg(struct tcl_list* tcl, struct config_file* cfg)
+{
+ regional_free_all(tcl->region);
+ addr_tree_init(&tcl->tree);
+ if(!read_tcl_list(tcl, cfg))
+ return 0;
+ addr_tree_init_parents(&tcl->tree);
+ return 1;
+}
+
+int
+tcl_new_connection(struct tcl_addr* tcl)
+{
+ if(tcl) {
+ int res = 1;
+ lock_quick_lock(&tcl->lock);
+ if(tcl->count >= tcl->limit)
+ res = 0;
+ else
+ tcl->count++;
+ lock_quick_unlock(&tcl->lock);
+ return res;
+ }
+ return 1;
+}
+
+void
+tcl_close_connection(struct tcl_addr* tcl)
+{
+ if(tcl) {
+ lock_quick_lock(&tcl->lock);
+ log_assert(tcl->count > 0);
+ tcl->count--;
+ lock_quick_unlock(&tcl->lock);
+ }
+}
+
+struct tcl_addr*
+tcl_addr_lookup(struct tcl_list* tcl, struct sockaddr_storage* addr,
+ socklen_t addrlen)
+{
+ return (struct tcl_addr*)addr_tree_lookup(&tcl->tree,
+ addr, addrlen);
+}
+
+size_t
+tcl_list_get_mem(struct tcl_list* tcl)
+{
+ if(!tcl) return 0;
+ return sizeof(*tcl) + regional_get_mem(tcl->region);
+}
--- /dev/null
+/*
+ * daemon/tcp_conn_limit.h - client TCP connection limit storage for the server.
+ *
+ * Copyright (c) 2018, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file keeps track of the limit on the number of TCP connections
+ * each client makes the server.
+ */
+
+#ifndef DAEMON_TCP_CONN_LIMIT_H
+#define DAEMON_TCP_CONN_LIMIT_H
+#include "util/storage/dnstree.h"
+#include "util/locks.h"
+struct config_file;
+struct regional;
+
+/**
+ * TCP connection limit storage structure
+ */
+struct tcl_list {
+ /** regional for allocation */
+ struct regional* region;
+ /**
+ * Tree of the addresses that are TCP connection limited.
+ * contents of type tcl_addr.
+ */
+ rbtree_type tree;
+};
+
+/**
+ *
+ * An address span with connection limit information
+ */
+struct tcl_addr {
+ /** node in address tree */
+ struct addr_tree_node node;
+ /** lock on structure data */
+ lock_quick_type lock;
+ /** connection limit on this netblock */
+ uint32_t limit;
+ /** current connection count on this netblock */
+ uint32_t count;
+};
+
+/**
+ * Create TCP connection limit structure
+ * @return new structure or NULL on error.
+ */
+struct tcl_list* tcl_list_create(void);
+
+/**
+ * Delete TCP connection limit structure.
+ * @param tcl: to delete.
+ */
+void tcl_list_delete(struct tcl_list* tcl);
+
+/**
+ * Process TCP connection limit config.
+ * @param tcl: where to store.
+ * @param cfg: config options.
+ * @return 0 on error.
+ */
+int tcl_list_apply_cfg(struct tcl_list* tcl, struct config_file* cfg);
+
+/**
+ * Increment TCP connection count if found, provided the
+ * count was below the limit.
+ * @param tcl: structure for tcl storage, or NULL.
+ * @return: 0 if limit reached, 1 if tcl was NULL or limit not reached.
+ */
+int tcl_new_connection(struct tcl_addr* tcl);
+
+/**
+ * Decrement TCP connection count if found.
+ * @param tcl: structure for tcl storage, or NULL.
+ */
+void tcl_close_connection(struct tcl_addr* tcl);
+
+/**
+ * Lookup address to see its TCP connection limit structure
+ * @param tcl: structure for address storage.
+ * @param addr: address to check
+ * @param addrlen: length of addr.
+ * @return: tcl structure from this address.
+ */
+struct tcl_addr*
+tcl_addr_lookup(struct tcl_list* tcl, struct sockaddr_storage* addr,
+ socklen_t addrlen);
+
+/**
+ * Get memory used by TCP connection limit structure.
+ * @param tcl: structure for address storage.
+ * @return bytes in use.
+ */
+size_t tcl_list_get_mem(struct tcl_list* tcl);
+
+#endif /* DAEMON_TCP_CONN_LIMIT_H */
if(key_entry_isbad(k) && qstate->errinf &&
qstate->env->cfg->val_log_level >= 2) {
/* on malloc failure there is simply no reason string */
- key_entry_set_reason(k, errinf_to_str(qstate));
+ key_entry_set_reason(k, errinf_to_str_bogus(qstate));
}
key_entry_hash(k);
slabhash_insert(kcache->slab, k->entry.hash, &k->entry,