mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-18 23:06:06 -05:00
* - dnsoverquic, configure --with-libngtcp2 option. * - dnsoverquic, create comm_point for doq and receive cmsg local address. * - dnsoverquic, less obtrusive debug. * - dnsoverquic, log and fix local port number. Neater subroutines and ifdefs. * - dnsoverquic, add testcode/doqclient. * - dnsoverquic, review fixes on doqclient. * - dnsoverquic, fix unit test testbound link. * - dnsoverquic, parse query in doqclient. * - dnsoverquic, link with libngtcp2_crypto_openssl and code for doqclient. * - dnsoverquic, random routine for doqclient and fix ngaddr allocation, and check ub_initstate return. * - dnsoverquic, fix doqclient free of allocated ngaddr addresses. * - dnsoverquic, enable debug output with -v for doqclient. * - dnsoverquic, create and set TLS object and TLS context in doqclient. * - dnsoverquic, work on quic tls context in doqclient. * - dnsoverquic, set default dnsoverquic port to the standardized 853 port. * - dnsoverquic, remove debug comment. * - dnsoverquic, dns-over-quic quic-port: 853 config option. * - dnsoverquic, log type of interface created at start of unbound. * - dnsoverquic, log type of no tls https as https when interface is created. * - dnsoverquic, setup client quic tls methods. * - dnsoverquic, event work in doqclient. * - dnsoverquic, explain in documentation that QUIC uses UDP. * - dnsoverquic, make doqclient exit. * - dnsoverquic, doqclient cleanup run routine. * - dnsoverquic, doqclient code nicer. * - dnsoverquic, doqclient read and timer. * - dnsoverquic, doqclient write work. * - dnsoverquic, review fixes. * - dnsoverquic, detect openssl quic support at configure time. * - dnsoverquic, do not allow QUIC on port 53 to stop confusion of DoQ and DNS. * - dnsoverquic, in doqclient, when idle close is returned, drop the connection without calling ngtcp2_conn_write_connection_close. * - dnsoverquic, in doqclient, log callbacks. * - dnsoverquic, in doqclient add extend_max_local_streams_bidi callback. * - dnsoverquic, in doqclient add client query lists. * - dnsoverquic, in doqclient, code cleaner, log text nicer. * - dnsoverquic, in doqclient, work on write_streams. * - dnsoverquic, in doqclient, use signed int for stream_id, work on the ngtcp2_recv_stream_data callback. * - dnsoverquic, in doqclient, print result and fixes for recv data. * - dnsoverquic, in doqclient, add the event callbacks to fptr wlist. * - dnsoverquic, in doqclient, when already expired, use zero timeout timer. * - dnsoverquic, in doqclient, ignore unused return codes from ngtcp2_conn_writev_stream. * - dnsoverquic, add doqclient event functions to the unbound-dnstap-socket test tool for linking. * - dnsoverquic, in doqclient, fix multiple operands for the commandline. neater dns message output. * - dnsoverquic, in doqclient, store packet when write blocks and try later. * - dnsoverquic, in doqclient, limit number of packets and number of bytes sent. * - dnsoverquic, in doqclient, better size estimate for outgoing packet. * - dnsoverquic, in doqclient, fix that already written next packet is not counted for data length to send. * - dnsoverquic, in doqclient, early data transmission and session resumption. * - dnsoverquic, send version negotiation packet. * - dnsoverquic, send retry and accept the connection. * - dnsoverquic, storage structures. * - dnsoverquic, doq connection setup. * - dnsoverquic, neater code layout for new conn. Fix verbosity of log print. * - dnsoverquic, doq conn callback functions. * - dnsoverquic, doq_fill_rand routine in header file. * - dnsoverquic, keep track of connection ids. * - dnsoverquic, get_new_connection_id callback. * - dnsoverquic, create doq_conid tree. * - dnsoverquic, settings for server connection. * - dnsoverquic, tls context. * - dnsoverquic, sendmsg error handling. * - dnsoverquic, neat code. * - dnsoverquic, track doq connection last error. * - dnsoverquic, neater packet address parameters. * - dnsoverquic, fix uninitialized bytes in msg control in doq sendmsg, and fix tree cleanup of conid tree. * - dnsoverquic, better usage text for doqclient. * - dnsoverquic, neat code. * - dnsoverquic, connection receive packet handling. * - dnsoverquic, debug output. * - dnsoverquic, debug switched meaning of scid and dcid gives ERR_TRANSPORT_PARAM. * - dnsoverquic, remove debug output. * - dnsoverquic, connection delete routine and error from connection read in more detail with less clutter. * - dnsoverquic, write to stream, and receive stream data, log packet. * - dnsoverquic, alpn set up. * - dnsoverquic, connection close. * - dnsoverquic, doq_table and locks. * - dnsoverquic, fix tests. * - dnsoverquic, better locking. * - dnsoverquic, doq_stream. * - dnsoverquic, remove compile warning. * - dnsoverquic, doq_stream receive data. * - dnsoverquic, fixes for locks and keep length bytes allocated. * - dnsoverquic, lock connection on initial insertion. * - dnsoverquic, reply information, and reply buffer. * - dnsoverquic, reply info from cache, local-zone and recursion lookups. * - dnsoverquic, spelling in comment about buffer storage. * - dnsoverquic, stream write list and doqclient fixes to exit and printout. * - dnsoverquic, doqclient -q option for short printout. * - dnsoverquic, unit test with local data reply. * - dnsoverquic, write connection and write event is set. * - dnsoverquic, neater logging for write event connection stream writes. * - dnsoverquic, log remote connection when the streams are written for it. * - dnsoverquic, better threaded use, threads can write to doq connections at the same time. * - dnsoverquic, unit test for the calculation of connection size with a query. * - dnsoverquic, use less memory per connection. * - dnsoverquic, remove unit test output. * - dnsoverquic, add MSG_DONTWAIT so that there is no mistakenly blocking socket operations. * - dnsoverquic, doqclient logs address on connection failures. * - dnsoverquic, compat code for clock get time routine. * - dnsoverquic, use skip_test for doq unit test. * - dnsoverquic, fixes for proxyprotocol, use remote_addr and set proxyprotocol disabled on the doq connection. * - dnsoverquic, doqclient sets log identity to its name, instead of "unbound". * - dnsoverquic, handle blocked udp packet writes. * - dnsoverquic, fix function documentation for verbose_print_addr from services/listen_dnsport.c. * - dnsoverquic, fix doq_conn lock protection. The checklock allows to set the output file name, and doqclient uses that. Print place of lock_protect. * - dnsoverquic, neater buffer clear when write of blocked packet fails, make sure that memory area does not overlap for blocked packet addresses when write of blocked packet fails, and size blocked packet buffer to the pkt buf. * - dnsoverquic, move lock check after the test to test script in doq test. * - dnsoverquic, the doq test uses valgrind when enabled. * - dnsoverquic, git ignore the doqclient test. * - dnsoverquic, limit the buffer for packets to max packet size with some more. * - dnsoverquic, spelling fix. * - dnsoverquic, timer work, structure and adds and deletes. * - dnsoverquic, timer_tree uses table.lock. * - dnsoverquic, fix timer tree remove and spelling in header file comment. * - dnsoverquic, fix testbound for timer compare function linkage. * - dnsoverquic, timer set add debug output. * - dnsoverquic, doq_conn_check_timer function. * - dnsoverquic, doq_done_setup_timer_and_write function. * - dnsoverquic, fix that doq conn is not deleted whilst editing write and timer. * - dnsoverquic, Fix #861 make ERROR netevent.h:1073:32: error: field 'blocked_pkt_pi' has incomplete type * - dnsoverquic, timer element has timeout setup when socket callback complete. * - dnsoverquic, fix unit test compile. * - dnsoverquic, timer callback routine, handle timeout and close and delete the connection if necessary. * - dnsoverquic, timer pickup stops at current time. * - dnsoverquic, timer comparable with the event base time. * - dnsoverquic, erase marked time when timer disabled. * - dnsoverquic, fix timer to set correctly and lock popped write connection early, before it is modified. * - dnsoverquic, fix to unlock connection lock when it is unlinked and deleted. * - dnsoverquic, fix to unlock connection lock when it is deleted because it is a duplicate connection. * - dnsoverquic, fix that doq timer is not disabled when not set. * - dnsoverquic, quic-size: 8m maximum number of bytes for QUIC buffers. * - dnsoverquic, flex and bison. * - dnsoverquic, quic-size turn away new connections when full. * - dnsoverquic, doqclient outputs stream reset information. * - dnsoverquic, detect stream close and reset. * - dnsoverquic, free stream buffers when data is acked and stream is closed. * - dnsoverquic, delete stream when closed. Unlink it. Allow stream_id 4 as first. * - dnsoverquic, stats output for mem.quic and num.query.quic. * - dnsoverquic, review fix. * - dnsoverquic, fix when compiled without ngtcp2. * - dnsoverquic, fix to detect ngtcp2_crypto_quictls for openssl crypto, after change in libngtcp2. * - dnsoverquic, fix for newer ngtcp2 versions. detect ngtcp2_ccerr_default, ngtcp2/ngtcp2_crypto_quictls.h, struct ngtcp2_pkt_hd.tokenlen, struct ngtcp2_settings.tokenlen and struct ngtcp2_version_cid. * - dnsoverquic, fix for newer ngtcp2 version, detect number of arguments for ngtcp2_conn_shutdown_stream. * - dnsoverquic, fix for newer ngtcp2. * - dnsoverquic, use the functions from util/timeval_func.h. * - dnsoverquic, fix in doqclient only write transport parameters once. * - dnsoverquic, debug log output removed. * - dnsoverquic, fix in doqclient to work with renamed NGTCP2_CC_ALGO_BBR_V2 from ngtcp2. * - dnsoverquic, fix to check in doq_server_socket_create that tls-service-key and tls-service-pem have a value. * - dnsoverquic, fix to error when doq_server_socket_create fails. * - dnsoverquic, improve linebreaks in configparser additions. * - dnsoverquic, fix port from interface pickup after main branch change. * Fix getting user data from SSL, fix calloc warning. * Fix fwrite return value check in doqclient * - timeval_substruct from timeval_func.h - lock_protect also for HAVE_NGTCP2_CCERR_DEFAULT - fix doq logging for inet_ntop failures * - memset for consistency - no value returned from msghdr_get_ecn when S_SPLINT_S is defined * - dnsoverquic, rerun autoconf. --------- Co-authored-by: Yorgos Thessalonikefs <yorgos@nlnetlabs.nl>
1474 lines
47 KiB
C
1474 lines
47 KiB
C
/*
|
|
* testcode/unitmain.c - unit test main program for unbound.
|
|
*
|
|
* Copyright (c) 2007, 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
|
|
* Unit test main program. Calls all the other unit tests.
|
|
* Exits with code 1 on a failure. 0 if all unit tests are successful.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#ifdef HAVE_OPENSSL_ERR_H
|
|
#include <openssl/err.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_OPENSSL_RAND_H
|
|
#include <openssl/rand.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_OPENSSL_CONF_H
|
|
#include <openssl/conf.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_OPENSSL_ENGINE_H
|
|
#include <openssl/engine.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_NSS
|
|
/* nss3 */
|
|
#include "nss.h"
|
|
#endif
|
|
|
|
#include "sldns/rrdef.h"
|
|
#include "sldns/keyraw.h"
|
|
#include "util/log.h"
|
|
#include "testcode/unitmain.h"
|
|
|
|
/** number of tests done */
|
|
int testcount = 0;
|
|
|
|
#include "util/alloc.h"
|
|
/** test alloc code */
|
|
static void
|
|
alloc_test(void) {
|
|
alloc_special_type *t1, *t2;
|
|
struct alloc_cache major, minor1, minor2;
|
|
int i;
|
|
|
|
unit_show_feature("alloc_special_obtain");
|
|
alloc_init(&major, NULL, 0);
|
|
alloc_init(&minor1, &major, 0);
|
|
alloc_init(&minor2, &major, 1);
|
|
|
|
t1 = alloc_special_obtain(&minor1);
|
|
alloc_clear(&minor1);
|
|
|
|
alloc_special_release(&minor2, t1);
|
|
t2 = alloc_special_obtain(&minor2);
|
|
unit_assert( t1 == t2 ); /* reused */
|
|
alloc_special_release(&minor2, t1);
|
|
|
|
for(i=0; i<100; i++) {
|
|
t1 = alloc_special_obtain(&minor1);
|
|
alloc_special_release(&minor2, t1);
|
|
}
|
|
if(0) {
|
|
alloc_stats(&minor1);
|
|
alloc_stats(&minor2);
|
|
alloc_stats(&major);
|
|
}
|
|
/* reuse happened */
|
|
unit_assert(minor1.num_quar + minor2.num_quar + major.num_quar == 11);
|
|
|
|
alloc_clear(&minor1);
|
|
alloc_clear(&minor2);
|
|
unit_assert(major.num_quar == 11);
|
|
alloc_clear(&major);
|
|
}
|
|
|
|
#include "util/net_help.h"
|
|
/** test net code */
|
|
static void
|
|
net_test(void)
|
|
{
|
|
const char* t4[] = {"\000\000\000\000",
|
|
"\200\000\000\000",
|
|
"\300\000\000\000",
|
|
"\340\000\000\000",
|
|
"\360\000\000\000",
|
|
"\370\000\000\000",
|
|
"\374\000\000\000",
|
|
"\376\000\000\000",
|
|
"\377\000\000\000",
|
|
"\377\200\000\000",
|
|
"\377\300\000\000",
|
|
"\377\340\000\000",
|
|
"\377\360\000\000",
|
|
"\377\370\000\000",
|
|
"\377\374\000\000",
|
|
"\377\376\000\000",
|
|
"\377\377\000\000",
|
|
"\377\377\200\000",
|
|
"\377\377\300\000",
|
|
"\377\377\340\000",
|
|
"\377\377\360\000",
|
|
"\377\377\370\000",
|
|
"\377\377\374\000",
|
|
"\377\377\376\000",
|
|
"\377\377\377\000",
|
|
"\377\377\377\200",
|
|
"\377\377\377\300",
|
|
"\377\377\377\340",
|
|
"\377\377\377\360",
|
|
"\377\377\377\370",
|
|
"\377\377\377\374",
|
|
"\377\377\377\376",
|
|
"\377\377\377\377",
|
|
"\377\377\377\377",
|
|
"\377\377\377\377",
|
|
};
|
|
unit_show_func("util/net_help.c", "str_is_ip6");
|
|
unit_assert( str_is_ip6("::") );
|
|
unit_assert( str_is_ip6("::1") );
|
|
unit_assert( str_is_ip6("2001:7b8:206:1:240:f4ff:fe37:8810") );
|
|
unit_assert( str_is_ip6("fe80::240:f4ff:fe37:8810") );
|
|
unit_assert( !str_is_ip6("0.0.0.0") );
|
|
unit_assert( !str_is_ip6("213.154.224.12") );
|
|
unit_assert( !str_is_ip6("213.154.224.255") );
|
|
unit_assert( !str_is_ip6("255.255.255.0") );
|
|
unit_show_func("util/net_help.c", "is_pow2");
|
|
unit_assert( is_pow2(0) );
|
|
unit_assert( is_pow2(1) );
|
|
unit_assert( is_pow2(2) );
|
|
unit_assert( is_pow2(4) );
|
|
unit_assert( is_pow2(8) );
|
|
unit_assert( is_pow2(16) );
|
|
unit_assert( is_pow2(1024) );
|
|
unit_assert( is_pow2(1024*1024) );
|
|
unit_assert( is_pow2(1024*1024*1024) );
|
|
unit_assert( !is_pow2(3) );
|
|
unit_assert( !is_pow2(5) );
|
|
unit_assert( !is_pow2(6) );
|
|
unit_assert( !is_pow2(7) );
|
|
unit_assert( !is_pow2(9) );
|
|
unit_assert( !is_pow2(10) );
|
|
unit_assert( !is_pow2(11) );
|
|
unit_assert( !is_pow2(17) );
|
|
unit_assert( !is_pow2(23) );
|
|
unit_assert( !is_pow2(257) );
|
|
unit_assert( !is_pow2(259) );
|
|
|
|
/* test addr_mask */
|
|
unit_show_func("util/net_help.c", "addr_mask");
|
|
if(1) {
|
|
struct sockaddr_in a4;
|
|
struct sockaddr_in6 a6;
|
|
socklen_t l4 = (socklen_t)sizeof(a4);
|
|
socklen_t l6 = (socklen_t)sizeof(a6);
|
|
int i;
|
|
a4.sin_family = AF_INET;
|
|
a6.sin6_family = AF_INET6;
|
|
for(i=0; i<35; i++) {
|
|
/* address 255.255.255.255 */
|
|
memcpy(&a4.sin_addr, "\377\377\377\377", 4);
|
|
addr_mask((struct sockaddr_storage*)&a4, l4, i);
|
|
unit_assert(memcmp(&a4.sin_addr, t4[i], 4) == 0);
|
|
}
|
|
memcpy(&a6.sin6_addr, "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377", 16);
|
|
addr_mask((struct sockaddr_storage*)&a6, l6, 128);
|
|
unit_assert(memcmp(&a6.sin6_addr, "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377", 16) == 0);
|
|
addr_mask((struct sockaddr_storage*)&a6, l6, 122);
|
|
unit_assert(memcmp(&a6.sin6_addr, "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\300", 16) == 0);
|
|
addr_mask((struct sockaddr_storage*)&a6, l6, 120);
|
|
unit_assert(memcmp(&a6.sin6_addr, "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\000", 16) == 0);
|
|
addr_mask((struct sockaddr_storage*)&a6, l6, 64);
|
|
unit_assert(memcmp(&a6.sin6_addr, "\377\377\377\377\377\377\377\377\000\000\000\000\000\000\000\000", 16) == 0);
|
|
addr_mask((struct sockaddr_storage*)&a6, l6, 0);
|
|
unit_assert(memcmp(&a6.sin6_addr, "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16) == 0);
|
|
}
|
|
|
|
/* test addr_in_common */
|
|
unit_show_func("util/net_help.c", "addr_in_common");
|
|
if(1) {
|
|
struct sockaddr_in a4, b4;
|
|
struct sockaddr_in6 a6, b6;
|
|
socklen_t l4 = (socklen_t)sizeof(a4);
|
|
socklen_t l6 = (socklen_t)sizeof(a6);
|
|
int i;
|
|
a4.sin_family = AF_INET;
|
|
b4.sin_family = AF_INET;
|
|
a6.sin6_family = AF_INET6;
|
|
b6.sin6_family = AF_INET6;
|
|
memcpy(&a4.sin_addr, "abcd", 4);
|
|
memcpy(&b4.sin_addr, "abcd", 4);
|
|
unit_assert(addr_in_common((struct sockaddr_storage*)&a4, 32,
|
|
(struct sockaddr_storage*)&b4, 32, l4) == 32);
|
|
unit_assert(addr_in_common((struct sockaddr_storage*)&a4, 34,
|
|
(struct sockaddr_storage*)&b4, 32, l4) == 32);
|
|
for(i=0; i<=32; i++) {
|
|
unit_assert(addr_in_common(
|
|
(struct sockaddr_storage*)&a4, 32,
|
|
(struct sockaddr_storage*)&b4, i, l4) == i);
|
|
unit_assert(addr_in_common(
|
|
(struct sockaddr_storage*)&a4, i,
|
|
(struct sockaddr_storage*)&b4, 32, l4) == i);
|
|
unit_assert(addr_in_common(
|
|
(struct sockaddr_storage*)&a4, i,
|
|
(struct sockaddr_storage*)&b4, i, l4) == i);
|
|
}
|
|
for(i=0; i<=32; i++) {
|
|
memcpy(&a4.sin_addr, "\377\377\377\377", 4);
|
|
memcpy(&b4.sin_addr, t4[i], 4);
|
|
unit_assert(addr_in_common(
|
|
(struct sockaddr_storage*)&a4, 32,
|
|
(struct sockaddr_storage*)&b4, 32, l4) == i);
|
|
unit_assert(addr_in_common(
|
|
(struct sockaddr_storage*)&b4, 32,
|
|
(struct sockaddr_storage*)&a4, 32, l4) == i);
|
|
}
|
|
memcpy(&a6.sin6_addr, "abcdefghabcdefgh", 16);
|
|
memcpy(&b6.sin6_addr, "abcdefghabcdefgh", 16);
|
|
unit_assert(addr_in_common((struct sockaddr_storage*)&a6, 128,
|
|
(struct sockaddr_storage*)&b6, 128, l6) == 128);
|
|
unit_assert(addr_in_common((struct sockaddr_storage*)&a6, 129,
|
|
(struct sockaddr_storage*)&b6, 128, l6) == 128);
|
|
for(i=0; i<=128; i++) {
|
|
unit_assert(addr_in_common(
|
|
(struct sockaddr_storage*)&a6, 128,
|
|
(struct sockaddr_storage*)&b6, i, l6) == i);
|
|
unit_assert(addr_in_common(
|
|
(struct sockaddr_storage*)&a6, i,
|
|
(struct sockaddr_storage*)&b6, 128, l6) == i);
|
|
unit_assert(addr_in_common(
|
|
(struct sockaddr_storage*)&a6, i,
|
|
(struct sockaddr_storage*)&b6, i, l6) == i);
|
|
}
|
|
}
|
|
/* test sockaddr_cmp_addr */
|
|
unit_show_func("util/net_help.c", "sockaddr_cmp_addr");
|
|
if(1) {
|
|
struct sockaddr_storage a, b;
|
|
socklen_t alen = (socklen_t)sizeof(a);
|
|
socklen_t blen = (socklen_t)sizeof(b);
|
|
unit_assert(ipstrtoaddr("127.0.0.0", 53, &a, &alen));
|
|
unit_assert(ipstrtoaddr("127.255.255.255", 53, &b, &blen));
|
|
unit_assert(sockaddr_cmp_addr(&a, alen, &b, blen) < 0);
|
|
unit_assert(sockaddr_cmp_addr(&b, blen, &a, alen) > 0);
|
|
unit_assert(sockaddr_cmp_addr(&a, alen, &a, alen) == 0);
|
|
unit_assert(sockaddr_cmp_addr(&b, blen, &b, blen) == 0);
|
|
unit_assert(ipstrtoaddr("192.168.121.5", 53, &a, &alen));
|
|
unit_assert(sockaddr_cmp_addr(&a, alen, &b, blen) > 0);
|
|
unit_assert(sockaddr_cmp_addr(&b, blen, &a, alen) < 0);
|
|
unit_assert(sockaddr_cmp_addr(&a, alen, &a, alen) == 0);
|
|
unit_assert(ipstrtoaddr("2001:3578:ffeb::99", 53, &b, &blen));
|
|
unit_assert(sockaddr_cmp_addr(&b, blen, &b, blen) == 0);
|
|
unit_assert(sockaddr_cmp_addr(&a, alen, &b, blen) < 0);
|
|
unit_assert(sockaddr_cmp_addr(&b, blen, &a, alen) > 0);
|
|
}
|
|
/* test addr_is_ip4mapped */
|
|
unit_show_func("util/net_help.c", "addr_is_ip4mapped");
|
|
if(1) {
|
|
struct sockaddr_storage a;
|
|
socklen_t l = (socklen_t)sizeof(a);
|
|
unit_assert(ipstrtoaddr("12.13.14.15", 53, &a, &l));
|
|
unit_assert(!addr_is_ip4mapped(&a, l));
|
|
unit_assert(ipstrtoaddr("fe80::217:31ff:fe91:df", 53, &a, &l));
|
|
unit_assert(!addr_is_ip4mapped(&a, l));
|
|
unit_assert(ipstrtoaddr("ffff::217:31ff:fe91:df", 53, &a, &l));
|
|
unit_assert(!addr_is_ip4mapped(&a, l));
|
|
unit_assert(ipstrtoaddr("::ffff:31ff:fe91:df", 53, &a, &l));
|
|
unit_assert(!addr_is_ip4mapped(&a, l));
|
|
unit_assert(ipstrtoaddr("::fffe:fe91:df", 53, &a, &l));
|
|
unit_assert(!addr_is_ip4mapped(&a, l));
|
|
unit_assert(ipstrtoaddr("::ffff:127.0.0.1", 53, &a, &l));
|
|
unit_assert(addr_is_ip4mapped(&a, l));
|
|
unit_assert(ipstrtoaddr("::ffff:127.0.0.2", 53, &a, &l));
|
|
unit_assert(addr_is_ip4mapped(&a, l));
|
|
unit_assert(ipstrtoaddr("::ffff:192.168.0.2", 53, &a, &l));
|
|
unit_assert(addr_is_ip4mapped(&a, l));
|
|
unit_assert(ipstrtoaddr("2::ffff:192.168.0.2", 53, &a, &l));
|
|
unit_assert(!addr_is_ip4mapped(&a, l));
|
|
}
|
|
/* test addr_is_any */
|
|
unit_show_func("util/net_help.c", "addr_is_any");
|
|
if(1) {
|
|
struct sockaddr_storage a;
|
|
socklen_t l = (socklen_t)sizeof(a);
|
|
unit_assert(ipstrtoaddr("0.0.0.0", 53, &a, &l));
|
|
unit_assert(addr_is_any(&a, l));
|
|
unit_assert(ipstrtoaddr("0.0.0.0", 10053, &a, &l));
|
|
unit_assert(addr_is_any(&a, l));
|
|
unit_assert(ipstrtoaddr("0.0.0.0", 0, &a, &l));
|
|
unit_assert(addr_is_any(&a, l));
|
|
unit_assert(ipstrtoaddr("::0", 0, &a, &l));
|
|
unit_assert(addr_is_any(&a, l));
|
|
unit_assert(ipstrtoaddr("::0", 53, &a, &l));
|
|
unit_assert(addr_is_any(&a, l));
|
|
unit_assert(ipstrtoaddr("::1", 53, &a, &l));
|
|
unit_assert(!addr_is_any(&a, l));
|
|
unit_assert(ipstrtoaddr("2001:1667::1", 0, &a, &l));
|
|
unit_assert(!addr_is_any(&a, l));
|
|
unit_assert(ipstrtoaddr("2001::0", 0, &a, &l));
|
|
unit_assert(!addr_is_any(&a, l));
|
|
unit_assert(ipstrtoaddr("10.0.0.0", 0, &a, &l));
|
|
unit_assert(!addr_is_any(&a, l));
|
|
unit_assert(ipstrtoaddr("0.0.0.10", 0, &a, &l));
|
|
unit_assert(!addr_is_any(&a, l));
|
|
unit_assert(ipstrtoaddr("192.0.2.1", 0, &a, &l));
|
|
unit_assert(!addr_is_any(&a, l));
|
|
}
|
|
}
|
|
|
|
#include "util/config_file.h"
|
|
/** test config_file: cfg_parse_memsize */
|
|
static void
|
|
config_memsize_test(void)
|
|
{
|
|
size_t v = 0;
|
|
unit_show_func("util/config_file.c", "cfg_parse_memsize");
|
|
if(0) {
|
|
/* these emit errors */
|
|
unit_assert( cfg_parse_memsize("", &v) == 0);
|
|
unit_assert( cfg_parse_memsize("bla", &v) == 0);
|
|
unit_assert( cfg_parse_memsize("nop", &v) == 0);
|
|
unit_assert( cfg_parse_memsize("n0b", &v) == 0);
|
|
unit_assert( cfg_parse_memsize("gb", &v) == 0);
|
|
unit_assert( cfg_parse_memsize("b", &v) == 0);
|
|
unit_assert( cfg_parse_memsize("kb", &v) == 0);
|
|
unit_assert( cfg_parse_memsize("kk kb", &v) == 0);
|
|
}
|
|
unit_assert( cfg_parse_memsize("0", &v) && v==0);
|
|
unit_assert( cfg_parse_memsize("1", &v) && v==1);
|
|
unit_assert( cfg_parse_memsize("10", &v) && v==10);
|
|
unit_assert( cfg_parse_memsize("10b", &v) && v==10);
|
|
unit_assert( cfg_parse_memsize("5b", &v) && v==5);
|
|
unit_assert( cfg_parse_memsize("1024", &v) && v==1024);
|
|
unit_assert( cfg_parse_memsize("1k", &v) && v==1024);
|
|
unit_assert( cfg_parse_memsize("1K", &v) && v==1024);
|
|
unit_assert( cfg_parse_memsize("1Kb", &v) && v==1024);
|
|
unit_assert( cfg_parse_memsize("1kb", &v) && v==1024);
|
|
unit_assert( cfg_parse_memsize("1 kb", &v) && v==1024);
|
|
unit_assert( cfg_parse_memsize("10 kb", &v) && v==10240);
|
|
unit_assert( cfg_parse_memsize("2k", &v) && v==2048);
|
|
unit_assert( cfg_parse_memsize("2m", &v) && v==2048*1024);
|
|
unit_assert( cfg_parse_memsize("3M", &v) && v==3072*1024);
|
|
unit_assert( cfg_parse_memsize("40m", &v) && v==40960*1024);
|
|
unit_assert( cfg_parse_memsize("1G", &v) && v==1024*1024*1024);
|
|
unit_assert( cfg_parse_memsize("1 Gb", &v) && v==1024*1024*1024);
|
|
unit_assert( cfg_parse_memsize("0 Gb", &v) && v==0*1024*1024);
|
|
}
|
|
|
|
/** test config_file: test tag code */
|
|
static void
|
|
config_tag_test(void)
|
|
{
|
|
unit_show_func("util/config_file.c", "taglist_intersect");
|
|
unit_assert( taglist_intersect(
|
|
(uint8_t*)"\000\000\000", 3, (uint8_t*)"\001\000\001", 3
|
|
) == 0);
|
|
unit_assert( taglist_intersect(
|
|
(uint8_t*)"\000\000\001", 3, (uint8_t*)"\001\000\001", 3
|
|
) == 1);
|
|
unit_assert( taglist_intersect(
|
|
(uint8_t*)"\001\000\000", 3, (uint8_t*)"\001\000\001", 3
|
|
) == 1);
|
|
unit_assert( taglist_intersect(
|
|
(uint8_t*)"\001", 1, (uint8_t*)"\001\000\001", 3
|
|
) == 1);
|
|
unit_assert( taglist_intersect(
|
|
(uint8_t*)"\001\000\001", 3, (uint8_t*)"\001", 1
|
|
) == 1);
|
|
}
|
|
|
|
#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 = UNKNOWN_SERVER_NICENESS;
|
|
int i;
|
|
struct rtt_info r;
|
|
unit_show_func("util/rtt.c", "rtt_timeout");
|
|
rtt_init(&r);
|
|
/* initial value sensible */
|
|
unit_assert( rtt_timeout(&r) == init );
|
|
rtt_lost(&r, init);
|
|
unit_assert( rtt_timeout(&r) == init*2 );
|
|
rtt_lost(&r, init*2);
|
|
unit_assert( rtt_timeout(&r) == init*4 );
|
|
rtt_update(&r, 4000);
|
|
unit_assert( rtt_timeout(&r) >= 2000 );
|
|
rtt_lost(&r, rtt_timeout(&r) );
|
|
for(i=0; i<100; i++) {
|
|
rtt_lost(&r, rtt_timeout(&r) );
|
|
unit_assert( rtt_timeout(&r) > RTT_MIN_TIMEOUT-1);
|
|
unit_assert( rtt_timeout(&r) < RTT_MAX_TIMEOUT+1);
|
|
}
|
|
/* must be the same, timehist bucket is used in stats */
|
|
unit_assert(UB_STATS_BUCKET_NUM == NUM_BUCKETS_HIST);
|
|
}
|
|
|
|
#include "services/cache/infra.h"
|
|
|
|
/* lookup and get key and data structs easily */
|
|
static struct infra_data* infra_lookup_host(struct infra_cache* infra,
|
|
struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
|
|
size_t zonelen, int wr, time_t now, struct infra_key** k)
|
|
{
|
|
struct infra_data* d;
|
|
struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
|
|
zone, zonelen, wr);
|
|
if(!e) return NULL;
|
|
d = (struct infra_data*)e->data;
|
|
if(d->ttl < now) {
|
|
lock_rw_unlock(&e->lock);
|
|
return NULL;
|
|
}
|
|
*k = (struct infra_key*)e->key;
|
|
return d;
|
|
}
|
|
|
|
/** test host cache */
|
|
static void
|
|
infra_test(void)
|
|
{
|
|
struct sockaddr_storage one;
|
|
socklen_t onelen;
|
|
uint8_t* zone = (uint8_t*)"\007example\003com\000";
|
|
size_t zonelen = 13;
|
|
struct infra_cache* slab;
|
|
struct config_file* cfg = config_create();
|
|
time_t now = 0;
|
|
uint8_t edns_lame;
|
|
int vs, to;
|
|
struct infra_key* k;
|
|
struct infra_data* d;
|
|
int init = 376;
|
|
|
|
unit_show_feature("infra cache");
|
|
unit_assert(ipstrtoaddr("127.0.0.1", 53, &one, &onelen));
|
|
|
|
slab = infra_create(cfg);
|
|
unit_assert( infra_host(slab, &one, onelen, zone, zonelen, now,
|
|
&vs, &edns_lame, &to) );
|
|
unit_assert( vs == 0 && to == init && edns_lame == 0 );
|
|
|
|
unit_assert( infra_rtt_update(slab, &one, onelen, zone, zonelen, LDNS_RR_TYPE_A, -1, init, now) );
|
|
unit_assert( infra_host(slab, &one, onelen, zone, zonelen,
|
|
now, &vs, &edns_lame, &to) );
|
|
unit_assert( vs == 0 && to == init*2 && edns_lame == 0 );
|
|
|
|
unit_assert( infra_edns_update(slab, &one, onelen, zone, zonelen, -1, now) );
|
|
unit_assert( infra_host(slab, &one, onelen, zone, zonelen,
|
|
now, &vs, &edns_lame, &to) );
|
|
unit_assert( vs == -1 && to == init*2 && edns_lame == 1);
|
|
|
|
now += cfg->host_ttl + 10;
|
|
unit_assert( infra_host(slab, &one, onelen, zone, zonelen,
|
|
now, &vs, &edns_lame, &to) );
|
|
unit_assert( vs == 0 && to == init && edns_lame == 0 );
|
|
|
|
unit_assert( infra_set_lame(slab, &one, onelen,
|
|
zone, zonelen, now, 0, 0, LDNS_RR_TYPE_A) );
|
|
unit_assert( (d=infra_lookup_host(slab, &one, onelen, zone, zonelen, 0, now, &k)) );
|
|
unit_assert( d->ttl == now+cfg->host_ttl );
|
|
unit_assert( d->edns_version == 0 );
|
|
unit_assert(!d->isdnsseclame && !d->rec_lame && d->lame_type_A &&
|
|
!d->lame_other);
|
|
lock_rw_unlock(&k->entry.lock);
|
|
|
|
/* test merge of data */
|
|
unit_assert( infra_set_lame(slab, &one, onelen,
|
|
zone, zonelen, now, 0, 0, LDNS_RR_TYPE_AAAA) );
|
|
unit_assert( (d=infra_lookup_host(slab, &one, onelen, zone, zonelen, 0, now, &k)) );
|
|
unit_assert(!d->isdnsseclame && !d->rec_lame && d->lame_type_A &&
|
|
d->lame_other);
|
|
lock_rw_unlock(&k->entry.lock);
|
|
|
|
/* test that noEDNS cannot overwrite known-yesEDNS */
|
|
now += cfg->host_ttl + 10;
|
|
unit_assert( infra_host(slab, &one, onelen, zone, zonelen,
|
|
now, &vs, &edns_lame, &to) );
|
|
unit_assert( vs == 0 && to == init && edns_lame == 0 );
|
|
|
|
unit_assert( infra_edns_update(slab, &one, onelen, zone, zonelen, 0, now) );
|
|
unit_assert( infra_host(slab, &one, onelen, zone, zonelen,
|
|
now, &vs, &edns_lame, &to) );
|
|
unit_assert( vs == 0 && to == init && edns_lame == 1 );
|
|
|
|
unit_assert( infra_edns_update(slab, &one, onelen, zone, zonelen, -1, now) );
|
|
unit_assert( infra_host(slab, &one, onelen, zone, zonelen,
|
|
now, &vs, &edns_lame, &to) );
|
|
unit_assert( vs == 0 && to == init && edns_lame == 1 );
|
|
|
|
infra_delete(slab);
|
|
config_delete(cfg);
|
|
}
|
|
|
|
#include "util/edns.h"
|
|
/* Complete version-invalid client cookie; needs a new one.
|
|
* Based on edns_cookie_rfc9018_a2 */
|
|
static void
|
|
edns_cookie_invalid_version(void)
|
|
{
|
|
uint32_t timestamp = 1559734385;
|
|
uint8_t client_cookie[] = {
|
|
0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
|
|
0x99, 0x00, 0x00, 0x00,
|
|
0x5c, 0xf7, 0x9f, 0x11,
|
|
0x1f, 0x81, 0x30, 0xc3, 0xee, 0xe2, 0x94, 0x80 };
|
|
uint8_t server_cookie[] = {
|
|
0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
|
|
0x01, 0x00, 0x00, 0x00,
|
|
0x5c, 0xf7, 0xa8, 0x71,
|
|
0xd4, 0xa5, 0x64, 0xa1, 0x44, 0x2a, 0xca, 0x77 };
|
|
uint8_t server_secret[] = {
|
|
0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
|
|
0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
|
|
uint8_t buf[32];
|
|
/* copy client cookie|version|reserved|timestamp */
|
|
memcpy(buf, client_cookie, 8 + 4 + 4);
|
|
/* copy ip 198.51.100.100 */
|
|
memcpy(buf + 16, "\306\063\144\144", 4);
|
|
unit_assert(edns_cookie_server_validate(client_cookie,
|
|
sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
|
|
buf, timestamp) == COOKIE_STATUS_INVALID);
|
|
edns_cookie_server_write(buf, server_secret, 1, timestamp);
|
|
unit_assert(memcmp(server_cookie, buf, 24) == 0);
|
|
}
|
|
|
|
/* Complete hash-invalid client cookie; needs a new one. */
|
|
static void
|
|
edns_cookie_invalid_hash(void)
|
|
{
|
|
uint32_t timestamp = 0;
|
|
uint8_t client_cookie[] = {
|
|
0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
|
|
0x01, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x32, 0xF2, 0x43, 0xB9, 0xBC, 0xFE, 0xC4, 0x06 };
|
|
uint8_t server_cookie[] = {
|
|
0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
|
|
0x01, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0xBA, 0x0D, 0x82, 0x90, 0x8F, 0xAA, 0xEB, 0xBD };
|
|
uint8_t server_secret[] = {
|
|
0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
|
|
0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
|
|
uint8_t buf[32];
|
|
/* copy client cookie|version|reserved|timestamp */
|
|
memcpy(buf, client_cookie, 8 + 4 + 4);
|
|
/* copy ip 203.0.113.203 */
|
|
memcpy(buf + 16, "\313\000\161\313", 4);
|
|
unit_assert(edns_cookie_server_validate(client_cookie,
|
|
sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
|
|
buf, timestamp) == COOKIE_STATUS_INVALID);
|
|
edns_cookie_server_write(buf, server_secret, 1, timestamp);
|
|
unit_assert(memcmp(server_cookie, buf, 24) == 0);
|
|
}
|
|
|
|
/* Complete hash-valid client cookie; more than 30 minutes old; needs a
|
|
* refreshed server cookie.
|
|
* A slightly better variation of edns_cookie_rfc9018_a3 for Unbound to check
|
|
* that RESERVED bits do not influence cookie validation. */
|
|
static void
|
|
edns_cookie_rfc9018_a3_better(void)
|
|
{
|
|
uint32_t timestamp = 1800 + 1;
|
|
uint8_t client_cookie[] = {
|
|
0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
|
|
0x01, 0xab, 0xcd, 0xef,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x32, 0xF2, 0x43, 0xB9, 0xBC, 0xFE, 0xC4, 0x06 };
|
|
uint8_t server_cookie[] = {
|
|
0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
|
|
0x01, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x07, 0x09,
|
|
0x62, 0xD5, 0x93, 0x09, 0x14, 0x5C, 0x23, 0x9D };
|
|
uint8_t server_secret[] = {
|
|
0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
|
|
0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
|
|
uint8_t buf[32];
|
|
/* copy client cookie|version|reserved|timestamp */
|
|
memcpy(buf, client_cookie, 8 + 4 + 4);
|
|
/* copy ip 203.0.113.203 */
|
|
memcpy(buf + 16, "\313\000\161\313", 4);
|
|
unit_assert(edns_cookie_server_validate(client_cookie,
|
|
sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
|
|
buf, timestamp) == COOKIE_STATUS_VALID_RENEW);
|
|
edns_cookie_server_write(buf, server_secret, 1, timestamp);
|
|
unit_assert(memcmp(server_cookie, buf, 24) == 0);
|
|
}
|
|
|
|
/* Complete hash-valid client cookie; more than 60 minutes old (expired);
|
|
* needs a refreshed server cookie. */
|
|
static void
|
|
edns_cookie_rfc9018_a3(void)
|
|
{
|
|
uint32_t timestamp = 1559734700;
|
|
uint8_t client_cookie[] = {
|
|
0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
|
|
0x01, 0xab, 0xcd, 0xef,
|
|
0x5c, 0xf7, 0x8f, 0x71,
|
|
0xa3, 0x14, 0x22, 0x7b, 0x66, 0x79, 0xeb, 0xf5 };
|
|
uint8_t server_cookie[] = {
|
|
0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
|
|
0x01, 0x00, 0x00, 0x00,
|
|
0x5c, 0xf7, 0xa9, 0xac,
|
|
0xf7, 0x3a, 0x78, 0x10, 0xac, 0xa2, 0x38, 0x1e };
|
|
uint8_t server_secret[] = {
|
|
0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
|
|
0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
|
|
uint8_t buf[32];
|
|
/* copy client cookie|version|reserved|timestamp */
|
|
memcpy(buf, client_cookie, 8 + 4 + 4);
|
|
/* copy ip 203.0.113.203 */
|
|
memcpy(buf + 16, "\313\000\161\313", 4);
|
|
unit_assert(edns_cookie_server_validate(client_cookie,
|
|
sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
|
|
buf, timestamp) == COOKIE_STATUS_EXPIRED);
|
|
edns_cookie_server_write(buf, server_secret, 1, timestamp);
|
|
unit_assert(memcmp(server_cookie, buf, 24) == 0);
|
|
}
|
|
|
|
/* Complete hash-valid client cookie; more than 30 minutes old; needs a
|
|
* refreshed server cookie. */
|
|
static void
|
|
edns_cookie_rfc9018_a2(void)
|
|
{
|
|
uint32_t timestamp = 1559734385;
|
|
uint8_t client_cookie[] = {
|
|
0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
|
|
0x01, 0x00, 0x00, 0x00,
|
|
0x5c, 0xf7, 0x9f, 0x11,
|
|
0x1f, 0x81, 0x30, 0xc3, 0xee, 0xe2, 0x94, 0x80 };
|
|
uint8_t server_cookie[] = {
|
|
0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
|
|
0x01, 0x00, 0x00, 0x00,
|
|
0x5c, 0xf7, 0xa8, 0x71,
|
|
0xd4, 0xa5, 0x64, 0xa1, 0x44, 0x2a, 0xca, 0x77 };
|
|
uint8_t server_secret[] = {
|
|
0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
|
|
0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
|
|
uint8_t buf[32];
|
|
/* copy client cookie|version|reserved|timestamp */
|
|
memcpy(buf, client_cookie, 8 + 4 + 4);
|
|
/* copy ip 198.51.100.100 */
|
|
memcpy(buf + 16, "\306\063\144\144", 4);
|
|
unit_assert(edns_cookie_server_validate(client_cookie,
|
|
sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
|
|
buf, timestamp) == COOKIE_STATUS_VALID_RENEW);
|
|
edns_cookie_server_write(buf, server_secret, 1, timestamp);
|
|
unit_assert(memcmp(server_cookie, buf, 24) == 0);
|
|
}
|
|
|
|
/* Only client cookie; needs a complete server cookie. */
|
|
static void
|
|
edns_cookie_rfc9018_a1(void)
|
|
{
|
|
uint32_t timestamp = 1559731985;
|
|
uint8_t client_cookie[] = {
|
|
0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57 };
|
|
uint8_t server_cookie[] = {
|
|
0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
|
|
0x01, 0x00, 0x00, 0x00,
|
|
0x5c, 0xf7, 0x9f, 0x11,
|
|
0x1f, 0x81, 0x30, 0xc3, 0xee, 0xe2, 0x94, 0x80 };
|
|
uint8_t server_secret[] = {
|
|
0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
|
|
0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
|
|
uint8_t buf[32];
|
|
/* copy client cookie|version|reserved|timestamp */
|
|
memcpy(buf, server_cookie, 8 + 4 + 4);
|
|
/* copy ip 198.51.100.100 */
|
|
memcpy(buf + 16, "\306\063\144\144", 4);
|
|
unit_assert(edns_cookie_server_validate(client_cookie,
|
|
sizeof(client_cookie),
|
|
/* these will not be used; it will return invalid
|
|
* because of the size. */
|
|
NULL, 0, 1, NULL, 0) == COOKIE_STATUS_CLIENT_ONLY);
|
|
edns_cookie_server_write(buf, server_secret, 1, timestamp);
|
|
unit_assert(memcmp(server_cookie, buf, 24) == 0);
|
|
}
|
|
|
|
/** test interoperable DNS cookies (RFC9018) */
|
|
static void
|
|
edns_cookie_test(void)
|
|
{
|
|
unit_show_feature("interoperable dns cookies");
|
|
/* Check RFC9018 appendix test vectors */
|
|
edns_cookie_rfc9018_a1();
|
|
edns_cookie_rfc9018_a2();
|
|
edns_cookie_rfc9018_a3();
|
|
/* More tests */
|
|
edns_cookie_rfc9018_a3_better();
|
|
edns_cookie_invalid_hash();
|
|
edns_cookie_invalid_version();
|
|
}
|
|
|
|
#include "util/random.h"
|
|
/** test randomness */
|
|
static void
|
|
rnd_test(void)
|
|
{
|
|
struct ub_randstate* r;
|
|
int num = 1000, i;
|
|
long int a[1000];
|
|
unit_show_feature("ub_random");
|
|
unit_assert( (r = ub_initstate(NULL)) );
|
|
for(i=0; i<num; i++) {
|
|
a[i] = ub_random(r);
|
|
unit_assert(a[i] >= 0);
|
|
unit_assert((size_t)a[i] <= (size_t)0x7fffffff);
|
|
if(i > 5)
|
|
unit_assert(a[i] != a[i-1] || a[i] != a[i-2] ||
|
|
a[i] != a[i-3] || a[i] != a[i-4] ||
|
|
a[i] != a[i-5] || a[i] != a[i-6]);
|
|
}
|
|
a[0] = ub_random_max(r, 1);
|
|
unit_assert(a[0] >= 0 && a[0] < 1);
|
|
a[0] = ub_random_max(r, 10000);
|
|
unit_assert(a[0] >= 0 && a[0] < 10000);
|
|
for(i=0; i<num; i++) {
|
|
a[i] = ub_random_max(r, 10);
|
|
unit_assert(a[i] >= 0 && a[i] < 10);
|
|
}
|
|
ub_randfree(r);
|
|
}
|
|
|
|
#include "respip/respip.h"
|
|
#include "services/localzone.h"
|
|
#include "util/data/packed_rrset.h"
|
|
typedef struct addr_action {char* ip; char* sact; enum respip_action act;}
|
|
addr_action_t;
|
|
|
|
/** Utility function that verifies that the respip set has actions as expected */
|
|
static void
|
|
verify_respip_set_actions(struct respip_set* set, addr_action_t actions[],
|
|
int actions_len)
|
|
{
|
|
int i = 0;
|
|
struct rbtree_type* tree = respip_set_get_tree(set);
|
|
for (i=0; i<actions_len; i++) {
|
|
struct sockaddr_storage addr;
|
|
int net;
|
|
socklen_t addrlen;
|
|
struct resp_addr* node;
|
|
netblockstrtoaddr(actions[i].ip, UNBOUND_DNS_PORT, &addr,
|
|
&addrlen, &net);
|
|
node = (struct resp_addr*)addr_tree_find(tree, &addr, addrlen, net);
|
|
|
|
/** we have the node and the node has the correct action
|
|
* and has no data */
|
|
unit_assert(node);
|
|
unit_assert(actions[i].act ==
|
|
resp_addr_get_action(node));
|
|
unit_assert(resp_addr_get_rrset(node) == NULL);
|
|
}
|
|
unit_assert(actions_len && i == actions_len);
|
|
unit_assert(actions_len == (int)tree->count);
|
|
}
|
|
|
|
/** Global respip actions test; apply raw config data and verify that
|
|
* all the nodes in the respip set, looked up by address, have expected
|
|
* actions */
|
|
static void
|
|
respip_conf_actions_test(void)
|
|
{
|
|
addr_action_t config_response_ip[] = {
|
|
{"192.0.1.0/24", "deny", respip_deny},
|
|
{"192.0.2.0/24", "redirect", respip_redirect},
|
|
{"192.0.3.0/26", "inform", respip_inform},
|
|
{"192.0.4.0/27", "inform_deny", respip_inform_deny},
|
|
{"2001:db8:1::/48", "always_transparent", respip_always_transparent},
|
|
{"2001:db8:2::/49", "always_refuse", respip_always_refuse},
|
|
{"2001:db8:3::/50", "always_nxdomain", respip_always_nxdomain},
|
|
};
|
|
int i;
|
|
struct respip_set* set = respip_set_create();
|
|
struct config_file cfg;
|
|
int clen = (int)(sizeof(config_response_ip) / sizeof(addr_action_t));
|
|
|
|
unit_assert(set);
|
|
unit_show_feature("global respip config actions apply");
|
|
memset(&cfg, 0, sizeof(cfg));
|
|
for(i=0; i<clen; i++) {
|
|
char* ip = strdup(config_response_ip[i].ip);
|
|
char* sact = strdup(config_response_ip[i].sact);
|
|
unit_assert(ip && sact);
|
|
if(!cfg_str2list_insert(&cfg.respip_actions, ip, sact))
|
|
unit_assert(0);
|
|
}
|
|
unit_assert(respip_global_apply_cfg(set, &cfg));
|
|
verify_respip_set_actions(set, config_response_ip, clen);
|
|
|
|
respip_set_delete(set);
|
|
config_deldblstrlist(cfg.respip_actions);
|
|
}
|
|
|
|
/** Per-view respip actions test; apply raw configuration with two views
|
|
* and verify that actions are as expected in respip sets of both views */
|
|
static void
|
|
respip_view_conf_actions_test(void)
|
|
{
|
|
addr_action_t config_response_ip_view1[] = {
|
|
{"192.0.1.0/24", "deny", respip_deny},
|
|
{"192.0.2.0/24", "redirect", respip_redirect},
|
|
{"192.0.3.0/26", "inform", respip_inform},
|
|
{"192.0.4.0/27", "inform_deny", respip_inform_deny},
|
|
};
|
|
addr_action_t config_response_ip_view2[] = {
|
|
{"2001:db8:1::/48", "always_transparent", respip_always_transparent},
|
|
{"2001:db8:2::/49", "always_refuse", respip_always_refuse},
|
|
{"2001:db8:3::/50", "always_nxdomain", respip_always_nxdomain},
|
|
};
|
|
int i;
|
|
struct config_file cfg;
|
|
int clen1 = (int)(sizeof(config_response_ip_view1) / sizeof(addr_action_t));
|
|
int clen2 = (int)(sizeof(config_response_ip_view2) / sizeof(addr_action_t));
|
|
struct config_view* cv1;
|
|
struct config_view* cv2;
|
|
int have_respip_cfg = 0;
|
|
struct views* views = NULL;
|
|
struct view* v = NULL;
|
|
|
|
unit_show_feature("per-view respip config actions apply");
|
|
memset(&cfg, 0, sizeof(cfg));
|
|
cv1 = (struct config_view*)calloc(1, sizeof(struct config_view));
|
|
cv2 = (struct config_view*)calloc(1, sizeof(struct config_view));
|
|
unit_assert(cv1 && cv2);
|
|
cv1->name = strdup("view1");
|
|
cv2->name = strdup("view2");
|
|
unit_assert(cv1->name && cv2->name);
|
|
cv1->next = cv2;
|
|
cfg.views = cv1;
|
|
|
|
for(i=0; i<clen1; i++) {
|
|
char* ip = strdup(config_response_ip_view1[i].ip);
|
|
char* sact = strdup(config_response_ip_view1[i].sact);
|
|
unit_assert(ip && sact);
|
|
if(!cfg_str2list_insert(&cv1->respip_actions, ip, sact))
|
|
unit_assert(0);
|
|
}
|
|
for(i=0; i<clen2; i++) {
|
|
char* ip = strdup(config_response_ip_view2[i].ip);
|
|
char* sact = strdup(config_response_ip_view2[i].sact);
|
|
unit_assert(ip && sact);
|
|
if(!cfg_str2list_insert(&cv2->respip_actions, ip, sact))
|
|
unit_assert(0);
|
|
}
|
|
views = views_create();
|
|
unit_assert(views);
|
|
unit_assert(views_apply_cfg(views, &cfg));
|
|
unit_assert(respip_views_apply_cfg(views, &cfg, &have_respip_cfg));
|
|
|
|
/* now verify the respip sets in each view */
|
|
v = views_find_view(views, "view1", 0);
|
|
unit_assert(v);
|
|
verify_respip_set_actions(v->respip_set, config_response_ip_view1, clen1);
|
|
lock_rw_unlock(&v->lock);
|
|
v = views_find_view(views, "view2", 0);
|
|
unit_assert(v);
|
|
verify_respip_set_actions(v->respip_set, config_response_ip_view2, clen2);
|
|
lock_rw_unlock(&v->lock);
|
|
|
|
views_delete(views);
|
|
free(cv1->name);
|
|
free(cv1);
|
|
free(cv2->name);
|
|
free(cv2);
|
|
}
|
|
|
|
typedef struct addr_data {char* ip; char* data;} addr_data_t;
|
|
|
|
/** find the respip address node in the specified tree (by address lookup)
|
|
* and verify type and address of the specified rdata (by index) in this
|
|
* node's rrset */
|
|
static void
|
|
verify_rrset(struct respip_set* set, const char* ipstr,
|
|
const char* rdatastr, size_t rdi, uint16_t type)
|
|
{
|
|
struct sockaddr_storage addr;
|
|
int net;
|
|
char buf[65536];
|
|
socklen_t addrlen;
|
|
struct rbtree_type* tree;
|
|
struct resp_addr* node;
|
|
const struct ub_packed_rrset_key* rrs;
|
|
|
|
netblockstrtoaddr(ipstr, UNBOUND_DNS_PORT, &addr, &addrlen, &net);
|
|
tree = respip_set_get_tree(set);
|
|
node = (struct resp_addr*)addr_tree_find(tree, &addr, addrlen, net);
|
|
unit_assert(node);
|
|
unit_assert((rrs = resp_addr_get_rrset(node)));
|
|
unit_assert(ntohs(rrs->rk.type) == type);
|
|
packed_rr_to_string((struct ub_packed_rrset_key*)rrs,
|
|
rdi, 0, buf, sizeof(buf));
|
|
unit_assert(strstr(buf, rdatastr));
|
|
}
|
|
|
|
/** Dataset used to test redirect rrset initialization for both
|
|
* global and per-view respip redirect configuration */
|
|
static addr_data_t config_response_ip_data[] = {
|
|
{"192.0.1.0/24", "A 1.2.3.4"},
|
|
{"192.0.1.0/24", "A 11.12.13.14"},
|
|
{"192.0.2.0/24", "CNAME www.example.com."},
|
|
{"2001:db8:1::/48", "AAAA 2001:db8:1::2:1"},
|
|
};
|
|
|
|
/** Populate raw respip redirect config data, used for both global and
|
|
* view-based respip redirect test case */
|
|
static void
|
|
cfg_insert_respip_data(struct config_str2list** respip_actions,
|
|
struct config_str2list** respip_data)
|
|
{
|
|
int clen = (int)(sizeof(config_response_ip_data) / sizeof(addr_data_t));
|
|
int i = 0;
|
|
|
|
/* insert actions (duplicate netblocks don't matter) */
|
|
for(i=0; i<clen; i++) {
|
|
char* ip = strdup(config_response_ip_data[i].ip);
|
|
char* sact = strdup("redirect");
|
|
unit_assert(ip && sact);
|
|
if(!cfg_str2list_insert(respip_actions, ip, sact))
|
|
unit_assert(0);
|
|
}
|
|
/* insert data */
|
|
for(i=0; i<clen; i++) {
|
|
char* ip = strdup(config_response_ip_data[i].ip);
|
|
char* data = strdup(config_response_ip_data[i].data);
|
|
unit_assert(ip && data);
|
|
if(!cfg_str2list_insert(respip_data, ip, data))
|
|
unit_assert(0);
|
|
}
|
|
}
|
|
|
|
/** Test global respip redirect w/ data directives */
|
|
static void
|
|
respip_conf_data_test(void)
|
|
{
|
|
struct respip_set* set = respip_set_create();
|
|
struct config_file cfg;
|
|
|
|
unit_show_feature("global respip config data apply");
|
|
memset(&cfg, 0, sizeof(cfg));
|
|
|
|
cfg_insert_respip_data(&cfg.respip_actions, &cfg.respip_data);
|
|
|
|
/* apply configuration and verify rrsets */
|
|
unit_assert(respip_global_apply_cfg(set, &cfg));
|
|
verify_rrset(set, "192.0.1.0/24", "1.2.3.4", 0, LDNS_RR_TYPE_A);
|
|
verify_rrset(set, "192.0.1.0/24", "11.12.13.14", 1, LDNS_RR_TYPE_A);
|
|
verify_rrset(set, "192.0.2.0/24", "www.example.com", 0, LDNS_RR_TYPE_CNAME);
|
|
verify_rrset(set, "2001:db8:1::/48", "2001:db8:1::2:1", 0, LDNS_RR_TYPE_AAAA);
|
|
|
|
respip_set_delete(set);
|
|
}
|
|
|
|
/** Test per-view respip redirect w/ data directives */
|
|
static void
|
|
respip_view_conf_data_test(void)
|
|
{
|
|
struct config_file cfg;
|
|
struct config_view* cv;
|
|
int have_respip_cfg = 0;
|
|
struct views* views = NULL;
|
|
struct view* v = NULL;
|
|
|
|
unit_show_feature("per-view respip config data apply");
|
|
memset(&cfg, 0, sizeof(cfg));
|
|
cv = (struct config_view*)calloc(1, sizeof(struct config_view));
|
|
unit_assert(cv);
|
|
cv->name = strdup("view1");
|
|
unit_assert(cv->name);
|
|
cfg.views = cv;
|
|
cfg_insert_respip_data(&cv->respip_actions, &cv->respip_data);
|
|
views = views_create();
|
|
unit_assert(views);
|
|
unit_assert(views_apply_cfg(views, &cfg));
|
|
|
|
/* apply configuration and verify rrsets */
|
|
unit_assert(respip_views_apply_cfg(views, &cfg, &have_respip_cfg));
|
|
v = views_find_view(views, "view1", 0);
|
|
unit_assert(v);
|
|
verify_rrset(v->respip_set, "192.0.1.0/24", "1.2.3.4",
|
|
0, LDNS_RR_TYPE_A);
|
|
verify_rrset(v->respip_set, "192.0.1.0/24", "11.12.13.14",
|
|
1, LDNS_RR_TYPE_A);
|
|
verify_rrset(v->respip_set, "192.0.2.0/24", "www.example.com",
|
|
0, LDNS_RR_TYPE_CNAME);
|
|
verify_rrset(v->respip_set, "2001:db8:1::/48", "2001:db8:1::2:1",
|
|
0, LDNS_RR_TYPE_AAAA);
|
|
lock_rw_unlock(&v->lock);
|
|
|
|
views_delete(views);
|
|
free(cv->name);
|
|
free(cv);
|
|
}
|
|
|
|
/** respip unit tests */
|
|
static void respip_test(void)
|
|
{
|
|
respip_view_conf_data_test();
|
|
respip_conf_data_test();
|
|
respip_view_conf_actions_test();
|
|
respip_conf_actions_test();
|
|
}
|
|
|
|
#include "util/regional.h"
|
|
#include "sldns/sbuffer.h"
|
|
#include "util/data/dname.h"
|
|
#include "util/data/msgreply.h"
|
|
#include "util/data/msgencode.h"
|
|
#include "sldns/str2wire.h"
|
|
|
|
static void edns_ede_encode_setup(struct edns_data* edns,
|
|
struct regional* region)
|
|
{
|
|
memset(edns, 0, sizeof(*edns));
|
|
edns->edns_present = 1;
|
|
edns->edns_version = EDNS_ADVERTISED_VERSION;
|
|
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
|
edns->bits &= EDNS_DO;
|
|
/* Fill up opt_list_out with EDEs */
|
|
unit_assert(
|
|
edns_opt_list_append_ede(&edns->opt_list_out, region,
|
|
LDNS_EDE_OTHER, "Too long other text"));
|
|
unit_assert(
|
|
edns_opt_list_append_ede(&edns->opt_list_out, region,
|
|
LDNS_EDE_OTHER, "Too long other text"));
|
|
unit_assert(
|
|
edns_opt_list_append_ede(&edns->opt_list_out, region,
|
|
LDNS_EDE_BLOCKED, "Too long blocked text"));
|
|
unit_assert(
|
|
edns_opt_list_append_ede(&edns->opt_list_out, region,
|
|
LDNS_EDE_OTHER, "Too long other text"));
|
|
unit_assert(
|
|
edns_opt_list_append_ede(&edns->opt_list_out, region,
|
|
LDNS_EDE_BLOCKED, "Too long blocked text"));
|
|
/* Fill up opt_list_inplace_cb_out with EDEs */
|
|
unit_assert(
|
|
edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region,
|
|
LDNS_EDE_OTHER, "Too long other text"));
|
|
unit_assert(
|
|
edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region,
|
|
LDNS_EDE_OTHER, "Too long other text"));
|
|
unit_assert(
|
|
edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region,
|
|
LDNS_EDE_BLOCKED, "Too long blocked text"));
|
|
unit_assert(
|
|
edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region,
|
|
LDNS_EDE_OTHER, "Too long other text"));
|
|
unit_assert(
|
|
edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region,
|
|
LDNS_EDE_BLOCKED, "Too long blocked text"));
|
|
/* append another EDNS option to both lists */
|
|
unit_assert(
|
|
edns_opt_list_append(&edns->opt_list_out,
|
|
LDNS_EDNS_UNBOUND_CACHEDB_TESTFRAME_TEST, 0, NULL, region));
|
|
unit_assert(
|
|
edns_opt_list_append(&edns->opt_list_inplace_cb_out,
|
|
LDNS_EDNS_UNBOUND_CACHEDB_TESTFRAME_TEST, 0, NULL, region));
|
|
/* append LDNS_EDE_OTHER at the end of both lists */
|
|
unit_assert(
|
|
edns_opt_list_append_ede(&edns->opt_list_out, region,
|
|
LDNS_EDE_OTHER, "Too long other text"));
|
|
unit_assert(
|
|
edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region,
|
|
LDNS_EDE_OTHER, "Too long other text"));
|
|
}
|
|
|
|
static void edns_ede_encode_encodedecode(struct query_info* qinfo,
|
|
struct reply_info* rep, struct regional* region,
|
|
struct edns_data* edns, sldns_buffer* pkt)
|
|
{
|
|
/* encode */
|
|
unit_assert(
|
|
reply_info_answer_encode(qinfo, rep, 1, rep->flags, pkt,
|
|
0, 0, region, 65535, edns, 0, 0));
|
|
/* buffer ready for reading; skip after the question section */
|
|
sldns_buffer_skip(pkt, LDNS_HEADER_SIZE);
|
|
(void)query_dname_len(pkt);
|
|
sldns_buffer_skip(pkt, 2 + 2);
|
|
/* decode */
|
|
unit_assert(parse_edns_from_query_pkt(pkt, edns, NULL, NULL, NULL, 0,
|
|
region, NULL) == 0);
|
|
}
|
|
|
|
static void edns_ede_encode_check(struct edns_data* edns, int* found_ede,
|
|
int* found_ede_other, int* found_ede_txt, int* found_other_edns)
|
|
{
|
|
struct edns_option* opt;
|
|
for(opt = edns->opt_list_in; opt; opt = opt->next) {
|
|
if(opt->opt_code == LDNS_EDNS_EDE) {
|
|
(*found_ede)++;
|
|
if(opt->opt_len > 2)
|
|
(*found_ede_txt)++;
|
|
if(opt->opt_len >= 2 && sldns_read_uint16(
|
|
opt->opt_data) == LDNS_EDE_OTHER)
|
|
(*found_ede_other)++;
|
|
} else {
|
|
(*found_other_edns)++;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
static void edns_ede_encode_fit_test(struct query_info* qinfo,
|
|
struct reply_info* rep, struct regional* region)
|
|
{
|
|
struct edns_data edns;
|
|
int found_ede = 0, found_ede_other = 0, found_ede_txt = 0;
|
|
int found_other_edns = 0;
|
|
sldns_buffer* pkt = sldns_buffer_new(65535);
|
|
unit_assert(pkt);
|
|
edns_ede_encode_setup(&edns, region);
|
|
/* leave the pkt buffer as is; everything should fit */
|
|
edns_ede_encode_encodedecode(qinfo, rep, region, &edns, pkt);
|
|
edns_ede_encode_check(&edns, &found_ede, &found_ede_other,
|
|
&found_ede_txt, &found_other_edns);
|
|
unit_assert(found_ede == 12);
|
|
unit_assert(found_ede_other == 8);
|
|
unit_assert(found_ede_txt == 12);
|
|
unit_assert(found_other_edns == 2);
|
|
/* cleanup */
|
|
sldns_buffer_free(pkt);
|
|
}
|
|
|
|
static void edns_ede_encode_notxt_fit_test( struct query_info* qinfo,
|
|
struct reply_info* rep, struct regional* region)
|
|
{
|
|
struct edns_data edns;
|
|
sldns_buffer* pkt;
|
|
uint16_t edns_field_size, ede_txt_size;
|
|
int found_ede = 0, found_ede_other = 0, found_ede_txt = 0;
|
|
int found_other_edns = 0;
|
|
edns_ede_encode_setup(&edns, region);
|
|
/* pkt buffer should fit everything if the ede txt is cropped.
|
|
* OTHER EDE should not be there since it is useless without text. */
|
|
edns_field_size = calc_edns_field_size(&edns);
|
|
(void)calc_ede_option_size(&edns, &ede_txt_size);
|
|
pkt = sldns_buffer_new(LDNS_HEADER_SIZE
|
|
+ qinfo->qname_len
|
|
+ 2 + 2 /* qtype + qclass */
|
|
+ 11 /* opt record */
|
|
+ edns_field_size
|
|
- ede_txt_size);
|
|
unit_assert(pkt);
|
|
edns_ede_encode_encodedecode(qinfo, rep, region, &edns, pkt);
|
|
edns_ede_encode_check(&edns, &found_ede, &found_ede_other,
|
|
&found_ede_txt, &found_other_edns);
|
|
unit_assert(found_ede == 4);
|
|
unit_assert(found_ede_other == 0);
|
|
unit_assert(found_ede_txt == 0);
|
|
unit_assert(found_other_edns == 2);
|
|
/* cleanup */
|
|
sldns_buffer_free(pkt);
|
|
}
|
|
|
|
static void edns_ede_encode_no_fit_test( struct query_info* qinfo,
|
|
struct reply_info* rep, struct regional* region)
|
|
{
|
|
struct edns_data edns;
|
|
sldns_buffer* pkt;
|
|
uint16_t edns_field_size, ede_size, ede_txt_size;
|
|
int found_ede = 0, found_ede_other = 0, found_ede_txt = 0;
|
|
int found_other_edns = 0;
|
|
edns_ede_encode_setup(&edns, region);
|
|
/* pkt buffer should fit only non-EDE options. */
|
|
edns_field_size = calc_edns_field_size(&edns);
|
|
ede_size = calc_ede_option_size(&edns, &ede_txt_size);
|
|
pkt = sldns_buffer_new(LDNS_HEADER_SIZE
|
|
+ qinfo->qname_len
|
|
+ 2 + 2 /* qtype + qclass */
|
|
+ 11 /* opt record */
|
|
+ edns_field_size
|
|
- ede_size);
|
|
unit_assert(pkt);
|
|
edns_ede_encode_encodedecode(qinfo, rep, region, &edns, pkt);
|
|
edns_ede_encode_check(&edns, &found_ede, &found_ede_other,
|
|
&found_ede_txt, &found_other_edns);
|
|
unit_assert(found_ede == 0);
|
|
unit_assert(found_ede_other == 0);
|
|
unit_assert(found_ede_txt == 0);
|
|
unit_assert(found_other_edns == 2);
|
|
/* cleanup */
|
|
sldns_buffer_free(pkt);
|
|
}
|
|
|
|
/** test optional EDE encoding with various buffer
|
|
* available sizes */
|
|
static void edns_ede_answer_encode_test(void)
|
|
{
|
|
struct regional* region = regional_create();
|
|
struct reply_info* rep;
|
|
struct query_info qinfo;
|
|
unit_show_feature("edns ede optional encoding");
|
|
unit_assert(region);
|
|
rep = construct_reply_info_base(region,
|
|
LDNS_RCODE_NOERROR | BIT_QR, 1,
|
|
3600, 3600, 3600, 0,
|
|
0, 0, 0, 0,
|
|
sec_status_unchecked, LDNS_EDE_NONE);
|
|
unit_assert(rep);
|
|
memset(&qinfo, 0, sizeof(qinfo));
|
|
qinfo.qname = sldns_str2wire_dname("encode.ede.", &qinfo.qname_len);
|
|
unit_assert(qinfo.qname);
|
|
qinfo.qtype = LDNS_RR_TYPE_TXT;
|
|
qinfo.qclass = LDNS_RR_CLASS_IN;
|
|
|
|
edns_ede_encode_fit_test(&qinfo, rep, region);
|
|
edns_ede_encode_notxt_fit_test(&qinfo, rep, region);
|
|
edns_ede_encode_no_fit_test(&qinfo, rep, region);
|
|
|
|
/* cleanup */
|
|
free(qinfo.qname);
|
|
regional_free_all(region);
|
|
regional_destroy(region);
|
|
}
|
|
|
|
#include "services/localzone.h"
|
|
/* Utility function that compares two localzone trees */
|
|
static void compare_localzone_trees(struct local_zones* z1,
|
|
struct local_zones* z2)
|
|
{
|
|
struct local_zone *node1, *node2;
|
|
lock_rw_rdlock(&z1->lock);
|
|
lock_rw_rdlock(&z2->lock);
|
|
/* size should be the same */
|
|
unit_assert(z1->ztree.count == z2->ztree.count);
|
|
for(node1=(struct local_zone*)rbtree_first(&z1->ztree),
|
|
node2=(struct local_zone*)rbtree_first(&z2->ztree);
|
|
(rbnode_type*)node1 != RBTREE_NULL &&
|
|
(rbnode_type*)node2 != RBTREE_NULL;
|
|
node1=(struct local_zone*)rbtree_next((rbnode_type*)node1),
|
|
node2=(struct local_zone*)rbtree_next((rbnode_type*)node2)) {
|
|
int labs;
|
|
/* the same zone should be at the same nodes */
|
|
unit_assert(!dname_lab_cmp(
|
|
node1->name, node1->namelabs,
|
|
node2->name, node2->namelabs,
|
|
&labs));
|
|
/* the zone's parent should be the same on both nodes */
|
|
unit_assert(
|
|
(node1->parent == NULL && node2->parent == NULL) ||
|
|
(node1->parent != NULL && node2->parent != NULL));
|
|
if(node1->parent) {
|
|
unit_assert(!dname_lab_cmp(
|
|
node1->parent->name, node1->parent->namelabs,
|
|
node2->parent->name, node2->parent->namelabs,
|
|
&labs));
|
|
}
|
|
}
|
|
lock_rw_unlock(&z1->lock);
|
|
lock_rw_unlock(&z2->lock);
|
|
}
|
|
|
|
/* test that zone addition results in the same tree from both the configuration
|
|
* file and the unbound-control commands */
|
|
static void localzone_parents_test(void)
|
|
{
|
|
struct local_zones *z1, *z2;
|
|
size_t i;
|
|
char* zone_data[] = {
|
|
"one",
|
|
"a.b.c.one",
|
|
"b.c.one",
|
|
"c.one",
|
|
"two",
|
|
"c.two",
|
|
"b.c.two",
|
|
"a.b.c.two",
|
|
"a.b.c.three",
|
|
"b.c.three",
|
|
"c.three",
|
|
"three",
|
|
"c.four",
|
|
"b.c.four",
|
|
"a.b.c.four",
|
|
"four",
|
|
"."
|
|
};
|
|
unit_show_feature("localzones parent calculation");
|
|
z1 = local_zones_create();
|
|
z2 = local_zones_create();
|
|
/* parse test data */
|
|
for(i=0; i<sizeof(zone_data)/sizeof(zone_data[0]); i++) {
|
|
uint8_t* nm;
|
|
int nmlabs;
|
|
size_t nmlen;
|
|
struct local_zone* z;
|
|
|
|
/* This is the config way */
|
|
z = lz_enter_zone(z1, zone_data[i], "always_nxdomain",
|
|
LDNS_RR_CLASS_IN);
|
|
(void)z; /* please compiler when no threading and no lock
|
|
code; the following line disappears and z stays unused */
|
|
lock_rw_unlock(&z->lock);
|
|
lz_init_parents(z1);
|
|
|
|
/* This is the unbound-control way */
|
|
nm = sldns_str2wire_dname(zone_data[i], &nmlen);
|
|
if(!nm) unit_assert(0);
|
|
nmlabs = dname_count_size_labels(nm, &nmlen);
|
|
lock_rw_wrlock(&z2->lock);
|
|
local_zones_add_zone(z2, nm, nmlen, nmlabs, LDNS_RR_CLASS_IN,
|
|
local_zone_always_nxdomain);
|
|
lock_rw_unlock(&z2->lock);
|
|
}
|
|
/* The trees should be the same, iterate and check the nodes */
|
|
compare_localzone_trees(z1, z2);
|
|
|
|
/* cleanup */
|
|
local_zones_delete(z1);
|
|
local_zones_delete(z2);
|
|
}
|
|
|
|
/** localzone unit tests */
|
|
static void localzone_test(void)
|
|
{
|
|
localzone_parents_test();
|
|
}
|
|
|
|
void unit_show_func(const char* file, const char* func)
|
|
{
|
|
printf("test %s:%s\n", file, func);
|
|
}
|
|
|
|
void unit_show_feature(const char* feature)
|
|
{
|
|
printf("test %s functions\n", feature);
|
|
}
|
|
|
|
#ifdef USE_ECDSA_EVP_WORKAROUND
|
|
void ecdsa_evp_workaround_init(void);
|
|
#endif
|
|
|
|
/**
|
|
* Main unit test program. Setup, teardown and report errors.
|
|
* @param argc: arg count.
|
|
* @param argv: array of commandline arguments.
|
|
* @return program failure if test fails.
|
|
*/
|
|
int
|
|
main(int argc, char* argv[])
|
|
{
|
|
checklock_start();
|
|
log_init(NULL, 0, NULL);
|
|
if(argc != 1) {
|
|
printf("usage: %s\n", argv[0]);
|
|
printf("\tperforms unit tests.\n");
|
|
return 1;
|
|
}
|
|
/* Disable roundrobin for the unit tests */
|
|
RRSET_ROUNDROBIN = 0;
|
|
#ifdef USE_LIBEVENT
|
|
printf("Start of %s+libevent unit test.\n", PACKAGE_STRING);
|
|
#else
|
|
printf("Start of %s unit test.\n", PACKAGE_STRING);
|
|
#endif
|
|
#ifdef HAVE_SSL
|
|
# ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS
|
|
ERR_load_crypto_strings();
|
|
# endif
|
|
# ifdef USE_GOST
|
|
(void)sldns_key_EVP_load_gost_id();
|
|
# endif
|
|
# ifdef USE_ECDSA_EVP_WORKAROUND
|
|
ecdsa_evp_workaround_init();
|
|
# endif
|
|
#elif defined(HAVE_NSS)
|
|
if(NSS_NoDB_Init(".") != SECSuccess)
|
|
fatal_exit("could not init NSS");
|
|
#endif /* HAVE_SSL or HAVE_NSS*/
|
|
authzone_test();
|
|
neg_test();
|
|
rnd_test();
|
|
respip_test();
|
|
verify_test();
|
|
net_test();
|
|
config_memsize_test();
|
|
config_tag_test();
|
|
dname_test();
|
|
rtt_test();
|
|
anchors_test();
|
|
alloc_test();
|
|
regional_test();
|
|
lruhash_test();
|
|
slabhash_test();
|
|
infra_test();
|
|
ldns_test();
|
|
edns_cookie_test();
|
|
zonemd_test();
|
|
tcpreuse_test();
|
|
msgparse_test();
|
|
edns_ede_answer_encode_test();
|
|
localzone_test();
|
|
#ifdef CLIENT_SUBNET
|
|
ecs_test();
|
|
#endif /* CLIENT_SUBNET */
|
|
#ifdef HAVE_NGTCP2
|
|
doq_test();
|
|
#endif /* HAVE_NGTCP2 */
|
|
if(log_get_lock()) {
|
|
lock_basic_destroy((lock_basic_type*)log_get_lock());
|
|
}
|
|
checklock_stop();
|
|
printf("%d checks ok.\n", testcount);
|
|
#ifdef HAVE_SSL
|
|
# if defined(USE_GOST)
|
|
sldns_key_EVP_unload_gost();
|
|
# endif
|
|
# ifdef HAVE_OPENSSL_CONFIG
|
|
# ifdef HAVE_EVP_CLEANUP
|
|
EVP_cleanup();
|
|
# endif
|
|
# if (OPENSSL_VERSION_NUMBER < 0x10100000) && !defined(OPENSSL_NO_ENGINE) && defined(HAVE_ENGINE_CLEANUP)
|
|
ENGINE_cleanup();
|
|
# endif
|
|
CONF_modules_free();
|
|
# endif
|
|
# ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
|
|
CRYPTO_cleanup_all_ex_data();
|
|
# endif
|
|
# ifdef HAVE_ERR_FREE_STRINGS
|
|
ERR_free_strings();
|
|
# endif
|
|
# ifdef HAVE_RAND_CLEANUP
|
|
RAND_cleanup();
|
|
# endif
|
|
#elif defined(HAVE_NSS)
|
|
if(NSS_Shutdown() != SECSuccess)
|
|
fatal_exit("could not shutdown NSS");
|
|
#endif /* HAVE_SSL or HAVE_NSS */
|
|
#ifdef HAVE_PTHREAD
|
|
/* dlopen frees its thread specific state */
|
|
pthread_exit(NULL);
|
|
#endif
|
|
return 0;
|
|
}
|