468c984aa5b83da60370312117a76a4c0ef184ff
[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  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_dnsparser_lib.h"
30
31
32 // DNS-Stuff
33 GNUNET_NETWORK_STRUCT_BEGIN
34 struct dns_header
35 {
36   uint16_t id GNUNET_PACKED;
37   struct GNUNET_DNSPARSER_Flags flags; 
38   uint16_t query_count GNUNET_PACKED;       // number of questions
39   uint16_t answer_rcount GNUNET_PACKED;       // number of answers
40   uint16_t authority_rcount GNUNET_PACKED;       // number of authority-records
41   uint16_t additional_rcount GNUNET_PACKED;       // number of additional records
42 };
43
44 struct query_line
45 {
46   uint16_t type GNUNET_PACKED;
47   uint16_t class GNUNET_PACKED;
48 };
49
50 struct record_line
51 {
52   uint16_t type GNUNET_PACKED;
53   uint16_t class GNUNET_PACKED;
54   uint32_t ttl GNUNET_PACKED;
55   uint16_t data_len GNUNET_PACKED;
56 };
57
58 GNUNET_NETWORK_STRUCT_END
59
60
61 /**
62  * Parse name inside of a DNS query or record.
63  *
64  * @param udp_payload entire UDP payload
65  * @param udp_payload_length length of udp_payload
66  * @param off pointer to the offset of the name to parse in the udp_payload (to be
67  *                    incremented by the size of the name)
68  * @return name as 0-terminated C string on success, NULL if the payload is malformed
69  */
70 static char *
71 parse_name (const char *udp_payload,
72             size_t udp_payload_length,
73             size_t *off)
74 {
75   const uint8_t *input = (const uint8_t *) udp_payload;
76   char *ret;
77   char *tmp;
78   char *xstr;
79   uint8_t len;
80   size_t xoff;
81   
82   ret = GNUNET_strdup ("");
83   while (1)
84   {
85     if (*off >= udp_payload_length)
86       goto error;
87     len = input[*off];
88     if (0 == len)
89     {
90       (*off)++;
91       break;
92     }
93     if (len < 64)
94     {
95       if (*off + 1 + len > udp_payload_length)
96         goto error;
97       GNUNET_asprintf (&tmp,
98                        "%s%.*s.",
99                        ret,
100                        (int) len,
101                        &udp_payload[*off + 1]);
102       GNUNET_free (ret);
103       ret = tmp;
104       *off += 1 + len;
105     }
106     else if ((64 | 128) == (len & (64 | 128)) )
107     {
108       /* pointer to string */
109       if (*off + 1 > udp_payload_length)
110         goto error;
111       xoff = ((len - (64 | 128)) << 8) + input[*off+1];
112       xstr = parse_name (udp_payload,
113                          udp_payload_length,
114                          &xoff);
115       GNUNET_asprintf (&tmp,
116                        "%s%s.",
117                        ret,
118                        xstr);
119       GNUNET_free (ret);
120       GNUNET_free (xstr);
121       ret = tmp;
122       *off += 2;
123       /* pointers always terminate names */
124       break;
125     } 
126     else
127     {
128       /* neither pointer nor inline string, not supported... */
129       goto error;
130     }
131   }
132   if (0 < strlen(ret))
133     ret[strlen(ret)-1] = '\0'; /* eat tailing '.' */
134   return ret;
135  error:  
136   GNUNET_free (ret);
137   return NULL;
138 }
139
140
141 /**
142  * Parse a DNS query entry.
143  *
144  * @param udp_payload entire UDP payload
145  * @param udp_payload_length length of udp_payload
146  * @param off pointer to the offset of the query to parse in the udp_payload (to be
147  *                    incremented by the size of the query)
148  * @param q where to write the query information
149  * @return GNUNET_OK on success, GNUNET_SYSERR if the query is malformed
150  */
151 static int
152 parse_query (const char *udp_payload,
153              size_t udp_payload_length,
154              size_t *off,
155              struct GNUNET_DNSPARSER_Query *q)
156 {
157   char *name;
158   struct query_line ql;
159
160   name = parse_name (udp_payload, 
161                      udp_payload_length,
162                      off);
163   if (NULL == name)
164     return GNUNET_SYSERR;
165   q->name = name;
166   if (*off + sizeof (struct query_line) > udp_payload_length)
167     return GNUNET_SYSERR;
168   memcpy (&ql, &udp_payload[*off], sizeof (ql));
169   *off += sizeof (ql);
170   q->type = ntohs (ql.type);
171   q->class = ntohs (ql.class);
172   return GNUNET_OK;
173 }
174
175
176 /**
177  * Parse a DNS record entry.
178  *
179  * @param udp_payload entire UDP payload
180  * @param udp_payload_length length of udp_payload
181  * @param off pointer to the offset of the record to parse in the udp_payload (to be
182  *                    incremented by the size of the record)
183  * @param r where to write the record information
184  * @return GNUNET_OK on success, GNUNET_SYSERR if the record is malformed
185  */
186 static int
187 parse_record (const char *udp_payload,
188               size_t udp_payload_length,
189               size_t *off,
190               struct GNUNET_DNSPARSER_Record *r)
191 {
192   char *name;
193   struct record_line rl;
194
195   name = parse_name (udp_payload, 
196                      udp_payload_length,
197                      off);
198   if (NULL == name)
199     return GNUNET_SYSERR;
200   r->name = name;
201   if (*off + sizeof (struct record_line) > udp_payload_length)
202     return GNUNET_SYSERR;
203   memcpy (&rl, &udp_payload[*off], sizeof (rl));
204   *off += sizeof (rl);
205   r->type = ntohs (rl.type);
206   r->class = ntohs (rl.class);
207   r->expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
208                                                                                         ntohl (rl.ttl)));
209   r->data_len = ntohs (rl.data_len);
210   if (*off + r->data_len > udp_payload_length)
211     return GNUNET_SYSERR;
212   if (0 == r->data_len)
213     return GNUNET_OK;
214   r->data = GNUNET_malloc (r->data_len);
215   memcpy (r->data, &udp_payload[*off], r->data_len);
216   *off += r->data_len;
217   return GNUNET_OK;  
218 }
219
220
221 /**
222  * Parse a UDP payload of a DNS packet in to a nice struct for further
223  * processing and manipulation.
224  *
225  * @param udp_payload wire-format of the DNS packet
226  * @param udp_payload_length number of bytes in udp_payload 
227  * @return NULL on error, otherwise the parsed packet
228  */
229 struct GNUNET_DNSPARSER_Packet *
230 GNUNET_DNSPARSER_parse (const char *udp_payload,
231                         size_t udp_payload_length)
232 {
233   struct GNUNET_DNSPARSER_Packet *p;
234   const struct dns_header *dns;
235   size_t off;
236   unsigned int n;  
237   unsigned int i;
238
239   if (udp_payload_length < sizeof (struct dns_header))
240     return NULL;
241   dns = (const struct dns_header *) udp_payload;
242   off = sizeof (struct dns_header);
243   p = GNUNET_malloc (sizeof (struct GNUNET_DNSPARSER_Packet));
244   p->flags = dns->flags;
245   p->id = dns->id;
246   n = ntohs (dns->query_count);
247   if (n > 0)
248   {
249     p->queries = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Query));
250     p->num_queries = n;
251     for (i=0;i<n;i++)
252       if (GNUNET_OK !=
253           parse_query (udp_payload,
254                        udp_payload_length,
255                        &off,
256                        &p->queries[i]))
257         goto error;
258   }
259   n = ntohs (dns->answer_rcount);
260   if (n > 0)
261   {
262     p->answers = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record));
263     p->num_answers = n;
264     for (i=0;i<n;i++)
265       if (GNUNET_OK !=
266           parse_record (udp_payload,
267                         udp_payload_length,
268                         &off,
269                         &p->answers[i]))
270         goto error;
271   }
272   n = ntohs (dns->authority_rcount);
273   if (n > 0)
274   {
275     p->authority_records = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record));
276     p->num_authority_records = n;
277     for (i=0;i<n;i++)
278       if (GNUNET_OK !=
279           parse_record (udp_payload,
280                         udp_payload_length,
281                         &off,
282                         &p->authority_records[i]))
283         goto error;  
284   }
285   n = ntohs (dns->additional_rcount);
286   if (n > 0)
287   {
288     p->additional_records = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record));
289     p->num_additional_records = n;
290     for (i=0;i<n;i++)
291       if (GNUNET_OK !=
292           parse_record (udp_payload,
293                         udp_payload_length,
294                         &off,
295                         &p->additional_records[i]))
296         goto error;   
297   }
298   return p;
299  error:
300   GNUNET_DNSPARSER_free_packet (p);
301   return NULL;
302 }
303
304
305 /**
306  * Free memory taken by a packet.
307  *
308  * @param p packet to free
309  */
310 void
311 GNUNET_DNSPARSER_free_packet (struct GNUNET_DNSPARSER_Packet *p)
312 {
313   unsigned int i;
314
315   for (i=0;i<p->num_queries;i++)
316     GNUNET_free_non_null (p->queries[i].name);
317   GNUNET_free_non_null (p->queries);
318   for (i=0;i<p->num_answers;i++)
319   {
320     GNUNET_free_non_null (p->answers[i].name);
321     GNUNET_free_non_null (p->answers[i].data);
322   }
323   GNUNET_free_non_null (p->answers);
324   for (i=0;i<p->num_authority_records;i++)
325   {
326     GNUNET_free_non_null (p->authority_records[i].name);
327     GNUNET_free_non_null (p->authority_records[i].data);
328   }
329   GNUNET_free_non_null (p->authority_records);
330   for (i=0;i<p->num_additional_records;i++)
331   {
332     GNUNET_free_non_null (p->additional_records[i].name);
333     GNUNET_free_non_null (p->additional_records[i].data);
334   }
335   GNUNET_free_non_null (p->additional_records);
336   GNUNET_free (p);
337 }
338
339
340 /**
341  * Given a DNS packet, generate the corresponding UDP payload.
342  *
343  * @param p packet to pack
344  * @param buf set to a buffer with the packed message
345  * @param buf_length set to the length of buf
346  * @return GNUNET_SYSERR if 'p' is invalid
347  *         GNUNET_NO if 'p' was truncated (but there is still a result in 'buf')
348  *         GNUNET_OK if 'p' was packed completely into '*buf'
349  */
350 int
351 GNUNET_DNSPARSER_pack (struct GNUNET_DNSPARSER_Packet *p,
352                        char **buf,
353                        size_t *buf_length)
354 {
355   // FIXME: not implemented
356   GNUNET_break (0);
357   return GNUNET_SYSERR;
358 }
359
360
361
362
363 /* legacy code follows */
364
365 /**
366  * Parse a name from DNS to a normal .-delimited, 0-terminated string.
367  *
368  * @param d The destination of the name. Should have at least 255 bytes allocated.
369  * @param src The DNS-Packet
370  * @param idx The offset inside the Packet from which on the name should be read
371  * @returns The offset of the first unparsed byte (the byte right behind the name)
372  */
373 static unsigned int
374 parse_dns_name (char *d, const unsigned char *src, unsigned short idx)
375 {                               /*{{{ */
376   char *dest = d;
377
378   int len = src[idx++];
379
380   while (len != 0)
381   {
382     if (len & 0xC0)
383     {                           /* Compressed name, offset in this and the next octet */
384       unsigned short offset = ((len & 0x3F) << 8) | src[idx++];
385
386       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 */
387       return idx;
388     }
389     memcpy (dest, src + idx, len);
390     idx += len;
391     dest += len;
392     *dest = '.';
393     dest++;
394     len = src[idx++];
395   };
396   *dest = 0;
397
398   return idx;
399 }
400
401 /*}}}*/
402
403 /**
404  * Parse a complete DNS-Record from raw DNS-data to a struct dns_record
405  *
406  * @param data The DNS-data
407  * @param dst Pointer to count pointers; individual pointers will be allocated
408  * @param count Number of records to parse
409  * @param idx The offset inside the Packet from which on the name should be read
410  * @returns The offset of the first unparsed byte (the byte right behind the last record)
411  */
412 static unsigned short
413 parse_dns_record (unsigned char *data,  /*{{{ */
414                   struct dns_record **dst, unsigned short count,
415                   unsigned short idx)
416 {
417   int i;
418   unsigned short _idx;
419
420   for (i = 0; i < count; i++)
421   {
422     dst[i] = GNUNET_malloc (sizeof (struct dns_record));
423     dst[i]->name = alloca (255);        // see RFC1035, no name can be longer than this.
424     char *name = dst[i]->name;
425
426     _idx = parse_dns_name (name, data, idx);
427     dst[i]->namelen = _idx - idx;
428
429     dst[i]->name = GNUNET_malloc (dst[i]->namelen);
430     memcpy (dst[i]->name, name, dst[i]->namelen);
431
432     idx = _idx;
433
434     dst[i]->type = *((unsigned short *) (data + idx));
435     idx += 2;
436     dst[i]->class = *((unsigned short *) (data + idx));
437     idx += 2;
438     dst[i]->ttl = *((unsigned int *) (data + idx));
439     idx += 4;
440     dst[i]->data_len = *((unsigned short *) (data + idx));
441     idx += 2;
442     dst[i]->data = GNUNET_malloc (ntohs (dst[i]->data_len));
443     memcpy (dst[i]->data, data + idx, ntohs (dst[i]->data_len));
444     idx += ntohs (dst[i]->data_len);
445   }
446   return idx;
447 }                               /*}}} */
448
449 /**
450  * Parse a raw DNS-Packet into an usable struct
451  */
452 struct dns_pkt_parsed *
453 parse_dns_packet (struct dns_pkt *pkt)
454 {                               /*{{{ */
455   struct dns_pkt_parsed *ppkt = GNUNET_malloc (sizeof (struct dns_pkt_parsed));
456
457   memcpy (&ppkt->s, &pkt->s, sizeof pkt->s);
458
459   unsigned short qdcount = ntohs (ppkt->s.qdcount);
460   unsigned short ancount = ntohs (ppkt->s.ancount);
461   unsigned short nscount = ntohs (ppkt->s.nscount);
462   unsigned short arcount = ntohs (ppkt->s.arcount);
463
464   ppkt->queries = GNUNET_malloc (qdcount * sizeof (struct dns_query *));
465   ppkt->answers = GNUNET_malloc (ancount * sizeof (struct dns_record *));
466   ppkt->nameservers = GNUNET_malloc (nscount * sizeof (struct dns_record *));
467   ppkt->additional = GNUNET_malloc (arcount * sizeof (struct dns_record *));
468
469   unsigned short idx = 0, _idx; /* This keeps track how far we have parsed the data */
470
471   /* Parse the Query */
472   int i;
473
474   for (i = 0; i < qdcount; i++)
475   {                             /*{{{ */
476     ppkt->queries[i] = GNUNET_malloc (sizeof (struct dns_query));
477     char *name = alloca (255);  /* see RFC1035, it can't be more than this. */
478
479     _idx = parse_dns_name (name, pkt->data, idx);
480     ppkt->queries[i]->namelen = _idx - idx;
481     idx = _idx;
482
483     ppkt->queries[i]->name = GNUNET_malloc (ppkt->queries[i]->namelen);
484     memcpy (ppkt->queries[i]->name, name, ppkt->queries[i]->namelen);
485
486     ppkt->queries[i]->qtype = *((unsigned short *) (pkt->data + idx));
487     idx += 2;
488     ppkt->queries[i]->qclass = *((unsigned short *) (pkt->data + idx));
489     idx += 2;
490   }
491   /*}}} */
492   idx = parse_dns_record (pkt->data, ppkt->answers, ancount, idx);
493   idx = parse_dns_record (pkt->data, ppkt->nameservers, nscount, idx);
494   idx = parse_dns_record (pkt->data, ppkt->additional, arcount, idx);
495   return ppkt;
496 }                               /*}}} */
497
498 static void
499 unparse_dns_name (char *dest, char *src, size_t len)
500 {
501   char *b = dest;
502   char cnt = 0;
503
504   dest++;
505   while (*src != 0)
506   {
507     while (*src != '.' && *src != 0)
508     {
509       *dest = *src;
510       src++;
511       dest++;
512       cnt++;
513     }
514     *b = cnt;
515     cnt = 0;
516     b = dest;
517     dest++;
518     src++;
519   }
520   *b = 0;
521 }
522
523 struct dns_pkt *
524 unparse_dns_packet (struct dns_pkt_parsed *ppkt)
525 {
526   size_t size = sizeof (struct dns_pkt) - 1;
527   int i;
528
529   for (i = 0; i < ntohs (ppkt->s.qdcount); i++)
530     size += ppkt->queries[i]->namelen + 1;
531
532   for (i = 0; i < ntohs (ppkt->s.ancount); i++)
533   {
534     size += ppkt->answers[i]->namelen + 1;
535     size += ppkt->answers[i]->data_len;
536   }
537   for (i = 0; i < ntohs (ppkt->s.nscount); i++)
538   {
539     size += ppkt->nameservers[i]->namelen + 1;
540     size += ppkt->nameservers[i]->data_len;
541   }
542   for (i = 0; i < ntohs (ppkt->s.arcount); i++)
543   {
544     size += ppkt->additional[i]->namelen + 1;
545     size += ppkt->additional[i]->data_len;
546   }
547
548   size +=
549       4 * ntohs (ppkt->s.qdcount) + 10 * (ntohs (ppkt->s.ancount) +
550                                           ntohs (ppkt->s.arcount) +
551                                           ntohs (ppkt->s.nscount));
552
553   struct dns_pkt *pkt = GNUNET_malloc (size);
554   char *pkt_c = (char *) pkt;
555
556   memcpy (&pkt->s, &ppkt->s, sizeof ppkt->s);
557   size_t idx = sizeof ppkt->s;
558
559   for (i = 0; i < ntohs (ppkt->s.qdcount); i++)
560   {
561     unparse_dns_name (&pkt_c[idx], ppkt->queries[i]->name,
562                       ppkt->queries[i]->namelen);
563     idx += ppkt->queries[i]->namelen;
564     struct dns_query_line *d = (struct dns_query_line *) &pkt_c[idx];
565
566     d->class = ppkt->queries[i]->qclass;
567     d->type = ppkt->queries[i]->qtype;
568     idx += sizeof (struct dns_query_line);
569   }
570
571   for (i = 0; i < ntohs (ppkt->s.ancount); i++)
572   {
573     unparse_dns_name (&pkt_c[idx], ppkt->answers[i]->name,
574                       ppkt->answers[i]->namelen);
575     idx += ppkt->answers[i]->namelen;
576     struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx];
577
578     r->type = ppkt->answers[i]->type;
579     r->class = ppkt->answers[i]->class;
580     r->ttl = ppkt->answers[i]->ttl;
581     r->data_len = ppkt->answers[i]->data_len;
582     idx += sizeof (struct dns_record_line);
583     memcpy (&r->data, ppkt->answers[i]->data, ppkt->answers[i]->data_len);
584     idx += ppkt->answers[i]->data_len;
585   }
586
587   for (i = 0; i < ntohs (ppkt->s.nscount); i++)
588   {
589     unparse_dns_name (&pkt_c[idx], ppkt->nameservers[i]->name,
590                       ppkt->nameservers[i]->namelen);
591     idx += ppkt->nameservers[i]->namelen;
592     struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx];
593
594     r->type = ppkt->nameservers[i]->type;
595     r->class = ppkt->nameservers[i]->class;
596     r->ttl = ppkt->nameservers[i]->ttl;
597     r->data_len = ppkt->nameservers[i]->data_len;
598     idx += sizeof (struct dns_record_line);
599     memcpy (&r->data, ppkt->nameservers[i]->data,
600             ppkt->nameservers[i]->data_len);
601     idx += ppkt->nameservers[i]->data_len;
602   }
603
604   for (i = 0; i < ntohs (ppkt->s.arcount); i++)
605   {
606     unparse_dns_name (&pkt_c[idx], ppkt->additional[i]->name,
607                       ppkt->additional[i]->namelen);
608     idx += ppkt->additional[i]->namelen;
609     struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx];
610
611     r->type = ppkt->additional[i]->type;
612     r->class = ppkt->additional[i]->class;
613     r->ttl = ppkt->additional[i]->ttl;
614     r->data_len = ppkt->additional[i]->data_len;
615     idx += sizeof (struct dns_record_line);
616     memcpy (&r->data, ppkt->additional[i]->data, ppkt->additional[i]->data_len);
617     idx += ppkt->additional[i]->data_len;
618   }
619
620   return pkt;
621 }
622
623 void
624 free_parsed_dns_packet (struct dns_pkt_parsed *ppkt)
625 {
626   unsigned short qdcount = ntohs (ppkt->s.qdcount);
627   unsigned short ancount = ntohs (ppkt->s.ancount);
628   unsigned short nscount = ntohs (ppkt->s.nscount);
629   unsigned short arcount = ntohs (ppkt->s.arcount);
630
631   int i;
632
633   for (i = 0; i < qdcount; i++)
634   {
635     GNUNET_free (ppkt->queries[i]->name);
636     GNUNET_free (ppkt->queries[i]);
637   }
638   GNUNET_free (ppkt->queries);
639   for (i = 0; i < ancount; i++)
640   {
641     GNUNET_free (ppkt->answers[i]->name);
642     GNUNET_free (ppkt->answers[i]->data);
643     GNUNET_free (ppkt->answers[i]);
644   }
645   GNUNET_free (ppkt->answers);
646   for (i = 0; i < nscount; i++)
647   {
648     GNUNET_free (ppkt->nameservers[i]->name);
649     GNUNET_free (ppkt->nameservers[i]->data);
650     GNUNET_free (ppkt->nameservers[i]);
651   }
652   GNUNET_free (ppkt->nameservers);
653   for (i = 0; i < arcount; i++)
654   {
655     GNUNET_free (ppkt->additional[i]->name);
656     GNUNET_free (ppkt->additional[i]->data);
657     GNUNET_free (ppkt->additional[i]);
658   }
659   GNUNET_free (ppkt->additional);
660   GNUNET_free (ppkt);
661 }