53c571eddb5ab1c91b7fb02187d9efc86e07df7e
[oweals/gnunet.git] / src / dns / dnsparser.c
1 /*
2       This file is part of GNUnet
3       (C) 2010, 2011, 2012 Christian Grothoff (and other contributing authors)
4
5       GNUnet is free software; you can redistribute it and/or modify
6       it under the terms of the GNU General Public License as published
7       by the Free Software Foundation; either version 2, or (at your
8       option) any later version.
9
10       GNUnet is distributed in the hope that it will be useful, but
11       WITHOUT ANY WARRANTY; without even the implied warranty of
12       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13       General Public License for more details.
14
15       You should have received a copy of the GNU General Public License
16       along with GNUnet; see the file COPYING.  If not, write to the
17       Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18       Boston, MA 02111-1307, USA.
19  */
20
21 /**
22  * @file dns/dnsparser.c
23  * @brief helper library to parse DNS packets. 
24  * @author Philipp Toelke
25  */
26
27 #include "platform.h"
28 #include "gnunet_dnsparser_lib.h"
29
30
31 // DNS-Stuff
32 GNUNET_NETWORK_STRUCT_BEGIN
33 struct dns_header
34 {
35   uint16_t id GNUNET_PACKED;
36   struct GNUNET_DNSPARSER_Flags flags GNUNET_PACKED; 
37   uint16_t query_count GNUNET_PACKED;       // number of questions
38   uint16_t answer_rcount GNUNET_PACKED;       // number of answers
39   uint16_t authority_rcount GNUNET_PACKED;       // number of authority-records
40   uint16_t additional_rcount GNUNET_PACKED;       // number of additional records
41 };
42 GNUNET_NETWORK_STRUCT_END
43
44
45 /**
46  * Parse a DNS query entry.
47  *
48  * @param udp_payload entire UDP payload
49  * @param udp_payload_length length of udp_payload
50  * @param off pointer to the offset of the query to parse in the udp_payload (to be
51  *                    incremented by the size of the query)
52  * @param q where to write the query information
53  * @return GNUNET_OK on success, GNUNET_SYSERR if the query is malformed
54  */
55 static int
56 parse_query (const char *udp_payload,
57              size_t udp_payload_length,
58              size_t *off,
59              struct GNUNET_DNSPARSER_Query *q)
60 {
61   return GNUNET_SYSERR;
62 }
63
64
65 /**
66  * Parse a DNS record entry.
67  *
68  * @param udp_payload entire UDP payload
69  * @param udp_payload_length length of udp_payload
70  * @param off pointer to the offset of the record to parse in the udp_payload (to be
71  *                    incremented by the size of the record)
72  * @param r where to write the record information
73  * @return GNUNET_OK on success, GNUNET_SYSERR if the record is malformed
74  */
75 static int
76 parse_record (const char *udp_payload,
77               size_t udp_payload_length,
78               size_t *off,
79               struct GNUNET_DNSPARSER_Record *r)
80 {
81   return GNUNET_SYSERR;
82 }
83
84
85
86 /**
87  * Parse a UDP payload of a DNS packet in to a nice struct for further
88  * processing and manipulation.
89  *
90  * @param udp_payload wire-format of the DNS packet
91  * @param udp_payload_length number of bytes in udp_payload 
92  * @return NULL on error, otherwise the parsed packet
93  */
94 struct GNUNET_DNSPARSER_Packet *
95 GNUNET_DNSPARSER_parse (const char *udp_payload,
96                         size_t udp_payload_length)
97 {
98   struct GNUNET_DNSPARSER_Packet *p;
99   const struct dns_header *dns;
100   size_t off;
101   unsigned int n;  
102   unsigned int i;
103
104   if (udp_payload_length < sizeof (struct dns_header))
105     return NULL;
106   dns = (const struct dns_header *) udp_payload;
107   off = sizeof (struct dns_header);
108   p = GNUNET_malloc (sizeof (struct GNUNET_DNSPARSER_Packet));
109   p->flags = dns->flags;
110   p->id = dns->id;
111   n = ntohs (dns->query_count);
112   if (n > 0)
113   {
114     p->queries = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Query));
115     p->num_queries = n;
116     for (i=0;i<n;i++)
117       if (GNUNET_OK !=
118           parse_query (udp_payload,
119                        udp_payload_length,
120                        &off,
121                        &p->queries[i]))
122         goto error;
123   }
124   n = ntohs (dns->answer_rcount);
125   if (n > 0)
126   {
127     p->answers = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record));
128     p->num_answers = n;
129     for (i=0;i<n;i++)
130       if (GNUNET_OK !=
131           parse_record (udp_payload,
132                         udp_payload_length,
133                         &off,
134                         &p->answers[i]))
135         goto error;
136   }
137   n = ntohs (dns->authority_rcount);
138   if (n > 0)
139   {
140     p->authority_records = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record));
141     p->num_authority_records = n;
142     for (i=0;i<n;i++)
143       if (GNUNET_OK !=
144           parse_record (udp_payload,
145                         udp_payload_length,
146                         &off,
147                         &p->authority_records[i]))
148         goto error;  
149   }
150   n = ntohs (dns->additional_rcount);
151   if (n > 0)
152   {
153     p->additional_records = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record));
154     p->num_additional_records = n;
155     for (i=0;i<n;i++)
156       if (GNUNET_OK !=
157           parse_record (udp_payload,
158                         udp_payload_length,
159                         &off,
160                         &p->additional_records[i]))
161         goto error;   
162   }
163   return p;
164  error:
165   GNUNET_DNSPARSER_free_packet (p);
166   return NULL;
167 }
168
169
170 /**
171  * Free memory taken by a packet.
172  *
173  * @param p packet to free
174  */
175 void
176 GNUNET_DNSPARSER_free_packet (struct GNUNET_DNSPARSER_Packet *p)
177 {
178   unsigned int i;
179
180   for (i=0;i<p->num_queries;i++)
181     GNUNET_free_non_null (p->queries[i].name);
182   GNUNET_free_non_null (p->queries);
183   for (i=0;i<p->num_answers;i++)
184   {
185     GNUNET_free_non_null (p->answers[i].name);
186     GNUNET_free_non_null (p->answers[i].data);
187   }
188   GNUNET_free_non_null (p->answers);
189   for (i=0;i<p->num_authority_records;i++)
190   {
191     GNUNET_free_non_null (p->authority_records[i].name);
192     GNUNET_free_non_null (p->authority_records[i].data);
193   }
194   GNUNET_free_non_null (p->authority_records);
195   for (i=0;i<p->num_additional_records;i++)
196   {
197     GNUNET_free_non_null (p->additional_records[i].name);
198     GNUNET_free_non_null (p->additional_records[i].data);
199   }
200   GNUNET_free_non_null (p->additional_records);
201   GNUNET_free (p);
202 }
203
204
205 /**
206  * Given a DNS packet, generate the corresponding UDP payload.
207  *
208  * @param p packet to pack
209  * @param buf set to a buffer with the packed message
210  * @param buf_length set to the length of buf
211  * @return GNUNET_SYSERR if 'p' is invalid
212  *         GNUNET_NO if 'p' was truncated (but there is still a result in 'buf')
213  *         GNUNET_OK if 'p' was packed completely into '*buf'
214  */
215 int
216 GNUNET_DNSPARSER_pack (struct GNUNET_DNSPARSER_Packet *p,
217                        char **buf,
218                        size_t *buf_length)
219 {
220   // FIXME: not implemented
221   GNUNET_break (0);
222   return GNUNET_SYSERR;
223 }
224
225
226
227
228 /* legacy code follows */
229
230 /**
231  * Parse a name from DNS to a normal .-delimited, 0-terminated string.
232  *
233  * @param d The destination of the name. Should have at least 255 bytes allocated.
234  * @param src The DNS-Packet
235  * @param idx The offset inside the Packet from which on the name should be read
236  * @returns The offset of the first unparsed byte (the byte right behind the name)
237  */
238 static unsigned int
239 parse_dns_name (char *d, const unsigned char *src, unsigned short idx)
240 {                               /*{{{ */
241   char *dest = d;
242
243   int len = src[idx++];
244
245   while (len != 0)
246   {
247     if (len & 0xC0)
248     {                           /* Compressed name, offset in this and the next octet */
249       unsigned short offset = ((len & 0x3F) << 8) | src[idx++];
250
251       parse_dns_name (dest, src, offset - 12);  /* 12 for the Header of the DNS-Packet, idx starts at 0 which is 12 bytes from the start of the packet */
252       return idx;
253     }
254     memcpy (dest, src + idx, len);
255     idx += len;
256     dest += len;
257     *dest = '.';
258     dest++;
259     len = src[idx++];
260   };
261   *dest = 0;
262
263   return idx;
264 }
265
266 /*}}}*/
267
268 /**
269  * Parse a complete DNS-Record from raw DNS-data to a struct dns_record
270  *
271  * @param data The DNS-data
272  * @param dst Pointer to count pointers; individual pointers will be allocated
273  * @param count Number of records to parse
274  * @param idx The offset inside the Packet from which on the name should be read
275  * @returns The offset of the first unparsed byte (the byte right behind the last record)
276  */
277 static unsigned short
278 parse_dns_record (unsigned char *data,  /*{{{ */
279                   struct dns_record **dst, unsigned short count,
280                   unsigned short idx)
281 {
282   int i;
283   unsigned short _idx;
284
285   for (i = 0; i < count; i++)
286   {
287     dst[i] = GNUNET_malloc (sizeof (struct dns_record));
288     dst[i]->name = alloca (255);        // see RFC1035, no name can be longer than this.
289     char *name = dst[i]->name;
290
291     _idx = parse_dns_name (name, data, idx);
292     dst[i]->namelen = _idx - idx;
293
294     dst[i]->name = GNUNET_malloc (dst[i]->namelen);
295     memcpy (dst[i]->name, name, dst[i]->namelen);
296
297     idx = _idx;
298
299     dst[i]->type = *((unsigned short *) (data + idx));
300     idx += 2;
301     dst[i]->class = *((unsigned short *) (data + idx));
302     idx += 2;
303     dst[i]->ttl = *((unsigned int *) (data + idx));
304     idx += 4;
305     dst[i]->data_len = *((unsigned short *) (data + idx));
306     idx += 2;
307     dst[i]->data = GNUNET_malloc (ntohs (dst[i]->data_len));
308     memcpy (dst[i]->data, data + idx, ntohs (dst[i]->data_len));
309     idx += ntohs (dst[i]->data_len);
310   }
311   return idx;
312 }                               /*}}} */
313
314 /**
315  * Parse a raw DNS-Packet into an usable struct
316  */
317 struct dns_pkt_parsed *
318 parse_dns_packet (struct dns_pkt *pkt)
319 {                               /*{{{ */
320   struct dns_pkt_parsed *ppkt = GNUNET_malloc (sizeof (struct dns_pkt_parsed));
321
322   memcpy (&ppkt->s, &pkt->s, sizeof pkt->s);
323
324   unsigned short qdcount = ntohs (ppkt->s.qdcount);
325   unsigned short ancount = ntohs (ppkt->s.ancount);
326   unsigned short nscount = ntohs (ppkt->s.nscount);
327   unsigned short arcount = ntohs (ppkt->s.arcount);
328
329   ppkt->queries = GNUNET_malloc (qdcount * sizeof (struct dns_query *));
330   ppkt->answers = GNUNET_malloc (ancount * sizeof (struct dns_record *));
331   ppkt->nameservers = GNUNET_malloc (nscount * sizeof (struct dns_record *));
332   ppkt->additional = GNUNET_malloc (arcount * sizeof (struct dns_record *));
333
334   unsigned short idx = 0, _idx; /* This keeps track how far we have parsed the data */
335
336   /* Parse the Query */
337   int i;
338
339   for (i = 0; i < qdcount; i++)
340   {                             /*{{{ */
341     ppkt->queries[i] = GNUNET_malloc (sizeof (struct dns_query));
342     char *name = alloca (255);  /* see RFC1035, it can't be more than this. */
343
344     _idx = parse_dns_name (name, pkt->data, idx);
345     ppkt->queries[i]->namelen = _idx - idx;
346     idx = _idx;
347
348     ppkt->queries[i]->name = GNUNET_malloc (ppkt->queries[i]->namelen);
349     memcpy (ppkt->queries[i]->name, name, ppkt->queries[i]->namelen);
350
351     ppkt->queries[i]->qtype = *((unsigned short *) (pkt->data + idx));
352     idx += 2;
353     ppkt->queries[i]->qclass = *((unsigned short *) (pkt->data + idx));
354     idx += 2;
355   }
356   /*}}} */
357   idx = parse_dns_record (pkt->data, ppkt->answers, ancount, idx);
358   idx = parse_dns_record (pkt->data, ppkt->nameservers, nscount, idx);
359   idx = parse_dns_record (pkt->data, ppkt->additional, arcount, idx);
360   return ppkt;
361 }                               /*}}} */
362
363 static void
364 unparse_dns_name (char *dest, char *src, size_t len)
365 {
366   char *b = dest;
367   char cnt = 0;
368
369   dest++;
370   while (*src != 0)
371   {
372     while (*src != '.' && *src != 0)
373     {
374       *dest = *src;
375       src++;
376       dest++;
377       cnt++;
378     }
379     *b = cnt;
380     cnt = 0;
381     b = dest;
382     dest++;
383     src++;
384   }
385   *b = 0;
386 }
387
388 struct dns_pkt *
389 unparse_dns_packet (struct dns_pkt_parsed *ppkt)
390 {
391   size_t size = sizeof (struct dns_pkt) - 1;
392   int i;
393
394   for (i = 0; i < ntohs (ppkt->s.qdcount); i++)
395     size += ppkt->queries[i]->namelen + 1;
396
397   for (i = 0; i < ntohs (ppkt->s.ancount); i++)
398   {
399     size += ppkt->answers[i]->namelen + 1;
400     size += ppkt->answers[i]->data_len;
401   }
402   for (i = 0; i < ntohs (ppkt->s.nscount); i++)
403   {
404     size += ppkt->nameservers[i]->namelen + 1;
405     size += ppkt->nameservers[i]->data_len;
406   }
407   for (i = 0; i < ntohs (ppkt->s.arcount); i++)
408   {
409     size += ppkt->additional[i]->namelen + 1;
410     size += ppkt->additional[i]->data_len;
411   }
412
413   size +=
414       4 * ntohs (ppkt->s.qdcount) + 10 * (ntohs (ppkt->s.ancount) +
415                                           ntohs (ppkt->s.arcount) +
416                                           ntohs (ppkt->s.nscount));
417
418   struct dns_pkt *pkt = GNUNET_malloc (size);
419   char *pkt_c = (char *) pkt;
420
421   memcpy (&pkt->s, &ppkt->s, sizeof ppkt->s);
422   size_t idx = sizeof ppkt->s;
423
424   for (i = 0; i < ntohs (ppkt->s.qdcount); i++)
425   {
426     unparse_dns_name (&pkt_c[idx], ppkt->queries[i]->name,
427                       ppkt->queries[i]->namelen);
428     idx += ppkt->queries[i]->namelen;
429     struct dns_query_line *d = (struct dns_query_line *) &pkt_c[idx];
430
431     d->class = ppkt->queries[i]->qclass;
432     d->type = ppkt->queries[i]->qtype;
433     idx += sizeof (struct dns_query_line);
434   }
435
436   for (i = 0; i < ntohs (ppkt->s.ancount); i++)
437   {
438     unparse_dns_name (&pkt_c[idx], ppkt->answers[i]->name,
439                       ppkt->answers[i]->namelen);
440     idx += ppkt->answers[i]->namelen;
441     struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx];
442
443     r->type = ppkt->answers[i]->type;
444     r->class = ppkt->answers[i]->class;
445     r->ttl = ppkt->answers[i]->ttl;
446     r->data_len = ppkt->answers[i]->data_len;
447     idx += sizeof (struct dns_record_line);
448     memcpy (&r->data, ppkt->answers[i]->data, ppkt->answers[i]->data_len);
449     idx += ppkt->answers[i]->data_len;
450   }
451
452   for (i = 0; i < ntohs (ppkt->s.nscount); i++)
453   {
454     unparse_dns_name (&pkt_c[idx], ppkt->nameservers[i]->name,
455                       ppkt->nameservers[i]->namelen);
456     idx += ppkt->nameservers[i]->namelen;
457     struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx];
458
459     r->type = ppkt->nameservers[i]->type;
460     r->class = ppkt->nameservers[i]->class;
461     r->ttl = ppkt->nameservers[i]->ttl;
462     r->data_len = ppkt->nameservers[i]->data_len;
463     idx += sizeof (struct dns_record_line);
464     memcpy (&r->data, ppkt->nameservers[i]->data,
465             ppkt->nameservers[i]->data_len);
466     idx += ppkt->nameservers[i]->data_len;
467   }
468
469   for (i = 0; i < ntohs (ppkt->s.arcount); i++)
470   {
471     unparse_dns_name (&pkt_c[idx], ppkt->additional[i]->name,
472                       ppkt->additional[i]->namelen);
473     idx += ppkt->additional[i]->namelen;
474     struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx];
475
476     r->type = ppkt->additional[i]->type;
477     r->class = ppkt->additional[i]->class;
478     r->ttl = ppkt->additional[i]->ttl;
479     r->data_len = ppkt->additional[i]->data_len;
480     idx += sizeof (struct dns_record_line);
481     memcpy (&r->data, ppkt->additional[i]->data, ppkt->additional[i]->data_len);
482     idx += ppkt->additional[i]->data_len;
483   }
484
485   return pkt;
486 }
487
488 void
489 free_parsed_dns_packet (struct dns_pkt_parsed *ppkt)
490 {
491   unsigned short qdcount = ntohs (ppkt->s.qdcount);
492   unsigned short ancount = ntohs (ppkt->s.ancount);
493   unsigned short nscount = ntohs (ppkt->s.nscount);
494   unsigned short arcount = ntohs (ppkt->s.arcount);
495
496   int i;
497
498   for (i = 0; i < qdcount; i++)
499   {
500     GNUNET_free (ppkt->queries[i]->name);
501     GNUNET_free (ppkt->queries[i]);
502   }
503   GNUNET_free (ppkt->queries);
504   for (i = 0; i < ancount; i++)
505   {
506     GNUNET_free (ppkt->answers[i]->name);
507     GNUNET_free (ppkt->answers[i]->data);
508     GNUNET_free (ppkt->answers[i]);
509   }
510   GNUNET_free (ppkt->answers);
511   for (i = 0; i < nscount; i++)
512   {
513     GNUNET_free (ppkt->nameservers[i]->name);
514     GNUNET_free (ppkt->nameservers[i]->data);
515     GNUNET_free (ppkt->nameservers[i]);
516   }
517   GNUNET_free (ppkt->nameservers);
518   for (i = 0; i < arcount; i++)
519   {
520     GNUNET_free (ppkt->additional[i]->name);
521     GNUNET_free (ppkt->additional[i]->data);
522     GNUNET_free (ppkt->additional[i]);
523   }
524   GNUNET_free (ppkt->additional);
525   GNUNET_free (ppkt);
526 }