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