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
28 #include "gnunet_dnsparser_lib.h"
32 GNUNET_NETWORK_STRUCT_BEGIN
35 uint16_t id GNUNET_PACKED;
36 struct GNUNET_DNSPARSER_Flags flags GNUNET_PACKED;
37 uint16_t query_count GNUNET_PACKED; // number of questions
38 uint16_t answer_rcount GNUNET_PACKED; // number of answers
39 uint16_t authority_rcount GNUNET_PACKED; // number of authority-records
40 uint16_t additional_rcount GNUNET_PACKED; // number of additional records
42 GNUNET_NETWORK_STRUCT_END
46 * Parse a DNS query entry.
48 * @param udp_payload entire UDP payload
49 * @param udp_payload_length length of udp_payload
50 * @param off pointer to the offset of the query to parse in the udp_payload (to be
51 * incremented by the size of the query)
52 * @param q where to write the query information
53 * @return GNUNET_OK on success, GNUNET_SYSERR if the query is malformed
56 parse_query (const char *udp_payload,
57 size_t udp_payload_length,
59 struct GNUNET_DNSPARSER_Query *q)
66 * Parse a DNS record entry.
68 * @param udp_payload entire UDP payload
69 * @param udp_payload_length length of udp_payload
70 * @param off pointer to the offset of the record to parse in the udp_payload (to be
71 * incremented by the size of the record)
72 * @param r where to write the record information
73 * @return GNUNET_OK on success, GNUNET_SYSERR if the record is malformed
76 parse_record (const char *udp_payload,
77 size_t udp_payload_length,
79 struct GNUNET_DNSPARSER_Record *r)
87 * Parse a UDP payload of a DNS packet in to a nice struct for further
88 * processing and manipulation.
90 * @param udp_payload wire-format of the DNS packet
91 * @param udp_payload_length number of bytes in udp_payload
92 * @return NULL on error, otherwise the parsed packet
94 struct GNUNET_DNSPARSER_Packet *
95 GNUNET_DNSPARSER_parse (const char *udp_payload,
96 size_t udp_payload_length)
98 struct GNUNET_DNSPARSER_Packet *p;
99 const struct dns_header *dns;
104 if (udp_payload_length < sizeof (struct dns_header))
106 dns = (const struct dns_header *) udp_payload;
107 off = sizeof (struct dns_header);
108 p = GNUNET_malloc (sizeof (struct GNUNET_DNSPARSER_Packet));
109 p->flags = dns->flags;
111 n = ntohs (dns->query_count);
114 p->queries = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Query));
118 parse_query (udp_payload,
124 n = ntohs (dns->answer_rcount);
127 p->answers = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record));
131 parse_record (udp_payload,
137 n = ntohs (dns->authority_rcount);
140 p->authority_records = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record));
141 p->num_authority_records = n;
144 parse_record (udp_payload,
147 &p->authority_records[i]))
150 n = ntohs (dns->additional_rcount);
153 p->additional_records = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record));
154 p->num_additional_records = n;
157 parse_record (udp_payload,
160 &p->additional_records[i]))
165 GNUNET_DNSPARSER_free_packet (p);
171 * Free memory taken by a packet.
173 * @param p packet to free
176 GNUNET_DNSPARSER_free_packet (struct GNUNET_DNSPARSER_Packet *p)
180 for (i=0;i<p->num_queries;i++)
181 GNUNET_free_non_null (p->queries[i].name);
182 GNUNET_free_non_null (p->queries);
183 for (i=0;i<p->num_answers;i++)
185 GNUNET_free_non_null (p->answers[i].name);
186 GNUNET_free_non_null (p->answers[i].data);
188 GNUNET_free_non_null (p->answers);
189 for (i=0;i<p->num_authority_records;i++)
191 GNUNET_free_non_null (p->authority_records[i].name);
192 GNUNET_free_non_null (p->authority_records[i].data);
194 GNUNET_free_non_null (p->authority_records);
195 for (i=0;i<p->num_additional_records;i++)
197 GNUNET_free_non_null (p->additional_records[i].name);
198 GNUNET_free_non_null (p->additional_records[i].data);
200 GNUNET_free_non_null (p->additional_records);
206 * Given a DNS packet, generate the corresponding UDP payload.
208 * @param p packet to pack
209 * @param buf set to a buffer with the packed message
210 * @param buf_length set to the length of buf
211 * @return GNUNET_SYSERR if 'p' is invalid
212 * GNUNET_NO if 'p' was truncated (but there is still a result in 'buf')
213 * GNUNET_OK if 'p' was packed completely into '*buf'
216 GNUNET_DNSPARSER_pack (struct GNUNET_DNSPARSER_Packet *p,
220 // FIXME: not implemented
222 return GNUNET_SYSERR;
228 /* legacy code follows */
231 * Parse a name from DNS to a normal .-delimited, 0-terminated string.
233 * @param d The destination of the name. Should have at least 255 bytes allocated.
234 * @param src The DNS-Packet
235 * @param idx The offset inside the Packet from which on the name should be read
236 * @returns The offset of the first unparsed byte (the byte right behind the name)
239 parse_dns_name (char *d, const unsigned char *src, unsigned short idx)
243 int len = src[idx++];
248 { /* Compressed name, offset in this and the next octet */
249 unsigned short offset = ((len & 0x3F) << 8) | src[idx++];
251 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 */
254 memcpy (dest, src + idx, len);
269 * Parse a complete DNS-Record from raw DNS-data to a struct dns_record
271 * @param data The DNS-data
272 * @param dst Pointer to count pointers; individual pointers will be allocated
273 * @param count Number of records to parse
274 * @param idx The offset inside the Packet from which on the name should be read
275 * @returns The offset of the first unparsed byte (the byte right behind the last record)
277 static unsigned short
278 parse_dns_record (unsigned char *data, /*{{{ */
279 struct dns_record **dst, unsigned short count,
285 for (i = 0; i < count; i++)
287 dst[i] = GNUNET_malloc (sizeof (struct dns_record));
288 dst[i]->name = alloca (255); // see RFC1035, no name can be longer than this.
289 char *name = dst[i]->name;
291 _idx = parse_dns_name (name, data, idx);
292 dst[i]->namelen = _idx - idx;
294 dst[i]->name = GNUNET_malloc (dst[i]->namelen);
295 memcpy (dst[i]->name, name, dst[i]->namelen);
299 dst[i]->type = *((unsigned short *) (data + idx));
301 dst[i]->class = *((unsigned short *) (data + idx));
303 dst[i]->ttl = *((unsigned int *) (data + idx));
305 dst[i]->data_len = *((unsigned short *) (data + idx));
307 dst[i]->data = GNUNET_malloc (ntohs (dst[i]->data_len));
308 memcpy (dst[i]->data, data + idx, ntohs (dst[i]->data_len));
309 idx += ntohs (dst[i]->data_len);
315 * Parse a raw DNS-Packet into an usable struct
317 struct dns_pkt_parsed *
318 parse_dns_packet (struct dns_pkt *pkt)
320 struct dns_pkt_parsed *ppkt = GNUNET_malloc (sizeof (struct dns_pkt_parsed));
322 memcpy (&ppkt->s, &pkt->s, sizeof pkt->s);
324 unsigned short qdcount = ntohs (ppkt->s.qdcount);
325 unsigned short ancount = ntohs (ppkt->s.ancount);
326 unsigned short nscount = ntohs (ppkt->s.nscount);
327 unsigned short arcount = ntohs (ppkt->s.arcount);
329 ppkt->queries = GNUNET_malloc (qdcount * sizeof (struct dns_query *));
330 ppkt->answers = GNUNET_malloc (ancount * sizeof (struct dns_record *));
331 ppkt->nameservers = GNUNET_malloc (nscount * sizeof (struct dns_record *));
332 ppkt->additional = GNUNET_malloc (arcount * sizeof (struct dns_record *));
334 unsigned short idx = 0, _idx; /* This keeps track how far we have parsed the data */
336 /* Parse the Query */
339 for (i = 0; i < qdcount; i++)
341 ppkt->queries[i] = GNUNET_malloc (sizeof (struct dns_query));
342 char *name = alloca (255); /* see RFC1035, it can't be more than this. */
344 _idx = parse_dns_name (name, pkt->data, idx);
345 ppkt->queries[i]->namelen = _idx - idx;
348 ppkt->queries[i]->name = GNUNET_malloc (ppkt->queries[i]->namelen);
349 memcpy (ppkt->queries[i]->name, name, ppkt->queries[i]->namelen);
351 ppkt->queries[i]->qtype = *((unsigned short *) (pkt->data + idx));
353 ppkt->queries[i]->qclass = *((unsigned short *) (pkt->data + idx));
357 idx = parse_dns_record (pkt->data, ppkt->answers, ancount, idx);
358 idx = parse_dns_record (pkt->data, ppkt->nameservers, nscount, idx);
359 idx = parse_dns_record (pkt->data, ppkt->additional, arcount, idx);
364 unparse_dns_name (char *dest, char *src, size_t len)
372 while (*src != '.' && *src != 0)
389 unparse_dns_packet (struct dns_pkt_parsed *ppkt)
391 size_t size = sizeof (struct dns_pkt) - 1;
394 for (i = 0; i < ntohs (ppkt->s.qdcount); i++)
395 size += ppkt->queries[i]->namelen + 1;
397 for (i = 0; i < ntohs (ppkt->s.ancount); i++)
399 size += ppkt->answers[i]->namelen + 1;
400 size += ppkt->answers[i]->data_len;
402 for (i = 0; i < ntohs (ppkt->s.nscount); i++)
404 size += ppkt->nameservers[i]->namelen + 1;
405 size += ppkt->nameservers[i]->data_len;
407 for (i = 0; i < ntohs (ppkt->s.arcount); i++)
409 size += ppkt->additional[i]->namelen + 1;
410 size += ppkt->additional[i]->data_len;
414 4 * ntohs (ppkt->s.qdcount) + 10 * (ntohs (ppkt->s.ancount) +
415 ntohs (ppkt->s.arcount) +
416 ntohs (ppkt->s.nscount));
418 struct dns_pkt *pkt = GNUNET_malloc (size);
419 char *pkt_c = (char *) pkt;
421 memcpy (&pkt->s, &ppkt->s, sizeof ppkt->s);
422 size_t idx = sizeof ppkt->s;
424 for (i = 0; i < ntohs (ppkt->s.qdcount); i++)
426 unparse_dns_name (&pkt_c[idx], ppkt->queries[i]->name,
427 ppkt->queries[i]->namelen);
428 idx += ppkt->queries[i]->namelen;
429 struct dns_query_line *d = (struct dns_query_line *) &pkt_c[idx];
431 d->class = ppkt->queries[i]->qclass;
432 d->type = ppkt->queries[i]->qtype;
433 idx += sizeof (struct dns_query_line);
436 for (i = 0; i < ntohs (ppkt->s.ancount); i++)
438 unparse_dns_name (&pkt_c[idx], ppkt->answers[i]->name,
439 ppkt->answers[i]->namelen);
440 idx += ppkt->answers[i]->namelen;
441 struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx];
443 r->type = ppkt->answers[i]->type;
444 r->class = ppkt->answers[i]->class;
445 r->ttl = ppkt->answers[i]->ttl;
446 r->data_len = ppkt->answers[i]->data_len;
447 idx += sizeof (struct dns_record_line);
448 memcpy (&r->data, ppkt->answers[i]->data, ppkt->answers[i]->data_len);
449 idx += ppkt->answers[i]->data_len;
452 for (i = 0; i < ntohs (ppkt->s.nscount); i++)
454 unparse_dns_name (&pkt_c[idx], ppkt->nameservers[i]->name,
455 ppkt->nameservers[i]->namelen);
456 idx += ppkt->nameservers[i]->namelen;
457 struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx];
459 r->type = ppkt->nameservers[i]->type;
460 r->class = ppkt->nameservers[i]->class;
461 r->ttl = ppkt->nameservers[i]->ttl;
462 r->data_len = ppkt->nameservers[i]->data_len;
463 idx += sizeof (struct dns_record_line);
464 memcpy (&r->data, ppkt->nameservers[i]->data,
465 ppkt->nameservers[i]->data_len);
466 idx += ppkt->nameservers[i]->data_len;
469 for (i = 0; i < ntohs (ppkt->s.arcount); i++)
471 unparse_dns_name (&pkt_c[idx], ppkt->additional[i]->name,
472 ppkt->additional[i]->namelen);
473 idx += ppkt->additional[i]->namelen;
474 struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx];
476 r->type = ppkt->additional[i]->type;
477 r->class = ppkt->additional[i]->class;
478 r->ttl = ppkt->additional[i]->ttl;
479 r->data_len = ppkt->additional[i]->data_len;
480 idx += sizeof (struct dns_record_line);
481 memcpy (&r->data, ppkt->additional[i]->data, ppkt->additional[i]->data_len);
482 idx += ppkt->additional[i]->data_len;
489 free_parsed_dns_packet (struct dns_pkt_parsed *ppkt)
491 unsigned short qdcount = ntohs (ppkt->s.qdcount);
492 unsigned short ancount = ntohs (ppkt->s.ancount);
493 unsigned short nscount = ntohs (ppkt->s.nscount);
494 unsigned short arcount = ntohs (ppkt->s.arcount);
498 for (i = 0; i < qdcount; i++)
500 GNUNET_free (ppkt->queries[i]->name);
501 GNUNET_free (ppkt->queries[i]);
503 GNUNET_free (ppkt->queries);
504 for (i = 0; i < ancount; i++)
506 GNUNET_free (ppkt->answers[i]->name);
507 GNUNET_free (ppkt->answers[i]->data);
508 GNUNET_free (ppkt->answers[i]);
510 GNUNET_free (ppkt->answers);
511 for (i = 0; i < nscount; i++)
513 GNUNET_free (ppkt->nameservers[i]->name);
514 GNUNET_free (ppkt->nameservers[i]->data);
515 GNUNET_free (ppkt->nameservers[i]);
517 GNUNET_free (ppkt->nameservers);
518 for (i = 0; i < arcount; i++)
520 GNUNET_free (ppkt->additional[i]->name);
521 GNUNET_free (ppkt->additional[i]->data);
522 GNUNET_free (ppkt->additional[i]);
524 GNUNET_free (ppkt->additional);