4 unsigned short int net2short(unsigned char **bufp)
14 unsigned long int net2long(unsigned char **bufp)
28 void short2net(unsigned short int i, unsigned char **bufp)
30 *(*bufp + 1) = (unsigned char)i;
32 **bufp = (unsigned char)i;
36 void long2net(unsigned long int l, unsigned char **bufp)
38 *(*bufp + 3) = (unsigned char)l;
40 *(*bufp + 2) = (unsigned char)l;
42 *(*bufp + 1) = (unsigned char)l;
44 **bufp = (unsigned char)l;
48 unsigned short int _ldecomp(unsigned char *ptr)
54 if(i >= 4096) i = 4095;
58 void _label(struct message *m, unsigned char **bufp, unsigned char **namep)
60 unsigned char *label, *name;
63 // set namep to the end of the block
64 *namep = name = m->_packet + m->_len;
66 // loop storing label in the block
67 for(label = *bufp; *label != 0; name += *label + 1, label += *label + 1)
69 // skip past any compression pointers, kick out if end encountered (bad data prolly)
71 if(*(label = m->_buf + _ldecomp(label)) == 0) break;
73 // make sure we're not over the limits
74 if((name + *label) - *namep > 255 || m->_len + ((name + *label) - *namep) > 4096) return;
76 // copy chars for this label
77 memcpy(name,label+1,*label);
82 for(label = *bufp; *label != 0 && !(*label & 0xc0 && label++); label += *label + 1);
85 // terminate name and check for cache or cache it
87 for(x = 0; x <= 19 && m->_labels[x]; x++)
89 if(strcmp(*namep,m->_labels[x])) continue;
90 *namep = m->_labels[x];
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;
99 // internal label matching
100 int _lmatch(struct message *m, unsigned char *l1, unsigned char *l2)
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));
109 if(l1 == l2) return 1;
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;
120 // at the end, all matched
121 if(*l1 == 0 && *l2 == 0) return 1;
124 return _lmatch(m,l1,l2);
127 // nasty, convert host into label using compression
128 int _host(struct message *m, unsigned char **bufp, unsigned char *name)
130 unsigned char label[256], *l;
131 int len = 0, x = 1, y = 0, last = 0;
133 if(name == 0) return 0;
140 if(!name[y+1]) break;
141 label[last] = x - (last + 1);
146 if(x++ == 255) return 0;
149 label[last] = x - (last + 1);
150 if(x == 1) x--; // special case, bad names, but handle correctly
152 label[x] = 0; // always terminate w/ a 0
154 // double-loop checking each label against all m->_labels for match
155 for(x = 0; label[x]; x += label[x] + 1)
157 for(y = 0; m->_labels[y]; y++)
158 if(_lmatch(m,label+x,m->_labels[y]))
160 // matching label, set up pointer
162 short2net(m->_labels[y] - m->_packet, &l);
167 if(label[x] & 0xc0) break;
170 // copy into buffer, point there now
171 memcpy(*bufp,label,len);
175 // for each new label, store it's location for future compression
176 for(x = 0; l[x]; x += l[x] + 1)
178 if(l[x] & 0xc0) break;
179 if(m->_label + 1 >= 19) break;
180 m->_labels[m->_label++] = l + x;
186 int _rrparse(struct message *m, struct resource *rr, int count, unsigned char **bufp)
189 for(i=0; i < count; i++)
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);
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);
203 // parse commonly known ones
207 if(m->_len + 16 > MAX_PACKET_LEN) return 1;
208 rr[i].known.a.name = m->_packet + m->_len;
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);
214 _label(m, bufp, &(rr[i].known.ns.name));
217 _label(m, bufp, &(rr[i].known.cname.name));
220 _label(m, bufp, &(rr[i].known.ptr.name));
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));
229 *bufp += rr[i].rdlength;
236 void message_parse(struct message *m, unsigned char *packet)
241 if(packet == 0 || m == 0) return;
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;
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;
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; }
268 my(m->qd, sizeof(struct question) * m->qdcount);
269 for(i=0; i < m->qdcount; i++)
271 _label(m, &buf, &(m->qd[i].name));
272 m->qd[i].type = net2short(&buf);
273 m->qd[i].class = net2short(&buf);
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;
285 void message_qd(struct message *m, unsigned char *name, unsigned short int type, unsigned short int class)
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));
294 void _rrappend(struct message *m, unsigned char *name, unsigned short int type, unsigned short int class, unsigned long int ttl)
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));
303 void message_an(struct message *m, unsigned char *name, unsigned short int type, unsigned short int class, unsigned long int ttl)
306 _rrappend(m,name,type,class,ttl);
309 void message_ns(struct message *m, unsigned char *name, unsigned short int type, unsigned short int class, unsigned long int ttl)
312 _rrappend(m,name,type,class,ttl);
315 void message_ar(struct message *m, unsigned char *name, unsigned short int type, unsigned short int class, unsigned long int ttl)
318 _rrappend(m,name,type,class,ttl);
321 void message_rdata_long(struct message *m, unsigned long int l)
323 short2net(4, &(m->_buf));
324 long2net(l, &(m->_buf));
327 void message_rdata_name(struct message *m, unsigned char *name)
329 unsigned char *mybuf = m->_buf;
331 short2net(_host(m, &(m->_buf), name),&mybuf); // hackish, but cute
334 void message_rdata_srv(struct message *m, unsigned short int priority, unsigned short int weight, unsigned short int port, unsigned char *name)
336 unsigned char *mybuf = m->_buf;
338 short2net(priority, &(m->_buf));
339 short2net(weight, &(m->_buf));
340 short2net(port, &(m->_buf));
341 short2net(_host(m, &(m->_buf), name) + 6, &mybuf);
344 void message_rdata_raw(struct message *m, unsigned char *rdata, unsigned short int rdlength)
346 if((m->_buf - m->_packet) + rdlength > 4096) rdlength = 0;
347 short2net(rdlength, &(m->_buf));
348 memcpy(m->_buf,rdata,rdlength);
352 unsigned char *message_packet(struct message *m)
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;
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
374 int message_packet_len(struct message *m)
376 if(m->_buf == 0) return 12;
377 return m->_buf - m->_packet;