work.c revision 246827
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 */
21size_t
22hexstr2bin(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
67size_t
68packetbuffromfile(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
174ldns_buffer *
175read_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
207ldns_pkt *
208read_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
236void
237dump_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