~ubuntu-branches/ubuntu/raring/maradns/raring

« back to all changes in this revision

Viewing changes to deadwood-2.4.10/src/DwDnsStr.c

  • Committer: Bazaar Package Importer
  • Author(s): Kai Hendry
  • Date: 2010-01-24 12:17:40 UTC
  • mfrom: (1.1.13 upstream) (10.1.4 sid)
  • Revision ID: james.westby@ubuntu.com-20100124121740-a4e1fjobwaouz443
Tags: 1.4.02-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2009 Sam Trenholme
 
2
 *
 
3
 * TERMS
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 *
 
9
 * 1. Redistributions of source code must retain the above copyright
 
10
 *    notice, this list of conditions and the following disclaimer.
 
11
 * 2. Redistributions in binary form must reproduce the above copyright
 
12
 *    notice, this list of conditions and the following disclaimer in the
 
13
 *    documentation and/or other materials provided with the distribution.
 
14
 *
 
15
 * This software is provided 'as is' with no guarantees of correctness or
 
16
 * fitness for purpose.
 
17
 */
 
18
 
 
19
#include "DwStr.h"
 
20
#include "DwStr_functions.h"
 
21
#include "DwDnsStr.h"
 
22
#include "DwHash.h"
 
23
#include "DwMararc.h"
 
24
extern int32_t key_n[];
 
25
 
 
26
/* Create a blank dns_string object, where the dns packet has size SIZE
 
27
 * Input: The number of DNS answers, NS records, and additional records
 
28
 * this string will have pointers to.
 
29
 * Output: The newly created blank dns_string object
 
30
 */
 
31
 
 
32
dns_string *dwc_init_dns_str(int32_t ancount, int32_t nscount,
 
33
                int32_t arcount) {
 
34
        dns_string *out = 0;
 
35
 
 
36
        out = malloc(sizeof(dns_string));
 
37
        if(out == 0 || ancount < 0 || nscount < 0 || arcount < 0) {
 
38
                return 0;
 
39
        }
 
40
        out->an = malloc((ancount * sizeof(uint16_t) * 2) + 2);
 
41
        out->ns = malloc((nscount * sizeof(uint16_t) * 2) + 2);
 
42
        out->ar = malloc((arcount * sizeof(uint16_t) * 2) + 2);
 
43
        out->packet = 0;
 
44
        out->ancount = ancount;
 
45
        out->nscount = nscount;
 
46
        out->arcount = arcount;
 
47
        out->type = 0;
 
48
        if(out->an == 0 || out->ns == 0 || out->ar == 0) {
 
49
                goto catch_dwc_init_dns_str;
 
50
        }
 
51
        return out;
 
52
 
 
53
catch_dwc_init_dns_str:
 
54
        if(out->packet != 0) {
 
55
                dw_destroy(out->packet);
 
56
        }
 
57
        if(out->an != 0) {
 
58
                free(out->an);
 
59
        }
 
60
        if(out->ns != 0) {
 
61
                free(out->ns);
 
62
        }
 
63
        if(out->ar != 0) {
 
64
                free(out->ar);
 
65
        }
 
66
        return 0;
 
67
}
 
68
 
 
69
/* Destroy an already created dns_string object */
 
70
void dwc_zap_dns_str(dns_string *zap) {
 
71
        if(zap == 0) {
 
72
                return;
 
73
        }
 
74
        if(zap->packet != 0) {
 
75
                dw_destroy(zap->packet);
 
76
        }
 
77
        if(zap->an != 0) {
 
78
                free(zap->an);
 
79
        }
 
80
        if(zap->ns != 0) {
 
81
                free(zap->ns);
 
82
        }
 
83
        if(zap->ar != 0) {
 
84
                free(zap->ar);
 
85
        }
 
86
        free(zap);
 
87
}
 
88
 
 
89
/* Place offsets for a given DNS record part in a dns_string */
 
90
int32_t dwc_place_offsets(dw_str *in, int32_t offset, int32_t count,
 
91
                uint16_t *array) {
 
92
 
 
93
        if(dw_assert_sanity(in) == -1) {
 
94
                return -1;
 
95
        }
 
96
 
 
97
        while(count > 0) {
 
98
                count--;
 
99
                offset -= 2;
 
100
                if(offset < 0) {
 
101
                        return -1;
 
102
                }
 
103
                array[(count * 2) + 1] = dw_fetch_u16(in,offset);
 
104
                offset -= 2;
 
105
                if(offset < 0) {
 
106
                        return -1;
 
107
                }
 
108
                array[count * 2] = dw_fetch_u16(in,offset);
 
109
        }
 
110
        return offset;
 
111
 
 
112
}
 
