1
/* Copyright (c) 2007-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.
38
/* Mararc parameters that are set in DwMararc.c */
39
extern dw_str *key_s[];
40
extern dw_str *key_d[];
41
extern int32_t key_n[];
43
/* The cache that is used for storing DNS queries */
46
/* The user and group ID Deadwood runs as */
47
extern int32_t maradns_uid;
48
extern int32_t maradns_gid;
57
GetDateFormat(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, &t,
59
GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, &t,
61
fprintf(LOG,"%s %s: ",d,h);
65
/* Logging functions */
66
/* Initialize the log */
69
LOG = fopen("dwlog.txt","ab");
71
fprintf(LOG,"%s\n","==Deadwood started==");
80
fprintf(LOG,"%s\n","==Deadwood stopped==");
86
/* Log a string followed by the contents of a DwStr object ; private */
87
void dw_log_dwstr_p(char *s1, dw_str *s2, int min_log_level) {
88
int32_t ll = key_n[DWM_N_verbose_level];
91
if(ll <= 0 || ll < min_log_level) {
104
printf("(null dw_str)");
106
fprintf(LOG,"(null dw_str)");
111
for(ll = 0 ; ll < s2->len ; ll++) {
113
if(q >= '@' && q <= '~' /* Last ASCII char */) {
123
fprintf(LOG,"\\%03o",q);
129
/* Log a string followed by the contents of a DwStr object */
130
void dw_log_dwstr(char *s1, dw_str *s2, int min_log_level) {
131
int32_t ll = key_n[DWM_N_verbose_level];
132
if(ll <= 0 || ll < min_log_level) {
136
dw_log_dwstr_p(s1,s2,min_log_level);
138
/* OK, add a newline */
143
fprintf(LOG,"%s","\n");
147
/* Log a string followed by the contents of a DwStr object followed by
149
void dw_log_dwstr_str(char *s1, dw_str *s2, char *s3, int min_log_level) {
150
int32_t ll = key_n[DWM_N_verbose_level];
151
if(ll <= 0 || ll < min_log_level) {
155
dw_log_dwstr_p(s1,s2,min_log_level);
157
/* OK, add a newline */
162
fprintf(LOG,"%s\n",s3);
167
/* Log a string; input: String to log; minimum log level that we log this
169
void dw_log_string(char *string, int min_log_level) {
170
int32_t ll = key_n[DWM_N_verbose_level];
172
if(ll <= 0 || ll < min_log_level) {
177
printf("%s\n",string);
180
fprintf(LOG,"%s\n",string);
185
/* Log 3 strings; input: Strings to log; minimum log level that we log these
187
void dw_log_3strings(char *s1, char *s2, char *s3, int min_log_level) {
188
int32_t ll = key_n[DWM_N_verbose_level];
190
if(ll <= 0 || ll < min_log_level) {
195
printf("%s%s%s\n",s1,s2,s3);
198
fprintf(LOG,"%s%s%s\n",s1,s2,s3);
202
/* Log a string, a number, and a string
203
* input: String #1, Number, and String #2 to log;
204
* minimum log level that we log this at */
205
void dw_log_number(char *s1, int number, char *s2, int min_log_level) {
206
int32_t ll = key_n[DWM_N_verbose_level];
208
if(ll <= 0 || ll < min_log_level) {
213
printf("%s%d%s\n",s1,number,s2);
216
fprintf(LOG,"%s%d%s\n",s1,number,s2);
221
/* Log 3 strings; input: Strings to log; minimum log level that we log these
222
* strings at; this always logs and is run before Dwood2rc file is parsed */
223
void dw_alog_3strings(char *s1, char *s2, char *s3) {
226
printf("%s%s%s\n",s1,s2,s3);
229
fprintf(LOG,"%s%s%s\n",s1,s2,s3);
234
/* Log a string, a number, and a string
235
* input: String #1, Number, and String #2 to log;
236
* minimum log level that we log this at
237
* This always logs and is run before Dwood2rc file is fully parsed */
238
void dw_alog_number(char *s1, int number, char *s2) {
241
printf("%s%d %s\n",s1,number,s2);
244
fprintf(LOG,"%s%d %s\n",s1,number,s2);
249
/* Exit with a fatal error */
250
/* Exit with a fatal error */
251
void dw_fatal(char *why) {
254
printf("Fatal: %s\n",why);
257
fprintf(LOG,"Fatal: %s\n",why);
261
printf("Fatal: Unknown fatal error\n");
264
fprintf(LOG,"Fatal: Unknown fatal error\n");
270
/* Set the 64-bit timestamp starting at 290805600 unix() time (When
271
* the Blake's 7 episode Gambit was originally broadcast); this should
272
* be called once a second or so */
276
if(sizeof(sys_time) > 4) {
278
the_time = sys_time - 290805600;
281
if(sys_time < DW_MINTIME) {
282
the_time = sys_time + 4004161696U;
284
the_time = sys_time - 290805600;
287
the_time <<= 8; /* Each second has 256 "ticks" */
290
/* Set up some signal handlers, so MaraDNS can write the cache to a file
295
/* Handler for various signals.
297
* TERM: Write cache to disk, end program, exit with 0
298
* HUP: Write cache to disk, end program, exit with 8
299
* USR1: Write cache to disk; continue running program
302
/* TERM signal handler */
303
void handle_signal(int code) {
315
signal(code, handle_signal);
318
/* Assign handlers for TERM, HUP, and USR1 signals */
319
void setup_signals() {
320
signal(SIGTERM,handle_signal);
321
signal(SIGHUP,handle_signal);
322
signal(SIGUSR1,handle_signal);
323
signal(SIGINT,handle_signal);
327
/* Process a signal received */
328
void process_signal(int number) {
329
dw_str *filename = 0;
330
char *fname_convert = 0;
333
/* Clear the signal flag */
337
/* Write the cache contents to disk */
338
filename = key_s[DWM_S_cache_file];
339
if(cache != 0 && filename != 0) {
340
dw_filename_sanitize(filename);
341
fname_convert = (char *)dw_to_cstr(filename);
342
dwh_write_hash(cache,fname_convert);
347
/* Exit if they requested it (*NIX only) */
348
if(number == 1) { /* TERM */
350
} else if(number == 2) { /* HUP */
351
exit(8); /* Use by Duende to indicate we exited with HUP */
356
/* Initialize the cache */
358
dw_str *filename = 0;
359
char *fname_convert = 0;
361
dwh_process_mararc_params(); /* Get the cache size */
362
if(cache != 0) { /* Don't init cache twice */
366
/* See if we can read the cache from a file */
367
filename = key_s[DWM_S_cache_file];
369
dw_filename_sanitize(filename);
370
fname_convert = (char *)dw_to_cstr(filename);
371
cache = dwh_read_hash(fname_convert);
375
if(cache == 0) { /* Just in case read from file failed */
376
cache = dwh_hash_init(0); /* Size comes from dwood2rc */
380
/* Read mararc parameters and set global variables based on those
382
void process_mararc(char *name) {
383
if(dwm_parse_mararc(name) != 1) {
384
dw_log_3strings("Fatal error parsing file ",name,"",1);
387
/* The following sanity check triggers a warning; disabled */
388
/*if(key_s == 0 || key_d == 0) {
389
dw_fatal("error getting mararc parameters");
393
/* Given a C-string string containing random noise, the length of that
394
* string, initialize the RNG */
395
void noise_to_rng(uint8_t *noise, int len) {
398
z = dw_create(len + 1);
400
dw_fatal("error creating rng dw_str");
403
if(dw_cstr_append(noise, len, z) == -1) {
404
dw_fatal("error putting noise in dw_str object");
407
rng_seed = dwr_init_rg(z);
410
dw_fatal("error initializing rng_seed");
419
/* Given a pointer to some noise, and a desired length, open up the
420
* random_seed_file and get between 16 bytes and the desired length from
421
* said file, putting the entropy in the noise pointer */
422
void get_entropy_from_seedfile(uint8_t *noise,int len) {
427
if(key_s[DWM_S_random_seed_file] == 0) {
428
filename = "/dev/urandom"; /* Default filename */
430
filename = (char *)dw_to_cstr(key_s[DWM_S_random_seed_file]);
434
seed = open(filename, O_RDONLY);
436
dw_log_3strings("Fatal error opening random seed file ",
441
if(read(seed,(void *)noise,len) < 16) {
442
dw_log_3strings("Unable to get 128 bits of entropy; file ",
444
" must be\n at least 16 bytes (128 bits) long",1);
456
/* Initialize random number generator. Note that some bytes of the "noise"
457
* string will have random junk in them. This is intentional. */
464
noise = (uint8_t *)malloc(512);
465
#ifdef VALGRIND_NOERRORS
466
/* Valgrind reports our intentional use of values of uncleared
467
* allocated memory as one source of entropy as an error, so we
468
* allow it to be disabled for Valgrind testing */
470
#endif /* VALGRIND_NOERRORS */
472
dw_fatal("error allocating memory for noise");
475
get_entropy_from_seedfile(noise,256);
477
/* Get entropy from the current timestamp */
480
for(a = 0 ; a < 8 ; a++) {
481
*(noise + a + 256) = tstamp & 0xff;
485
/* Get entropy from the process' ID number */
487
for(a = 0 ; a < sizeof(pnum) ; a++ ) {
488
*(noise + a + 272) = pnum & 0xff;
492
/* Initialize the RNG based on the contents of noise */
493
noise_to_rng(noise,510);
502
/* Drop privileges and become unprivileged user */
504
#if ! (defined MINGW || defined __CYGWIN__)
505
unsigned char *c = 0;
507
if(key_s[DWM_S_chroot_dir] == 0) {
508
dw_fatal("chroot_dir not set");
510
c = dw_to_cstr(key_s[DWM_S_chroot_dir]);
512
dw_fatal("Converting chroot_dir to string failed");
514
if(chdir((char *)c) != 0) {
515
dw_fatal("chdir() failed");
518
if(chroot((char *)c) == -1) {
519
dw_fatal("chroot() failed");
522
if(setgroups(1,&g) == -1) {
523
dw_fatal("setgroups() failed");
525
if(setgid(maradns_gid) != 0) {
526
dw_fatal("setgid() failed");
528
if(setuid(maradns_uid) != 0) {
529
dw_fatal("setuid() failed");
532
dw_fatal("Your kernel\'s setuid() is broken");
543
/* Get, from the Mararc parameters, the list of bind addresses
544
* we will bind to; return this list as a comma-separated dw_str */
545
dw_str *get_bind_addrs() {
548
if(key_s[DWM_S_bind_address] != 0) {
549
bind = dw_copy(key_s[DWM_S_bind_address]);
550
} else if(key_s[DWM_S_ipv4_bind_addresses] != 0) {
551
bind = dw_copy(key_s[DWM_S_ipv4_bind_addresses]);
553
dw_fatal("Please set bind_address");
557
goto catch_get_bind_addrs;
560
if(key_s[DWM_S_bind_address] != 0 &&
561
key_s[DWM_S_ipv4_bind_addresses] != 0) {
562
if(dw_addchar(',',bind) == -1) {
563
goto catch_get_bind_addrs;
565
if(dw_append(key_s[DWM_S_ipv4_bind_addresses],bind) == -1) {
566
goto catch_get_bind_addrs;
572
catch_get_bind_addrs:
580
/* Make sure a DNS packet is sane, and return the packet's
581
* query ID. If roy_arends_check has a value of 1, we also make sure
582
* it's a DNS question (and not a reply). This is named in honor of
583
* Roy Arends, who pointed out the original MaraDNS didn't check this.
584
* If this returns -1, the packet was not sane.
586
* If roy_arends_check has a value of 2, we make sure the packet is
587
* a sane packet for a recursive request. In more detail:
595
* ANCOUNT, NSCOUNT, and ARCOUNT must be 0
598
int32_t get_dns_qid(unsigned char *a, int len, int roy_arends_check) {
599
/* Make sure we're kosher */
600
if(len < 12) { /* Size of DNS header */
603
if(roy_arends_check == 1 && ((a[2] & 0x80) != 0)) {
604
/* If it's an answer, not a query */
607
if(roy_arends_check == 2 && (
608
/* a[2]: QR, Opcode (4 bits), AA, TC, and RD */
609
((a[2] & 0xf9)) != 0x01 ||
610
/* a[3]: RA, Z (3 bits), RCODE (4 bits) */
611
((a[3] & 0x7f)) != 0x00 ||
612
/* a[4] and a[5]: QDCOUNT */
613
a[4] != 0 || a[5] != 1 ||
614
/* a[6], a[7]: ANCOUNT */
615
a[6] != 0 || a[7] != 0 ||
616
/* a[8], a[9]: NSCOUNT */
617
a[8] != 0 || a[9] != 0 ||
618
/* a[10], a[11]: ARCOUNT */
619
a[10] != 0 || a[11] != 0))
623
/* A DNS header is not considered kosher if it doesn't
624
* have an question, nor any other RRs ; we look
625
* at QDCOUNT, ANCOUNT, NSCOUNT, and ARCOUNT */
626
if(a[5] == 0 && a[4] == 0 && a[6] == 0 && a[7] == 0 &&
627
a[8] == 0 && a[9] == 0 && a[10] == 0 && a[11] == 0) {
628
dw_log_string("Warning: Blank DNS packet",10);
632
return (a[0] << 8) | a[1];
635
/* Given a string with a DNS packet, and the length of that string,
636
* make the first two bytes of the packet (the query ID) the third
637
* argument (qid), and return that number. -1 on error */
638
int32_t set_dns_qid(unsigned char *packet, int len, uint16_t qid) {
639
/* Make sure we're kosher */
640
if(len < 12) { /* Size of DNS header */
644
*(packet + 1) = qid & 0xff;
648
/* This function converts a dw_str object in to a null-terminated
649
* C-string with the last item in the comma-separated list in the
650
* dw_str, with any leading whitespace in the last item removed */
651
char *pop_last_item(dw_str *list) {
652
dw_str *a = 0, *b = 0;
657
goto catch_pop_last_item;
661
goto catch_pop_last_item;
663
ret = (char *)dw_to_cstr(b);
677
/* This creates a netmask from a single number, storing the number in a
678
* string of octets. 0 just makes the string all 0s; 1 makes the string
679
* 0x80 0x00 0x00 etc.; 2 makes the string 0xc0 0x00 etc.; etc.
680
* The string of octets has a length len (4 for ipv6; 16 for ipv6) */
681
void make_netmask(int num, uint8_t *str, int len) {
682
int div = 0, rem = 0;
685
if(len < 1 || len > 64) {
689
/* Since we're dividing by a power of 2, we don't need to do
690
* an expensive division */
694
if(div < 0 || div > len) { /* Sanity check */
698
/* The last byte in the string is determined by the modulo */
702
/* This kind of coding is dangerous. I have triple-checked
703
* the following code and don't see any possible overflows */
704
while(div > 0) { /* 0xff up until the last non-0 byte */
710
if(len > 0) { /* Check needed for /32 and /128 masks */
711
*str = last; /* The last non-0 byte */
713
while(len > 0) { /* The rest of the mask is 0x00 */
721
/* Get a numeric value from the mararc parameters and make sure it is
722
* within a range; if def is not -1, make an out-of-range parameter
724
int32_t get_key_n(int32_t get, int32_t min, int32_t max, int32_t def) {
735
} else if(val > max) {