File indexing completed on 2024-05-19 04:06:37
0001 /* 0002 * Copyright (C) 2006 Justin Karneges 0003 * 0004 * Permission is hereby granted, free of charge, to any person obtaining a 0005 * copy of this software and associated documentation files (the 0006 * "Software"), to deal in the Software without restriction, including 0007 * without limitation the rights to use, copy, modify, merge, publish, 0008 * distribute, sublicense, and/or sell copies of the Software, and to 0009 * permit persons to whom the Software is furnished to do so, subject to 0010 * the following conditions: 0011 * 0012 * The above copyright notice and this permission notice shall be included 0013 * in all copies or substantial portions of the Software. 0014 * 0015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 0016 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 0017 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 0018 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 0019 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 0020 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 0021 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 0022 */ 0023 0024 #include "jdns_packet.h" 0025 0026 #include "jdns_p.h" 0027 0028 /* maximum length of a sublabel */ 0029 #define MAX_SUBLABEL_LENGTH 63 0030 0031 /* maximum length of a label, including final terminating zero (root sublabel) */ 0032 /* according to RFC 2181, the maximum length is 255, not counting the root */ 0033 /* sublabel. so, with the root sublabel, that means a max length of 256. */ 0034 #define MAX_LABEL_LENGTH 256 0035 0036 /* jer's endian functions */ 0037 static unsigned short int net2short(const unsigned char **bufp) 0038 { 0039 unsigned short int i; 0040 i = **bufp; 0041 i <<= 8; 0042 i |= *(*bufp + 1); 0043 *bufp += 2; 0044 return i; 0045 } 0046 0047 static unsigned long int net2long(const unsigned char **bufp) 0048 { 0049 unsigned long int l; 0050 l = **bufp; 0051 l <<= 8; 0052 l |= *(*bufp + 1); 0053 l <<= 8; 0054 l |= *(*bufp + 2); 0055 l <<= 8; 0056 l |= *(*bufp + 3); 0057 *bufp += 4; 0058 return l; 0059 } 0060 0061 static void short2net(unsigned short int i, unsigned char **bufp) 0062 { 0063 *(*bufp + 1) = (unsigned char)i; 0064 i >>= 8; 0065 **bufp = (unsigned char)i; 0066 *bufp += 2; 0067 } 0068 0069 static void long2net(unsigned long int l, unsigned char **bufp) 0070 { 0071 *(*bufp + 3) = (unsigned char)l; 0072 l >>= 8; 0073 *(*bufp + 2) = (unsigned char)l; 0074 l >>= 8; 0075 *(*bufp + 1) = (unsigned char)l; 0076 l >>= 8; 0077 **bufp = (unsigned char)l; 0078 *bufp += 4; 0079 } 0080 0081 /* label stuff */ 0082 typedef struct jdns_packet_label 0083 { 0084 JDNS_OBJECT 0085 int offset; 0086 jdns_string_t *value; 0087 } jdns_packet_label_t; 0088 0089 static void jdns_packet_label_delete(jdns_packet_label_t *a); 0090 static jdns_packet_label_t *jdns_packet_label_copy(const jdns_packet_label_t *a); 0091 0092 static jdns_packet_label_t *jdns_packet_label_new() 0093 { 0094 jdns_packet_label_t *a = JDNS_OBJECT_NEW(jdns_packet_label); 0095 a->offset = 0; 0096 a->value = 0; 0097 return a; 0098 } 0099 0100 jdns_packet_label_t *jdns_packet_label_copy(const jdns_packet_label_t *a) 0101 { 0102 jdns_packet_label_t *c = jdns_packet_label_new(); 0103 c->offset = a->offset; 0104 if(a->value) 0105 c->value = jdns_string_copy(a->value); 0106 return c; 0107 } 0108 0109 void jdns_packet_label_delete(jdns_packet_label_t *a) 0110 { 0111 if(!a) 0112 return; 0113 jdns_string_delete(a->value); 0114 jdns_object_free(a); 0115 } 0116 0117 /* gets an offset for decompression. does range and hop count checking also */ 0118 static int getoffset(const unsigned char *str, int refsize, int *hopsleft) 0119 { 0120 unsigned short int x; 0121 if(*hopsleft <= 0) 0122 return -1; 0123 --(*hopsleft); 0124 x = str[0] & 0x3f; 0125 x <<= 8; 0126 x |= str[1]; 0127 /* stay in bounds */ 0128 if(x >= refsize) 0129 return -1; 0130 return x; 0131 } 0132 0133 static int readlabel(const unsigned char *in, int insize, const unsigned char *ref, int refsize, int *_at, jdns_string_t **name) 0134 { 0135 int at; 0136 /* string format is one character smaller than dns format. e.g.: */ 0137 /* dns: [7] affinix [3] com [0] = 13 bytes */ 0138 /* string: "affinix.com." = 12 bytes */ 0139 /* only exception is '.' itself, but that won't influence the max. */ 0140 unsigned char out[MAX_LABEL_LENGTH - 1]; 0141 int out_size; 0142 const unsigned char *label, *last; 0143 int hopped_yet; 0144 int hopsleft; 0145 int label_size; 0146 0147 at = *_at; 0148 0149 /* stay in range */ 0150 if(at < 0 || at >= insize) 0151 return 0; 0152 0153 out_size = 0; 0154 label = in + at; 0155 hopped_yet = 0; 0156 last = in + insize; 0157 while(1) 0158 { 0159 /* need a byte */ 0160 if(label + 1 > last) 0161 goto error; 0162 0163 /* we make this a while loop instead of an 'if', in case */ 0164 /* there's a pointer to a pointer. as a precaution, */ 0165 /* we will hop no more than 8 times */ 0166 hopsleft = 8; 0167 while(*label & 0xc0) 0168 { 0169 int offset; 0170 0171 /* need the next byte, too */ 0172 if(label + 2 > last) 0173 goto error; 0174 0175 offset = getoffset(label, refsize, &hopsleft); 0176 if(offset == -1) 0177 goto error; 0178 0179 label = ref + offset; 0180 if(!hopped_yet) 0181 { 0182 at += 2; 0183 hopped_yet = 1; 0184 last = ref + refsize; 0185 } 0186 0187 /* need a byte */ 0188 if(label + 1 > last) 0189 goto error; 0190 } 0191 0192 label_size = *label & 0x3f; 0193 0194 /* null label? then we're done */ 0195 if(label_size == 0) 0196 { 0197 if(!hopped_yet) 0198 ++at; 0199 break; 0200 } 0201 0202 /* enough source bytes? (length byte + length) */ 0203 if(label + label_size + 1 > last) 0204 goto error; 0205 0206 /* enough dest bytes? (length + dot) */ 0207 if(out_size + label_size + 1 > MAX_LABEL_LENGTH - 1) 0208 goto error; 0209 0210 memcpy(out + out_size, label + 1, label_size); 0211 out_size += label_size; 0212 out[out_size] = '.'; 0213 ++out_size; 0214 0215 if(!hopped_yet) 0216 at += label_size + 1; 0217 0218 label += label_size + 1; 0219 } 0220 0221 *_at = at; 0222 *name = jdns_string_new(); 0223 jdns_string_set(*name, out, out_size); 0224 return 1; 0225 0226 error: 0227 return 0; 0228 } 0229 0230 /* this function compares labels in label format: */ 0231 /* [length] [value ...] [length] [value ...] [0] */ 0232 static int matchlabel(const unsigned char *a, int asize, const unsigned char *b, int bsize, const unsigned char *ref, int refsize, int ahopsleft, int bhopsleft) 0233 { 0234 int n, alen, blen, offset; 0235 0236 /* same pointer? */ 0237 if(a == b) 0238 return 1; 0239 0240 if(asize < 1 || bsize < 1) 0241 return 0; 0242 0243 /* always ensure we get called without a pointer */ 0244 if(*a & 0xc0) 0245 { 0246 if(asize < 2) 0247 return 0; 0248 offset = getoffset(a, refsize, &ahopsleft); 0249 if(offset == -1) 0250 return 0; 0251 return matchlabel(ref + offset, refsize - offset, b, bsize, ref, refsize, ahopsleft, bhopsleft); 0252 } 0253 if(*b & 0xc0) 0254 { 0255 if(bsize < 2) 0256 return 0; 0257 offset = getoffset(b, refsize, &bhopsleft); 0258 if(offset == -1) 0259 return 0; 0260 return matchlabel(a, asize, ref + offset, refsize - offset, ref, refsize, ahopsleft, bhopsleft); 0261 } 0262 0263 alen = *a & 0x3f; 0264 blen = *b & 0x3f; 0265 0266 /* must be same length */ 0267 if(alen != blen) 0268 return 0; 0269 0270 /* done? */ 0271 if(alen == 0) 0272 return 1; 0273 0274 /* length byte + length + first byte of next label */ 0275 if(asize < alen + 2) 0276 return 0; 0277 if(bsize < blen + 2) 0278 return 0; 0279 0280 /* compare the value */ 0281 for(n = 1; n < alen + 1; ++n) 0282 { 0283 if(a[n] != b[n]) 0284 return 0; 0285 } 0286 0287 /* try next labels */ 0288 n = alen + 1; 0289 return matchlabel(a + n, asize - n, b + n, bsize - n, ref, refsize, ahopsleft, bhopsleft); 0290 } 0291 0292 int jdns_packet_name_isvalid(const unsigned char *name, int size) 0293 { 0294 int n, at, len; 0295 0296 /* at least one byte, no larger than MAX_LABEL_LENGTH - 1 (one byte is */ 0297 /* gained when converting to a label) */ 0298 if(size < 1 || size > (MAX_LABEL_LENGTH - 1)) 0299 return 0; 0300 0301 /* last byte must be a dot */ 0302 if(name[size - 1] != '.') 0303 return 0; 0304 0305 /* first byte can't be a dot if there are characters after */ 0306 if(size > 1 && name[0] == '.') 0307 return 0; 0308 0309 /* each sublabel must be between 1 and MAX_SUBLABEL_LENGTH in length */ 0310 at = 0; 0311 while(1) 0312 { 0313 /* search for dot or end */ 0314 for(n = at; n < size; ++n) 0315 { 0316 if(name[n] == '.') 0317 break; 0318 } 0319 /* length of last one is always zero */ 0320 if(n >= size) 0321 break; 0322 0323 len = n - at; 0324 if(len < 1 || len > MAX_SUBLABEL_LENGTH) 0325 return 0; 0326 at = n + 1; /* skip over the dot */ 0327 } 0328 0329 return 1; 0330 } 0331 0332 /* this function assumes label is pointing to a MAX_LABEL_LENGTH byte buffer */ 0333 static int name_to_label(const jdns_string_t *name, unsigned char *label) 0334 { 0335 int n, i, at, len; 0336 0337 if(!jdns_packet_name_isvalid(name->data, name->size)) 0338 return -1; 0339 0340 if(name->size == 1) 0341 { 0342 label[0] = 0; 0343 return 1; 0344 } 0345 0346 at = 0; 0347 i = 0; 0348 while(1) 0349 { 0350 /* search for dot or end */ 0351 for(n = at; n < name->size; ++n) 0352 { 0353 if(name->data[n] == '.') 0354 break; 0355 } 0356 len = n - at; 0357 if(i + (len + 1) > MAX_LABEL_LENGTH) /* length byte + length */ 0358 return 0; 0359 0360 label[i++] = len; 0361 memcpy(label + i, name->data + at, len); 0362 i += len; 0363 0364 if(n >= name->size) /* end? */ 0365 break; 0366 at = n + 1; /* skip over the dot */ 0367 } 0368 0369 return i; 0370 } 0371 0372 /* lookup list is made of jdns_packet_labels */ 0373 static int writelabel(const jdns_string_t *name, int at, int left, unsigned char **bufp, jdns_list_t *lookup) 0374 { 0375 unsigned char label[MAX_LABEL_LENGTH]; 0376 int n, i, len; 0377 unsigned char *l; 0378 unsigned char *ref; 0379 int refsize; 0380 0381 len = name_to_label(name, label); 0382 if(len == -1) 0383 return 0; 0384 0385 ref = *bufp - at; 0386 refsize = at + left; 0387 for(n = 0; label[n]; n += label[n] + 1) 0388 { 0389 for(i = 0; i < lookup->count; ++i) 0390 { 0391 jdns_packet_label_t *pl = (jdns_packet_label_t *)lookup->item[i]; 0392 0393 if(matchlabel(label + n, len - n, pl->value->data, pl->value->size, ref, refsize, 8, 8)) 0394 { 0395 /* set up a pointer right here, overwriting */ 0396 /* the length byte and the first content */ 0397 /* byte of this section within 'label'. */ 0398 /* this is safe, because the length value */ 0399 /* will always be greater than zero, */ 0400 /* ensuring we have two bytes available to */ 0401 /* use. */ 0402 l = label + n; 0403 short2net((unsigned short int)pl->offset, &l); 0404 label[n] |= 0xc0; 0405 len = n + 2; /* cut things short */ 0406 break; 0407 } 0408 } 0409 if(label[n] & 0xc0) /* double loop, so break again */ 0410 break; 0411 } 0412 0413 if(left < len) 0414 return 0; 0415 0416 /* copy into buffer, point there now */ 0417 memcpy(*bufp, label, len); 0418 l = *bufp; 0419 *bufp += len; 0420 0421 /* for each new label, store its location for future compression */ 0422 for(n = 0; l[n]; n += l[n] + 1) 0423 { 0424 jdns_string_t *str; 0425 jdns_packet_label_t *pl; 0426 if(l[n] & 0xc0) 0427 break; 0428 0429 pl = jdns_packet_label_new(); 0430 str = jdns_string_new(); 0431 jdns_string_set(str, l + n, len - n); 0432 pl->offset = l + n - ref; 0433 pl->value = str; 0434 jdns_list_insert(lookup, pl, -1); 0435 } 0436 0437 return 1; 0438 } 0439 0440 /*---------------------------------------------------------------------------- */ 0441 /* jdns_packet_write */ 0442 /*---------------------------------------------------------------------------- */ 0443 #define JDNS_PACKET_WRITE_RAW 0 0444 #define JDNS_PACKET_WRITE_NAME 1 0445 0446 struct jdns_packet_write 0447 { 0448 JDNS_OBJECT 0449 int type; 0450 jdns_string_t *value; 0451 }; 0452 0453 void jdns_packet_write_delete(jdns_packet_write_t *a); 0454 jdns_packet_write_t *jdns_packet_write_copy(const jdns_packet_write_t *a); 0455 0456 jdns_packet_write_t *jdns_packet_write_new() 0457 { 0458 jdns_packet_write_t *a = JDNS_OBJECT_NEW(jdns_packet_write); 0459 a->type = 0; 0460 a->value = 0; 0461 return a; 0462 } 0463 0464 jdns_packet_write_t *jdns_packet_write_copy(const jdns_packet_write_t *a) 0465 { 0466 jdns_packet_write_t *c = jdns_packet_write_new(); 0467 c->type = a->type; 0468 if(a->value) 0469 c->value = jdns_string_copy(a->value); 0470 return c; 0471 } 0472 0473 void jdns_packet_write_delete(jdns_packet_write_t *a) 0474 { 0475 if(!a) 0476 return; 0477 jdns_string_delete(a->value); 0478 jdns_object_free(a); 0479 } 0480 0481 /*---------------------------------------------------------------------------- */ 0482 /* jdns_packet_question */ 0483 /*---------------------------------------------------------------------------- */ 0484 jdns_packet_question_t *jdns_packet_question_new() 0485 { 0486 jdns_packet_question_t *a = JDNS_OBJECT_NEW(jdns_packet_question); 0487 a->qname = 0; 0488 a->qtype = 0; 0489 a->qclass = 0; 0490 return a; 0491 } 0492 0493 jdns_packet_question_t *jdns_packet_question_copy(const jdns_packet_question_t *a) 0494 { 0495 jdns_packet_question_t *c = jdns_packet_question_new(); 0496 if(a->qname) 0497 c->qname = jdns_string_copy(a->qname); 0498 c->qtype = a->qtype; 0499 c->qclass = a->qclass; 0500 return c; 0501 } 0502 0503 void jdns_packet_question_delete(jdns_packet_question_t *a) 0504 { 0505 if(!a) 0506 return; 0507 jdns_string_delete(a->qname); 0508 jdns_object_free(a); 0509 } 0510 0511 /*---------------------------------------------------------------------------- */ 0512 /* jdns_packet_resource */ 0513 /*---------------------------------------------------------------------------- */ 0514 jdns_packet_resource_t *jdns_packet_resource_new() 0515 { 0516 jdns_packet_resource_t *a = JDNS_OBJECT_NEW(jdns_packet_resource); 0517 a->qname = 0; 0518 a->qtype = 0; 0519 a->qclass = 0; 0520 a->ttl = 0; 0521 a->rdlength = 0; 0522 a->rdata = 0; 0523 0524 a->writelog = jdns_list_new(); 0525 a->writelog->valueList = 1; 0526 return a; 0527 } 0528 0529 jdns_packet_resource_t *jdns_packet_resource_copy(const jdns_packet_resource_t *a) 0530 { 0531 jdns_packet_resource_t *c = jdns_packet_resource_new(); 0532 if(a->qname) 0533 c->qname = jdns_string_copy(a->qname); 0534 c->qtype = a->qtype; 0535 c->qclass = a->qclass; 0536 c->ttl = a->ttl; 0537 c->rdlength = a->rdlength; 0538 c->rdata = jdns_copy_array(a->rdata, a->rdlength); 0539 0540 jdns_list_delete(c->writelog); 0541 c->writelog = jdns_list_copy(a->writelog); 0542 return c; 0543 } 0544 0545 void jdns_packet_resource_delete(jdns_packet_resource_t *a) 0546 { 0547 if(!a) 0548 return; 0549 jdns_string_delete(a->qname); 0550 if(a->rdata) 0551 jdns_free(a->rdata); 0552 jdns_list_delete(a->writelog); 0553 jdns_object_free(a); 0554 } 0555 0556 void jdns_packet_resource_add_bytes(jdns_packet_resource_t *a, const unsigned char *data, int size) 0557 { 0558 jdns_packet_write_t *write = jdns_packet_write_new(); 0559 write->type = JDNS_PACKET_WRITE_RAW; 0560 write->value = jdns_string_new(); 0561 jdns_string_set(write->value, data, size); 0562 jdns_list_insert_value(a->writelog, write, -1); 0563 jdns_packet_write_delete(write); 0564 } 0565 0566 void jdns_packet_resource_add_name(jdns_packet_resource_t *a, const jdns_string_t *name) 0567 { 0568 jdns_packet_write_t *write = jdns_packet_write_new(); 0569 write->type = JDNS_PACKET_WRITE_NAME; 0570 write->value = jdns_string_copy(name); 0571 jdns_list_insert_value(a->writelog, write, -1); 0572 jdns_packet_write_delete(write); 0573 } 0574 0575 int jdns_packet_resource_read_name(const jdns_packet_resource_t *a, const jdns_packet_t *p, int *at, jdns_string_t **name) 0576 { 0577 return readlabel(a->rdata, a->rdlength, p->raw_data, p->raw_size, at, name); 0578 } 0579 0580 /*---------------------------------------------------------------------------- */ 0581 /* jdns_packet */ 0582 /*---------------------------------------------------------------------------- */ 0583 0584 /* note: both process_qsection and process_rrsection modify the 'dest' list, */ 0585 /* even if later items cause an error. this turns out to be convenient */ 0586 /* for handling truncated dns packets */ 0587 0588 static int process_qsection(jdns_list_t *dest, int count, const unsigned char *data, int size, const unsigned char **bufp) 0589 { 0590 int n; 0591 int offset, at; 0592 jdns_string_t *name = 0; 0593 const unsigned char *buf; 0594 0595 buf = *bufp; 0596 for(n = 0; n < count; ++n) 0597 { 0598 jdns_packet_question_t *q; 0599 0600 offset = buf - data; 0601 at = 0; 0602 0603 if(!readlabel(data + offset, size - offset, data, size, &at, &name)) 0604 goto error; 0605 0606 offset += at; 0607 0608 /* need 4 more bytes */ 0609 if(size - offset < 4) 0610 goto error; 0611 0612 buf = data + offset; 0613 0614 q = jdns_packet_question_new(); 0615 q->qname = name; 0616 name = 0; 0617 q->qtype = net2short(&buf); 0618 q->qclass = net2short(&buf); 0619 0620 jdns_list_insert_value(dest, q, -1); 0621 jdns_packet_question_delete(q); 0622 } 0623 0624 *bufp = buf; 0625 return 1; 0626 0627 error: 0628 jdns_string_delete(name); 0629 return 0; 0630 } 0631 0632 static int process_rrsection(jdns_list_t *dest, int count, const unsigned char *data, int size, const unsigned char **bufp) 0633 { 0634 int n; 0635 int offset, at; 0636 jdns_string_t *name = 0; 0637 const unsigned char *buf; 0638 0639 buf = *bufp; 0640 for(n = 0; n < count; ++n) 0641 { 0642 jdns_packet_resource_t *r; 0643 0644 offset = buf - data; 0645 at = 0; 0646 0647 if(!readlabel(data + offset, size - offset, data, size, &at, &name)) 0648 goto error; 0649 0650 offset += at; 0651 0652 /* need 10 more bytes */ 0653 if(offset + 10 > size) 0654 goto error; 0655 0656 buf = data + offset; 0657 0658 r = jdns_packet_resource_new(); 0659 r->qname = name; 0660 name = 0; 0661 r->qtype = net2short(&buf); 0662 r->qclass = net2short(&buf); 0663 r->ttl = net2long(&buf); 0664 0665 /* per RFC 2181, ttl is supposed to be a 31 bit number. if */ 0666 /* the top bit of the 32 bit field is 1, then entire ttl is */ 0667 /* to be considered 0. */ 0668 if(r->ttl & 0x80000000) 0669 r->ttl = 0; 0670 0671 r->rdlength = net2short(&buf); 0672 0673 offset = buf - data; 0674 0675 /* make sure we have enough for the rdata */ 0676 if(size - offset < r->rdlength) 0677 { 0678 jdns_packet_resource_delete(r); 0679 goto error; 0680 } 0681 0682 r->rdata = jdns_copy_array(buf, r->rdlength); 0683 buf += r->rdlength; 0684 0685 jdns_list_insert_value(dest, r, -1); 0686 jdns_packet_resource_delete(r); 0687 } 0688 0689 *bufp = buf; 0690 return 1; 0691 0692 error: 0693 jdns_string_delete(name); 0694 return 0; 0695 } 0696 0697 static int append_qsection(const jdns_list_t *src, int at, int left, unsigned char **bufp, jdns_list_t *lookup) 0698 { 0699 unsigned char *buf, *start, *last; 0700 int n; 0701 0702 buf = *bufp; 0703 start = buf - at; 0704 last = buf + left; 0705 for(n = 0; n < src->count; ++n) 0706 { 0707 jdns_packet_question_t *q = (jdns_packet_question_t *)src->item[n]; 0708 0709 if(!writelabel(q->qname, buf - start, last - buf, &buf, lookup)) 0710 goto error; 0711 0712 if(buf + 4 > last) 0713 goto error; 0714 0715 short2net(q->qtype, &buf); 0716 short2net(q->qclass, &buf); 0717 } 0718 0719 *bufp = buf; 0720 return 1; 0721 0722 error: 0723 return 0; 0724 } 0725 0726 static int append_rrsection(const jdns_list_t *src, int at, int left, unsigned char **bufp, jdns_list_t *lookup) 0727 { 0728 unsigned char *buf, *start, *last, *rdlengthp; 0729 int n, i, rdlength; 0730 0731 buf = *bufp; 0732 start = buf - at; 0733 last = buf + left; 0734 for(n = 0; n < src->count; ++n) 0735 { 0736 jdns_packet_resource_t *r = (jdns_packet_resource_t *)src->item[n]; 0737 0738 if(!writelabel(r->qname, buf - start, last - buf, &buf, lookup)) 0739 goto error; 0740 0741 if(buf + 10 > last) 0742 goto error; 0743 0744 short2net(r->qtype, &buf); 0745 short2net(r->qclass, &buf); 0746 long2net(r->ttl, &buf); 0747 0748 /* skip over rdlength */ 0749 rdlengthp = buf; 0750 buf += 2; 0751 0752 /* play write log */ 0753 rdlength = 0; 0754 for(i = 0; i < r->writelog->count; ++i) 0755 { 0756 jdns_packet_write_t *write = (jdns_packet_write_t *)r->writelog->item[i]; 0757 if(write->type == JDNS_PACKET_WRITE_RAW) 0758 { 0759 if(buf + write->value->size > last) 0760 goto error; 0761 0762 memcpy(buf, write->value->data, write->value->size); 0763 buf += write->value->size; 0764 } 0765 else /* JDNS_PACKET_WRITE_NAME */ 0766 { 0767 if(!writelabel(write->value, buf - start, last - buf, &buf, lookup)) 0768 goto error; 0769 } 0770 } 0771 0772 i = buf - rdlengthp; /* should be rdata size + 2 */ 0773 short2net((unsigned short int)(i - 2), &rdlengthp); 0774 } 0775 0776 *bufp = buf; 0777 return 1; 0778 0779 error: 0780 return 0; 0781 } 0782 0783 jdns_packet_t *jdns_packet_new() 0784 { 0785 jdns_packet_t *a = JDNS_OBJECT_NEW(jdns_packet); 0786 a->id = 0; 0787 a->opts.qr = 0; 0788 a->opts.opcode = 0; 0789 a->opts.aa = 0; 0790 a->opts.tc = 0; 0791 a->opts.rd = 0; 0792 a->opts.ra = 0; 0793 a->opts.z = 0; 0794 a->opts.rcode = 0; 0795 0796 a->questions = jdns_list_new(); 0797 a->answerRecords = jdns_list_new(); 0798 a->authorityRecords = jdns_list_new(); 0799 a->additionalRecords = jdns_list_new(); 0800 0801 a->questions->valueList = 1; 0802 a->answerRecords->valueList = 1; 0803 a->authorityRecords->valueList = 1; 0804 a->additionalRecords->valueList = 1; 0805 0806 a->fully_parsed = 0; 0807 0808 a->raw_size = 0; 0809 a->raw_data = 0; 0810 return a; 0811 } 0812 0813 jdns_packet_t *jdns_packet_copy(const jdns_packet_t *a) 0814 { 0815 jdns_packet_t *c = jdns_packet_new(); 0816 c->id = a->id; 0817 c->opts.qr = a->opts.qr; 0818 c->opts.opcode = a->opts.opcode; 0819 c->opts.aa = a->opts.aa; 0820 c->opts.tc = a->opts.tc; 0821 c->opts.rd = a->opts.rd; 0822 c->opts.ra = a->opts.ra; 0823 c->opts.z = a->opts.z; 0824 c->opts.rcode = a->opts.rcode; 0825 0826 jdns_list_delete(c->questions); 0827 jdns_list_delete(c->answerRecords); 0828 jdns_list_delete(c->authorityRecords); 0829 jdns_list_delete(c->additionalRecords); 0830 c->questions = jdns_list_copy(a->questions); 0831 c->answerRecords = jdns_list_copy(a->answerRecords); 0832 c->authorityRecords = jdns_list_copy(a->authorityRecords); 0833 c->additionalRecords = jdns_list_copy(a->additionalRecords); 0834 0835 c->fully_parsed = a->fully_parsed; 0836 0837 c->raw_size = a->raw_size; 0838 c->raw_data = jdns_copy_array(a->raw_data, a->raw_size); 0839 0840 return c; 0841 } 0842 0843 void jdns_packet_delete(jdns_packet_t *a) 0844 { 0845 if(!a) 0846 return; 0847 jdns_list_delete(a->questions); 0848 jdns_list_delete(a->answerRecords); 0849 jdns_list_delete(a->authorityRecords); 0850 jdns_list_delete(a->additionalRecords); 0851 if(a->raw_data) 0852 jdns_free(a->raw_data); 0853 jdns_object_free(a); 0854 } 0855 0856 int jdns_packet_import(jdns_packet_t **a, const unsigned char *data, int size) 0857 { 0858 jdns_packet_t *tmp = 0; 0859 const unsigned char *buf; 0860 0861 /* need at least some data */ 0862 if(!data || size == 0) 0863 return 0; 0864 0865 /* header (id + options + item counts) is 12 bytes */ 0866 if(size < 12) 0867 goto error; 0868 0869 tmp = jdns_packet_new(); 0870 buf = data; 0871 0872 /* id */ 0873 tmp->id = net2short(&buf); 0874 0875 /* options */ 0876 if(buf[0] & 0x80) /* qr is bit 7 */ 0877 tmp->opts.qr = 1; 0878 tmp->opts.opcode = (buf[0] & 0x78) >> 3; /* opcode is bits 6,5,4,3 */ 0879 if(buf[0] & 0x04) /* aa is bit 2 */ 0880 tmp->opts.aa = 1; 0881 if(buf[0] & 0x02) /* tc is bit 1 */ 0882 tmp->opts.tc = 1; 0883 if(buf[0] & 0x01) /* rd is bit 0 */ 0884 tmp->opts.rd = 1; 0885 if(buf[1] & 0x80) /* ra is bit 7 (second byte) */ 0886 tmp->opts.ra = 1; 0887 tmp->opts.z = (buf[1] & 0x70) >> 4; /* z is bits 6,5,4 */ 0888 tmp->opts.rcode = buf[1] & 0x0f; /* rcode is bits 3,2,1,0 */ 0889 buf += 2; 0890 0891 /* item counts */ 0892 tmp->qdcount = net2short(&buf); 0893 tmp->ancount = net2short(&buf); 0894 tmp->nscount = net2short(&buf); 0895 tmp->arcount = net2short(&buf); 0896 0897 /* if these fail, we don't count them as errors, since the packet */ 0898 /* might have been truncated */ 0899 if(!process_qsection(tmp->questions, tmp->qdcount, data, size, &buf)) 0900 goto skip; 0901 if(!process_rrsection(tmp->answerRecords, tmp->ancount, data, size, &buf)) 0902 goto skip; 0903 if(!process_rrsection(tmp->authorityRecords, tmp->nscount, data, size, &buf)) 0904 goto skip; 0905 if(!process_rrsection(tmp->additionalRecords, tmp->arcount, data, size, &buf)) 0906 goto skip; 0907 0908 tmp->fully_parsed = 1; 0909 0910 skip: 0911 /* keep the raw data for reference during rdata parsing */ 0912 tmp->raw_size = size; 0913 tmp->raw_data = jdns_copy_array(data, size); 0914 0915 *a = tmp; 0916 return 1; 0917 0918 error: 0919 jdns_packet_delete(tmp); 0920 return 0; 0921 } 0922 0923 int jdns_packet_export(jdns_packet_t *a, int maxsize) 0924 { 0925 unsigned char *block = 0; 0926 unsigned char *buf, *last; 0927 unsigned char c; 0928 int size; 0929 jdns_list_t *lookup = 0; /* to hold jdns_packet_label_t */ 0930 0931 /* clear out any existing raw data before we begin */ 0932 if(a->raw_data) 0933 { 0934 jdns_free(a->raw_data); 0935 a->raw_data = 0; 0936 a->raw_size = 0; 0937 } 0938 0939 /* preallocate */ 0940 size = maxsize; 0941 block = (unsigned char *)jdns_alloc(size); 0942 memset(block, 0, size); 0943 0944 buf = block; 0945 last = block + size; 0946 0947 if(size < 12) 0948 goto error; 0949 0950 short2net(a->id, &buf); 0951 if(a->opts.qr) 0952 buf[0] |= 0x80; 0953 c = (unsigned char)a->opts.opcode; 0954 buf[0] |= c << 3; 0955 if(a->opts.aa) 0956 buf[0] |= 0x04; 0957 if(a->opts.tc) 0958 buf[0] |= 0x02; 0959 if(a->opts.rd) 0960 buf[0] |= 0x01; 0961 if(a->opts.ra) 0962 buf[1] |= 0x80; 0963 c = (unsigned char)a->opts.z; 0964 buf[1] |= c << 4; 0965 c = (unsigned char)a->opts.rcode; 0966 buf[1] |= c; 0967 buf += 2; 0968 short2net((unsigned short int)a->questions->count, &buf); 0969 short2net((unsigned short int)a->answerRecords->count, &buf); 0970 short2net((unsigned short int)a->authorityRecords->count, &buf); 0971 short2net((unsigned short int)a->additionalRecords->count, &buf); 0972 0973 /* append sections */ 0974 lookup = jdns_list_new(); 0975 lookup->autoDelete = 1; 0976 0977 if(!append_qsection(a->questions, buf - block, last - buf, &buf, lookup)) 0978 goto error; 0979 if(!append_rrsection(a->answerRecords, buf - block, last - buf, &buf, lookup)) 0980 goto error; 0981 if(!append_rrsection(a->authorityRecords, buf - block, last - buf, &buf, lookup)) 0982 goto error; 0983 if(!append_rrsection(a->additionalRecords, buf - block, last - buf, &buf, lookup)) 0984 goto error; 0985 0986 /* done with all sections */ 0987 jdns_list_delete(lookup); 0988 0989 /* condense */ 0990 size = buf - block; 0991 block = (unsigned char *)jdns_realloc(block, size); 0992 0993 /* finalize */ 0994 a->qdcount = a->questions->count; 0995 a->ancount = a->answerRecords->count; 0996 a->nscount = a->authorityRecords->count; 0997 a->arcount = a->additionalRecords->count; 0998 a->raw_data = block; 0999 a->raw_size = size; 1000 1001 return 1; 1002 1003 error: 1004 jdns_list_delete(lookup); 1005 if(block) 1006 jdns_free(block); 1007 return 0; 1008 }