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
hexstr2bin(char * hexstr,int len,uint8_t * buf,size_t offset,size_t buf_len)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
packetbuffromfile(char * filename,uint8_t * wire)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 *
read_hex_buffer(char * filename)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 *
read_hex_pkt(char * filename)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
dump_hex(const ldns_pkt * pkt,const char * filename)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