- 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:
Wouter Wijngaards
2013-10-31 15:09:26 +00:00
parent 1a9e620f8c
commit 29e96e86c9
268 changed files with 13955 additions and 5108 deletions
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
-857
View File
@@ -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;
}
-898
View File
@@ -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
View File
@@ -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
View File
@@ -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[])
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)
+3 -1
View File
@@ -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
View File
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 */
+2 -1
View File
@@ -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
+8 -9
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+1
View File
@@ -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
View File
@@ -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);