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

« back to all changes in this revision

Viewing changes to deadwood-2.4.10/src/DwSys.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) 2007-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 <stdio.h>
 
20
#include <string.h>
 
21
#include <unistd.h>
 
22
#include <fcntl.h>
 
23
#include <time.h>
 
24
#ifndef MINGW
 
25
#include <grp.h>
 
26
#include <signal.h>
 
27
#endif /* MINGW */
 
28
 
 
29
#include "DwSocket.h"
 
30
#include "version.h"
 
31
 
 
32
/* Timestamp */
 
33
int64_t the_time = 0;
 
34
 
 
35
/* RNG seed/state */
 
36
dwr_rg *rng_seed;
 
37
 
 
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[];
 
42
 
 
43
/* The cache that is used for storing DNS queries */
 
44
dw_hash *cache = 0;
 
45
 
 
46
/* The user and group ID Deadwood runs as */
 
47
extern int32_t maradns_uid;
 
48
extern int32_t maradns_gid;
 
49
 
 
50
#ifdef MINGW
 
51
FILE *LOG = 0;
 
52
void dw_win_time() {
 
53
        SYSTEMTIME t;
 
54
        char d[256];
 
55
        char h[256];
 
56
        GetLocalTime(&t);
 
57
        GetDateFormat(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, &t,
 
58
                NULL, d, 250);
 
59
        GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, &t,
 
60
                NULL, h, 250);
 
61
        fprintf(LOG,"%s %s: ",d,h);
 
62
}
 
63
#endif /* MINGW */
 
64
 
 
65
/* Logging functions */
 
66
/* Initialize the log */
 
67
void dw_log_init() {
 
68
#ifdef MINGW
 
69
        LOG = fopen("dwlog.txt","ab");
 
70
        dw_win_time();
 
71
        fprintf(LOG,"%s\n","==Deadwood started==");
 
72
#endif /* MINGW */
 
73
        return;
 
74
}
 
75
 
 
76
/* Close the log */
 
77
void dw_log_close() {
 
78
#ifdef MINGW
 
79
        dw_win_time();
 
80
        fprintf(LOG,"%s\n","==Deadwood stopped==");
 
81
        fclose(LOG);
 
82
#endif /* MINGW */
 
83
        return;
 
84
}
 
85
 
 
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];
 
89
        uint8_t q = 0;
 
90
 
 
91
        if(ll <= 0 || ll < min_log_level) {
 
92
                return;
 
93
        }
 
94
 
 
95
#ifndef MINGW
 
96
        printf("%s",s1);
 
97
#else /* MINGW */
 
98
        dw_win_time();
 
99
        fprintf(LOG,"%s",s1);
 
100
#endif /* MINGW */
 
101
 
 
102
        if(s2 == 0) {
 
103
#ifndef MINGW
 
104
                printf("(null dw_str)");
 
105
#else /* MINGW */
 
106
                fprintf(LOG,"(null dw_str)");
 
107
#endif /* MINGW */
 
108
                return;
 
109
        }
 
110
 
 
111
        for(ll = 0 ; ll < s2->len ; ll++) {
 
112
                q = *(s2->str + ll);
 
113
                if(q >= '@' && q <= '~' /* Last ASCII char */) {
 
114
#ifndef MINGW
 
115
                        printf("%c",q);
 
116
#else /* MINGW */
 
117
                        fprintf(LOG,"%c",q);
 
118
#endif /* MINGW */
 
119
                } else {
 
120
#ifndef MINGW
 
121
                        printf("\\%03o",q);
 
122
#else /* MINGW */
 
123
                        fprintf(LOG,"\\%03o",q);
 
124
#endif /* MINGW */
 
125
                }
 
126
        }
 
127
}
 
128
 
 
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) {
 
133
                return;
 
134
        }
 
135
 
 
136
        dw_log_dwstr_p(s1,s2,min_log_level);
 
137
 
 
138
        /* OK, add a newline */
 
139
 
 
140
#ifndef MINGW
 
141
        printf("%s","\n");
 
142
#else /* MINGW */
 
143
        fprintf(LOG,"%s","\n");
 
144
#endif /* MINGW */
 
145
}
 
146
 
 
147
/* Log a string followed by the contents of a DwStr object followed by
 
148
 * another string */
 
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) {
 
152
                return;
 
153
        }
 