113
 
 
114
/* Convert an uncompressed string in to a newly created dns_string object */
 
115
dns_string *dwc_make_dns_str(dw_str *in) {
 
116
        dns_string *out = 0;
 
117
        int32_t offset = 0;
 
118
        uint8_t type = 0;
 
119
        int32_t ancount = 0, nscount = 0, arcount = 0;
 
120
 
 
121
        if(dw_assert_sanity(in) == -1) {
 
122
                goto catch_dwc_make_dns_str;
 
123
        }
 
124
        offset = in->len - 1;
 
125
        if(offset < 7) {
 
126
                goto catch_dwc_make_dns_str;
 
127
        }
 
128
        type = (uint8_t)*(in->str + offset);
 
129
        offset -= 2;
 
130
        arcount = dw_fetch_u16(in,offset);
 
131
        offset -= 2;
 
132
        nscount = dw_fetch_u16(in,offset);
 
133
        offset -= 2;
 
134
        ancount = dw_fetch_u16(in,offset);
 
135
        out = dwc_init_dns_str(ancount,nscount,arcount);
 
136
        if(out == 0) {
 
137
                goto catch_dwc_make_dns_str;
 
138
        }
 
139
        out->packet = dw_copy(in);
 
140
        out->type = type;
 
141
 
 
142
        offset = dwc_place_offsets(in,offset,arcount,out->ar);
 
143
        if(offset < 0) {
 
144
                goto catch_dwc_make_dns_str;
 
145
        }
 
146
        offset = dwc_place_offsets(in,offset,nscount,out->ns);
 
147
        if(offset < 0) {
 
148
                goto catch_dwc_make_dns_str;
 
149
        }
 
150
        offset = dwc_place_offsets(in,offset,ancount,out->an);
 
151
        if(offset < 0) {
 
152
                goto catch_dwc_make_dns_str;
 
153
        }
 
154
 
 
155
        return out;
 
156
 
 
157
catch_dwc_make_dns_str:
 
158
        if(out != 0) {
 
159
                dwc_zap_dns_str(out);
 
160
        }
 
161
        return 0;
 
162
}
 
163
 
 
164
#ifndef UNUSED
 
165
 
 
166
/* Convert a DNS string object back in to an uncompressed string as stored
 
167
 * in the Deadwood cache */
 
168
 
 
169
dw_str *dwc_convert_dns_str(dns_string *in) {
 
170
        int32_t len = 0, counter = 0;
 
171
        dw_str *out = 0;
 
172
 
 
173
        if(in == 0) {
 
174
                goto catch_dwc_convert_dns_str;
 
175
        }
 
176
        if(in->packet == 0 || in->an == 0 || in->ns == 0 || in->ar == 0) {
 
177
                goto catch_dwc_convert_dns_str;
 
178
        }
 
179
 
 
180
        len = in->packet->len;
 
181
        len += (in->ancount + in->nscount + in->arcount) * 4;
 
182
        len += 8;
 
183
        out = dw_create(len);
 
184
        dw_append(in->packet,out);
 
185
        for(counter = 0; counter < in->ancount * 2; counter += 2) {
 
186
                dw_push_u16(in->an[counter],out);
 
187
                dw_push_u16(in->an[counter + 1],out);
 
188
        }
 
189
        for(counter = 0; counter < in->nscount * 2; counter += 2) {
 
190
                dw_push_u16(in->ns[counter],out);
 
191
                dw_push_u16(in->ns[counter + 1],out);
 
192
        }
 
193
        for(counter = 0; counter < in->nscount * 2; counter += 2) {
 
194
                dw_push_u16(in->ar[counter],out);
 
195
                dw_push_u16(in->ar[counter + 1],out);
 
196
        }
 
197
 
 
198
        dw_push_u16(in->ancount,out);
 
199
        dw_push_u16(in->nscount,out);
 
200
        dw_push_u16(in->arcount,out);
 
201
        dw_addchar(in->type,out);
 
202
        return out;
 
203
 
 
204
catch_dwc_convert_dns_str:
 
205
        if(out != 0) {
 
206
                dw_destroy(out);
 
207
        }
 
208
        return 0;
 
209
}
 
210
 
 
211
#endif /* UNUSED */
 
212
 
 
213
/* Given a list of records pointers in a DNS string, and the DNS packet,
 
214
 * return the record type for the number they want.  Return 65393 (see
 
215
 * doc/internals/RR.Allocation for a description of how these RR numbers
 
216
 * are reserved for Deadwood's internal use; 65393 is "error") on error */
 
