~ubuntu-branches/ubuntu/karmic/psi/karmic

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2008-04-14 18:57:30 UTC
  • mfrom: (2.1.9 hardy)
  • Revision ID: james.westby@ubuntu.com-20080414185730-528re3zp0m2hdlhi
Tags: 0.11-8
* added CONFIG -= link_prl to .pro files and removed dependencies
  which are made unnecessary by this change
* Fix segfault when closing last chat tab with qt4.4
  (This is from upstream svn, rev. 1101) (Closes: Bug#476122)

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