~ubuntu-branches/ubuntu/utopic/psi/utopic

« back to all changes in this revision

Viewing changes to iris/src/jdns/jdns_packet.c

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2009-09-25 17:49:51 UTC
  • mfrom: (6.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20090925174951-lvm7kdap82o8xhn3
Tags: 0.13-1
* Updated to upstream version 0.13
* Set Standards-Version to 3.8.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2006  Justin Karneges
 
3
 *
 
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:
 
11
 *
 
12
 * The above copyright notice and this permission notice shall be included
 
13
 * in all copies or substantial portions of the Software.
 
14
 *
 
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.
 
22
 */
 
23
 
 
24
#include "jdns_packet.h"
 
25
 
 
26
#include "jdns_p.h"
 
27
 
 
28
// maximum length of a sublabel
 
29
#define MAX_SUBLABEL_LENGTH  63
 
30
 
 
31
// maximum length of a label, including final terminating zero (root sublabel)
 
32
//   according to RFC 2181, the maximum length is 255, not counting the root
 
33
//   sublabel.  so, with the root sublabel, that means a max length of 256.
 
34
#define MAX_LABEL_LENGTH     256
 
35
 
 
36
// jer's endian functions
 
37
static unsigned short int net2short(const unsigned char **bufp)
 
38
{
 
39
        unsigned short int i;
 
40
        i = **bufp;
 
41
        i <<= 8;
 
42
        i |= *(*bufp + 1);
 
43
        *bufp += 2;
 
44
        return i;
 
45
}
 
46
 
 
47
static unsigned long int net2long(const unsigned char **bufp)
 
48
{
 
49
        unsigned long int l;
 
50
        l = **bufp;
 
51
        l <<= 8;
 
52
        l |= *(*bufp + 1);
 
53
        l <<= 8;
 
54
        l |= *(*bufp + 2);
 
55
        l <<= 8;
 
56
        l |= *(*bufp + 3);
 
57
        *bufp += 4;
 
58
        return l;
 
59
}
 
60
 
 
61
static void short2net(unsigned short int i, unsigned char **bufp)
 
62
{
 
63
        *(*bufp + 1) = (unsigned char)i;
 
64
        i >>= 8;
 
65
        **bufp = (unsigned char)i;
 
66
        *bufp += 2;    
 
67
}
 
68
 
 
69
static void long2net(unsigned long int l, unsigned char **bufp)
 
70
{
 
71
        *(*bufp + 3) = (unsigned char)l;
 
72
        l >>= 8;
 
73
        *(*bufp + 2) = (unsigned char)l;
 
74
        l >>= 8;
 
75
        *(*bufp + 1) = (unsigned char)l;
 
76
        l >>= 8;
 
77
        **bufp = (unsigned char)l;
 
78
        *bufp += 4;
 
79
}
 
80
 
 
81
// label stuff
 
82
typedef struct jdns_packet_label
 
83
{
 
84
        JDNS_OBJECT
 
85
        int offset;
 
86
        jdns_string_t *value;
 
87
} jdns_packet_label_t;
 
88
 
 
89
static void jdns_packet_label_delete(jdns_packet_label_t *a);
 
90
static jdns_packet_label_t *jdns_packet_label_copy(const jdns_packet_label_t *a);
 
91
 
 
92
static jdns_packet_label_t *jdns_packet_label_new()
 
93
{
 
94
        jdns_packet_label_t *a = JDNS_OBJECT_NEW(jdns_packet_label);
 
95
        a->offset = 0;
 
96
        a->value = 0;
 
97
        return a;
 
98
}
 
99
 
 
100
jdns_packet_label_t *jdns_packet_label_copy(const jdns_packet_label_t *a)
 
101
{
 
102
        jdns_packet_label_t *c = jdns_packet_label_new();
 
103
        c->offset = a->offset;
 
104
        if(a->value)
 
105
                c->value = jdns_string_copy(a->value);
 
106
        return c;
 
107
}
 
108
 
 
109
void jdns_packet_label_delete(jdns_packet_label_t *a)
 
110
{
 
111
        if(!a)
 
112
                return;
 
113
        jdns_string_delete(a->value);
 
114
        jdns_object_free(a);
 
115
}
 
116
 
 
117
// gets an offset for decompression.  does range and hop count checking also
 
118
static int getoffset(const unsigned char *str, int refsize, int *hopsleft)
 
119
{
 
120
        unsigned short int x;
 
121
        if(*hopsleft <= 0)
 
122
                return -1;
 
123
        --(*hopsleft);
 
124
        x = str[0] & 0x3f;
 
125
        x <<= 8;
 
126
        x |= str[1];
 
127
        // stay in bounds
 
128
        if(x >= refsize)
 
129
                return -1;
 
130
        return x;
 
131
}
 
132
 
 
133
static int readlabel(const unsigned char *in, int insize, const unsigned char *ref, int refsize, int *_at, jdns_string_t **name)
 
134
{
 
135
        int at;
 
136
        // string format is one character smaller than dns format.  e.g.:
 
137
        //   dns:    [7] affinix [3] com [0] = 13 bytes
 
138
        //   string: "affinix.com."          = 12 bytes
 
139
        // only exception is '.' itself, but that won't influence the max.
 
140
        unsigned char out[MAX_LABEL_LENGTH - 1];
 
141
        int out_size;
 
142
        const unsigned char *label, *last;
 
143
        int hopped_yet;
 
144
        int hopsleft;
 
145
        int label_size;
 
146
 
 
147
        at = *_at;
 
148
 
 
149
        // stay in range
 
150
        if(at < 0 || at >= insize)
 
151
                return 0;
 
152
 
 
153
        out_size = 0;
 
154
        label = in + at;
 
155
        hopped_yet = 0;
 
156
        last = in + insize;
 
157
        while(1)
 
158
        {
 
159
                // need a byte
 
160
                if(label + 1 > last)
 
161
                        goto error;
 
162
 
 
163
                // we make this a while loop instead of an 'if', in case
 
164
                //   there's a pointer to a pointer.  as a precaution,
 
165
                //   we will hop no more than 8 times
 
166
                hopsleft = 8;
 
167
                while(*label & 0xc0)
 
168
                {
 
169
                        int offset;
 
170
 
 
171
                        // need the next byte, too
 
172
                        if(label + 2 > last)
 
173
                                goto error;
 
174
 
 
175
                        offset = getoffset(label, refsize, &hopsleft);
 
176
                        if(offset == -1)
 
177
                                goto error;
 
178
 
 
179
                        label = ref + offset;
 
180
                        if(!hopped_yet)
 
181
                        {
 
182
                                at += 2;
 
183
                                hopped_yet = 1;
 
184
                                last = ref + refsize;
 
185
                        }
 
186
 
 
187
                        // need a byte
 
188
                        if(label + 1 > last)
 
189
                                goto error;
 
190
                }
 
191
 
 
192
                label_size = *label & 0x3f;
 
193
 
 
194
                // null label?  then we're done
 
195
                if(label_size == 0)
 
196
                {
 
197
                        if(!hopped_yet)
 
198
                                ++at;
 
199
                        break;
 
200
                }
 
201
 
 
202
                // enough source bytes? (length byte + length)
 
203
                if(label + label_size + 1 > last)
 
204
                        goto error;
 
205
 
 
206
                // enough dest bytes? (length + dot)
 
207
                if(out_size + label_size + 1 > MAX_LABEL_LENGTH - 1)
 
208
                        goto error;
 
209
 
 
210
                memcpy(out + out_size, label + 1, label_size);
 
211
                out_size += label_size;
 
212
                out[out_size] = '.';
 
213
                ++out_size;
 
214
 
 
215
                if(!hopped_yet)
 
216
                        at += label_size + 1;
 
217
 
 
218
                label += label_size + 1;
 
219
        }
 
220
 
 
221
        *_at = at;
 
222
        *name = jdns_string_new();
 
223
        jdns_string_set(*name, out, out_size);
 
224
        return 1;
 
225
 
 
226
error:
 
227
        return 0;
 
228
}
 
229
 
 
230
// this function compares labels in label format:
 
231
//   [length] [value ...] [length] [value ...] [0]
 
232
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)
 
