From: Jelte Jansen Date: Mon, 31 Jul 2006 09:09:07 +0000 (+0000) Subject: fixed bug in packet.c X-Git-Tag: release-1.2.0~210 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b56a8a7d2d7dcf4ea1ab86e6550bb4ca61e5a65b;p=thirdparty%2Fldns.git fixed bug in packet.c (unfinished) expansions to pcat-diff, to make it more intelligent --- diff --git a/packet.c b/packet.c index 77c1f2a7..c70124fb 100644 --- a/packet.c +++ b/packet.c @@ -232,9 +232,9 @@ void ldns_pkt_set_edns_do(ldns_pkt *packet, bool value) { if (value) { - packet->_edns_z = packet->_edns_z | LDNS_EDNS_MASK_DO_BIT; + packet->_edns_z = packet->_edns_z & LDNS_EDNS_MASK_DO_BIT; } else { - packet->_edns_z = packet->_edns_z | !LDNS_EDNS_MASK_DO_BIT; + packet->_edns_z = packet->_edns_z & !LDNS_EDNS_MASK_DO_BIT; } } diff --git a/pcat/pcat-diff.c b/pcat/pcat-diff.c index caeb1435..1e7ee2d3 100644 --- a/pcat/pcat-diff.c +++ b/pcat/pcat-diff.c @@ -3,6 +3,7 @@ #include #include +#include #define SEQUENCE 1 #define QDATA 2 @@ -14,6 +15,31 @@ ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream); #endif +/* perform advance checking (not just string comparison on the input; + * - sort packet sections + */ +bool advanced = true; + +/* you can either dump the exact original packets as hex, or the + * packet after it has been 'normalized' + */ +bool show_originals = true; + +/* pcat diff can ameliorate its output so that it does not show + * known differences (for example the version.bind answer, but + * there are more advanced ones). It will keep a number of actual + * differences it found and print that, as well as the number of + * known differences and their origin + * + * THIS CHANGES THE PACKET! BE CAREFUL WHEN USING show_originals = false! + */ +bool ameliorate_output = true; +size_t differences = 0; +size_t do_bit = 0; +size_t version = 0; +size_t notimpl_notauth = 0; +size_t notauth_notimpl = 0; + struct dns_info { size_t seq; /* seq number */ @@ -21,6 +47,191 @@ struct dns_info char *adata; /* answer data in hex */ }; +/** + * Converts a hex string to binary data + * len is the length of the string + * buf is the buffer to store the result in + * offset is the starting position in the result buffer + * + * This function returns the length of the result + */ +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= '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; +} + +size_t +packetbuffromfile(char *hexbuf, uint8_t *wire) +{ + int c; + + /* stat hack + * 0 = normal + * 1 = comment (skip to end of line) + * 2 = unprintable character found, read binary data directly + */ + int state = 0; + int hexbufpos = 0; + size_t wirelen; + + while (hexbufpos < strlen(hexbuf) && hexbufpos < LDNS_MAX_PACKETLEN) { + c = hexbuf[hexbufpos]; + 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') ) + { + 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: + hexbuf[hexbufpos] = (uint8_t) c; + hexbufpos++; + break; + default: + fprintf(stderr, "unknown state while reading %s", hexbuf); + return 0; + break; + } + } + + if (c == EOF) { + /* + if (have_drill_opt && drill_opt->verbose) { + verbose("END OF FILE REACHED\n"); + if (state < 2) { + verbose("read:\n"); + verbose("%s\n", hexbuf); + } else { + verbose("Not printing wire because it contains non ascii data\n"); + } + } + */ + } + if (hexbufpos >= LDNS_MAX_PACKETLEN) { + /*verbose("packet size reached\n");*/ + } + + /* lenient mode: length must be multiple of 2 */ + if (hexbufpos % 2 != 0) { + hexbuf[hexbufpos] = (uint8_t) '0'; + hexbufpos++; + } + + if (state < 2) { + wirelen = hexstr2bin((char *) hexbuf, hexbufpos, wire, 0, LDNS_MAX_PACKETLEN); + } else { + memcpy(wire, hexbuf, (size_t) hexbufpos); + wirelen = (size_t) hexbufpos; + } + return wirelen; +} + +ldns_pkt * +read_hex_pkt(char *hex_data) +{ + uint8_t *wire; + size_t wiresize; + ldns_status status = LDNS_STATUS_ERR; + + ldns_pkt *pkt = NULL; + + wire = malloc(LDNS_MAX_PACKETLEN); + + wiresize = packetbuffromfile(hex_data, wire); + + if (wiresize > 0) { + status = ldns_wire2pkt(&pkt, wire, wiresize); + } + + free(wire); + + if (status == LDNS_STATUS_OK) { + return pkt; + } else { + return NULL; + } +} + +bool +dump_hex(FILE *fp, const ldns_pkt *pkt) +{ + uint8_t *wire;// = xmalloc((packet->udppacketsize)*21); + size_t size, i; + ldns_status status; + + status = ldns_pkt2wire(&wire, pkt, &size); + + if (status != LDNS_STATUS_OK) { + fprintf(stdout, "= Unable to convert packet back to wire: error code %u", status); + fprintf(stdout, "= original hex:\n"); + return false; + } + + for (i = 0; i < size; i++) { + fprintf(fp, "%02x", (unsigned int)wire[i]); + } + LDNS_FREE(wire); + return true; +} + + void usage(FILE *fp) { @@ -44,14 +255,137 @@ usage(FILE *fp) void compare(struct dns_info *d1, struct dns_info *d2) { + ldns_pkt *p1, *p2; + bool diff = false; + char *pstr1, *pstr2; + struct timeval now; + + gettimeofday(&now, NULL); + if (strcmp(d1->qdata, d2->qdata) != 0) { fprintf(stderr, "Query differs!\n"); fprintf(stdout, "q: %d:%d\n%s\n%s\n%s\n", (int)d1->seq, (int)d2->seq, d1->qdata, d1->qdata, d2->qdata); } else { if (strcmp(d1->adata, d2->adata) != 0) { - fprintf(stdout, "%d:%d\n%s\n%s\n%s\n", (int)d1->seq, (int)d2->seq, - d1->qdata, d1->adata, d2->adata); + if (advanced) { + /* try to read the packet and sort the sections */ + p1 = read_hex_pkt(d1->adata); + p2 = read_hex_pkt(d2->adata); + if (p1 && p2) { +ldns_pkt_set_timestamp(p1, now); +ldns_pkt_set_timestamp(p2, now); + if (ldns_pkt_qdcount(p1) > 0) { + ldns_rr_list2canonical(ldns_pkt_question(p1)); + ldns_rr_list_sort(ldns_pkt_question(p1)); + } + if (ldns_pkt_ancount(p1) > 0) { + ldns_rr_list2canonical(ldns_pkt_answer(p1)); + ldns_rr_list_sort(ldns_pkt_answer(p1)); + } + if (ldns_pkt_nscount(p1) > 0) { + ldns_rr_list2canonical(ldns_pkt_authority(p1)); + ldns_rr_list_sort(ldns_pkt_authority(p1)); + } + if (ldns_pkt_arcount(p1) > 0) { + ldns_rr_list2canonical(ldns_pkt_additional(p1)); + ldns_rr_list_sort(ldns_pkt_additional(p1)); + } + if (ldns_pkt_qdcount(p2) > 0) { + ldns_rr_list2canonical(ldns_pkt_question(p2)); + ldns_rr_list_sort(ldns_pkt_question(p2)); + } + if (ldns_pkt_ancount(p2) > 0) { + ldns_rr_list2canonical(ldns_pkt_answer(p2)); + ldns_rr_list_sort(ldns_pkt_answer(p2)); + } + if (ldns_pkt_nscount(p2) > 0) { + ldns_rr_list2canonical(ldns_pkt_authority(p2)); + ldns_rr_list_sort(ldns_pkt_authority(p2)); + } + if (ldns_pkt_arcount(p2) > 0) { + ldns_rr_list2canonical(ldns_pkt_additional(p2)); + ldns_rr_list_sort(ldns_pkt_additional(p2)); + } + + if (ameliorate_output) { + /* extended checks */ + if (ldns_pkt_get_rcode(p1) == LDNS_RCODE_NOTIMPL && + ldns_pkt_get_rcode(p2) == LDNS_RCODE_NOTAUTH) { + differences++; + notimpl_notauth++; + ldns_pkt_set_rcode(p1, LDNS_RCODE_NOTAUTH); + } + if (ldns_pkt_get_rcode(p1) == LDNS_RCODE_NOTAUTH && + ldns_pkt_get_rcode(p2) == LDNS_RCODE_NOTIMPL) { + differences++; + notimpl_notauth++; + ldns_pkt_set_rcode(p1, LDNS_RCODE_NOTIMPL); + } + + if (ldns_pkt_edns_do(p1) && + !ldns_pkt_edns_do(p2)) { + differences++; + do_bit++; + ldns_pkt_set_edns_do(p1, false); + } + if (!ldns_pkt_edns_do(p1) && + ldns_pkt_edns_do(p2)) { + differences++; + do_bit++; + ldns_pkt_set_edns_do(p1, true); + } + + } + + /* simply do string comparison */ + pstr1 = ldns_pkt2str(p1); + pstr2 = ldns_pkt2str(p2); + if (strcmp(pstr1, pstr2) != 0) { + diff = true; + } + + if (diff) { + if (show_originals) { + fprintf(stdout, "%d:%d\n%s\n%s\n%s\n", (int)d1->seq, (int)d2->seq, + d1->qdata, d1->adata, d2->adata); + } else { + fprintf(stdout, "%d:%d\n", (int)d1->seq, (int)d2->seq); + if (!dump_hex(stdout, p1)) { + fprintf(stdout, "%s", d1->adata); + } + fprintf(stdout, "\n"); + if (!dump_hex(stdout, p2)) { + fprintf(stdout, "%s", d2->adata); + } + fprintf(stdout, "\n"); + } +/* +ldns_pkt_print(stdout, p1); +ldns_pkt_print(stdout, p2); +*/ +/* +printf(pstr1); +printf(pstr2); +printf("DIFF: %d\n", strcmp(pstr1, pstr2)); +exit(0); +*/ + } + LDNS_FREE(pstr1); + LDNS_FREE(pstr2); + ldns_pkt_free(p1); + ldns_pkt_free(p2); + + } else { + fprintf(stderr, "unable to parse string\n"); + fprintf(stdout, "= unable to parse string\n"); + fprintf(stdout, "%d:%d\n%s\n%s\n%s\n", (int)d1->seq, (int)d2->seq, + d1->qdata, d1->adata, d2->adata); + } + } else { + fprintf(stdout, "%d:%d\n%s\n%s\n%s\n", (int)d1->seq, (int)d2->seq, + d1->qdata, d1->adata, d2->adata); + } } } } diff --git a/pcat/pcat-print.c b/pcat/pcat-print.c index 6dc0bb62..ce903f52 100644 --- a/pcat/pcat-print.c +++ b/pcat/pcat-print.c @@ -44,7 +44,7 @@ main(int argc, char **argv) while((read = getdelim(&line, &len, '\n', diff)) != -1) { if (read < 2 || read > LDNS_MAX_PACKETLEN) { - fprintf(stderr, "Under- or overflow - skipping line %d\n", (int)i); + fprintf(stderr, "Under- or overflow (%u) - skipping line %d\n", read, (int)i); i++; continue; } @@ -67,6 +67,7 @@ main(int argc, char **argv) k++; } s = ldns_wire2pkt(&p, pkt_buf, k); + fprintf(stdout, "=* %s\n", line); if (s != LDNS_STATUS_OK) { fprintf(stderr, "%s\n", ldns_get_errorstr_by_id(s)); } else { diff --git a/pcat/pcat.c b/pcat/pcat.c index c2c23d2c..b7aa4b11 100644 --- a/pcat/pcat.c +++ b/pcat/pcat.c @@ -7,7 +7,7 @@ #include #include -#define FAILURE 100 +#define FAILURE 10000 #ifndef ETHERTYPE_IPV6 @@ -198,7 +198,7 @@ main(int argc, char **argv) ldns_buffer_clear(qpkt); i++; if (failure > FAILURE) { - fprintf(stderr, "More then 100 failures, bailing out\n"); + fprintf(stderr, "More than %u failures, bailing out\n", FAILURE); exit(EXIT_FAILURE); } }