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