233
{
 
234
        int n, alen, blen, offset;
 
235
 
 
236
        // same pointer?
 
237
        if(a == b)
 
238
                return 1;
 
239
 
 
240
        if(asize < 1 || bsize < 1)
 
241
                return 0;
 
242
 
 
243
        // always ensure we get called without a pointer
 
244
        if(*a & 0xc0)
 
245
        {
 
246
                if(asize < 2)
 
247
                        return 0;
 
248
                offset = getoffset(a, refsize, &ahopsleft);
 
249
                if(offset == -1)
 
250
                        return 0;
 
251
                return matchlabel(ref + offset, refsize - offset, b, bsize, ref, refsize, ahopsleft, bhopsleft);
 
252
        }
 
253
        if(*b & 0xc0)
 
254
        {
 
255
                if(bsize < 2)
 
256
                        return 0;
 
257
                offset = getoffset(b, refsize, &bhopsleft);
 
258
                if(offset == -1)
 
259
                        return 0;
 
260
                return matchlabel(a, asize, ref + offset, refsize - offset, ref, refsize, ahopsleft, bhopsleft);
 
261
        }
 
262
 
 
263
        alen = *a & 0x3f;
 
264
        blen = *b & 0x3f;
 
265
 
 
266
        // must be same length
 
267
        if(alen != blen)
 
268
                return 0;
 
269
 
 
270
        // done?
 
271
        if(alen == 0)
 
272
                return 1;
 
273
 
 
274
        // length byte + length + first byte of next label
 
275
        if(asize < alen + 2)
 
276
                return 0;
 
277
        if(bsize < blen + 2)
 
278
                return 0;
 
279
 
 
280
        // compare the value
 
281
        for(n = 1; n < alen + 1; ++n)
 
282
        {
 
283
                if(a[n] != b[n])
 
284
                        return 0;
 
285
        }
 
286
 
 
287
        // try next labels
 
288
        n = alen + 1;
 
289
        return matchlabel(a + n, asize - n, b + n, bsize - n, ref, refsize, ahopsleft, bhopsleft);
 
290
}
 
