indentation
[oweals/gnunet.git] / src / vpn / gnunet-dns-parser.c
1 #include "platform.h"
2 #include "gnunet-dns-parser.h"
3 #include "gnunet-vpn-packet.h"
4
5 /**
6  * Parse a name from DNS to a normal .-delimited, 0-terminated string.
7  *
8  * @param d The destination of the name. Should have at least 255 bytes allocated.
9  * @param src The DNS-Packet
10  * @param idx The offset inside the Packet from which on the name should be read
11  * @returns The offset of the first unparsed byte (the byte right behind the name)
12  */
13 static unsigned int
14 parse_dns_name (char *d, const unsigned char *src, unsigned short idx)
15 {                               /*{{{ */
16   char *dest = d;
17
18   int len = src[idx++];
19
20   while (len != 0)
21   {
22     if (len & 0xC0)
23     {                           /* Compressed name, offset in this and the next octet */
24       unsigned short offset = ((len & 0x3F) << 8) | src[idx++];
25
26       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 */
27       return idx;
28     }
29     memcpy (dest, src + idx, len);
30     idx += len;
31     dest += len;
32     *dest = '.';
33     dest++;
34     len = src[idx++];
35   };
36   *dest = 0;
37
38   return idx;
39 }
40
41 /*}}}*/
42
43 /**
44  * Parse a complete DNS-Record from raw DNS-data to a struct dns_record
45  *
46  * @param data The DNS-data
47  * @param dst Pointer to count pointers; individual pointers will be allocated
48  * @param count Number of records to parse
49  * @param idx The offset inside the Packet from which on the name should be read
50  * @returns The offset of the first unparsed byte (the byte right behind the last record)
51  */
52 static unsigned short
53 parse_dns_record (unsigned char *data,  /*{{{ */
54                   struct dns_record **dst,
55                   unsigned short count, unsigned short idx)
56 {
57   int i;
58   unsigned short _idx;
59
60   for (i = 0; i < count; i++)
61   {
62     dst[i] = GNUNET_malloc (sizeof (struct dns_record));
63     dst[i]->name = alloca (255);        // see RFC1035, no name can be longer than this.
64     char *name = dst[i]->name;
65
66     _idx = parse_dns_name (name, data, idx);
67     dst[i]->namelen = _idx - idx;
68
69     dst[i]->name = GNUNET_malloc (dst[i]->namelen);
70     memcpy (dst[i]->name, name, dst[i]->namelen);
71
72     idx = _idx;
73
74     dst[i]->type = *((unsigned short *) (data + idx));
75     idx += 2;
76     dst[i]->class = *((unsigned short *) (data + idx));
77     idx += 2;
78     dst[i]->ttl = *((unsigned int *) (data + idx));
79     idx += 4;
80     dst[i]->data_len = *((unsigned short *) (data + idx));
81     idx += 2;
82     dst[i]->data = GNUNET_malloc (ntohs (dst[i]->data_len));
83     memcpy (dst[i]->data, data + idx, ntohs (dst[i]->data_len));
84     idx += ntohs (dst[i]->data_len);
85   }
86   return idx;
87 }                               /*}}} */
88
89 /**
90  * Parse a raw DNS-Packet into an usable struct
91  */
92 struct dns_pkt_parsed *
93 parse_dns_packet (struct dns_pkt *pkt)
94 {                               /*{{{ */
95   struct dns_pkt_parsed *ppkt = GNUNET_malloc (sizeof (struct dns_pkt_parsed));
96
97   memcpy (&ppkt->s, &pkt->s, sizeof pkt->s);
98
99   unsigned short qdcount = ntohs (ppkt->s.qdcount);
100   unsigned short ancount = ntohs (ppkt->s.ancount);
101   unsigned short nscount = ntohs (ppkt->s.nscount);
102   unsigned short arcount = ntohs (ppkt->s.arcount);
103
104   ppkt->queries = GNUNET_malloc (qdcount * sizeof (struct dns_query *));
105   ppkt->answers = GNUNET_malloc (ancount * sizeof (struct dns_record *));
106   ppkt->nameservers = GNUNET_malloc (nscount * sizeof (struct dns_record *));
107   ppkt->additional = GNUNET_malloc (arcount * sizeof (struct dns_record *));
108
109   unsigned short idx = 0, _idx; /* This keeps track how far we have parsed the data */
110
111   /* Parse the Query */
112   int i;
113
114   for (i = 0; i < qdcount; i++)
115   {                             /*{{{ */
116     ppkt->queries[i] = GNUNET_malloc (sizeof (struct dns_query));
117     char *name = alloca (255);  /* see RFC1035, it can't be more than this. */
118
119     _idx = parse_dns_name (name, pkt->data, idx);
120     ppkt->queries[i]->namelen = _idx - idx;
121     idx = _idx;
122
123     ppkt->queries[i]->name = GNUNET_malloc (ppkt->queries[i]->namelen);
124     memcpy (ppkt->queries[i]->name, name, ppkt->queries[i]->namelen);
125
126     ppkt->queries[i]->qtype = *((unsigned short *) (pkt->data + idx));
127     idx += 2;
128     ppkt->queries[i]->qclass = *((unsigned short *) (pkt->data + idx));
129     idx += 2;
130   }
131   /*}}} */
132   idx = parse_dns_record (pkt->data, ppkt->answers, ancount, idx);
133   idx = parse_dns_record (pkt->data, ppkt->nameservers, nscount, idx);
134   idx = parse_dns_record (pkt->data, ppkt->additional, arcount, idx);
135   return ppkt;
136 }                               /*}}} */
137
138 void
139 free_parsed_dns_packet (struct dns_pkt_parsed *ppkt)
140 {
141   unsigned short qdcount = ntohs (ppkt->s.qdcount);
142   unsigned short ancount = ntohs (ppkt->s.ancount);
143   unsigned short nscount = ntohs (ppkt->s.nscount);
144   unsigned short arcount = ntohs (ppkt->s.arcount);
145
146   int i;
147
148   for (i = 0; i < qdcount; i++)
149   {
150     GNUNET_free (ppkt->queries[i]->name);
151     GNUNET_free (ppkt->queries[i]);
152   }
153   GNUNET_free (ppkt->queries);
154   for (i = 0; i < ancount; i++)
155   {
156     GNUNET_free (ppkt->answers[i]->name);
157     GNUNET_free (ppkt->answers[i]->data);
158     GNUNET_free (ppkt->answers[i]);
159   }
160   GNUNET_free (ppkt->answers);
161   for (i = 0; i < nscount; i++)
162   {
163     GNUNET_free (ppkt->nameservers[i]->name);
164     GNUNET_free (ppkt->nameservers[i]->data);
165     GNUNET_free (ppkt->nameservers[i]);
166   }
167   GNUNET_free (ppkt->nameservers);
168   for (i = 0; i < arcount; i++)
169   {
170     GNUNET_free (ppkt->additional[i]->name);
171     GNUNET_free (ppkt->additional[i]->data);
172     GNUNET_free (ppkt->additional[i]);
173   }
174   GNUNET_free (ppkt->additional);
175   GNUNET_free (ppkt);
176 }