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 * must not be changed if there is an error
470 * @param name name to write
471 * @return GNUNET_SYSERR if 'name' is invalid
472 * GNUNET_NO if 'name' did not fit
473 * GNUNET_OK if 'name' was added to 'dst'
487 return GNUNET_SYSERR;
489 if (start + strlen (name) + 2 > dst_len)
494 dot = strchr (name, '.');
499 if ( (len >= 64) || (len == 0) )
500 return GNUNET_NO; /* segment too long or empty */
501 dst[pos++] = (char) (uint8_t) len;
502 memcpy (&dst[pos], name, len);
504 name += len + 1; /* also skip dot */
507 dst[pos++] = '\0'; /* terminator */
514 * Add a DNS query to the UDP packet at the given location.
516 * @param dst where to write the query
517 * @param dst_len number of bytes in dst
518 * @param off pointer to offset where to write the query (increment by bytes used)
519 * must not be changed if there is an error
520 * @param query query to write
521 * @return GNUNET_SYSERR if 'query' is invalid
522 * GNUNET_NO if 'query' did not fit
523 * GNUNET_OK if 'query' was added to 'dst'
526 add_query (char *dst,
529 const struct GNUNET_DNSPARSER_Query *query)
532 struct query_line ql;
534 ret = add_name (dst, dst_len - sizeof (struct query_line), off, query->name);
535 if (ret != GNUNET_OK)
537 ql.type = htons (query->type);
538 ql.class = htons (query->class);
539 memcpy (&dst[*off], &ql, sizeof (ql));
540 (*off) += sizeof (ql);
546 * Add an MX record to the UDP packet at the given location.
548 * @param dst where to write the mx record
549 * @param dst_len number of bytes in dst
550 * @param off pointer to offset where to write the mx information (increment by bytes used);
551 * can also change if there was an error
552 * @param mx mx information to write
553 * @return GNUNET_SYSERR if 'mx' is invalid
554 * GNUNET_NO if 'mx' did not fit
555 * GNUNET_OK if 'mx' was added to 'dst'
561 const struct GNUNET_DNSPARSER_MxRecord *mx)
565 if (*off + sizeof (uint16_t) > dst_len)
567 mxpref = htons (mx->preference);
568 memcpy (&dst[*off], &mxpref, sizeof (mxpref));
569 (*off) += sizeof (mxpref);
570 return add_name (dst, dst_len, off, mx->mxhost);
575 * Add an SOA record to the UDP packet at the given location.
577 * @param dst where to write the SOA record
578 * @param dst_len number of bytes in dst
579 * @param off pointer to offset where to write the SOA information (increment by bytes used)
580 * can also change if there was an error
581 * @param soa SOA information to write
582 * @return GNUNET_SYSERR if 'soa' is invalid
583 * GNUNET_NO if 'soa' did not fit
584 * GNUNET_OK if 'soa' was added to 'dst'
590 const struct GNUNET_DNSPARSER_SoaRecord *soa)
595 if ( (GNUNET_OK != (ret = add_name (dst,
599 (GNUNET_OK != (ret = add_name (dst,
604 if (*off + sizeof (soa) > dst_len)
606 sd.serial = htonl (soa->serial);
607 sd.refresh = htonl (soa->refresh);
608 sd.retry = htonl (soa->retry);
609 sd.expire = htonl (soa->expire);
610 sd.minimum = htonl (soa->minimum_ttl);
611 memcpy (&dst[*off], &sd, sizeof (sd));
612 (*off) += sizeof (sd);
618 * Add a DNS record to the UDP packet at the given location.
620 * @param dst where to write the query
621 * @param dst_len number of bytes in dst
622 * @param off pointer to offset where to write the query (increment by bytes used)
623 * must not be changed if there is an error
624 * @param record record to write
625 * @return GNUNET_SYSERR if 'record' is invalid
626 * GNUNET_NO if 'record' did not fit
627 * GNUNET_OK if 'record' was added to 'dst'
630 add_record (char *dst,
633 const struct GNUNET_DNSPARSER_Record *record)
638 struct record_line rl;
641 ret = add_name (dst, dst_len - sizeof (struct record_line), off, record->name);
642 if (ret != GNUNET_OK)
644 /* '*off' is now the position where we will need to write the record line */
646 pos = *off + sizeof (struct record_line);
647 switch (record->type)
649 case GNUNET_DNSPARSER_TYPE_MX:
650 ret = add_mx (dst, dst_len, &pos, record->data.mx);
652 case GNUNET_DNSPARSER_TYPE_SOA:
653 ret = add_soa (dst, dst_len, &pos, record->data.soa);
655 case GNUNET_DNSPARSER_TYPE_NS:
656 case GNUNET_DNSPARSER_TYPE_CNAME:
657 case GNUNET_DNSPARSER_TYPE_PTR:
658 ret = add_name (dst, dst_len, &pos, record->data.hostname);
661 if (pos + record->data.raw.data_len > dst_len)
666 memcpy (&dst[pos], record->data.raw.data, record->data.raw.data_len);
667 pos += record->data.raw.data_len;
671 if (ret != GNUNET_OK)
677 if (pos - (*off + sizeof (struct record_line)) > UINT16_MAX)
679 /* record data too long */
683 rl.type = htons (record->type);
684 rl.class = htons (record->class);
685 rl.ttl = htonl (GNUNET_TIME_absolute_get_remaining (record->expiration_time).rel_value / 1000); /* in seconds */
686 rl.data_len = htons ((uint16_t) (pos - (*off + sizeof (struct record_line))));
687 memcpy (&dst[*off], &rl, sizeof (struct record_line));
694 * Given a DNS packet, generate the corresponding UDP payload.
695 * Note that we do not attempt to pack the strings with pointers
696 * as this would complicate the code and this is about being
697 * simple and secure, not fast, fancy and broken like bind.
699 * @param p packet to pack
700 * @param max maximum allowed size for the resulting UDP payload
701 * @param buf set to a buffer with the packed message
702 * @param buf_length set to the length of buf
703 * @return GNUNET_SYSERR if 'p' is invalid
704 * GNUNET_NO if 'p' was truncated (but there is still a result in 'buf')
705 * GNUNET_OK if 'p' was packed completely into '*buf'
708 GNUNET_DNSPARSER_pack (const struct GNUNET_DNSPARSER_Packet *p,
713 struct dns_header dns;
720 if ( (p->num_queries > UINT16_MAX) ||
721 (p->num_answers > UINT16_MAX) ||
722 (p->num_authority_records > UINT16_MAX) ||
723 (p->num_additional_records > UINT16_MAX) )
724 return GNUNET_SYSERR;
726 dns.flags = p->flags;
727 dns.query_count = htons (p->num_queries);
728 dns.answer_rcount = htons (p->num_answers);
729 dns.authority_rcount = htons (p->num_authority_records);
730 dns.additional_rcount = htons (p->num_additional_records);
732 off = sizeof (struct dns_header);
734 for (i=0;i<p->num_queries;i++)
736 ret = add_query (tmp, sizeof (tmp), &off, &p->queries[i]);
737 if (GNUNET_SYSERR == ret)
738 return GNUNET_SYSERR;
739 if (GNUNET_NO == ret)
741 dns.query_count = htons ((uint16_t) (i-1));
746 for (i=0;i<p->num_answers;i++)
748 ret = add_record (tmp, sizeof (tmp), &off, &p->answers[i]);
749 if (GNUNET_SYSERR == ret)
750 return GNUNET_SYSERR;
751 if (GNUNET_NO == ret)
753 dns.answer_rcount = htons ((uint16_t) (i-1));
758 for (i=0;i<p->num_authority_records;i++)
760 ret = add_record (tmp, sizeof (tmp), &off, &p->authority_records[i]);
761 if (GNUNET_SYSERR == ret)
762 return GNUNET_SYSERR;
763 if (GNUNET_NO == ret)
765 dns.authority_rcount = htons ((uint16_t) (i-1));
770 for (i=0;i<p->num_additional_records;i++)
772 ret = add_record (tmp, sizeof (tmp), &off, &p->additional_records[i]);
773 if (GNUNET_SYSERR == ret)
774 return GNUNET_SYSERR;
775 if (GNUNET_NO == ret)
777 dns.additional_rcount = htons (i-1);
783 if (GNUNET_YES == trc)
784 dns.flags.message_truncated = 1;
785 memcpy (tmp, &dns, sizeof (struct dns_header));
787 *buf = GNUNET_malloc (off);
789 memcpy (*buf, tmp, off);
822 /* legacy code follows */
825 * Parse a name from DNS to a normal .-delimited, 0-terminated string.
827 * @param d The destination of the name. Should have at least 255 bytes allocated.
828 * @param src The DNS-Packet
829 * @param idx The offset inside the Packet from which on the name should be read
830 * @returns The offset of the first unparsed byte (the byte right behind the name)
833 parse_dns_name (char *d, const unsigned char *src, unsigned short idx)
837 int len = src[idx++];
842 { /* Compressed name, offset in this and the next octet */
843 unsigned short offset = ((len & 0x3F) << 8) | src[idx++];
845 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 */
848 memcpy (dest, src + idx, len);
863 * Parse a complete DNS-Record from raw DNS-data to a struct dns_record
865 * @param data The DNS-data
866 * @param dst Pointer to count pointers; individual pointers will be allocated
867 * @param count Number of records to parse
868 * @param idx The offset inside the Packet from which on the name should be read
869 * @returns The offset of the first unparsed byte (the byte right behind the last record)
871 static unsigned short
872 parse_dns_record (unsigned char *data, /*{{{ */
873 struct dns_record **dst, unsigned short count,
879 for (i = 0; i < count; i++)
881 dst[i] = GNUNET_malloc (sizeof (struct dns_record));
882 dst[i]->name = alloca (255); // see RFC1035, no name can be longer than this.
883 char *name = dst[i]->name;
885 _idx = parse_dns_name (name, data, idx);
886 dst[i]->namelen = _idx - idx;
888 dst[i]->name = GNUNET_malloc (dst[i]->namelen);
889 memcpy (dst[i]->name, name, dst[i]->namelen);
893 dst[i]->type = *((unsigned short *) (data + idx));
895 dst[i]->class = *((unsigned short *) (data + idx));
897 dst[i]->ttl = *((unsigned int *) (data + idx));
899 dst[i]->data_len = *((unsigned short *) (data + idx));
901 dst[i]->data = GNUNET_malloc (ntohs (dst[i]->data_len));
902 memcpy (dst[i]->data, data + idx, ntohs (dst[i]->data_len));
903 idx += ntohs (dst[i]->data_len);
909 * Parse a raw DNS-Packet into an usable struct
911 struct dns_pkt_parsed *
912 parse_dns_packet (struct dns_pkt *pkt)
914 struct dns_pkt_parsed *ppkt = GNUNET_malloc (sizeof (struct dns_pkt_parsed));
916 memcpy (&ppkt->s, &pkt->s, sizeof pkt->s);
918 unsigned short qdcount = ntohs (ppkt->s.qdcount);
919 unsigned short ancount = ntohs (ppkt->s.ancount);
920 unsigned short nscount = ntohs (ppkt->s.nscount);
921 unsigned short arcount = ntohs (ppkt->s.arcount);
923 ppkt->queries = GNUNET_malloc (qdcount * sizeof (struct dns_query *));
924 ppkt->answers = GNUNET_malloc (ancount * sizeof (struct dns_record *));
925 ppkt->nameservers = GNUNET_malloc (nscount * sizeof (struct dns_record *));
926 ppkt->additional = GNUNET_malloc (arcount * sizeof (struct dns_record *));
928 unsigned short idx = 0, _idx; /* This keeps track how far we have parsed the data */
930 /* Parse the Query */
933 for (i = 0; i < qdcount; i++)
935 ppkt->queries[i] = GNUNET_malloc (sizeof (struct dns_query));
936 char *name = alloca (255); /* see RFC1035, it can't be more than this. */
938 _idx = parse_dns_name (name, pkt->data, idx);
939 ppkt->queries[i]->namelen = _idx - idx;
942 ppkt->queries[i]->name = GNUNET_malloc (ppkt->queries[i]->namelen);
943 memcpy (ppkt->queries[i]->name, name, ppkt->queries[i]->namelen);
945 ppkt->queries[i]->qtype = *((unsigned short *) (pkt->data + idx));
947 ppkt->queries[i]->qclass = *((unsigned short *) (pkt->data + idx));
951 idx = parse_dns_record (pkt->data, ppkt->answers, ancount, idx);
952 idx = parse_dns_record (pkt->data, ppkt->nameservers, nscount, idx);
953 idx = parse_dns_record (pkt->data, ppkt->additional, arcount, idx);
958 unparse_dns_name (char *dest, char *src, size_t len)
966 while (*src != '.' && *src != 0)
983 unparse_dns_packet (struct dns_pkt_parsed *ppkt)
985 size_t size = sizeof (struct dns_pkt) - 1;
988 for (i = 0; i < ntohs (ppkt->s.qdcount); i++)
989 size += ppkt->queries[i]->namelen + 1;
991 for (i = 0; i < ntohs (ppkt->s.ancount); i++)
993 size += ppkt->answers[i]->namelen + 1;
994 size += ppkt->answers[i]->data_len;
996 for (i = 0; i < ntohs (ppkt->s.nscount); i++)
998 size += ppkt->nameservers[i]->namelen + 1;
999 size += ppkt->nameservers[i]->data_len;
1001 for (i = 0; i < ntohs (ppkt->s.arcount); i++)
1003 size += ppkt->additional[i]->namelen + 1;
1004 size += ppkt->additional[i]->data_len;
1008 4 * ntohs (ppkt->s.qdcount) + 10 * (ntohs (ppkt->s.ancount) +
1009 ntohs (ppkt->s.arcount) +
1010 ntohs (ppkt->s.nscount));
1012 struct dns_pkt *pkt = GNUNET_malloc (size);
1013 char *pkt_c = (char *) pkt;
1015 memcpy (&pkt->s, &ppkt->s, sizeof ppkt->s);
1016 size_t idx = sizeof ppkt->s;
1018 for (i = 0; i < ntohs (ppkt->s.qdcount); i++)
1020 unparse_dns_name (&pkt_c[idx], ppkt->queries[i]->name,
1021 ppkt->queries[i]->namelen);
1022 idx += ppkt->queries[i]->namelen;
1023 struct dns_query_line *d = (struct dns_query_line *) &pkt_c[idx];
1025 d->class = ppkt->queries[i]->qclass;
1026 d->type = ppkt->queries[i]->qtype;
1027 idx += sizeof (struct dns_query_line);
1030 for (i = 0; i < ntohs (ppkt->s.ancount); i++)
1032 unparse_dns_name (&pkt_c[idx], ppkt->answers[i]->name,
1033 ppkt->answers[i]->namelen);
1034 idx += ppkt->answers[i]->namelen;
1035 struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx];
1037 r->type = ppkt->answers[i]->type;
1038 r->class = ppkt->answers[i]->class;
1039 r->ttl = ppkt->answers[i]->ttl;
1040 r->data_len = ppkt->answers[i]->data_len;
1041 idx += sizeof (struct dns_record_line);
1042 memcpy (&r->data, ppkt->answers[i]->data, ppkt->answers[i]->data_len);
1043 idx += ppkt->answers[i]->data_len;
1046 for (i = 0; i < ntohs (ppkt->s.nscount); i++)
1048 unparse_dns_name (&pkt_c[idx], ppkt->nameservers[i]->name,
1049 ppkt->nameservers[i]->namelen);
1050 idx += ppkt->nameservers[i]->namelen;
1051 struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx];
1053 r->type = ppkt->nameservers[i]->type;
1054 r->class = ppkt->nameservers[i]->class;
1055 r->ttl = ppkt->nameservers[i]->ttl;
1056 r->data_len = ppkt->nameservers[i]->data_len;
1057 idx += sizeof (struct dns_record_line);
1058 memcpy (&r->data, ppkt->nameservers[i]->data,
1059 ppkt->nameservers[i]->data_len);
1060 idx += ppkt->nameservers[i]->data_len;
1063 for (i = 0; i < ntohs (ppkt->s.arcount); i++)
1065 unparse_dns_name (&pkt_c[idx], ppkt->additional[i]->name,
1066 ppkt->additional[i]->namelen);
1067 idx += ppkt->additional[i]->namelen;
1068 struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx];
1070 r->type = ppkt->additional[i]->type;
1071 r->class = ppkt->additional[i]->class;
1072 r->ttl = ppkt->additional[i]->ttl;
1073 r->data_len = ppkt->additional[i]->data_len;
1074 idx += sizeof (struct dns_record_line);
1075 memcpy (&r->data, ppkt->additional[i]->data, ppkt->additional[i]->data_len);
1076 idx += ppkt->additional[i]->data_len;
1083 free_parsed_dns_packet (struct dns_pkt_parsed *ppkt)
1085 unsigned short qdcount = ntohs (ppkt->s.qdcount);
1086 unsigned short ancount = ntohs (ppkt->s.ancount);
1087 unsigned short nscount = ntohs (ppkt->s.nscount);
1088 unsigned short arcount = ntohs (ppkt->s.arcount);
1092 for (i = 0; i < qdcount; i++)
1094 GNUNET_free (ppkt->queries[i]->name);
1095 GNUNET_free (ppkt->queries[i]);
1097 GNUNET_free (ppkt->queries);
1098 for (i = 0; i < ancount; i++)
1100 GNUNET_free (ppkt->answers[i]->name);
1101 GNUNET_free (ppkt->answers[i]->data);
1102 GNUNET_free (ppkt->answers[i]);
1104 GNUNET_free (ppkt->answers);
1105 for (i = 0; i < nscount; i++)
1107 GNUNET_free (ppkt->nameservers[i]->name);
1108 GNUNET_free (ppkt->nameservers[i]->data);
1109 GNUNET_free (ppkt->nameservers[i]);
1111 GNUNET_free (ppkt->nameservers);
1112 for (i = 0; i < arcount; i++)
1114 GNUNET_free (ppkt->additional[i]->name);
1115 GNUNET_free (ppkt->additional[i]->data);
1116 GNUNET_free (ppkt->additional[i]);
1118 GNUNET_free (ppkt->additional);