291
 
 
292
int jdns_packet_name_isvalid(const unsigned char *name, int size)
 
293
{
 
294
        int n, at, len;
 
295
 
 
296
        // at least one byte, no larger than MAX_LABEL_LENGTH - 1 (one byte is
 
297
        //   gained when converting to a label)
 
298
        if(size < 1 || size > (MAX_LABEL_LENGTH - 1))
 
299
                return 0;
 
300
 
 
301
        // last byte must be a dot
 
302
        if(name[size - 1] != '.')
 
303
                return 0;
 
304
 
 
305
        // first byte can't be a dot if there are characters after
 
306
        if(size > 1 && name[0] == '.')
 
307
                return 0;
 
308
 
 
309
        // each sublabel must be between 1 and MAX_SUBLABEL_LENGTH in length
 
310
        at = 0;
 
311
        while(1)
 
312
        {
 
313
                // search for dot or end
 
314
                for(n = at; n < size; ++n)
 
315
                {
 
316
                        if(name[n] == '.')
 
317
                                break;
 
318
                }
 
319
                // length of last one is always zero
 
320
                if(n >= size)
 
321
                        break;
 
322
 
 
323
                len = n - at;
 
324
                if(len < 1 || len > MAX_SUBLABEL_LENGTH)
 
325
                        return 0;
 
326
                at = n + 1; // skip over the dot
 
327
        }
 
328
 
 
329
        return 1;
 
330
}
 
331
 
 
332
// this function assumes label is pointing to a MAX_LABEL_LENGTH byte buffer
 
333
static int name_to_label(const jdns_string_t *name, unsigned char *label)
 
334
{
 
335
        int n, i, at, len;
 
336
 
 
337
        if(!jdns_packet_name_isvalid(name->data, name->size))
 
338
                return -1;
 
339
 
 
340
        if(name->size == 1)
 
341
        {
 
342
                label[0] = 0;
 
343
                return 1;
 
344
        }
 
345
 
 
346
        at = 0;
 
347
        i = 0;
 
348
        while(1)
 
349
        {
 
350
                // search for dot or end
 
351
                for(n = at; n < name->size; ++n)
 
352
                {
 
353
                        if(name->data[n] == '.')
 
354
                                break;
 
355
                }
 
356
                len = n - at;
 
357
                if(i + (len + 1) > MAX_LABEL_LENGTH) // length byte + length
 
358
                        return 0;
 
359
 
 
360
                label[i++] = len;
 
361
                memcpy(label + i, name->data + at, len);
 
362
                i += len;
 
363
 
 
364
                if(n >= name->size) // end?
 
365
                        break;
 
366
                at = n + 1; // skip over the dot
 
367
        }
 
368
 
 
369
        return i;
 
370
}
 
371
 
 
372
// lookup list is made of jdns_packet_labels
 
373
static int writelabel(const jdns_string_t *name, int at, int left, unsigned char **bufp, jdns_list_t *lookup)
 
