]> git.meshlink.io Git - catta/blob - dns.c
some more inomcplete work
[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_extend(flxDnsPacket *p, guint l) {
82     guint8 *d;
83     
84     g_assert(p);
85     g_assert(p->size+l <= sizeof(p->data));
86
87     d = p->data + p->size;
88     p->size += l;
89     
90     return d;
91 }
92
93 guint8 *flx_dns_packet_append_name_compressed(flxDnsPacket *p, const gchar *name, guint8 *prev) {
94     guint16 *d;
95     signed long k;
96     g_assert(p);
97
98     if (!prev)
99         return flx_dns_packet_append_name(p, name);
100     
101     k = prev - p->data;
102     if (k < 0 || k >= 0x4000 || (guint) k >= p->size)
103         return flx_dns_packet_append_name(p, name);
104
105     d = (guint16*) flx_dns_packet_extend(p, sizeof(guint16));
106     *d = g_htons((0xC000 | k));
107     
108     return prev;
109 }
110
111 gint flx_dns_packet_check_valid(flxDnsPacket *p) {
112     guint16 flags;
113     g_assert(p);
114
115     if (p->size < 12)
116         return -1;
117
118     flags = flx_dns_packet_get_field(p, DNS_FIELD_FLAGS);
119
120     if (flags & DNS_FLAG_OPCODE || flags & DNS_FLAG_RCODE)
121         return -1;
122
123     return 0;
124 }
125
126 gint flx_dns_packet_is_query(flxDnsPacket *p) {
127     g_assert(p);
128     
129     return !(flx_dns_packet_get_field(p, DNS_FIELD_FLAGS) & DNS_FLAG_QR);
130 }
131
132 static gint consume_labels(flxDnsPacket *p, guint index, gchar *ret_name, guint l) {
133     gint ret = 0;
134     int compressed = 0;
135     int first_label = 1;
136     g_assert(p && ret_name && l);
137     
138     for (;;) {
139         guint8 n;
140
141         if (index+1 > p->size)
142             return -1;
143
144         n = p->data[index];
145
146         if (!n) {
147             index++;
148             if (!compressed)
149                 ret++;
150
151             if (l < 1)
152                 return -1;
153             *ret_name = 0;
154             
155             return ret;
156             
157         } else if (n <= 63) {
158             /* Uncompressed label */
159             index++;
160             if (!compressed)
161                 ret++;
162         
163             if (index + n > p->size)
164                 return -1;
165
166             if ((guint) n + 1 > l)
167                 return -1;
168
169             if (!first_label) {
170                 *(ret_name++) = '.';
171                 l--;
172             } else
173                 first_label = 0;
174
175             memcpy(ret_name, p->data + index, n);
176             index += n;
177             ret_name += n;
178             l -= n;
179             
180             if (!compressed)
181                 ret += n;
182         } else if ((n & 0xC0) == 0xC0) {
183             /* Compressed label */
184
185             if (index+2 > p->size)
186                 return -1;
187
188             index = ((guint) (p->data[index] & ~0xC0)) << 8 | p->data[index+1];
189
190             if (!compressed)
191                 ret += 2;
192             
193             compressed = 1;
194         } else
195             return -1;
196     }
197 }
198
199 gint flx_dns_packet_consume_name(flxDnsPacket *p, gchar *ret_name, guint l) {
200     gint r;
201     
202     if ((r = consume_labels(p, p->rindex, ret_name, l)) < 0)
203         return -1;
204
205     p->rindex += r;
206     return 0;
207 }
208
209 gint flx_dns_packet_consume_uint16(flxDnsPacket *p, guint16 *ret_v) {
210     g_assert(p);
211     g_assert(ret_v);
212
213     if (p->rindex + sizeof(guint16) > p->size)
214         return -1;
215
216     *ret_v = g_ntohs(*((guint16*) (p->data + p->rindex)));
217     p->rindex += sizeof(guint16);
218
219     return 0;
220 }
221
222 gint flx_dns_packet_consume_uint32(flxDnsPacket *p, guint32 *ret_v) {
223     g_assert(p);
224     g_assert(ret_v);
225
226     if (p->rindex + sizeof(guint32) > p->size)
227         return -1;
228
229     *ret_v = g_ntohl(*((guint32*) (p->data + p->rindex)));
230     p->rindex += sizeof(guint32);
231     
232     return 0;
233 }
234
235 gint flx_dns_packet_consume_bytes(flxDnsPacket *p, gpointer ret_data, guint l) {
236     g_assert(p);
237     g_assert(ret_data);
238     g_assert(l > 0);
239     
240     if (p->rindex + l > p->size)
241         return -1;
242
243     memcpy(ret_data, p->data + p->rindex, l);
244     p->rindex += l;
245
246     return 0;
247 }
248
249 gconstpointer flx_dns_packet_get_rptr(flxDnsPacket *p) {
250     g_assert(p);
251     
252     if (p->rindex >= p->size)
253         return NULL;
254
255     return p->data + p->rindex;
256 }
257
258 gint flx_dns_packet_skip(flxDnsPacket *p, guint length) {
259     g_assert(p);
260
261     if (p->rindex + length > p->size)
262         return -1;
263
264     p->rindex += length;
265     return 0;
266 }
267
268 flxRecord* flx_dns_packet_consume_record(flxDnsPacket *p, gboolean *ret_cache_flush) {
269     gchar name[256];
270     guint16 type, class;
271     guint32 ttl;
272     guint16 rdlength;
273     gconstpointer data;
274
275     g_assert(p);
276     g_assert(ret_cache_flush);
277
278     if (flx_dns_packet_consume_name(p, name, sizeof(name)) < 0 ||
279         flx_dns_packet_consume_uint16(p, &type) < 0 ||
280         flx_dns_packet_consume_uint16(p, &class) < 0 ||
281         flx_dns_packet_consume_uint32(p, &ttl) < 0 ||
282         flx_dns_packet_consume_uint16(p, &rdlength) < 0 ||
283         !(data = flx_dns_packet_get_rptr(p)) ||
284         flx_dns_packet_skip(p, rdlength) < 0)
285         return NULL;
286
287     *ret_cache_flush = !!(class & MDNS_CACHE_FLUSH);
288     class &= ~ MDNS_CACHE_FLUSH;
289
290     return flx_record_new_full(name, class, type, data, rdlength, ttl);
291 }
292
293 flxKey* flx_dns_packet_consume_key(flxDnsPacket *p) {
294     gchar name[256];
295     guint16 type, class;
296
297     g_assert(p);
298
299     if (flx_dns_packet_consume_name(p, name, sizeof(name)) < 0 ||
300         flx_dns_packet_consume_uint16(p, &type) < 0 ||
301         flx_dns_packet_consume_uint16(p, &class) < 0)
302         return NULL;
303
304     class &= ~ MDNS_CACHE_FLUSH;
305
306     return flx_key_new(name, class, type);
307 }
308
309 guint8* flx_dns_packet_append_key(flxDnsPacket *p, flxKey *k) {
310     guint8 *t;
311     
312     g_assert(p);
313     g_assert(k);
314
315     if (!(t = flx_dns_packet_append_name(p, k->name)) ||
316         !flx_dns_packet_append_uint16(p, k->type) ||
317         !flx_dns_packet_append_uint16(p, k->class))
318         return NULL;
319
320     return t;
321 }
322
323 guint8* flx_dns_packet_append_record(flxDnsPacket *p, flxRecord *r, gboolean cache_flush) {
324
325     
326 }