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