374
{
 
375
        unsigned char label[MAX_LABEL_LENGTH];
 
376
        int n, i, len;
 
377
        unsigned char *l;
 
378
        unsigned char *ref;
 
379
        int refsize;
 
380
 
 
381
        len = name_to_label(name, label);
 
382
        if(len == -1)
 
383
                return 0;
 
384
 
 
385
        ref = *bufp - at;
 
386
        refsize = at + left;
 
387
        for(n = 0; label[n]; n += label[n] + 1)
 
388
        {
 
389
                for(i = 0; i < lookup->count; ++i)
 
390
                {
 
391
                        jdns_packet_label_t *pl = (jdns_packet_label_t *)lookup->item[i];
 
392
 
 
393
                        if(matchlabel(label + n, len - n, pl->value->data, pl->value->size, ref, refsize, 8, 8))
 
394
                        {
 
395
                                // set up a pointer right here, overwriting
 
396
                                //   the length byte and the first content
 
397
                                //   byte of this section within 'label'.
 
398
                                //   this is safe, because the length value
 
399
                                //   will always be greater than zero,
 
400
                                //   ensuring we have two bytes available to
 
401
                                //   use.
 
402
                                l = label + n;
 
403
                                short2net((unsigned short int)pl->offset, &l);
 
404
                                label[n] |= 0xc0;
 
405
                                len = n + 2; // cut things short
 
406
                                break;
 
407
                        }
 
408
                }
 
409
                if(label[n] & 0xc0) // double loop, so break again
 
410
                        break;
 
411
        }
 
412
 
 
413
        if(left < len)
 
414
                return 0;
 
415
 
 
416
        // copy into buffer, point there now
 
417
        memcpy(*bufp, label, len);
 
418
        l = *bufp;
 
419
        *bufp += len;
 
420
 
 
421
        // for each new label, store its location for future compression
 
422
        for(n = 0; l[n]; n += l[n] + 1)
 
423
        {
 
424
                jdns_string_t *str;
 
425
                jdns_packet_label_t *pl;
 
426
                if(l[n] & 0xc0)
 
427
                        break;
 
428
 
 
429
                pl = jdns_packet_label_new();
 
430
                str = jdns_string_new();
 
431
                jdns_string_set(str, l + n, len - n);
 
432
                pl->offset = l + n - ref;
 
433
                pl->value = str;
 
434
                jdns_list_insert(lookup, pl, -1);
 
435
        }
 
436
 
 
437
        return 1;
 
438
}
 
439
 
 
440
//----------------------------------------------------------------------------
 
441
// jdns_packet_write
 
442
//----------------------------------------------------------------------------
 
443
#define JDNS_PACKET_WRITE_RAW  0
 
444
#define JDNS_PACKET_WRITE_NAME 1
 
445
 
 
446
struct jdns_packet_write
 
447
{
 
448
        JDNS_OBJECT
 
449
        int type;
 
450
        jdns_string_t *value;
 
451
};
 
452
 
 
453
void jdns_packet_write_delete(jdns_packet_write_t *a);
 
454
jdns_packet_write_t *jdns_packet_write_copy(const jdns_packet_write_t *a);
 
455
 
 
456
jdns_packet_write_t *jdns_packet_write_new()
 
457
{
 
458
        jdns_packet_write_t *a = JDNS_OBJECT_NEW(jdns_packet_write);
 
459
        a->type = 0;
 
460
        a->value = 0;
 
461
        return a;
 
462
}
 
463
 
 
464
jdns_packet_write_t *jdns_packet_write_copy(const jdns_packet_write_t *a)
 
465
{
 
466
        jdns_packet_write_t *c = jdns_packet_write_new();
 
467
        c->type = a->type;
 
468
        if(a->value)
 
469
                c->value = jdns_string_copy(a->value);
 
470
        return c;
 
471
}
 
472
 
 
473
void jdns_packet_write_delete(jdns_packet_write_t *a)
 
474
{
 
475
        if(!a)
 
476
                return;
 
477
        jdns_string_delete(a->value);
 
478
        jdns_object_free(a);
 
479
}
 
480
 
 
481
//----------------------------------------------------------------------------
 
482
// jdns_packet_question
 
483
//----------------------------------------------------------------------------
 
484
jdns_packet_question_t *jdns_packet_question_new()
 
485
{
 
486
        jdns_packet_question_t *a = JDNS_OBJECT_NEW(jdns_packet_question);
 
487
        a->qname = 0;
 
488
        a->qtype = 0;
 
489
        a->qclass = 0;
 
490
        return a;
 
491
}
 
492
 
 
493
jdns_packet_question_t *jdns_packet_question_copy(const jdns_packet_question_t *a)
 
494
{
 
495
        jdns_packet_question_t *c = jdns_packet_question_new();
 
496
        if(a->qname)
 
497
                c->qname = jdns_string_copy(a->qname);
 
498
        c->qtype = a->qtype;
 
499
        c->qclass = a->qclass;
 
500
        return c;
 
501
}
 
502
 
 
503
void jdns_packet_question_delete(jdns_packet_question_t *a)
 
504
{
 
505
        if(!a)
 
506
                return;
 
507
        jdns_string_delete(a->qname);
 
508
        jdns_object_free(a);
 
509
}
 
510
 
 
511
//----------------------------------------------------------------------------
 
512
// jdns_packet_resource
 
513
//----------------------------------------------------------------------------
 
514
jdns_packet_resource_t *jdns_packet_resource_new()
 
515
{
 
516
        jdns_packet_resource_t *a = JDNS_OBJECT_NEW(jdns_packet_resource);
 
517
        a->qname = 0;
 
518
        a->qtype = 0;
 
519
        a->qclass = 0;
 
520
        a->ttl = 0;
 
521
        a->rdlength = 0;
 
522
        a->rdata = 0;
 
523
 
 
524
        a->writelog = jdns_list_new();
 
525
        a->writelog->valueList = 1;
 
526
        return a;
 
527
}
 
528
 
 
529
jdns_packet_resource_t *jdns_packet_resource_copy(const jdns_packet_resource_t *a)
 
