]> git.ipfire.org Git - thirdparty/ldns.git/commitdiff
fixed bug in packet.c
authorJelte Jansen <jeltejan@NLnetLabs.nl>
Mon, 31 Jul 2006 09:09:07 +0000 (09:09 +0000)
committerJelte Jansen <jeltejan@NLnetLabs.nl>
Mon, 31 Jul 2006 09:09:07 +0000 (09:09 +0000)
(unfinished) expansions to pcat-diff, to make it more intelligent

packet.c
pcat/pcat-diff.c
pcat/pcat-print.c
pcat/pcat.c

index 77c1f2a7e772395860089b86056b13a347494fa4..c70124fb16b6bcfda61ef4757299c1113cd8d3d7 100644 (file)
--- 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;
        }
 }
 
index caeb14353e462109b8f4436f008763845d5e8b15..1e7ee2d3dfcdd99aca83c473c7fdf98561b705ce 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <ldns/ldns.h>
 #include <pcap.h>
+#include <errno.h>
 
 #define SEQUENCE 1
 #define QDATA    2
 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<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;
+}
+
+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);
+                       }
                }
        }
 }
index 6dc0bb622f613c4c4bcae43c0eadeb9fb1450f5e..ce903f5219c1e398dc9541faec716eb1652e46fc 100644 (file)
@@ -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 {
index c2c23d2cb2d9441444d07c4e91911a7904138b40..b7aa4b117f4edd895531ea325a669f72b8248907 100644 (file)
@@ -7,7 +7,7 @@
 #include <ldns/ldns.h>
 #include <pcap.h>
 
-#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);
                }
        }