~cyphermox/ubuntu/precise/dnsmasq/dbus

« back to all changes in this revision

Viewing changes to src/option.c

  • Committer: Bazaar Package Importer
  • Author(s): Simon Kelley
  • Date: 2005-05-04 13:25:23 UTC
  • mfrom: (0.2.1 upstream) (1.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050504132523-29x9nzdnkypp62nc
Tags: 2.22-2
Make the resolv.conf polling code resistant to 
backwards-moving system clocks. (closes: #306117) (closes: #300694)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* dnsmasq is Copyright (c) 2000 - 2005 Simon Kelley
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 dated June, 1991.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
*/
 
12
 
 
13
/* Author's email: simon@thekelleys.org.uk */
 
14
 
 
15
#include "dnsmasq.h"
 
16
 
 
17
struct myoption {
 
18
  const char *name;
 
19
  int has_arg;
 
20
  int *flag;
 
21
  int val;
 
22
};
 
23
 
 
24
#define OPTSTRING "yZDNLERKzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:J:W:Y:"
 
25
 
 
26
static struct myoption opts[] = { 
 
27
  {"version", 0, 0, 'v'},
 
28
  {"no-hosts", 0, 0, 'h'},
 
29
  {"no-poll", 0, 0, 'n'},
 
30
  {"help", 0, 0, 'w'},
 
31
  {"no-daemon", 0, 0, 'd'},
 
32
  {"log-queries", 0, 0, 'q'},
 
33
  {"user", 1, 0, 'u'},
 
34
  {"group", 1, 0, 'g'},
 
35
  {"resolv-file", 1, 0, 'r'},
 
36
  {"mx-host", 1, 0, 'm'},
 
37
  {"mx-target", 1, 0, 't'},
 
38
  {"cache-size", 1, 0, 'c'},
 
39
  {"port", 1, 0, 'p'},
 
40
  {"dhcp-leasefile", 1, 0, 'l'},
 
41
  {"dhcp-lease", 1, 0, 'l' },
 
42
  {"dhcp-host", 1, 0, 'G'},
 
43
  {"dhcp-range", 1, 0, 'F'},
 
44
  {"dhcp-option", 1, 0, 'O'},
 
45
  {"dhcp-boot", 1, 0, 'M'},
 
46
  {"domain", 1, 0, 's'},
 
47
  {"domain-suffix", 1, 0, 's'},
 
48
  {"interface", 1, 0, 'i'},
 
49
  {"listen-address", 1, 0, 'a'},
 
50
  {"bogus-priv", 0, 0, 'b'},
 
51
  {"bogus-nxdomain", 1, 0, 'B'},
 
52
  {"selfmx", 0, 0, 'e'},
 
53
  {"filterwin2k", 0, 0, 'f'},
 
54
  {"pid-file", 1, 0, 'x'},
 
55
  {"strict-order", 0, 0, 'o'},
 
56
  {"server", 1, 0, 'S'},
 
57
  {"local", 1, 0, 'S' },
 
58
  {"address", 1, 0, 'A' },
 
59
  {"conf-file", 1, 0, 'C'},
 
60
  {"no-resolv", 0, 0, 'R'},
 
61
  {"expand-hosts", 0, 0, 'E'},
 
62
  {"localmx", 0, 0, 'L'},
 
63
  {"local-ttl", 1, 0, 'T'},
 
64
  {"no-negcache", 0, 0, 'N'},
 
65
  {"addn-hosts", 1, 0, 'H'},
 
66
  {"query-port", 1, 0, 'Q'},
 
67
  {"except-interface", 1, 0, 'I'},
 
68
  {"domain-needed", 0, 0, 'D'},
 
69
  {"dhcp-lease-max", 1, 0, 'X' },
 
70
  {"bind-interfaces", 0, 0, 'z'},
 
71
  {"read-ethers", 0, 0, 'Z' },
 
72
  {"alias", 1, 0, 'V' },
 
73
  {"dhcp-vendorclass", 1, 0, 'U'},
 
74
  {"dhcp-userclass", 1, 0, 'j'},
 
75
  {"dhcp-ignore", 1, 0, 'J'},
 
76
  {"edns-packet-max", 1, 0, 'P'},
 
77
  {"keep-in-foreground", 0, 0, 'k'},
 
78
  {"dhcp-authoritative", 0, 0, 'K'},
 
79
  {"srv-host", 1, 0, 'W'},
 
80
  {"localise-queries", 0, 0, 'y'},
 
81
  {"txt-record", 1, 0, 'Y'},
 
82
  {0, 0, 0, 0}
 
83
};
 
84
 
 
85
struct optflags {
 
86
  char c;
 
87
  unsigned int flag; 
 
88
};
 
89
 
 
90
static struct optflags optmap[] = {
 
91
  { 'b', OPT_BOGUSPRIV },
 
92
  { 'f', OPT_FILTER },
 
93
  { 'q', OPT_LOG },
 
94
  { 'e', OPT_SELFMX },
 
95
  { 'h', OPT_NO_HOSTS },
 
96
  { 'n', OPT_NO_POLL },
 
97
  { 'd', OPT_DEBUG },
 
98
  { 'k', OPT_NO_FORK },
 
99
  { 'K', OPT_AUTHORITATIVE },
 
100
  { 'o', OPT_ORDER },
 
101
  { 'R', OPT_NO_RESOLV },
 
102
  { 'E', OPT_EXPAND },
 
103
  { 'L', OPT_LOCALMX },
 
104
  { 'N', OPT_NO_NEG },
 
105
  { 'D', OPT_NODOTS_LOCAL },
 
106
  { 'z', OPT_NOWILD },
 
107
  { 'Z', OPT_ETHERS },
 
108
  { 'y', OPT_LOCALISE },
 
109
  { 'v', 0},
 
110
  { 'w', 0},
 
111
  { 0, 0 }
 
112
};
 
113
 
 
114
static char *usage =
 
115
"Usage: dnsmasq [options]\n\n"
 
116
#ifndef HAVE_GETOPT_LONG
 
117
"Use short options only on the command line.\n"
 
118
#endif
 
119
"Valid options are :\n"
 
120
"-a, --listen-address=ipaddr         Specify local address(es) to listen on.\n"
 
121
"-A, --address=/domain/ipaddr        Return ipaddr for all hosts in specified domains.\n"
 
122
"-b, --bogus-priv                    Fake reverse lookups for RFC1918 private address ranges.\n"
 
123
"-B, --bogus-nxdomain=ipaddr         Treat ipaddr as NXDOMAIN (defeats Verisign wildcard).\n" 
 
124
"-c, --cache-size=cachesize          Specify the size of the cache in entries (defaults to %d).\n"
 
125
"-C, --conf-file=path                Specify configuration file (defaults to " CONFFILE ").\n"
 
126
"-d, --no-daemon                     Do NOT fork into the background: run in debug mode.\n"
 
127
"-D, --domain-needed                 Do NOT forward queries with no domain part.\n" 
 
128
"-e, --selfmx                        Return self-pointing MX records for local hosts.\n"
 
129
"-E, --expand-hosts                  Expand simple names in /etc/hosts with domain-suffix.\n"
 
130
"-f, --filterwin2k                   Don't forward spurious DNS requests from Windows hosts.\n"
 
131
"-F, --dhcp-range=ipaddr,ipaddr,time Enable DHCP in the range given with lease duration.\n"
 
132
"-g, --group=groupname               Change to this group after startup (defaults to " CHGRP ").\n"
 
133
"-G, --dhcp-host=<hostspec>          Set address or hostname for a specified machine.\n"
 
134
"-h, --no-hosts                      Do NOT load " HOSTSFILE " file.\n"
 
135
"-H, --addn-hosts=path               Specify a hosts file to be read in addition to " HOSTSFILE ".\n"
 
136
"-i, --interface=interface           Specify interface(s) to listen on.\n"
 
137
"-I, --except-interface=int          Specify interface(s) NOT to listen on.\n"
 
138
"-j, --dhcp-userclass=<id>,<class>   Map DHCP user class to option set.\n"
 
139
"-J, --dhcp-ignore=<id>              Don't do DHCP for hosts in option set.\n"
 
140
"-k, --keep-in-foreground            Do NOT fork into the background, do NOT run in debug mode.\n"
 
141
"-K, --dhcp-authoritative            Assume we are the only DHCP server on the local network.\n"
 
142
"-l, --dhcp-leasefile=path           Specify where to store DHCP leases (defaults to " LEASEFILE ").\n"
 
143
"-L, --localmx                       Return MX records for local hosts.\n"
 
144
"-m, --mx-host=host_name,target,pref Specify an MX record.\n"
 
145
"-M, --dhcp-boot=<bootp opts>        Specify BOOTP options to DHCP server.\n"
 
146
"-n, --no-poll                       Do NOT poll " RESOLVFILE " file, reload only on SIGHUP.\n"
 
147
"-N, --no-negcache                   Do NOT cache failed search results.\n"
 
148
"-o, --strict-order                  Use nameservers strictly in the order given in " RESOLVFILE ".\n"
 
149
"-O, --dhcp-option=<optspec>         Set extra options to be set to DHCP clients.\n"
 
150
"-p, --port=number                   Specify port to listen for DNS requests on (defaults to 53).\n"
 
151
"-P, --edns-packet-max=<size>        Maximum supported UDP packet size for EDNS.0 (defaults to %d).\n"
 
152
"-q, --log-queries                   Log queries.\n"
 
153
"-Q, --query-port=number             Force the originating port for upstream queries.\n"
 
154
"-R, --no-resolv                     Do NOT read resolv.conf.\n"
 
155
"-r, --resolv-file=path              Specify path to resolv.conf (defaults to " RESOLVFILE ").\n"
 
156
"-S, --server=/domain/ipaddr         Specify address(es) of upstream servers with optional domains.\n"
 
157
"    --local=/domain/                Never forward queries to specified domains.\n"
 
158
"-s, --domain=domain                 Specify the domain to be assigned in DHCP leases.\n"
 
159
"-t, --mx-target=host_name           Specify default target in an MX record.\n"
 
160
"-T, --local-ttl=time                Specify time-to-live in seconds for replies from /etc/hosts.\n"
 
161
"-u, --user=username                 Change to this user after startup. (defaults to " CHUSER ").\n" 
 
162
"-U, --dhcp-vendorclass=<id>,<class> Map DHCP vendor class to option set.\n"
 
163
"-v, --version                       Display dnsmasq version and copyright information.\n"
 
164
"-V, --alias=addr,addr,mask          Translate IPv4 addresses from upstream servers.\n"
 
165
"-W, --srv-host=name,target,...      Specify a SRV record.\n"
 
166
"-w, --help                          Display this message.\n"
 
167
"-x, --pid-file=path                 Specify path of PID file. (defaults to " RUNFILE ").\n"
 
168
"-X, --dhcp-lease-max=number         Specify maximum number of DHCP leases (defaults to %d).\n"
 
169
"-y, --localise-queries              Answer DNS queries based on the interface a query was sent to.\n"
 
170
"-Y  --txt-record=name,txt....       Specify TXT DNS record.\n"
 
171
"-z, --bind-interfaces               Bind only to interfaces in use.\n"
 
172
"-Z, --read-ethers                   Read DHCP static host information from " ETHERSFILE ".\n"
 
173
"\n";
 
174
 
 
175
static void add_txt(struct daemon *daemon, char *name, char *txt)
 
176
{
 
177
  size_t len = strlen(txt);
 
178
  struct txt_record *r = safe_malloc(sizeof(struct txt_record));
 
179
  
 
180
  r->name = safe_string_alloc(name);
 
181
  r->next = daemon->txt;
 
182
  daemon->txt = r;
 
183
  r->class = C_CHAOS;
 
184
  r->txt = safe_malloc(len+1);
 
185
  r->len = len+1;
 
186
  *(r->txt) = len;
 
187
  memcpy((r->txt)+1, txt, len);
 
188
}
 
189
 
 
190
/* filenames are OK with unquoted commas, restore them here. */
 
191
static char *safe_filename_alloc(char *filename)
 
192
{
 
193
  char *p, *ret = safe_string_alloc(filename);
 
194
  
 
195
  if (ret)
 
196
    for (p = ret; *p; p++)
 
197
      if (*p == '\001')
 
198
        *p = ',';
 
199
  
 
200
  return ret;
 
201
}
 
202
 
 
203
struct daemon *read_opts (int argc, char **argv)
 
204
{
 
205
  struct daemon *daemon = safe_malloc(sizeof(struct daemon));
 
206
  char *problem = NULL, *buff = safe_malloc(MAXDNAME);
 
207
  int option = 0, i;
 
208
  FILE *file_save = NULL, *f = NULL;
 
209
  char *p, *arg, *comma, *file_name_save = NULL, *conffile = CONFFILE;
 
210
  int hosts_index = 1, conffile_set = 0;
 
211
  int line_save = 0, lineno = 0;
 
212
  opterr = 0;
 
213
  
 
214
  memset(daemon, 0, sizeof(struct daemon));
 
215
  daemon->namebuff = buff;
 
216
 
 
217
  /* Set defaults - everything else is zero or NULL */
 
218
  daemon->min_leasetime = UINT_MAX;
 
219
  daemon->cachesize = CACHESIZ;
 
220
  daemon->port = NAMESERVER_PORT;
 
221
  daemon->default_resolv.is_default = 1;
 
222
  daemon->default_resolv.name = RESOLVFILE;
 
223
  daemon->resolv_files = &daemon->default_resolv;
 
224
  daemon->username = CHUSER;
 
225
  daemon->groupname = CHGRP;
 
226
  daemon->runfile =  RUNFILE;
 
227
  daemon->dhcp_max = MAXLEASES;
 
228
  daemon->edns_pktsz = EDNS_PKTSZ;
 
229
  add_txt(daemon, "version.bind", "dnsmasq-" VERSION );
 
230
  add_txt(daemon, "authors.bind", "Simon Kelley");
 
231
  add_txt(daemon, "copyright.bind", COPYRIGHT);
 
232
 
 
233
  
 
234
  while (1)
 
235
    {
 
236
      problem = NULL;
 
237
 
 
238
      if (!f)
 
239
        {
 
240
#ifdef HAVE_GETOPT_LONG
 
241
          option = getopt_long(argc, argv, OPTSTRING, (struct option *)opts, NULL);
 
242
#else
 
243
          option = getopt(argc, argv, OPTSTRING);
 
244
#endif
 
245
          /* Copy optarg so that argv doesn't get changed */
 
246
          if (optarg)
 
247
            {
 
248
              strncpy(buff, optarg, MAXDNAME);
 
249
              buff[MAXDNAME-1] = 0;
 
250
              arg = buff;
 
251
              for (p = arg; *p; p++)
 
252
                if (*p == ',')
 
253
                  *p = '\001';
 
254
            }
 
255
          else
 
256
            arg = NULL;
 
257
        }
 
258
      else
 
259
        { /* f non-NULL, reading from conffile. */
 
260
        reread:
 
261
          if (!fgets(buff, MAXDNAME, f))
 
262
            {
 
263
              /* At end of file, all done */
 
264
              fclose(f);
 
265
              if (file_save)
 
266
                {
 
267
                  /* may be nested */
 
268
                  conffile = file_name_save;
 
269
                  f = file_save;
 
270
                  file_save = NULL;
 
271
                  lineno = line_save;
 
272
                  goto reread;
 
273
                }
 
274
              break;
 
275
            }
 
276
          else
 
277
            {
 
278
              int white;
 
279
              lineno++;
 
280
              
 
281
              /* Implement quotes, inside quotes we allow \\ \" \n and \t 
 
282
                 unquoted commas get changed to \001 also strip comments */
 
283
              
 
284
              for (white = 1, p = buff; *p; p++)
 
285
                {
 
286
                  if (*p == '"')
 
287
                    {
 
288
                      memmove(p, p+1, strlen(p+1)+1);
 
289
                      for(; *p && *p != '"'; p++)
 
290
                        if (*p == '\\' && 
 
291
                            (p[1] == '\\' || p[1] == '"' || p[1] == 'n' || p[1] == 't'))
 
292
                          {
 
293
                            if (p[1] == 't')
 
294
                              p[1] = '\t';
 
295
                            else if (p[1] == 'n')
 
296
                              p[1] = '\n';
 
297
                            memmove(p, p+1, strlen(p+1)+1);
 
298
                          }
 
299
                      if (*p == '"') 
 
300
                        memmove(p, p+1, strlen(p+1)+1);
 
301
                      else
 
302
                        complain("missing \"", lineno, conffile);
 
303
                    }
 
304
 
 
305
                  if (white && *p == '#')
 
306
                    { 
 
307
                      *p = 0;
 
308
                      break;
 
309
                    }
 
310
                  white = isspace(*p); 
 
311
                  if (*p == ',')
 
312
                    *p = '\001';
 
313
 
 
314
                }
 
315
              /* fgets gets end of line char too. */
 
316
              while (strlen(buff) > 0 && isspace(buff[strlen(buff)-1]))
 
317
                buff[strlen(buff)-1] = 0;
 
318
              if (*buff == 0)
 
319
                continue; 
 
320
              if ((p=strchr(buff, '=')))
 
321
                {
 
322
                  arg = p+1;
 
323
                  *p = 0;
 
324
                }
 
325
              else
 
326
                arg = NULL;
 
327
              
 
328
              option = 0;
 
329
              for (i=0; opts[i].name; i++) 
 
330
                if (strcmp(opts[i].name, buff) == 0)
 
331
                  option = opts[i].val;
 
332
              if (!option)
 
333
                {
 
334
                  complain("bad option", lineno, conffile);
 
335
                  continue;
 
336
                }
 
337
            }
 
338
        }
 
339
      
 
340
      if (option == -1)
 
341
        { /* end of command line args, start reading conffile. */
 
342
          if (!conffile)
 
343
            break; /* "confile=" option disables */
 
344
        fileopen:
 
345
          option = 0;
 
346
          if (!(f = fopen(conffile, "r")))
 
347
            {   
 
348
              if (errno == ENOENT && !conffile_set)
 
349
                break; /* No conffile, all done. */
 
350
              else
 
351
                die("cannot read %s: %s", conffile);
 
352
            }
 
353
        }
 
354
     
 
355
      if (!f && option == 'w')
 
356
        {
 
357
          printf (usage,  CACHESIZ, EDNS_PKTSZ, MAXLEASES);
 
358
          exit(0);
 
359
        }
 
360
 
 
361
      if (!f && option == 'v')
 
362
        {
 
363
          printf("Dnsmasq version %s  %s\n\n", VERSION, COPYRIGHT);
 
364
          printf("This software comes with ABSOLUTELY NO WARRANTY.\n");
 
365
          printf("Dnsmasq is free software, and you are welcome to redistribute it\n");
 
366
          printf("under the terms of the GNU General Public License, version 2.\n");
 
367
          exit(0);
 
368
        }
 
369
      
 
370
      for (i=0; optmap[i].c; i++)
 
371
        if (option == optmap[i].c)
 
372
          {
 
373
            daemon->options |= optmap[i].flag;
 
374
            option = 0;
 
375
            if (f && arg)
 
376
              complain("extraneous parameter", lineno, conffile);
 
377
            break;
 
378
          }
 
379
      
 
380
      if (option && option != '?')
 
381
        {
 
382
          if (f && !arg)
 
383
            {
 
384
              complain("missing parameter", lineno, conffile);
 
385
              continue;
 
386
            }
 
387
                  
 
388
          switch (option)
 
389
            { 
 
390
             case 'C': 
 
391
               if (!f)
 
392
                 {
 
393
                   conffile = safe_filename_alloc(arg);
 
394
                   conffile_set = 1;
 
395
                   break;
 
396
                 }
 
397
              
 
398
               /* nest conffiles one deep */
 
399
               if (file_save)
 
400
                 {
 
401
                   complain("nested includes not allowed", lineno, conffile);
 
402
                   continue;
 
403
                 }
 
404
               file_name_save = conffile;
 
405
               file_save = f;
 
406
               line_save = lineno;
 
407
               conffile = safe_filename_alloc(arg);
 
408
               conffile_set = 1;
 
409
               lineno = 0;
 
410
               goto fileopen;
 
411
              
 
412
            case 'x': 
 
413
              daemon->runfile = safe_filename_alloc(arg);
 
414
              break;
 
415
              
 
416
            case 'r':
 
417
              {
 
418
                char *name = safe_filename_alloc(arg);
 
419
                struct resolvc *new, *list = daemon->resolv_files;
 
420
                
 
421
                if (list && list->is_default)
 
422
                  {
 
423
                    /* replace default resolv file - possibly with nothing */
 
424
                    if (name)
 
425
                      {
 
426
                        list->is_default = 0;
 
427
                        list->name = name;
 
428
                      }
 
429
                    else
 
430
                      list = NULL;
 
431
                  }
 
432
                else if (name)
 
433
                  {
 
434
                    new = safe_malloc(sizeof(struct resolvc));
 
435
                    new->next = list;
 
436
                    new->name = name;
 
437
                    new->is_default = 0;
 
438
                    new->mtime = 0;
 
439
                    new->logged = 0;
 
440
                    list = new;
 
441
                  }
 
442
                daemon->resolv_files = list;
 
443
                break;
 
444
              }
 
445
 
 
446
            case 'm':
 
447
              {
 
448
                int pref = 1;
 
449
                struct mx_srv_record *new;
 
450
 
 
451
                if ((comma = strchr(arg, '\001')))
 
452
                  {
 
453
                    char *prefstr;
 
454
                    *(comma++) = 0;
 
455
                    if ((prefstr=strchr(comma, '\001')))
 
456
                      {
 
457
                        *(prefstr++) = 0;
 
458
                        if (!atoi_check(prefstr, &pref))
 
459
                          {
 
460
                            option = '?';
 
461
                            problem = "bad MX preference";
 
462
                            break;
 
463
                          }
 
464
                      }
 
465
                  }
 
466
 
 
467
                if (!canonicalise(arg) || (comma && !canonicalise(comma)))
 
468
                  {
 
469
                    option = '?';
 
470
                    problem = "bad MX name";
 
471
                    break;
 
472
                  }
 
473
 
 
474
                new = safe_malloc(sizeof(struct mx_srv_record));
 
475
                new->next = daemon->mxnames;
 
476
                daemon->mxnames = new;
 
477
                new->issrv = 0;
 
478
                new->name = safe_string_alloc(arg);
 
479
                new->target = safe_string_alloc(comma); /* may be NULL */
 
480
                new->weight = pref;
 
481
                break;
 
482
              }
 
483
 
 
484
            case 't':
 
485
              if (!canonicalise(arg))
 
486
                {
 
487
                  option = '?';
 
488
                  problem = "bad MX target";
 
489
                }
 
490
              else
 
491
                daemon->mxtarget = safe_string_alloc(arg);
 
492
              break;
 
493
              
 
494
            case 'l':
 
495
              daemon->lease_file = safe_filename_alloc(arg);
 
496
              break;
 
497
              
 
498
            case 'H':
 
499
              {
 
500
                struct hostsfile *new = safe_malloc(sizeof(struct hostsfile));
 
501
                new->fname = safe_filename_alloc(arg);
 
502
                new->index = hosts_index++;
 
503
                new->next = daemon->addn_hosts;
 
504
                daemon->addn_hosts = new;
 
505
                break;
 
506
              }
 
507
 
 
508
            case 's':
 
509
              if (strcmp (arg, "#") == 0)
 
510
                daemon->options |= OPT_RESOLV_DOMAIN;
 
511
              else if (!canonicalise(arg))
 
512
                option = '?';
 
513
              else
 
514
                daemon->domain_suffix = safe_string_alloc(arg);
 
515
              break;
 
516
              
 
517
            case 'u':
 
518
              daemon->username = safe_string_alloc(arg);
 
519
              break;
 
520
              
 
521
            case 'g':
 
522
              daemon->groupname = safe_string_alloc(arg);
 
523
              break;
 
524
              
 
525
            case 'i':
 
526
              do {
 
527
                struct iname *new = safe_malloc(sizeof(struct iname));
 
528
                if ((comma = strchr(arg, '\001')))
 
529
                  *comma++ = 0;
 
530
                new->next = daemon->if_names;
 
531
                daemon->if_names = new;
 
532
                /* new->name may be NULL if someone does
 
533
                   "interface=" to disable all interfaces except loop. */
 
534
                new->name = safe_string_alloc(arg);
 
535
                new->isloop = new->used = 0;
 
536
                if (strchr(arg, ':'))
 
537
                  daemon->options |= OPT_NOWILD;
 
538
                arg = comma;
 
539
              } while (arg);
 
540
              break;
 
541
            
 
542
            case 'I':
 
543
              do {
 
544
                struct iname *new = safe_malloc(sizeof(struct iname));
 
545
                if ((comma = strchr(arg, '\001')))
 
546
                  *comma++ = 0;
 
547
                new->next = daemon->if_except;
 
548
                daemon->if_except = new;
 
549
                new->name = safe_string_alloc(arg);
 
550
                if (strchr(arg, ':'))
 
551
                  daemon->options |= OPT_NOWILD;
 
552
                arg = comma;
 
553
              } while (arg);
 
554
              break;
 
555
                      
 
556
            case 'B':
 
557
              {
 
558
                struct in_addr addr;
 
559
                if ((addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
 
560
                  {
 
561
                    struct bogus_addr *baddr = safe_malloc(sizeof(struct bogus_addr));
 
562
                    baddr->next = daemon->bogus_addr;
 
563
                    daemon->bogus_addr = baddr;
 
564
                    baddr->addr = addr;
 
565
                  }
 
566
                else
 
567
                  option = '?'; /* error */
 
568
                break;  
 
569
              }
 
570
 
 
571
            case 'a':
 
572
              do {
 
573
                struct iname *new = safe_malloc(sizeof(struct iname));
 
574
                if ((comma = strchr(arg, '\001')))
 
575
                  *comma++ = 0;
 
576
                new->next = daemon->if_addrs;
 
577
#ifdef HAVE_IPV6
 
578
                if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr))
 
579
                  {
 
580
                    new->addr.sa.sa_family = AF_INET;
 
581
#ifdef HAVE_SOCKADDR_SA_LEN
 
582
                    new->addr.in.sin_len = sizeof(struct sockaddr_in);
 
583
#endif
 
584
                  }
 
585
                else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr))
 
586
                  {
 
587
                    new->addr.sa.sa_family = AF_INET6;
 
588
                    new->addr.in6.sin6_flowinfo = htonl(0);
 
589
#ifdef HAVE_SOCKADDR_SA_LEN
 
590
                    new->addr.in6.sin6_len = sizeof(struct sockaddr_in6);
 
591
#endif
 
592
                  }
 
593
#else
 
594
                if ((new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
 
595
                  {
 
596
                    new->addr.sa.sa_family = AF_INET;
 
597
#ifdef HAVE_SOCKADDR_SA_LEN
 
598
                    new->addr.in.sin_len = sizeof(struct sockaddr_in);
 
599
#endif
 
600
                  }
 
601
#endif
 
602
                else
 
603
                  {
 
604
                    option = '?'; /* error */
 
605
                    free(new);
 
606
                    break;
 
607
                  }
 
608
                
 
609
                daemon->if_addrs = new;
 
610
                arg = comma;
 
611
              } while (arg);
 
612
              break;
 
613
                      
 
614
            case 'S':
 
615
            case 'A':
 
616
              {
 
617
                struct server *serv, *newlist = NULL;
 
618
                
 
619
                if (*arg == '/')
 
620
                  {
 
621
                    char *end;
 
622
                    arg++;
 
623
                    while ((end = strchr(arg, '/')))
 
624
                      {
 
625
                        char *domain = NULL;
 
626
                        *end = 0;
 
627
                        /* # matches everything and becomes a zero length domain string */
 
628
                        if (strcmp(arg, "#") == 0)
 
629
                          domain = "";
 
630
                        else if (!canonicalise(arg) && strlen(arg) != 0)
 
631
                          option = '?';
 
632
                        else
 
633
                          domain = safe_string_alloc(arg); /* NULL if strlen is zero */
 
634
                        serv = safe_malloc(sizeof(struct server));
 
635
                        serv->next = newlist;
 
636
                        newlist = serv;
 
637
                        serv->sfd = NULL;
 
638
                        serv->domain = domain;
 
639
                        serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
 
640
                        arg = end+1;
 
641
                      }
 
642
                    if (!newlist)
 
643
                      {
 
644
                        option = '?';
 
645
                        break;
 
646
                      }
 
647
                
 
648
                  }
 
649
                else
 
650
                  {
 
651
                    newlist = safe_malloc(sizeof(struct server));
 
652
                    newlist->next = NULL;
 
653
                    newlist->flags = 0;
 
654
                    newlist->sfd = NULL;
 
655
                    newlist->domain = NULL;
 
656
                  }
 
657
                
 
658
                if (option == 'A')
 
659
                  {
 
660
                    newlist->flags |= SERV_LITERAL_ADDRESS;
 
661
                    if (!(newlist->flags & SERV_TYPE))
 
662
                      option = '?';
 
663
                  }
 
664
                
 
665
                if (!*arg)
 
666
                  {
 
667
                    newlist->flags |= SERV_NO_ADDR; /* no server */
 
668
                    if (newlist->flags & SERV_LITERAL_ADDRESS)
 
669
                      option = '?';
 
670
                  }
 
671
                else
 
672
                  {
 
673
                    int source_port = 0, serv_port = NAMESERVER_PORT;
 
674
                    char *portno, *source;
 
675
                    
 
676
                    if ((source = strchr(arg, '@'))) /* is there a source. */
 
677
                      {
 
678
                        *source = 0; 
 
679
                        if ((portno = strchr(source+1, '#')))
 
680
                          { 
 
681
                            *portno = 0;
 
682
                            if (!atoi_check(portno+1, &source_port))
 
683
                              {
 
684
                                option = '?';
 
685
                                problem = "bad port";
 
686
                              }
 
687
                          }
 
688
                      }
 
689
                    
 
690
                    if ((portno = strchr(arg, '#'))) /* is there a port no. */
 
691
                      {
 
692
                        *portno = 0;
 
693
                        if (!atoi_check(portno+1, &serv_port))
 
694
                          {
 
695
                            option = '?';
 
696
                            problem = "bad port";
 
697
                          }
 
698
                      }
 
699
 
 
700
#ifdef HAVE_IPV6
 
701
                    if (inet_pton(AF_INET, arg, &newlist->addr.in.sin_addr))
 
702
#else
 
703
                    if ((newlist->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t) -1)
 
704
#endif
 
705
                      {
 
706
                        newlist->addr.in.sin_port = htons(serv_port);   
 
707
                        newlist->source_addr.in.sin_port = htons(source_port); 
 
708
                        newlist->addr.sa.sa_family = newlist->source_addr.sa.sa_family = AF_INET;
 
709
#ifdef HAVE_SOCKADDR_SA_LEN
 
710
                        newlist->source_addr.in.sin_len = newlist->addr.in.sin_len = sizeof(struct sockaddr_in);
 
711
#endif
 
712
                        if (source)
 
713
                          {
 
714
#ifdef HAVE_IPV6
 
715
                            if (inet_pton(AF_INET, source+1, &newlist->source_addr.in.sin_addr))
 
716
#else
 
717
                            if ((newlist->source_addr.in.sin_addr.s_addr = inet_addr(source+1)) != (in_addr_t) -1)
 
718
#endif
 
719
                                newlist->flags |= SERV_HAS_SOURCE;
 
720
                            else
 
721
                              option = '?'; /* error */
 
722
                          }
 
723
                        else
 
724
                          newlist->source_addr.in.sin_addr.s_addr = INADDR_ANY;
 
725
                      }
 
726
#ifdef HAVE_IPV6
 
727
                    else if (inet_pton(AF_INET6, arg, &newlist->addr.in6.sin6_addr))
 
728
                      {
 
729
                        newlist->addr.in6.sin6_port = htons(serv_port);
 
730
                        newlist->source_addr.in6.sin6_port = htons(source_port);
 
731
                        newlist->addr.sa.sa_family = newlist->source_addr.sa.sa_family = AF_INET6;
 
732
                        newlist->addr.in6.sin6_flowinfo = newlist->source_addr.in6.sin6_flowinfo = htonl(0);
 
733
#ifdef HAVE_SOCKADDR_SA_LEN
 
734
                        newlist->addr.in6.sin6_len = newlist->source_addr.in6.sin6_len = sizeof(struct sockaddr_in6);
 
735
#endif
 
736
                        if (source)
 
737
                          {
 
738
                            if (inet_pton(AF_INET6, source+1, &newlist->source_addr.in6.sin6_addr))
 
739
                              newlist->flags |= SERV_HAS_SOURCE;
 
740
                            else
 
741
                              option = '?'; /* error */
 
742
                          }
 
743
                        else
 
744
                          newlist->source_addr.in6.sin6_addr = in6addr_any; 
 
745
                      }
 
746
#endif
 
747
                    else
 
748
                      option = '?'; /* error */
 
749
                    
 
750
                  }
 
751
                
 
752
                if (option == '?')
 
753
                  while (newlist)
 
754
                    { 
 
755
                      serv = newlist;
 
756
                      newlist = newlist->next;
 
757
                      free(serv);
 
758
                    }
 
759
                else
 
760
                  {
 
761
                    serv = newlist;
 
762
                    while (serv->next)
 
763
                      {
 
764
                        serv->next->flags = serv->flags;
 
765
                        serv->next->addr = serv->addr;
 
766
                        serv->next->source_addr = serv->source_addr;
 
767
                        serv = serv->next;
 
768
                      }
 
769
                    serv->next = daemon->servers;
 
770
                    daemon->servers = newlist;
 
771
                  }
 
772
                break;
 
773
              }
 
774
              
 
775
            case 'c':
 
776
              {
 
777
                int size;
 
778
                if (!atoi_check(arg, &size))
 
779
                  option = '?';
 
780
                else
 
781
                  {
 
782
                    /* zero is OK, and means no caching. */
 
783
                    
 
784
                    if (size < 0)
 
785
                      size = 0;
 
786
                    else if (size > 10000)
 
787
                      size = 10000;
 
788
                    
 
789
                    daemon->cachesize = size;
 
790
                  }
 
791
                break;
 
792
              }
 
793
              
 
794
            case 'p':
 
795
              if (!atoi_check(arg, &daemon->port))
 
796
                option = '?';
 
797
              break;
 
798
              
 
799
            case 'P':
 
800
              {
 
801
                int i;
 
802
                if (!atoi_check(arg, &i))
 
803
                  option = '?';
 
804
                daemon->edns_pktsz = (unsigned short)i; 
 
805
                break;
 
806
              }
 
807
 
 
808
            case 'Q':
 
809
              if (!atoi_check(arg, &daemon->query_port))
 
810
                option = '?';
 
811
              break;
 
812
 
 
813
            case 'T':
 
814
              {
 
815
                int ttl;
 
816
                if (!atoi_check(arg, &ttl))
 
817
                  option = '?';
 
818
                else
 
819
                  daemon->local_ttl = (unsigned long)ttl;
 
820
                break;
 
821
              }
 
822
 
 
823
            case 'X':
 
824
              if (!atoi_check(arg, &daemon->dhcp_max))
 
825
                option = '?';
 
826
              break;
 
827
 
 
828
            case 'F':
 
829
              {
 
830
                int k, leasepos = 2;
 
831
                char *cp, *a[5] = { NULL, NULL, NULL, NULL, NULL };
 
832
                struct dhcp_context *new = safe_malloc(sizeof(struct dhcp_context));
 
833
                
 
834
                new->next = daemon->dhcp;
 
835
                new->lease_time = DEFLEASE;
 
836
                new->addr_epoch = 0;
 
837
                new->netmask.s_addr = 0;
 
838
                new->broadcast.s_addr = 0;
 
839
                new->router.s_addr = 0;
 
840
                new->netid.net = NULL;
 
841
                new->flags = 0;
 
842
                
 
843
                problem = "bad dhcp-range";
 
844
 
 
845
                for (cp = arg; *cp; cp++)
 
846
                  if (!(*cp == ' ' || *cp == '.' ||  (*cp >='0' && *cp <= '9')))
 
847
                    break;
 
848
 
 
849
                if (*cp != '\001' && (comma = strchr(arg, '\001')))
 
850
                  {
 
851
                    *comma = 0;
 
852
                    if (strstr(arg, "net:") == arg)
 
853
                      {
 
854
                        new->netid.net = safe_string_alloc(arg+4);
 
855
                        new->netid.next = NULL;
 
856
                        new->flags |= CONTEXT_FILTER;
 
857
                      }
 
858
                    else
 
859
                      new->netid.net = safe_string_alloc(arg);
 
860
                    a[0] = comma + 1;
 
861
                  }
 
862
                else
 
863
                  a[0] = arg;
 
864
 
 
865
                
 
866
                for (k = 1; k < 5; k++)
 
867
                  {
 
868
                    if (!(a[k] = strchr(a[k-1], '\001')))
 
869
                      break;
 
870
                    *(a[k]++) = 0;
 
871
                  }
 
872
                  
 
873
                if ((k < 2) || ((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1))
 
874
                  option = '?';
 
875
                else if (strcmp(a[1], "static") == 0)
 
876
                  {
 
877
                    new->end = new->start;
 
878
                    new->flags |= CONTEXT_STATIC;
 
879
                  }
 
880
                else if ((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1)
 
881
                  option = '?';
 
882
                  
 
883
                if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
 
884
                  {
 
885
                    struct in_addr tmp = new->start;
 
886
                    new->start = new->end;
 
887
                    new->end = tmp;
 
888
                  }
 
889
                    
 
890
                if (option != '?' && k >= 3 && strchr(a[2], '.') &&  
 
891
                    ((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1))
 
892
                  {
 
893
                    new->flags |= CONTEXT_NETMASK;
 
894
                    leasepos = 3;
 
895
                    if (!is_same_net(new->start, new->end, new->netmask))
 
896
                      {
 
897
                        problem = "inconsistent DHCP range";
 
898
                        option = '?';
 
899
                      }
 
900
                  }
 
901
 
 
902
                if (option == '?')
 
903
                  {
 
904
                    free(new);
 
905
                    break;
 
906
                  }
 
907
                else
 
908
                  daemon->dhcp = new;
 
909
 
 
910
                if (k >= 4 && strchr(a[3], '.') &&  
 
911
                    ((new->broadcast.s_addr = inet_addr(a[3])) != (in_addr_t)-1))
 
912
                  {
 
913
                    new->flags |= CONTEXT_BRDCAST;
 
914
                    leasepos = 4;
 
915
                  }
 
916
 
 
917
                if (k >= leasepos+1)
 
918
                  {
 
919
                    if (strcmp(a[leasepos], "infinite") == 0)
 
920
                      new->lease_time = 0xffffffff;
 
921
                    else
 
922
                      {
 
923
                        int fac = 1;
 
924
                        if (strlen(a[leasepos]) > 0)
 
925
                          {
 
926
                            switch (a[leasepos][strlen(a[leasepos]) - 1])
 
927
                              {
 
928
                              case 'h':
 
929
                              case 'H':
 
930
                                fac *= 60;
 
931
                                /* fall through */
 
932
                              case 'm':
 
933
                              case 'M':
 
934
                                fac *= 60;
 
935
                                /* fall through */
 
936
                              case 's':
 
937
                              case 'S':
 
938
                                a[leasepos][strlen(a[leasepos]) - 1] = 0;
 
939
                              }
 
940
                            
 
941
                            new->lease_time = atoi(a[leasepos]) * fac;
 
942
                            /* Leases of a minute or less confuse
 
943
                               some clients, notably Apple's */
 
944
                            if (new->lease_time < 120)
 
945
                              new->lease_time = 120;
 
946
                          }
 
947
                      }
 
948
                  }
 
949
                                
 
950
                if (new->lease_time < daemon->min_leasetime)
 
951
                  daemon->min_leasetime = new->lease_time;
 
952
                break;
 
953
              }
 
954
 
 
955
            case 'G':
 
956
              {
 
957
                int j, k;
 
958
                char *a[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
 
959
                struct dhcp_config *new = safe_malloc(sizeof(struct dhcp_config));
 
960
                struct in_addr in;
 
961
 
 
962
                new->next = daemon->dhcp_conf;
 
963
                new->flags = 0;           
 
964
                
 
965
                
 
966
                a[0] = arg;
 
967
                for (k = 1; k < 6; k++)
 
968
                  {
 
969
                    if (!(a[k] = strchr(a[k-1], '\001')))
 
970
                      break;
 
971
                    *(a[k]++) = 0;
 
972
                  }
 
973
                   
 
974
                for(j = 0; j < k; j++)
 
975
                  if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
 
976
                    {
 
977
                      char *arg = a[j];
 
978
                      
 
979
                      if ((arg[0] == 'i' || arg[0] == 'I') &&
 
980
                          (arg[1] == 'd' || arg[1] == 'D') &&
 
981
                          arg[2] == ':')
 
982
                        {
 
983
                          if (arg[3] == '*')
 
984
                            new->flags |= CONFIG_NOCLID;
 
985
                          else
 
986
                            {
 
987
                              int len;
 
988
                              arg += 3; /* dump id: */
 
989
                              if (strchr(arg, ':'))
 
990
                                len = parse_hex(arg, arg, -1, NULL);
 
991
                              else
 
992
                                len = (int) strlen(arg);
 
993
                              
 
994
                              new->flags |= CONFIG_CLID;
 
995
                              new->clid_len = len;
 
996
                              new->clid = safe_malloc(len);
 
997
                              memcpy(new->clid, arg, len);
 
998
                            }
 
999
                        }
 
1000
                      else if (strstr(arg, "net:") == arg)
 
1001
                        {
 
1002
                          new->flags |= CONFIG_NETID;
 
1003
                          new->netid.net = safe_string_alloc(arg+4);
 
1004
                        }
 
1005
                      else if (parse_hex(a[j],  new->hwaddr, 6, &new->wildcard_mask) == 6)
 
1006
                          new->flags |= CONFIG_HWADDR;
 
1007
                      else
 
1008
                        option = '?';
 
1009
                    }
 
1010
                  else if (strchr(a[j], '.') && (in.s_addr = inet_addr(a[j])) != (in_addr_t)-1)
 
1011
                    {
 
1012
                      new->addr = in;
 
1013
                      new->flags |= CONFIG_ADDR;
 
1014
                    }
 
1015
                  else
 
1016
                    {
 
1017
                      char *cp, *lastp = NULL, last = 0;
 
1018
                      int fac = 1;
 
1019
                      
 
1020
                      if (strlen(a[j]) > 1)
 
1021
                        {
 
1022
                          lastp = a[j] + strlen(a[j]) - 1;
 
1023
                          last = *lastp;
 
1024
                          switch (last)
 
1025
                            {
 
1026
                            case 'h':
 
1027
                            case 'H':
 
1028
                              fac *= 60;
 
1029
                              /* fall through */
 
1030
                            case 'm':
 
1031
                            case 'M':
 
1032
                              fac *= 60;
 
1033
                              /* fall through */
 
1034
                            case 's':
 
1035
                            case 'S':
 
1036
                              *lastp = 0;
 
1037
                            }
 
1038
                        }
 
1039
                      
 
1040
                      for (cp = a[j]; *cp; cp++)
 
1041
                        if (!isdigit(*cp) && *cp != ' ')
 
1042
                          break;
 
1043
                      
 
1044
                      if (*cp)
 
1045
                        {
 
1046
                          if (lastp)
 
1047
                            *lastp = last;
 
1048
                          if (strcmp(a[j], "infinite") == 0)
 
1049
                            {
 
1050
                              new->lease_time = 0xffffffff;
 
1051
                              new->flags |= CONFIG_TIME;
 
1052
                            }
 
1053
                          else if (strcmp(a[j], "ignore") == 0)
 
1054
                            new->flags |= CONFIG_DISABLE;
 
1055
                          else
 
1056
                            {
 
1057
                              new->hostname = safe_string_alloc(a[j]);
 
1058
                              new->flags |= CONFIG_NAME;
 
1059
                            }
 
1060
                        }
 
1061
                      else
 
1062
                        {
 
1063
                          new->lease_time = atoi(a[j]) * fac; 
 
1064
                          /* Leases of a minute or less confuse
 
1065
                             some clients, notably Apple's */
 
1066
                          if (new->lease_time < 120)
 
1067
                            new->lease_time = 120;
 
1068
                          new->flags |= CONFIG_TIME;
 
1069
                        }
 
1070
                    }
 
1071
 
 
1072
                if (option == '?')
 
1073
                  {
 
1074
                    problem = "bad dhcp-host";
 
1075
                    if (new->flags & CONFIG_NAME)
 
1076
                      free(new->hostname);
 
1077
                    if (new->flags & CONFIG_CLID)
 
1078
                      free(new->clid);
 
1079
                    if (new->flags & CONFIG_NETID)
 
1080
                      free(new->netid.net);
 
1081
                    free(new);
 
1082
                  }
 
1083
                else
 
1084
                  {
 
1085
                    if ((new->flags & CONFIG_TIME) && new->lease_time < daemon->min_leasetime)
 
1086
                      daemon->min_leasetime = new->lease_time;
 
1087
                    daemon->dhcp_conf = new;
 
1088
                  }
 
1089
                break;
 
1090
              }
 
1091
              
 
1092
            case 'O':
 
1093
              {
 
1094
                struct dhcp_opt *new = safe_malloc(sizeof(struct dhcp_opt));
 
1095
                char lenchar = 0, *cp;
 
1096
                int addrs, digs, is_addr, is_hex, is_dec;
 
1097
                
 
1098
                new->len = 0;
 
1099
                new->is_addr = 0;
 
1100
                new->netid = NULL;
 
1101
                new->val = NULL;
 
1102
                new->vendor_class = NULL;
 
1103
                                
 
1104
                if ((comma = strchr(arg, '\001')))
 
1105
                  {
 
1106
                    struct dhcp_netid *np = NULL;
 
1107
                    *comma++ = 0;
 
1108
                
 
1109
                    do {
 
1110
                      for (cp = arg; *cp; cp++)
 
1111
                        if (!(*cp == ' ' || (*cp >='0' && *cp <= '9')))
 
1112
                          break;
 
1113
                      if (!*cp)
 
1114
                        break;
 
1115
                      
 
1116
                      if (strstr(arg, "vendor:") == arg)
 
1117
                        new->vendor_class = safe_string_alloc(arg+7);
 
1118
                      else
 
1119
                        {
 
1120
                          new->netid = safe_malloc(sizeof (struct dhcp_netid));
 
1121
                          new->netid->net = safe_string_alloc(arg);
 
1122
                          new->netid->next = np;
 
1123
                          np = new->netid;
 
1124
                        }
 
1125
                      arg = comma;
 
1126
                      if ((comma = strchr(arg, '\001')))
 
1127
                        *comma++ = 0;
 
1128
                    } while (arg);
 
1129
                  }
 
1130
                
 
1131
                if (!arg || (new->opt = atoi(arg)) == 0)
 
1132
                  {
 
1133
                    option = '?';
 
1134
                    problem = "bad dhcp-option";
 
1135
                  }
 
1136
                else if (comma && new->opt == 119 && !new->vendor_class)
 
1137
                  {
 
1138
                    /* dns search, RFC 3397 */
 
1139
                    unsigned char *q, *r, *tail;
 
1140
                    unsigned char *p = NULL;
 
1141
                    size_t newlen, len = 0;
 
1142
                    
 
1143
                    arg = comma;
 
1144
                    if ((comma = strchr(arg, '\001')))
 
1145
                      *(comma++) = 0;
 
1146
 
 
1147
                    while (arg && *arg)
 
1148
                      {
 
1149
                        if (!canonicalise(arg))
 
1150
                          {
 
1151
                            option = '?';
 
1152
                            problem = "bad domain in dhcp-option";
 
1153
                            break;
 
1154
                          }
 
1155
                        
 
1156
                        if (!(p = realloc(p, len + strlen(arg) + 2)))
 
1157
                          die("could not get memory", NULL);
 
1158
                        q = p + len;
 
1159
                        
 
1160
                        /* add string on the end in RFC1035 format */
 
1161
                        while (*arg) 
 
1162
                          {
 
1163
                            char *cp = q++;
 
1164
                            int j;
 
1165
                            for (j = 0; *arg && (*arg != '.'); arg++, j++)
 
1166
                              *q++ = *arg;
 
1167
                            *cp = j;
 
1168
                            if (*arg)
 
1169
                              arg++;
 
1170
                          }
 
1171
                        *q++ = 0;
 
1172
                        
 
1173
                        /* Now tail-compress using earlier names. */
 
1174
                        newlen = q - p;
 
1175
                        for (tail = p + len; *tail; tail += (*tail) + 1)
 
1176
                          for (r = p; r - p < (int)len; r += (*r) + 1)
 
1177
                            if (strcmp(r, tail) == 0)
 
1178
                              {
 
1179
                                PUTSHORT((r - p) | 0xc000, tail); 
 
1180
                                newlen = tail - p;
 
1181
                                goto end;
 
1182
                              }
 
1183
                      end:
 
1184
                        len = newlen;
 
1185
                    
 
1186
                        arg = comma;
 
1187
                        if (arg && (comma = strchr(arg, '\001')))
 
1188
                          *(comma++) = 0;
 
1189
                      }
 
1190
 
 
1191
                    new->len = (int) len;
 
1192
                    new->val = p;
 
1193
                  }
 
1194
                else if (comma)
 
1195
                  {
 
1196
                    /* not option 119 */
 
1197
                    /* characterise the value */
 
1198
                    is_addr = is_hex = is_dec = 1;
 
1199
                    addrs = digs = 1;
 
1200
                    for (cp = comma; *cp; cp++)
 
1201
                      if (*cp == '\001')
 
1202
                        {
 
1203
                          addrs++;
 
1204
                          is_dec = is_hex = 0;
 
1205
                        }
 
1206
                      else if (*cp == ':')
 
1207
                        {
 
1208
                          digs++;
 
1209
                          is_dec = is_addr = 0;
 
1210
                        }
 
1211
                      else if (*cp == '.')
 
1212
                        is_dec = is_hex = 0;
 
1213
                      else if (!((*cp >='0' && *cp <= '9') || *cp == '-'))
 
1214
                        {
 
1215
                          is_addr = 0;
 
1216
                          if (cp[1] == 0 && is_dec &&
 
1217
                              (*cp == 'b' || *cp == 's' || *cp == 'i'))
 
1218
                            {
 
1219
                              lenchar = *cp;
 
1220
                              *cp = 0;
 
1221
                            }
 
1222
                          else
 
1223
                            is_dec = 0;
 
1224
                          if (!((*cp >='A' && *cp <= 'F') ||
 
1225
                                (*cp >='a' && *cp <= 'f')))
 
1226
                            is_hex = 0;
 
1227
                        }
 
1228
                
 
1229
                    if (is_hex && digs > 1)
 
1230
                      {
 
1231
                        new->len = digs;
 
1232
                        new->val = safe_malloc(new->len);
 
1233
                        parse_hex(comma, new->val, digs, NULL);
 
1234
                      }
 
1235
                    else if (is_dec)
 
1236
                      {
 
1237
                        int i, val = atoi(comma);
 
1238
                        /* assume numeric arg is 1 byte except for
 
1239
                           options where it is known otherwise.
 
1240
                           For vendor class option, we have to hack. */
 
1241
                        new->len = 1;
 
1242
                        if (lenchar == 'b')
 
1243
                          new->len = 1;
 
1244
                        else if (lenchar == 's')
 
1245
                          new->len = 2;
 
1246
                        else if (lenchar == 'i')
 
1247
                          new->len = 4;
 
1248
                        else if (new->vendor_class)
 
1249
                          {
 
1250
                            if (val & 0xffff0000)
 
1251
                              new->len = 4;
 
1252
                            else if (val & 0xff00)
 
1253
                              new->len = 2;
 
1254
                          } 
 
1255
                        else
 
1256
                          switch (new->opt)
 
1257
                            {
 
1258
                            case 13: case 22: case 25: case 26: 
 
1259
                              new->len = 2;
 
1260
                              break;
 
1261
                            case 2: case 24: case 35: case 38: 
 
1262
                              new->len = 4;
 
1263
                              break;
 
1264
                            }
 
1265
                        new->val = safe_malloc(new->len);
 
1266
                        for (i=0; i<new->len; i++)
 
1267
                          new->val[i] = val>>((new->len - i - 1)*8);
 
1268
                      }
 
1269
                    else if (is_addr)   
 
1270
                      {
 
1271
                        struct in_addr in;
 
1272
                        unsigned char *op;
 
1273
                        new->len = INADDRSZ * addrs;
 
1274
                        new->val = op = safe_malloc(new->len);
 
1275
                        new->is_addr = 1;
 
1276
                        while (addrs--) 
 
1277
                          {
 
1278
                            cp = comma;
 
1279
                            if ((comma = strchr(cp, '\001')))
 
1280
                              *comma++ = 0;
 
1281
                            in.s_addr = inet_addr(cp);
 
1282
                            memcpy(op, &in, INADDRSZ);
 
1283
                            op += INADDRSZ;
 
1284
                          }
 
1285
                      }
 
1286
                    else
 
1287
                      {
 
1288
                        /* text arg */
 
1289
                        new->len = strlen(comma);
 
1290
                        /* keep terminating zero on string */
 
1291
                        new->val = safe_string_alloc(comma);
 
1292
                      }
 
1293
                  }
 
1294
 
 
1295
                if (new->len > 255)
 
1296
                  {
 
1297
                    option = '?';
 
1298
                    problem = "dhcp-option too long";
 
1299
                  }
 
1300
 
 
1301
                if (option == '?')
 
1302
                  {
 
1303
                    if (new->netid)
 
1304
                      free(new->netid);
 
1305
                    if (new->val)
 
1306
                      free(new->val);
 
1307
                    if (new->vendor_class)
 
1308
                      free(new->vendor_class);
 
1309
                    free(new);
 
1310
                  }
 
1311
                else if (new->vendor_class)
 
1312
                  {
 
1313
                    new->next = daemon->vendor_opts;
 
1314
                    daemon->vendor_opts = new;
 
1315
                  }
 
1316
                else
 
1317
                  {
 
1318
                    new->next = daemon->dhcp_opts;
 
1319
                    daemon->dhcp_opts = new;
 
1320
                  }
 
1321
                break;
 
1322
              }
 
1323
 
 
1324
            case 'M':
 
1325
              {
 
1326
                struct dhcp_netid *id = NULL;
 
1327
                while (arg && strstr(arg, "net:") == arg)
 
1328
                  {
 
1329
                    struct dhcp_netid *newid = safe_malloc(sizeof(struct dhcp_netid));
 
1330
                    newid->next = id;
 
1331
                    id = newid;
 
1332
                    if ((comma = strchr(arg, '\001')))
 
1333
                      *comma++ = 0;
 
1334
                    newid->net = safe_string_alloc(arg+4);
 
1335
                    arg = comma;
 
1336
                  };
 
1337
                
 
1338
                if (!arg)
 
1339
                  option = '?';
 
1340
                else 
 
1341
                  {
 
1342
                    char *dhcp_file, *dhcp_sname = NULL;
 
1343
                    struct in_addr dhcp_next_server;
 
1344
                    if ((comma = strchr(arg, '\001')))
 
1345
                      *comma++ = 0;
 
1346
                    dhcp_file = safe_string_alloc(arg);
 
1347
                    dhcp_next_server.s_addr = 0;
 
1348
                    if (comma)
 
1349
                      {
 
1350
                        arg = comma;
 
1351
                        if ((comma = strchr(arg, '\001')))
 
1352
                          *comma++ = 0;
 
1353
                        dhcp_sname = safe_string_alloc(arg);
 
1354
                        if (comma && (dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
 
1355
                          option = '?';
 
1356
                      }
 
1357
                    if (option != '?')
 
1358
                      {
 
1359
                        struct dhcp_boot *new = safe_malloc(sizeof(struct dhcp_boot));
 
1360
                        new->file = dhcp_file;
 
1361
                        new->sname = dhcp_sname;
 
1362
                        new->next_server = dhcp_next_server;
 
1363
                        new->netid = id;
 
1364
                        new->next = daemon->boot_config;
 
1365
                        daemon->boot_config = new;
 
1366
                      }
 
1367
                  }
 
1368
 
 
1369
                if (option == '?')
 
1370
                  {
 
1371
                    struct dhcp_netid *tmp;
 
1372
                    for (; id; id = tmp)
 
1373
                      {
 
1374
                        tmp = id->next;
 
1375
                        free(id);
 
1376
                      }
 
1377
                  }
 
1378
                break;
 
1379
              }
 
1380
 
 
1381
            case 'U':
 
1382
            case 'j':
 
1383
              {
 
1384
                if (!(comma = strchr(arg, '\001')))
 
1385
                  option = '?';
 
1386
                else
 
1387
                  {
 
1388
                    struct dhcp_vendor *new = safe_malloc(sizeof(struct dhcp_vendor));
 
1389
                    *comma = 0;
 
1390
                    new->netid.net = safe_string_alloc(arg);
 
1391
                    new->len = strlen(comma+1);
 
1392
                    new->data = safe_malloc(new->len);
 
1393
                    memcpy(new->data, comma+1, new->len);
 
1394
                    new->is_vendor = (option == 'U');
 
1395
                    new->next = daemon->dhcp_vendors;
 
1396
                    daemon->dhcp_vendors = new;
 
1397
                  }
 
1398
                break;
 
1399
              }
 
1400
              
 
1401
            case 'J':
 
1402
              {
 
1403
                struct dhcp_netid_list *new = safe_malloc(sizeof(struct dhcp_netid_list));
 
1404
                struct dhcp_netid *list = NULL;
 
1405
                new->next = daemon->dhcp_ignore;
 
1406
                daemon->dhcp_ignore = new;
 
1407
                do {
 
1408
                  struct dhcp_netid *member = safe_malloc(sizeof(struct dhcp_netid));
 
1409
                  if ((comma = strchr(arg, '\001')))
 
1410
                    *comma++ = 0;
 
1411
                  member->next = list;
 
1412
                  list = member;
 
1413
                  member->net = safe_string_alloc(arg);
 
1414
                  arg = comma;
 
1415
                } while (arg);
 
1416
                
 
1417
                new->list = list;
 
1418
                break;
 
1419
              }
 
1420
 
 
1421
            case 'V':
 
1422
              {
 
1423
                char *a[3] = { NULL, NULL, NULL };
 
1424
                int k;
 
1425
                struct in_addr in, out, mask;
 
1426
                struct doctor *new;
 
1427
 
 
1428
                mask.s_addr = 0xffffffff;
 
1429
                
 
1430
                a[0] = arg;
 
1431
                for (k = 1; k < 4; k++)
 
1432
                  {
 
1433
                    if (!(a[k] = strchr(a[k-1], '\001')))
 
1434
                      break;
 
1435
                    *(a[k]++) = 0;
 
1436
                  }
 
1437
 
 
1438
                if ((k < 2) ||
 
1439
                    ((in.s_addr = inet_addr(a[0])) == (in_addr_t)-1) ||
 
1440
                    ((out.s_addr = inet_addr(a[1])) == (in_addr_t)-1))
 
1441
                  {
 
1442
                    option = '?';
 
1443
                    break;
 
1444
                  }
 
1445
 
 
1446
                if (k == 3)
 
1447
                  mask.s_addr = inet_addr(a[2]);
 
1448
 
 
1449
                new = safe_malloc(sizeof(struct doctor));
 
1450
                new->in = in;
 
1451
                new->out = out;
 
1452
                new->mask = mask;
 
1453
                new->next = daemon->doctors;
 
1454
                daemon->doctors = new;
 
1455
                
 
1456
                break;
 
1457
              }
 
1458
 
 
1459
            case 'Y':
 
1460
              {
 
1461
                struct txt_record *new;
 
1462
                unsigned char *p, *q;
 
1463
 
 
1464
                if ((comma = strchr(arg, '\001')))
 
1465
                  *(comma) = 0;
 
1466
 
 
1467
                if (!canonicalise(arg))
 
1468
                  {
 
1469
                    option = '?';
 
1470
                    problem = "bad TXT record";
 
1471
                    break;
 
1472
                  }
 
1473
                                  
 
1474
                if ((q = comma))
 
1475
                  while (1)
 
1476
                    {
 
1477
                      size_t len;
 
1478
                      if ((p = strchr(q+1, '\001')))
 
1479
                        {
 
1480
                          if ((len = p - q - 1) > 255)
 
1481
                            { 
 
1482
                              option = '?';
 
1483
                              break;
 
1484
                            }
 
1485
                          *q = len;
 
1486
                          q = p;
 
1487
                        }
 
1488
                      else
 
1489
                        {
 
1490
                          if ((len = strlen(q+1)) > 255)
 
1491
                            option = '?';
 
1492
                          *q = len;
 
1493
                          break;
 
1494
                        }
 
1495
                    }
 
1496
                
 
1497
                if (option == '?')
 
1498
                  {
 
1499
                    problem = "TXT record string too long";
 
1500
                    break;
 
1501
                  }
 
1502
 
 
1503
                new = safe_malloc(sizeof(struct txt_record));
 
1504
                new->next = daemon->txt;
 
1505
                daemon->txt = new;
 
1506
                new->class = C_IN;
 
1507
                if (comma)
 
1508
                  {
 
1509
                    new->len = q - ((unsigned char *)comma) + *q + 1;
 
1510
                    new->txt = safe_malloc(new->len);
 
1511
                    memcpy(new->txt, comma, new->len);
 
1512
                  }
 
1513
                else
 
1514
                  {
 
1515
                    static char empty[] = "";
 
1516
                    new->len = 1;
 
1517
                    new->txt = empty;
 
1518
                  }
 
1519
                
 
1520
                if (comma)
 
1521
                  *comma = 0;
 
1522
                new->name = safe_string_alloc(arg);
 
1523
                break;
 
1524
              }
 
1525
 
 
1526
            case 'W':
 
1527
              {
 
1528
                int port = 1, priority = 0, weight = 0;
 
1529
                char *name, *target = NULL;
 
1530
                struct mx_srv_record *new;
 
1531
                
 
1532
                if ((comma = strchr(arg, '\001')))
 
1533
                  *(comma++) = 0;
 
1534
 
 
1535
                if (!canonicalise(arg))
 
1536
                  {
 
1537
                    option = '?';
 
1538
                    problem = "bad SRV record";
 
1539
                    break;
 
1540
                  }
 
1541
                name = safe_string_alloc(arg);
 
1542
                
 
1543
                if (comma)
 
1544
                  {
 
1545
                    arg = comma;
 
1546
                    if ((comma = strchr(arg, '\001')))
 
1547
                      *(comma++) = 0;
 
1548
                    if (!canonicalise(arg))
 
1549
                      {
 
1550
                        option = '?';
 
1551
                        problem = "bad SRV target";
 
1552
                        break;
 
1553
                      }
 
1554
                    target = safe_string_alloc(arg);
 
1555
                    if (comma)
 
1556
                      {
 
1557
                        arg = comma;
 
1558
                        if ((comma = strchr(arg, '\001')))
 
1559
                          *(comma++) = 0;
 
1560
                        if (!atoi_check(arg, &port))
 
1561
                          {
 
1562
                            option = '?';
 
1563
                            problem = "invalid port number";
 
1564
                            break;
 
1565
                          }
 
1566
                        if (comma)
 
1567
                          {
 
1568
                            arg = comma;
 
1569
                            if ((comma = strchr(arg, '\001')))
 
1570
                              *(comma++) = 0;
 
1571
                            if (!atoi_check(arg, &priority))
 
1572
                              {
 
1573
                                option = '?';
 
1574
                                problem = "invalid priority";
 
1575
                                break;
 
1576
                              }
 
1577
                            if (comma)
 
1578
                              {
 
1579
                                arg = comma;
 
1580
                                if ((comma = strchr(arg, '\001')))
 
1581
                                  *(comma++) = 0;
 
1582
                                if (!atoi_check(arg, &weight))
 
1583
                                  {
 
1584
                                    option = '?';
 
1585
                                    problem = "invalid weight";
 
1586
                                    break;
 
1587
                                  }
 
1588
                              }
 
1589
                          }
 
1590
                      }
 
1591
                  }
 
1592
                
 
1593
                new = safe_malloc(sizeof(struct mx_srv_record));
 
1594
                new->next = daemon->mxnames;
 
1595
                daemon->mxnames = new;
 
1596
                new->issrv = 1;
 
1597
                new->name = name;
 
1598
                new->target = target;
 
1599
                new->srvport = port;
 
1600
                new->priority = priority;
 
1601
                new->weight = weight;
 
1602
                break;
 
1603
              }
 
1604
            }
 
1605
        }
 
1606
      
 
1607
      if (option == '?')
 
1608
        {
 
1609
          if (f)
 
1610
            complain( problem ? problem : "error", lineno, conffile);
 
1611
          else
 
1612
#ifdef HAVE_GETOPT_LONG
 
1613
            die("bad command line options: %s.", problem ? problem : "try --help");
 
1614
#else
 
1615
            die("bad command line options: %s.", problem ? problem : "try -w");
 
1616
#endif
 
1617
        }
 
1618
    }
 
1619
      
 
1620
  /* port might no be known when the address is parsed - fill in here */
 
1621
  if (daemon->servers)
 
1622
    {
 
1623
      struct server *tmp;
 
1624
      for (tmp = daemon->servers; tmp; tmp = tmp->next)
 
1625
        if (!(tmp->flags & SERV_HAS_SOURCE))
 
1626
          {
 
1627
            if (tmp->source_addr.sa.sa_family == AF_INET)
 
1628
              tmp->source_addr.in.sin_port = htons(daemon->query_port);
 
1629
#ifdef HAVE_IPV6
 
1630
            else if (tmp->source_addr.sa.sa_family == AF_INET6)
 
1631
              tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
 
1632
#endif  
 
1633
          }
 
1634
    }
 
1635
  
 
1636
  if (daemon->if_addrs)
 
1637
    {  
 
1638
      struct iname *tmp;
 
1639
      for(tmp = daemon->if_addrs; tmp; tmp = tmp->next)
 
1640
        if (tmp->addr.sa.sa_family == AF_INET)
 
1641
          tmp->addr.in.sin_port = htons(daemon->port);
 
1642
#ifdef HAVE_IPV6
 
1643
        else if (tmp->addr.sa.sa_family == AF_INET6)
 
1644
          tmp->addr.in6.sin6_port = htons(daemon->port);
 
1645
#endif /* IPv6 */
 
1646
    }
 
1647
                      
 
1648
  /* only one of these need be specified: the other defaults to the host-name */
 
1649
  if ((daemon->options & OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
 
1650
    {
 
1651
      struct mx_srv_record *mx;
 
1652
      
 
1653
      if (gethostname(buff, MAXDNAME) == -1)
 
1654
        die("cannot get host-name: %s", NULL);
 
1655
      
 
1656
      for (mx = daemon->mxnames; mx; mx = mx->next)
 
1657
        if (!mx->issrv && hostname_isequal(mx->name, buff))
 
1658
          break;
 
1659
      
 
1660
      if ((daemon->mxtarget || (daemon->options & OPT_LOCALMX)) && !mx)
 
1661
        {
 
1662
          mx = safe_malloc(sizeof(struct mx_srv_record));
 
1663
          mx->next = daemon->mxnames;
 
1664
          mx->issrv = 0;
 
1665
          mx->target = NULL;
 
1666
          mx->name = safe_string_alloc(buff);
 
1667
          daemon->mxnames = mx;
 
1668
        }
 
1669
      
 
1670
      if (!daemon->mxtarget)
 
1671
        daemon->mxtarget = safe_string_alloc(buff);
 
1672
 
 
1673
      for (mx = daemon->mxnames; mx; mx = mx->next)
 
1674
        if (!mx->issrv && !mx->target)
 
1675
          mx->target = daemon->mxtarget;
 
1676
    }
 
1677
 
 
1678
  if (daemon->domain_suffix)
 
1679
    {
 
1680
       /* add domain for any srv record without one. */
 
1681
      struct mx_srv_record *srv;
 
1682
      
 
1683
      for (srv = daemon->mxnames; srv; srv = srv->next)
 
1684
        if (srv->issrv &&
 
1685
            strchr(srv->name, '.') && 
 
1686
            strchr(srv->name, '.') == strrchr(srv->name, '.'))
 
1687
          {
 
1688
            strcpy(buff, srv->name);
 
1689
            strcat(buff, ".");
 
1690
            strcat(buff, daemon->domain_suffix);
 
1691
            free(srv->name);
 
1692
            srv->name = safe_string_alloc(buff);
 
1693
          }
 
1694
    }
 
1695
  
 
1696
  if (daemon->options & OPT_NO_RESOLV)
 
1697
    daemon->resolv_files = 0;
 
1698
  else if (daemon->resolv_files && (daemon->resolv_files)->next && (daemon->options & OPT_NO_POLL))
 
1699
    die("only one resolv.conf file allowed in no-poll mode.", NULL);
 
1700
  
 
1701
  if (daemon->options & OPT_RESOLV_DOMAIN)
 
1702
    {
 
1703
      char *line;
 
1704
      
 
1705
      if (!daemon->resolv_files || (daemon->resolv_files)->next)
 
1706
        die("must have exactly one resolv.conf to read domain from.", NULL);
 
1707
      
 
1708
      if (!(f = fopen((daemon->resolv_files)->name, "r")))
 
1709
        die("failed to read %s: %m", (daemon->resolv_files)->name);
 
1710
      
 
1711
      while ((line = fgets(buff, MAXDNAME, f)))
 
1712
        {
 
1713
          char *token = strtok(line, " \t\n\r");
 
1714
          
 
1715
          if (!token || strcmp(token, "search") != 0)
 
1716
            continue;
 
1717
          
 
1718
          if ((token = strtok(NULL, " \t\n\r")) &&  
 
1719
              canonicalise(token) &&
 
1720
              (daemon->domain_suffix = safe_string_alloc(token)))
 
1721
            break;
 
1722
        }
 
1723
 
 
1724
      fclose(f);
 
1725
 
 
1726
      if (!daemon->domain_suffix)
 
1727
        die("no search directive found in %s", (daemon->resolv_files)->name);
 
1728
    }
 
1729
      
 
1730
  return daemon;
 
1731
}
 
1732
      
 
1733
      
 
1734