import of dnsmasq-2.40.tar.gz

This commit is contained in:
Simon Kelley
2007-08-29 11:24:47 +01:00
parent f2621c7ff0
commit 5aabfc78bc
38 changed files with 6006 additions and 4068 deletions

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000 - 2006 Simon Kelley
/* dnsmasq is Copyright (c) 2000 - 2007 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -43,6 +43,9 @@ struct myoption {
#define LOPT_REMOTE 269
#define LOPT_SUBSCR 270
#define LOPT_INTNAME 271
#define LOPT_BANK 272
#define LOPT_DHCP_HOST 273
#define LOPT_APREF 274
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -119,6 +122,7 @@ static const struct myoption opts[] =
{"dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
{"enable-tftp", 0, 0, LOPT_TFTP },
{"tftp-secure", 0, 0, LOPT_SECURE },
{"tftp-unique-root", 0, 0, LOPT_APREF },
{"tftp-root", 1, 0, LOPT_PREFIX },
{"tftp-max", 1, 0, LOPT_TFTP_MAX },
{"ptr-record", 1, 0, LOPT_PTR },
@@ -133,6 +137,7 @@ static const struct myoption opts[] =
{"dhcp-remoteid", 1, 0, LOPT_REMOTE },
{"dhcp-subscrid", 1, 0, LOPT_SUBSCR },
{"interface-name", 1, 0, LOPT_INTNAME },
{"dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
{ NULL, 0, 0, 0 }
};
@@ -169,6 +174,7 @@ static const struct optflags optmap[] = {
{ LOPT_SECURE, OPT_TFTP_SECURE },
{ LOPT_NOBLOCK, OPT_TFTP_NOBLOCK },
{ LOPT_LOG_OPTS, OPT_LOG_OPTS },
{ LOPT_APREF, OPT_TFTP_APREF },
{ 'v', 0},
{ 'w', 0},
{ 0, 0 }
@@ -192,7 +198,8 @@ static const struct {
{ "-f, --filterwin2k", gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL },
{ "-F, --dhcp-range=ipaddr,ipaddr,time", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
{ "-g, --group=groupname", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
{ "-G, --dhcp-host=<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
{ "-G, --dhcp-host=<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
{ " --dhcp-hostsfile=<filename>", gettext_noop("Read DHCP host specs from file"), NULL },
{ "-h, --no-hosts", gettext_noop("Do NOT load %s file."), HOSTSFILE },
{ "-H, --addn-hosts=path", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
{ "-i, --interface=interface", gettext_noop("Specify interface(s) to listen on."), NULL },
@@ -255,6 +262,7 @@ static const struct {
{ " --dhcp-ignore-names[=<id>]", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
{ " --enable-tftp", gettext_noop("Enable integrated read-only TFTP server."), NULL },
{ " --tftp-root=<directory>", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
{ " --tftp-unique-root", gettext_noop("Add client IP address to tftp-root."), NULL },
{ " --tftp-secure", gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
{ " --tftp-max=<connections>", gettext_noop("Maximum number of conncurrent TFTP transfers (defaults to %s)."), "#" },
{ " --tftp-no-blocksize", gettext_noop("Disable the TFTP blocksize extension."), NULL },
@@ -367,8 +375,6 @@ char *option_string(unsigned char opt)
static const char meta[] = "\000123456 \b\t\n78\r90abcdefABCDE\033F:,.";
static void one_file(struct daemon *daemon, char *file, int nest);
static char hide_meta(char c)
{
unsigned int i;
@@ -460,7 +466,7 @@ static int atoi_check(char *a, int *res)
return 1;
}
static void add_txt(struct daemon *daemon, char *name, char *txt)
static void add_txt(char *name, char *txt)
{
size_t len = strlen(txt);
struct txt_record *r = safe_malloc(sizeof(struct txt_record));
@@ -525,7 +531,7 @@ static void display_opts(void)
}
/* This is too insanely large to keep in-line in the switch */
static char *parse_dhcp_opt(struct daemon *daemon, char *arg, int forced)
static char *parse_dhcp_opt(char *arg, int forced)
{
struct dhcp_opt *new = safe_malloc(sizeof(struct dhcp_opt));
char lenchar = 0, *cp;
@@ -749,7 +755,7 @@ static char *parse_dhcp_opt(struct daemon *daemon, char *arg, int forced)
}
if (!(m = realloc(m, len + strlen(arg) + 2 + header_size)))
die(_("could not get memory"), NULL);
die(_("could not get memory"), NULL, EC_NOMEM);
p = m + header_size;
q = p + len;
@@ -809,7 +815,7 @@ static char *parse_dhcp_opt(struct daemon *daemon, char *arg, int forced)
}
static char *one_opt(struct daemon *daemon, int option, char *arg, char *problem, int nest)
static char *one_opt(int option, char *arg, char *problem, int nest)
{
int i;
char *comma;
@@ -830,7 +836,7 @@ static char *one_opt(struct daemon *daemon, int option, char *arg, char *problem
{
char *file = safe_string_alloc(arg);
if (file)
one_file(daemon, file, nest);
one_file(file, nest, 0);
break;
}
@@ -844,7 +850,7 @@ static char *one_opt(struct daemon *daemon, int option, char *arg, char *problem
break;
if (!(dir_stream = opendir(directory)))
die(_("cannot access directory %s: %s"), directory);
die(_("cannot access directory %s: %s"), directory, EC_FILE);
while ((ent = readdir(dir_stream)))
{
@@ -863,13 +869,13 @@ static char *one_opt(struct daemon *daemon, int option, char *arg, char *problem
strcat(path, "/");
strcat(path, ent->d_name);
if (stat(path, &buf) == -1)
die(_("cannot access %s: %s"), path);
die(_("cannot access %s: %s"), path, EC_FILE);
/* only reg files allowed. */
if (!S_ISREG(buf.st_mode))
continue;
/* dir is one level, so files must be readable */
one_file(daemon, path, nest + 1);
one_file(path, nest + 1, 0);
free(path);
}
@@ -900,6 +906,15 @@ static char *one_opt(struct daemon *daemon, int option, char *arg, char *problem
case 'x': /* --pid-file */
daemon->runfile = safe_string_alloc(arg);
break;
case LOPT_DHCP_HOST: /* --dhcp-hostfile */
if (daemon->dhcp_hosts_file)
{
problem = _("only one dhcp-hostsfile allowed");
option = '?';
}
daemon->dhcp_hosts_file = safe_string_alloc(arg);
break;
case 'r': /* --resolv-file */
{
@@ -1210,7 +1225,7 @@ static char *one_opt(struct daemon *daemon, int option, char *arg, char *problem
}
else
newlist->source_addr.in.sin_addr.s_addr = INADDR_ANY;
}
}
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, arg, &newlist->addr.in6.sin6_addr) > 0)
{
@@ -1494,17 +1509,24 @@ static char *one_opt(struct daemon *daemon, int option, char *arg, char *problem
}
break;
}
/* Note, must not die() via safe_* if option is LOPT_BANK, since
when called with this we are re-loading the file. */
case LOPT_BANK:
case 'G': /* --dhcp-host */
{
int j, k = 0;
char *a[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
struct dhcp_config *new = safe_malloc(sizeof(struct dhcp_config));
struct dhcp_config *new;
struct in_addr in;
if (option != LOPT_BANK)
new = safe_malloc(sizeof(struct dhcp_config));
else if (!(new = whine_malloc(sizeof(struct dhcp_config))))
break;
new->next = daemon->dhcp_conf;
new->flags = 0;
new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
if ((a[0] = arg))
for (k = 1; k < 6; k++)
@@ -1529,18 +1551,28 @@ static char *one_opt(struct daemon *daemon, int option, char *arg, char *problem
if (strchr(arg, ':'))
len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL);
else
len = (int) strlen(arg);
new->flags |= CONFIG_CLID;
new->clid_len = len;
new->clid = safe_malloc(len);
memcpy(new->clid, arg, len);
{
unhide_metas(arg);
len = (int) strlen(arg);
}
if ((new->clid = (option == LOPT_BANK) ? whine_malloc(len): safe_malloc(len)))
{
new->flags |= CONFIG_CLID;
new->clid_len = len;
memcpy(new->clid, arg, len);
}
}
}
else if (strstr(arg, "net:") == arg)
{
new->flags |= CONFIG_NETID;
new->netid.net = safe_string_alloc(arg+4);
int len = strlen(arg + 4) + 1;
if ((new->netid.net = (option == LOPT_BANK) ? whine_malloc(len): safe_malloc(len)))
{
new->flags |= CONFIG_NETID;
strcpy(new->netid.net, arg+4);
unhide_metas(new->netid.net);
}
}
else
{
@@ -1599,8 +1631,17 @@ static char *one_opt(struct daemon *daemon, int option, char *arg, char *problem
new->flags |= CONFIG_DISABLE;
else
{
new->hostname = safe_string_alloc(a[j]);
new->flags |= CONFIG_NAME;
int len = strlen(a[j]) + 1;
if (!canonicalise_opt(a[j]))
{
problem = _("bad DHCP host name");
option = '?';
}
else if ((new->hostname = (option == LOPT_BANK) ? whine_malloc(len): safe_malloc(len)))
{
new->flags |= CONFIG_NAME;
strcpy(new->hostname, a[j]);
}
}
}
else
@@ -1614,17 +1655,13 @@ static char *one_opt(struct daemon *daemon, int option, char *arg, char *problem
}
}
if (option == '?')
problem = _("bad dhcp-host");
else
daemon->dhcp_conf = new;
daemon->dhcp_conf = new;
break;
}
case 'O':
case LOPT_FORCE:
if ((problem = parse_dhcp_opt(daemon, arg, option == LOPT_FORCE)))
if ((problem = parse_dhcp_opt(arg, option == LOPT_FORCE)))
option = '?';
break;
@@ -2007,21 +2044,30 @@ static char *one_opt(struct daemon *daemon, int option, char *arg, char *problem
return option == '?' ? problem : NULL;
}
static void one_file(struct daemon *daemon, char *file, int nest)
void one_file(char *file, int nest, int hosts)
{
int i, option, lineno = 0;
FILE *f;
char *p, *arg, *start, *buff = daemon->namebuff;
if (nest > 20)
die(_("files nested too deep in %s"), file);
die(_("files nested too deep in %s"), file, EC_BADCONF);
if (!(f = fopen(file, "r")))
{
if (errno == ENOENT && nest == 0)
return; /* No conffile, all done. */
else
die(_("cannot read %s: %s"), file);
{
char *str = _("cannot read %s: %s");
if (hosts)
{
my_syslog(LOG_ERR, str, file, strerror(errno));
return;
}
else
die(str, file, EC_FILE);
}
}
while (fgets(buff, MAXDNAME, f))
@@ -2042,7 +2088,7 @@ static void one_file(struct daemon *daemon, char *file, int nest)
memmove(p, p+1, strlen(p+1)+1);
for(; *p && *p != '"'; p++)
{
if (*p == '\\' && strchr("\"tn\033br\\", p[1]))
if (*p == '\\' && strchr("\"tnebr\\", p[1]))
{
if (p[1] == 't')
p[1] = '\t';
@@ -2085,55 +2131,71 @@ static void one_file(struct daemon *daemon, char *file, int nest)
if (*buff == 0)
continue;
if ((p=strchr(buff, '=')))
if (hosts)
arg = buff;
else if ((p=strchr(buff, '=')))
{
/* allow spaces around "=" */
for (arg = p+1; isspace(*arg); arg++);
arg = p+1;
for (; p >= buff && (isspace(*p) || *p == '='); p--)
*p = 0;
}
else
arg = NULL;
/* skip leading space */
for (start = buff; *start && isspace(*start); start++);
for (option = 0, i = 0; opts[i].name; i++)
if (strcmp(opts[i].name, start) == 0)
{
option = opts[i].val;
break;
}
if (!option)
errmess = _("bad option");
else if (opts[i].has_arg == 0 && arg)
errmess = _("extraneous parameter");
else if (opts[i].has_arg == 1 && !arg)
errmess = _("missing parameter");
if (hosts)
option = LOPT_BANK;
else
errmess = one_opt(daemon, option, arg, _("error"), nest + 1);
{
/* skip leading space */
for (start = buff; *start && isspace(*start); start++);
for (option = 0, i = 0; opts[i].name; i++)
if (strcmp(opts[i].name, start) == 0)
{
option = opts[i].val;
break;
}
if (!option)
errmess = _("bad option");
else if (opts[i].has_arg == 0 && arg)
errmess = _("extraneous parameter");
else if (opts[i].has_arg == 1 && !arg)
errmess = _("missing parameter");
}
if (!errmess)
{
if (arg)
for (; isspace(*arg); arg++);
errmess = one_opt(option, arg, _("error"), nest + 1);
}
if (errmess)
{
oops:
sprintf(buff, _("%s at line %d of %%s"), errmess, lineno);
die(buff, file);
if (hosts)
my_syslog(LOG_ERR, buff, file);
else
die(buff, file, EC_BADCONF);
}
}
fclose(f);
}
struct daemon *read_opts(int argc, char **argv, char *compile_opts)
void read_opts(int argc, char **argv, char *compile_opts)
{
struct daemon *daemon = safe_malloc(sizeof(struct daemon));
char *buff = safe_malloc(MAXDNAME);
int option, nest = 0;
char *errmess, *arg, *conffile = CONFFILE;
opterr = 0;
daemon = safe_malloc(sizeof(struct daemon));
memset(daemon, 0, sizeof(struct daemon));
daemon->namebuff = buff;
@@ -2151,9 +2213,9 @@ struct daemon *read_opts(int argc, char **argv, char *compile_opts)
daemon->tftp_max = TFTP_MAX_CONNECTIONS;
daemon->edns_pktsz = EDNS_PKTSZ;
daemon->log_fac = -1;
add_txt(daemon, "version.bind", "dnsmasq-" VERSION );
add_txt(daemon, "authors.bind", "Simon Kelley");
add_txt(daemon, "copyright.bind", COPYRIGHT);
add_txt("version.bind", "dnsmasq-" VERSION );
add_txt("authors.bind", "Simon Kelley");
add_txt("copyright.bind", COPYRIGHT);
while (1)
{
@@ -2202,17 +2264,17 @@ struct daemon *read_opts(int argc, char **argv, char *compile_opts)
else
{
#ifdef HAVE_GETOPT_LONG
errmess = one_opt(daemon, option, arg, _("try --help"), 0);
errmess = one_opt(option, arg, _("try --help"), 0);
#else
errmess = one_opt(daemon, option, arg, _("try -w"), 0);
errmess = one_opt(option, arg, _("try -w"), 0);
#endif
if (errmess)
die(_("bad command line options: %s"), errmess);
die(_("bad command line options: %s"), errmess, EC_BADCONF);
}
}
if (conffile)
one_file(daemon, conffile, nest);
one_file(conffile, nest, 0);
/* port might no be known when the address is parsed - fill in here */
if (daemon->servers)
@@ -2226,8 +2288,8 @@ struct daemon *read_opts(int argc, char **argv, char *compile_opts)
#ifdef HAVE_IPV6
else if (tmp->source_addr.sa.sa_family == AF_INET6)
tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
#endif
}
#endif
}
}
if (daemon->if_addrs)
@@ -2248,7 +2310,7 @@ struct daemon *read_opts(int argc, char **argv, char *compile_opts)
struct mx_srv_record *mx;
if (gethostname(buff, MAXDNAME) == -1)
die(_("cannot get host-name: %s"), NULL);
die(_("cannot get host-name: %s"), NULL, EC_MISC);
for (mx = daemon->mxnames; mx; mx = mx->next)
if (!mx->issrv && hostname_isequal(mx->name, buff))
@@ -2276,7 +2338,7 @@ struct daemon *read_opts(int argc, char **argv, char *compile_opts)
daemon->resolv_files &&
daemon->resolv_files->next &&
(daemon->options & OPT_NO_POLL))
die(_("only one resolv.conf file allowed in no-poll mode."), NULL);
die(_("only one resolv.conf file allowed in no-poll mode."), NULL, EC_BADCONF);
if (daemon->options & OPT_RESOLV_DOMAIN)
{
@@ -2286,10 +2348,10 @@ struct daemon *read_opts(int argc, char **argv, char *compile_opts)
if ((daemon->options & OPT_NO_RESOLV) ||
!daemon->resolv_files ||
(daemon->resolv_files)->next)
die(_("must have exactly one resolv.conf to read domain from."), NULL);
die(_("must have exactly one resolv.conf to read domain from."), NULL, EC_BADCONF);
if (!(f = fopen((daemon->resolv_files)->name, "r")))
die(_("failed to read %s: %s"), (daemon->resolv_files)->name);
die(_("failed to read %s: %s"), (daemon->resolv_files)->name, EC_FILE);
while ((line = fgets(buff, MAXDNAME, f)))
{
@@ -2307,7 +2369,7 @@ struct daemon *read_opts(int argc, char **argv, char *compile_opts)
fclose(f);
if (!daemon->domain_suffix)
die(_("no search directive found in %s"), (daemon->resolv_files)->name);
die(_("no search directive found in %s"), (daemon->resolv_files)->name, EC_MISC);
}
if (daemon->domain_suffix)
@@ -2327,8 +2389,6 @@ struct daemon *read_opts(int argc, char **argv, char *compile_opts)
srv->name = safe_string_alloc(buff);
}
}
return daemon;
}