530
{
 
531
        jdns_packet_resource_t *c = jdns_packet_resource_new();
 
532
        if(a->qname)
 
533
                c->qname = jdns_string_copy(a->qname);
 
534
        c->qtype = a->qtype;
 
535
        c->qclass = a->qclass;
 
536
        c->ttl = a->ttl;
 
537
        c->rdlength = a->rdlength;
 
538
        c->rdata = jdns_copy_array(a->rdata, a->rdlength);
 
539
 
 
540
        jdns_list_delete(c->writelog);
 
541
        c->writelog = jdns_list_copy(a->writelog);
 
542
        return c;
 
543
}
 
544
 
 
545
void jdns_packet_resource_delete(jdns_packet_resource_t *a)
 
546
{
 
547
        if(!a)
 
548
                return;
 
549
        jdns_string_delete(a->qname);
 
550
        if(a->rdata)
 
551
                jdns_free(a->rdata);
 
552
        jdns_list_delete(a->writelog);
 
553
        jdns_object_free(a);
 
554
}
 
555
 
 
556
void jdns_packet_resource_add_bytes(jdns_packet_resource_t *a, const unsigned char *data, int size)
 
557
{
 
558
        jdns_packet_write_t *write = jdns_packet_write_new();
 
559
        write->type = JDNS_PACKET_WRITE_RAW;
 
560
        write->value = jdns_string_new();
 
561
        jdns_string_set(write->value, data, size);
 
562
        jdns_list_insert_value(a->writelog, write, -1);
 
563
        jdns_packet_write_delete(write);
 
564
}
 
565
 
 
566
void jdns_packet_resource_add_name(jdns_packet_resource_t *a, const jdns_string_t *name)
 
567
{
 
568
        jdns_packet_write_t *write = jdns_packet_write_new();
 
569
        write->type = JDNS_PACKET_WRITE_NAME;
 
570
        write->value = jdns_string_copy(name);
 
571
        jdns_list_insert_value(a->writelog, write, -1);
 
572
        jdns_packet_write_delete(write);
 
573
}
 
574
 
 
575
int jdns_packet_resource_read_name(const jdns_packet_resource_t *a, const jdns_packet_t *p, int *at, jdns_string_t **name)
 
576
{
 
577
        return readlabel(a->rdata, a->rdlength, p->raw_data, p->raw_size, at, name);
 
578
}
 
579
 
 
580
//----------------------------------------------------------------------------
 
581
// jdns_packet
 
582
//----------------------------------------------------------------------------
 
583
 
 
584
// note: both process_qsection and process_rrsection modify the 'dest' list,
 
585
//   even if later items cause an error.  this turns out to be convenient
 
586
//   for handling truncated dns packets
 
587
 
 
588
static int process_qsection(jdns_list_t *dest, int count, const unsigned char *data, int size, const unsigned char **bufp)
 
589
{
 
590
        int n;
 
591
        int offset, at;
 
592
        jdns_string_t *name = 0;
 
593
        const unsigned char *buf;
 
594
 
 
595
        buf = *bufp;
 
596
        for(n = 0; n < count; ++n)
 
597
        {
 
598
                jdns_packet_question_t *q;
 
599
 
 
600
                offset = buf - data;
 
601
                at = 0;
 
602
 
 
603
                if(!readlabel(data + offset, size - offset, data, size, &at, &name))
 
604
                        goto error;
 
605
 
 
606
                offset += at;
 
607
 
 
608
                // need 4 more bytes
 
609
                if(size - offset < 4)
 
610
                        goto error;
 
611
 
 
612
                buf = data + offset;
 
613
 
 
614
                q = jdns_packet_question_new();
 
615
                q->qname = name;
 
616
                name = 0;
 
617
                q->qtype = net2short(&buf);
 
618
                q->qclass = net2short(&buf);
 
619
 
 
620
                jdns_list_insert_value(dest, q, -1);
 
621
                jdns_packet_question_delete(q);
 
622
        }
 
623
 
 
624
        *bufp = buf;
 
625
        return 1;
 
626
 
 
627
error:
 
628
        jdns_string_delete(name);
 
629
        return 0;
 
630
}
 
631
 
 
632
static int process_rrsection(jdns_list_t *dest, int count, const unsigned char *data, int size, const unsigned char **bufp)
 
