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 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 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 default: 126 warning("unknown state while reading %s", filename); 127 xfree(hexbuf); 128 return 0; 129 break; 130 } 131 c = fgetc(fp); 132 } 133 134 if (c == EOF) { 135 /* 136 if (have_drill_opt && drill_opt->verbose) { 137 verbose("END OF FILE REACHED\n"); 138 if (state < 2) { 139 verbose("read:\n"); 140 verbose("%s\n", hexbuf); 141 } else { 142 verbose("Not printing wire because it contains non ascii data\n"); 143 } 144 } 145 */ 146 } 147 if (hexbufpos >= LDNS_MAX_PACKETLEN) { 148 /*verbose("packet size reached\n");*/ 149 } 150 151 /* lenient mode: length must be multiple of 2 */ 152 if (hexbufpos % 2 != 0) { 153 hexbuf[hexbufpos] = (uint8_t) '0'; 154 hexbufpos++; 155 } 156 157 if (state < 2) { 158 wirelen = hexstr2bin((char *) hexbuf, 159 hexbufpos, 160 wire, 161 0, 162 LDNS_MAX_PACKETLEN); 163 } else { 164 memcpy(wire, hexbuf, (size_t) hexbufpos); 165 wirelen = (size_t) hexbufpos; 166 } 167 if (fp != stdin) { 168 fclose(fp); 169 } 170 xfree(hexbuf); 171 return wirelen; 172 } 173 174 ldns_buffer * 175 read_hex_buffer(char *filename) 176 { 177 uint8_t *wire; 178 size_t wiresize; 179 ldns_buffer *result_buffer = NULL; 180 181 FILE *fp = NULL; 182 183 if (strncmp(filename, "-", 2) != 0) { 184 fp = fopen(filename, "r"); 185 } else { 186 fp = stdin; 187 } 188 189 if (fp == NULL) { 190 perror(""); 191 warning("Unable to open %s", filename); 192 return NULL; 193 } 194 195 wire = xmalloc(LDNS_MAX_PACKETLEN); 196 197 wiresize = packetbuffromfile(filename, wire); 198 199 result_buffer = LDNS_MALLOC(ldns_buffer); 200 ldns_buffer_new_frm_data(result_buffer, wire, wiresize); 201 ldns_buffer_set_position(result_buffer, ldns_buffer_capacity(result_buffer)); 202 203 xfree(wire); 204 return result_buffer; 205 } 206 207 ldns_pkt * 208 read_hex_pkt(char *filename) 209 { 210 uint8_t *wire; 211 size_t wiresize; 212 213 ldns_pkt *pkt = NULL; 214 215 ldns_status status = LDNS_STATUS_ERR; 216 217 wire = xmalloc(LDNS_MAX_PACKETLEN); 218 219 wiresize = packetbuffromfile(filename, wire); 220 221 if (wiresize > 0) { 222 status = ldns_wire2pkt(&pkt, wire, wiresize); 223 } 224 225 xfree(wire); 226 227 if (status == LDNS_STATUS_OK) { 228 return pkt; 229 } else { 230 fprintf(stderr, "Error parsing hex file: %s\n", 231 ldns_get_errorstr_by_id(status)); 232 return NULL; 233 } 234 } 235 236 void 237 dump_hex(const ldns_pkt *pkt, const char *filename) 238 { 239 uint8_t *wire; 240 size_t size, i; 241 FILE *fp; 242 ldns_status status; 243 244 fp = fopen(filename, "w"); 245 246 if (fp == NULL) { 247 error("Unable to open %s for writing", filename); 248 return; 249 } 250 251 status = ldns_pkt2wire(&wire, pkt, &size); 252 253 if (status != LDNS_STATUS_OK) { 254 error("Unable to convert packet: error code %u", status); 255 return; 256 } 257 258 fprintf(fp, "; 0"); 259 for (i = 1; i < 20; i++) { 260 fprintf(fp, " %2u", (unsigned int) i); 261 } 262 fprintf(fp, "\n"); 263 fprintf(fp, ";--"); 264 for (i = 1; i < 20; i++) { 265 fprintf(fp, " --"); 266 } 267 fprintf(fp, "\n"); 268 for (i = 0; i < size; i++) { 269 if (i % 20 == 0 && i > 0) { 270 fprintf(fp, "\t;\t%4u-%4u\n", (unsigned int) i-19, (unsigned int) i); 271 } 272 fprintf(fp, " %02x", (unsigned int)wire[i]); 273 } 274 fprintf(fp, "\n"); 275 fclose(fp); 276 } 277