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 }