154
 
 
155
        dw_log_dwstr_p(s1,s2,min_log_level);
 
156
 
 
157
        /* OK, add a newline */
 
158
 
 
159
#ifndef MINGW
 
160
        printf("%s\n",s3);
 
161
#else /* MINGW */
 
162
        fprintf(LOG,"%s\n",s3);
 
163
#endif /* MINGW */
 
164
}
 
165
 
 
166
 
 
167
/* Log a string; input: String to log; minimum log level that we log this
 
168
 * string at */
 
169
void dw_log_string(char *string, int min_log_level) {
 
170
        int32_t ll = key_n[DWM_N_verbose_level];
 
171
 
 
172
        if(ll <= 0 || ll < min_log_level) {
 
173
                return;
 
174
        }
 
175
 
 
176
#ifndef MINGW
 
177
        printf("%s\n",string);
 
178
#else /* MINGW */
 
179
        dw_win_time();
 
180
        fprintf(LOG,"%s\n",string);
 
181
#endif /* MINGW */
 
182
 
 
183
}
 
184
 
 
185
/* Log 3 strings; input: Strings to log; minimum log level that we log these
 
186
 * strings at */
 
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];
 
189
 
 
190
        if(ll <= 0 || ll < min_log_level) {
 
191
                return;
 
192
        }
 
193
 
 
194
#ifndef MINGW
 
195
        printf("%s%s%s\n",s1,s2,s3);
 
196
#else /* MINGW */
 
197
        dw_win_time();
 
198
        fprintf(LOG,"%s%s%s\n",s1,s2,s3);
 
199
#endif /* MINGW */
 
200
}
 
201
 
 
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];
 
207
 
 
208
        if(ll <= 0 || ll < min_log_level) {
 
209
                return;
 
210
        }
 
211
 
 
212
#ifndef MINGW
 
213
        printf("%s%d%s\n",s1,number,s2);
 
214
#else /* MINGW */
 
215
        dw_win_time();
 
216
        fprintf(LOG,"%s%d%s\n",s1,number,s2);
 
217
#endif /* MINGW */
 
218
 
 
219
}
 
220
 
 
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) {
 
224
 
 
225
#ifndef MINGW
 
226
        printf("%s%s%s\n",s1,s2,s3);
 
227
#else /* MINGW */
 
228
        dw_win_time();
 
229
        fprintf(LOG,"%s%s%s\n",s1,s2,s3);
 
230
#endif /* MINGW */
 
231
 
 
232
}
 
233
 
 
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) {
 
239
 
 
240
#ifndef MINGW
 
241
        printf("%s%d %s\n",s1,number,s2);
 
242
#else /* MINGW */
 
243
        dw_win_time();
 
244
        fprintf(LOG,"%s%d %s\n",s1,number,s2);
 
245
#endif /* MINGW */
 
246
 
 
247
}
 
248
 
 
249
/* Exit with a fatal error */
 
250
/* Exit with a fatal error */
 
251
void dw_fatal(char *why) {
 
252
        if(why != 0) {
 
253
#ifndef MINGW
 
254
                printf("Fatal: %s\n",why);
 
255
#else /* MINGW */
 
256
                dw_win_time();
 
257
                fprintf(LOG,"Fatal: %s\n",why);
 
258
#endif /* MINGW */
 
259
        } else {
 
260
#ifndef MINGW
 
261
                printf("Fatal: Unknown fatal error\n");
 
262
#else /* MINGW */
 
263
                dw_win_time();
 
264
                fprintf(LOG,"Fatal: Unknown fatal error\n");
 
265
#endif /* MINGW */
 
266
        }
 
267
        exit(1);
 
268
}
 
269
 
 
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 */
 
273
void set_time() {
 
274
        time_t sys_time;
 
275
        sys_time = time(0);
 
276
        if(sizeof(sys_time) > 4) {
 
277
                if(sys_time != -1) {
 
278
                        the_time = sys_time - 290805600;
 
279
                }
 
280
        } else {
 
281
                if(sys_time < DW_MINTIME) {
 
282
                        the_time = sys_time + 4004161696U;
 
283
                } else {
 
284
                        the_time = sys_time - 290805600;
 
285
                }
 
286
        }
 
287
        the_time <<= 8; /* Each second has 256 "ticks" */
 
288
}
 
