2
* Copyright (C) 2006 Justin Karneges
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the
6
* "Software"), to deal in the Software without restriction, including
7
* without limitation the rights to use, copy, modify, merge, publish,
8
* distribute, sublicense, and/or sell copies of the Software, and to
9
* permit persons to whom the Software is furnished to do so, subject to
10
* the following conditions:
12
* The above copyright notice and this permission notice shall be included
13
* in all copies or substantial portions of the Software.
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
#include "jdns_packet.h"
28
// jer's endian functions
29
static unsigned short int net2short(const unsigned char **bufp)
39
static unsigned long int net2long(const unsigned char **bufp)
53
static void short2net(unsigned short int i, unsigned char **bufp)
55
*(*bufp + 1) = (unsigned char)i;
57
**bufp = (unsigned char)i;
61
static void long2net(unsigned long int l, unsigned char **bufp)
63
*(*bufp + 3) = (unsigned char)l;
65
*(*bufp + 2) = (unsigned char)l;
67
*(*bufp + 1) = (unsigned char)l;
69
**bufp = (unsigned char)l;
74
typedef struct jdns_packet_label
79
} jdns_packet_label_t;
81
static void jdns_packet_label_delete(jdns_packet_label_t *a);
82
static jdns_packet_label_t *jdns_packet_label_copy(const jdns_packet_label_t *a);
84
static jdns_packet_label_t *jdns_packet_label_new()
86
jdns_packet_label_t *a = JDNS_OBJECT_NEW(jdns_packet_label);
92
jdns_packet_label_t *jdns_packet_label_copy(const jdns_packet_label_t *a)
94
jdns_packet_label_t *c = jdns_packet_label_new();
95
c->offset = a->offset;
97
c->value = jdns_string_copy(a->value);
101
void jdns_packet_label_delete(jdns_packet_label_t *a)
105
jdns_string_delete(a->value);
109
// gets an offset for decompression. does range and hop count checking also
110
static int getoffset(const unsigned char *str, int refsize, int *hopsleft)
112
unsigned short int x;
125
static int readlabel(const unsigned char *in, int insize, const unsigned char *ref, int refsize, int *_at, jdns_string_t **name)
128
unsigned char out[255];
130
const unsigned char *label, *last;
138
if(at < 0 || at >= insize)
151
// we make this a while loop instead of an 'if', in case
152
// there's a pointer to a pointer. as a precaution,
153
// we will hop no more than 8 times
159
// need the next byte, too
163
offset = getoffset(label, refsize, &hopsleft);
167
label = ref + offset;
172
last = ref + refsize;
180
label_size = *label & 0x3f;
182
// null label? then we're done
190
// enough source bytes? (length byte + length)
191
if(label + label_size + 1 > last)
194
// enough dest bytes? (length + dot)
195
if(out_size + label_size + 1 > 255)
198
memcpy(out + out_size, label + 1, label_size);
199
out_size += label_size;
204
at += label_size + 1;
206
label += label_size + 1;
210
*name = jdns_string_new();
211
jdns_string_set(*name, out, out_size);
218
// this function compares labels in label format:
219
// [length] [value ...] [length] [value ...] [0]
220
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)
222
int n, alen, blen, offset;
228
if(asize < 1 || bsize < 1)
231
// always ensure we get called without a pointer
236
offset = getoffset(a, refsize, &ahopsleft);
239
return matchlabel(ref + offset, refsize - offset, b, bsize, ref, refsize, ahopsleft, bhopsleft);
245
offset = getoffset(b, refsize, &bhopsleft);
248
return matchlabel(a, asize, ref + offset, refsize - offset, ref, refsize, ahopsleft, bhopsleft);
254
// must be same length
262
// length byte + length + first byte of next label
269
for(n = 1; n < alen + 1; ++n)
277
return matchlabel(a + n, asize - n, b + n, bsize - n, ref, refsize, ahopsleft, bhopsleft);
280
int jdns_packet_name_isvalid(const unsigned char *name, int size)
284
// at least one byte, no larger than 254 (one byte is gained when
285
// converting to a label, which has a 255 byte max)
286
if(size < 1 || size > 254)
289
// last byte must be a dot
290
if(name[size - 1] != '.')
293
// first byte can't be a dot if there are characters after
294
if(size > 1 && name[0] == '.')
297
// each sublabel must be between 1 and 63 in length
301
// search for dot or end
302
for(n = at; n < size; ++n)
307
// length of last one is always zero
312
if(len < 1 || len > 63)
314
at = n + 1; // skip over the dot
320
// this function assumes label is pointing to a 255 byte buffer
321
static int name_to_label(const jdns_string_t *name, unsigned char *label)
325
if(!jdns_packet_name_isvalid(name->data, name->size))
338
// search for dot or end
339
for(n = at; n < name->size; ++n)
341
if(name->data[n] == '.')
345
if(i + (len + 1) > 255) // length byte + length
349
memcpy(label + i, name->data + at, len);
352
if(n >= name->size) // end?
354
at = n + 1; // skip over the dot
360
// lookup list is made of jdns_packet_labels
361
static int writelabel(const jdns_string_t *name, int at, int left, unsigned char **bufp, jdns_list_t *lookup)
363
unsigned char label[255];
369
len = name_to_label(name, label);
375
for(n = 0; label[n]; n += label[n] + 1)
377
for(i = 0; i < lookup->count; ++i)
379
jdns_packet_label_t *pl = (jdns_packet_label_t *)lookup->item[i];
381
if(matchlabel(label + n, len - n, pl->value->data, pl->value->size, ref, refsize, 8, 8))
383
// set up a pointer right here, overwriting
384
// the length byte and the first content
385
// byte of this section within 'label'.
386
// this is safe, because the length value
387
// will always be greater than zero,
388
// ensuring we have two bytes available to
391
short2net((unsigned short int)pl->offset, &l);
393
len = n + 2; // cut things short
397
if(label[n] & 0xc0) // double loop, so break again
404
// copy into buffer, point there now
405
memcpy(*bufp, label, len);
409
// for each new label, store its location for future compression
410
for(n = 0; l[n]; n += l[n] + 1)
413
jdns_packet_label_t *pl;
417
pl = jdns_packet_label_new();
418
str = jdns_string_new();
419
jdns_string_set(str, l + n, len - n);
420
pl->offset = l + n - ref;
422
jdns_list_insert(lookup, pl, -1);
428
//----------------------------------------------------------------------------
430
//----------------------------------------------------------------------------
431
#define JDNS_PACKET_WRITE_RAW 0
432
#define JDNS_PACKET_WRITE_NAME 1
434
struct jdns_packet_write
438
jdns_string_t *value;
441
void jdns_packet_write_delete(jdns_packet_write_t *a);
442
jdns_packet_write_t *jdns_packet_write_copy(const jdns_packet_write_t *a);
444
jdns_packet_write_t *jdns_packet_write_new()
446
jdns_packet_write_t *a = JDNS_OBJECT_NEW(jdns_packet_write);
452
jdns_packet_write_t *jdns_packet_write_copy(const jdns_packet_write_t *a)
454
jdns_packet_write_t *c = jdns_packet_write_new();
457
c->value = jdns_string_copy(a->value);
461
void jdns_packet_write_delete(jdns_packet_write_t *a)
465
jdns_string_delete(a->value);
469
//----------------------------------------------------------------------------
470
// jdns_packet_question
471
//----------------------------------------------------------------------------
472
jdns_packet_question_t *jdns_packet_question_new()
474
jdns_packet_question_t *a = JDNS_OBJECT_NEW(jdns_packet_question);
481
jdns_packet_question_t *jdns_packet_question_copy(const jdns_packet_question_t *a)
483
jdns_packet_question_t *c = jdns_packet_question_new();
485
c->qname = jdns_string_copy(a->qname);
487
c->qclass = a->qclass;
491
void jdns_packet_question_delete(jdns_packet_question_t *a)
495
jdns_string_delete(a->qname);
499
//----------------------------------------------------------------------------
500
// jdns_packet_resource
501
//----------------------------------------------------------------------------
502
jdns_packet_resource_t *jdns_packet_resource_new()
504
jdns_packet_resource_t *a = JDNS_OBJECT_NEW(jdns_packet_resource);
512
a->writelog = jdns_list_new();
513
a->writelog->valueList = 1;
517
jdns_packet_resource_t *jdns_packet_resource_copy(const jdns_packet_resource_t *a)
519
jdns_packet_resource_t *c = jdns_packet_resource_new();
521
c->qname = jdns_string_copy(a->qname);
523
c->qclass = a->qclass;
525
c->rdlength = a->rdlength;
526
c->rdata = jdns_copy_array(a->rdata, a->rdlength);
528
jdns_list_delete(c->writelog);
529
c->writelog = jdns_list_copy(a->writelog);
533
void jdns_packet_resource_delete(jdns_packet_resource_t *a)
537
jdns_string_delete(a->qname);
540
jdns_list_delete(a->writelog);
544
void jdns_packet_resource_add_bytes(jdns_packet_resource_t *a, const unsigned char *data, int size)
546
jdns_packet_write_t *write = jdns_packet_write_new();
547
write->type = JDNS_PACKET_WRITE_RAW;
548
write->value = jdns_string_new();
549
jdns_string_set(write->value, data, size);
550
jdns_list_insert_value(a->writelog, write, -1);
551
jdns_packet_write_delete(write);
554
void jdns_packet_resource_add_name(jdns_packet_resource_t *a, const jdns_string_t *name)
556
jdns_packet_write_t *write = jdns_packet_write_new();
557
write->type = JDNS_PACKET_WRITE_NAME;
558
write->value = jdns_string_copy(name);
559
jdns_list_insert_value(a->writelog, write, -1);
560
jdns_packet_write_delete(write);
563
int jdns_packet_resource_read_name(const jdns_packet_resource_t *a, const jdns_packet_t *p, int *at, jdns_string_t **name)
565
return readlabel(a->rdata, a->rdlength, p->raw_data, p->raw_size, at, name);
568
//----------------------------------------------------------------------------
570
//----------------------------------------------------------------------------
572
// note: both process_qsection and process_rrsection modify the 'dest' list,
573
// even if later items cause an error. this turns out to be convenient
574
// for handling truncated dns packets
576
static int process_qsection(jdns_list_t *dest, int count, const unsigned char *data, int size, const unsigned char **bufp)
580
jdns_string_t *name = 0;
581
const unsigned char *buf;
584
for(n = 0; n < count; ++n)
586
jdns_packet_question_t *q;
591
if(!readlabel(data + offset, size - offset, data, size, &at, &name))
597
if(size - offset < 4)
602
q = jdns_packet_question_new();
605
q->qtype = net2short(&buf);
606
q->qclass = net2short(&buf);
608
jdns_list_insert_value(dest, q, -1);
609
jdns_packet_question_delete(q);
616
jdns_string_delete(name);
620
static int process_rrsection(jdns_list_t *dest, int count, const unsigned char *data, int size, const unsigned char **bufp)
624
jdns_string_t *name = 0;
625
const unsigned char *buf;
628
for(n = 0; n < count; ++n)
630
jdns_packet_resource_t *r;
635
if(!readlabel(data + offset, size - offset, data, size, &at, &name))
640
// need 10 more bytes
641
if(offset + 10 > size)
646
r = jdns_packet_resource_new();
649
r->qtype = net2short(&buf);
650
r->qclass = net2short(&buf);
651
r->ttl = net2long(&buf);
652
r->rdlength = net2short(&buf);
656
// make sure we have enough for the rdata
657
if(size - offset < r->rdlength)
659
jdns_packet_resource_delete(r);
663
r->rdata = jdns_copy_array(buf, r->rdlength);
666
jdns_list_insert_value(dest, r, -1);
667
jdns_packet_resource_delete(r);
674
jdns_string_delete(name);
678
static int append_qsection(const jdns_list_t *src, int at, int left, unsigned char **bufp, jdns_list_t *lookup)
680
unsigned char *buf, *start, *last;
686
for(n = 0; n < src->count; ++n)
688
jdns_packet_question_t *q = (jdns_packet_question_t *)src->item[n];
690
if(!writelabel(q->qname, buf - start, last - buf, &buf, lookup))
696
short2net(q->qtype, &buf);
697
short2net(q->qclass, &buf);
707
static int append_rrsection(const jdns_list_t *src, int at, int left, unsigned char **bufp, jdns_list_t *lookup)
709
unsigned char *buf, *start, *last, *rdlengthp;
715
for(n = 0; n < src->count; ++n)
717
jdns_packet_resource_t *r = (jdns_packet_resource_t *)src->item[n];
719
if(!writelabel(r->qname, buf - start, last - buf, &buf, lookup))
725
short2net(r->qtype, &buf);
726
short2net(r->qclass, &buf);
727
long2net(r->ttl, &buf);
729
// skip over rdlength
735
for(i = 0; i < r->writelog->count; ++i)
737
jdns_packet_write_t *write = (jdns_packet_write_t *)r->writelog->item[i];
738
if(write->type == JDNS_PACKET_WRITE_RAW)
740
if(buf + write->value->size > last)
743
memcpy(buf, write->value->data, write->value->size);
744
buf += write->value->size;
746
else // JDNS_PACKET_WRITE_NAME
748
if(!writelabel(write->value, buf - start, last - buf, &buf, lookup))
753
i = buf - rdlengthp; // should be rdata size + 2
754
short2net((unsigned short int)(i - 2), &rdlengthp);
764
jdns_packet_t *jdns_packet_new()
766
jdns_packet_t *a = JDNS_OBJECT_NEW(jdns_packet);
777
a->questions = jdns_list_new();
778
a->answerRecords = jdns_list_new();
779
a->authorityRecords = jdns_list_new();
780
a->additionalRecords = jdns_list_new();
782
a->questions->valueList = 1;
783
a->answerRecords->valueList = 1;
784
a->authorityRecords->valueList = 1;
785
a->additionalRecords->valueList = 1;
794
jdns_packet_t *jdns_packet_copy(const jdns_packet_t *a)
796
jdns_packet_t *c = jdns_packet_new();
798
c->opts.qr = a->opts.qr;
799
c->opts.opcode = a->opts.opcode;
800
c->opts.aa = a->opts.aa;
801
c->opts.tc = a->opts.tc;
802
c->opts.rd = a->opts.rd;
803
c->opts.ra = a->opts.ra;
804
c->opts.z = a->opts.z;
805
c->opts.rcode = a->opts.rcode;
807
jdns_list_delete(c->questions);
808
jdns_list_delete(c->answerRecords);
809
jdns_list_delete(c->authorityRecords);
810
jdns_list_delete(c->additionalRecords);
811
c->questions = jdns_list_copy(a->questions);
812
c->answerRecords = jdns_list_copy(a->answerRecords);
813
c->authorityRecords = jdns_list_copy(a->authorityRecords);
814
c->additionalRecords = jdns_list_copy(a->additionalRecords);
816
c->fully_parsed = a->fully_parsed;
818
c->raw_size = a->raw_size;
819
c->raw_data = jdns_copy_array(a->raw_data, a->raw_size);
824
void jdns_packet_delete(jdns_packet_t *a)
828
jdns_list_delete(a->questions);
829
jdns_list_delete(a->answerRecords);
830
jdns_list_delete(a->authorityRecords);
831
jdns_list_delete(a->additionalRecords);
833
jdns_free(a->raw_data);
837
int jdns_packet_import(jdns_packet_t **a, const unsigned char *data, int size)
839
jdns_packet_t *tmp = 0;
840
const unsigned char *buf;
842
// need at least some data
843
if(!data || size == 0)
846
// header (id + options + item counts) is 12 bytes
850
tmp = jdns_packet_new();
854
tmp->id = net2short(&buf);
857
if(buf[0] & 0x80) // qr is bit 7
859
tmp->opts.opcode = (buf[0] & 0x78) >> 3; // opcode is bits 6,5,4,3
860
if(buf[0] & 0x04) // aa is bit 2
862
if(buf[0] & 0x02) // tc is bit 1
864
if(buf[0] & 0x01) // rd is bit 0
866
if(buf[1] & 0x80) // ra is bit 7 (second byte)
868
tmp->opts.z = (buf[1] & 0x70) >> 4; // z is bits 6,5,4
869
tmp->opts.rcode = buf[1] & 0x0f; // rcode is bits 3,2,1,0
873
tmp->qdcount = net2short(&buf);
874
tmp->ancount = net2short(&buf);
875
tmp->nscount = net2short(&buf);
876
tmp->arcount = net2short(&buf);
878
// if these fail, we don't count them as errors, since the packet
879
// might have been truncated
880
if(!process_qsection(tmp->questions, tmp->qdcount, data, size, &buf))
882
if(!process_rrsection(tmp->answerRecords, tmp->ancount, data, size, &buf))
884
if(!process_rrsection(tmp->authorityRecords, tmp->nscount, data, size, &buf))
886
if(!process_rrsection(tmp->additionalRecords, tmp->arcount, data, size, &buf))
889
tmp->fully_parsed = 1;
892
// keep the raw data for reference during rdata parsing
893
tmp->raw_size = size;
894
tmp->raw_data = jdns_copy_array(data, size);
900
jdns_packet_delete(tmp);
904
int jdns_packet_export(jdns_packet_t *a, int maxsize)
906
unsigned char *block = 0;
907
unsigned char *buf, *last;
910
jdns_list_t *lookup = 0; // to hold jdns_packet_label_t
912
// clear out any existing raw data before we begin
915
jdns_free(a->raw_data);
922
block = (unsigned char *)jdns_alloc(size);
923
memset(block, 0, size);
931
short2net(a->id, &buf);
934
c = (unsigned char)a->opts.opcode;
944
c = (unsigned char)a->opts.z;
946
c = (unsigned char)a->opts.rcode;
949
short2net((unsigned short int)a->questions->count, &buf);
950
short2net((unsigned short int)a->answerRecords->count, &buf);
951
short2net((unsigned short int)a->authorityRecords->count, &buf);
952
short2net((unsigned short int)a->additionalRecords->count, &buf);
955
lookup = jdns_list_new();
956
lookup->autoDelete = 1;
958
if(!append_qsection(a->questions, buf - block, last - buf, &buf, lookup))
960
if(!append_rrsection(a->answerRecords, buf - block, last - buf, &buf, lookup))
962
if(!append_rrsection(a->authorityRecords, buf - block, last - buf, &buf, lookup))
964
if(!append_rrsection(a->additionalRecords, buf - block, last - buf, &buf, lookup))
967
// done with all sections
968
jdns_list_delete(lookup);
972
block = (unsigned char *)jdns_realloc(block, size);
975
a->qdcount = a->questions->count;
976
a->ancount = a->answerRecords->count;
977
a->nscount = a->authorityRecords->count;
978
a->arcount = a->additionalRecords->count;
985
jdns_list_delete(lookup);