xref: /freebsd/contrib/ldns/drill/work.c (revision 986ba33c7a3bc8f5ba13c7a9d6512602f6e32c61)
17b5038d7SDag-Erling Smørgrav /*
27b5038d7SDag-Erling Smørgrav  * work.c
37b5038d7SDag-Erling Smørgrav  * Where all the hard work is done
47b5038d7SDag-Erling Smørgrav  * (c) 2005 NLnet Labs
57b5038d7SDag-Erling Smørgrav  *
67b5038d7SDag-Erling Smørgrav  * See the file LICENSE for the license
77b5038d7SDag-Erling Smørgrav  *
87b5038d7SDag-Erling Smørgrav  */
97b5038d7SDag-Erling Smørgrav 
107b5038d7SDag-Erling Smørgrav #include "drill.h"
117b5038d7SDag-Erling Smørgrav #include <ldns/ldns.h>
127b5038d7SDag-Erling Smørgrav 
137b5038d7SDag-Erling Smørgrav /**
147b5038d7SDag-Erling Smørgrav  * Converts a hex string to binary data
157b5038d7SDag-Erling Smørgrav  * len is the length of the string
167b5038d7SDag-Erling Smørgrav  * buf is the buffer to store the result in
177b5038d7SDag-Erling Smørgrav  * offset is the starting position in the result buffer
187b5038d7SDag-Erling Smørgrav  *
197b5038d7SDag-Erling Smørgrav  * This function returns the length of the result
207b5038d7SDag-Erling Smørgrav  */
21*986ba33cSDag-Erling Smørgrav static size_t
hexstr2bin(char * hexstr,int len,uint8_t * buf,size_t offset,size_t buf_len)227b5038d7SDag-Erling Smørgrav hexstr2bin(char *hexstr, int len, uint8_t *buf, size_t offset, size_t buf_len)
237b5038d7SDag-Erling Smørgrav {
247b5038d7SDag-Erling Smørgrav 	char c;
257b5038d7SDag-Erling Smørgrav 	int i;
267b5038d7SDag-Erling Smørgrav 	uint8_t int8 = 0;
277b5038d7SDag-Erling Smørgrav 	int sec = 0;
287b5038d7SDag-Erling Smørgrav 	size_t bufpos = 0;
297b5038d7SDag-Erling Smørgrav 
307b5038d7SDag-Erling Smørgrav 	if (len % 2 != 0) {
317b5038d7SDag-Erling Smørgrav 		return 0;
327b5038d7SDag-Erling Smørgrav 	}
337b5038d7SDag-Erling Smørgrav 
347b5038d7SDag-Erling Smørgrav 	for (i=0; i<len; i++) {
357b5038d7SDag-Erling Smørgrav 		c = hexstr[i];
367b5038d7SDag-Erling Smørgrav 
377b5038d7SDag-Erling Smørgrav 		/* case insensitive, skip spaces */
387b5038d7SDag-Erling Smørgrav 		if (c != ' ') {
397b5038d7SDag-Erling Smørgrav 			if (c >= '0' && c <= '9') {
407b5038d7SDag-Erling Smørgrav 				int8 += c & 0x0f;
417b5038d7SDag-Erling Smørgrav 			} else if (c >= 'a' && c <= 'z') {
427b5038d7SDag-Erling Smørgrav 				int8 += (c & 0x0f) + 9;
437b5038d7SDag-Erling Smørgrav 			} else if (c >= 'A' && c <= 'Z') {
447b5038d7SDag-Erling Smørgrav 				int8 += (c & 0x0f) + 9;
457b5038d7SDag-Erling Smørgrav 			} else {
467b5038d7SDag-Erling Smørgrav 				return 0;
477b5038d7SDag-Erling Smørgrav 			}
487b5038d7SDag-Erling Smørgrav 
497b5038d7SDag-Erling Smørgrav 			if (sec == 0) {
507b5038d7SDag-Erling Smørgrav 				int8 = int8 << 4;
517b5038d7SDag-Erling Smørgrav 				sec = 1;
527b5038d7SDag-Erling Smørgrav 			} else {
537b5038d7SDag-Erling Smørgrav 				if (bufpos + offset + 1 <= buf_len) {
547b5038d7SDag-Erling Smørgrav 					buf[bufpos+offset] = int8;
557b5038d7SDag-Erling Smørgrav 					int8 = 0;
567b5038d7SDag-Erling Smørgrav 					sec = 0;
577b5038d7SDag-Erling Smørgrav 					bufpos++;
587b5038d7SDag-Erling Smørgrav 				} else {
597b5038d7SDag-Erling Smørgrav 					error("Buffer too small in hexstr2bin");
607b5038d7SDag-Erling Smørgrav 				}
617b5038d7SDag-Erling Smørgrav 			}
627b5038d7SDag-Erling Smørgrav 		}
637b5038d7SDag-Erling Smørgrav         }
647b5038d7SDag-Erling Smørgrav         return bufpos;
657b5038d7SDag-Erling Smørgrav }
667b5038d7SDag-Erling Smørgrav 
67*986ba33cSDag-Erling Smørgrav static size_t
packetbuffromfile(char * filename,uint8_t * wire)687b5038d7SDag-Erling Smørgrav packetbuffromfile(char *filename, uint8_t *wire)
697b5038d7SDag-Erling Smørgrav {
707b5038d7SDag-Erling Smørgrav 	FILE *fp = NULL;
717b5038d7SDag-Erling Smørgrav 	int c;
727b5038d7SDag-Erling Smørgrav 
737b5038d7SDag-Erling Smørgrav 	/* stat hack
747b5038d7SDag-Erling Smørgrav 	 * 0 = normal
757b5038d7SDag-Erling Smørgrav 	 * 1 = comment (skip to end of line)
767b5038d7SDag-Erling Smørgrav 	 * 2 = unprintable character found, read binary data directly
777b5038d7SDag-Erling Smørgrav 	 */
787b5038d7SDag-Erling Smørgrav 	int state = 0;
797b5038d7SDag-Erling Smørgrav 	uint8_t *hexbuf = xmalloc(LDNS_MAX_PACKETLEN);
807b5038d7SDag-Erling Smørgrav 	int hexbufpos = 0;
817b5038d7SDag-Erling Smørgrav 	size_t wirelen;
827b5038d7SDag-Erling Smørgrav 
837b5038d7SDag-Erling Smørgrav 	if (strncmp(filename, "-", 2) == 0) {
847b5038d7SDag-Erling Smørgrav 		fp = stdin;
857b5038d7SDag-Erling Smørgrav 	} else {
867b5038d7SDag-Erling Smørgrav 		fp = fopen(filename, "r");
877b5038d7SDag-Erling Smørgrav 	}
887b5038d7SDag-Erling Smørgrav 	if (fp == NULL) {
897b5038d7SDag-Erling Smørgrav 		perror("Unable to open file for reading");
907b5038d7SDag-Erling Smørgrav 		xfree(hexbuf);
917b5038d7SDag-Erling Smørgrav 		return 0;
927b5038d7SDag-Erling Smørgrav 	}
937b5038d7SDag-Erling Smørgrav 
947b5038d7SDag-Erling Smørgrav 	/*verbose("Opened %s\n", filename);*/
957b5038d7SDag-Erling Smørgrav 
967b5038d7SDag-Erling Smørgrav 	c = fgetc(fp);
977b5038d7SDag-Erling Smørgrav 	while (c != EOF && hexbufpos < LDNS_MAX_PACKETLEN) {
987b5038d7SDag-Erling Smørgrav 		if (state < 2 && !isascii(c)) {
997b5038d7SDag-Erling Smørgrav 			/*verbose("non ascii character found in file: (%d) switching to raw mode\n", c);*/
1007b5038d7SDag-Erling Smørgrav 			state = 2;
1017b5038d7SDag-Erling Smørgrav 		}
1027b5038d7SDag-Erling Smørgrav 		switch (state) {
1037b5038d7SDag-Erling Smørgrav 			case 0:
1047b5038d7SDag-Erling Smørgrav 				if (	(c >= '0' && c <= '9') ||
1057b5038d7SDag-Erling Smørgrav 					(c >= 'a' && c <= 'f') ||
1067b5038d7SDag-Erling Smørgrav 					(c >= 'A' && c <= 'F') )
1077b5038d7SDag-Erling Smørgrav 				{
1087b5038d7SDag-Erling Smørgrav 					hexbuf[hexbufpos] = (uint8_t) c;
1097b5038d7SDag-Erling Smørgrav 					hexbufpos++;
1107b5038d7SDag-Erling Smørgrav 				} else if (c == ';') {
1117b5038d7SDag-Erling Smørgrav 					state = 1;
1127b5038d7SDag-Erling Smørgrav 				} else if (c == ' ' || c == '\t' || c == '\n') {
1137b5038d7SDag-Erling Smørgrav 					/* skip whitespace */
1147b5038d7SDag-Erling Smørgrav 				}
1157b5038d7SDag-Erling Smørgrav 				break;
1167b5038d7SDag-Erling Smørgrav 			case 1:
1177b5038d7SDag-Erling Smørgrav 				if (c == '\n' || c == EOF) {
1187b5038d7SDag-Erling Smørgrav 					state = 0;
1197b5038d7SDag-Erling Smørgrav 				}
1207b5038d7SDag-Erling Smørgrav 				break;
1217b5038d7SDag-Erling Smørgrav 			case 2:
1227b5038d7SDag-Erling Smørgrav 				hexbuf[hexbufpos] = (uint8_t) c;
1237b5038d7SDag-Erling Smørgrav 				hexbufpos++;
1247b5038d7SDag-Erling Smørgrav 				break;
1257b5038d7SDag-Erling Smørgrav 		}
1267b5038d7SDag-Erling Smørgrav 		c = fgetc(fp);
1277b5038d7SDag-Erling Smørgrav 	}
1287b5038d7SDag-Erling Smørgrav 
1297b5038d7SDag-Erling Smørgrav 	if (c == EOF) {
1307b5038d7SDag-Erling Smørgrav 		/*
1317b5038d7SDag-Erling Smørgrav 		if (have_drill_opt && drill_opt->verbose) {
1327b5038d7SDag-Erling Smørgrav 			verbose("END OF FILE REACHED\n");
1337b5038d7SDag-Erling Smørgrav 			if (state < 2) {
1347b5038d7SDag-Erling Smørgrav 				verbose("read:\n");
1357b5038d7SDag-Erling Smørgrav 				verbose("%s\n", hexbuf);
1367b5038d7SDag-Erling Smørgrav 			} else {
1377b5038d7SDag-Erling Smørgrav 				verbose("Not printing wire because it contains non ascii data\n");
1387b5038d7SDag-Erling Smørgrav 			}
1397b5038d7SDag-Erling Smørgrav 		}
1407b5038d7SDag-Erling Smørgrav 		*/
1417b5038d7SDag-Erling Smørgrav 	}
1427b5038d7SDag-Erling Smørgrav 	if (hexbufpos >= LDNS_MAX_PACKETLEN) {
1437b5038d7SDag-Erling Smørgrav 		/*verbose("packet size reached\n");*/
1447b5038d7SDag-Erling Smørgrav 	}
1457b5038d7SDag-Erling Smørgrav 
1467b5038d7SDag-Erling Smørgrav 	/* lenient mode: length must be multiple of 2 */
1477b5038d7SDag-Erling Smørgrav 	if (hexbufpos % 2 != 0) {
1487b5038d7SDag-Erling Smørgrav 		hexbuf[hexbufpos] = (uint8_t) '0';
1497b5038d7SDag-Erling Smørgrav 		hexbufpos++;
1507b5038d7SDag-Erling Smørgrav 	}
1517b5038d7SDag-Erling Smørgrav 
1527b5038d7SDag-Erling Smørgrav 	if (state < 2) {
1537b5038d7SDag-Erling Smørgrav 		wirelen = hexstr2bin((char *) hexbuf,
1547b5038d7SDag-Erling Smørgrav 						 hexbufpos,
1557b5038d7SDag-Erling Smørgrav 						 wire,
1567b5038d7SDag-Erling Smørgrav 						 0,
1577b5038d7SDag-Erling Smørgrav 						 LDNS_MAX_PACKETLEN);
1587b5038d7SDag-Erling Smørgrav 	} else {
1597b5038d7SDag-Erling Smørgrav 		memcpy(wire, hexbuf, (size_t) hexbufpos);
1607b5038d7SDag-Erling Smørgrav 		wirelen = (size_t) hexbufpos;
1617b5038d7SDag-Erling Smørgrav 	}
1627b5038d7SDag-Erling Smørgrav 	if (fp != stdin) {
1637b5038d7SDag-Erling Smørgrav 		fclose(fp);
1647b5038d7SDag-Erling Smørgrav 	}
1657b5038d7SDag-Erling Smørgrav 	xfree(hexbuf);
1667b5038d7SDag-Erling Smørgrav 	return wirelen;
1677b5038d7SDag-Erling Smørgrav }
1687b5038d7SDag-Erling Smørgrav 
1697b5038d7SDag-Erling Smørgrav ldns_buffer *
read_hex_buffer(char * filename)1707b5038d7SDag-Erling Smørgrav read_hex_buffer(char *filename)
1717b5038d7SDag-Erling Smørgrav {
1727b5038d7SDag-Erling Smørgrav 	uint8_t *wire;
1737b5038d7SDag-Erling Smørgrav 	size_t wiresize;
1747b5038d7SDag-Erling Smørgrav 	ldns_buffer *result_buffer = NULL;
1757b5038d7SDag-Erling Smørgrav 
1767b5038d7SDag-Erling Smørgrav 
1777b5038d7SDag-Erling Smørgrav 	wire = xmalloc(LDNS_MAX_PACKETLEN);
1787b5038d7SDag-Erling Smørgrav 
1797b5038d7SDag-Erling Smørgrav 	wiresize = packetbuffromfile(filename, wire);
1807b5038d7SDag-Erling Smørgrav 
1817b5038d7SDag-Erling Smørgrav 	result_buffer = LDNS_MALLOC(ldns_buffer);
1827b5038d7SDag-Erling Smørgrav 	ldns_buffer_new_frm_data(result_buffer, wire, wiresize);
1837b5038d7SDag-Erling Smørgrav 	ldns_buffer_set_position(result_buffer, ldns_buffer_capacity(result_buffer));
1847b5038d7SDag-Erling Smørgrav 	xfree(wire);
1852787e39aSDag-Erling Smørgrav 
1867b5038d7SDag-Erling Smørgrav 	return result_buffer;
1877b5038d7SDag-Erling Smørgrav }
1887b5038d7SDag-Erling Smørgrav 
1897b5038d7SDag-Erling Smørgrav ldns_pkt *
read_hex_pkt(char * filename)1907b5038d7SDag-Erling Smørgrav read_hex_pkt(char *filename)
1917b5038d7SDag-Erling Smørgrav {
1927b5038d7SDag-Erling Smørgrav 	uint8_t *wire;
1937b5038d7SDag-Erling Smørgrav 	size_t wiresize;
1947b5038d7SDag-Erling Smørgrav 
1957b5038d7SDag-Erling Smørgrav 	ldns_pkt *pkt = NULL;
1967b5038d7SDag-Erling Smørgrav 
1977b5038d7SDag-Erling Smørgrav 	ldns_status status = LDNS_STATUS_ERR;
1987b5038d7SDag-Erling Smørgrav 
1997b5038d7SDag-Erling Smørgrav 	wire = xmalloc(LDNS_MAX_PACKETLEN);
2007b5038d7SDag-Erling Smørgrav 
2017b5038d7SDag-Erling Smørgrav 	wiresize = packetbuffromfile(filename, wire);
2027b5038d7SDag-Erling Smørgrav 
2037b5038d7SDag-Erling Smørgrav 	if (wiresize > 0) {
2047b5038d7SDag-Erling Smørgrav 		status = ldns_wire2pkt(&pkt, wire, wiresize);
2057b5038d7SDag-Erling Smørgrav 	}
2067b5038d7SDag-Erling Smørgrav 
2077b5038d7SDag-Erling Smørgrav 	xfree(wire);
2087b5038d7SDag-Erling Smørgrav 
2097b5038d7SDag-Erling Smørgrav 	if (status == LDNS_STATUS_OK) {
2107b5038d7SDag-Erling Smørgrav 		return pkt;
2117b5038d7SDag-Erling Smørgrav 	} else {
2127b5038d7SDag-Erling Smørgrav 		fprintf(stderr, "Error parsing hex file: %s\n",
2137b5038d7SDag-Erling Smørgrav 			   ldns_get_errorstr_by_id(status));
2147b5038d7SDag-Erling Smørgrav 		return NULL;
2157b5038d7SDag-Erling Smørgrav 	}
2167b5038d7SDag-Erling Smørgrav }
2177b5038d7SDag-Erling Smørgrav 
2187b5038d7SDag-Erling Smørgrav void
dump_hex(const ldns_pkt * pkt,const char * filename)2197b5038d7SDag-Erling Smørgrav dump_hex(const ldns_pkt *pkt, const char *filename)
2207b5038d7SDag-Erling Smørgrav {
2212787e39aSDag-Erling Smørgrav 	uint8_t *wire = NULL;
2227b5038d7SDag-Erling Smørgrav 	size_t size, i;
2237b5038d7SDag-Erling Smørgrav 	FILE *fp;
2247b5038d7SDag-Erling Smørgrav 	ldns_status status;
2257b5038d7SDag-Erling Smørgrav 
2267b5038d7SDag-Erling Smørgrav 	fp = fopen(filename, "w");
2277b5038d7SDag-Erling Smørgrav 
2287b5038d7SDag-Erling Smørgrav 	if (fp == NULL) {
2297b5038d7SDag-Erling Smørgrav 		error("Unable to open %s for writing", filename);
2307b5038d7SDag-Erling Smørgrav 		return;
2317b5038d7SDag-Erling Smørgrav 	}
2327b5038d7SDag-Erling Smørgrav 
2337b5038d7SDag-Erling Smørgrav 	status = ldns_pkt2wire(&wire, pkt, &size);
2347b5038d7SDag-Erling Smørgrav 
2357b5038d7SDag-Erling Smørgrav 	if (status != LDNS_STATUS_OK) {
2367b5038d7SDag-Erling Smørgrav 		error("Unable to convert packet: error code %u", status);
2372787e39aSDag-Erling Smørgrav 		LDNS_FREE(wire);
23817d15b25SDag-Erling Smørgrav 		fclose(fp);
2397b5038d7SDag-Erling Smørgrav 		return;
2407b5038d7SDag-Erling Smørgrav 	}
2417b5038d7SDag-Erling Smørgrav 
2427b5038d7SDag-Erling Smørgrav 	fprintf(fp, "; 0");
2437b5038d7SDag-Erling Smørgrav 	for (i = 1; i < 20; i++) {
2447b5038d7SDag-Erling Smørgrav 		fprintf(fp, " %2u", (unsigned int) i);
2457b5038d7SDag-Erling Smørgrav 	}
2467b5038d7SDag-Erling Smørgrav 	fprintf(fp, "\n");
2477b5038d7SDag-Erling Smørgrav 	fprintf(fp, ";--");
2487b5038d7SDag-Erling Smørgrav 	for (i = 1; i < 20; i++) {
2497b5038d7SDag-Erling Smørgrav 		fprintf(fp, " --");
2507b5038d7SDag-Erling Smørgrav 	}
2517b5038d7SDag-Erling Smørgrav 	fprintf(fp, "\n");
2527b5038d7SDag-Erling Smørgrav 	for (i = 0; i < size; i++) {
2537b5038d7SDag-Erling Smørgrav 		if (i % 20 == 0 && i > 0) {
2547b5038d7SDag-Erling Smørgrav 			fprintf(fp, "\t;\t%4u-%4u\n", (unsigned int) i-19, (unsigned int) i);
2557b5038d7SDag-Erling Smørgrav 		}
2567b5038d7SDag-Erling Smørgrav 		fprintf(fp, " %02x", (unsigned int)wire[i]);
2577b5038d7SDag-Erling Smørgrav 	}
2587b5038d7SDag-Erling Smørgrav 	fprintf(fp, "\n");
2597b5038d7SDag-Erling Smørgrav 	fclose(fp);
2602787e39aSDag-Erling Smørgrav 	LDNS_FREE(wire);
2617b5038d7SDag-Erling Smørgrav }
262