2 This file is part of GNUnet
3 (C) 2010, 2011, 2012 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file dns/dnsparser.c
23 * @brief helper library to parse DNS packets.
24 * @author Philipp Toelke
25 * @author Christian Grothoff
28 #include "gnunet_util_lib.h"
29 #include "gnunet_dnsparser_lib.h"
33 GNUNET_NETWORK_STRUCT_BEGIN
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
46 uint16_t type GNUNET_PACKED;
47 uint16_t class GNUNET_PACKED;
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;
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;
67 GNUNET_NETWORK_STRUCT_END
71 * Parse name inside of a DNS query or record.
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
81 parse_name (const char *udp_payload,
82 size_t udp_payload_length,
86 const uint8_t *input = (const uint8_t *) udp_payload;
93 ret = GNUNET_strdup ("");
96 if (*off >= udp_payload_length)
106 if (*off + 1 + len > udp_payload_length)
108 GNUNET_asprintf (&tmp,
112 &udp_payload[*off + 1]);
117 else if ((64 | 128) == (len & (64 | 128)) )
120 goto error; /* hard bound on stack to prevent "infinite" recursion, disallow! */
121 /* pointer to string */
122 if (*off + 1 > udp_payload_length)
124 xoff = ((len - (64 | 128)) << 8) + input[*off+1];
125 xstr = parse_name (udp_payload,
131 GNUNET_asprintf (&tmp,
138 if (strlen (ret) > udp_payload_length)
139 goto error; /* we are looping (building an infinite string) */
141 /* pointers always terminate names */
146 /* neither pointer nor inline string, not supported... */
151 ret[strlen(ret)-1] = '\0'; /* eat tailing '.' */
160 * Parse a DNS query entry.
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
170 parse_query (const char *udp_payload,
171 size_t udp_payload_length,
173 struct GNUNET_DNSPARSER_Query *q)
176 struct query_line ql;
178 name = parse_name (udp_payload,
182 return GNUNET_SYSERR;
184 if (*off + sizeof (struct query_line) > udp_payload_length)
185 return GNUNET_SYSERR;
186 memcpy (&ql, &udp_payload[*off], sizeof (ql));
188 q->type = ntohs (ql.type);
189 q->class = ntohs (ql.class);
195 * Parse a DNS record entry.
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
205 parse_record (const char *udp_payload,
206 size_t udp_payload_length,
208 struct GNUNET_DNSPARSER_Record *r)
211 struct record_line rl;
217 name = parse_name (udp_payload,
221 return GNUNET_SYSERR;
223 if (*off + sizeof (struct record_line) > udp_payload_length)
224 return GNUNET_SYSERR;
225 memcpy (&rl, &udp_payload[*off], sizeof (rl));
226 (*off) += sizeof (rl);
227 r->type = ntohs (rl.type);
228 r->class = ntohs (rl.class);
229 r->expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
231 data_len = ntohs (rl.data_len);
232 if (*off + data_len > udp_payload_length)
233 return GNUNET_SYSERR;
236 case GNUNET_DNSPARSER_TYPE_NS:
237 case GNUNET_DNSPARSER_TYPE_CNAME:
238 case GNUNET_DNSPARSER_TYPE_PTR:
240 r->data.hostname = parse_name (udp_payload,
243 if ( (NULL == r->data.hostname) ||
244 (old_off + data_len != *off) )
245 return GNUNET_SYSERR;
247 case GNUNET_DNSPARSER_TYPE_SOA:
249 r->data.soa = GNUNET_malloc (sizeof (struct GNUNET_DNSPARSER_SoaRecord));
250 r->data.soa->mname = parse_name (udp_payload,
253 r->data.soa->rname = parse_name (udp_payload,
256 if ( (NULL == r->data.soa->mname) ||
257 (NULL == r->data.soa->rname) ||
258 (*off + sizeof (soa) > udp_payload_length) )
259 return GNUNET_SYSERR;
260 memcpy (&soa, &udp_payload[*off], sizeof (soa));
261 r->data.soa->serial = ntohl (soa.serial);
262 r->data.soa->refresh = ntohl (soa.refresh);
263 r->data.soa->retry = ntohl (soa.retry);
264 r->data.soa->expire = ntohl (soa.expire);
265 r->data.soa->minimum_ttl = ntohl (soa.minimum);
266 (*off) += sizeof (soa);
267 if (old_off + data_len != *off)
268 return GNUNET_SYSERR;
270 case GNUNET_DNSPARSER_TYPE_MX:
272 if (*off + sizeof (uint16_t) > udp_payload_length)
273 return GNUNET_SYSERR;
274 memcpy (&mxpref, &udp_payload[*off], sizeof (uint16_t));
275 (*off) += sizeof (uint16_t);
276 r->data.mx = GNUNET_malloc (sizeof (struct GNUNET_DNSPARSER_MxRecord));
277 r->data.mx->preference = ntohs (mxpref);
278 r->data.mx->mxhost = parse_name (udp_payload,
281 if (old_off + data_len != *off)
282 return GNUNET_SYSERR;
285 r->data.raw.data = GNUNET_malloc (data_len);
286 r->data.raw.data_len = data_len;
287 memcpy (r->data.raw.data, &udp_payload[*off], data_len);
296 * Parse a UDP payload of a DNS packet in to a nice struct for further
297 * processing and manipulation.
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
303 struct GNUNET_DNSPARSER_Packet *
304 GNUNET_DNSPARSER_parse (const char *udp_payload,
305 size_t udp_payload_length)
307 struct GNUNET_DNSPARSER_Packet *p;
308 const struct dns_header *dns;
313 if (udp_payload_length < sizeof (struct dns_header))
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;
320 n = ntohs (dns->query_count);
323 p->queries = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Query));
327 parse_query (udp_payload,
333 n = ntohs (dns->answer_rcount);
336 p->answers = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record));
340 parse_record (udp_payload,
346 n = ntohs (dns->authority_rcount);
349 p->authority_records = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record));
350 p->num_authority_records = n;
353 parse_record (udp_payload,
356 &p->authority_records[i]))
359 n = ntohs (dns->additional_rcount);
362 p->additional_records = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record));
363 p->num_additional_records = n;
366 parse_record (udp_payload,
369 &p->additional_records[i]))
374 GNUNET_DNSPARSER_free_packet (p);
380 * Free SOA information record.
382 * @param soa record to free
385 free_soa (struct GNUNET_DNSPARSER_SoaRecord *soa)
389 GNUNET_free_non_null (soa->mname);
390 GNUNET_free_non_null (soa->rname);
396 * Free MX information record.
398 * @param mx record to free
401 free_mx (struct GNUNET_DNSPARSER_MxRecord *mx)
405 GNUNET_free_non_null (mx->mxhost);
411 free_record (struct GNUNET_DNSPARSER_Record *r)
413 GNUNET_free_non_null (r->name);
416 case GNUNET_DNSPARSER_TYPE_MX:
417 free_mx (r->data.mx);
419 case GNUNET_DNSPARSER_TYPE_SOA:
420 free_soa (r->data.soa);
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);
428 GNUNET_free_non_null (r->data.raw.data);
435 * Free memory taken by a packet.
437 * @param p packet to free
440 GNUNET_DNSPARSER_free_packet (struct GNUNET_DNSPARSER_Packet *p)
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);
460 /* ********************** DNS packet assembly code **************** */
464 * Add a DNS name to the UDP packet at the given location.
466 * @param dst where to write the name
467 * @param dst_len number of bytes in dst
468 * @param off pointer to offset where to write the name (increment by bytes used)
469 * @param name name to write
470 * @return GNUNET_SYSERR if 'name' is invalid
471 * GNUNET_NO if 'name' did not fit
472 * GNUNET_OK if 'name' was added to 'dst'
486 return GNUNET_SYSERR;
488 if (start + strlen (name) + 2 > dst_len)
493 dot = strchr (name, '.');
498 if ( (len >= 64) || (len == 0) )
499 return GNUNET_NO; /* segment too long or empty */
500 dst[pos++] = (char) (uint8_t) len;
501 memcpy (&dst[pos], name, len);
503 name += len + 1; /* also skip dot */
506 dst[pos++] = '\0'; /* terminator */
513 * Add a DNS query to the UDP packet at the given location.
515 * @param dst where to write the query
516 * @param dst_len number of bytes in dst
517 * @param off pointer to offset where to write the query (increment by bytes used)
518 * @param query query to write
519 * @return GNUNET_SYSERR if 'query' is invalid
520 * GNUNET_NO if 'query' did not fit
521 * GNUNET_OK if 'query' was added to 'dst'
524 add_query (char *dst,
527 const struct GNUNET_DNSPARSER_Query *query)
530 struct query_line ql;
532 ret = add_name (dst, dst_len - sizeof (struct query_line), off, query->name);
533 if (ret != GNUNET_OK)
535 ql.type = htons (query->type);
536 ql.class = htons (query->class);
537 memcpy (&dst[*off], &ql, sizeof (ql));
538 (*off) += sizeof (ql);
544 * Add an MX record to the UDP packet at the given location.
546 * @param dst where to write the mx record
547 * @param dst_len number of bytes in dst
548 * @param off pointer to offset where to write the mx information (increment by bytes used)
549 * @param mx mx information to write
550 * @return GNUNET_SYSERR if 'mx' is invalid
551 * GNUNET_NO if 'mx' did not fit
552 * GNUNET_OK if 'mx' was added to 'dst'
558 const struct GNUNET_DNSPARSER_MxRecord *mx)
560 return GNUNET_SYSERR; // not implemented
565 * Add an SOA record to the UDP packet at the given location.
567 * @param dst where to write the SOA record
568 * @param dst_len number of bytes in dst
569 * @param off pointer to offset where to write the SOA information (increment by bytes used)
570 * @param soa SOA information to write
571 * @return GNUNET_SYSERR if 'soa' is invalid
572 * GNUNET_NO if 'soa' did not fit
573 * GNUNET_OK if 'soa' was added to 'dst'
579 const struct GNUNET_DNSPARSER_SoaRecord *soa)
581 return GNUNET_SYSERR; // not implemented
586 * Add a DNS record to the UDP packet at the given location.
588 * @param dst where to write the query
589 * @param dst_len number of bytes in dst
590 * @param off pointer to offset where to write the query (increment by bytes used)
591 * @param record record to write
592 * @return GNUNET_SYSERR if 'record' is invalid
593 * GNUNET_NO if 'record' did not fit
594 * GNUNET_OK if 'record' was added to 'dst'
597 add_record (char *dst,
600 const struct GNUNET_DNSPARSER_Record *record)
605 struct record_line rl;
608 ret = add_name (dst, dst_len - sizeof (struct record_line), off, record->name);
609 if (ret != GNUNET_OK)
611 /* '*off' is now the position where we will need to write the record line */
613 pos = *off + sizeof (struct record_line);
614 switch (record->type)
616 case GNUNET_DNSPARSER_TYPE_MX:
617 ret = add_mx (dst, dst_len, &pos, record->data.mx);
619 case GNUNET_DNSPARSER_TYPE_SOA:
620 ret = add_soa (dst, dst_len, &pos, record->data.soa);
622 case GNUNET_DNSPARSER_TYPE_NS:
623 case GNUNET_DNSPARSER_TYPE_CNAME:
624 case GNUNET_DNSPARSER_TYPE_PTR:
625 ret = add_name (dst, dst_len, &pos, record->data.hostname);
628 if (pos + record->data.raw.data_len > dst_len)
633 memcpy (&dst[pos], record->data.raw.data, record->data.raw.data_len);
634 pos += record->data.raw.data_len;
637 if (pos - (*off + sizeof (struct record_line)) > UINT16_MAX)
639 /* record data too long */
643 rl.type = htons (record->type);
644 rl.class = htons (record->class);
645 rl.ttl = htonl (GNUNET_TIME_absolute_get_remaining (record->expiration_time).rel_value / 1000); /* in seconds */
646 rl.data_len = htons ((uint16_t) (pos - (*off + sizeof (struct record_line))));
647 memcpy (&dst[*off], &rl, sizeof (struct record_line));
655 * Given a DNS packet, generate the corresponding UDP payload.
656 * Note that we do not attempt to pack the strings with pointers
657 * as this would complicate the code and this is about being
658 * simple and secure, not fast, fancy and broken like bind.
660 * @param p packet to pack
661 * @param max maximum allowed size for the resulting UDP payload
662 * @param buf set to a buffer with the packed message
663 * @param buf_length set to the length of buf
664 * @return GNUNET_SYSERR if 'p' is invalid
665 * GNUNET_NO if 'p' was truncated (but there is still a result in 'buf')
666 * GNUNET_OK if 'p' was packed completely into '*buf'
669 GNUNET_DNSPARSER_pack (const struct GNUNET_DNSPARSER_Packet *p,
674 struct dns_header dns;
681 if ( (p->num_queries > UINT16_MAX) ||
682 (p->num_answers > UINT16_MAX) ||
683 (p->num_authority_records > UINT16_MAX) ||
684 (p->num_additional_records > UINT16_MAX) )
685 return GNUNET_SYSERR;
687 dns.flags = p->flags;
688 dns.query_count = htons (p->num_queries);
689 dns.answer_rcount = htons (p->num_answers);
690 dns.authority_rcount = htons (p->num_authority_records);
691 dns.additional_rcount = htons (p->num_additional_records);
692 off = sizeof (struct dns_header);
694 for (i=0;i<p->num_queries;i++)
696 ret = add_query (tmp, sizeof (tmp), &off, &p->queries[i]);
697 if (GNUNET_SYSERR == ret)
698 return GNUNET_SYSERR;
699 if (GNUNET_NO == ret)
701 dns.query_count = htons ((uint16_t) (i-1));
706 for (i=0;i<p->num_answers;i++)
708 ret = add_record (tmp, sizeof (tmp), &off, &p->answers[i]);
709 if (GNUNET_SYSERR == ret)
710 return GNUNET_SYSERR;
711 if (GNUNET_NO == ret)
713 dns.answer_rcount = htons ((uint16_t) (i-1));
718 for (i=0;i<p->num_authority_records;i++)
720 ret = add_record (tmp, sizeof (tmp), &off, &p->authority_records[i]);
721 if (GNUNET_SYSERR == ret)
722 return GNUNET_SYSERR;
723 if (GNUNET_NO == ret)
725 dns.authority_rcount = htons ((uint16_t) (i-1));
730 for (i=0;i<p->num_additional_records;i++)
732 ret = add_record (tmp, sizeof (tmp), &off, &p->additional_records[i]);
733 if (GNUNET_SYSERR == ret)
734 return GNUNET_SYSERR;
735 if (GNUNET_NO == ret)
737 dns.additional_rcount = htons (i-1);
742 if (GNUNET_YES == trc)
743 dns.flags.message_truncated = 1;
746 memcpy (tmp, &dns, sizeof (struct dns_header));
747 *buf = GNUNET_malloc (off);
749 memcpy (*buf, tmp, off);
782 /* legacy code follows */
785 * Parse a name from DNS to a normal .-delimited, 0-terminated string.
787 * @param d The destination of the name. Should have at least 255 bytes allocated.
788 * @param src The DNS-Packet
789 * @param idx The offset inside the Packet from which on the name should be read
790 * @returns The offset of the first unparsed byte (the byte right behind the name)
793 parse_dns_name (char *d, const unsigned char *src, unsigned short idx)
797 int len = src[idx++];
802 { /* Compressed name, offset in this and the next octet */
803 unsigned short offset = ((len & 0x3F) << 8) | src[idx++];
805 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 */
808 memcpy (dest, src + idx, len);
823 * Parse a complete DNS-Record from raw DNS-data to a struct dns_record
825 * @param data The DNS-data
826 * @param dst Pointer to count pointers; individual pointers will be allocated
827 * @param count Number of records to parse
828 * @param idx The offset inside the Packet from which on the name should be read
829 * @returns The offset of the first unparsed byte (the byte right behind the last record)
831 static unsigned short
832 parse_dns_record (unsigned char *data, /*{{{ */
833 struct dns_record **dst, unsigned short count,
839 for (i = 0; i < count; i++)
841 dst[i] = GNUNET_malloc (sizeof (struct dns_record));
842 dst[i]->name = alloca (255); // see RFC1035, no name can be longer than this.
843 char *name = dst[i]->name;
845 _idx = parse_dns_name (name, data, idx);
846 dst[i]->namelen = _idx - idx;
848 dst[i]->name = GNUNET_malloc (dst[i]->namelen);
849 memcpy (dst[i]->name, name, dst[i]->namelen);
853 dst[i]->type = *((unsigned short *) (data + idx));
855 dst[i]->class = *((unsigned short *) (data + idx));
857 dst[i]->ttl = *((unsigned int *) (data + idx));
859 dst[i]->data_len = *((unsigned short *) (data + idx));
861 dst[i]->data = GNUNET_malloc (ntohs (dst[i]->data_len));
862 memcpy (dst[i]->data, data + idx, ntohs (dst[i]->data_len));
863 idx += ntohs (dst[i]->data_len);
869 * Parse a raw DNS-Packet into an usable struct
871 struct dns_pkt_parsed *
872 parse_dns_packet (struct dns_pkt *pkt)
874 struct dns_pkt_parsed *ppkt = GNUNET_malloc (sizeof (struct dns_pkt_parsed));
876 memcpy (&ppkt->s, &pkt->s, sizeof pkt->s);
878 unsigned short qdcount = ntohs (ppkt->s.qdcount);
879 unsigned short ancount = ntohs (ppkt->s.ancount);
880 unsigned short nscount = ntohs (ppkt->s.nscount);
881 unsigned short arcount = ntohs (ppkt->s.arcount);
883 ppkt->queries = GNUNET_malloc (qdcount * sizeof (struct dns_query *));
884 ppkt->answers = GNUNET_malloc (ancount * sizeof (struct dns_record *));
885 ppkt->nameservers = GNUNET_malloc (nscount * sizeof (struct dns_record *));
886 ppkt->additional = GNUNET_malloc (arcount * sizeof (struct dns_record *));
888 unsigned short idx = 0, _idx; /* This keeps track how far we have parsed the data */
890 /* Parse the Query */
893 for (i = 0; i < qdcount; i++)
895 ppkt->queries[i] = GNUNET_malloc (sizeof (struct dns_query));
896 char *name = alloca (255); /* see RFC1035, it can't be more than this. */
898 _idx = parse_dns_name (name, pkt->data, idx);
899 ppkt->queries[i]->namelen = _idx - idx;
902 ppkt->queries[i]->name = GNUNET_malloc (ppkt->queries[i]->namelen);
903 memcpy (ppkt->queries[i]->name, name, ppkt->queries[i]->namelen);
905 ppkt->queries[i]->qtype = *((unsigned short *) (pkt->data + idx));
907 ppkt->queries[i]->qclass = *((unsigned short *) (pkt->data + idx));
911 idx = parse_dns_record (pkt->data, ppkt->answers, ancount, idx);
912 idx = parse_dns_record (pkt->data, ppkt->nameservers, nscount, idx);
913 idx = parse_dns_record (pkt->data, ppkt->additional, arcount, idx);
918 unparse_dns_name (char *dest, char *src, size_t len)
926 while (*src != '.' && *src != 0)
943 unparse_dns_packet (struct dns_pkt_parsed *ppkt)
945 size_t size = sizeof (struct dns_pkt) - 1;
948 for (i = 0; i < ntohs (ppkt->s.qdcount); i++)
949 size += ppkt->queries[i]->namelen + 1;
951 for (i = 0; i < ntohs (ppkt->s.ancount); i++)
953 size += ppkt->answers[i]->namelen + 1;
954 size += ppkt->answers[i]->data_len;
956 for (i = 0; i < ntohs (ppkt->s.nscount); i++)
958 size += ppkt->nameservers[i]->namelen + 1;
959 size += ppkt->nameservers[i]->data_len;
961 for (i = 0; i < ntohs (ppkt->s.arcount); i++)
963 size += ppkt->additional[i]->namelen + 1;
964 size += ppkt->additional[i]->data_len;
968 4 * ntohs (ppkt->s.qdcount) + 10 * (ntohs (ppkt->s.ancount) +
969 ntohs (ppkt->s.arcount) +
970 ntohs (ppkt->s.nscount));
972 struct dns_pkt *pkt = GNUNET_malloc (size);
973 char *pkt_c = (char *) pkt;
975 memcpy (&pkt->s, &ppkt->s, sizeof ppkt->s);
976 size_t idx = sizeof ppkt->s;
978 for (i = 0; i < ntohs (ppkt->s.qdcount); i++)
980 unparse_dns_name (&pkt_c[idx], ppkt->queries[i]->name,
981 ppkt->queries[i]->namelen);
982 idx += ppkt->queries[i]->namelen;
983 struct dns_query_line *d = (struct dns_query_line *) &pkt_c[idx];
985 d->class = ppkt->queries[i]->qclass;
986 d->type = ppkt->queries[i]->qtype;
987 idx += sizeof (struct dns_query_line);
990 for (i = 0; i < ntohs (ppkt->s.ancount); i++)
992 unparse_dns_name (&pkt_c[idx], ppkt->answers[i]->name,
993 ppkt->answers[i]->namelen);
994 idx += ppkt->answers[i]->namelen;
995 struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx];
997 r->type = ppkt->answers[i]->type;
998 r->class = ppkt->answers[i]->class;
999 r->ttl = ppkt->answers[i]->ttl;
1000 r->data_len = ppkt->answers[i]->data_len;
1001 idx += sizeof (struct dns_record_line);
1002 memcpy (&r->data, ppkt->answers[i]->data, ppkt->answers[i]->data_len);
1003 idx += ppkt->answers[i]->data_len;
1006 for (i = 0; i < ntohs (ppkt->s.nscount); i++)
1008 unparse_dns_name (&pkt_c[idx], ppkt->nameservers[i]->name,
1009 ppkt->nameservers[i]->namelen);
1010 idx += ppkt->nameservers[i]->namelen;
1011 struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx];
1013 r->type = ppkt->nameservers[i]->type;
1014 r->class = ppkt->nameservers[i]->class;
1015 r->ttl = ppkt->nameservers[i]->ttl;
1016 r->data_len = ppkt->nameservers[i]->data_len;
1017 idx += sizeof (struct dns_record_line);
1018 memcpy (&r->data, ppkt->nameservers[i]->data,
1019 ppkt->nameservers[i]->data_len);
1020 idx += ppkt->nameservers[i]->data_len;
1023 for (i = 0; i < ntohs (ppkt->s.arcount); i++)
1025 unparse_dns_name (&pkt_c[idx], ppkt->additional[i]->name,
1026 ppkt->additional[i]->namelen);
1027 idx += ppkt->additional[i]->namelen;
1028 struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx];
1030 r->type = ppkt->additional[i]->type;
1031 r->class = ppkt->additional[i]->class;
1032 r->ttl = ppkt->additional[i]->ttl;
1033 r->data_len = ppkt->additional[i]->data_len;
1034 idx += sizeof (struct dns_record_line);
1035 memcpy (&r->data, ppkt->additional[i]->data, ppkt->additional[i]->data_len);
1036 idx += ppkt->additional[i]->data_len;
1043 free_parsed_dns_packet (struct dns_pkt_parsed *ppkt)
1045 unsigned short qdcount = ntohs (ppkt->s.qdcount);
1046 unsigned short ancount = ntohs (ppkt->s.ancount);
1047 unsigned short nscount = ntohs (ppkt->s.nscount);
1048 unsigned short arcount = ntohs (ppkt->s.arcount);
1052 for (i = 0; i < qdcount; i++)
1054 GNUNET_free (ppkt->queries[i]->name);
1055 GNUNET_free (ppkt->queries[i]);
1057 GNUNET_free (ppkt->queries);
1058 for (i = 0; i < ancount; i++)
1060 GNUNET_free (ppkt->answers[i]->name);
1061 GNUNET_free (ppkt->answers[i]->data);
1062 GNUNET_free (ppkt->answers[i]);
1064 GNUNET_free (ppkt->answers);
1065 for (i = 0; i < nscount; i++)
1067 GNUNET_free (ppkt->nameservers[i]->name);
1068 GNUNET_free (ppkt->nameservers[i]->data);
1069 GNUNET_free (ppkt->nameservers[i]);
1071 GNUNET_free (ppkt->nameservers);
1072 for (i = 0; i < arcount; i++)
1074 GNUNET_free (ppkt->additional[i]->name);
1075 GNUNET_free (ppkt->additional[i]->data);
1076 GNUNET_free (ppkt->additional[i]);
1078 GNUNET_free (ppkt->additional);