633
{
 
634
        int n;
 
635
        int offset, at;
 
636
        jdns_string_t *name = 0;
 
637
        const unsigned char *buf;
 
638
 
 
639
        buf = *bufp;
 
640
        for(n = 0; n < count; ++n)
 
641
        {
 
642
                jdns_packet_resource_t *r;
 
643
 
 
644
                offset = buf - data;
 
645
                at = 0;
 
646
 
 
647
                if(!readlabel(data + offset, size - offset, data, size, &at, &name))
 
648
                        goto error;
 
649
 
 
650
                offset += at;
 
651
 
 
652
                // need 10 more bytes
 
653
                if(offset + 10 > size)
 
654
                        goto error;
 
655
 
 
656
                buf = data + offset;
 
657
 
 
658
                r = jdns_packet_resource_new();
 
659
                r->qname = name;
 
660
                name = 0;
 
661
                r->qtype = net2short(&buf);
 
662
                r->qclass = net2short(&buf);
 
663
                r->ttl = net2long(&buf);
 
664
 
 
665
                // per RFC 2181, ttl is supposed to be a 31 bit number.  if
 
666
                //   the top bit of the 32 bit field is 1, then entire ttl is
 
667
                //   to be considered 0.
 
668
                if(r->ttl & 0x80000000)
 
669
                        r->ttl = 0;
 
670
 
 
671
                r->rdlength = net2short(&buf);
 
672
 
 
673
                offset = buf - data;
 
674
 
 
675
                // make sure we have enough for the rdata
 
676
                if(size - offset < r->rdlength)
 
677
                {
 
678
                        jdns_packet_resource_delete(r);
 
679
                        goto error;
 
680
                }
 
681
 
 
682
                r->rdata = jdns_copy_array(buf, r->rdlength);
 
683
                buf += r->rdlength;
 
684
 
 
685
                jdns_list_insert_value(dest, r, -1);
 
686
                jdns_packet_resource_delete(r);
 
687
        }
 
688
 
 
689
        *bufp = buf;
 
690
        return 1;
 
691
 
 
692
error:
 
693
        jdns_string_delete(name);
 
694
        return 0;
 
695
}
 
696
 
 
697
static int append_qsection(const jdns_list_t *src, int at, int left, unsigned char **bufp, jdns_list_t *lookup)
 
698
{
 
699
        unsigned char *buf, *start, *last;
 
700
        int n;
 
701
 
 
702
        buf = *bufp;
 
703
        start = buf - at;
 
704
        last = buf + left;
 
705
        for(n = 0; n < src->count; ++n)
 
706
        {
 
707
                jdns_packet_question_t *q = (jdns_packet_question_t *)src->item[n];
 
708
 
 
709
                if(!writelabel(q->qname, buf - start, last - buf, &buf, lookup))
 
710
                        goto error;
 
711
 
 
712
                if(buf + 4 > last)
 
713
                        goto error;
 
714
 
 
715
                short2net(q->qtype, &buf);
 
716
                short2net(q->qclass, &buf);
 
717
        }
 
718
 
 
719
        *bufp = buf;
 
720
        return 1;
 
721
 
 
722
error:
 
723
        return 0;
 
724
}
 
725
 
 
726
static int append_rrsection(const jdns_list_t *src, int at, int left, unsigned char **bufp, jdns_list_t *lookup)
 
727
{
 
728
        unsigned char *buf, *start, *last, *rdlengthp;
 
729
        int n, i, rdlength;
 
730
 
 
731
        buf = *bufp;
 
732
        start = buf - at;
 
733
        last = buf + left;
 
734
        for(n = 0; n < src->count; ++n)
 
735
        {
 
736
                jdns_packet_resource_t *r = (jdns_packet_resource_t *)src->item[n];
 
737
 
 
738
                if(!writelabel(r->qname, buf - start, last - buf, &buf, lookup))
 
739
                        goto error;
 
740
 
 
741
                if(buf + 10 > last)
 
742
                        goto error;
 
743
 
 
744
                short2net(r->qtype, &buf);
 
745
                short2net(r->qclass, &buf);
 
746
                long2net(r->ttl, &buf);
 
747
 
 
748
                // skip over rdlength
 
749
                rdlengthp = buf;
 
750
                buf += 2;
 
751
 
 
752
                // play write log
 
753
                rdlength = 0;
 
754
                for(i = 0; i < r->writelog->count; ++i)
 
755
                {
 
756
                        jdns_packet_write_t *write = (jdns_packet_write_t *)r->writelog->item[i];
 
757
                        if(write->type == JDNS_PACKET_WRITE_RAW)
 
758
                        {
 
759
                                if(buf + write->value->size > last)
 
760
                                        goto error;
 
761
 
 
762
                                memcpy(buf, write->value->data, write->value->size);
 
763
                                buf += write->value->size;
 
764
                        }
 
765
                        else // JDNS_PACKET_WRITE_NAME
 
766
                        {
 
767
                                if(!writelabel(write->value, buf - start, last - buf, &buf, lookup))
 
768
                                        goto error;
 
769
                        }
 
770
                }
 
771
 
 
772
                i = buf - rdlengthp; // should be rdata size + 2
 
773
                short2net((unsigned short int)(i - 2), &rdlengthp);
 
774
        }
 
775
 
 
776
        *bufp = buf;
 
777
        return 1;
 
778
 
 
779
error:
 
780
        return 0;
 
781
}
 
