]> git.karo-electronics.de Git - mdnsd.git/blob - 1035.c
Applied Simons initial checkin, first slightly modifications
[mdnsd.git] / 1035.c
1 #include "1035.h"
2 #include <string.h>
3
4 unsigned short int net2short(unsigned char **bufp)
5 {
6     short int i;
7     i = **bufp;
8     i <<= 8;
9     i |= *(*bufp + 1);
10     *bufp += 2;
11     return i;
12 }
13
14 unsigned long int net2long(unsigned char **bufp)
15 {
16     long int l;
17     l = **bufp;
18     l <<= 8;
19     l |= *(*bufp + 1);
20     l <<= 8;
21     l |= *(*bufp + 2);
22     l <<= 8;
23     l |= *(*bufp + 3);
24     *bufp += 4;
25     return l;
26 }
27
28 void short2net(unsigned short int i, unsigned char **bufp)
29 {
30     *(*bufp + 1) = (unsigned char)i;
31     i >>= 8;
32     **bufp = (unsigned char)i;
33     *bufp += 2;
34 }
35
36 void long2net(unsigned long int l, unsigned char **bufp)
37 {
38     *(*bufp + 3) = (unsigned char)l;
39     l >>= 8;
40     *(*bufp + 2) = (unsigned char)l;
41     l >>= 8;
42     *(*bufp + 1) = (unsigned char)l;
43     l >>= 8;
44     **bufp = (unsigned char)l;
45     *bufp += 4;
46 }
47
48 unsigned short int _ldecomp(unsigned char *ptr)
49 {
50     unsigned short int i;
51     i = 0xc0 ^ ptr[0];
52     i <<= 8;
53     i |= ptr[1];
54     if(i >= 4096) i = 4095;
55     return i;
56 }
57
58 void _label(struct message *m, unsigned char **bufp, unsigned char **namep)
59 {
60     unsigned char *label, *name;
61     int x;
62
63     // set namep to the end of the block
64     *namep = name = m->_packet + m->_len;
65
66     // loop storing label in the block
67     for(label = *bufp; *label != 0; name += *label + 1, label += *label + 1)
68     {
69         // skip past any compression pointers, kick out if end encountered (bad data prolly)
70         while(*label & 0xc0)
71             if(*(label = m->_buf + _ldecomp(label)) == 0) break;
72
73         // make sure we're not over the limits
74         if((name + *label) - *namep > 255 || m->_len + ((name + *label) - *namep) > 4096) return;
75
76         // copy chars for this label
77         memcpy(name,label+1,*label);
78         name[*label] = '.';
79     }
80
81     // advance buffer
82     for(label = *bufp; *label != 0 && !(*label & 0xc0 && label++); label += *label + 1);
83     *bufp = label + 1;
84
85     // terminate name and check for cache or cache it
86     *name = '\0';
87     for(x = 0; x <= 19 && m->_labels[x]; x++)
88     {
89         if(strcmp(*namep,m->_labels[x])) continue;
90         *namep = m->_labels[x];
91         return;
92     }
93     // no cache, so cache it if room
94     if(x <= 19 && m->_labels[x] == 0)
95         m->_labels[x] = *namep;
96     m->_len += (name - *namep) + 1;
97 }
98
99 // internal label matching
100 int _lmatch(struct message *m, unsigned char *l1, unsigned char *l2)
101 {
102     int len;
103
104     // always ensure we get called w/o a pointer
105     if(*l1 & 0xc0) return _lmatch(m, m->_buf + _ldecomp(l1),l2);
106     if(*l2 & 0xc0) return _lmatch(m, l1, m->_buf + _ldecomp(l2));
107
108     // same already?
109     if(l1 == l2) return 1;
110
111     // compare all label characters
112     if(*l1 != *l2) return 0;
113     for(len = 1; len <= *l1; len++)
114         if(l1[len] != l2[len]) return 0;
115
116     // get new labels
117     l1 += *l1 + 1;
118     l2 += *l2 + 1;
119
120     // at the end, all matched
121     if(*l1 == 0 && *l2 == 0) return 1;
122
123     // try next labels
124     return _lmatch(m,l1,l2);
125 }
126
127 // nasty, convert host into label using compression
128 int _host(struct message *m, unsigned char **bufp, unsigned char *name)
129 {
130     unsigned char label[256], *l;
131     int len = 0, x = 1, y = 0, last = 0;
132
133     if(name == 0) return 0;
134
135     // make our label
136     while(name[y])
137     {
138         if(name[y] == '.')
139         {
140             if(!name[y+1]) break;
141             label[last] = x - (last + 1);
142             last = x;
143         }else{
144             label[x] = name[y];
145         }
146         if(x++ == 255) return 0;
147         y++;
148     }
149     label[last] = x - (last + 1);
150     if(x == 1) x--; // special case, bad names, but handle correctly
151     len = x + 1;
152     label[x] = 0; // always terminate w/ a 0
153
154     // double-loop checking each label against all m->_labels for match
155     for(x = 0; label[x]; x += label[x] + 1)
156     {
157         for(y = 0; m->_labels[y]; y++)
158             if(_lmatch(m,label+x,m->_labels[y]))
159             {
160                 // matching label, set up pointer
161                 l = label + x;
162                 short2net(m->_labels[y] - m->_packet, &l);
163                 label[x] |= 0xc0;
164                 len = x + 2;
165                 break;
166             }
167         if(label[x] & 0xc0) break;
168     }
169
170     // copy into buffer, point there now
171     memcpy(*bufp,label,len);
172     l = *bufp;
173     *bufp += len;
174
175     // for each new label, store it's location for future compression
176     for(x = 0; l[x]; x += l[x] + 1)
177     {
178         if(l[x] & 0xc0) break;
179         if(m->_label + 1 >= 19) break;
180         m->_labels[m->_label++] = l + x;
181     }
182
183     return len;
184 }
185
186 int _rrparse(struct message *m, struct resource *rr, int count, unsigned char **bufp)
187 {
188     int i;
189     for(i=0; i < count; i++)
190     {
191         _label(m, bufp, &(rr[i].name));
192         rr[i].type = net2short(bufp);
193         rr[i].class = net2short(bufp);
194         rr[i].ttl = net2long(bufp);
195         rr[i].rdlength = net2short(bufp);
196
197         // if not going to overflow, make copy of source rdata
198         if(rr[i].rdlength + (*bufp - m->_buf) > MAX_PACKET_LEN || m->_len + rr[i].rdlength > MAX_PACKET_LEN) return 1;
199         rr[i].rdata = m->_packet + m->_len;
200         m->_len += rr[i].rdlength;
201         memcpy(rr[i].rdata,*bufp,rr[i].rdlength);
202
203         // parse commonly known ones
204         switch(rr[i].type)
205         {
206         case 1:
207             if(m->_len + 16 > MAX_PACKET_LEN) return 1;
208             rr[i].known.a.name = m->_packet + m->_len;
209             m->_len += 16;
210             sprintf(rr[i].known.a.name,"%d.%d.%d.%d",(*bufp)[0],(*bufp)[1],(*bufp)[2],(*bufp)[3]);
211             rr[i].known.a.ip = net2long(bufp);
212             break;
213         case 2:
214             _label(m, bufp, &(rr[i].known.ns.name));
215             break;
216         case 5:
217             _label(m, bufp, &(rr[i].known.cname.name));
218             break;
219         case 12:
220             _label(m, bufp, &(rr[i].known.ptr.name));
221             break;
222         case 33:
223             rr[i].known.srv.priority = net2short(bufp);
224             rr[i].known.srv.weight = net2short(bufp);
225             rr[i].known.srv.port = net2short(bufp);
226             _label(m, bufp, &(rr[i].known.srv.name));
227             break;
228         default:
229             *bufp += rr[i].rdlength;
230         }
231     }
232
233     return 0;
234 }
235
236 void message_parse(struct message *m, unsigned char *packet)
237 {
238     unsigned char *buf;
239     int i;
240
241     if(packet == 0 || m == 0) return;
242
243     // keep all our mem in one (aligned) block for easy freeing
244     #define my(x,y) while(m->_len&7) m->_len++; (void*)x = (void*)(m->_packet + m->_len); m->_len += y;
245
246     // header stuff bit crap
247     m->_buf = buf = packet;
248     m->id = net2short(&buf);
249     if(buf[0] & 0x80) m->header.qr = 1;
250     m->header.opcode = (buf[0] & 0x78) >> 3;
251     if(buf[0] & 0x04) m->header.aa = 1;
252     if(buf[0] & 0x02) m->header.tc = 1;
253     if(buf[0] & 0x01) m->header.rd = 1;
254     if(buf[1] & 0x80) m->header.ra = 1;
255     m->header.z = (buf[1] & 0x70) >> 4;
256     m->header.rcode = buf[1] & 0x0F;
257     buf += 2;
258     m->qdcount = net2short(&buf);
259     if(m->_len + (sizeof(struct question) * m->qdcount) > MAX_PACKET_LEN - 8) { m->qdcount = 0; return; }
260     m->ancount = net2short(&buf);
261     if(m->_len + (sizeof(struct resource) * m->ancount) > MAX_PACKET_LEN - 8) { m->ancount = 0; return; }
262     m->nscount = net2short(&buf);
263     if(m->_len + (sizeof(struct resource) * m->nscount) > MAX_PACKET_LEN - 8) { m->nscount = 0; return; }
264     m->arcount = net2short(&buf);
265     if(m->_len + (sizeof(struct resource) * m->arcount) > MAX_PACKET_LEN - 8) { m->arcount = 0; return; }
266
267     // process questions
268     my(m->qd, sizeof(struct question) * m->qdcount);
269     for(i=0; i < m->qdcount; i++)
270     {
271         _label(m, &buf, &(m->qd[i].name));
272         m->qd[i].type = net2short(&buf);
273         m->qd[i].class = net2short(&buf);
274     }
275
276     // process rrs
277     my(m->an, sizeof(struct resource) * m->ancount);
278     my(m->ns, sizeof(struct resource) * m->nscount);
279     my(m->ar, sizeof(struct resource) * m->arcount);
280     if(_rrparse(m,m->an,m->ancount,&buf)) return;
281     if(_rrparse(m,m->ns,m->nscount,&buf)) return;
282     if(_rrparse(m,m->ar,m->arcount,&buf)) return;
283 }
284
285 void message_qd(struct message *m, unsigned char *name, unsigned short int type, unsigned short int class)
286 {
287     m->qdcount++;
288     if(m->_buf == 0) m->_buf = m->_packet + 12; // initialization
289     _host(m, &(m->_buf), name);
290     short2net(type, &(m->_buf));
291     short2net(class, &(m->_buf));
292 }
293
294 void _rrappend(struct message *m, unsigned char *name, unsigned short int type, unsigned short int class, unsigned long int ttl)
295 {
296     if(m->_buf == 0) m->_buf = m->_packet + 12; // initialization
297     _host(m, &(m->_buf), name);
298     short2net(type, &(m->_buf));
299     short2net(class, &(m->_buf));
300     long2net(ttl, &(m->_buf));
301 }
302
303 void message_an(struct message *m, unsigned char *name, unsigned short int type, unsigned short int class, unsigned long int ttl)
304 {
305     m->ancount++;
306     _rrappend(m,name,type,class,ttl);
307 }
308
309 void message_ns(struct message *m, unsigned char *name, unsigned short int type, unsigned short int class, unsigned long int ttl)
310 {
311     m->nscount++;
312     _rrappend(m,name,type,class,ttl);
313 }
314
315 void message_ar(struct message *m, unsigned char *name, unsigned short int type, unsigned short int class, unsigned long int ttl)
316 {
317     m->arcount++;
318     _rrappend(m,name,type,class,ttl);
319 }
320
321 void message_rdata_long(struct message *m, unsigned long int l)
322 {
323     short2net(4, &(m->_buf));
324     long2net(l, &(m->_buf));
325 }
326
327 void message_rdata_name(struct message *m, unsigned char *name)
328 {
329     unsigned char *mybuf = m->_buf;
330     m->_buf += 2;
331     short2net(_host(m, &(m->_buf), name),&mybuf); // hackish, but cute
332 }
333
334 void message_rdata_srv(struct message *m, unsigned short int priority, unsigned short int weight, unsigned short int port, unsigned char *name)
335 {
336     unsigned char *mybuf = m->_buf;
337     m->_buf += 2;
338     short2net(priority, &(m->_buf));
339     short2net(weight, &(m->_buf));
340     short2net(port, &(m->_buf));
341     short2net(_host(m, &(m->_buf), name) + 6, &mybuf);
342 }
343
344 void message_rdata_raw(struct message *m, unsigned char *rdata, unsigned short int rdlength)
345 {
346     if((m->_buf - m->_packet) + rdlength > 4096) rdlength = 0;
347     short2net(rdlength, &(m->_buf));
348     memcpy(m->_buf,rdata,rdlength);
349     m->_buf += rdlength;
350 }
351
352 unsigned char *message_packet(struct message *m)
353 {
354     unsigned char c, *buf = m->_buf;
355     m->_buf = m->_packet;
356     short2net(m->id, &(m->_buf));
357     if(m->header.qr) m->_buf[0] |= 0x80;
358     if((c = m->header.opcode)) m->_buf[0] |= (c << 3);
359     if(m->header.aa) m->_buf[0] |= 0x04;
360     if(m->header.tc) m->_buf[0] |= 0x02;
361     if(m->header.rd) m->_buf[0] |= 0x01;
362     if(m->header.ra) m->_buf[1] |= 0x80;
363     if((c = m->header.z)) m->_buf[1] |= (c << 4);
364     if(m->header.rcode) m->_buf[1] |= m->header.rcode;
365     m->_buf += 2;
366     short2net(m->qdcount, &(m->_buf));
367     short2net(m->ancount, &(m->_buf));
368     short2net(m->nscount, &(m->_buf));
369     short2net(m->arcount, &(m->_buf));
370     m->_buf = buf; // restore, so packet_len works
371     return m->_packet;
372 }
373
374 int message_packet_len(struct message *m)
375 {
376     if(m->_buf == 0) return 12;
377     return m->_buf - m->_packet;
378 }