289
 
 
290
/* Set up some signal handlers, so MaraDNS can write the cache to a file
 
291
 * when exiting */
 
292
#ifndef MINGW
 
293
int got_signal = 0;
 
294
 
 
295
/* Handler for various signals.
 
296
 *
 
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
 
300
 */
 
301
 
 
302
/* TERM signal handler */
 
303
void handle_signal(int code) {
 
304
        switch(code) {
 
305
                case SIGTERM:
 
306
                case SIGINT:
 
307
                        got_signal = 1;
 
308
                        break;
 
309
                case SIGHUP:
 
310
                        got_signal = 2;
 
311
                        break;
 
312
                case SIGUSR1:
 
313
                        got_signal = 3;
 
314
        }
 
315
        signal(code, handle_signal);
 
316
}
 
317
 
 
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);
 
324
}
 
325
#endif /* MINGW */
 
326
 
 
327
/* Process a signal received */
 
328
void process_signal(int number) {
 
329
        dw_str *filename = 0;
 
330
        char *fname_convert = 0;
 
331
 
 
332
#ifndef MINGW
 
333
        /* Clear the signal flag */
 
334
        got_signal = 0;
 
335
#endif /* MINGW */
 
336
 
 
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);
 
343
                free(fname_convert);
 
344
        }
 
345
 
 
346
#ifndef MINGW
 
347
        /* Exit if they requested it (*NIX only) */
 
348
        if(number == 1) { /* TERM */
 
349
                exit(0);
 
350
        } else if(number == 2) { /* HUP */
 
351
                exit(8); /* Use by Duende to indicate we exited with HUP */
 
352
        }
 
353
#endif /* MINGW */
 
354
}
 
355
 
 
356
/* Initialize the cache */
 
357
void init_cache() {
 
358
        dw_str *filename = 0;
 
359
        char *fname_convert = 0;
 
360
 
 
361
        dwh_process_mararc_params(); /* Get the cache size */
 
362
        if(cache != 0) { /* Don't init cache twice */
 
363
                return;
 
364
        }
 
365
 
 
366
        /* See if we can read the cache from a file */
 
367
        filename = key_s[DWM_S_cache_file];
 
368
        if(filename != 0) {
 
369
                dw_filename_sanitize(filename);
 
370
                fname_convert = (char *)dw_to_cstr(filename);
 
371
                cache = dwh_read_hash(fname_convert);
 
372
                free(fname_convert);
 
373
        }
 
374
 
 
375
        if(cache == 0) { /* Just in case read from file failed */
 
376
                cache = dwh_hash_init(0); /* Size comes from dwood2rc */
 
377
        }
 
378
}
 
379
 
 
380
/* Read mararc parameters and set global variables based on those
 
381
 * parameters */
 
382
void process_mararc(char *name) {
 
383
        if(dwm_parse_mararc(name) != 1) {
 
384
                dw_log_3strings("Fatal error parsing file ",name,"",1);
 
385
                exit(1);
 
386
        }
 
387
        /* The following sanity check triggers a warning; disabled */
 
388
        /*if(key_s == 0 || key_d == 0) {
 
389
                dw_fatal("error getting mararc parameters");
 
390
        }*/
 
391
}
 
392
 
 
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) {
 
396
        dw_str *z = 0;
 
397
 
 
398
        z = dw_create(len + 1);
 
399
        if(z == 0) {
 
400
                dw_fatal("error creating rng dw_str");
 
401
        }
 
402
 
 
403
        if(dw_cstr_append(noise, len, z) == -1) {
 
404
                dw_fatal("error putting noise in dw_str object");
 
405
        }
 
406
 
 
407
        rng_seed = dwr_init_rg(z);
 
408
 
 
409
        if(rng_seed == 0) {
 
410
                dw_fatal("error initializing rng_seed");
 
411
        }
 
412
 
 
413
        if(z != 0) {
 
414
                dw_destroy(z);
 
415
                z = 0;
 
416
        }
 
417
}
 
