1238104Sdes/* 2238104Sdes * work.c 3238104Sdes * Where all the hard work is done 4238104Sdes * (c) 2005 NLnet Labs 5238104Sdes * 6238104Sdes * See the file LICENSE for the license 7238104Sdes * 8238104Sdes */ 9238104Sdes 10238104Sdes#include "drill.h" 11238104Sdes#include <ldns/ldns.h> 12238104Sdes 13238104Sdes/** 14238104Sdes * Converts a hex string to binary data 15238104Sdes * len is the length of the string 16238104Sdes * buf is the buffer to store the result in 17238104Sdes * offset is the starting position in the result buffer 18238104Sdes * 19238104Sdes * This function returns the length of the result 20238104Sdes */ 21238104Sdessize_t 22238104Sdeshexstr2bin(char *hexstr, int len, uint8_t *buf, size_t offset, size_t buf_len) 23238104Sdes{ 24238104Sdes char c; 25238104Sdes int i; 26238104Sdes uint8_t int8 = 0; 27238104Sdes int sec = 0; 28238104Sdes size_t bufpos = 0; 29238104Sdes 30238104Sdes if (len % 2 != 0) { 31238104Sdes return 0; 32238104Sdes } 33238104Sdes 34238104Sdes for (i=0; i<len; i++) { 35238104Sdes c = hexstr[i]; 36238104Sdes 37238104Sdes /* case insensitive, skip spaces */ 38238104Sdes if (c != ' ') { 39238104Sdes if (c >= '0' && c <= '9') { 40238104Sdes int8 += c & 0x0f; 41238104Sdes } else if (c >= 'a' && c <= 'z') { 42238104Sdes int8 += (c & 0x0f) + 9; 43238104Sdes } else if (c >= 'A' && c <= 'Z') { 44238104Sdes int8 += (c & 0x0f) + 9; 45238104Sdes } else { 46238104Sdes return 0; 47238104Sdes } 48238104Sdes 49238104Sdes if (sec == 0) { 50238104Sdes int8 = int8 << 4; 51238104Sdes sec = 1; 52238104Sdes } else { 53238104Sdes if (bufpos + offset + 1 <= buf_len) { 54238104Sdes buf[bufpos+offset] = int8; 55238104Sdes int8 = 0; 56238104Sdes sec = 0; 57238104Sdes bufpos++; 58238104Sdes } else { 59238104Sdes error("Buffer too small in hexstr2bin"); 60238104Sdes } 61238104Sdes } 62238104Sdes } 63238104Sdes } 64238104Sdes return bufpos; 65238104Sdes} 66238104Sdes 67238104Sdessize_t 68238104Sdespacketbuffromfile(char *filename, uint8_t *wire) 69238104Sdes{ 70238104Sdes FILE *fp = NULL; 71238104Sdes int c; 72238104Sdes 73238104Sdes /* stat hack 74238104Sdes * 0 = normal 75238104Sdes * 1 = comment (skip to end of line) 76238104Sdes * 2 = unprintable character found, read binary data directly 77238104Sdes */ 78238104Sdes int state = 0; 79238104Sdes uint8_t *hexbuf = xmalloc(LDNS_MAX_PACKETLEN); 80238104Sdes int hexbufpos = 0; 81238104Sdes size_t wirelen; 82238104Sdes 83238104Sdes if (strncmp(filename, "-", 2) == 0) { 84238104Sdes fp = stdin; 85238104Sdes } else { 86238104Sdes fp = fopen(filename, "r"); 87238104Sdes } 88238104Sdes if (fp == NULL) { 89238104Sdes perror("Unable to open file for reading"); 90238104Sdes xfree(hexbuf); 91238104Sdes return 0; 92238104Sdes } 93238104Sdes 94238104Sdes /*verbose("Opened %s\n", filename);*/ 95238104Sdes 96238104Sdes c = fgetc(fp); 97238104Sdes while (c != EOF && hexbufpos < LDNS_MAX_PACKETLEN) { 98238104Sdes if (state < 2 && !isascii(c)) { 99238104Sdes /*verbose("non ascii character found in file: (%d) switching to raw mode\n", c);*/ 100238104Sdes state = 2; 101238104Sdes } 102238104Sdes switch (state) { 103238104Sdes case 0: 104238104Sdes if ( (c >= '0' && c <= '9') || 105238104Sdes (c >= 'a' && c <= 'f') || 106238104Sdes (c >= 'A' && c <= 'F') ) 107238104Sdes { 108238104Sdes hexbuf[hexbufpos] = (uint8_t) c; 109238104Sdes hexbufpos++; 110238104Sdes } else if (c == ';') { 111238104Sdes state = 1; 112238104Sdes } else if (c == ' ' || c == '\t' || c == '\n') { 113238104Sdes /* skip whitespace */ 114238104Sdes } 115238104Sdes break; 116238104Sdes case 1: 117238104Sdes if (c == '\n' || c == EOF) { 118238104Sdes state = 0; 119238104Sdes } 120238104Sdes break; 121238104Sdes case 2: 122238104Sdes hexbuf[hexbufpos] = (uint8_t) c; 123238104Sdes hexbufpos++; 124238104Sdes break; 125238104Sdes } 126238104Sdes c = fgetc(fp); 127238104Sdes } 128238104Sdes 129238104Sdes if (c == EOF) { 130238104Sdes /* 131238104Sdes if (have_drill_opt && drill_opt->verbose) { 132238104Sdes verbose("END OF FILE REACHED\n"); 133238104Sdes if (state < 2) { 134238104Sdes verbose("read:\n"); 135238104Sdes verbose("%s\n", hexbuf); 136238104Sdes } else { 137238104Sdes verbose("Not printing wire because it contains non ascii data\n"); 138238104Sdes } 139238104Sdes } 140238104Sdes */ 141238104Sdes } 142238104Sdes if (hexbufpos >= LDNS_MAX_PACKETLEN) { 143238104Sdes /*verbose("packet size reached\n");*/ 144238104Sdes } 145238104Sdes 146238104Sdes /* lenient mode: length must be multiple of 2 */ 147238104Sdes if (hexbufpos % 2 != 0) { 148238104Sdes hexbuf[hexbufpos] = (uint8_t) '0'; 149238104Sdes hexbufpos++; 150238104Sdes } 151238104Sdes 152238104Sdes if (state < 2) { 153238104Sdes wirelen = hexstr2bin((char *) hexbuf, 154238104Sdes hexbufpos, 155238104Sdes wire, 156238104Sdes 0, 157238104Sdes LDNS_MAX_PACKETLEN); 158238104Sdes } else { 159238104Sdes memcpy(wire, hexbuf, (size_t) hexbufpos); 160238104Sdes wirelen = (size_t) hexbufpos; 161238104Sdes } 162238104Sdes if (fp != stdin) { 163238104Sdes fclose(fp); 164238104Sdes } 165238104Sdes xfree(hexbuf); 166238104Sdes return wirelen; 167238104Sdes} 168238104Sdes 169238104Sdesldns_buffer * 170238104Sdesread_hex_buffer(char *filename) 171238104Sdes{ 172238104Sdes uint8_t *wire; 173238104Sdes size_t wiresize; 174238104Sdes ldns_buffer *result_buffer = NULL; 175238104Sdes 176246854Sdes 177238104Sdes wire = xmalloc(LDNS_MAX_PACKETLEN); 178238104Sdes 179238104Sdes wiresize = packetbuffromfile(filename, wire); 180238104Sdes 181238104Sdes result_buffer = LDNS_MALLOC(ldns_buffer); 182238104Sdes ldns_buffer_new_frm_data(result_buffer, wire, wiresize); 183238104Sdes ldns_buffer_set_position(result_buffer, ldns_buffer_capacity(result_buffer)); 184238104Sdes xfree(wire); 185246854Sdes 186238104Sdes return result_buffer; 187238104Sdes} 188238104Sdes 189238104Sdesldns_pkt * 190238104Sdesread_hex_pkt(char *filename) 191238104Sdes{ 192238104Sdes uint8_t *wire; 193238104Sdes size_t wiresize; 194238104Sdes 195238104Sdes ldns_pkt *pkt = NULL; 196238104Sdes 197238104Sdes ldns_status status = LDNS_STATUS_ERR; 198238104Sdes 199238104Sdes wire = xmalloc(LDNS_MAX_PACKETLEN); 200238104Sdes 201238104Sdes wiresize = packetbuffromfile(filename, wire); 202238104Sdes 203238104Sdes if (wiresize > 0) { 204238104Sdes status = ldns_wire2pkt(&pkt, wire, wiresize); 205238104Sdes } 206238104Sdes 207238104Sdes xfree(wire); 208238104Sdes 209238104Sdes if (status == LDNS_STATUS_OK) { 210238104Sdes return pkt; 211238104Sdes } else { 212238104Sdes fprintf(stderr, "Error parsing hex file: %s\n", 213238104Sdes ldns_get_errorstr_by_id(status)); 214238104Sdes return NULL; 215238104Sdes } 216238104Sdes} 217238104Sdes 218238104Sdesvoid 219238104Sdesdump_hex(const ldns_pkt *pkt, const char *filename) 220238104Sdes{ 221246854Sdes uint8_t *wire = NULL; 222238104Sdes size_t size, i; 223238104Sdes FILE *fp; 224238104Sdes ldns_status status; 225238104Sdes 226238104Sdes fp = fopen(filename, "w"); 227238104Sdes 228238104Sdes if (fp == NULL) { 229238104Sdes error("Unable to open %s for writing", filename); 230238104Sdes return; 231238104Sdes } 232238104Sdes 233238104Sdes status = ldns_pkt2wire(&wire, pkt, &size); 234238104Sdes 235238104Sdes if (status != LDNS_STATUS_OK) { 236238104Sdes error("Unable to convert packet: error code %u", status); 237246854Sdes LDNS_FREE(wire); 238269257Sdes fclose(fp); 239238104Sdes return; 240238104Sdes } 241238104Sdes 242238104Sdes fprintf(fp, "; 0"); 243238104Sdes for (i = 1; i < 20; i++) { 244238104Sdes fprintf(fp, " %2u", (unsigned int) i); 245238104Sdes } 246238104Sdes fprintf(fp, "\n"); 247238104Sdes fprintf(fp, ";--"); 248238104Sdes for (i = 1; i < 20; i++) { 249238104Sdes fprintf(fp, " --"); 250238104Sdes } 251238104Sdes fprintf(fp, "\n"); 252238104Sdes for (i = 0; i < size; i++) { 253238104Sdes if (i % 20 == 0 && i > 0) { 254238104Sdes fprintf(fp, "\t;\t%4u-%4u\n", (unsigned int) i-19, (unsigned int) i); 255238104Sdes } 256238104Sdes fprintf(fp, " %02x", (unsigned int)wire[i]); 257238104Sdes } 258238104Sdes fprintf(fp, "\n"); 259238104Sdes fclose(fp); 260246854Sdes LDNS_FREE(wire); 261238104Sdes} 262