1
/* Copyright (c) 2009 Sam Trenholme
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
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.
15
* This software is provided 'as is' with no guarantees of correctness or
16
* fitness for purpose.
20
#include "DwStr_functions.h"
24
extern int32_t key_n[];
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
32
dns_string *dwc_init_dns_str(int32_t ancount, int32_t nscount,
36
out = malloc(sizeof(dns_string));
37
if(out == 0 || ancount < 0 || nscount < 0 || arcount < 0) {
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);
44
out->ancount = ancount;
45
out->nscount = nscount;
46
out->arcount = arcount;
48
if(out->an == 0 || out->ns == 0 || out->ar == 0) {
49
goto catch_dwc_init_dns_str;
53
catch_dwc_init_dns_str:
54
if(out->packet != 0) {
55
dw_destroy(out->packet);
69
/* Destroy an already created dns_string object */
70
void dwc_zap_dns_str(dns_string *zap) {
74
if(zap->packet != 0) {
75
dw_destroy(zap->packet);
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,
93
if(dw_assert_sanity(in) == -1) {
103
array[(count * 2) + 1] = dw_fetch_u16(in,offset);
108
array[count * 2] = dw_fetch_u16(in,offset);
114
/* Convert an uncompressed string in to a newly created dns_string object */
115
dns_string *dwc_make_dns_str(dw_str *in) {
119
int32_t ancount = 0, nscount = 0, arcount = 0;
121
if(dw_assert_sanity(in) == -1) {
122
goto catch_dwc_make_dns_str;
124
offset = in->len - 1;
126
goto catch_dwc_make_dns_str;
128
type = (uint8_t)*(in->str + offset);
130
arcount = dw_fetch_u16(in,offset);
132
nscount = dw_fetch_u16(in,offset);
134
ancount = dw_fetch_u16(in,offset);
135
out = dwc_init_dns_str(ancount,nscount,arcount);
137
goto catch_dwc_make_dns_str;
139
out->packet = dw_copy(in);
142
offset = dwc_place_offsets(in,offset,arcount,out->ar);
144
goto catch_dwc_make_dns_str;
146
offset = dwc_place_offsets(in,offset,nscount,out->ns);
148
goto catch_dwc_make_dns_str;
150
offset = dwc_place_offsets(in,offset,ancount,out->an);
152
goto catch_dwc_make_dns_str;
157
catch_dwc_make_dns_str:
159
dwc_zap_dns_str(out);
166
/* Convert a DNS string object back in to an uncompressed string as stored
167
* in the Deadwood cache */
169
dw_str *dwc_convert_dns_str(dns_string *in) {
170
int32_t len = 0, counter = 0;
174
goto catch_dwc_convert_dns_str;
176
if(in->packet == 0 || in->an == 0 || in->ns == 0 || in->ar == 0) {
177
goto catch_dwc_convert_dns_str;
180
len = in->packet->len;
181
len += (in->ancount + in->nscount + in->arcount) * 4;
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);
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);
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);
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);
204
catch_dwc_convert_dns_str:
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,
219
int32_t where = 0,val = 0;
221
if(packet == 0 || list == 0) {
222
goto catch_dwc_get_type;
224
if(offset < 0 || offset > max) {
225
goto catch_dwc_get_type;
228
where = *(list + offset * 2 + 1);
229
if(where < 0 || where > packet->len) {
230
goto catch_dwc_get_type;
233
val = dw_fetch_u16(packet,where);
235
if(val < 0 || (val >= 65392 && val <= 65407) || val >= 65536) {
236
goto catch_dwc_get_type;
245
/* Determine where the first non-CNAME record to rotate is */
246
int dwc_rr_find(dns_string *look) {
248
uint16_t type = 5; /* CNAME */
250
/* Iterate through the RRs in the answer until we got one that isn't
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 */
258
if(rr > look->ancount) {
266
/* Rotate DNS records in a compressed DNS string */
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;
274
goto catch_dwc_rr_rotate;
277
look = dwc_make_dns_str(in);
278
if(look == 0 || look->an == 0) {
279
goto catch_dwc_rr_rotate;
282
rr = dwc_rr_find(look);
283
if(rr == -1 || rr + 1 >= look->ancount) {
284
goto catch_dwc_rr_rotate;
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);
291
goto catch_dwc_rr_rotate;
293
} else if(look->nscount > 0) {
295
} else if(look->arcount > 0) {
298
goto catch_dwc_rr_rotate;
300
if(dw_rotate(in,start,pivot,end) == -1) {
301
goto catch_dwc_rr_rotate;
307
dwc_zap_dns_str(look);
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;
317
uint16_t left = 0, right = 0;
320
goto catch_dwc_ttl_age;
323
look = dwc_make_dns_str(fetch);
325
if(look == 0 || look->an == 0) {
326
goto catch_dwc_ttl_age;
335
right = ttl & 0xffff;
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);
346
dwc_zap_dns_str(look);
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) {
358
if(key_n[DWM_N_ttl_age] == 1 && (action & 0x02) == 2) {
359
fetch = dwh_get(cache,query,0,1);
361
goto catch_dwc_process;
363
ttl = dwh_get_ttl(cache,query);
365
goto catch_dwc_process;
367
if(dwc_ttl_age(fetch,ttl) == -1) {
368
goto catch_dwc_process;
370
dwh_add(cache,query,fetch,ttl,1);
376
if(key_n[DWM_N_max_ar_chain] == 1 && (action & 0x01) == 1) {
377
fetch = dwh_get(cache,query,0,1);
379
goto catch_dwc_process;
381
if(dwc_rr_rotate(fetch) == -1) {
382
goto catch_dwc_process;
384
ttl = dwh_get_ttl(cache,query);
386
goto catch_dwc_process;
388
dwh_add(cache,query,fetch,ttl,1);
398
/* See if an IP in our answer is blacklisted. 1 if it is, 0 if it's not or
400
int has_bad_ip(dw_str *answer, dwd_dict *blacklist_hash) {
401
dns_string *look = 0;
406
if(answer == 0 || blacklist_hash == 0) {
407
goto catch_has_bad_ip;
410
look = dwc_make_dns_str(answer);
411
if(look == 0 || look->an == 0) {
412
goto catch_has_bad_ip;
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);
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);
443
dwc_zap_dns_str(look);