]> git.meshlink.io Git - catta/blob - dns.c
add code for recieving packets
[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_check_valid_response(flxDnsPacket *p) {
127     guint16 flags;
128     g_assert(p);
129     
130     if (flx_dns_packet_check_valid(p) < 0)
131         return -1;
132
133     flags = flx_dns_packet_get_field(p, DNS_FIELD_FLAGS);
134
135     if (!(flags & DNS_FLAG_QR))
136         return -1;
137
138     if (flx_dns_packet_get_field(p, DNS_FIELD_QDCOUNT) > 0)
139         return -1;
140
141     return 0;
142 }
143
144 static gint consume_labels(flxDnsPacket *p, guint index, gchar *ret_name, guint l) {
145     gint ret = 0;
146     int compressed = 0;
147     int first_label = 1;
148     g_assert(p && ret_name && l);
149     
150     for (;;) {
151         guint8 n;
152
153         if (index+1 > p->size)
154             return -1;
155
156         n = p->data[index];
157
158         if (!n) {
159             index++;
160             if (!compressed)
161                 ret++;
162
163             if (l < 1)
164                 return -1;
165             *ret_name = 0;
166             
167             return ret;
168             
169         } else if (n <= 63) {
170             /* Uncompressed label */
171             index++;
172             if (!compressed)
173                 ret++;
174         
175             if (index + n > p->size)
176                 return -1;
177
178             if ((guint) n + 1 > l)
179                 return -1;
180
181             if (!first_label) {
182                 *(ret_name++) = '.';
183                 l--;
184             } else
185                 first_label = 0;
186
187             memcpy(ret_name, p->data + index, n);
188             index += n;
189             ret_name += n;
190             l -= n;
191             
192             if (!compressed)
193                 ret += n;
194         } else if ((n & 0xC0) == 0xC0) {
195             /* Compressed label */
196
197             if (index+2 > p->size)
198                 return -1;
199
200             index = ((guint) (p->data[index] & ~0xC0)) << 8 | p->data[index+1];
201
202             if (!compressed)
203                 ret += 2;
204             
205             compressed = 1;
206         } else
207             return -1;
208     }
209 }
210
211 gint flx_dns_packet_consume_name(flxDnsPacket *p, gchar *ret_name, guint l) {
212     gint r;
213     
214     if ((r = consume_labels(p, p->rindex, ret_name, l)) < 0)
215         return -1;
216
217     p->rindex += r;
218     return 0;
219 }
220
221 gint flx_dns_packet_consume_uint16(flxDnsPacket *p, guint16 *ret_v) {
222     g_assert(p);
223     g_assert(ret_v);
224
225     if (p->rindex + sizeof(guint16) > p->size)
226         return -1;
227
228     *ret_v = g_ntohs(*((guint16*) (p->data + p->rindex)));
229     p->rindex += sizeof(guint16);
230
231     return 0;
232 }
233
234 gint flx_dns_packet_consume_uint32(flxDnsPacket *p, guint32 *ret_v) {
235     g_assert(p);
236     g_assert(ret_v);
237
238     if (p->rindex + sizeof(guint32) > p->size)
239         return -1;
240
241     *ret_v = g_ntohl(*((guint32*) (p->data + p->rindex)));
242     p->rindex += sizeof(guint32);
243     
244     return 0;
245 }
246
247 gint flx_dns_packet_consume_bytes(flxDnsPacket *p, gpointer ret_data, guint l) {
248     g_assert(p);
249     g_assert(ret_data);
250     g_assert(l > 0);
251     
252     if (p->rindex + l > p->size)
253         return -1;
254
255     memcpy(ret_data, p->data + p->rindex, l);
256     p->rindex += l;
257
258     return 0;
259 }
260
261 gint flx_dns_packet_skip(flxDnsPacket *p, guint length) {
262     g_assert(p);
263
264     if (p->rindex + length > p->size)
265         return -1;
266
267     p->rindex += length;
268     return 0;
269 }