aboutsummaryrefslogtreecommitdiff
path: root/testcode/ldns-testpkts.c
diff options
context:
space:
mode:
Diffstat (limited to 'testcode/ldns-testpkts.c')
-rw-r--r--testcode/ldns-testpkts.c898
1 files changed, 0 insertions, 898 deletions
diff --git a/testcode/ldns-testpkts.c b/testcode/ldns-testpkts.c
deleted file mode 100644
index be94eb2fe438..000000000000
--- a/testcode/ldns-testpkts.c
+++ /dev/null
@@ -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;
- }
-}