1 /* 2 * work.c 3 * Where all the hard work is done 4 * (c) 2005 NLnet Labs 5 * 6 * See the file LICENSE for the license 7 * 8 */ 9 10 #include "drill.h" 11 #include <ldns/ldns.h> 12 13 /** 14 * Converts a hex string to binary data 15 * len is the length of the string 16 * buf is the buffer to store the result in 17 * offset is the starting position in the result buffer 18 * 19 * This function returns the length of the result 20 */ 21 static size_t 22 hexstr2bin(char *hexstr, int len, uint8_t *buf, size_t offset, size_t buf_len) 23 { 24 char c; 25 int i; 26 uint8_t int8 = 0; 27 int sec = 0; 28 size_t bufpos = 0; 29 30 if (len % 2 != 0) { 31 return 0; 32 } 33 34 for (i=0; i<len; i++) { 35 c = hexstr[i]; 36 37 /* case insensitive, skip spaces */ 38 if (c != ' ') { 39 if (c >= '0' && c <= '9') { 40 int8 += c & 0x0f; 41 } else if (c >= 'a' && c <= 'z') { 42 int8 += (c & 0x0f) + 9; 43 } else if (c >= 'A' && c <= 'Z') { 44 int8 += (c & 0x0f) + 9; 45 } else { 46 return 0; 47 } 48 49 if (sec == 0) { 50 int8 = int8 << 4; 51 sec = 1; 52 } else { 53 if (bufpos + offset + 1 <= buf_len) { 54 buf[bufpos+offset] = int8; 55 int8 = 0; 56 sec = 0; 57 bufpos++; 58 } else { 59 error("Buffer too small in hexstr2bin"); 60 } 61 } 62 } 63 } 64 return bufpos; 65 } 66 67 static size_t 68 packetbuffromfile(char *filename, uint8_t *wire) 69 { 70 FILE *fp = NULL; 71 int c; 72 73 /* stat hack 74 * 0 = normal 75 * 1 = comment (skip to end of line) 76 * 2 = unprintable character found, read binary data directly 77 */ 78 int state = 0; 79 uint8_t *hexbuf = xmalloc(LDNS_MAX_PACKETLEN); 80 int hexbufpos = 0; 81 size_t wirelen; 82 83 if (strncmp(filename, "-", 2) == 0) { 84 fp = stdin; 85 } else { 86 fp = fopen(filename, "r"); 87 } 88 if (fp == NULL) { 89 perror("Unable to open file for reading"); 90 xfree(hexbuf); 91 return 0; 92 } 93 94 /*verbose("Opened %s\n", filename);*/ 95 96 c = fgetc(fp); 97 while (c != EOF && hexbufpos < LDNS_MAX_PACKETLEN) { 98 if (state < 2 && !isascii(c)) { 99 /*verbose("non ascii character found in file: (%d) switching to raw mode\n", c);*/ 100 state = 2; 101 } 102 switch (state) { 103 case 0: 104 if ( (c >= '0' && c <= '9') || 105 (c >= 'a' && c <= 'f') || 106 (c >= 'A' && c <= 'F') ) 107 { 108 hexbuf[hexbufpos] = (uint8_t) c; 109 hexbufpos++; 110 } else if (c == ';') { 111 state = 1; 112 } else if (c == ' ' || c == '\t' || c == '\n') { 113 /* skip whitespace */ 114 } 115 break; 116 case 1: 117 if (c == '\n' || c == EOF) { 118 state = 0; 119 } 120 break; 121 case 2: 122 hexbuf[hexbufpos] = (uint8_t) c; 123 hexbufpos++; 124 break; 125 } 126 c = fgetc(fp); 127 } 128 129 if (c == EOF) { 130 /* 131 if (have_drill_opt && drill_opt->verbose) { 132 verbose("END OF FILE REACHED\n"); 133 if (state < 2) { 134 verbose("read:\n"); 135 verbose("%s\n", hexbuf); 136 } else { 137 verbose("Not printing wire because it contains non ascii data\n"); 138 } 139 } 140 */ 141 } 142 if (hexbufpos >= LDNS_MAX_PACKETLEN) { 143 /*verbose("packet size reached\n");*/ 144 } 145 146 /* lenient mode: length must be multiple of 2 */ 147 if (hexbufpos % 2 != 0) { 148 hexbuf[hexbufpos] = (uint8_t) '0'; 149 hexbufpos++; 150 } 151 152 if (state < 2) { 153 wirelen = hexstr2bin((char *) hexbuf, 154 hexbufpos, 155 wire, 156 0, 157 LDNS_MAX_PACKETLEN); 158 } else { 159 memcpy(wire, hexbuf, (size_t) hexbufpos); 160 wirelen = (size_t) hexbufpos; 161 } 162 if (fp != stdin) { 163 fclose(fp); 164 } 165 xfree(hexbuf); 166 return wirelen; 167 } 168 169 ldns_buffer * 170 read_hex_buffer(char *filename) 171 { 172 uint8_t *wire; 173 size_t wiresize; 174 ldns_buffer *result_buffer = NULL; 175 176 177 wire = xmalloc(LDNS_MAX_PACKETLEN); 178 179 wiresize = packetbuffromfile(filename, wire); 180 181 result_buffer = LDNS_MALLOC(ldns_buffer); 182 ldns_buffer_new_frm_data(result_buffer, wire, wiresize); 183 ldns_buffer_set_position(result_buffer, ldns_buffer_capacity(result_buffer)); 184 xfree(wire); 185 186 return result_buffer; 187 } 188 189 ldns_pkt * 190 read_hex_pkt(char *filename) 191 { 192 uint8_t *wire; 193 size_t wiresize; 194 195 ldns_pkt *pkt = NULL; 196 197 ldns_status status = LDNS_STATUS_ERR; 198 199 wire = xmalloc(LDNS_MAX_PACKETLEN); 200 201 wiresize = packetbuffromfile(filename, wire); 202 203 if (wiresize > 0) { 204 status = ldns_wire2pkt(&pkt, wire, wiresize); 205 } 206 207 xfree(wire); 208 209 if (status == LDNS_STATUS_OK) { 210 return pkt; 211 } else { 212 fprintf(stderr, "Error parsing hex file: %s\n", 213 ldns_get_errorstr_by_id(status)); 214 return NULL; 215 } 216 } 217 218 void 219 dump_hex(const ldns_pkt *pkt, const char *filename) 220 { 221 uint8_t *wire = NULL; 222 size_t size, i; 223 FILE *fp; 224 ldns_status status; 225 226 fp = fopen(filename, "w"); 227 228 if (fp == NULL) { 229 error("Unable to open %s for writing", filename); 230 return; 231 } 232 233 status = ldns_pkt2wire(&wire, pkt, &size); 234 235 if (status != LDNS_STATUS_OK) { 236 error("Unable to convert packet: error code %u", status); 237 LDNS_FREE(wire); 238 fclose(fp); 239 return; 240 } 241 242 fprintf(fp, "; 0"); 243 for (i = 1; i < 20; i++) { 244 fprintf(fp, " %2u", (unsigned int) i); 245 } 246 fprintf(fp, "\n"); 247 fprintf(fp, ";--"); 248 for (i = 1; i < 20; i++) { 249 fprintf(fp, " --"); 250 } 251 fprintf(fp, "\n"); 252 for (i = 0; i < size; i++) { 253 if (i % 20 == 0 && i > 0) { 254 fprintf(fp, "\t;\t%4u-%4u\n", (unsigned int) i-19, (unsigned int) i); 255 } 256 fprintf(fp, " %02x", (unsigned int)wire[i]); 257 } 258 fprintf(fp, "\n"); 259 fclose(fp); 260 LDNS_FREE(wire); 261 } 262