3a9cb5855d703607a3444808585d7ac585550121
[dragonfly.git] / contrib / ldns / drill / work.c
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 }