c2fd1671de835b70d7b77a1f7edcdc5b3894b5d6
[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  */
26
27 #include "platform.h"
28 #include "gnunet_dnsparser_lib.h"
29
30 /**
31  * Parse a name from DNS to a normal .-delimited, 0-terminated string.
32  *
33  * @param d The destination of the name. Should have at least 255 bytes allocated.
34  * @param src The DNS-Packet
35  * @param idx The offset inside the Packet from which on the name should be read
36  * @returns The offset of the first unparsed byte (the byte right behind the name)
37  */
38 static unsigned int
39 parse_dns_name (char *d, const unsigned char *src, unsigned short idx)
40 {                               /*{{{ */
41   char *dest = d;
42
43   int len = src[idx++];
44
45   while (len != 0)
46   {
47     if (len & 0xC0)
48     {                           /* Compressed name, offset in this and the next octet */
49       unsigned short offset = ((len & 0x3F) << 8) | src[idx++];
50
51       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 */
52       return idx;
53     }
54     memcpy (dest, src + idx, len);
55     idx += len;
56     dest += len;
57     *dest = '.';
58     dest++;
59     len = src[idx++];
60   };
61   *dest = 0;
62
63   return idx;
64 }
65
66 /*}}}*/
67
68 /**
69  * Parse a complete DNS-Record from raw DNS-data to a struct dns_record
70  *
71  * @param data The DNS-data
72  * @param dst Pointer to count pointers; individual pointers will be allocated
73  * @param count Number of records to parse
74  * @param idx The offset inside the Packet from which on the name should be read
75  * @returns The offset of the first unparsed byte (the byte right behind the last record)
76  */
77 static unsigned short
78 parse_dns_record (unsigned char *data,  /*{{{ */
79                   struct dns_record **dst, unsigned short count,
80                   unsigned short idx)
81 {
82   int i;
83   unsigned short _idx;
84
85   for (i = 0; i < count; i++)
86   {
87     dst[i] = GNUNET_malloc (sizeof (struct dns_record));
88     dst[i]->name = alloca (255);        // see RFC1035, no name can be longer than this.
89     char *name = dst[i]->name;
90
91     _idx = parse_dns_name (name, data, idx);
92     dst[i]->namelen = _idx - idx;
93
94     dst[i]->name = GNUNET_malloc (dst[i]->namelen);
95     memcpy (dst[i]->name, name, dst[i]->namelen);
96
97     idx = _idx;
98
99     dst[i]->type = *((unsigned short *) (data + idx));
100     idx += 2;
101     dst[i]->class = *((unsigned short *) (data + idx));
102     idx += 2;
103     dst[i]->ttl = *((unsigned int *) (data + idx));
104     idx += 4;
105     dst[i]->data_len = *((unsigned short *) (data + idx));
106     idx += 2;
107     dst[i]->data = GNUNET_malloc (ntohs (dst[i]->data_len));
108     memcpy (dst[i]->data, data + idx, ntohs (dst[i]->data_len));
109     idx += ntohs (dst[i]->data_len);
110   }
111   return idx;
112 }                               /*}}} */
113
114 /**
115  * Parse a raw DNS-Packet into an usable struct
116  */
117 struct dns_pkt_parsed *
118 parse_dns_packet (struct dns_pkt *pkt)
119 {                               /*{{{ */
120   struct dns_pkt_parsed *ppkt = GNUNET_malloc (sizeof (struct dns_pkt_parsed));
121
122   memcpy (&ppkt->s, &pkt->s, sizeof pkt->s);
123
124   unsigned short qdcount = ntohs (ppkt->s.qdcount);
125   unsigned short ancount = ntohs (ppkt->s.ancount);
126   unsigned short nscount = ntohs (ppkt->s.nscount);
127   unsigned short arcount = ntohs (ppkt->s.arcount);
128
129   ppkt->queries = GNUNET_malloc (qdcount * sizeof (struct dns_query *));
130   ppkt->answers = GNUNET_malloc (ancount * sizeof (struct dns_record *));
131   ppkt->nameservers = GNUNET_malloc (nscount * sizeof (struct dns_record *));
132   ppkt->additional = GNUNET_malloc (arcount * sizeof (struct dns_record *));
133
134   unsigned short idx = 0, _idx; /* This keeps track how far we have parsed the data */
135
136   /* Parse the Query */
137   int i;
138
139   for (i = 0; i < qdcount; i++)
140   {                             /*{{{ */
141     ppkt->queries[i] = GNUNET_malloc (sizeof (struct dns_query));
142     char *name = alloca (255);  /* see RFC1035, it can't be more than this. */
143
144     _idx = parse_dns_name (name, pkt->data, idx);
145     ppkt->queries[i]->namelen = _idx - idx;
146     idx = _idx;
147
148     ppkt->queries[i]->name = GNUNET_malloc (ppkt->queries[i]->namelen);
149     memcpy (ppkt->queries[i]->name, name, ppkt->queries[i]->namelen);
150
151     ppkt->queries[i]->qtype = *((unsigned short *) (pkt->data + idx));
152     idx += 2;
153     ppkt->queries[i]->qclass = *((unsigned short *) (pkt->data + idx));
154     idx += 2;
155   }
156   /*}}} */
157   idx = parse_dns_record (pkt->data, ppkt->answers, ancount, idx);
158   idx = parse_dns_record (pkt->data, ppkt->nameservers, nscount, idx);
159   idx = parse_dns_record (pkt->data, ppkt->additional, arcount, idx);
160   return ppkt;
161 }                               /*}}} */
162
163 static void
164 unparse_dns_name (char *dest, char *src, size_t len)
165 {
166   char *b = dest;
167   char cnt = 0;
168
169   dest++;
170   while (*src != 0)
171   {
172     while (*src != '.' && *src != 0)
173     {
174       *dest = *src;
175       src++;
176       dest++;
177       cnt++;
178     }
179     *b = cnt;
180     cnt = 0;
181     b = dest;
182     dest++;
183     src++;
184   }
185   *b = 0;
186 }
187
188 struct dns_pkt *
189 unparse_dns_packet (struct dns_pkt_parsed *ppkt)
190 {
191   size_t size = sizeof (struct dns_pkt) - 1;
192   int i;
193
194   for (i = 0; i < ntohs (ppkt->s.qdcount); i++)
195     size += ppkt->queries[i]->namelen + 1;
196
197   for (i = 0; i < ntohs (ppkt->s.ancount); i++)
198   {
199     size += ppkt->answers[i]->namelen + 1;
200     size += ppkt->answers[i]->data_len;
201   }
202   for (i = 0; i < ntohs (ppkt->s.nscount); i++)
203   {
204     size += ppkt->nameservers[i]->namelen + 1;
205     size += ppkt->nameservers[i]->data_len;
206   }
207   for (i = 0; i < ntohs (ppkt->s.arcount); i++)
208   {
209     size += ppkt->additional[i]->namelen + 1;
210     size += ppkt->additional[i]->data_len;
211   }
212
213   size +=
214       4 * ntohs (ppkt->s.qdcount) + 10 * (ntohs (ppkt->s.ancount) +
215                                           ntohs (ppkt->s.arcount) +
216                                           ntohs (ppkt->s.nscount));
217
218   struct dns_pkt *pkt = GNUNET_malloc (size);
219   char *pkt_c = (char *) pkt;
220
221   memcpy (&pkt->s, &ppkt->s, sizeof ppkt->s);
222   size_t idx = sizeof ppkt->s;
223
224   for (i = 0; i < ntohs (ppkt->s.qdcount); i++)
225   {
226     unparse_dns_name (&pkt_c[idx], ppkt->queries[i]->name,
227                       ppkt->queries[i]->namelen);
228     idx += ppkt->queries[i]->namelen;
229     struct dns_query_line *d = (struct dns_query_line *) &pkt_c[idx];
230
231     d->class = ppkt->queries[i]->qclass;
232     d->type = ppkt->queries[i]->qtype;
233     idx += sizeof (struct dns_query_line);
234   }
235
236   for (i = 0; i < ntohs (ppkt->s.ancount); i++)
237   {
238     unparse_dns_name (&pkt_c[idx], ppkt->answers[i]->name,
239                       ppkt->answers[i]->namelen);
240     idx += ppkt->answers[i]->namelen;
241     struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx];
242
243     r->type = ppkt->answers[i]->type;
244     r->class = ppkt->answers[i]->class;
245     r->ttl = ppkt->answers[i]->ttl;
246     r->data_len = ppkt->answers[i]->data_len;
247     idx += sizeof (struct dns_record_line);
248     memcpy (&r->data, ppkt->answers[i]->data, ppkt->answers[i]->data_len);
249     idx += ppkt->answers[i]->data_len;
250   }
251
252   for (i = 0; i < ntohs (ppkt->s.nscount); i++)
253   {
254     unparse_dns_name (&pkt_c[idx], ppkt->nameservers[i]->name,
255                       ppkt->nameservers[i]->namelen);
256     idx += ppkt->nameservers[i]->namelen;
257     struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx];
258
259     r->type = ppkt->nameservers[i]->type;
260     r->class = ppkt->nameservers[i]->class;
261     r->ttl = ppkt->nameservers[i]->ttl;
262     r->data_len = ppkt->nameservers[i]->data_len;
263     idx += sizeof (struct dns_record_line);
264     memcpy (&r->data, ppkt->nameservers[i]->data,
265             ppkt->nameservers[i]->data_len);
266     idx += ppkt->nameservers[i]->data_len;
267   }
268
269   for (i = 0; i < ntohs (ppkt->s.arcount); i++)
270   {
271     unparse_dns_name (&pkt_c[idx], ppkt->additional[i]->name,
272                       ppkt->additional[i]->namelen);
273     idx += ppkt->additional[i]->namelen;
274     struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx];
275
276     r->type = ppkt->additional[i]->type;
277     r->class = ppkt->additional[i]->class;
278     r->ttl = ppkt->additional[i]->ttl;
279     r->data_len = ppkt->additional[i]->data_len;
280     idx += sizeof (struct dns_record_line);
281     memcpy (&r->data, ppkt->additional[i]->data, ppkt->additional[i]->data_len);
282     idx += ppkt->additional[i]->data_len;
283   }
284
285   return pkt;
286 }
287
288 void
289 free_parsed_dns_packet (struct dns_pkt_parsed *ppkt)
290 {
291   unsigned short qdcount = ntohs (ppkt->s.qdcount);
292   unsigned short ancount = ntohs (ppkt->s.ancount);
293   unsigned short nscount = ntohs (ppkt->s.nscount);
294   unsigned short arcount = ntohs (ppkt->s.arcount);
295
296   int i;
297
298   for (i = 0; i < qdcount; i++)
299   {
300     GNUNET_free (ppkt->queries[i]->name);
301     GNUNET_free (ppkt->queries[i]);
302   }
303   GNUNET_free (ppkt->queries);
304   for (i = 0; i < ancount; i++)
305   {
306     GNUNET_free (ppkt->answers[i]->name);
307     GNUNET_free (ppkt->answers[i]->data);
308     GNUNET_free (ppkt->answers[i]);
309   }
310   GNUNET_free (ppkt->answers);
311   for (i = 0; i < nscount; i++)
312   {
313     GNUNET_free (ppkt->nameservers[i]->name);
314     GNUNET_free (ppkt->nameservers[i]->data);
315     GNUNET_free (ppkt->nameservers[i]);
316   }
317   GNUNET_free (ppkt->nameservers);
318   for (i = 0; i < arcount; i++)
319   {
320     GNUNET_free (ppkt->additional[i]->name);
321     GNUNET_free (ppkt->additional[i]->data);
322     GNUNET_free (ppkt->additional[i]);
323   }
324   GNUNET_free (ppkt->additional);
325   GNUNET_free (ppkt);
326 }