418
 
 
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) {
 
423
        char *filename = 0;
 
424
        int zap = 0;
 
425
        int seed = -1;
 
426
 
 
427
        if(key_s[DWM_S_random_seed_file] == 0) {
 
428
                filename = "/dev/urandom"; /* Default filename */
 
429
        } else {
 
430
                filename = (char *)dw_to_cstr(key_s[DWM_S_random_seed_file]);
 
431
                zap = 1;
 
432
        }
 
433
 
 
434
        seed = open(filename, O_RDONLY);
 
435
        if(seed == -1) {
 
436
                dw_log_3strings("Fatal error opening random seed file ",
 
437
                       filename,"",1);
 
438
                exit(1);
 
439
        }
 
440
 
 
441
        if(read(seed,(void *)noise,len) < 16) {
 
442
                dw_log_3strings("Unable to get 128 bits of entropy; file ",
 
443
                       filename,
 
444
                       " must be\n at least 16 bytes (128 bits) long",1);
 
445
                exit(1);
 
446
        }
 
447
 
 
448
        if(zap == 1) {
 
449
                free(filename);
 
450
                filename = 0;
 
451
        }
 
452
        close(seed);
 
453
 
 
454
}
 
455
 
 
456
/* Initialize random number generator.  Note that some bytes of the "noise"
 
457
 * string will have random junk in them.  This is intentional. */
 
458
void init_rng() {
 
459
        int a = 0;
 
460
        uint8_t *noise = 0;
 
461
        int64_t tstamp = 0;
 
462
        pid_t pnum = 1;
 
463
 
 
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 */
 
469
        memset(noise,0,512);
 
470
#endif /* VALGRIND_NOERRORS */
 
471
        if(noise == 0) {
 
472
                dw_fatal("error allocating memory for noise");
 
473
        }
 
474
 
 
475
        get_entropy_from_seedfile(noise,256);
 
476
 
 
477
        /* Get entropy from the current timestamp */
 
478
        set_time();
 
479
        tstamp = get_time();
 
480
        for(a = 0 ; a < 8 ; a++) {
 
481
                *(noise + a + 256) = tstamp & 0xff;
 
482
                tstamp >>= 8;
 
483
        }
 
484
 
 
485
        /* Get entropy from the process' ID number */
 
486
        pnum = getpid();
 
487
        for(a = 0 ; a < sizeof(pnum) ; a++ ) {
 
488
                *(noise + a + 272) = pnum & 0xff;
 
489
                pnum >>= 8;
 
490
        }
 
491
 
 
492
        /* Initialize the RNG based on the contents of noise */
 
493
        noise_to_rng(noise,510);
 
494
 
 
495
        if(noise != 0) {
 
496
                free(noise);
 
497
                noise = 0;
 
498
        }
 
499
 
 
500
}
 
501
 
 
502
/* Drop privileges and become unprivileged user */
 
503
void sandbox() {
 
504
#if ! (defined MINGW || defined __CYGWIN__)
 
505
        unsigned char *c = 0;
 
506
        gid_t g = DW_UID;
 
507
        if(key_s[DWM_S_chroot_dir] == 0) {
 
508
                dw_fatal("chroot_dir not set");
 
509
        }
 
510
        c = dw_to_cstr(key_s[DWM_S_chroot_dir]);
 
511
        if(c == 0) {
 
512
                dw_fatal("Converting chroot_dir to string failed");
 
513
        }
 
514
        if(chdir((char *)c) != 0) {
 
515
                dw_fatal("chdir() failed");
 
516
        }
 
517
#ifndef QNX
 
518
        if(chroot((char *)c) == -1) {
 
519
                dw_fatal("chroot() failed");
 
520
        }
 
521
#endif
 
522
        if(setgroups(1,&g) == -1) {
 
523
                dw_fatal("setgroups() failed");
 
524
        }
 
525
        if(setgid(maradns_gid) != 0) {
 
526
                dw_fatal("setgid() failed");
 
527
        }
 
528
        if(setuid(maradns_uid) != 0) {
 
529
                dw_fatal("setuid() failed");
 
530
        }
 
531
        if(setuid(0) == 0) {
 
532
                dw_fatal("Your kernel\'s setuid() is broken");
 
533
        }
 
534
 
 
535
        if(c != 0) {
 
536
                free(c);
 
537
                c = 0;
 
538
        }
 
539
        return;
 
540
#endif /* MINGW */
 
541
}
 
542
 
 
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() {
 
546
        dw_str *bind = 0;
 
547
 
 
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]);
 
552
        } else {
 
553
                        dw_fatal("Please set bind_address");
 
554
        }
 
