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