mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-09-27 20:24:55 +02:00
- separate ldns into core ldns inside ldns/ subdirectory. No more
--with-ldns is needed and unbound does not rely on libldns. git-svn-id: file:///svn/unbound/trunk@2998 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
@@ -48,6 +48,7 @@
|
||||
#include "libunbound/context.h"
|
||||
#include "util/locks.h"
|
||||
#include "util/log.h"
|
||||
#include "ldns/rrdef.h"
|
||||
#ifdef UNBOUND_ALLOC_LITE
|
||||
#undef malloc
|
||||
#undef calloc
|
||||
|
||||
+3
-2
@@ -50,6 +50,7 @@
|
||||
#include <sys/time.h>
|
||||
#include "util/net_help.h"
|
||||
#include "util/config_file.h"
|
||||
#include "ldns/sbuffer.h"
|
||||
#include <signal.h>
|
||||
|
||||
/** number of reads per select for delayer */
|
||||
@@ -889,12 +890,12 @@ proxy_list_clear(struct proxy* p)
|
||||
if(inet_ntop(AF_INET6,
|
||||
&((struct sockaddr_in6*)&p->addr)->sin6_addr,
|
||||
from, (socklen_t)sizeof(from)) == 0)
|
||||
strncpy(from, "err", sizeof(from));
|
||||
strlcpy(from, "err", sizeof(from));
|
||||
} else {
|
||||
if(inet_ntop(AF_INET,
|
||||
&((struct sockaddr_in*)&p->addr)->sin_addr,
|
||||
from, (socklen_t)sizeof(from)) == 0)
|
||||
strncpy(from, "err", sizeof(from));
|
||||
strlcpy(from, "err", sizeof(from));
|
||||
}
|
||||
printf("client[%d]: last %s@%d of %d : %u in, %u out, "
|
||||
"%u returned\n", i++, from, port, (int)p->numreuse+1,
|
||||
|
||||
+68
-75
@@ -57,9 +57,12 @@
|
||||
#include "services/outside_network.h"
|
||||
#include "services/cache/infra.h"
|
||||
#include "testcode/replay.h"
|
||||
#include "testcode/ldns-testpkts.h"
|
||||
#include "testcode/testpkts.h"
|
||||
#include "util/log.h"
|
||||
#include "util/fptr_wlist.h"
|
||||
#include "ldns/sbuffer.h"
|
||||
#include "ldns/wire2str.h"
|
||||
#include "ldns/str2wire.h"
|
||||
#include <signal.h>
|
||||
struct worker;
|
||||
struct daemon_remote;
|
||||
@@ -108,11 +111,11 @@ fake_event_cleanup(void)
|
||||
|
||||
/** helper function that logs a ldns_pkt packet to logfile */
|
||||
static void
|
||||
log_pkt(const char* desc, ldns_pkt* pkt)
|
||||
log_pkt(const char* desc, uint8_t* pkt, size_t len)
|
||||
{
|
||||
char* str = ldns_pkt2str(pkt);
|
||||
char* str = ldns_wire2str_pkt(pkt, len);
|
||||
if(!str)
|
||||
log_info("%s: (failed)", desc);
|
||||
fatal_exit("%s: (failed out of memory wire2str_pkt)", desc);
|
||||
else {
|
||||
log_info("%s%s", desc, str);
|
||||
free(str);
|
||||
@@ -150,7 +153,7 @@ delete_fake_pending(struct fake_pending* pend)
|
||||
return;
|
||||
free(pend->zone);
|
||||
ldns_buffer_free(pend->buffer);
|
||||
ldns_pkt_free(pend->pkt);
|
||||
free(pend->pkt);
|
||||
free(pend);
|
||||
}
|
||||
|
||||
@@ -164,7 +167,7 @@ delete_replay_answer(struct replay_answer* a)
|
||||
ldns_buffer_free(a->repinfo.c->buffer);
|
||||
free(a->repinfo.c);
|
||||
}
|
||||
ldns_pkt_free(a->pkt);
|
||||
free(a->pkt);
|
||||
free(a);
|
||||
}
|
||||
|
||||
@@ -186,7 +189,8 @@ pending_matches_current(struct replay_runtime* runtime,
|
||||
sockaddr_cmp(&p->addr, p->addrlen, &runtime->now->addr,
|
||||
runtime->now->addrlen) != 0)
|
||||
continue;
|
||||
if((e=find_match(runtime->now->match, p->pkt, p->transport))) {
|
||||
if((e=find_match(runtime->now->match, p->pkt, p->pkt_len,
|
||||
p->transport))) {
|
||||
*entry = e;
|
||||
*pend = p;
|
||||
return 1;
|
||||
@@ -212,13 +216,16 @@ pending_find_match(struct replay_runtime* runtime, struct entry** entry,
|
||||
if(p->start_step <= timenow && timenow <= p->end_step &&
|
||||
(p->addrlen == 0 || sockaddr_cmp(&p->addr, p->addrlen,
|
||||
&pend->addr, pend->addrlen) == 0) &&
|
||||
(*entry = find_match(p->match, pend->pkt, pend->transport))) {
|
||||
(*entry = find_match(p->match, pend->pkt, pend->pkt_len,
|
||||
pend->transport))) {
|
||||
log_info("matched query time %d in range [%d, %d] "
|
||||
"with entry line %d", timenow,
|
||||
p->start_step, p->end_step, (*entry)->lineno);
|
||||
if(p->addrlen != 0)
|
||||
log_addr(0, "matched ip", &p->addr, p->addrlen);
|
||||
log_pkt("matched pkt: ", (*entry)->reply_list->reply);
|
||||
log_pkt("matched pkt: ",
|
||||
(*entry)->reply_list->reply_pkt,
|
||||
(*entry)->reply_list->reply_len);
|
||||
return 1;
|
||||
}
|
||||
p = p->next_range;
|
||||
@@ -275,31 +282,26 @@ pending_list_delete(struct replay_runtime* runtime, struct fake_pending* pend)
|
||||
* Fill buffer with reply from the entry.
|
||||
*/
|
||||
static void
|
||||
fill_buffer_with_reply(ldns_buffer* buffer, struct entry* entry, ldns_pkt* q)
|
||||
fill_buffer_with_reply(ldns_buffer* buffer, struct entry* entry, uint8_t* q,
|
||||
size_t qlen)
|
||||
{
|
||||
ldns_status status;
|
||||
ldns_pkt* answer_pkt = NULL;
|
||||
uint8_t* c;
|
||||
size_t clen;
|
||||
log_assert(entry && entry->reply_list);
|
||||
ldns_buffer_clear(buffer);
|
||||
if(entry->reply_list->reply_from_hex) {
|
||||
status = ldns_buffer2pkt_wire(&answer_pkt,
|
||||
entry->reply_list->reply_from_hex);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
log_err("testbound: hex packet unparsable, used asis.");
|
||||
ldns_buffer_write(buffer,
|
||||
ldns_buffer_begin(entry->reply_list->reply_from_hex),
|
||||
ldns_buffer_limit(entry->reply_list->reply_from_hex));
|
||||
}
|
||||
c = ldns_buffer_begin(entry->reply_list->reply_from_hex);
|
||||
clen = ldns_buffer_limit(entry->reply_list->reply_from_hex);
|
||||
if(!c) fatal_exit("out of memory");
|
||||
} else {
|
||||
answer_pkt = ldns_pkt_clone(entry->reply_list->reply);
|
||||
c = entry->reply_list->reply_pkt;
|
||||
clen = entry->reply_list->reply_len;
|
||||
}
|
||||
if(answer_pkt) {
|
||||
if(q) adjust_packet(entry, answer_pkt, q);
|
||||
status = ldns_pkt2buffer_wire(buffer, answer_pkt);
|
||||
if(status != LDNS_STATUS_OK)
|
||||
fatal_exit("ldns: cannot pkt2buffer_wire parsed pkt");
|
||||
if(c) {
|
||||
if(q) adjust_packet(entry, &c, &clen, q, qlen);
|
||||
ldns_buffer_write(buffer, c, clen);
|
||||
if(q) free(c);
|
||||
}
|
||||
ldns_pkt_free(answer_pkt);
|
||||
ldns_buffer_flip(buffer);
|
||||
}
|
||||
|
||||
@@ -324,7 +326,7 @@ answer_callback_from_entry(struct replay_runtime* runtime,
|
||||
c.type = comm_udp;
|
||||
if(pend->transport == transport_tcp)
|
||||
c.type = comm_tcp;
|
||||
fill_buffer_with_reply(c.buffer, entry, pend->pkt);
|
||||
fill_buffer_with_reply(c.buffer, entry, pend->pkt, pend->pkt_len);
|
||||
repinfo.c = &c;
|
||||
repinfo.addrlen = pend->addrlen;
|
||||
memcpy(&repinfo.addr, &pend->addr, pend->addrlen);
|
||||
@@ -351,7 +353,8 @@ answer_check_it(struct replay_runtime* runtime)
|
||||
if((runtime->now->addrlen == 0 || sockaddr_cmp(
|
||||
&runtime->now->addr, runtime->now->addrlen,
|
||||
&ans->repinfo.addr, ans->repinfo.addrlen) == 0) &&
|
||||
find_match(runtime->now->match, ans->pkt, tr)) {
|
||||
find_match(runtime->now->match, ans->pkt,
|
||||
ans->pkt_len, tr)) {
|
||||
log_info("testbound matched event entry from line %d",
|
||||
runtime->now->match->lineno);
|
||||
log_info("testbound: do STEP %d %s",
|
||||
@@ -394,9 +397,10 @@ fake_front_query(struct replay_runtime* runtime, struct replay_moment *todo)
|
||||
if(todo->match->match_transport == transport_tcp)
|
||||
repinfo.c->type = comm_tcp;
|
||||
else repinfo.c->type = comm_udp;
|
||||
fill_buffer_with_reply(repinfo.c->buffer, todo->match, NULL);
|
||||
fill_buffer_with_reply(repinfo.c->buffer, todo->match, NULL, 0);
|
||||
log_info("testbound: incoming QUERY");
|
||||
log_pkt("query pkt", todo->match->reply_list->reply);
|
||||
log_pkt("query pkt", todo->match->reply_list->reply_pkt,
|
||||
todo->match->reply_list->reply_len);
|
||||
/* call the callback for incoming queries */
|
||||
if((*runtime->callback_query)(repinfo.c, runtime->cb_arg,
|
||||
NETEVENT_NOERROR, &repinfo)) {
|
||||
@@ -424,13 +428,13 @@ fake_pending_callback(struct replay_runtime* runtime,
|
||||
if(!p) fatal_exit("No pending queries.");
|
||||
cb_arg = p->cb_arg;
|
||||
cb = p->callback;
|
||||
log_assert(todo->qname == NULL); /* or find that one */
|
||||
c.buffer = ldns_buffer_new(runtime->bufsize);
|
||||
c.type = comm_udp;
|
||||
if(p->transport == transport_tcp)
|
||||
c.type = comm_tcp;
|
||||
if(todo->evt_type == repevt_back_reply && todo->match) {
|
||||
fill_buffer_with_reply(c.buffer, todo->match, p->pkt);
|
||||
fill_buffer_with_reply(c.buffer, todo->match, p->pkt,
|
||||
p->pkt_len);
|
||||
}
|
||||
repinfo.c = &c;
|
||||
repinfo.addrlen = p->addrlen;
|
||||
@@ -552,16 +556,17 @@ do_infra_rtt(struct replay_runtime* runtime)
|
||||
{
|
||||
struct replay_moment* now = runtime->now;
|
||||
int rto;
|
||||
ldns_rdf* dp = ldns_dname_new_frm_str(now->variable);
|
||||
size_t dplen = 0;
|
||||
uint8_t* dp = ldns_str2wire_dname(now->variable, &dplen);
|
||||
if(!dp) fatal_exit("cannot parse %s", now->variable);
|
||||
rto = infra_rtt_update(runtime->infra, &now->addr,
|
||||
now->addrlen, ldns_rdf_data(dp), ldns_rdf_size(dp),
|
||||
LDNS_RR_TYPE_A, atoi(now->string), -1, runtime->now_secs);
|
||||
rto = infra_rtt_update(runtime->infra, &now->addr, now->addrlen,
|
||||
dp, dplen, LDNS_RR_TYPE_A, atoi(now->string),
|
||||
-1, runtime->now_secs);
|
||||
log_addr(0, "INFRA_RTT for", &now->addr, now->addrlen);
|
||||
log_info("INFRA_RTT(%s roundtrip %d): rto of %d", now->variable,
|
||||
atoi(now->string), rto);
|
||||
if(rto == 0) fatal_exit("infra_rtt_update failed");
|
||||
ldns_rdf_deep_free(dp);
|
||||
free(dp);
|
||||
}
|
||||
|
||||
/** perform exponential backoff on the timout */
|
||||
@@ -712,7 +717,7 @@ run_scenario(struct replay_runtime* runtime)
|
||||
struct fake_pending* p;
|
||||
log_err("testbound: there are still messages pending.");
|
||||
for(p = runtime->pending_list; p; p=p->next) {
|
||||
log_pkt("pending msg", p->pkt);
|
||||
log_pkt("pending msg", p->pkt, p->pkt_len);
|
||||
log_addr(0, "pending to", &p->addr, p->addrlen);
|
||||
}
|
||||
fatal_exit("testbound: there are still messages pending.");
|
||||
@@ -856,7 +861,6 @@ comm_point_send_reply(struct comm_reply* repinfo)
|
||||
{
|
||||
struct replay_answer* ans = (struct replay_answer*)calloc(1,
|
||||
sizeof(struct replay_answer));
|
||||
ldns_status status;
|
||||
struct replay_runtime* runtime = (struct replay_runtime*)repinfo->c->ev;
|
||||
log_info("testbound: comm_point_send_reply fake");
|
||||
/* dump it into the todo list */
|
||||
@@ -869,13 +873,11 @@ comm_point_send_reply(struct comm_reply* repinfo)
|
||||
runtime->answer_last = ans;
|
||||
|
||||
/* try to parse packet */
|
||||
status = ldns_buffer2pkt_wire(&ans->pkt, ans->repinfo.c->buffer);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
log_err("ldns error parsing packet: %s",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
fatal_exit("Sending unparseable DNS replies to clients!");
|
||||
}
|
||||
log_pkt("reply pkt: ", ans->pkt);
|
||||
ans->pkt = memdup(ldns_buffer_begin(ans->repinfo.c->buffer),
|
||||
ldns_buffer_limit(ans->repinfo.c->buffer));
|
||||
ans->pkt_len = ldns_buffer_limit(ans->repinfo.c->buffer);
|
||||
if(!ans->pkt) fatal_exit("out of memory");
|
||||
log_pkt("reply pkt: ", ans->pkt, ans->pkt_len);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -938,7 +940,6 @@ pending_udp_query(struct outside_network* outnet, ldns_buffer* packet,
|
||||
struct replay_runtime* runtime = (struct replay_runtime*)outnet->base;
|
||||
struct fake_pending* pend = (struct fake_pending*)calloc(1,
|
||||
sizeof(struct fake_pending));
|
||||
ldns_status status;
|
||||
log_assert(pend);
|
||||
pend->buffer = ldns_buffer_new(ldns_buffer_capacity(packet));
|
||||
log_assert(pend->buffer);
|
||||
@@ -955,20 +956,18 @@ pending_udp_query(struct outside_network* outnet, ldns_buffer* packet,
|
||||
pend->zone = NULL;
|
||||
pend->serviced = 0;
|
||||
pend->runtime = runtime;
|
||||
status = ldns_buffer2pkt_wire(&pend->pkt, packet);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
log_err("ldns error parsing udp output packet: %s",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
fatal_exit("Sending unparseable DNS packets to servers!");
|
||||
}
|
||||
log_pkt("pending udp pkt: ", pend->pkt);
|
||||
pend->pkt_len = ldns_buffer_limit(packet);
|
||||
pend->pkt = memdup(ldns_buffer_begin(packet), pend->pkt_len);
|
||||
if(!pend->pkt) fatal_exit("out of memory");
|
||||
log_pkt("pending udp pkt: ", pend->pkt, pend->pkt_len);
|
||||
|
||||
/* see if it matches the current moment */
|
||||
if(runtime->now && runtime->now->evt_type == repevt_back_query &&
|
||||
(runtime->now->addrlen == 0 || sockaddr_cmp(
|
||||
&runtime->now->addr, runtime->now->addrlen,
|
||||
&pend->addr, pend->addrlen) == 0) &&
|
||||
find_match(runtime->now->match, pend->pkt, pend->transport)) {
|
||||
find_match(runtime->now->match, pend->pkt, pend->pkt_len,
|
||||
pend->transport)) {
|
||||
log_info("testbound: matched pending to event. "
|
||||
"advance time between events.");
|
||||
log_info("testbound: do STEP %d %s", runtime->now->time_step,
|
||||
@@ -992,7 +991,6 @@ pending_tcp_query(struct outside_network* outnet, ldns_buffer* packet,
|
||||
struct replay_runtime* runtime = (struct replay_runtime*)outnet->base;
|
||||
struct fake_pending* pend = (struct fake_pending*)calloc(1,
|
||||
sizeof(struct fake_pending));
|
||||
ldns_status status;
|
||||
log_assert(pend);
|
||||
pend->buffer = ldns_buffer_new(ldns_buffer_capacity(packet));
|
||||
log_assert(pend->buffer);
|
||||
@@ -1009,20 +1007,18 @@ pending_tcp_query(struct outside_network* outnet, ldns_buffer* packet,
|
||||
pend->zone = NULL;
|
||||
pend->runtime = runtime;
|
||||
pend->serviced = 0;
|
||||
status = ldns_buffer2pkt_wire(&pend->pkt, packet);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
log_err("ldns error parsing tcp output packet: %s",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
fatal_exit("Sending unparseable DNS packets to servers!");
|
||||
}
|
||||
log_pkt("pending tcp pkt: ", pend->pkt);
|
||||
pend->pkt_len = ldns_buffer_limit(packet);
|
||||
pend->pkt = memdup(ldns_buffer_begin(packet), pend->pkt_len);
|
||||
if(!pend->pkt) fatal_exit("out of memory");
|
||||
log_pkt("pending tcp pkt: ", pend->pkt, pend->pkt_len);
|
||||
|
||||
/* see if it matches the current moment */
|
||||
if(runtime->now && runtime->now->evt_type == repevt_back_query &&
|
||||
(runtime->now->addrlen == 0 || sockaddr_cmp(
|
||||
&runtime->now->addr, runtime->now->addrlen,
|
||||
&pend->addr, pend->addrlen) == 0) &&
|
||||
find_match(runtime->now->match, pend->pkt, pend->transport)) {
|
||||
find_match(runtime->now->match, pend->pkt, pend->pkt_len,
|
||||
pend->transport)) {
|
||||
log_info("testbound: matched pending to event. "
|
||||
"advance time between events.");
|
||||
log_info("testbound: do STEP %d %s", runtime->now->time_step,
|
||||
@@ -1049,7 +1045,6 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
|
||||
struct fake_pending* pend = (struct fake_pending*)calloc(1,
|
||||
sizeof(struct fake_pending));
|
||||
char z[256];
|
||||
ldns_status status;
|
||||
log_assert(pend);
|
||||
log_nametypeclass(VERB_OPS, "pending serviced query",
|
||||
qname, qtype, qclass);
|
||||
@@ -1096,20 +1091,18 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
|
||||
pend->pkt = NULL;
|
||||
pend->runtime = runtime;
|
||||
pend->serviced = 1;
|
||||
status = ldns_buffer2pkt_wire(&pend->pkt, pend->buffer);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
log_err("ldns error parsing serviced output packet: %s",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
fatal_exit("internal error");
|
||||
}
|
||||
/*log_pkt("pending serviced query: ", pend->pkt);*/
|
||||
pend->pkt_len = ldns_buffer_limit(pend->buffer);
|
||||
pend->pkt = memdup(ldns_buffer_begin(pend->buffer), pend->pkt_len);
|
||||
if(!pend->pkt) fatal_exit("out of memory");
|
||||
/*log_pkt("pending serviced query: ", pend->pkt, pend->pkt_len);*/
|
||||
|
||||
/* see if it matches the current moment */
|
||||
if(runtime->now && runtime->now->evt_type == repevt_back_query &&
|
||||
(runtime->now->addrlen == 0 || sockaddr_cmp(
|
||||
&runtime->now->addr, runtime->now->addrlen,
|
||||
&pend->addr, pend->addrlen) == 0) &&
|
||||
find_match(runtime->now->match, pend->pkt, pend->transport)) {
|
||||
find_match(runtime->now->match, pend->pkt, pend->pkt_len,
|
||||
pend->transport)) {
|
||||
log_info("testbound: matched pending to event. "
|
||||
"advance time between events.");
|
||||
log_info("testbound: do STEP %d %s", runtime->now->time_step,
|
||||
@@ -1138,7 +1131,7 @@ void outnet_serviced_query_stop(struct serviced_query* sq, void* cb_arg)
|
||||
prev->next = p->next;
|
||||
else runtime->pending_list = p->next;
|
||||
ldns_buffer_free(p->buffer);
|
||||
ldns_pkt_free(p->pkt);
|
||||
free(p->pkt);
|
||||
free(p->zone);
|
||||
free(p);
|
||||
return;
|
||||
|
||||
@@ -1,857 +0,0 @@
|
||||
/*
|
||||
* testcode/harvest.c - debug program to get relevant data to a set of queries.
|
||||
*
|
||||
* Copyright (c) 2008, 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 REGENTS 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 program downloads relevant DNS data to a set of queries.
|
||||
* This means that the queries are asked to root, TLD, SLD servers and
|
||||
* the results stored per zone.
|
||||
* The following data is pertinent:
|
||||
*
|
||||
* At each label:
|
||||
* SOA
|
||||
* NS
|
||||
* DNSKEY
|
||||
* DS
|
||||
* For the whole query:
|
||||
* the result.
|
||||
* For NS-records:
|
||||
* their label data
|
||||
* and the A and AAAA records for it.
|
||||
* (as if the name, with A and AAAA query type is in the list,
|
||||
* referred to as recursion depth+1)
|
||||
* Any NSEC, NSEC3, SOA records or additional data found in answers.
|
||||
*
|
||||
* All of this is data that would be encountered during an iterative lookup
|
||||
* for the queries in the list. It is saved to enable a replay of iterative
|
||||
* lookups for performance testing.
|
||||
*
|
||||
* A number of assumptions are made.
|
||||
* 1) configuration is correct.
|
||||
* The parent has the same NS records as the child.
|
||||
* All nameservers carry the same data.
|
||||
* 2) EDNS/nonEDNS responses and other behaviour is ignored.
|
||||
* Only the data is saved.
|
||||
* This creates a snapshot that represents the data as this resolver saw it.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
#include <ldns/ldns.h>
|
||||
#include <signal.h>
|
||||
#include "libunbound/unbound.h"
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef UNBOUND_ALLOC_LITE
|
||||
#undef malloc
|
||||
#undef calloc
|
||||
#undef realloc
|
||||
#undef free
|
||||
#undef strdup
|
||||
#define unbound_lite_wrapstr(s) s
|
||||
#endif
|
||||
struct todo_item;
|
||||
struct labdata;
|
||||
|
||||
/** this represents the data that has been collected
|
||||
* as well as a todo list and some settings */
|
||||
struct harvest_data {
|
||||
/** the unbound context */
|
||||
struct ub_ctx* ctx;
|
||||
|
||||
/** a tree per label; thus this first one is one root entry,
|
||||
* that has a tree of TLD labels. Those have trees of SLD labels. */
|
||||
struct labdata* root;
|
||||
/** the original query list */
|
||||
struct todo_item* orig_list;
|
||||
/** the query list todo */
|
||||
struct todo_item* todo_list;
|
||||
/** last item in todo list */
|
||||
struct todo_item* todo_last;
|
||||
/** number of todo items */
|
||||
int numtodo;
|
||||
|
||||
/** where to store the results */
|
||||
char* resultdir;
|
||||
/** maximum recursion depth */
|
||||
int maxdepth;
|
||||
/** current recursion depth */
|
||||
int curdepth;
|
||||
|
||||
/** max depth of labels */
|
||||
int maxlabels;
|
||||
/** number of RRs stored */
|
||||
int num_rrs;
|
||||
/** number of zones written */
|
||||
int num_zones;
|
||||
};
|
||||
|
||||
/**
|
||||
* Todo item
|
||||
*/
|
||||
struct todo_item {
|
||||
/** the next item */
|
||||
struct todo_item* next;
|
||||
|
||||
/** query as rdf */
|
||||
ldns_rdf* qname;
|
||||
/** the query type */
|
||||
int qtype;
|
||||
/** query class */
|
||||
int qclass;
|
||||
|
||||
/** recursion depth of todo item (orig list is 0) */
|
||||
int depth;
|
||||
/** the label associated with the query */
|
||||
struct labdata* lab;
|
||||
};
|
||||
|
||||
/**
|
||||
* Every label has a sest of sublabels, that have sets of sublabels ...
|
||||
* Per label is stored also a set of data items, and todo information
|
||||
*/
|
||||
struct labdata {
|
||||
/** node in ldns rbtree */
|
||||
ldns_rbnode_t node;
|
||||
/** the name of this label */
|
||||
ldns_rdf* label;
|
||||
/** full name of point in domain tree */
|
||||
ldns_rdf* name;
|
||||
|
||||
/** parent in label tree (NULL for root) */
|
||||
struct labdata* parent;
|
||||
/** tree of sublabels (if any) */
|
||||
ldns_rbtree_t* sublabels;
|
||||
|
||||
/** list of RRs for this label */
|
||||
ldns_rr_list* rrlist;
|
||||
/** have queries for this label been queued */
|
||||
int done;
|
||||
};
|
||||
|
||||
/** usage information for harvest */
|
||||
static void usage(char* nm)
|
||||
{
|
||||
printf("usage: %s [options]\n", nm);
|
||||
printf("-f fnm query list to read from file\n");
|
||||
printf(" every line has format: qname qclass qtype\n");
|
||||
printf("-v verbose (-v -v even more)\n");
|
||||
printf("-C cfg config file with resolver options\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/** verbosity for harvest */
|
||||
static int hverb = 0;
|
||||
|
||||
/** exit with error */
|
||||
static void error_exit(const char* str)
|
||||
{
|
||||
printf("error: %s\n", str);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/** read a query file */
|
||||
static void
|
||||
qlist_read_file(struct harvest_data* data, char* fname)
|
||||
{
|
||||
char buf[1024];
|
||||
char nm[1024], cl[1024], tp[1024];
|
||||
int r;
|
||||
int num = 0;
|
||||
FILE* in = fopen(fname, "r");
|
||||
struct todo_item* t;
|
||||
if(!in) {
|
||||
perror(fname);
|
||||
error_exit("could not open file");
|
||||
}
|
||||
while(fgets(buf, (int)sizeof(buf), in)) {
|
||||
if(buf[0] == 0) continue;
|
||||
if(buf[0] == '\n') continue;
|
||||
/* allow some comments */
|
||||
if(buf[0] == ';') continue;
|
||||
if(buf[0] == '#') continue;
|
||||
nm[0] = 0; cl[0] = 0; tp[0] = 0;
|
||||
r = sscanf(buf, " %1023s %1023s %1023s", nm, cl, tp);
|
||||
if(r == 0) continue;
|
||||
t = (struct todo_item*)calloc(1, sizeof(*t));
|
||||
if(!t) error_exit("out of memory");
|
||||
t->qname = ldns_dname_new_frm_str(nm);
|
||||
if(!t->qname) {
|
||||
printf("parse error: %s\n", nm);
|
||||
error_exit("bad qname");
|
||||
}
|
||||
t->depth = 0;
|
||||
t->qtype = LDNS_RR_TYPE_A;
|
||||
t->qclass = LDNS_RR_CLASS_IN;
|
||||
if(r >= 2) {
|
||||
if(strcmp(cl, "IN") == 0 || strcmp(cl, "CH") == 0)
|
||||
t->qclass = ldns_get_rr_class_by_name(cl);
|
||||
else t->qtype = ldns_get_rr_type_by_name(cl);
|
||||
}
|
||||
if(r >= 3) {
|
||||
if(strcmp(tp, "IN") == 0 || strcmp(tp, "CH") == 0)
|
||||
t->qclass = ldns_get_rr_class_by_name(tp);
|
||||
else t->qtype = ldns_get_rr_type_by_name(tp);
|
||||
}
|
||||
num++;
|
||||
|
||||
t->next = data->orig_list;
|
||||
data->orig_list = t;
|
||||
}
|
||||
printf("read %s: %d queries\n", fname, num);
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
/** compare two labels */
|
||||
static int
|
||||
lab_cmp(const void *x, const void *y)
|
||||
{
|
||||
return ldns_dname_compare((const ldns_rdf*)x, (const ldns_rdf*)y);
|
||||
}
|
||||
|
||||
/** create label entry */
|
||||
static struct labdata*
|
||||
lab_create(const char* name)
|
||||
{
|
||||
struct labdata* lab = (struct labdata*)calloc(1, sizeof(*lab));
|
||||
if(!lab) error_exit("out of memory");
|
||||
lab->label = ldns_dname_new_frm_str(name);
|
||||
if(!lab->label) error_exit("out of memory");
|
||||
lab->name = ldns_dname_new_frm_str(name);
|
||||
if(!lab->name) error_exit("out of memory");
|
||||
lab->node.key = lab->label;
|
||||
lab->node.data = lab;
|
||||
lab->sublabels = ldns_rbtree_create(lab_cmp);
|
||||
if(!lab->sublabels) error_exit("out of memory");
|
||||
lab->rrlist = ldns_rr_list_new();
|
||||
if(!lab->rrlist) error_exit("out of memory");
|
||||
|
||||
return lab;
|
||||
}
|
||||
|
||||
/** for this name, lookup the label, create if does not exist */
|
||||
static struct labdata*
|
||||
find_create_lab(struct harvest_data* data, ldns_rdf* name)
|
||||
{
|
||||
struct labdata* lab = data->root;
|
||||
struct labdata* nextlab;
|
||||
ldns_rdf* next;
|
||||
uint8_t numlab = ldns_dname_label_count(name);
|
||||
if((int)numlab > data->maxlabels)
|
||||
data->maxlabels = (int)numlab;
|
||||
while(numlab--) {
|
||||
next = ldns_dname_label(name, numlab);
|
||||
if(!next) error_exit("ldns_dname_label");
|
||||
|
||||
nextlab = (struct labdata*)
|
||||
ldns_rbtree_search(lab->sublabels, next);
|
||||
if(!nextlab) {
|
||||
/* create it */
|
||||
nextlab = (struct labdata*)calloc(1, sizeof(*lab));
|
||||
if(!nextlab) error_exit("out of memory");
|
||||
nextlab->label = ldns_rdf_clone(next);
|
||||
if(!nextlab->label) error_exit("out of memory");
|
||||
nextlab->node.key = nextlab->label;
|
||||
nextlab->node.data = nextlab;
|
||||
nextlab->sublabels = ldns_rbtree_create(lab_cmp);
|
||||
if(!nextlab->sublabels) error_exit("out of memory");
|
||||
nextlab->parent = lab;
|
||||
nextlab->name = ldns_rdf_clone(next);
|
||||
if(!nextlab->name) error_exit("out of memory");
|
||||
if(ldns_dname_cat(nextlab->name, lab->name)
|
||||
!= LDNS_STATUS_OK) error_exit("outofmem");
|
||||
nextlab->rrlist = ldns_rr_list_new();
|
||||
if(!nextlab->rrlist) error_exit("out of memory");
|
||||
(void)ldns_rbtree_insert(lab->sublabels,
|
||||
&nextlab->node);
|
||||
if(hverb) {
|
||||
printf("new label: ");
|
||||
ldns_rdf_print(stdout, nextlab->name);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
lab = nextlab;
|
||||
ldns_rdf_deep_free(next);
|
||||
}
|
||||
return lab;
|
||||
}
|
||||
|
||||
/** for given query, create todo items, and labels if needed */
|
||||
static void
|
||||
new_todo_item(struct harvest_data* data, ldns_rdf* qname, int qtype,
|
||||
int qclass, int depth)
|
||||
{
|
||||
struct labdata* lab = find_create_lab(data, qname);
|
||||
struct todo_item* it;
|
||||
if(!lab) error_exit("out of memory creating new label");
|
||||
it = (struct todo_item*)calloc(1, sizeof(*it));
|
||||
it->qname = ldns_rdf_clone(qname);
|
||||
it->qtype = qtype;
|
||||
it->qclass = qclass;
|
||||
it->depth = depth;
|
||||
it->lab = lab;
|
||||
it->next = NULL;
|
||||
if(data->todo_last)
|
||||
data->todo_last->next = it;
|
||||
else data->todo_list = it;
|
||||
data->todo_last = it;
|
||||
data->numtodo ++;
|
||||
if(hverb >= 2) {
|
||||
printf("new todo: ");
|
||||
ldns_rdf_print(stdout, it->qname);
|
||||
if(ldns_rr_descript((uint16_t)it->qtype) &&
|
||||
ldns_rr_descript((uint16_t)it->qtype)->_name)
|
||||
printf(" %s", ldns_rr_descript((uint16_t)
|
||||
it->qtype)->_name);
|
||||
if(ldns_lookup_by_id(ldns_rr_classes, it->qclass) &&
|
||||
ldns_lookup_by_id(ldns_rr_classes, it->qclass)->name)
|
||||
printf(" %s", ldns_lookup_by_id(ldns_rr_classes,
|
||||
it->qclass)->name);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/** add infra todo items for this query */
|
||||
static void
|
||||
new_todo_infra(struct harvest_data* data, struct labdata* startlab, int depth)
|
||||
{
|
||||
struct labdata* lab;
|
||||
for(lab = startlab; lab; lab = lab->parent) {
|
||||
if(lab->done)
|
||||
return;
|
||||
new_todo_item(data, lab->name, LDNS_RR_TYPE_NS,
|
||||
LDNS_RR_CLASS_IN, depth);
|
||||
new_todo_item(data, lab->name, LDNS_RR_TYPE_SOA,
|
||||
LDNS_RR_CLASS_IN, depth);
|
||||
new_todo_item(data, lab->name, LDNS_RR_TYPE_DNSKEY,
|
||||
LDNS_RR_CLASS_IN, depth);
|
||||
new_todo_item(data, lab->name, LDNS_RR_TYPE_DS,
|
||||
LDNS_RR_CLASS_IN, depth);
|
||||
new_todo_item(data, lab->name, LDNS_RR_TYPE_A,
|
||||
LDNS_RR_CLASS_IN, depth);
|
||||
new_todo_item(data, lab->name, LDNS_RR_TYPE_AAAA,
|
||||
LDNS_RR_CLASS_IN, depth);
|
||||
lab->done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/** make todo items for initial data */
|
||||
static void
|
||||
make_todo(struct harvest_data* data)
|
||||
{
|
||||
struct todo_item* it;
|
||||
for(it=data->orig_list; it; it = it->next) {
|
||||
/* create todo item for this query itself */
|
||||
new_todo_item(data, it->qname, it->qtype, it->qclass, 0);
|
||||
/* create todo items for infra queries to support it */
|
||||
new_todo_infra(data, data->todo_list->lab,
|
||||
data->todo_list->depth);
|
||||
}
|
||||
}
|
||||
|
||||
/** store RR and make new work items for it if needed */
|
||||
static void
|
||||
process_rr(struct harvest_data* data, ldns_rr* rr, int depth)
|
||||
{
|
||||
/* must free or store rr */
|
||||
struct labdata* lab = find_create_lab(data, ldns_rr_owner(rr));
|
||||
if(!lab) error_exit("cannot find/create label");
|
||||
/* generate extra queries */
|
||||
if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_NS) {
|
||||
new_todo_infra(data, find_create_lab(data,
|
||||
ldns_rr_ns_nsdname(rr)), depth+1);
|
||||
} else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_MX) {
|
||||
new_todo_infra(data, find_create_lab(data,
|
||||
ldns_rr_mx_exchange(rr)), depth+1);
|
||||
} else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
|
||||
new_todo_infra(data, find_create_lab(data,
|
||||
ldns_rr_rdf(rr, 0)), depth+1);
|
||||
} else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_CNAME) {
|
||||
int t = ldns_rr_get_type(rr);
|
||||
if(t!=LDNS_RR_TYPE_A && t!=LDNS_RR_TYPE_AAAA &&
|
||||
t!=LDNS_RR_TYPE_SOA && t!=LDNS_RR_TYPE_NS &&
|
||||
t!=LDNS_RR_TYPE_DS && t!=LDNS_RR_TYPE_DNSKEY)
|
||||
new_todo_item(data, ldns_rr_rdf(rr, 0), t,
|
||||
ldns_rr_get_class(rr), depth+1);
|
||||
/* can get caught in CNAME loop, but depth will
|
||||
* catch that; unbound cache helps too(servfails on
|
||||
* a cname loop) */
|
||||
new_todo_infra(data, find_create_lab(data,
|
||||
ldns_rr_rdf(rr, 0)), depth+1);
|
||||
}
|
||||
/* store it */
|
||||
if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC) {
|
||||
/* find correct zone to store NSEC in (for delegation zones) */
|
||||
if(ldns_dname_compare(ldns_rr_rdf(rr, 0), ldns_rr_owner(rr))
|
||||
== 0) {
|
||||
/* store at the single name = apex */
|
||||
} else if(!ldns_dname_is_subdomain(ldns_rr_rdf(rr, 0),
|
||||
ldns_rr_owner(rr)) && lab->parent) {
|
||||
/* if owner NSEC subdomain-of-owner then
|
||||
* store at owner (owner is apex or empty nonterminal).
|
||||
* Otherwise at owner parent. */
|
||||
lab = lab->parent;
|
||||
}
|
||||
} else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_DS) {
|
||||
/* store DSes in parent zone */
|
||||
if(lab->parent)
|
||||
lab = lab->parent;
|
||||
} else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3) {
|
||||
/* store NSEC3s one label up at zone apex */
|
||||
if(lab->parent)
|
||||
lab = lab->parent;
|
||||
}
|
||||
/* we assume NS set is equal across parent-child border. */
|
||||
|
||||
if(!ldns_rr_list_contains_rr(lab->rrlist, rr)) {
|
||||
if(hverb >= 2) {
|
||||
printf("store RR ");
|
||||
ldns_rr_print(stdout, rr);
|
||||
printf("\n");
|
||||
}
|
||||
if(!ldns_rr_list_push_rr(lab->rrlist, rr))
|
||||
error_exit("outofmem ldns_rr_list_push_rr");
|
||||
data->num_rrs++;
|
||||
} else {
|
||||
if(hverb >= 2) {
|
||||
printf("duplicate RR ");
|
||||
ldns_rr_print(stdout, rr);
|
||||
printf("\n");
|
||||
}
|
||||
ldns_rr_free(rr);
|
||||
}
|
||||
}
|
||||
|
||||
/** store RRs and make new work items if needed */
|
||||
static void
|
||||
process_pkt(struct harvest_data* data, ldns_pkt* pkt, int depth)
|
||||
{
|
||||
size_t i;
|
||||
ldns_rr_list* list;
|
||||
list = ldns_pkt_get_section_clone(pkt, LDNS_SECTION_ANY_NOQUESTION);
|
||||
if(!list) error_exit("outofmemory");
|
||||
for(i=0; i<ldns_rr_list_rr_count(list); i++) {
|
||||
process_rr(data, ldns_rr_list_rr(list, i), depth);
|
||||
}
|
||||
ldns_rr_list_free(list);
|
||||
}
|
||||
|
||||
/** process a todo item */
|
||||
static void
|
||||
process(struct harvest_data* data, struct todo_item* it)
|
||||
{
|
||||
int r;
|
||||
char* nm;
|
||||
struct ub_result* result = NULL;
|
||||
ldns_pkt* pkt = NULL;
|
||||
ldns_status s;
|
||||
if(hverb) {
|
||||
printf("process: ");
|
||||
ldns_rdf_print(stdout, it->qname);
|
||||
if(ldns_rr_descript((uint16_t)it->qtype) &&
|
||||
ldns_rr_descript((uint16_t)it->qtype)->_name)
|
||||
printf(" %s", ldns_rr_descript((uint16_t)
|
||||
it->qtype)->_name);
|
||||
if(ldns_lookup_by_id(ldns_rr_classes, it->qclass) &&
|
||||
ldns_lookup_by_id(ldns_rr_classes, it->qclass)->name)
|
||||
printf(" %s", ldns_lookup_by_id(ldns_rr_classes,
|
||||
it->qclass)->name);
|
||||
printf("\n");
|
||||
}
|
||||
/* do lookup */
|
||||
nm = ldns_rdf2str(it->qname);
|
||||
if(!nm) error_exit("ldns_rdf2str");
|
||||
r = ub_resolve(data->ctx, nm, it->qtype, it->qclass, &result);
|
||||
if(r != 0) {
|
||||
printf("ub_resolve(%s, %d, %d): %s\n", nm, it->qtype,
|
||||
it->qclass, ub_strerror(r));
|
||||
free(nm);
|
||||
return;
|
||||
}
|
||||
if(result->rcode == LDNS_RCODE_SERVFAIL) {
|
||||
free(nm);
|
||||
return;
|
||||
}
|
||||
/* even if result is a negative, try to store resulting SOA/NSEC */
|
||||
|
||||
/* create ldns pkt */
|
||||
s = ldns_wire2pkt(&pkt, result->answer_packet,
|
||||
(size_t)result->answer_len);
|
||||
if(s != LDNS_STATUS_OK) {
|
||||
printf("ldns_wire2pkt failed! %s %d %d %s %d\n", nm,
|
||||
it->qtype, it->qclass, ldns_get_errorstr_by_id(s),
|
||||
result->answer_len);
|
||||
free(nm);
|
||||
return;
|
||||
}
|
||||
if(hverb >= 2) {
|
||||
printf("answer: ");
|
||||
ldns_pkt_print(stdout, pkt);
|
||||
printf("\n");
|
||||
}
|
||||
/* process results */
|
||||
process_pkt(data, pkt, it->depth);
|
||||
|
||||
ldns_pkt_free(pkt);
|
||||
free(nm);
|
||||
ub_resolve_free(result);
|
||||
}
|
||||
|
||||
/** perform main harvesting */
|
||||
static void
|
||||
harvest_main(struct harvest_data* data)
|
||||
{
|
||||
struct todo_item* it;
|
||||
int numdone = 0;
|
||||
/* register todo queries for all original queries */
|
||||
make_todo(data);
|
||||
printf("depth 0: done %d todo %d\n", 0, data->numtodo);
|
||||
/* pick up a todo item and process it */
|
||||
while(data->todo_list) {
|
||||
numdone++;
|
||||
it = data->todo_list;
|
||||
data->todo_list = it->next;
|
||||
if(!data->todo_list) data->todo_last = NULL;
|
||||
if(numdone%1000==0 || it->depth > data->curdepth) {
|
||||
data->curdepth = it->depth;
|
||||
printf("depth %d: done %d todo %d, %d rrs\n",
|
||||
it->depth, numdone, data->numtodo,
|
||||
data->num_rrs);
|
||||
}
|
||||
if(it->depth >= data->maxdepth) {
|
||||
printf("obtained %d rrs to a max of %d labels.\n",
|
||||
data->num_rrs, data->maxlabels);
|
||||
return;
|
||||
}
|
||||
data->numtodo--;
|
||||
process(data, it);
|
||||
usleep(1000000/100);
|
||||
}
|
||||
}
|
||||
|
||||
/** create directory if it does not exist */
|
||||
static void
|
||||
hv_mkdir(char* dir)
|
||||
{
|
||||
#ifdef MKDIR_HAS_ONE_ARG
|
||||
if(mkdir(dir) == -1) {
|
||||
#else
|
||||
if(mkdir(dir, 0755) == -1) {
|
||||
#endif
|
||||
if(errno == EEXIST)
|
||||
return;
|
||||
perror(dir);
|
||||
error_exit("mkdir failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** see if rrlist contains a SOA record */
|
||||
static ldns_rr*
|
||||
has_SOA(ldns_rr_list* list)
|
||||
{
|
||||
size_t i;
|
||||
for(i=0; i<ldns_rr_list_rr_count(list); i++) {
|
||||
if(ldns_rr_get_type(ldns_rr_list_rr(list, i))
|
||||
== LDNS_RR_TYPE_SOA)
|
||||
return ldns_rr_list_rr(list, i);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** write moredata for a zone*/
|
||||
static void
|
||||
write_moredata(struct harvest_data* data, struct labdata* zone,
|
||||
FILE *f, struct labdata* thislab, ldns_rr* nslist)
|
||||
{
|
||||
struct labdata* lab;
|
||||
size_t i;
|
||||
ldns_rr* ns;
|
||||
LDNS_RBTREE_FOR(lab, struct labdata*, thislab->sublabels) {
|
||||
if(has_SOA(lab->rrlist)) {
|
||||
/* copy only NS glue */
|
||||
for(i=0; i<ldns_rr_list_rr_count(lab->rrlist); i++) {
|
||||
ns = ldns_rr_list_rr(lab->rrlist, i);
|
||||
if(ldns_rr_get_type(ns) == LDNS_RR_TYPE_NS) {
|
||||
ldns_rr_print(f, ns);
|
||||
if(ldns_dname_is_subdomain(
|
||||
ldns_rr_ns_nsdname(ns),
|
||||
lab->name)) {
|
||||
ldns_rr_push_rdf(nslist,
|
||||
ldns_rdf_clone(
|
||||
ldns_rr_ns_nsdname(ns)));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* copy all, recurse */
|
||||
for(i=0; i<ldns_rr_list_rr_count(lab->rrlist); i++) {
|
||||
ldns_rr_print(f,
|
||||
ldns_rr_list_rr(lab->rrlist, i));
|
||||
}
|
||||
write_moredata(data, zone, f, lab, nslist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** find and write glue into zone file */
|
||||
static void
|
||||
write_glue(struct harvest_data* data, struct labdata* thislab, FILE* f,
|
||||
ldns_rdf* name, int dep)
|
||||
{
|
||||
size_t i;
|
||||
struct labdata* lab;
|
||||
ldns_rr* rr;
|
||||
if(ldns_dname_compare(name, thislab->name) == 0) {
|
||||
/* this is it! Did we go outside the zone? */
|
||||
if(dep == 0)
|
||||
return;
|
||||
/* find A and AAAA */
|
||||
for(i=0; i<ldns_rr_list_rr_count(thislab->rrlist); i++) {
|
||||
rr = ldns_rr_list_rr(thislab->rrlist, i);
|
||||
if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_A ||
|
||||
ldns_rr_get_type(rr) == LDNS_RR_TYPE_AAAA) {
|
||||
ldns_rr_print(f, rr);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* recurse deeper */
|
||||
LDNS_RBTREE_FOR(lab, struct labdata*, thislab->sublabels) {
|
||||
if(has_SOA(lab->rrlist)) {
|
||||
write_glue(data, lab, f, name, dep+1);
|
||||
} else {
|
||||
write_glue(data, lab, f, name, dep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** write zonefile for zone at this apex */
|
||||
static void
|
||||
write_zonefile(struct harvest_data* data, int dep, FILE* zlist,
|
||||
struct labdata* apex, ldns_rr* soa)
|
||||
{
|
||||
FILE *f;
|
||||
char fname[1024];
|
||||
char* zname = ldns_rdf2str(apex->name);
|
||||
time_t tm = time(NULL);
|
||||
size_t i;
|
||||
ldns_rr* nslist;
|
||||
if(!zname) error_exit("out of mem ldns_rdf2str");
|
||||
if(strcmp(zname, ".") == 0)
|
||||
snprintf(fname, sizeof(fname), "l%d/root.zone", dep);
|
||||
else snprintf(fname, sizeof(fname), "l%d/%szone", dep, zname);
|
||||
|
||||
fprintf(zlist, "zone: name: \"%s\" %s%szonefile: \"%s\"\n",
|
||||
zname,
|
||||
strlen(zname)/8<1?"\t":"",
|
||||
strlen(zname)/8<2?"\t":"",
|
||||
fname);
|
||||
|
||||
if(hverb) printf("writing %s\n", fname);
|
||||
f = fopen(fname, "w");
|
||||
if(!f) {
|
||||
perror(fname);
|
||||
error_exit("cannot open zone file");
|
||||
}
|
||||
fprintf(f, "; %s - generated by harvest program.\n", fname);
|
||||
fprintf(f, "; zone name %s - this is a partial snapshot of "
|
||||
"data relevant to the query list.\n", zname);
|
||||
fprintf(f, "; created %u - date %s\n", (unsigned)tm, ctime(&tm));
|
||||
ldns_rr_print(f, soa);
|
||||
fprintf(f, "\n");
|
||||
for(i=0; i<ldns_rr_list_rr_count(apex->rrlist); i++) {
|
||||
if(ldns_rr_get_type(ldns_rr_list_rr(apex->rrlist, i))
|
||||
== LDNS_RR_TYPE_SOA) continue;
|
||||
ldns_rr_print(f, ldns_rr_list_rr(apex->rrlist, i));
|
||||
}
|
||||
/* search for more data - subdomains inside the zone, NS glue */
|
||||
nslist = ldns_rr_new();
|
||||
if(!nslist) error_exit("out of memory");
|
||||
fprintf(f, "; end of apex, more data follows\n");
|
||||
write_moredata(data, apex, f, apex, nslist);
|
||||
|
||||
/* add NS from apex that need glue too */
|
||||
for(i=0; i<ldns_rr_list_rr_count(apex->rrlist); i++) {
|
||||
if(ldns_rr_get_type(ldns_rr_list_rr(apex->rrlist, i)) !=
|
||||
LDNS_RR_TYPE_NS)
|
||||
continue;
|
||||
/* these are only added again if in a subzone */
|
||||
if(ldns_dname_is_subdomain(ldns_rr_ns_nsdname(
|
||||
ldns_rr_list_rr(apex->rrlist, i)), apex->name)) {
|
||||
ldns_rr_push_rdf(nslist, ldns_rdf_clone(
|
||||
ldns_rr_ns_nsdname(ldns_rr_list_rr(
|
||||
apex->rrlist, i))));
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(f, "; glue data follows\n");
|
||||
/* lookup and add glue (if not already in zone) */
|
||||
for(i=0; i<ldns_rr_rd_count(nslist); i++) {
|
||||
write_glue(data, apex, f, ldns_rr_rdf(nslist, i), 0);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
ldns_rr_free(nslist);
|
||||
free(zname);
|
||||
}
|
||||
|
||||
/** create zones at depth d in label tree */
|
||||
static void
|
||||
create_zones(struct harvest_data* data, int dep, FILE* zlist,
|
||||
struct labdata* labnow, int depnow)
|
||||
{
|
||||
struct labdata* s;
|
||||
ldns_rr* soa;
|
||||
if(depnow == dep) {
|
||||
/* see if this is a zone start - a SOA */
|
||||
if((soa=has_SOA(labnow->rrlist))) {
|
||||
write_zonefile(data, dep, zlist, labnow, soa);
|
||||
data->num_zones++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* recurse */
|
||||
LDNS_RBTREE_FOR(s, struct labdata*, labnow->sublabels) {
|
||||
create_zones(data, dep, zlist, s, depnow+1);
|
||||
}
|
||||
}
|
||||
|
||||
/** sort rrlists */
|
||||
static void
|
||||
harvest_sort(struct labdata* lab)
|
||||
{
|
||||
struct labdata* s;
|
||||
/* prettier output if sorted here */
|
||||
ldns_rr_list_sort(lab->rrlist);
|
||||
/* and recurse */
|
||||
LDNS_RBTREE_FOR(s, struct labdata*, lab->sublabels) {
|
||||
harvest_sort(s);
|
||||
}
|
||||
}
|
||||
|
||||
/** output harvested results */
|
||||
static void
|
||||
harvest_output(struct harvest_data* data)
|
||||
{
|
||||
int d;
|
||||
char buf[20];
|
||||
FILE* zlist;
|
||||
int lastzones;
|
||||
hv_mkdir(data->resultdir);
|
||||
if(chdir(data->resultdir) == -1) {
|
||||
perror(data->resultdir);
|
||||
error_exit("cannot chdir");
|
||||
}
|
||||
harvest_sort(data->root);
|
||||
/* create zones */
|
||||
for(d = 0; d<data->maxlabels; d++) {
|
||||
lastzones = data->num_zones;
|
||||
printf("creating zones %d\n", d);
|
||||
snprintf(buf, sizeof(buf), "l%d", d);
|
||||
hv_mkdir(buf);
|
||||
snprintf(buf, sizeof(buf), "l%d.zones", d);
|
||||
zlist = fopen(buf, "w");
|
||||
if(!zlist) {
|
||||
perror(buf);
|
||||
error_exit("cannot write zonelist file");
|
||||
}
|
||||
fprintf(zlist, "# partial zones at depth %d\n", d);
|
||||
create_zones(data, d, zlist, data->root, 0);
|
||||
fclose(zlist);
|
||||
printf("creating zones %d - %d zones written\n", d,
|
||||
data->num_zones - lastzones);
|
||||
}
|
||||
}
|
||||
|
||||
/** getopt global, in case header files fail to declare it. */
|
||||
extern int optind;
|
||||
/** getopt global, in case header files fail to declare it. */
|
||||
extern char* optarg;
|
||||
|
||||
/** main program for harvest */
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
struct harvest_data data;
|
||||
char* nm = argv[0];
|
||||
int c;
|
||||
|
||||
/* defaults */
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.ctx = ub_ctx_create();
|
||||
data.resultdir = strdup("harvested_zones");
|
||||
if(!data.resultdir) error_exit("out of memory");
|
||||
data.maxdepth = 2;
|
||||
|
||||
/* parse the options */
|
||||
while( (c=getopt(argc, argv, "hf:vC:")) != -1) {
|
||||
switch(c) {
|
||||
case 'C':
|
||||
if(ub_ctx_config(data.ctx, optarg) != 0)
|
||||
error_exit("config read failed");
|
||||
break;
|
||||
case 'f':
|
||||
qlist_read_file(&data, optarg);
|
||||
break;
|
||||
case 'v':
|
||||
hverb++;
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
default:
|
||||
usage(nm);
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if(argc != 0)
|
||||
usage(nm);
|
||||
if(data.orig_list == NULL)
|
||||
error_exit("No queries to make, use -f (help with -h).");
|
||||
data.root = lab_create(".");
|
||||
if(!data.root) error_exit("out of memory");
|
||||
|
||||
/* harvest the data */
|
||||
harvest_main(&data);
|
||||
harvest_output(&data);
|
||||
|
||||
/* no cleanup except the context (to close open sockets) */
|
||||
ub_ctx_delete(data.ctx);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,898 +0,0 @@
|
||||
/*
|
||||
* ldns-testpkts. Data file parse for test packets, and query matching.
|
||||
*
|
||||
* Data storage for specially crafted replies for testing purposes.
|
||||
*
|
||||
* (c) NLnet Labs, 2005, 2006, 2007, 2008
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* This is a debugging aid. It is not efficient, especially
|
||||
* with a long config file, but it can give any reply to any query.
|
||||
* This can help the developer pre-script replies for queries.
|
||||
*
|
||||
* You can specify a packet RR by RR with header flags to return.
|
||||
*
|
||||
* Missing features:
|
||||
* - matching content different from reply content.
|
||||
* - find way to adjust mangled packets?
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
struct sockaddr_storage;
|
||||
#include <ldns/ldns.h>
|
||||
#include <errno.h>
|
||||
#include "ldns-testpkts.h"
|
||||
|
||||
/** max line length */
|
||||
#define MAX_LINE 10240
|
||||
/** string to show in warnings and errors */
|
||||
static const char* prog_name = "ldns-testpkts";
|
||||
|
||||
#ifndef UTIL_LOG_H
|
||||
/** verbosity definition for compat */
|
||||
enum verbosity_value { NO_VERBOSE=0 };
|
||||
#endif
|
||||
/** logging routine, provided by caller */
|
||||
void verbose(enum verbosity_value lvl, const char* msg, ...) ATTR_FORMAT(printf, 2, 3);
|
||||
|
||||
/** print error and exit */
|
||||
static void error(const char* msg, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
fprintf(stderr, "%s error: ", prog_name);
|
||||
vfprintf(stderr, msg, args);
|
||||
fprintf(stderr, "\n");
|
||||
fflush(stderr);
|
||||
va_end(args);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/** return if string is empty or comment */
|
||||
static bool isendline(char c)
|
||||
{
|
||||
if(c == ';' || c == '#'
|
||||
|| c == '\n' || c == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/** true if the string starts with the keyword given. Moves the str ahead.
|
||||
* @param str: before keyword, afterwards after keyword and spaces.
|
||||
* @param keyword: the keyword to match
|
||||
* @return: true if keyword present. False otherwise, and str unchanged.
|
||||
*/
|
||||
static bool str_keyword(char** str, const char* keyword)
|
||||
{
|
||||
size_t len = strlen(keyword);
|
||||
assert(str && keyword);
|
||||
if(strncmp(*str, keyword, len) != 0)
|
||||
return false;
|
||||
*str += len;
|
||||
while(isspace((int)**str))
|
||||
(*str)++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Add reply packet to entry */
|
||||
static struct reply_packet*
|
||||
entry_add_reply(struct entry* entry)
|
||||
{
|
||||
struct reply_packet* pkt = (struct reply_packet*)malloc(
|
||||
sizeof(struct reply_packet));
|
||||
struct reply_packet ** p = &entry->reply_list;
|
||||
pkt->next = NULL;
|
||||
pkt->packet_sleep = 0;
|
||||
pkt->reply = ldns_pkt_new();
|
||||
pkt->reply_from_hex = NULL;
|
||||
/* link at end */
|
||||
while(*p)
|
||||
p = &((*p)->next);
|
||||
*p = pkt;
|
||||
return pkt;
|
||||
}
|
||||
|
||||
/** parse MATCH line */
|
||||
static void matchline(char* line, struct entry* e)
|
||||
{
|
||||
char* parse = line;
|
||||
while(*parse) {
|
||||
if(isendline(*parse))
|
||||
return;
|
||||
if(str_keyword(&parse, "opcode")) {
|
||||
e->match_opcode = true;
|
||||
} else if(str_keyword(&parse, "qtype")) {
|
||||
e->match_qtype = true;
|
||||
} else if(str_keyword(&parse, "qname")) {
|
||||
e->match_qname = true;
|
||||
} else if(str_keyword(&parse, "subdomain")) {
|
||||
e->match_subdomain = true;
|
||||
} else if(str_keyword(&parse, "all")) {
|
||||
e->match_all = true;
|
||||
} else if(str_keyword(&parse, "ttl")) {
|
||||
e->match_ttl = true;
|
||||
} else if(str_keyword(&parse, "DO")) {
|
||||
e->match_do = true;
|
||||
} else if(str_keyword(&parse, "noedns")) {
|
||||
e->match_noedns = true;
|
||||
} else if(str_keyword(&parse, "UDP")) {
|
||||
e->match_transport = transport_udp;
|
||||
} else if(str_keyword(&parse, "TCP")) {
|
||||
e->match_transport = transport_tcp;
|
||||
} else if(str_keyword(&parse, "serial")) {
|
||||
e->match_serial = true;
|
||||
if(*parse != '=' && *parse != ':')
|
||||
error("expected = or : in MATCH: %s", line);
|
||||
parse++;
|
||||
e->ixfr_soa_serial = (uint32_t)strtol(parse, (char**)&parse, 10);
|
||||
while(isspace((int)*parse))
|
||||
parse++;
|
||||
} else {
|
||||
error("could not parse MATCH: '%s'", parse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** parse REPLY line */
|
||||
static void replyline(char* line, ldns_pkt *reply)
|
||||
{
|
||||
char* parse = line;
|
||||
while(*parse) {
|
||||
if(isendline(*parse))
|
||||
return;
|
||||
/* opcodes */
|
||||
if(str_keyword(&parse, "QUERY")) {
|
||||
ldns_pkt_set_opcode(reply, LDNS_PACKET_QUERY);
|
||||
} else if(str_keyword(&parse, "IQUERY")) {
|
||||
ldns_pkt_set_opcode(reply, LDNS_PACKET_IQUERY);
|
||||
} else if(str_keyword(&parse, "STATUS")) {
|
||||
ldns_pkt_set_opcode(reply, LDNS_PACKET_STATUS);
|
||||
} else if(str_keyword(&parse, "NOTIFY")) {
|
||||
ldns_pkt_set_opcode(reply, LDNS_PACKET_NOTIFY);
|
||||
} else if(str_keyword(&parse, "UPDATE")) {
|
||||
ldns_pkt_set_opcode(reply, LDNS_PACKET_UPDATE);
|
||||
/* rcodes */
|
||||
} else if(str_keyword(&parse, "NOERROR")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_NOERROR);
|
||||
} else if(str_keyword(&parse, "FORMERR")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_FORMERR);
|
||||
} else if(str_keyword(&parse, "SERVFAIL")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_SERVFAIL);
|
||||
} else if(str_keyword(&parse, "NXDOMAIN")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_NXDOMAIN);
|
||||
} else if(str_keyword(&parse, "NOTIMPL")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_NOTIMPL);
|
||||
} else if(str_keyword(&parse, "REFUSED")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_REFUSED);
|
||||
} else if(str_keyword(&parse, "YXDOMAIN")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_YXDOMAIN);
|
||||
} else if(str_keyword(&parse, "YXRRSET")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_YXRRSET);
|
||||
} else if(str_keyword(&parse, "NXRRSET")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_NXRRSET);
|
||||
} else if(str_keyword(&parse, "NOTAUTH")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_NOTAUTH);
|
||||
} else if(str_keyword(&parse, "NOTZONE")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_NOTZONE);
|
||||
/* flags */
|
||||
} else if(str_keyword(&parse, "QR")) {
|
||||
ldns_pkt_set_qr(reply, true);
|
||||
} else if(str_keyword(&parse, "AA")) {
|
||||
ldns_pkt_set_aa(reply, true);
|
||||
} else if(str_keyword(&parse, "TC")) {
|
||||
ldns_pkt_set_tc(reply, true);
|
||||
} else if(str_keyword(&parse, "RD")) {
|
||||
ldns_pkt_set_rd(reply, true);
|
||||
} else if(str_keyword(&parse, "CD")) {
|
||||
ldns_pkt_set_cd(reply, true);
|
||||
} else if(str_keyword(&parse, "RA")) {
|
||||
ldns_pkt_set_ra(reply, true);
|
||||
} else if(str_keyword(&parse, "AD")) {
|
||||
ldns_pkt_set_ad(reply, true);
|
||||
} else if(str_keyword(&parse, "DO")) {
|
||||
ldns_pkt_set_edns_udp_size(reply, 4096);
|
||||
ldns_pkt_set_edns_do(reply, true);
|
||||
} else {
|
||||
error("could not parse REPLY: '%s'", parse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** parse ADJUST line */
|
||||
static void adjustline(char* line, struct entry* e,
|
||||
struct reply_packet* pkt)
|
||||
{
|
||||
char* parse = line;
|
||||
while(*parse) {
|
||||
if(isendline(*parse))
|
||||
return;
|
||||
if(str_keyword(&parse, "copy_id")) {
|
||||
e->copy_id = true;
|
||||
} else if(str_keyword(&parse, "copy_query")) {
|
||||
e->copy_query = true;
|
||||
} else if(str_keyword(&parse, "sleep=")) {
|
||||
e->sleeptime = (unsigned int) strtol(parse, (char**)&parse, 10);
|
||||
while(isspace((int)*parse))
|
||||
parse++;
|
||||
} else if(str_keyword(&parse, "packet_sleep=")) {
|
||||
pkt->packet_sleep = (unsigned int) strtol(parse, (char**)&parse, 10);
|
||||
while(isspace((int)*parse))
|
||||
parse++;
|
||||
} else {
|
||||
error("could not parse ADJUST: '%s'", parse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** create new entry */
|
||||
static struct entry* new_entry()
|
||||
{
|
||||
struct entry* e = LDNS_MALLOC(struct entry);
|
||||
memset(e, 0, sizeof(*e));
|
||||
e->match_opcode = false;
|
||||
e->match_qtype = false;
|
||||
e->match_qname = false;
|
||||
e->match_subdomain = false;
|
||||
e->match_all = false;
|
||||
e->match_ttl = false;
|
||||
e->match_do = false;
|
||||
e->match_noedns = false;
|
||||
e->match_serial = false;
|
||||
e->ixfr_soa_serial = 0;
|
||||
e->match_transport = transport_any;
|
||||
e->reply_list = NULL;
|
||||
e->copy_id = false;
|
||||
e->copy_query = false;
|
||||
e->sleeptime = 0;
|
||||
e->next = NULL;
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a hex string to binary data
|
||||
* @param hexstr: string of hex.
|
||||
* @param len: is the length of the string
|
||||
* @param buf: is the buffer to store the result in
|
||||
* @param offset: is the starting position in the result buffer
|
||||
* @param buf_len: is the length of buf.
|
||||
* @return This function returns the length of the result
|
||||
*/
|
||||
static size_t
|
||||
hexstr2bin(char *hexstr, int len, uint8_t *buf, size_t offset, size_t buf_len)
|
||||
{
|
||||
char c;
|
||||
int i;
|
||||
uint8_t int8 = 0;
|
||||
int sec = 0;
|
||||
size_t bufpos = 0;
|
||||
|
||||
if (len % 2 != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
c = hexstr[i];
|
||||
|
||||
/* case insensitive, skip spaces */
|
||||
if (c != ' ') {
|
||||
if (c >= '0' && c <= '9') {
|
||||
int8 += c & 0x0f;
|
||||
} else if (c >= 'a' && c <= 'z') {
|
||||
int8 += (c & 0x0f) + 9;
|
||||
} else if (c >= 'A' && c <= 'Z') {
|
||||
int8 += (c & 0x0f) + 9;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sec == 0) {
|
||||
int8 = int8 << 4;
|
||||
sec = 1;
|
||||
} else {
|
||||
if (bufpos + offset + 1 <= buf_len) {
|
||||
buf[bufpos+offset] = int8;
|
||||
int8 = 0;
|
||||
sec = 0;
|
||||
bufpos++;
|
||||
} else {
|
||||
fprintf(stderr, "Buffer too small in hexstr2bin");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bufpos;
|
||||
}
|
||||
|
||||
/** convert hex buffer to binary buffer */
|
||||
static ldns_buffer *
|
||||
data_buffer2wire(ldns_buffer *data_buffer)
|
||||
{
|
||||
ldns_buffer *wire_buffer = NULL;
|
||||
int c;
|
||||
|
||||
/* stat hack
|
||||
* 0 = normal
|
||||
* 1 = comment (skip to end of line)
|
||||
* 2 = unprintable character found, read binary data directly
|
||||
*/
|
||||
size_t data_buf_pos = 0;
|
||||
int state = 0;
|
||||
uint8_t *hexbuf;
|
||||
int hexbufpos = 0;
|
||||
size_t wirelen;
|
||||
uint8_t *data_wire = (uint8_t *) ldns_buffer_begin(data_buffer);
|
||||
uint8_t *wire = LDNS_XMALLOC(uint8_t, LDNS_MAX_PACKETLEN);
|
||||
|
||||
hexbuf = LDNS_XMALLOC(uint8_t, LDNS_MAX_PACKETLEN);
|
||||
for (data_buf_pos = 0; data_buf_pos < ldns_buffer_position(data_buffer); data_buf_pos++) {
|
||||
c = (int) data_wire[data_buf_pos];
|
||||
|
||||
if (state < 2 && !isascii(c)) {
|
||||
/*verbose("non ascii character found in file: (%d) switching to raw mode\n", c);*/
|
||||
state = 2;
|
||||
}
|
||||
switch (state) {
|
||||
case 0:
|
||||
if ( (c >= '0' && c <= '9') ||
|
||||
(c >= 'a' && c <= 'f') ||
|
||||
(c >= 'A' && c <= 'F') )
|
||||
{
|
||||
if (hexbufpos >= LDNS_MAX_PACKETLEN) {
|
||||
error("buffer overflow");
|
||||
LDNS_FREE(hexbuf);
|
||||
return 0;
|
||||
|
||||
}
|
||||
hexbuf[hexbufpos] = (uint8_t) c;
|
||||
hexbufpos++;
|
||||
} else if (c == ';') {
|
||||
state = 1;
|
||||
} else if (c == ' ' || c == '\t' || c == '\n') {
|
||||
/* skip whitespace */
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (c == '\n' || c == EOF) {
|
||||
state = 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (hexbufpos >= LDNS_MAX_PACKETLEN) {
|
||||
error("buffer overflow");
|
||||
LDNS_FREE(hexbuf);
|
||||
return 0;
|
||||
}
|
||||
hexbuf[hexbufpos] = (uint8_t) c;
|
||||
hexbufpos++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hexbufpos >= LDNS_MAX_PACKETLEN) {
|
||||
/*verbose("packet size reached\n");*/
|
||||
}
|
||||
|
||||
/* lenient mode: length must be multiple of 2 */
|
||||
if (hexbufpos % 2 != 0) {
|
||||
if (hexbufpos >= LDNS_MAX_PACKETLEN) {
|
||||
error("buffer overflow");
|
||||
LDNS_FREE(hexbuf);
|
||||
return 0;
|
||||
}
|
||||
hexbuf[hexbufpos] = (uint8_t) '0';
|
||||
hexbufpos++;
|
||||
}
|
||||
|
||||
if (state < 2) {
|
||||
wirelen = hexstr2bin((char *) hexbuf, hexbufpos, wire, 0, LDNS_MAX_PACKETLEN);
|
||||
wire_buffer = ldns_buffer_new(wirelen);
|
||||
ldns_buffer_new_frm_data(wire_buffer, wire, wirelen);
|
||||
} else {
|
||||
error("Incomplete hex data, not at byte boundary\n");
|
||||
}
|
||||
LDNS_FREE(wire);
|
||||
LDNS_FREE(hexbuf);
|
||||
return wire_buffer;
|
||||
}
|
||||
|
||||
/** parse ORIGIN */
|
||||
static void
|
||||
get_origin(const char* name, int lineno, ldns_rdf** origin, char* parse)
|
||||
{
|
||||
/* snip off rest of the text so as to make the parse work in ldns */
|
||||
char* end;
|
||||
char store;
|
||||
ldns_status status;
|
||||
|
||||
ldns_rdf_free(*origin);
|
||||
*origin = NULL;
|
||||
|
||||
end=parse;
|
||||
while(!isspace((int)*end) && !isendline(*end))
|
||||
end++;
|
||||
store = *end;
|
||||
*end = 0;
|
||||
verbose(3, "parsing '%s'\n", parse);
|
||||
status = ldns_str2rdf_dname(origin, parse);
|
||||
*end = store;
|
||||
if (status != LDNS_STATUS_OK)
|
||||
error("%s line %d:\n\t%s: %s", name, lineno,
|
||||
ldns_get_errorstr_by_id(status), parse);
|
||||
}
|
||||
|
||||
/* Reads one entry from file. Returns entry or NULL on error. */
|
||||
struct entry*
|
||||
read_entry(FILE* in, const char* name, int *lineno, uint32_t* default_ttl,
|
||||
ldns_rdf** origin, ldns_rdf** prev_rr, int skip_whitespace)
|
||||
{
|
||||
struct entry* current = NULL;
|
||||
char line[MAX_LINE];
|
||||
char* parse;
|
||||
ldns_pkt_section add_section = LDNS_SECTION_QUESTION;
|
||||
struct reply_packet *cur_reply = NULL;
|
||||
bool reading_hex = false;
|
||||
ldns_buffer* hex_data_buffer = NULL;
|
||||
|
||||
while(fgets(line, (int)sizeof(line), in) != NULL) {
|
||||
line[MAX_LINE-1] = 0;
|
||||
parse = line;
|
||||
(*lineno) ++;
|
||||
|
||||
while(isspace((int)*parse))
|
||||
parse++;
|
||||
/* test for keywords */
|
||||
if(isendline(*parse))
|
||||
continue; /* skip comment and empty lines */
|
||||
if(str_keyword(&parse, "ENTRY_BEGIN")) {
|
||||
if(current) {
|
||||
error("%s line %d: previous entry does not ENTRY_END",
|
||||
name, *lineno);
|
||||
}
|
||||
current = new_entry();
|
||||
current->lineno = *lineno;
|
||||
cur_reply = entry_add_reply(current);
|
||||
continue;
|
||||
} else if(str_keyword(&parse, "$ORIGIN")) {
|
||||
get_origin(name, *lineno, origin, parse);
|
||||
continue;
|
||||
} else if(str_keyword(&parse, "$TTL")) {
|
||||
*default_ttl = (uint32_t)atoi(parse);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* working inside an entry */
|
||||
if(!current) {
|
||||
error("%s line %d: expected ENTRY_BEGIN but got %s",
|
||||
name, *lineno, line);
|
||||
}
|
||||
if(str_keyword(&parse, "MATCH")) {
|
||||
matchline(parse, current);
|
||||
} else if(str_keyword(&parse, "REPLY")) {
|
||||
replyline(parse, cur_reply->reply);
|
||||
} else if(str_keyword(&parse, "ADJUST")) {
|
||||
adjustline(parse, current, cur_reply);
|
||||
} else if(str_keyword(&parse, "EXTRA_PACKET")) {
|
||||
cur_reply = entry_add_reply(current);
|
||||
} else if(str_keyword(&parse, "SECTION")) {
|
||||
if(str_keyword(&parse, "QUESTION"))
|
||||
add_section = LDNS_SECTION_QUESTION;
|
||||
else if(str_keyword(&parse, "ANSWER"))
|
||||
add_section = LDNS_SECTION_ANSWER;
|
||||
else if(str_keyword(&parse, "AUTHORITY"))
|
||||
add_section = LDNS_SECTION_AUTHORITY;
|
||||
else if(str_keyword(&parse, "ADDITIONAL"))
|
||||
add_section = LDNS_SECTION_ADDITIONAL;
|
||||
else error("%s line %d: bad section %s", name, *lineno, parse);
|
||||
} else if(str_keyword(&parse, "HEX_ANSWER_BEGIN")) {
|
||||
hex_data_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
|
||||
reading_hex = true;
|
||||
} else if(str_keyword(&parse, "HEX_ANSWER_END")) {
|
||||
if (!reading_hex) {
|
||||
error("%s line %d: HEX_ANSWER_END read but no HEX_ANSWER_BEGIN keyword seen", name, *lineno);
|
||||
}
|
||||
reading_hex = false;
|
||||
cur_reply->reply_from_hex = data_buffer2wire(hex_data_buffer);
|
||||
ldns_buffer_free(hex_data_buffer);
|
||||
hex_data_buffer = NULL;
|
||||
} else if(str_keyword(&parse, "ENTRY_END")) {
|
||||
if (hex_data_buffer)
|
||||
ldns_buffer_free(hex_data_buffer);
|
||||
return current;
|
||||
} else if(reading_hex) {
|
||||
ldns_buffer_printf(hex_data_buffer, line);
|
||||
} else {
|
||||
/* it must be a RR, parse and add to packet. */
|
||||
ldns_rr* n = NULL;
|
||||
ldns_status status;
|
||||
char* rrstr = line;
|
||||
if (skip_whitespace)
|
||||
rrstr = parse;
|
||||
if(add_section == LDNS_SECTION_QUESTION)
|
||||
status = ldns_rr_new_question_frm_str(
|
||||
&n, rrstr, *origin, prev_rr);
|
||||
else status = ldns_rr_new_frm_str(&n, rrstr,
|
||||
*default_ttl, *origin, prev_rr);
|
||||
if(status != LDNS_STATUS_OK)
|
||||
error("%s line %d:\n\t%s: %s", name, *lineno,
|
||||
ldns_get_errorstr_by_id(status), rrstr);
|
||||
ldns_pkt_push_rr(cur_reply->reply, add_section, n);
|
||||
}
|
||||
|
||||
}
|
||||
if (reading_hex) {
|
||||
error("%s: End of file reached while still reading hex, "
|
||||
"missing HEX_ANSWER_END\n", name);
|
||||
}
|
||||
if(current) {
|
||||
error("%s: End of file reached while reading entry. "
|
||||
"missing ENTRY_END\n", name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* reads the canned reply file and returns a list of structs */
|
||||
struct entry*
|
||||
read_datafile(const char* name, int skip_whitespace)
|
||||
{
|
||||
struct entry* list = NULL;
|
||||
struct entry* last = NULL;
|
||||
struct entry* current = NULL;
|
||||
FILE *in;
|
||||
int lineno = 0;
|
||||
uint32_t default_ttl = 0;
|
||||
ldns_rdf* origin = NULL;
|
||||
ldns_rdf* prev_rr = NULL;
|
||||
int entry_num = 0;
|
||||
|
||||
if((in=fopen(name, "r")) == NULL) {
|
||||
error("could not open file %s: %s", name, strerror(errno));
|
||||
}
|
||||
|
||||
while((current = read_entry(in, name, &lineno, &default_ttl,
|
||||
&origin, &prev_rr, skip_whitespace)))
|
||||
{
|
||||
if(last)
|
||||
last->next = current;
|
||||
else list = current;
|
||||
last = current;
|
||||
entry_num ++;
|
||||
}
|
||||
verbose(1, "%s: Read %d entries\n", prog_name, entry_num);
|
||||
|
||||
fclose(in);
|
||||
ldns_rdf_deep_free(origin);
|
||||
ldns_rdf_deep_free(prev_rr);
|
||||
return list;
|
||||
}
|
||||
|
||||
/** get qtype from rr */
|
||||
static ldns_rr_type get_qtype(ldns_pkt* p)
|
||||
{
|
||||
if(!ldns_rr_list_rr(ldns_pkt_question(p), 0))
|
||||
return 0;
|
||||
return ldns_rr_get_type(ldns_rr_list_rr(ldns_pkt_question(p), 0));
|
||||
}
|
||||
|
||||
/** returns owner from rr */
|
||||
static ldns_rdf* get_owner(ldns_pkt* p)
|
||||
{
|
||||
if(!ldns_rr_list_rr(ldns_pkt_question(p), 0))
|
||||
return NULL;
|
||||
return ldns_rr_owner(ldns_rr_list_rr(ldns_pkt_question(p), 0));
|
||||
}
|
||||
|
||||
/** get authority section SOA serial value */
|
||||
static uint32_t get_serial(ldns_pkt* p)
|
||||
{
|
||||
ldns_rr *rr = ldns_rr_list_rr(ldns_pkt_authority(p), 0);
|
||||
ldns_rdf *rdf;
|
||||
uint32_t val;
|
||||
if(!rr) return 0;
|
||||
rdf = ldns_rr_rdf(rr, 2);
|
||||
if(!rdf) return 0;
|
||||
val = ldns_rdf2native_int32(rdf);
|
||||
verbose(3, "found serial %u in msg. ", (int)val);
|
||||
return val;
|
||||
}
|
||||
|
||||
/** match two rr lists */
|
||||
static int
|
||||
match_list(ldns_rr_list* q, ldns_rr_list *p, bool mttl)
|
||||
{
|
||||
size_t i;
|
||||
if(ldns_rr_list_rr_count(q) != ldns_rr_list_rr_count(p))
|
||||
return 0;
|
||||
for(i=0; i<ldns_rr_list_rr_count(q); i++)
|
||||
{
|
||||
if(ldns_rr_compare(ldns_rr_list_rr(q, i),
|
||||
ldns_rr_list_rr(p, i)) != 0) {
|
||||
verbose(3, "rr %d different", (int)i);
|
||||
return 0;
|
||||
}
|
||||
if(mttl && ldns_rr_ttl(ldns_rr_list_rr(q, i)) !=
|
||||
ldns_rr_ttl(ldns_rr_list_rr(p, i))) {
|
||||
verbose(3, "rr %d ttl different", (int)i);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** compare two booleans */
|
||||
static int
|
||||
cmp_bool(int x, int y)
|
||||
{
|
||||
if(!x && !y) return 0;
|
||||
if(x && y) return 0;
|
||||
if(!x) return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** match all of the packet */
|
||||
static int
|
||||
match_all(ldns_pkt* q, ldns_pkt* p, bool mttl)
|
||||
{
|
||||
if(ldns_pkt_get_opcode(q) != ldns_pkt_get_opcode(p))
|
||||
{ verbose(3, "allmatch: opcode different"); return 0;}
|
||||
if(ldns_pkt_get_rcode(q) != ldns_pkt_get_rcode(p))
|
||||
{ verbose(3, "allmatch: rcode different"); return 0;}
|
||||
if(ldns_pkt_id(q) != ldns_pkt_id(p))
|
||||
{ verbose(3, "allmatch: id different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_qr(q), ldns_pkt_qr(p)) != 0)
|
||||
{ verbose(3, "allmatch: qr different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_aa(q), ldns_pkt_aa(p)) != 0)
|
||||
{ verbose(3, "allmatch: aa different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_tc(q), ldns_pkt_tc(p)) != 0)
|
||||
{ verbose(3, "allmatch: tc different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_rd(q), ldns_pkt_rd(p)) != 0)
|
||||
{ verbose(3, "allmatch: rd different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_cd(q), ldns_pkt_cd(p)) != 0)
|
||||
{ verbose(3, "allmatch: cd different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_ra(q), ldns_pkt_ra(p)) != 0)
|
||||
{ verbose(3, "allmatch: ra different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_ad(q), ldns_pkt_ad(p)) != 0)
|
||||
{ verbose(3, "allmatch: ad different"); return 0;}
|
||||
if(ldns_pkt_qdcount(q) != ldns_pkt_qdcount(p))
|
||||
{ verbose(3, "allmatch: qdcount different"); return 0;}
|
||||
if(ldns_pkt_ancount(q) != ldns_pkt_ancount(p))
|
||||
{ verbose(3, "allmatch: ancount different"); return 0;}
|
||||
if(ldns_pkt_nscount(q) != ldns_pkt_nscount(p))
|
||||
{ verbose(3, "allmatch: nscount different"); return 0;}
|
||||
if(ldns_pkt_arcount(q) != ldns_pkt_arcount(p))
|
||||
{ verbose(3, "allmatch: arcount different"); return 0;}
|
||||
if(!match_list(ldns_pkt_question(q), ldns_pkt_question(p), 0))
|
||||
{ verbose(3, "allmatch: qd section different"); return 0;}
|
||||
if(!match_list(ldns_pkt_answer(q), ldns_pkt_answer(p), mttl))
|
||||
{ verbose(3, "allmatch: an section different"); return 0;}
|
||||
if(!match_list(ldns_pkt_authority(q), ldns_pkt_authority(p), mttl))
|
||||
{ verbose(3, "allmatch: ar section different"); return 0;}
|
||||
if(!match_list(ldns_pkt_additional(q), ldns_pkt_additional(p), mttl))
|
||||
{ verbose(3, "allmatch: ns section different"); return 0;}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* finds entry in list, or returns NULL */
|
||||
struct entry*
|
||||
find_match(struct entry* entries, ldns_pkt* query_pkt,
|
||||
enum transport_type transport)
|
||||
{
|
||||
struct entry* p = entries;
|
||||
ldns_pkt* reply = NULL;
|
||||
for(p=entries; p; p=p->next) {
|
||||
verbose(3, "comparepkt: ");
|
||||
reply = p->reply_list->reply;
|
||||
if(p->match_opcode && ldns_pkt_get_opcode(query_pkt) !=
|
||||
ldns_pkt_get_opcode(reply)) {
|
||||
verbose(3, "bad opcode\n");
|
||||
continue;
|
||||
}
|
||||
if(p->match_qtype && get_qtype(query_pkt) != get_qtype(reply)) {
|
||||
verbose(3, "bad qtype\n");
|
||||
continue;
|
||||
}
|
||||
if(p->match_qname) {
|
||||
if(!get_owner(query_pkt) || !get_owner(reply) ||
|
||||
ldns_dname_compare(
|
||||
get_owner(query_pkt), get_owner(reply)) != 0) {
|
||||
verbose(3, "bad qname\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(p->match_subdomain) {
|
||||
if(!get_owner(query_pkt) || !get_owner(reply) ||
|
||||
(ldns_dname_compare(get_owner(query_pkt),
|
||||
get_owner(reply)) != 0 &&
|
||||
!ldns_dname_is_subdomain(
|
||||
get_owner(query_pkt), get_owner(reply))))
|
||||
{
|
||||
verbose(3, "bad subdomain\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(p->match_serial && get_serial(query_pkt) != p->ixfr_soa_serial) {
|
||||
verbose(3, "bad serial\n");
|
||||
continue;
|
||||
}
|
||||
if(p->match_do && !ldns_pkt_edns_do(query_pkt)) {
|
||||
verbose(3, "no DO bit set\n");
|
||||
continue;
|
||||
}
|
||||
if(p->match_noedns && ldns_pkt_edns(query_pkt)) {
|
||||
verbose(3, "bad; EDNS OPT present\n");
|
||||
continue;
|
||||
}
|
||||
if(p->match_transport != transport_any && p->match_transport != transport) {
|
||||
verbose(3, "bad transport\n");
|
||||
continue;
|
||||
}
|
||||
if(p->match_all && !match_all(query_pkt, reply, p->match_ttl)) {
|
||||
verbose(3, "bad allmatch\n");
|
||||
continue;
|
||||
}
|
||||
verbose(3, "match!\n");
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
adjust_packet(struct entry* match, ldns_pkt* answer_pkt, ldns_pkt* query_pkt)
|
||||
{
|
||||
/* copy & adjust packet */
|
||||
if(match->copy_id)
|
||||
ldns_pkt_set_id(answer_pkt, ldns_pkt_id(query_pkt));
|
||||
if(match->copy_query) {
|
||||
ldns_rr_list* list = ldns_pkt_get_section_clone(query_pkt,
|
||||
LDNS_SECTION_QUESTION);
|
||||
ldns_rr_list_deep_free(ldns_pkt_question(answer_pkt));
|
||||
ldns_pkt_set_question(answer_pkt, list);
|
||||
}
|
||||
if(match->sleeptime > 0) {
|
||||
verbose(3, "sleeping for %d seconds\n", match->sleeptime);
|
||||
#ifdef HAVE_SLEEP
|
||||
sleep(match->sleeptime);
|
||||
#else
|
||||
Sleep(match->sleeptime * 1000);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses data buffer to a query, finds the correct answer
|
||||
* and calls the given function for every packet to send.
|
||||
*/
|
||||
void
|
||||
handle_query(uint8_t* inbuf, ssize_t inlen, struct entry* entries, int* count,
|
||||
enum transport_type transport, void (*sendfunc)(uint8_t*, size_t, void*),
|
||||
void* userdata, FILE* verbose_out)
|
||||
{
|
||||
ldns_status status;
|
||||
ldns_pkt *query_pkt = NULL;
|
||||
ldns_pkt *answer_pkt = NULL;
|
||||
struct reply_packet *p;
|
||||
ldns_rr *query_rr = NULL;
|
||||
uint8_t *outbuf = NULL;
|
||||
size_t answer_size = 0;
|
||||
struct entry* entry = NULL;
|
||||
ldns_rdf *stop_command = ldns_dname_new_frm_str("server.stop.");
|
||||
|
||||
status = ldns_wire2pkt(&query_pkt, inbuf, (size_t)inlen);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
verbose(1, "Got bad packet: %s\n", ldns_get_errorstr_by_id(status));
|
||||
ldns_rdf_free(stop_command);
|
||||
return;
|
||||
}
|
||||
|
||||
query_rr = ldns_rr_list_rr(ldns_pkt_question(query_pkt), 0);
|
||||
verbose(1, "query %d: id %d: %s %d bytes: ", ++(*count), (int)ldns_pkt_id(query_pkt),
|
||||
(transport==transport_tcp)?"TCP":"UDP", (int)inlen);
|
||||
if(verbose_out) ldns_rr_print(verbose_out, query_rr);
|
||||
if(verbose_out) ldns_pkt_print(verbose_out, query_pkt);
|
||||
|
||||
if (ldns_rr_get_type(query_rr) == LDNS_RR_TYPE_TXT &&
|
||||
ldns_rr_get_class(query_rr) == LDNS_RR_CLASS_CH &&
|
||||
ldns_dname_compare(ldns_rr_owner(query_rr), stop_command) == 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* fill up answer packet */
|
||||
entry = find_match(entries, query_pkt, transport);
|
||||
if(!entry || !entry->reply_list) {
|
||||
verbose(1, "no answer packet for this query, no reply.\n");
|
||||
ldns_pkt_free(query_pkt);
|
||||
ldns_rdf_free(stop_command);
|
||||
return;
|
||||
}
|
||||
for(p = entry->reply_list; p; p = p->next)
|
||||
{
|
||||
verbose(3, "Answer pkt:\n");
|
||||
if (p->reply_from_hex) {
|
||||
/* try to parse the hex packet, if it can be
|
||||
* parsed, we can use adjust rules. if not,
|
||||
* send packet literally */
|
||||
status = ldns_buffer2pkt_wire(&answer_pkt, p->reply_from_hex);
|
||||
if (status == LDNS_STATUS_OK) {
|
||||
adjust_packet(entry, answer_pkt, query_pkt);
|
||||
if(verbose_out) ldns_pkt_print(verbose_out, answer_pkt);
|
||||
status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size);
|
||||
verbose(2, "Answer packet size: %u bytes.\n", (unsigned int)answer_size);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
verbose(1, "Error creating answer: %s\n", ldns_get_errorstr_by_id(status));
|
||||
ldns_pkt_free(query_pkt);
|
||||
ldns_rdf_free(stop_command);
|
||||
return;
|
||||
}
|
||||
ldns_pkt_free(answer_pkt);
|
||||
answer_pkt = NULL;
|
||||
} else {
|
||||
verbose(3, "Could not parse hex data (%s), sending hex data directly.\n", ldns_get_errorstr_by_id(status));
|
||||
/* still try to adjust ID */
|
||||
answer_size = ldns_buffer_capacity(p->reply_from_hex);
|
||||
outbuf = LDNS_XMALLOC(uint8_t, answer_size);
|
||||
memcpy(outbuf, ldns_buffer_begin(p->reply_from_hex), answer_size);
|
||||
if(entry->copy_id) {
|
||||
ldns_write_uint16(outbuf,
|
||||
ldns_pkt_id(query_pkt));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
answer_pkt = ldns_pkt_clone(p->reply);
|
||||
adjust_packet(entry, answer_pkt, query_pkt);
|
||||
if(verbose_out) ldns_pkt_print(verbose_out, answer_pkt);
|
||||
status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size);
|
||||
verbose(1, "Answer packet size: %u bytes.\n", (unsigned int)answer_size);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
verbose(1, "Error creating answer: %s\n", ldns_get_errorstr_by_id(status));
|
||||
ldns_pkt_free(query_pkt);
|
||||
ldns_rdf_free(stop_command);
|
||||
return;
|
||||
}
|
||||
ldns_pkt_free(answer_pkt);
|
||||
answer_pkt = NULL;
|
||||
}
|
||||
if(p->packet_sleep) {
|
||||
verbose(3, "sleeping for next packet %d secs\n",
|
||||
p->packet_sleep);
|
||||
#ifdef HAVE_SLEEP
|
||||
sleep(p->packet_sleep);
|
||||
#else
|
||||
Sleep(p->packet_sleep * 1000);
|
||||
#endif
|
||||
verbose(3, "wakeup for next packet "
|
||||
"(slept %d secs)\n", p->packet_sleep);
|
||||
}
|
||||
sendfunc(outbuf, answer_size, userdata);
|
||||
LDNS_FREE(outbuf);
|
||||
outbuf = NULL;
|
||||
answer_size = 0;
|
||||
}
|
||||
ldns_pkt_free(query_pkt);
|
||||
ldns_rdf_free(stop_command);
|
||||
}
|
||||
|
||||
/** delete the list of reply packets */
|
||||
void delete_replylist(struct reply_packet* replist)
|
||||
{
|
||||
struct reply_packet *p=replist, *np;
|
||||
while(p) {
|
||||
np = p->next;
|
||||
ldns_pkt_free(p->reply);
|
||||
ldns_buffer_free(p->reply_from_hex);
|
||||
free(p);
|
||||
p=np;
|
||||
}
|
||||
}
|
||||
|
||||
void delete_entry(struct entry* list)
|
||||
{
|
||||
struct entry *p=list, *np;
|
||||
while(p) {
|
||||
np = p->next;
|
||||
delete_replylist(p->reply_list);
|
||||
free(p);
|
||||
p = np;
|
||||
}
|
||||
}
|
||||
+10
-11
@@ -43,7 +43,6 @@
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
#include <ldns/ldns.h>
|
||||
#include <signal.h>
|
||||
#include "util/log.h"
|
||||
#include "util/locks.h"
|
||||
@@ -51,6 +50,10 @@
|
||||
#include "util/data/msgencode.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/data/msgparse.h"
|
||||
#include "ldns/sbuffer.h"
|
||||
#include "ldns/wire2str.h"
|
||||
#include "ldns/str2wire.h"
|
||||
#include <sys/time.h>
|
||||
|
||||
/** usage information for perf */
|
||||
static void usage(char* nm)
|
||||
@@ -434,11 +437,10 @@ perfendstats(struct perfinfo* info)
|
||||
for(i=0; i<(int)(sizeof(info->by_rcode)/sizeof(size_t)); i++)
|
||||
{
|
||||
if(info->by_rcode[i] > 0) {
|
||||
char rc[16];
|
||||
ldns_wire2str_rcode_buf(i, rc, sizeof(rc));
|
||||
printf("%d(%5s): %u replies\n",
|
||||
i, ldns_lookup_by_id(ldns_rcodes, i)?
|
||||
ldns_lookup_by_id(ldns_rcodes,
|
||||
i)->name:"??",
|
||||
(unsigned)info->by_rcode[i]);
|
||||
i, rc, (unsigned)info->by_rcode[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -465,7 +467,6 @@ qlist_parse_line(ldns_buffer* buf, char* p)
|
||||
int r;
|
||||
int rec = 1, edns = 0;
|
||||
struct query_info qinfo;
|
||||
ldns_rdf* rdf;
|
||||
nm[0] = 0; cl[0] = 0; tp[0] = 0; fl[0] = 0;
|
||||
r = sscanf(p, " %1023s %1023s %1023s %1023s", nm, cl, tp, fl);
|
||||
if(r != 3 && r != 4)
|
||||
@@ -483,11 +484,9 @@ qlist_parse_line(ldns_buffer* buf, char* p)
|
||||
else if(fl[0] == 'E') edns = 1;
|
||||
if((fl[0] == '+' || fl[0] == '-') && fl[1] == 'E')
|
||||
edns = 1;
|
||||
rdf = ldns_dname_new_frm_str(nm);
|
||||
if(!rdf)
|
||||
qinfo.qname = ldns_str2wire_dname(nm, &qinfo.qname_len);
|
||||
if(!qinfo.qname)
|
||||
return 0;
|
||||
qinfo.qname = ldns_rdf_data(rdf);
|
||||
qinfo.qname_len = ldns_rdf_size(rdf);
|
||||
qinfo_query_encode(buf, &qinfo);
|
||||
ldns_buffer_write_u16_at(buf, 0, 0); /* zero ID */
|
||||
if(rec) LDNS_RD_SET(ldns_buffer_begin(buf));
|
||||
@@ -500,7 +499,7 @@ qlist_parse_line(ldns_buffer* buf, char* p)
|
||||
ed.bits = EDNS_DO;
|
||||
attach_edns_record(buf, &ed);
|
||||
}
|
||||
ldns_rdf_deep_free(rdf);
|
||||
free(qinfo.qname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -40,12 +40,13 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <ldns/ldns.h>
|
||||
#include "util/log.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/data/msgparse.h"
|
||||
#include "testcode/unitmain.h"
|
||||
#include "testcode/readhex.h"
|
||||
#include "ldns/sbuffer.h"
|
||||
#include "ldns/parseutil.h"
|
||||
|
||||
/** usage information for pktview */
|
||||
static void usage(char* argv[])
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
#include <ctype.h>
|
||||
#include "testcode/readhex.h"
|
||||
#include "util/log.h"
|
||||
#include "ldns/sbuffer.h"
|
||||
#include "ldns/parseutil.h"
|
||||
|
||||
/** skip whitespace */
|
||||
static void
|
||||
|
||||
+2
-2
@@ -40,13 +40,13 @@
|
||||
|
||||
#ifndef TESTCODE_READHEX_H
|
||||
#define TESTCODE_READHEX_H
|
||||
#include <ldns/buffer.h>
|
||||
struct ldns_buffer;
|
||||
|
||||
/**
|
||||
* Helper to convert hex string to packet buffer.
|
||||
* @param pkt: buffer to put result in.
|
||||
* @param hex: string of hex data. Spaces and ';...' comments are skipped.
|
||||
*/
|
||||
void hex_to_buf(ldns_buffer* pkt, const char* hex);
|
||||
void hex_to_buf(struct ldns_buffer* pkt, const char* hex);
|
||||
|
||||
#endif /* TESTCODE_READHEX_H */
|
||||
|
||||
+35
-35
@@ -42,12 +42,15 @@
|
||||
#include "config.h"
|
||||
/* for strtod prototype */
|
||||
#include <math.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include "util/log.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/config_file.h"
|
||||
#include "testcode/replay.h"
|
||||
#include "testcode/ldns-testpkts.h"
|
||||
#include "testcode/testpkts.h"
|
||||
#include "testcode/fake_event.h"
|
||||
#include "ldns/str2wire.h"
|
||||
|
||||
/** max length of lines in file */
|
||||
#define MAX_LINE_LEN 10240
|
||||
@@ -138,16 +141,15 @@ strip_end_white(char* p)
|
||||
* @param remain: Rest of line (after RANGE keyword).
|
||||
* @param in: file to read from.
|
||||
* @param name: name to print in errors.
|
||||
* @param lineno: incremented as lines are read.
|
||||
* @param pstate: read state structure with
|
||||
* with lineno : incremented as lines are read.
|
||||
* ttl, origin, prev for readentry.
|
||||
* @param line: line buffer.
|
||||
* @param ttl: for readentry
|
||||
* @param or: for readentry
|
||||
* @param prev: for readentry
|
||||
* @return: range object to add to list, or NULL on error.
|
||||
*/
|
||||
static struct replay_range*
|
||||
replay_range_read(char* remain, FILE* in, const char* name, int* lineno,
|
||||
char* line, uint32_t* ttl, ldns_rdf** or, ldns_rdf** prev)
|
||||
replay_range_read(char* remain, FILE* in, const char* name,
|
||||
struct ldns_file_parse_state* pstate, char* line)
|
||||
{
|
||||
struct replay_range* rng = (struct replay_range*)malloc(
|
||||
sizeof(struct replay_range));
|
||||
@@ -166,7 +168,7 @@ replay_range_read(char* remain, FILE* in, const char* name, int* lineno,
|
||||
/* read entries */
|
||||
pos = ftello(in);
|
||||
while(fgets(line, MAX_LINE_LEN-1, in)) {
|
||||
(*lineno)++;
|
||||
pstate->lineno++;
|
||||
parse = line;
|
||||
while(isspace((int)*parse))
|
||||
parse++;
|
||||
@@ -180,7 +182,7 @@ replay_range_read(char* remain, FILE* in, const char* name, int* lineno,
|
||||
strip_end_white(parse);
|
||||
if(!extstrtoaddr(parse, &rng->addr, &rng->addrlen)) {
|
||||
log_err("Line %d: could not read ADDRESS: %s",
|
||||
*lineno, parse);
|
||||
pstate->lineno, parse);
|
||||
free(rng);
|
||||
return NULL;
|
||||
}
|
||||
@@ -191,11 +193,11 @@ replay_range_read(char* remain, FILE* in, const char* name, int* lineno,
|
||||
return rng;
|
||||
}
|
||||
/* set position before line; read entry */
|
||||
(*lineno)--;
|
||||
pstate->lineno--;
|
||||
fseeko(in, pos, SEEK_SET);
|
||||
entry = read_entry(in, name, lineno, ttl, or, prev, 1);
|
||||
entry = read_entry(in, name, pstate, 1);
|
||||
if(!entry)
|
||||
fatal_exit("%d: bad entry", *lineno);
|
||||
fatal_exit("%d: bad entry", pstate->lineno);
|
||||
entry->next = NULL;
|
||||
if(last)
|
||||
last->next = entry;
|
||||
@@ -258,15 +260,13 @@ read_assign_step(char* remain, struct replay_moment* mom)
|
||||
* @param remain: Rest of line (after STEP keyword).
|
||||
* @param in: file to read from.
|
||||
* @param name: name to print in errors.
|
||||
* @param lineno: incremented as lines are read.
|
||||
* @param ttl: for readentry
|
||||
* @param or: for readentry
|
||||
* @param prev: for readentry
|
||||
* @param pstate: with lineno, ttl, origin, prev for parse state.
|
||||
* lineno is incremented.
|
||||
* @return: range object to add to list, or NULL on error.
|
||||
*/
|
||||
static struct replay_moment*
|
||||
replay_moment_read(char* remain, FILE* in, const char* name, int* lineno,
|
||||
uint32_t* ttl, ldns_rdf** or, ldns_rdf** prev)
|
||||
replay_moment_read(char* remain, FILE* in, const char* name,
|
||||
struct ldns_file_parse_state* pstate)
|
||||
{
|
||||
struct replay_moment* mom = (struct replay_moment*)malloc(
|
||||
sizeof(struct replay_moment));
|
||||
@@ -276,7 +276,7 @@ replay_moment_read(char* remain, FILE* in, const char* name, int* lineno,
|
||||
return NULL;
|
||||
memset(mom, 0, sizeof(*mom));
|
||||
if(sscanf(remain, " %d%n", &mom->time_step, &skip) != 1) {
|
||||
log_err("%d: cannot read number: %s", *lineno, remain);
|
||||
log_err("%d: cannot read number: %s", pstate->lineno, remain);
|
||||
free(mom);
|
||||
return NULL;
|
||||
}
|
||||
@@ -322,7 +322,7 @@ replay_moment_read(char* remain, FILE* in, const char* name, int* lineno,
|
||||
remain[strlen(remain)-1] = 0;
|
||||
mom->autotrust_id = strdup(remain);
|
||||
if(!mom->autotrust_id) fatal_exit("out of memory");
|
||||
read_file_content(in, lineno, mom);
|
||||
read_file_content(in, &pstate->lineno, mom);
|
||||
} else if(parse_keyword(&remain, "ERROR")) {
|
||||
mom->evt_type = repevt_error;
|
||||
} else if(parse_keyword(&remain, "TRAFFIC")) {
|
||||
@@ -357,7 +357,7 @@ replay_moment_read(char* remain, FILE* in, const char* name, int* lineno,
|
||||
if(!mom->string) fatal_exit("out of memory");
|
||||
if(!mom->variable) fatal_exit("out of memory");
|
||||
} else {
|
||||
log_err("%d: unknown event type %s", *lineno, remain);
|
||||
log_err("%d: unknown event type %s", pstate->lineno, remain);
|
||||
free(mom);
|
||||
return NULL;
|
||||
}
|
||||
@@ -370,7 +370,7 @@ replay_moment_read(char* remain, FILE* in, const char* name, int* lineno,
|
||||
remain[strlen(remain)-1] = 0;
|
||||
if(!extstrtoaddr(remain, &mom->addr, &mom->addrlen)) {
|
||||
log_err("line %d: could not parse ADDRESS: %s",
|
||||
*lineno, remain);
|
||||
pstate->lineno, remain);
|
||||
free(mom);
|
||||
return NULL;
|
||||
}
|
||||
@@ -381,7 +381,7 @@ replay_moment_read(char* remain, FILE* in, const char* name, int* lineno,
|
||||
sec = strtod(remain, &remain);
|
||||
if(sec == 0. && errno != 0) {
|
||||
log_err("line %d: could not parse ELAPSE: %s (%s)",
|
||||
*lineno, remain, strerror(errno));
|
||||
pstate->lineno, remain, strerror(errno));
|
||||
free(mom);
|
||||
return NULL;
|
||||
}
|
||||
@@ -393,7 +393,7 @@ replay_moment_read(char* remain, FILE* in, const char* name, int* lineno,
|
||||
}
|
||||
|
||||
if(readentry) {
|
||||
mom->match = read_entry(in, name, lineno, ttl, or, prev, 1);
|
||||
mom->match = read_entry(in, name, pstate, 1);
|
||||
if(!mom->match) {
|
||||
free(mom);
|
||||
return NULL;
|
||||
@@ -432,13 +432,15 @@ replay_scenario_read(FILE* in, const char* name, int* lineno)
|
||||
char line[MAX_LINE_LEN];
|
||||
char *parse;
|
||||
struct replay_scenario* scen = NULL;
|
||||
uint32_t ttl = 3600;
|
||||
ldns_rdf* or = NULL;
|
||||
ldns_rdf* prev = NULL;
|
||||
struct ldns_file_parse_state pstate;
|
||||
line[MAX_LINE_LEN-1]=0;
|
||||
memset(&pstate, 0, sizeof(pstate));
|
||||
pstate.default_ttl = 3600;
|
||||
pstate.lineno = *lineno;
|
||||
|
||||
while(fgets(line, MAX_LINE_LEN-1, in)) {
|
||||
parse=line;
|
||||
pstate.lineno++;
|
||||
(*lineno)++;
|
||||
while(isspace((int)*parse))
|
||||
parse++;
|
||||
@@ -456,16 +458,18 @@ replay_scenario_read(FILE* in, const char* name, int* lineno)
|
||||
fatal_exit("%d: expected SCENARIO", *lineno);
|
||||
if(parse_keyword(&parse, "RANGE_BEGIN")) {
|
||||
struct replay_range* newr = replay_range_read(parse,
|
||||
in, name, lineno, line, &ttl, &or, &prev);
|
||||
in, name, &pstate, line);
|
||||
if(!newr)
|
||||
fatal_exit("%d: bad range", *lineno);
|
||||
fatal_exit("%d: bad range", pstate.lineno);
|
||||
*lineno = pstate.lineno;
|
||||
newr->next_range = scen->range_list;
|
||||
scen->range_list = newr;
|
||||
} else if(parse_keyword(&parse, "STEP")) {
|
||||
struct replay_moment* mom = replay_moment_read(parse,
|
||||
in, name, lineno, &ttl, &or, &prev);
|
||||
in, name, &pstate);
|
||||
if(!mom)
|
||||
fatal_exit("%d: bad moment", *lineno);
|
||||
fatal_exit("%d: bad moment", pstate.lineno);
|
||||
*lineno = pstate.lineno;
|
||||
if(scen->mom_last &&
|
||||
scen->mom_last->time_step >= mom->time_step)
|
||||
fatal_exit("%d: time goes backwards", *lineno);
|
||||
@@ -481,13 +485,9 @@ replay_scenario_read(FILE* in, const char* name, int* lineno)
|
||||
p = p->mom_next;
|
||||
}
|
||||
log_info("Scenario has %d steps", num);
|
||||
ldns_rdf_deep_free(or);
|
||||
ldns_rdf_deep_free(prev);
|
||||
return scen;
|
||||
}
|
||||
}
|
||||
ldns_rdf_deep_free(or);
|
||||
ldns_rdf_deep_free(prev);
|
||||
replay_scenario_delete(scen);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+7
-10
@@ -129,7 +129,7 @@
|
||||
#ifndef TESTCODE_REPLAY_H
|
||||
#define TESTCODE_REPLAY_H
|
||||
#include "util/netevent.h"
|
||||
#include "testcode/ldns-testpkts.h"
|
||||
#include "testcode/testpkts.h"
|
||||
#include "util/rbtree.h"
|
||||
struct replay_answer;
|
||||
struct replay_moment;
|
||||
@@ -138,6 +138,7 @@ struct fake_pending;
|
||||
struct fake_timer;
|
||||
struct replay_var;
|
||||
struct infra_cache;
|
||||
struct ldns_buffer;
|
||||
|
||||
/**
|
||||
* A replay scenario.
|
||||
@@ -217,12 +218,6 @@ struct replay_moment {
|
||||
/** length of addr, if 0, then any address will do */
|
||||
socklen_t addrlen;
|
||||
|
||||
/** what pending query should timeout or is answered. or
|
||||
* NULL for last sent query.
|
||||
* Unused at this time.
|
||||
*/
|
||||
ldns_rr* qname;
|
||||
|
||||
/** macro name, for assign. */
|
||||
char* variable;
|
||||
/** string argument, for assign. */
|
||||
@@ -318,7 +313,7 @@ struct replay_runtime {
|
||||
*/
|
||||
struct fake_pending {
|
||||
/** what is important only that we remember the query, copied here. */
|
||||
ldns_buffer* buffer;
|
||||
struct ldns_buffer* buffer;
|
||||
/** and to what address this is sent to. */
|
||||
struct sockaddr_storage addr;
|
||||
/** len of addr */
|
||||
@@ -339,7 +334,8 @@ struct fake_pending {
|
||||
/** next in pending list */
|
||||
struct fake_pending* next;
|
||||
/** the buffer parsed into a ldns_pkt */
|
||||
ldns_pkt* pkt;
|
||||
uint8_t* pkt;
|
||||
size_t pkt_len;
|
||||
/** by what transport was the query sent out */
|
||||
enum transport_type transport;
|
||||
/** if this is a serviced query */
|
||||
@@ -357,7 +353,8 @@ struct replay_answer {
|
||||
/** reply information */
|
||||
struct comm_reply repinfo;
|
||||
/** the answer preparsed as ldns pkt */
|
||||
ldns_pkt* pkt;
|
||||
uint8_t* pkt;
|
||||
size_t pkt_len;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+44
-10
@@ -41,9 +41,9 @@
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <ldns/ldns.h>
|
||||
#include "util/log.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/net_help.h"
|
||||
#include <assert.h>
|
||||
|
||||
#define DNSKEY_BIT_ZSK 0x0100
|
||||
|
||||
/**
|
||||
* Key settings
|
||||
@@ -74,12 +74,47 @@ usage()
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static time_t
|
||||
convert_timeval(const char* str)
|
||||
{
|
||||
time_t t;
|
||||
struct tm tm;
|
||||
memset(&tm, 0, sizeof(tm));
|
||||
if(strlen(str) < 14)
|
||||
return 0;
|
||||
if(sscanf(str, "%4d%2d%2d%2d%2d%2d", &tm.tm_year, &tm.tm_mon,
|
||||
&tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6)
|
||||
return 0;
|
||||
tm.tm_year -= 1900;
|
||||
tm.tm_mon--;
|
||||
/* Check values */
|
||||
if (tm.tm_year < 70) return 0;
|
||||
if (tm.tm_mon < 0 || tm.tm_mon > 11) return 0;
|
||||
if (tm.tm_mday < 1 || tm.tm_mday > 31) return 0;
|
||||
if (tm.tm_hour < 0 || tm.tm_hour > 23) return 0;
|
||||
if (tm.tm_min < 0 || tm.tm_min > 59) return 0;
|
||||
if (tm.tm_sec < 0 || tm.tm_sec > 59) return 0;
|
||||
/* call ldns conversion function */
|
||||
t = ldns_mktime_from_utc(&tm);
|
||||
return t;
|
||||
}
|
||||
|
||||
static void fatal_exit(const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
printf("fatal exit: ");
|
||||
vprintf(format, args);
|
||||
va_end(args);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/** read expi ince keytag owner from cmdline */
|
||||
static void
|
||||
parse_cmdline(char *argv[], struct keysets* s)
|
||||
{
|
||||
s->expi = cfg_convert_timeval(argv[1]);
|
||||
s->incep = cfg_convert_timeval(argv[2]);
|
||||
s->expi = convert_timeval(argv[1]);
|
||||
s->incep = convert_timeval(argv[2]);
|
||||
s->keytag = (uint16_t)atoi(argv[3]);
|
||||
s->owner = argv[4];
|
||||
s->flags = DNSKEY_BIT_ZSK; /* to enforce signing */
|
||||
@@ -118,7 +153,7 @@ read_keys(int num, char* names[], struct keysets* set)
|
||||
ldns_key_set_flags(k, set->flags);
|
||||
ldns_key_set_keytag(k, set->keytag);
|
||||
b = ldns_key_list_push_key(keys, k);
|
||||
log_assert(b);
|
||||
assert(b);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
@@ -151,7 +186,7 @@ read_rrs(FILE* in)
|
||||
fatal_exit("parse error in line %d: %s", line_nr,
|
||||
ldns_get_errorstr_by_id(s));
|
||||
b = ldns_rr_list_push_rr(list, rr);
|
||||
log_assert(b);
|
||||
assert(b);
|
||||
}
|
||||
printf("read %d lines\n", line_nr);
|
||||
|
||||
@@ -185,7 +220,7 @@ process_keys(int argc, char* argv[])
|
||||
ldns_rr_list* rrs;
|
||||
ldns_key_list* keys;
|
||||
struct keysets settings;
|
||||
log_assert(argc == 6);
|
||||
assert(argc == 6);
|
||||
|
||||
parse_cmdline(argv, &settings);
|
||||
keys = read_keys(1, argv+5, &settings);
|
||||
@@ -208,7 +243,7 @@ process_nsec3(int argc, char* argv[])
|
||||
if(status != LDNS_STATUS_OK)
|
||||
fatal_exit("Could not parse salt %s: %s", argv[5],
|
||||
ldns_get_errorstr_by_id(status));
|
||||
log_assert(argc == 6);
|
||||
assert(argc == 6);
|
||||
while(fgets(line, (int)sizeof(line), stdin)) {
|
||||
if(strlen(line) > 0)
|
||||
line[strlen(line)-1] = 0; /* remove trailing newline */
|
||||
@@ -237,7 +272,6 @@ process_nsec3(int argc, char* argv[])
|
||||
/** main program */
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
log_init(NULL, 0, NULL);
|
||||
if(argc != 6) {
|
||||
usage();
|
||||
}
|
||||
|
||||
+20
-19
@@ -43,7 +43,6 @@
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
#include <ldns/ldns.h>
|
||||
#include <signal.h>
|
||||
#include "util/locks.h"
|
||||
#include "util/log.h"
|
||||
@@ -52,6 +51,11 @@
|
||||
#include "util/data/msgparse.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "ldns/sbuffer.h"
|
||||
#include "ldns/str2wire.h"
|
||||
#include "ldns/wire2str.h"
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#ifndef PF_INET6
|
||||
@@ -112,18 +116,13 @@ write_q(int fd, int udp, SSL* ssl, ldns_buffer* buf, uint16_t id,
|
||||
const char* strname, const char* strtype, const char* strclass)
|
||||
{
|
||||
struct query_info qinfo;
|
||||
ldns_rdf* rdf;
|
||||
uint16_t len;
|
||||
/* qname */
|
||||
rdf = ldns_dname_new_frm_str(strname);
|
||||
if(!rdf) {
|
||||
qinfo.qname = ldns_str2wire_dname(strname, &qinfo.qname_len);
|
||||
if(!qinfo.qname) {
|
||||
printf("cannot parse query name: '%s'\n", strname);
|
||||
exit(1);
|
||||
}
|
||||
qinfo.qname = memdup(ldns_rdf_data(rdf), ldns_rdf_size(rdf));
|
||||
if(!qinfo.qname) fatal_exit("out of memory");
|
||||
(void)dname_count_size_labels(qinfo.qname, &qinfo.qname_len);
|
||||
ldns_rdf_deep_free(rdf);
|
||||
|
||||
/* qtype and qclass */
|
||||
qinfo.qtype = ldns_get_rr_type_by_name(strtype);
|
||||
@@ -192,9 +191,8 @@ write_q(int fd, int udp, SSL* ssl, ldns_buffer* buf, uint16_t id,
|
||||
static void
|
||||
recv_one(int fd, int udp, SSL* ssl, ldns_buffer* buf)
|
||||
{
|
||||
char* pktstr;
|
||||
uint16_t len;
|
||||
ldns_pkt* pkt;
|
||||
ldns_status status;
|
||||
if(!udp) {
|
||||
if(ssl) {
|
||||
if(SSL_read(ssl, (void*)&len, (int)sizeof(len)) <= 0) {
|
||||
@@ -256,15 +254,18 @@ recv_one(int fd, int udp, SSL* ssl, ldns_buffer* buf)
|
||||
printf("\nnext received packet\n");
|
||||
log_buf(0, "data", buf);
|
||||
|
||||
status = ldns_wire2pkt(&pkt, ldns_buffer_begin(buf), len);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
printf("could not parse incoming packet: %s\n",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
log_buf(0, "data was", buf);
|
||||
exit(1);
|
||||
pktstr = ldns_wire2str_pkt(ldns_buffer_begin(buf), len);
|
||||
printf("%s", pktstr);
|
||||
free(pktstr);
|
||||
}
|
||||
|
||||
static int get_random(void)
|
||||
{
|
||||
int r;
|
||||
if (RAND_bytes((unsigned char*)&r, (int)sizeof(r)) == 1) {
|
||||
return r;
|
||||
}
|
||||
ldns_pkt_print(stdout, pkt);
|
||||
ldns_pkt_free(pkt);
|
||||
return (int)random();
|
||||
}
|
||||
|
||||
/** send the TCP queries and print answers */
|
||||
@@ -305,7 +306,7 @@ send_em(const char* svr, int udp, int usessl, int noanswer, int num, char** qs)
|
||||
}
|
||||
for(i=0; i<num; i+=3) {
|
||||
printf("\nNext query is %s %s %s\n", qs[i], qs[i+1], qs[i+2]);
|
||||
write_q(fd, udp, ssl, buf, ldns_get_random(), qs[i],
|
||||
write_q(fd, udp, ssl, buf, (uint16_t)get_random(), qs[i],
|
||||
qs[i+1], qs[i+2]);
|
||||
/* print at least one result */
|
||||
if(!noanswer)
|
||||
|
||||
@@ -39,11 +39,13 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "testcode/ldns-testpkts.h"
|
||||
#include "testcode/testpkts.h"
|
||||
#include "testcode/replay.h"
|
||||
#include "testcode/fake_event.h"
|
||||
#include "daemon/remote.h"
|
||||
#include "util/config_file.h"
|
||||
#include "ldns/keyraw.h"
|
||||
#include <ctype.h>
|
||||
|
||||
/** signal that this is a testbound compile */
|
||||
#define unbound_testbound 1
|
||||
|
||||
+1427
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* ldns-testpkts. Data file parse for test packets, and query matching.
|
||||
* testpkts. Data file parse for test packets, and query matching.
|
||||
*
|
||||
* Data storage for specially crafted replies for testing purposes.
|
||||
*
|
||||
@@ -7,8 +7,10 @@
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#ifndef LDNS_TESTPKTS_H
|
||||
#define LDNS_TESTPKTS_H
|
||||
#ifndef TESTPKTS_H
|
||||
#define TESTPKTS_H
|
||||
struct ldns_buffer;
|
||||
struct ldns_file_parse_state;
|
||||
|
||||
/**
|
||||
* \file
|
||||
@@ -131,8 +133,6 @@ ENTRY_END
|
||||
void verbose(int level, char* format, ...); output function.
|
||||
*/
|
||||
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
/** Type of transport, since some entries match based on UDP or TCP of query */
|
||||
enum transport_type {transport_any = 0, transport_udp, transport_tcp };
|
||||
|
||||
@@ -141,9 +141,11 @@ struct reply_packet {
|
||||
/** next in list of reply packets, for TCP multiple pkts on wire */
|
||||
struct reply_packet* next;
|
||||
/** the reply pkt */
|
||||
ldns_pkt* reply;
|
||||
uint8_t* reply_pkt;
|
||||
/** length of reply pkt */
|
||||
size_t reply_len;
|
||||
/** or reply pkt in hex if not parsable */
|
||||
ldns_buffer* reply_from_hex;
|
||||
struct ldns_buffer* reply_from_hex;
|
||||
/** seconds to sleep before giving packet */
|
||||
unsigned int packet_sleep;
|
||||
};
|
||||
@@ -154,23 +156,23 @@ struct entry {
|
||||
/* match */
|
||||
/* How to match an incoming query with this canned reply */
|
||||
/** match query opcode with answer opcode */
|
||||
bool match_opcode;
|
||||
uint8_t match_opcode;
|
||||
/** match qtype with answer qtype */
|
||||
bool match_qtype;
|
||||
uint8_t match_qtype;
|
||||
/** match qname with answer qname */
|
||||
bool match_qname;
|
||||
uint8_t match_qname;
|
||||
/** match qname as subdomain of answer qname */
|
||||
bool match_subdomain;
|
||||
uint8_t match_subdomain;
|
||||
/** match SOA serial number, from auth section */
|
||||
bool match_serial;
|
||||
uint8_t match_serial;
|
||||
/** match all of the packet */
|
||||
bool match_all;
|
||||
uint8_t match_all;
|
||||
/** match ttls in the packet */
|
||||
bool match_ttl;
|
||||
uint8_t match_ttl;
|
||||
/** match DO bit */
|
||||
bool match_do;
|
||||
uint8_t match_do;
|
||||
/** match absence of EDNS OPT record in query */
|
||||
bool match_noedns;
|
||||
uint8_t match_noedns;
|
||||
/** match query serial with this value. */
|
||||
uint32_t ixfr_soa_serial;
|
||||
/** match on UDP/TCP */
|
||||
@@ -181,9 +183,9 @@ struct entry {
|
||||
|
||||
/** how to adjust the reply packet */
|
||||
/** copy over the ID from the query into the answer */
|
||||
bool copy_id;
|
||||
uint8_t copy_id;
|
||||
/** copy the query nametypeclass from query into the answer */
|
||||
bool copy_query;
|
||||
uint8_t copy_query;
|
||||
/** in seconds */
|
||||
unsigned int sleeptime;
|
||||
|
||||
@@ -211,32 +213,39 @@ void delete_entry(struct entry* list);
|
||||
* Read one entry from the data file.
|
||||
* @param in: file to read from. Filepos must be at the start of a new line.
|
||||
* @param name: name of the file for prettier errors.
|
||||
* @param lineno: line number in file, incremented as lines are read.
|
||||
* for prettier errors.
|
||||
* @param default_ttl: on first call set to default TTL for entries,
|
||||
* later it stores the $TTL value last seen. Try 3600 first call.
|
||||
* @param origin: domain name for origin appending. Can be &NULL on first call.
|
||||
* later it stores the $ORIGIN value last seen. Often &NULL or the zone
|
||||
* name on first call.
|
||||
* @param prev_rr: previous rr name for correcter parsing. &NULL on first call.
|
||||
* @param pstate: file parse state with lineno, default_ttl,
|
||||
* oirigin and prev_rr name.
|
||||
* @param skip_whitespace: skip leftside whitespace.
|
||||
* @return: The entry read (malloced) or NULL if no entry could be read.
|
||||
*/
|
||||
struct entry* read_entry(FILE* in, const char* name, int *lineno,
|
||||
uint32_t* default_ttl, ldns_rdf** origin, ldns_rdf** prev_rr,
|
||||
int skip_whitespace);
|
||||
struct entry* read_entry(FILE* in, const char* name,
|
||||
struct ldns_file_parse_state* pstate, int skip_whitespace);
|
||||
|
||||
/**
|
||||
* finds entry in list, or returns NULL.
|
||||
*/
|
||||
struct entry* find_match(struct entry* entries, ldns_pkt* query_pkt,
|
||||
enum transport_type transport);
|
||||
struct entry* find_match(struct entry* entries, uint8_t* query_pkt,
|
||||
size_t query_pkt_len, enum transport_type transport);
|
||||
|
||||
/**
|
||||
* copy & adjust packet
|
||||
* match two packets, all must match
|
||||
* @param q: packet 1
|
||||
* @param qlen: length of q.
|
||||
* @param p: packet 2
|
||||
* @param plen: length of p.
|
||||
* @param mttl: if true, ttls must match, if false, ttls do not need to match
|
||||
* @param noloc: if true, rrs may be reordered in their packet-section.
|
||||
* rrs are then matches without location of the rr being important.
|
||||
* @return true if matched.
|
||||
*/
|
||||
void adjust_packet(struct entry* match, ldns_pkt* answer_pkt,
|
||||
ldns_pkt* query_pkt);
|
||||
int match_all(uint8_t* q, size_t qlen, uint8_t* p, size_t plen, int mttl,
|
||||
int noloc);
|
||||
|
||||
/**
|
||||
* copy & adjust packet, mallocs a copy.
|
||||
*/
|
||||
void adjust_packet(struct entry* match, uint8_t** answer_pkt,
|
||||
size_t* answer_pkt_len, uint8_t* query_pkt, size_t query_pkt_len);
|
||||
|
||||
/**
|
||||
* Parses data buffer to a query, finds the correct answer
|
||||
@@ -256,4 +265,4 @@ void handle_query(uint8_t* inbuf, ssize_t inlen, struct entry* entries,
|
||||
void (*sendfunc)(uint8_t*, size_t, void*), void* userdata,
|
||||
FILE* verbose_out);
|
||||
|
||||
#endif /* LDNS_TESTPKTS_H */
|
||||
#endif /* TESTPKTS_H */
|
||||
@@ -39,11 +39,12 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <ldns/rr.h>
|
||||
#include "util/log.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "testcode/unitmain.h"
|
||||
#include "validator/val_anchor.h"
|
||||
#include "ldns/sbuffer.h"
|
||||
#include "ldns/rrdef.h"
|
||||
|
||||
/** test empty set */
|
||||
static void
|
||||
|
||||
@@ -39,25 +39,24 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <ldns/dname.h>
|
||||
#include <ldns/host2wire.h>
|
||||
#include "util/log.h"
|
||||
#include "testcode/unitmain.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "ldns/sbuffer.h"
|
||||
#include "ldns/str2wire.h"
|
||||
|
||||
/** put dname into buffer */
|
||||
static ldns_buffer*
|
||||
dname_to_buf(ldns_buffer* b, const char* str)
|
||||
{
|
||||
ldns_rdf* rdf;
|
||||
ldns_status status;
|
||||
int e;
|
||||
size_t len = ldns_buffer_capacity(b);
|
||||
ldns_buffer_clear(b);
|
||||
rdf = ldns_dname_new_frm_str(str);
|
||||
status = ldns_dname2buffer_wire(b, rdf);
|
||||
if(status != LDNS_STATUS_OK)
|
||||
e = ldns_str2wire_dname_buf(str, ldns_buffer_begin(b), &len);
|
||||
if(e != 0)
|
||||
fatal_exit("%s ldns: %s", __func__,
|
||||
ldns_get_errorstr_by_id(status));
|
||||
ldns_rdf_deep_free(rdf);
|
||||
ldns_get_errorstr_parse(e));
|
||||
ldns_buffer_set_position(b, len);
|
||||
ldns_buffer_flip(b);
|
||||
return b;
|
||||
}
|
||||
|
||||
+2
-1
@@ -61,7 +61,8 @@
|
||||
#include "nss.h"
|
||||
#endif
|
||||
|
||||
#include <ldns/ldns.h>
|
||||
#include "ldns/rrdef.h"
|
||||
#include "ldns/keyraw.h"
|
||||
#include "util/log.h"
|
||||
#include "testcode/unitmain.h"
|
||||
|
||||
|
||||
+64
-149
@@ -39,7 +39,7 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <ldns/ldns.h>
|
||||
#include <sys/time.h>
|
||||
#include "util/log.h"
|
||||
#include "testcode/unitmain.h"
|
||||
#include "util/data/msgparse.h"
|
||||
@@ -50,6 +50,10 @@
|
||||
#include "util/regional.h"
|
||||
#include "util/net_help.h"
|
||||
#include "testcode/readhex.h"
|
||||
#include "testcode/testpkts.h"
|
||||
#include "ldns/sbuffer.h"
|
||||
#include "ldns/str2wire.h"
|
||||
#include "ldns/wire2str.h"
|
||||
|
||||
/** verbose message parse unit test */
|
||||
static int vbmp = 0;
|
||||
@@ -62,122 +66,10 @@ static int check_rrsigs = 0;
|
||||
/** do not check buffer sameness */
|
||||
static int check_nosameness = 0;
|
||||
|
||||
/** match two rr lists */
|
||||
static int
|
||||
match_list(ldns_rr_list* q, ldns_rr_list *p)
|
||||
{
|
||||
size_t i;
|
||||
if(ldns_rr_list_rr_count(q) != ldns_rr_list_rr_count(p)) {
|
||||
verbose(3, "rrlistcount different %d %d",
|
||||
(int)ldns_rr_list_rr_count(q),
|
||||
(int)ldns_rr_list_rr_count(p));
|
||||
return 0;
|
||||
}
|
||||
for(i=0; i<ldns_rr_list_rr_count(q); i++)
|
||||
{
|
||||
if(matches_nolocation) {
|
||||
if(!ldns_rr_list_contains_rr(p, ldns_rr_list_rr(q, i)))
|
||||
{
|
||||
verbose(3, "rr %u not found", (unsigned)i);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if(ldns_rr_compare(ldns_rr_list_rr(q, i),
|
||||
ldns_rr_list_rr(p, i)) != 0) {
|
||||
verbose(3, "rr %u different", (unsigned)i);
|
||||
return 0;
|
||||
}
|
||||
/* and check the ttl */
|
||||
if(ldns_rr_ttl(ldns_rr_list_rr(q, i)) !=
|
||||
ldns_rr_ttl(ldns_rr_list_rr(p, i))) {
|
||||
verbose(3, "rr %u ttl different", (unsigned)i);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** match edns sections */
|
||||
static int
|
||||
match_edns(ldns_pkt* q, ldns_pkt* p)
|
||||
{
|
||||
if(ldns_pkt_edns_udp_size(q) != ldns_pkt_edns_udp_size(p))
|
||||
return 0;
|
||||
if(ldns_pkt_edns_extended_rcode(q) != ldns_pkt_edns_extended_rcode(p))
|
||||
return 0;
|
||||
if(ldns_pkt_edns_version(q) != ldns_pkt_edns_version(p))
|
||||
return 0;
|
||||
if(ldns_pkt_edns_do(q) != ldns_pkt_edns_do(p))
|
||||
return 0;
|
||||
if(ldns_pkt_edns_z(q) != ldns_pkt_edns_z(p))
|
||||
return 0;
|
||||
if(ldns_rdf_compare(ldns_pkt_edns_data(q), ldns_pkt_edns_data(p)) != 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** compare two booleans */
|
||||
static int
|
||||
cmp_bool(int x, int y)
|
||||
{
|
||||
if(!x && !y) return 0;
|
||||
if(x && y) return 0;
|
||||
if(!x) return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** match all of the packet */
|
||||
static int
|
||||
match_all(ldns_pkt* q, ldns_pkt* p)
|
||||
{
|
||||
if(ldns_pkt_get_opcode(q) != ldns_pkt_get_opcode(p))
|
||||
{ verbose(3, "allmatch: opcode different"); return 0;}
|
||||
if(ldns_pkt_get_rcode(q) != ldns_pkt_get_rcode(p))
|
||||
{ verbose(3, "allmatch: rcode different"); return 0;}
|
||||
if(ldns_pkt_id(q) != ldns_pkt_id(p))
|
||||
{ verbose(3, "allmatch: id different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_qr(q), ldns_pkt_qr(p)) != 0)
|
||||
{ verbose(3, "allmatch: qr different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_aa(q), ldns_pkt_aa(p)) != 0)
|
||||
{ verbose(3, "allmatch: aa different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_tc(q), ldns_pkt_tc(p)) != 0)
|
||||
{ verbose(3, "allmatch: tc different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_rd(q), ldns_pkt_rd(p)) != 0)
|
||||
{ verbose(3, "allmatch: rd different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_cd(q), ldns_pkt_cd(p)) != 0)
|
||||
{ verbose(3, "allmatch: cd different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_ra(q), ldns_pkt_ra(p)) != 0)
|
||||
{ verbose(3, "allmatch: ra different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_ad(q), ldns_pkt_ad(p)) != 0)
|
||||
{ verbose(3, "allmatch: ad different"); return 0;}
|
||||
if(ldns_pkt_qdcount(q) != ldns_pkt_qdcount(p))
|
||||
{ verbose(3, "allmatch: qdcount different"); return 0;}
|
||||
if(ldns_pkt_ancount(q) != ldns_pkt_ancount(p))
|
||||
{ verbose(3, "allmatch: ancount different"); return 0;}
|
||||
if(ldns_pkt_nscount(q) != ldns_pkt_nscount(p))
|
||||
{ verbose(3, "allmatch: nscount different"); return 0;}
|
||||
if(ldns_pkt_arcount(q) != ldns_pkt_arcount(p))
|
||||
{ verbose(3, "allmatch: arcount different"); return 0;}
|
||||
if(!match_list(ldns_pkt_question(q), ldns_pkt_question(p)))
|
||||
{ verbose(3, "allmatch: qd section different"); return 0;}
|
||||
if(!match_list(ldns_pkt_answer(q), ldns_pkt_answer(p)))
|
||||
{ verbose(3, "allmatch: an section different"); return 0;}
|
||||
if(!match_list(ldns_pkt_authority(q), ldns_pkt_authority(p)))
|
||||
{ verbose(3, "allmatch: ns section different"); return 0;}
|
||||
if(!match_list(ldns_pkt_additional(q), ldns_pkt_additional(p)))
|
||||
{ verbose(3, "allmatch: ar section different"); return 0;}
|
||||
if(!match_edns(q, p))
|
||||
{ verbose(3, "edns different."); return 0;}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** see if buffers contain the same packet */
|
||||
static int
|
||||
test_buffers(ldns_buffer* pkt, ldns_buffer* out)
|
||||
{
|
||||
ldns_pkt* p1=0, *p2=0;
|
||||
ldns_status s1, s2;
|
||||
/* check binary same */
|
||||
if(ldns_buffer_limit(pkt) == ldns_buffer_limit(out) &&
|
||||
memcmp(ldns_buffer_begin(pkt), ldns_buffer_begin(out),
|
||||
@@ -210,32 +102,42 @@ test_buffers(ldns_buffer* pkt, ldns_buffer* out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check if it 'means the same' */
|
||||
s1 = ldns_buffer2pkt_wire(&p1, pkt);
|
||||
s2 = ldns_buffer2pkt_wire(&p2, out);
|
||||
if(vbmp) {
|
||||
char* s1, *s2;
|
||||
log_buf(0, "orig in hex", pkt);
|
||||
log_buf(0, "unbound out in hex", out);
|
||||
printf("\npacket from unbound (%d):\n",
|
||||
(int)ldns_buffer_limit(out));
|
||||
ldns_pkt_print(stdout, p2);
|
||||
s1 = ldns_wire2str_pkt(ldns_buffer_begin(out),
|
||||
ldns_buffer_limit(out));
|
||||
printf("%s\n", s1?s1:"null");
|
||||
free(s1);
|
||||
|
||||
printf("\npacket original (%d):\n",
|
||||
(int)ldns_buffer_limit(pkt));
|
||||
ldns_pkt_print(stdout, p1);
|
||||
s2 = ldns_wire2str_pkt(ldns_buffer_begin(pkt),
|
||||
ldns_buffer_limit(pkt));
|
||||
printf("%s\n", s2?s2:"null");
|
||||
free(s2);
|
||||
printf("\n");
|
||||
}
|
||||
if(s1 != s2) {
|
||||
/* oops! */
|
||||
printf("input ldns parse: %s, output ldns parse: %s.\n",
|
||||
ldns_get_errorstr_by_id(s1),
|
||||
ldns_get_errorstr_by_id(s2));
|
||||
unit_assert(0);
|
||||
/* if it had two EDNS sections, skip comparison */
|
||||
if(1) {
|
||||
char* s = ldns_wire2str_pkt(ldns_buffer_begin(pkt),
|
||||
ldns_buffer_limit(pkt));
|
||||
char* e1 = strstr(s, "; EDNS:");
|
||||
if(e1 && strstr(e1+4, "; EDNS:")) {
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
free(s);
|
||||
}
|
||||
/* compare packets */
|
||||
unit_assert(match_all(p1, p2));
|
||||
ldns_pkt_free(p1);
|
||||
ldns_pkt_free(p2);
|
||||
unit_assert(match_all(ldns_buffer_begin(pkt), ldns_buffer_limit(pkt),
|
||||
ldns_buffer_begin(out), ldns_buffer_limit(out), 1,
|
||||
matches_nolocation));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -243,16 +145,20 @@ test_buffers(ldns_buffer* pkt, ldns_buffer* out)
|
||||
static void
|
||||
checkformerr(ldns_buffer* pkt)
|
||||
{
|
||||
ldns_pkt* p;
|
||||
ldns_status status = ldns_buffer2pkt_wire(&p, pkt);
|
||||
if(vbmp) printf("formerr, ldns parse is: %s\n",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
if(status == LDNS_STATUS_OK) {
|
||||
int status = 0;
|
||||
char* s = ldns_wire2str_pkt(ldns_buffer_begin(pkt),
|
||||
ldns_buffer_limit(pkt));
|
||||
if(!s) fatal_exit("out of memory");
|
||||
if(strstr(s, "Error")) status = 1;
|
||||
if(strstr(s, "error")) status = 1;
|
||||
if(status == 0) {
|
||||
printf("Formerr, but ldns gives packet:\n");
|
||||
ldns_pkt_print(stdout, p);
|
||||
printf("%s\n", s);
|
||||
free(s);
|
||||
exit(1);
|
||||
}
|
||||
unit_assert(status != LDNS_STATUS_OK);
|
||||
free(s);
|
||||
unit_assert(status != 0);
|
||||
}
|
||||
|
||||
/** performance test message encoding */
|
||||
@@ -311,8 +217,9 @@ perftestpkt(ldns_buffer* pkt, struct alloc_cache* alloc, ldns_buffer* out,
|
||||
flags = ntohs(flags);
|
||||
ret = reply_info_parse(pkt, alloc, &qi, &rep, region, &edns);
|
||||
if(ret != 0) {
|
||||
if(vbmp) printf("parse code %d: %s\n", ret,
|
||||
ldns_lookup_by_id(ldns_rcodes, ret)->name);
|
||||
char rbuf[16];
|
||||
ldns_wire2str_rcode_buf(ret, rbuf, sizeof(rbuf));
|
||||
if(vbmp) printf("parse code %d: %s\n", ret, rbuf);
|
||||
if(ret == LDNS_RCODE_FORMERR)
|
||||
checkformerr(pkt);
|
||||
unit_assert(ret != LDNS_RCODE_SERVFAIL);
|
||||
@@ -325,37 +232,44 @@ perftestpkt(ldns_buffer* pkt, struct alloc_cache* alloc, ldns_buffer* out,
|
||||
regional_destroy(region);
|
||||
}
|
||||
|
||||
/** print packed rrset */
|
||||
static void
|
||||
print_rrset(struct ub_packed_rrset_key* rrset)
|
||||
{
|
||||
struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
|
||||
entry.data;
|
||||
char buf[65535];
|
||||
size_t i;
|
||||
for(i=0; i<d->count+d->rrsig_count; i++) {
|
||||
if(!packed_rr_to_string(rrset, i, 0, buf, sizeof(buf)))
|
||||
printf("failedtoconvert %d\n", (int)i);
|
||||
else
|
||||
printf("%s\n", buf);
|
||||
}
|
||||
}
|
||||
|
||||
/** debug print a packet that failed */
|
||||
static void
|
||||
print_packet_rrsets(struct query_info* qinfo, struct reply_info* rep)
|
||||
{
|
||||
size_t i;
|
||||
ldns_rr_list* l;
|
||||
ldns_buffer* buf = ldns_buffer_new(65536);
|
||||
log_query_info(0, "failed query", qinfo);
|
||||
printf(";; ANSWER SECTION (%d rrsets)\n", (int)rep->an_numrrsets);
|
||||
for(i=0; i<rep->an_numrrsets; i++) {
|
||||
l = packed_rrset_to_rr_list(rep->rrsets[i], buf);
|
||||
printf("; rrset %d\n", (int)i);
|
||||
ldns_rr_list_print(stdout, l);
|
||||
ldns_rr_list_deep_free(l);
|
||||
print_rrset(rep->rrsets[i]);
|
||||
}
|
||||
printf(";; AUTHORITY SECTION (%d rrsets)\n", (int)rep->ns_numrrsets);
|
||||
for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) {
|
||||
l = packed_rrset_to_rr_list(rep->rrsets[i], buf);
|
||||
printf("; rrset %d\n", (int)i);
|
||||
ldns_rr_list_print(stdout, l);
|
||||
ldns_rr_list_deep_free(l);
|
||||
print_rrset(rep->rrsets[i]);
|
||||
}
|
||||
printf(";; ADDITIONAL SECTION (%d rrsets)\n", (int)rep->ar_numrrsets);
|
||||
for(i=rep->an_numrrsets+rep->ns_numrrsets; i<rep->rrset_count; i++) {
|
||||
l = packed_rrset_to_rr_list(rep->rrsets[i], buf);
|
||||
printf("; rrset %d\n", (int)i);
|
||||
ldns_rr_list_print(stdout, l);
|
||||
ldns_rr_list_deep_free(l);
|
||||
print_rrset(rep->rrsets[i]);
|
||||
}
|
||||
printf(";; packet end\n");
|
||||
ldns_buffer_free(buf);
|
||||
}
|
||||
|
||||
/** check that there is no data element that matches the RRSIG */
|
||||
@@ -417,8 +331,9 @@ testpkt(ldns_buffer* pkt, struct alloc_cache* alloc, ldns_buffer* out,
|
||||
flags = ntohs(flags);
|
||||
ret = reply_info_parse(pkt, alloc, &qi, &rep, region, &edns);
|
||||
if(ret != 0) {
|
||||
if(vbmp) printf("parse code %d: %s\n", ret,
|
||||
ldns_lookup_by_id(ldns_rcodes, ret)->name);
|
||||
char rbuf[16];
|
||||
ldns_wire2str_rcode_buf(ret, rbuf, sizeof(rbuf));
|
||||
if(vbmp) printf("parse code %d: %s\n", ret, rbuf);
|
||||
if(ret == LDNS_RCODE_FORMERR) {
|
||||
unit_assert(!check_formerr_gone);
|
||||
checkformerr(pkt);
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include "util/data/dname.h"
|
||||
#include "testcode/unitmain.h"
|
||||
#include "validator/val_neg.h"
|
||||
#include "ldns/rrdef.h"
|
||||
|
||||
/** verbose unit test for negative cache */
|
||||
static int negverbose = 0;
|
||||
|
||||
+22
-24
@@ -46,7 +46,7 @@
|
||||
#include "validator/val_nsec.h"
|
||||
#include "validator/val_nsec3.h"
|
||||
#include "validator/validator.h"
|
||||
#include "testcode/ldns-testpkts.h"
|
||||
#include "testcode/testpkts.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/data/msgparse.h"
|
||||
#include "util/data/dname.h"
|
||||
@@ -56,6 +56,10 @@
|
||||
#include "util/net_help.h"
|
||||
#include "util/module.h"
|
||||
#include "util/config_file.h"
|
||||
#include "ldns/sbuffer.h"
|
||||
#include "ldns/keyraw.h"
|
||||
#include "ldns/str2wire.h"
|
||||
#include "ldns/wire2str.h"
|
||||
|
||||
/** verbose signature test */
|
||||
static int vsig = 0;
|
||||
@@ -68,20 +72,10 @@ entry_to_buf(struct entry* e, ldns_buffer* pkt)
|
||||
if(e->reply_list->reply_from_hex) {
|
||||
ldns_buffer_copy(pkt, e->reply_list->reply_from_hex);
|
||||
} else {
|
||||
ldns_status status;
|
||||
size_t answer_size;
|
||||
uint8_t* ans = NULL;
|
||||
status = ldns_pkt2wire(&ans, e->reply_list->reply,
|
||||
&answer_size);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
log_err("could not create reply: %s",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
fatal_exit("error in test");
|
||||
}
|
||||
ldns_buffer_clear(pkt);
|
||||
ldns_buffer_write(pkt, ans, answer_size);
|
||||
ldns_buffer_write(pkt, e->reply_list->reply_pkt,
|
||||
e->reply_list->reply_len);
|
||||
ldns_buffer_flip(pkt);
|
||||
free(ans);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,8 +96,9 @@ entry_to_repinfo(struct entry* e, struct alloc_cache* alloc,
|
||||
ret = reply_info_parse(pkt, alloc, qi, rep, region, &edns);
|
||||
lock_quick_unlock(&alloc->lock);
|
||||
if(ret != 0) {
|
||||
printf("parse code %d: %s\n", ret,
|
||||
ldns_lookup_by_id(ldns_rcodes, ret)->name);
|
||||
char rcode[16];
|
||||
ldns_wire2str_rcode_buf(ret, rcode, sizeof(rcode));
|
||||
printf("parse code %d: %s\n", ret, rcode);
|
||||
unit_assert(ret != 0);
|
||||
}
|
||||
}
|
||||
@@ -216,9 +211,10 @@ verifytest_entry(struct entry* e, struct alloc_cache* alloc,
|
||||
|
||||
regional_free_all(region);
|
||||
if(vsig) {
|
||||
printf("verifying pkt:\n");
|
||||
ldns_pkt_print(stdout, e->reply_list->reply);
|
||||
printf("\n");
|
||||
char* s = ldns_wire2str_pkt(e->reply_list->reply_pkt,
|
||||
e->reply_list->reply_len);
|
||||
printf("verifying pkt:\n%s\n", s?s:"outofmemory");
|
||||
free(s);
|
||||
}
|
||||
entry_to_repinfo(e, alloc, region, pkt, &qinfo, &rep);
|
||||
|
||||
@@ -254,9 +250,10 @@ dstest_entry(struct entry* e, struct alloc_cache* alloc,
|
||||
|
||||
regional_free_all(region);
|
||||
if(vsig) {
|
||||
printf("verifying DS-DNSKEY match:\n");
|
||||
ldns_pkt_print(stdout, e->reply_list->reply);
|
||||
printf("\n");
|
||||
char* s = ldns_wire2str_pkt(e->reply_list->reply_pkt,
|
||||
e->reply_list->reply_len);
|
||||
printf("verifying DS-DNSKEY match:\n%s\n", s?s:"outofmemory");
|
||||
free(s);
|
||||
}
|
||||
entry_to_repinfo(e, alloc, region, pkt, &qinfo, &rep);
|
||||
ds = find_rrset_type(rep, LDNS_RR_TYPE_DS);
|
||||
@@ -427,9 +424,10 @@ nsec3_hash_test_entry(struct entry* e, rbtree_t* ct,
|
||||
uint8_t* qname;
|
||||
|
||||
if(vsig) {
|
||||
printf("verifying NSEC3 hash:\n");
|
||||
ldns_pkt_print(stdout, e->reply_list->reply);
|
||||
printf("\n");
|
||||
char* s = ldns_wire2str_pkt(e->reply_list->reply_pkt,
|
||||
e->reply_list->reply_len);
|
||||
printf("verifying NSEC3 hash:\n%s\n", s?s:"outofmemory");
|
||||
free(s);
|
||||
}
|
||||
entry_to_repinfo(e, alloc, region, buf, &qinfo, &rep);
|
||||
nsec3 = find_rrset_type(rep, LDNS_RR_TYPE_NSEC3);
|
||||
|
||||
Reference in New Issue
Block a user