217
uint16_t dwc_get_type(dw_str *packet, uint16_t *list, int32_t max,
 
218
                int32_t offset) {
 
219
        int32_t where = 0,val = 0;
 
220
 
 
221
        if(packet == 0 || list == 0) {
 
222
                goto catch_dwc_get_type;
 
223
        }
 
224
        if(offset < 0 || offset > max) {
 
225
                goto catch_dwc_get_type;
 
226
        }
 
227
 
 
228
        where = *(list + offset * 2 + 1);
 
229
        if(where < 0 || where > packet->len) {
 
230
                goto catch_dwc_get_type;
 
231
        }
 
232
 
 
233
        val = dw_fetch_u16(packet,where);
 
234
 
 
235
        if(val < 0 || (val >= 65392 && val <= 65407) || val >= 65536) {
 
236
                goto catch_dwc_get_type;
 
237
        }
 
238
 
 
239
        return val;
 
240
 
 
241
catch_dwc_get_type:
 
242
        return 65393;
 
243
}
 
244
 
 
245
/* Determine where the first non-CNAME record to rotate is */
 
246
int dwc_rr_find(dns_string *look) {
 
247
        int rr = 0;
 
248
        uint16_t type = 5; /* CNAME */
 
249
 
 
250
        /* Iterate through the RRs in the answer until we got one that isn't
 
251
         * a CNAME */
 
252
        for(rr = 0; rr < look->ancount && type == 5; rr++) {
 
253
                type = dwc_get_type(look->packet, look->an, look->ancount, rr);
 
254
                if(type == 65393) { /* Error */
 
255
                        return -1;
 
256
                }
 
257
        }
 
258
        if(rr > look->ancount) {
 
259
                return -1;
 
260
        }
 
261
        rr--;
 
262
 
 
263
        return rr;
 
264
}
 
265
 
 
266
/* Rotate DNS records in a compressed DNS string */
 
267
 
 
268
int dwc_rr_rotate(dw_str *in) {
 
269
        dns_string *look = 0;
 
270
        int ret = -1, rr = 0;
 
271
        int32_t start = 0, pivot = 0, end = 0;
 
272
 
 
273
        if(in == 0) {
 
274
                goto catch_dwc_rr_rotate;
 
275
        }
 
276
 
 
277
        look = dwc_make_dns_str(in);
 
278
        if(look == 0 || look->an == 0) {
 
279
                goto catch_dwc_rr_rotate;
 
280
        }
 
281
 
 
282
        rr = dwc_rr_find(look);
 
283
        if(rr == -1 || rr + 1 >= look->ancount) {
 
284
                goto catch_dwc_rr_rotate;
 
285
        }
 
286
        start = *(look->an + (rr * 2));
 
287
        pivot = *(look->an + ((rr + 1) * 2));
 
288
        if(look->nscount == 0 && look->arcount == 0) {
 
289
                end = in->len - 7 - (look->ancount * 4);
 
290
                if(end < 0) {
 
291
                        goto catch_dwc_rr_rotate;
 
292
                }
 
293
        } else if(look->nscount > 0) {
 
294
                end = *(look->ns);
 
295
        } else if(look->arcount > 0) {
 
296
                end = *(look->ar);
 
297
        } else {
 
298
                goto catch_dwc_rr_rotate;
 
299
        }
 
300
        if(dw_rotate(in,start,pivot,end) == -1) {
 
301
                goto catch_dwc_rr_rotate;
 
302
        }
 
303
        ret = 1;
 
304
 
 
305
catch_dwc_rr_rotate:
 
306
        if(look != 0) {
 
307
                dwc_zap_dns_str(look);
 
308
        }
 
309
        return ret;
 
310
}
 
311
 
 
312
/* Age the TTLs for a given entry in the cache */
 
313
int dwc_ttl_age(dw_str *fetch, int32_t ttl) {
 
314
        dns_string *look = 0;
 
315
        int ret = -1;
 
316
        int counter = 0;
 
317
        uint16_t left = 0, right = 0;
 
318
 
 
319
        if(ttl == -1) {
 
320
                goto catch_dwc_ttl_age;
 
321
        }
 
322
 
 
323
        look = dwc_make_dns_str(fetch);
 
324
 
 
325
        if(look == 0 || look->an == 0) {
 
326
                goto catch_dwc_ttl_age;
 
327
        }
 
328
 
 
329
        if(ttl < 5) {
 
330
                ttl = 5;
 
331
        }
 
332
 
 
333
        left = ttl >> 16;
 
334
        left &= 0x7fff;
 
335
        right = ttl & 0xffff;
 
336
 
 
337
        for(counter = 0; counter < look->ancount; counter++) {
 
338
                dw_put_u16(fetch,left,look->an[(counter * 2) + 1] + 4);
 
339
                dw_put_u16(fetch,right,look->an[(counter * 2) + 1] + 6);
 
340
        }
 
341
 
 
342
        ret = 1;
 
343
 
 
344
catch_dwc_ttl_age:
 
345
        if(look != 0) {
 
346
                dwc_zap_dns_str(look);
 
347
        }
 
348
        return ret;
 
349
 
 
350
}
 