555
 
 
556
        if(bind == 0) {
 
557
                goto catch_get_bind_addrs;
 
558
        }
 
559
 
 
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;
 
564
                }
 
565
                if(dw_append(key_s[DWM_S_ipv4_bind_addresses],bind) == -1) {
 
566
                        goto catch_get_bind_addrs;
 
567
                }
 
568
        }
 
569
 
 
570
        return bind;
 
571
 
 
572
catch_get_bind_addrs:
 
573
        if(bind != 0) {
 
574
                dw_destroy(bind);
 
575
                bind = 0;
 
576
        }
 
577
        return 0;
 
578
}
 
579
 
 
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.
 
585
 *
 
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:
 
588
 *
 
589
 * QR must be 0
 
590
 * Opcode must be 0
 
591
 * RD must be 1
 
592
 * Z must be 0
 
593
 * RCODE must be 0
 
594
 * QDCOUNT must be 1
 
595
 * ANCOUNT, NSCOUNT, and ARCOUNT must be 0
 
596
 */
 
597
 
 
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 */
 
601
                return -1;
 
602
        }
 
603
        if(roy_arends_check == 1 && ((a[2] & 0x80) != 0)) {
 
604
                /* If it's an answer, not a query */
 
605
                return -1;
 
606
        }
 
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))
 
620
        {
 
621
                return -1;
 
622
        }
 
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);
 
629
                return -1;
 
630
        }
 
631
 
 
632
        return (a[0] << 8) | a[1];
 
633
}
 
634
 
 
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 */
 
641
                return -1;
 
642
        }
 
643
        *packet = qid >> 8;
 
644
        *(packet + 1) = qid & 0xff;
 
645
        return qid;
 
646
}
 
647
 
 
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;
 
653
        char *ret = 0;
 
654
 
 
655
        a = dw_qspop(list);
 
656
        if(a == 0) {
 
657
                goto catch_pop_last_item;
 
658
        }
 
659
        b = dw_zap_lws(a);
 
660
        if(b == 0) {
 
661
                goto catch_pop_last_item;
 
662
        }
 
663
        ret = (char *)dw_to_cstr(b);
 
664
 
 
665
catch_pop_last_item:
 
666
        if(a != 0) {
 
667
                dw_destroy(a);
 
668
                a = 0;
 
669
        }
 
670
        if(b != 0) {
 
671
                dw_destroy(b);
 
672
                b = 0;
 
673
        }
 
674
        return ret;
 
675
}
 
676
 
 
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;
 
683
        uint8_t last = 0;
 
684
 
 
685
        if(len < 1 || len > 64) {
 
686
                return;
 
687
        }
 
688
 
 
689
        /* Since we're dividing by a power of 2, we don't need to do
 
690
         * an expensive division */
 
691
        div = num >> 3;
 
692
        rem = (num & 0x07);
 
693
 
 
694
        if(div < 0 || div > len) { /* Sanity check */
 
695
                return;
 
696
        }
 
697
 
 
698
        /* The last byte in the string is determined by the modulo */
 
699
        last = 0xff;
 
700
        last <<= (8 - rem);
 
701
 
 
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 */
 
705
                *str = 0xff;
 
706
                str++;
 
707
                div--;
 
708
                len--;
 
709
        }
 
710
        if(len > 0) { /* Check needed for /32 and /128 masks */
 
711
                *str = last; /* The last non-0 byte */
 
712
                len--;
 
713
                while(len > 0) { /* The rest of the mask is 0x00 */
 
714
                        str++;
 
715
                        *str = 0x00;
 
716
                        len--;
 
717
                }
 
718
        }
 
719
}
 
720
 
 
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
 
723
 * the def value */
 
724
int32_t get_key_n(int32_t get, int32_t min, int32_t max, int32_t def) {
 
725
        int32_t val;
 
726
 
 
727
        val = key_n[get];
 
728
 
 
729
        if(val < min) {
 
730
                if(def == -1) {
 
731
                        val = min;
 
732
                } else {
 
733
                        val = def;
 
734
                }
 
735
        } else if(val > max) {
 
736
                if(def == -1) {
 
737
                        val = max;
 
738
                } else {
 
739
                        val = def;
 
740
                }
 
741
        }
 
742
        return val;
 
743
}
 
744