782
 
 
783
jdns_packet_t *jdns_packet_new()
 
784
{
 
785
        jdns_packet_t *a = JDNS_OBJECT_NEW(jdns_packet);
 
786
        a->id = 0;
 
787
        a->opts.qr = 0;
 
788
        a->opts.opcode = 0;
 
789
        a->opts.aa = 0;
 
790
        a->opts.tc = 0;
 
791
        a->opts.rd = 0;
 
792
        a->opts.ra = 0;
 
793
        a->opts.z = 0;
 
794
        a->opts.rcode = 0;
 
795
 
 
796
        a->questions = jdns_list_new();
 
797
        a->answerRecords = jdns_list_new();
 
798
        a->authorityRecords = jdns_list_new();
 
799
        a->additionalRecords = jdns_list_new();
 
800
 
 
801
        a->questions->valueList = 1;
 
802
        a->answerRecords->valueList = 1;
 
803
        a->authorityRecords->valueList = 1;
 
804
        a->additionalRecords->valueList = 1;
 
805
 
 
806
        a->fully_parsed = 0;
 
807
 
 
808
        a->raw_size = 0;
 
809
        a->raw_data = 0;
 
810
        return a;
 
811
}
 
812
 
 
813
jdns_packet_t *jdns_packet_copy(const jdns_packet_t *a)
 
814
{
 
815
        jdns_packet_t *c = jdns_packet_new();
 
816
        c->id = a->id;
 
817
        c->opts.qr = a->opts.qr;
 
818
        c->opts.opcode = a->opts.opcode;
 
819
        c->opts.aa = a->opts.aa;
 
820
        c->opts.tc = a->opts.tc;
 
821
        c->opts.rd = a->opts.rd;
 
822
        c->opts.ra = a->opts.ra;
 
823
        c->opts.z = a->opts.z;
 
824
        c->opts.rcode = a->opts.rcode;
 
825
 
 
826
        jdns_list_delete(c->questions);
 
827
        jdns_list_delete(c->answerRecords);
 
828
        jdns_list_delete(c->authorityRecords);
 
829
        jdns_list_delete(c->additionalRecords);
 
830
        c->questions = jdns_list_copy(a->questions);
 
831
        c->answerRecords = jdns_list_copy(a->answerRecords);
 
832
        c->authorityRecords = jdns_list_copy(a->authorityRecords);
 
833
        c->additionalRecords = jdns_list_copy(a->additionalRecords);
 
834
 
 
835
        c->fully_parsed = a->fully_parsed;
 
836
 
 
837
        c->raw_size = a->raw_size;
 
838
        c->raw_data = jdns_copy_array(a->raw_data, a->raw_size);
 
839
 
 
840
        return c;
 
841
}
 
842
 
 
843
void jdns_packet_delete(jdns_packet_t *a)
 
844
{
 
845
        if(!a)
 
846
                return;
 
847
        jdns_list_delete(a->questions);
 
848
        jdns_list_delete(a->answerRecords);
 
849
        jdns_list_delete(a->authorityRecords);
 
850
        jdns_list_delete(a->additionalRecords);
 
851
        if(a->raw_data)
 
852
                jdns_free(a->raw_data);
 
853
        jdns_object_free(a);
 
854
}
 
855
 
 
856
int jdns_packet_import(jdns_packet_t **a, const unsigned char *data, int size)
 