351
 
 
352
/* Process an entry in the cache: Perform RR rotation, TTL aging, etc. */
 
353
void dwc_process(dw_hash *cache, dw_str *query, uint8_t action) {
 
354
        dw_str *fetch = 0;
 
355
        int32_t ttl = 0;
 
356
 
 
357
        /* TTL aging */
 
358
        if(key_n[DWM_N_ttl_age] == 1 && (action & 0x02) == 2) {
 
359
                fetch = dwh_get(cache,query,0,1);
 
360
                if(fetch == 0) {
 
361
                        goto catch_dwc_process;
 
362
                }
 
363
                ttl = dwh_get_ttl(cache,query);
 
364
                if(ttl == -1) {
 
365
                        goto catch_dwc_process;
 
366
                }
 
367
                if(dwc_ttl_age(fetch,ttl) == -1) {
 
368
                        goto catch_dwc_process;
 
369
                }
 
370
                dwh_add(cache,query,fetch,ttl,1);
 
371
                dw_destroy(fetch);
 
372
                fetch = 0;
 
373
        }
 
374
 
 
375
        /* RR rotation */
 
376
        if(key_n[DWM_N_max_ar_chain] == 1 && (action & 0x01) == 1) {
 
377
                fetch = dwh_get(cache,query,0,1);
 
378
                if(fetch == 0) {
 
379
                        goto catch_dwc_process;
 
380
                }
 
381
                if(dwc_rr_rotate(fetch) == -1) {
 
382
                        goto catch_dwc_process;
 
383
                }
 
384
                ttl = dwh_get_ttl(cache,query);
 
385
                if(ttl == -1) {
 
386
                        goto catch_dwc_process;
 
387
                }
 
388
                dwh_add(cache,query,fetch,ttl,1);
 
389
        }
 
390
 
 
391
catch_dwc_process:
 
392
        if(fetch != 0) {
 
393
                dw_destroy(fetch);
 
394
        }
 
395
        return;
 
396
}
 
397
 
 
398
/* See if an IP in our answer is blacklisted.  1 if it is, 0 if it's not or
 
399
 * we got an error */
 
400
int has_bad_ip(dw_str *answer, dwd_dict *blacklist_hash) {
 
401
        dns_string *look = 0;
 
402
        dw_str *ip = 0;
 
403
        int counter = 0;
 
404
        int32_t type = 0;
 
405
 
 
406
        if(answer == 0 || blacklist_hash == 0) {
 
407
                goto catch_has_bad_ip;
 
408
        }
 
409
 
 
410
        look = dwc_make_dns_str(answer);
 
411
        if(look == 0 || look->an == 0) {
 
412
                goto catch_has_bad_ip;
 
413
        }
 
414
 
 
415
        for(counter = 0; counter < look->ancount; counter++) {
 
416
                type = dw_fetch_u16(answer,look->an[(counter * 2) + 1]);
 
417
                if(type == 1 /* A record */ ) {
 
418
                        ip = dw_substr(answer,
 
419
                                look->an[(counter * 2) + 1] + 10,4,1);
 
420
                        if(dwd_fetch(blacklist_hash,ip) != 0) {
 
421
                                dwc_zap_dns_str(look);
 
422
                                dw_destroy(ip);
 
423
                                return 1;
 
424
                        }
 
425
                        dw_destroy(ip);
 
426
                        ip = 0;
 
427
                } else if(type == 28 /* AAAA record */) {
 
428
                        ip = dw_substr(answer,
 
429
                                look->an[(counter * 2) + 1] + 10,16,1);
 
430
                        if(dwd_fetch(blacklist_hash,ip) != 0) {
 
431
                                dwc_zap_dns_str(look);
 
432
                                dw_destroy(ip);
 
433
                                return 1;
 
434
                        }
 
435
                        dw_destroy(ip);
 
436
                        ip = 0;
 
437
                }
 
438
 
 
439
        }
 
440
 
 
441
catch_has_bad_ip:
 
442
        if(look != 0) {
 
443
                dwc_zap_dns_str(look);
 
444
        }
 
445
        return 0;
 
446
 
 
447
}
 
448
 
 
449