xref: /dragonfly/contrib/ldns/drill/work.c (revision 92fc8b5c)
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