]> git.meshlink.io Git - catta/blob - dns.c
make the daemon response to queries
[catta] / dns.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdio.h>
4
5 #include "dns.h"
6
7 flxDnsPacket* flx_dns_packet_new(void) {
8     flxDnsPacket *p;
9     p = g_new(flxDnsPacket, 1);
10     p->size = p->rindex = 2*6;
11     memset(p->data, 0, p->size);
12     return p;
13 }
14
15 void flx_dns_packet_free(flxDnsPacket *p) {
16     g_assert(p);
17     g_free(p);
18 }
19
20 void flx_dns_packet_set_field(flxDnsPacket *p, guint index, guint16 v) {
21     g_assert(p);
22     g_assert(index < 2*6);
23     
24     ((guint16*) p->data)[index] = g_htons(v);
25 }
26
27 guint16 flx_dns_packet_get_field(flxDnsPacket *p, guint index) {
28     g_assert(p);
29     g_assert(index < 2*6);
30
31     return g_ntohs(((guint16*) p->data)[index]);
32 }
33
34 guint8* flx_dns_packet_append_name(flxDnsPacket *p, const gchar *name) {
35     guint8 *d, *f = NULL;
36     
37     g_assert(p);
38     g_assert(name);
39
40     for (;;) {
41         guint n = strcspn(name, ".");
42         if (!n || n > 63)
43             return NULL;
44         
45         d = flx_dns_packet_extend(p, n+1);
46         if (!f)
47             f = d;
48         d[0] = n;
49         memcpy(d+1, name, n);
50
51         name += n;
52
53         /* no trailing dot */
54         if (!*name)
55             break;
56
57         name ++;
58
59         /* trailing dot */
60         if (!*name)
61             break;
62     }
63
64     d = flx_dns_packet_extend(p, 1);
65     d[0] = 0;
66
67     return f;
68 }
69
70 guint8* flx_dns_packet_append_uint16(flxDnsPacket *p, guint16 v) {
71     guint8 *d;
72     
73     g_assert(p);
74     
75     d = flx_dns_packet_extend(p, sizeof(guint16));
76     *((guint16*) d) = g_htons(v);
77     
78     return d;
79 }
80
81 guint8 *flx_dns_packet_append_uint32(flxDnsPacket *p, guint32 v) {
82     guint8 *d;
83
84     g_assert(p);
85     d = flx_dns_packet_extend(p, sizeof(guint32));
86     *((guint32*) d) = g_htonl(v);
87
88     return d;
89 }
90
91 guint8 *flx_dns_packet_append_bytes(flxDnsPacket  *p, gconstpointer b, guint l) {
92     guint8* d;
93
94     g_assert(p);
95     g_assert(b);
96     g_assert(l);
97     
98     d = flx_dns_packet_extend(p, l);
99     g_assert(d);
100     memcpy(d, b, l);
101
102     return d;
103 }
104
105
106 guint8 *flx_dns_packet_extend(flxDnsPacket *p, guint l) {
107     guint8 *d;
108     
109     g_assert(p);
110     g_assert(p->size+l <= sizeof(p->data));
111
112     d = p->data + p->size;
113     p->size += l;
114     
115     return d;
116 }
117
118 guint8 *flx_dns_packet_append_name_compressed(flxDnsPacket *p, const gchar *name, guint8 *prev) {
119     guint16 *d;
120     signed long k;
121     g_assert(p);
122
123     if (!prev)
124         return flx_dns_packet_append_name(p, name);
125     
126     k = prev - p->data;
127     if (k < 0 || k >= 0x4000 || (guint) k >= p->size)
128         return flx_dns_packet_append_name(p, name);
129
130     d = (guint16*) flx_dns_packet_extend(p, sizeof(guint16));
131     *d = g_htons((0xC000 | k));
132     
133     return prev;
134 }
135
136 gint flx_dns_packet_check_valid(flxDnsPacket *p) {
137     guint16 flags;
138     g_assert(p);
139
140     if (p->size < 12)
141         return -1;
142
143     flags = flx_dns_packet_get_field(p, DNS_FIELD_FLAGS);
144
145     if (flags & DNS_FLAG_OPCODE || flags & DNS_FLAG_RCODE)
146         return -1;
147
148     return 0;
149 }
150
151 gint flx_dns_packet_is_query(flxDnsPacket *p) {
152     g_assert(p);
153     
154     return !(flx_dns_packet_get_field(p, DNS_FIELD_FLAGS) & DNS_FLAG_QR);
155 }
156
157 static gint consume_labels(flxDnsPacket *p, guint index, gchar *ret_name, guint l) {
158     gint ret = 0;
159     int compressed = 0;
160     int first_label = 1;
161     g_assert(p && ret_name && l);
162     
163     for (;;) {
164         guint8 n;
165
166         if (index+1 > p->size)
167             return -1;
168
169         n = p->data[index];
170
171         if (!n) {
172             index++;
173             if (!compressed)
174                 ret++;
175
176             if (l < 1)
177                 return -1;
178             *ret_name = 0;
179             
180             return ret;
181             
182         } else if (n <= 63) {
183             /* Uncompressed label */
184             index++;
185             if (!compressed)
186                 ret++;
187         
188             if (index + n > p->size)
189                 return -1;
190
191             if ((guint) n + 1 > l)
192                 return -1;
193
194             if (!first_label) {
195                 *(ret_name++) = '.';
196                 l--;
197             } else
198                 first_label = 0;
199
200             memcpy(ret_name, p->data + index, n);
201             index += n;
202             ret_name += n;
203             l -= n;
204             
205             if (!compressed)
206                 ret += n;
207         } else if ((n & 0xC0) == 0xC0) {
208             /* Compressed label */
209
210             if (index+2 > p->size)
211                 return -1;
212
213             index = ((guint) (p->data[index] & ~0xC0)) << 8 | p->data[index+1];
214
215             if (!compressed)
216                 ret += 2;
217             
218             compressed = 1;
219         } else
220             return -1;
221     }
222 }
223
224 gint flx_dns_packet_consume_name(flxDnsPacket *p, gchar *ret_name, guint l) {
225     gint r;
226     
227     if ((r = consume_labels(p, p->rindex, ret_name, l)) < 0)
228         return -1;
229
230     p->rindex += r;
231     return 0;
232 }
233
234 gint flx_dns_packet_consume_uint16(flxDnsPacket *p, guint16 *ret_v) {
235     g_assert(p);
236     g_assert(ret_v);
237
238     if (p->rindex + sizeof(guint16) > p->size)
239         return -1;
240
241     *ret_v = g_ntohs(*((guint16*) (p->data + p->rindex)));
242     p->rindex += sizeof(guint16);
243
244     return 0;
245 }
246
247 gint flx_dns_packet_consume_uint32(flxDnsPacket *p, guint32 *ret_v) {
248     g_assert(p);
249     g_assert(ret_v);
250
251     if (p->rindex + sizeof(guint32) > p->size)
252         return -1;
253
254     *ret_v = g_ntohl(*((guint32*) (p->data + p->rindex)));
255     p->rindex += sizeof(guint32);
256     
257     return 0;
258 }
259
260 gint flx_dns_packet_consume_bytes(flxDnsPacket *p, gpointer ret_data, guint l) {
261     g_assert(p);
262     g_assert(ret_data);
263     g_assert(l > 0);
264     
265     if (p->rindex + l > p->size)
266         return -1;
267
268     memcpy(ret_data, p->data + p->rindex, l);
269     p->rindex += l;
270
271     return 0;
272 }
273
274 gconstpointer flx_dns_packet_get_rptr(flxDnsPacket *p) {
275     g_assert(p);
276     
277     if (p->rindex >= p->size)
278         return NULL;
279
280     return p->data + p->rindex;
281 }
282
283 gint flx_dns_packet_skip(flxDnsPacket *p, guint length) {
284     g_assert(p);
285
286     if (p->rindex + length > p->size)
287         return -1;
288
289     p->rindex += length;
290     return 0;
291 }
292
293 flxRecord* flx_dns_packet_consume_record(flxDnsPacket *p, gboolean *ret_cache_flush) {
294     gchar name[256];
295     guint16 type, class;
296     guint32 ttl;
297     guint16 rdlength;
298     gconstpointer data;
299
300     g_assert(p);
301     g_assert(ret_cache_flush);
302
303     if (flx_dns_packet_consume_name(p, name, sizeof(name)) < 0 ||
304         flx_dns_packet_consume_uint16(p, &type) < 0 ||
305         flx_dns_packet_consume_uint16(p, &class) < 0 ||
306         flx_dns_packet_consume_uint32(p, &ttl) < 0 ||
307         flx_dns_packet_consume_uint16(p, &rdlength) < 0 ||
308         !(data = flx_dns_packet_get_rptr(p)) ||
309         flx_dns_packet_skip(p, rdlength) < 0)
310         return NULL;
311
312     *ret_cache_flush = !!(class & MDNS_CACHE_FLUSH);
313     class &= ~ MDNS_CACHE_FLUSH;
314
315     return flx_record_new_full(name, class, type, data, rdlength, ttl);
316 }
317
318 flxKey* flx_dns_packet_consume_key(flxDnsPacket *p) {
319     gchar name[256];
320     guint16 type, class;
321
322     g_assert(p);
323
324     if (flx_dns_packet_consume_name(p, name, sizeof(name)) < 0 ||
325         flx_dns_packet_consume_uint16(p, &type) < 0 ||
326         flx_dns_packet_consume_uint16(p, &class) < 0)
327         return NULL;
328
329     class &= ~ MDNS_CACHE_FLUSH;
330
331     return flx_key_new(name, class, type);
332 }
333
334 guint8* flx_dns_packet_append_key(flxDnsPacket *p, flxKey *k) {
335     guint8 *t;
336     
337     g_assert(p);
338     g_assert(k);
339
340     if (!(t = flx_dns_packet_append_name(p, k->name)) ||
341         !flx_dns_packet_append_uint16(p, k->type) ||
342         !flx_dns_packet_append_uint16(p, k->class))
343         return NULL;
344
345     return t;
346 }
347
348 guint8* flx_dns_packet_append_record(flxDnsPacket *p, flxRecord *r, gboolean cache_flush) {
349     guint8 *t;
350
351     g_assert(p);
352     g_assert(r);
353
354     if (!(t = flx_dns_packet_append_name(p, r->key->name)) ||
355         !flx_dns_packet_append_uint16(p, r->key->type) ||
356         !flx_dns_packet_append_uint16(p, cache_flush ? (r->key->class | MDNS_CACHE_FLUSH) : (r->key->class &~ MDNS_CACHE_FLUSH)) ||
357         !flx_dns_packet_append_uint32(p, r->ttl) ||
358         !flx_dns_packet_append_uint16(p, r->size) ||
359         !flx_dns_packet_append_bytes(p, r->data, r->size))
360         return NULL;
361
362     return t;
363 }