857
{
 
858
        jdns_packet_t *tmp = 0;
 
859
        const unsigned char *buf;
 
860
 
 
861
        // need at least some data
 
862
        if(!data || size == 0)
 
863
                return 0;
 
864
 
 
865
        // header (id + options + item counts) is 12 bytes
 
866
        if(size < 12)
 
867
                goto error;
 
868
 
 
869
        tmp = jdns_packet_new();
 
870
        buf = data;
 
871
 
 
872
        // id
 
873
        tmp->id = net2short(&buf);
 
874
 
 
875
        // options
 
876
        if(buf[0] & 0x80)                        // qr is bit 7
 
877
                tmp->opts.qr = 1;
 
878
        tmp->opts.opcode = (buf[0] & 0x78) >> 3; // opcode is bits 6,5,4,3
 
879
        if(buf[0] & 0x04)                        // aa is bit 2
 
880
                tmp->opts.aa = 1;
 
881
        if(buf[0] & 0x02)                        // tc is bit 1
 
882
                tmp->opts.tc = 1;
 
883
        if(buf[0] & 0x01)                        // rd is bit 0
 
884
                tmp->opts.rd = 1;
 
885
        if(buf[1] & 0x80)                        // ra is bit 7 (second byte)
 
886
                tmp->opts.ra = 1;
 
887
        tmp->opts.z = (buf[1] & 0x70) >> 4;      // z is bits 6,5,4
 
888
        tmp->opts.rcode = buf[1] & 0x0f;         // rcode is bits 3,2,1,0
 
889
        buf += 2;
 
890
 
 
891
        // item counts
 
892
        tmp->qdcount = net2short(&buf);
 
893
        tmp->ancount = net2short(&buf);
 
894
        tmp->nscount = net2short(&buf);
 
895
        tmp->arcount = net2short(&buf);
 
896
 
 
897
        // if these fail, we don't count them as errors, since the packet
 
898
        //   might have been truncated
 
899
        if(!process_qsection(tmp->questions, tmp->qdcount, data, size, &buf))
 
900
                goto skip;
 
901
        if(!process_rrsection(tmp->answerRecords, tmp->ancount, data, size, &buf))
 
902
                goto skip;
 
903
        if(!process_rrsection(tmp->authorityRecords, tmp->nscount, data, size, &buf))
 
904
                goto skip;
 
905
        if(!process_rrsection(tmp->additionalRecords, tmp->arcount, data, size, &buf))
 
906
                goto skip;
 
907
 
 
908
        tmp->fully_parsed = 1;
 
909
 
 
910
skip:
 
911
        // keep the raw data for reference during rdata parsing
 
912
        tmp->raw_size = size;
 
913
        tmp->raw_data = jdns_copy_array(data, size);
 
914
 
 
915
        *a = tmp;
 
916
        return 1;
 
917
 
 
918
error:
 
919
        jdns_packet_delete(tmp);
 
920
        return 0;
 
921
}
 
922
 
 
923
int jdns_packet_export(jdns_packet_t *a, int maxsize)
 
924
{
 
925
        unsigned char *block = 0;
 
926
        unsigned char *buf, *last;
 
927
        unsigned char c;
 
928
        int size;
 
929
        jdns_list_t *lookup = 0; // to hold jdns_packet_label_t
 
930
 
 
931
        // clear out any existing raw data before we begin
 
932
        if(a->raw_data)
 
933
        {
 
934
                jdns_free(a->raw_data);
 
935
                a->raw_data = 0;
 
936
                a->raw_size = 0;
 
937
        }
 
938
 
 
939
        // preallocate
 
940
        size = maxsize;
 
941
        block = (unsigned char *)jdns_alloc(size);
 
942
        memset(block, 0, size);
 
943
 
 
944
        buf = block;
 
945
        last = block + size;
 
946
 
 
947
        if(size < 12)
 
948
                goto error;
 
949
 
 
950
        short2net(a->id, &buf);
 
951
        if(a->opts.qr)
 
952
                buf[0] |= 0x80;
 
953
        c = (unsigned char)a->opts.opcode;
 
954
        buf[0] |= c << 3;
 
955
        if(a->opts.aa)
 
956
                buf[0] |= 0x04;
 
957
        if(a->opts.tc)
 
958
                buf[0] |= 0x02;
 
959
        if(a->opts.rd)
 
960
                buf[0] |= 0x01;
 
961
        if(a->opts.ra)
 
962
                buf[1] |= 0x80;
 
963
        c = (unsigned char)a->opts.z;
 
964
        buf[1] |= c << 4;
 
965
        c = (unsigned char)a->opts.rcode;
 
966
        buf[1] |= c;
 
967
        buf += 2;
 
968
        short2net((unsigned short int)a->questions->count, &buf);
 
969
        short2net((unsigned short int)a->answerRecords->count, &buf);
 
970
        short2net((unsigned short int)a->authorityRecords->count, &buf);
 
971
        short2net((unsigned short int)a->additionalRecords->count, &buf);
 
972
 
 
973
        // append sections
 
974
        lookup = jdns_list_new();
 
975
        lookup->autoDelete = 1;
 
976
 
 
977
        if(!append_qsection(a->questions, buf - block, last - buf, &buf, lookup))
 
978
                goto error;
 
979
        if(!append_rrsection(a->answerRecords, buf - block, last - buf, &buf, lookup))
 
980
                goto error;
 
981
        if(!append_rrsection(a->authorityRecords, buf - block, last - buf, &buf, lookup))
 
982
                goto error;
 
983
        if(!append_rrsection(a->additionalRecords, buf - block, last - buf, &buf, lookup))
 
984
                goto error;
 
985
 
 
986
        // done with all sections
 
987
        jdns_list_delete(lookup);
 
988
 
 
989
        // condense
 
990
        size = buf - block;
 
991
        block = (unsigned char *)jdns_realloc(block, size);
 
992
 
 
993
        // finalize
 
994
        a->qdcount = a->questions->count;
 
995
        a->ancount = a->answerRecords->count;
 
996
        a->nscount = a->authorityRecords->count;
 
997
        a->arcount = a->additionalRecords->count;
 
998
        a->raw_data = block;
 
999
        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
}