import of dnsmasq-2.46.tar.gz

This commit is contained in:
Simon Kelley
2008-11-14 20:04:27 +00:00
parent 1ad24ae15c
commit 9009d74652
38 changed files with 4374 additions and 3918 deletions

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 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

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 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
@@ -642,150 +642,224 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
unsigned short flags, int index, int addr_dup)
{
struct crec *lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6));
int i;
int i, nameexists = 0;
struct cname *a;
/* Remove duplicates in hosts files. */
if (lookup && (lookup->flags & F_HOSTS) &&
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
free(cache);
else
if (lookup && (lookup->flags & F_HOSTS))
{
/* Ensure there is only one address -> name mapping (first one trumps)
We do this by steam here, first we see if the address is the same as
the last one we saw, which eliminates most in the case of an ad-block
file with thousands of entries for the same address.
Then we search and bail at the first matching address that came from
a HOSTS file. Since the first host entry gets reverse, we know
then that it must exist without searching exhaustively for it. */
if (addr_dup)
flags &= ~F_REVERSE;
else
for (i=0; i<hash_size; i++)
{
for (lookup = hash_table[i]; lookup; lookup = lookup->hash_next)
if ((lookup->flags & F_HOSTS) &&
(lookup->flags & flags & (F_IPV4 | F_IPV6)) &&
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
{
flags &= ~F_REVERSE;
break;
}
if (lookup)
nameexists = 1;
if (memcmp(&lookup->addr.addr, addr, addrlen) == 0)
{
free(cache);
return;
}
}
/* Ensure there is only one address -> name mapping (first one trumps)
We do this by steam here, first we see if the address is the same as
the last one we saw, which eliminates most in the case of an ad-block
file with thousands of entries for the same address.
Then we search and bail at the first matching address that came from
a HOSTS file. Since the first host entry gets reverse, we know
then that it must exist without searching exhaustively for it. */
if (addr_dup)
flags &= ~F_REVERSE;
else
for (i=0; i<hash_size; i++)
{
for (lookup = hash_table[i]; lookup; lookup = lookup->hash_next)
if ((lookup->flags & F_HOSTS) &&
(lookup->flags & flags & (F_IPV4 | F_IPV6)) &&
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
{
flags &= ~F_REVERSE;
break;
}
}
if (lookup)
break;
}
cache->flags = flags;
cache->uid = index;
memcpy(&cache->addr.addr, addr, addrlen);
cache_hash(cache);
/* don't need to do alias stuff for second and subsequent addresses. */
if (!nameexists)
for (a = daemon->cnames; a; a = a->next)
if (hostname_isequal(cache->name.sname, a->target) &&
(lookup = whine_malloc(sizeof(struct crec) + strlen(a->alias)+1-SMALLDNAME)))
{
lookup->flags = F_FORWARD | F_IMMORTAL | F_HOSTS | F_CNAME;
strcpy(lookup->name.sname, a->alias);
lookup->addr.cname.cache = cache;
lookup->addr.cname.uid = index;
cache_hash(lookup);
}
}
static int eatspace(FILE *f)
{
int c, nl = 0;
while (1)
{
if ((c = getc(f)) == '#')
while (c != '\n' && c != EOF)
c = getc(f);
cache->flags = flags;
cache->uid = index;
memcpy(&cache->addr.addr, addr, addrlen);
cache_hash(cache);
if (c == EOF)
return 1;
if (!isspace(c))
{
ungetc(c, f);
return nl;
}
if (c == '\n')
nl = 1;
}
}
static int gettok(FILE *f, char *token)
{
int c, count = 0;
while (1)
{
if ((c = getc(f)) == EOF)
return (count == 0) ? EOF : 1;
if (isspace(c) || c == '#')
{
ungetc(c, f);
return eatspace(f);
}
if (count < (MAXDNAME - 1))
{
token[count++] = c;
token[count] = 0;
}
}
}
static int read_hostsfile(char *filename, int opts, char *buff, char *domain_suffix, int index, int cache_size)
static int read_hostsfile(char *filename, int index, int cache_size)
{
FILE *f = fopen(filename, "r");
char *line;
char *token = daemon->namebuff, *domain_suffix = NULL;
int addr_count = 0, name_count = cache_size, lineno = 0;
unsigned short flags, saved_flags = 0;
unsigned short flags = 0, saved_flags = 0;
struct all_addr addr, saved_addr;
int atnl, addrlen = 0, addr_dup;
if (!f)
{
my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
return 0;
}
while ((line = fgets(buff, MAXDNAME, f)))
eatspace(f);
while ((atnl = gettok(f, token)) != EOF)
{
char *token = strtok(line, " \t\n\r");
int addrlen, addr_dup = 0;
addr_dup = 0;
lineno++;
if (!token || (*token == '#'))
continue;
#ifdef HAVE_IPV6
if (inet_pton(AF_INET, token, &addr) > 0)
{
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
addrlen = INADDRSZ;
domain_suffix = get_domain(addr.addr.addr4);
}
else if (inet_pton(AF_INET6, token, &addr) > 0)
{
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
addrlen = IN6ADDRSZ;
domain_suffix = daemon->domain_suffix;
}
#else
if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1)
{
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
addrlen = INADDRSZ;
if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1)
{
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
addrlen = INADDRSZ;
domain_suffix = get_domain(addr.addr.addr4);
}
#endif
else
{
my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
while (atnl == 0)
atnl = gettok(f, token);
continue;
}
if (saved_flags == flags && memcmp(&addr, &saved_addr, addrlen) == 0)
addr_dup = 1;
else
{
saved_flags = flags;
saved_addr = addr;
}
addr_count++;
/* rehash every 1000 names. */
if ((name_count - cache_size) > 1000)
{
rehash(name_count);
cache_size = name_count;
}
while (atnl == 0)
{
struct crec *cache;
int fqdn;
if ((atnl = gettok(f, token)) == EOF)
break;
fqdn = !!strchr(token, '.');
if (canonicalise(token))
{
/* If set, add a version of the name with a default domain appended */
if ((daemon->options & OPT_EXPAND) && domain_suffix && !fqdn &&
(cache = whine_malloc(sizeof(struct crec) +
strlen(token)+2+strlen(domain_suffix)-SMALLDNAME)))
{
strcpy(cache->name.sname, token);
strcat(cache->name.sname, ".");
strcat(cache->name.sname, domain_suffix);
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
addr_dup = 1;
name_count++;
}
if ((cache = whine_malloc(sizeof(struct crec) + strlen(token)+1-SMALLDNAME)))
{
strcpy(cache->name.sname, token);
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
name_count++;
}
}
else
my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
}
}
if (saved_flags == flags && memcmp(&addr, &saved_addr, addrlen) == 0)
addr_dup = 1;
else
{
saved_flags = flags;
saved_addr = addr;
}
addr_count++;
/* rehash every 1000 names. */
if ((name_count - cache_size) > 1000)
{
rehash(name_count);
cache_size = name_count;
}
while ((token = strtok(NULL, " \t\n\r")) && (*token != '#'))
{
struct crec *cache;
int fqdn = !!strchr(token, '.');
if (canonicalise(token))
{
/* If set, add a version of the name with a default domain appended */
if ((opts & OPT_EXPAND) && domain_suffix && !fqdn &&
(cache = whine_malloc(sizeof(struct crec) +
strlen(token)+2+strlen(domain_suffix)-SMALLDNAME)))
{
strcpy(cache->name.sname, token);
strcat(cache->name.sname, ".");
strcat(cache->name.sname, domain_suffix);
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
addr_dup = 1;
name_count++;
}
if ((cache = whine_malloc(sizeof(struct crec) + strlen(token)+1-SMALLDNAME)))
{
strcpy(cache->name.sname, token);
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
name_count++;
}
}
else
my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
}
}
fclose(f);
rehash(name_count);
my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
return name_count;
}
void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *addn_hosts)
void cache_reload(struct hostsfile *addn_hosts)
{
struct crec *cache, **up, *tmp;
int i, total_size = daemon->cachesize;
@@ -815,18 +889,18 @@ void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *a
up = &cache->hash_next;
}
if ((opts & OPT_NO_HOSTS) && !addn_hosts)
if ((daemon->options & OPT_NO_HOSTS) && !addn_hosts)
{
if (daemon->cachesize > 0)
my_syslog(LOG_INFO, _("cleared cache"));
return;
}
if (!(opts & OPT_NO_HOSTS))
total_size = read_hostsfile(HOSTSFILE, opts, buff, domain_suffix, 0, total_size);
if (!(daemon->options & OPT_NO_HOSTS))
total_size = read_hostsfile(HOSTSFILE, 0, total_size);
while (addn_hosts)
{
total_size = read_hostsfile(addn_hosts->fname, opts, buff, domain_suffix, addn_hosts->index, total_size);
total_size = read_hostsfile(addn_hosts->fname, addn_hosts->index, total_size);
addn_hosts = addn_hosts->next;
}
}
@@ -851,13 +925,11 @@ void cache_unhash_dhcp(void)
void cache_add_dhcp_entry(char *host_name,
struct in_addr *host_address, time_t ttd)
{
struct crec *crec = NULL;
struct crec *crec = NULL, *aliasc;
unsigned short flags = F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
int in_hosts = 0;
if (!host_name)
return;
struct cname *a;
while ((crec = cache_find_by_name(crec, host_name, 0, F_IPV4 | F_CNAME)))
{
/* check all addresses associated with name */
@@ -911,10 +983,34 @@ void cache_add_dhcp_entry(char *host_name,
crec->ttd = ttd;
crec->addr.addr.addr.addr4 = *host_address;
crec->name.namep = host_name;
crec->uid = uid++;
cache_hash(crec);
for (a = daemon->cnames; a; a = a->next)
if (hostname_isequal(host_name, a->target))
{
if ((aliasc = dhcp_spare))
dhcp_spare = dhcp_spare->next;
else /* need new one */
aliasc = whine_malloc(sizeof(struct crec));
if (aliasc)
{
aliasc->flags = F_FORWARD | F_DHCP | F_CNAME;
if (ttd == 0)
aliasc->flags |= F_IMMORTAL;
else
aliasc->ttd = ttd;
aliasc->name.namep = a->alias;
aliasc->addr.cname.cache = crec;
aliasc->addr.cname.uid = crec->uid;
cache_hash(aliasc);
}
}
}
}
void dump_cache(time_t now)
{
struct server *serv, *serv1;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 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
@@ -14,7 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define VERSION "2.45"
#define VERSION "2.46"
#define FTABSIZ 150 /* max number of outstanding requests (default) */
#define MAX_PROCS 20 /* max no children for TCP requests */
@@ -115,10 +115,6 @@ HAVE_BROKEN_RTC
NOTE: when enabling or disabling this, be sure to delete any old
leases file, otherwise dnsmasq may get very confused.
HAVE_ISC_READER
define this to include the old ISC dhcpcd integration. Note that you cannot
set both HAVE_ISC_READER and HAVE_BROKEN_RTC.
HAVE_TFTP
define this to get dnsmasq's built-in TFTP server.
@@ -141,9 +137,6 @@ HAVE_BSD_BRIDGE
Define this to enable the --bridge-interface option, useful on some
BSD systems.
HAVE_LARGFILE
Define this if the C library supports large (>2GB) files probably true everywhere
except some builds of uclibc
NOTES:
For Linux you should define
@@ -166,13 +159,8 @@ NOTES:
/* platform independent options- uncomment to enable */
#define HAVE_TFTP
/* #define HAVE_BROKEN_RTC */
/* #define HAVE_ISC_READER */
/* #define HAVE_DBUS */
#if defined(HAVE_BROKEN_RTC) && defined(HAVE_ISC_READER)
# error HAVE_ISC_READER is not compatible with HAVE_BROKEN_RTC
#endif
/* Allow TFTP to be disabled with COPTS=-DNO_TFTP */
#ifdef NO_TFTP
#undef HAVE_TFTP

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 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
@@ -283,7 +283,10 @@ char *dbus_init(void)
daemon->dbus = connection;
if ((message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, "Up")))
dbus_connection_send(connection, message, NULL);
{
dbus_connection_send(connection, message, NULL);
dbus_message_unref(message);
}
return NULL;
}
@@ -352,4 +355,36 @@ void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset)
}
}
void emit_dbus_signal(int action, char *mac, char *hostname, char *addr)
{
DBusConnection *connection = (DBusConnection *)daemon->dbus;
DBusMessage* message = NULL;
DBusMessageIter args;
const char *action_str;
if (!connection)
return;
if (action == ACTION_DEL)
action_str = "DhcpLeaseDeleted";
else if (action == ACTION_ADD)
action_str = "DhcpLeaseAdded";
else if (action == ACTION_OLD)
action_str = "DhcpLeaseUpdated";
else
return;
if (!(message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, action_str)))
return;
dbus_message_iter_init_append(message, &args);
if (dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &addr) &&
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &mac) &&
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &hostname))
dbus_connection_send(connection, message, NULL);
dbus_message_unref(message);
}
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 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
@@ -635,6 +635,19 @@ static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *
return 0;
}
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
{
struct hwaddr_config *conf_addr;
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask == 0 &&
conf_addr->hwaddr_len == len &&
(conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
return 1;
return 0;
}
struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
@@ -643,7 +656,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
int hw_type, char *hostname)
{
struct dhcp_config *config;
struct hwaddr_config *conf_addr;
if (clid)
for (config = configs; config; config = config->next)
if (config->flags & CONFIG_CLID)
@@ -663,11 +677,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_HWADDR) &&
config->wildcard_mask == 0 &&
config->hwaddr_len == hw_len &&
(config->hwaddr_type == hw_type || config->hwaddr_type == 0) &&
memcmp(config->hwaddr, hwaddr, hw_len) == 0 &&
if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
is_addr_in_context(context, config))
return config;
@@ -679,14 +689,14 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
return config;
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_HWADDR) &&
config->wildcard_mask != 0 &&
config->hwaddr_len == hw_len &&
(config->hwaddr_type == hw_type || config->hwaddr_type == 0) &&
is_addr_in_context(context, config) &&
memcmp_masked(config->hwaddr, hwaddr, hw_len, config->wildcard_mask))
return config;
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask != 0 &&
conf_addr->hwaddr_len == hw_len &&
(conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
is_addr_in_context(context, config) &&
memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask))
return config;
return NULL;
}
@@ -720,6 +730,7 @@ void dhcp_read_ethers(void)
/* cannot have a clid */
if (config->flags & CONFIG_NAME)
free(config->hostname);
free(config->hwaddr);
free(config);
}
else
@@ -766,7 +777,7 @@ void dhcp_read_ethers(void)
}
else
{
if (!canonicalise(ip) || strip_hostname(ip))
if (!canonicalise(ip))
{
my_syslog(LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
continue;
@@ -782,19 +793,24 @@ void dhcp_read_ethers(void)
if (!config)
{
for (config = daemon->dhcp_conf; config; config = config->next)
if ((config->flags & CONFIG_HWADDR) &&
config->wildcard_mask == 0 &&
config->hwaddr_len == ETHER_ADDR_LEN &&
(config->hwaddr_type == ARPHRD_ETHER || config->hwaddr_type == 0) &&
memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
break;
{
struct hwaddr_config *conf_addr = config->hwaddr;
if (conf_addr &&
conf_addr->next == NULL &&
conf_addr->wildcard_mask == 0 &&
conf_addr->hwaddr_len == ETHER_ADDR_LEN &&
(conf_addr->hwaddr_type == ARPHRD_ETHER || conf_addr->hwaddr_type == 0) &&
memcmp(conf_addr->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
break;
}
if (!config)
{
if (!(config = whine_malloc(sizeof(struct dhcp_config))))
continue;
config->flags = CONFIG_FROM_ETHERS;
config->wildcard_mask = 0;
config->hwaddr = NULL;
config->domain = NULL;
config->next = daemon->dhcp_conf;
daemon->dhcp_conf = config;
}
@@ -813,10 +829,17 @@ void dhcp_read_ethers(void)
config->addr = addr;
}
config->flags |= CONFIG_HWADDR | CONFIG_NOCLID;
memcpy(config->hwaddr, hwaddr, ETHER_ADDR_LEN);
config->hwaddr_len = ETHER_ADDR_LEN;
config->hwaddr_type = ARPHRD_ETHER;
config->flags |= CONFIG_NOCLID;
if (!config->hwaddr)
config->hwaddr = whine_malloc(sizeof(struct hwaddr_config));
if (config->hwaddr)
{
memcpy(config->hwaddr->hwaddr, hwaddr, ETHER_ADDR_LEN);
config->hwaddr->hwaddr_len = ETHER_ADDR_LEN;
config->hwaddr->hwaddr_type = ARPHRD_ETHER;
config->hwaddr->wildcard_mask = 0;
config->hwaddr->next = NULL;
}
count++;
}
@@ -852,15 +875,9 @@ void check_dhcp_hosts(int fatal)
configs->flags &= ~CONFIG_ADDR;
}
/* split off domain part */
if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
{
if (fatal)
die(_("illegal domain %s in dhcp-config directive."), domain, EC_BADCONF);
else
my_syslog(LOG_ERR, _("illegal domain %s in %s."), domain, daemon->dhcp_hosts_file);
free(configs->hostname);
configs->flags &= ~CONFIG_NAME;
}
configs->domain = domain;
}
}
}
@@ -918,6 +935,7 @@ char *host_from_dns(struct in_addr addr)
{
struct crec *lookup;
char *hostname = NULL;
char *d1, *d2;
if (daemon->port == 0)
return NULL; /* DNS disabled. */
@@ -928,14 +946,16 @@ char *host_from_dns(struct in_addr addr)
hostname = daemon->dhcp_buff;
strncpy(hostname, cache_get_name(lookup), 256);
hostname[255] = 0;
if (strip_hostname(hostname))
d1 = strip_hostname(hostname);
d2 = get_domain(addr);
if (d1 && (!d2 || hostname_isequal(d1, d2)))
hostname = NULL;
}
return hostname;
}
/* return illegal domain or NULL if OK */
/* return domain or NULL if none. */
char *strip_hostname(char *hostname)
{
char *dot = strchr(hostname, '.');
@@ -944,9 +964,20 @@ char *strip_hostname(char *hostname)
return NULL;
*dot = 0; /* truncate */
if (*(dot+1) && (!daemon->domain_suffix || !hostname_isequal(dot+1, daemon->domain_suffix)))
if (strlen(dot+1) != 0)
return dot+1;
return NULL;
}
char *get_domain(struct in_addr addr)
{
struct cond_domain *c;
for (c = daemon->cond_domain; c; c = c->next)
if (ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
return c->domain;
return daemon->domain_suffix;
}

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 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
@@ -36,10 +36,6 @@ static char *compile_opts =
#ifdef HAVE_BSD_BRIDGE
"BSD-bridge "
#endif
#ifndef HAVE_ISC_READER
"no-"
#endif
"ISC-leasefile "
#ifndef HAVE_DBUS
"no-"
#endif
@@ -66,7 +62,7 @@ static void poll_resolv(void);
int main (int argc, char **argv)
{
int bind_fallback = 0;
time_t now, last = 0;
time_t now;
struct sigaction sigact;
struct iname *if_tmp;
int piperead, pipefd[2], err_pipe[2];
@@ -117,10 +113,6 @@ int main (int argc, char **argv)
if (daemon->dhcp)
daemon->lease_file = LEASEFILE;
}
#ifndef HAVE_ISC_READER
else if (!daemon->dhcp)
die(_("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h"), NULL, EC_BADCONF);
#endif
/* Close any file descriptors we inherited apart from std{in|out|err} */
for (i = 0; i < max_fd; i++)
@@ -633,14 +625,11 @@ int main (int argc, char **argv)
/* Check for changes to resolv files once per second max. */
/* Don't go silent for long periods if the clock goes backwards. */
if (last == 0 || difftime(now, last) > 1.0 || difftime(now, last) < -1.0)
if (daemon->last_resolv == 0 ||
difftime(now, daemon->last_resolv) > 1.0 ||
difftime(now, daemon->last_resolv) < -1.0)
{
last = now;
#ifdef HAVE_ISC_READER
if (daemon->lease_file && !daemon->dhcp)
load_dhcp(now);
#endif
daemon->last_resolv = now;
if (daemon->port != 0 && !(daemon->options & OPT_NO_POLL))
poll_resolv();
@@ -912,7 +901,7 @@ static void poll_resolv()
warned = 0;
check_servers();
if (daemon->options & OPT_RELOAD)
cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts);
cache_reload(daemon->addn_hosts);
}
else
{
@@ -929,7 +918,7 @@ static void poll_resolv()
void clear_cache_and_reload(time_t now)
{
if (daemon->port != 0)
cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts);
cache_reload(daemon->addn_hosts);
if (daemon->dhcp)
{

View File

@@ -172,7 +172,7 @@ struct event_desc {
#define OPT_AUTHORITATIVE (1u<<17)
#define OPT_LOCALISE (1u<<18)
#define OPT_DBUS (1u<<19)
#define OPT_BOOTP_DYNAMIC (1u<<20)
#define OPT_DHCP_FQDN (1u<<20)
#define OPT_NO_PING (1u<<21)
#define OPT_LEASE_RO (1u<<22)
#define OPT_ALL_SERVERS (1u<<23)
@@ -229,6 +229,11 @@ struct ptr_record {
struct ptr_record *next;
};
struct cname {
char *alias, *target;
struct cname *next;
};
struct interface_name {
char *name; /* domain name */
char *intr; /* interface name */
@@ -425,23 +430,28 @@ struct dhcp_netid_list {
struct dhcp_netid_list *next;
};
struct hwaddr_config {
int hwaddr_len, hwaddr_type;
unsigned char hwaddr[DHCP_CHADDR_MAX];
unsigned int wildcard_mask;
struct hwaddr_config *next;
};
struct dhcp_config {
unsigned int flags;
int clid_len; /* length of client identifier */
unsigned char *clid; /* clientid */
int hwaddr_len, hwaddr_type;
unsigned char hwaddr[DHCP_CHADDR_MAX];
char *hostname;
char *hostname, *domain;
struct dhcp_netid netid;
struct in_addr addr;
time_t decline_time;
unsigned int lease_time, wildcard_mask;
unsigned int lease_time;
struct hwaddr_config *hwaddr;
struct dhcp_config *next;
};
#define CONFIG_DISABLE 1
#define CONFIG_CLID 2
#define CONFIG_HWADDR 4
#define CONFIG_TIME 8
#define CONFIG_NAME 16
#define CONFIG_ADDR 32
@@ -503,6 +513,12 @@ struct dhcp_bridge {
};
#endif
struct cond_domain {
char *domain;
struct in_addr start, end;
struct cond_domain *next;
};
struct dhcp_context {
unsigned int lease_time, addr_epoch;
struct in_addr netmask, broadcast;
@@ -565,16 +581,19 @@ extern struct daemon {
unsigned int options;
struct resolvc default_resolv, *resolv_files;
time_t last_resolv;
struct mx_srv_record *mxnames;
struct naptr *naptr;
struct txt_record *txt;
struct ptr_record *ptr;
struct cname *cnames;
struct interface_name *int_names;
char *mxtarget;
char *lease_file;
char *username, *groupname, *scriptuser;
int group_set, osport;
char *domain_suffix;
struct cond_domain *cond_domain;
char *runfile;
char *lease_change_command;
struct iname *if_names, *if_addrs, *if_except, *dhcp_except;
@@ -593,7 +612,7 @@ extern struct daemon {
struct dhcp_vendor *dhcp_vendors;
struct dhcp_mac *dhcp_macs;
struct dhcp_boot *boot_config;
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *force_broadcast;
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *force_broadcast, *bootp_dynamic;
char *dhcp_hosts_file, *dhcp_opts_file;
int dhcp_max, tftp_max;
int dhcp_server_port, dhcp_client_port;
@@ -660,7 +679,7 @@ void cache_end_insert(void);
void cache_start_insert(void);
struct crec *cache_insert(char *name, struct all_addr *addr,
time_t now, unsigned long ttl, unsigned short flags);
void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *addn_hosts);
void cache_reload(struct hostsfile *addn_hosts);
void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd);
void cache_unhash_dhcp(void);
void dump_cache(time_t now);
@@ -749,17 +768,17 @@ struct in_addr get_ifaddr(char *intr);
/* dhcp.c */
void dhcp_init(void);
void dhcp_packet(time_t now);
char *get_domain(struct in_addr addr);
struct dhcp_context *address_available(struct dhcp_context *context,
struct in_addr addr,
struct dhcp_netid *netids);
struct dhcp_context *narrow_context(struct dhcp_context *context,
struct in_addr taddr,
struct dhcp_netid *netids);
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly);
int address_allocate(struct dhcp_context *context,
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly);int address_allocate(struct dhcp_context *context,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
struct dhcp_netid *netids, time_t now);
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *clid, int clid_len,
@@ -771,6 +790,7 @@ void check_dhcp_hosts(int fatal);
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
char *strip_hostname(char *hostname);
char *host_from_dns(struct in_addr addr);
char *get_domain(struct in_addr addr);
/* lease.c */
void lease_update_file(time_t now);
@@ -779,8 +799,7 @@ void lease_init(time_t now);
struct dhcp_lease *lease_allocate(struct in_addr addr);
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
unsigned char *clid, int hw_len, int hw_type, int clid_len);
void lease_set_hostname(struct dhcp_lease *lease, char *name,
char *suffix, int auth);
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth);
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now);
void lease_set_interface(struct dhcp_lease *lease, int interface);
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
@@ -794,6 +813,8 @@ void rerun_scripts(void);
/* rfc2131.c */
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int *is_inform);
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int clid_len, unsigned char *clid, int *len_out);
/* dnsmasq.c */
int make_icmp_sock(void);
@@ -801,11 +822,6 @@ int icmp_ping(struct in_addr addr);
void send_event(int fd, int event, int data);
void clear_cache_and_reload(time_t now);
/* isc.c */
#ifdef HAVE_ISC_READER
void load_dhcp(time_t now);
#endif
/* netlink.c */
#ifdef HAVE_LINUX_NETWORK
void netlink_init(void);
@@ -827,6 +843,7 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)());
char *dbus_init(void);
void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset);
void set_dbus_listeners(int *maxfdp, fd_set *rset, fd_set *wset, fd_set *eset);
void emit_dbus_signal(int action, char *mac, char *hostname, char *addr);
#endif
/* helper.c */

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 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
@@ -381,8 +381,8 @@ static size_t process_reply(HEADER *header, time_t now,
size_t plen;
/* If upstream is advertising a larger UDP packet size
than we allow, trim it so that we don't get overlarge
requests for the client. We can't do this for signed packets. */
than we allow, trim it so that we don't get overlarge
requests for the client. We can't do this for signed packets. */
if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)) && !is_sign)
{
@@ -918,19 +918,23 @@ static struct randfd *allocate_rfd(int family)
(eg) TFTP. Once we have a reasonable number, randomness should be OK */
for (i = 0; i < RANDOM_SOCKS; i++)
if (daemon->randomsocks[i].refcount == 0 &&
(daemon->randomsocks[i].fd = random_sock(family)) != -1)
if (daemon->randomsocks[i].refcount == 0)
{
if ((daemon->randomsocks[i].fd = random_sock(family)) == -1)
break;
daemon->randomsocks[i].refcount = 1;
daemon->randomsocks[i].family = family;
return &daemon->randomsocks[i];
}
/* No free ones, grab an existing one */
/* No free ones or cannot get new socket, grab an existing one */
for (i = 0; i < RANDOM_SOCKS; i++)
{
int j = (i+finger) % RANDOM_SOCKS;
if (daemon->randomsocks[j].family == family && daemon->randomsocks[j].refcount != 0xffff)
if (daemon->randomsocks[j].refcount != 0 &&
daemon->randomsocks[j].family == family &&
daemon->randomsocks[j].refcount != 0xffff)
{
finger = j;
daemon->randomsocks[j].refcount++;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 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
@@ -31,7 +31,7 @@
#ifndef NO_FORK
static void my_setenv(const char *name, const char *value, int *error);
struct script_data
{
unsigned char action, hwaddr_len, hwaddr_type;
@@ -130,13 +130,13 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
/* stringify MAC into dhcp_buff */
p = daemon->dhcp_buff;
if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
p += sprintf(p, "%.2x-", data.hwaddr_type);
p += sprintf(p, "%.2x-", data.hwaddr_type);
for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
{
p += sprintf(p, "%.2x", data.hwaddr[i]);
if (i != data.hwaddr_len - 1)
p += sprintf(p, ":");
}
{
p += sprintf(p, "%.2x", data.hwaddr[i]);
if (i != data.hwaddr_len - 1)
p += sprintf(p, ":");
}
/* and CLID into packet */
if (!read_write(pipefd[0], buf, data.clid_len, 1))
@@ -237,10 +237,16 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
if (data.hostname_len != 0)
{
char *dot;
hostname = (char *)buf;
hostname[data.hostname_len - 1] = 0;
if (!canonicalise(hostname))
hostname = NULL;
else if ((dot = strchr(hostname, '.')))
{
my_setenv("DNSMASQ_DOMAIN", dot+1, &err);
*dot = 0;
}
}
if (data.action == ACTION_OLD_HOSTNAME && hostname)
@@ -299,7 +305,15 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
{
unsigned char *p;
size_t size;
unsigned int i, hostname_len = 0, clid_len = 0, vclass_len = 0, uclass_len = 0;
int i;
unsigned int hostname_len = 0, clid_len = 0, vclass_len = 0, uclass_len = 0;
#ifdef HAVE_DBUS
p = extended_hwaddr(lease->hwaddr_type, lease->hwaddr_len,
lease->hwaddr, lease->clid_len, lease->clid, &i);
print_mac(daemon->namebuff, p, i);
emit_dbus_signal(action, daemon->namebuff, hostname ? hostname : "", inet_ntoa(lease->addr));
#endif
/* no script */
if (daemon->helperfd == -1)
@@ -320,7 +334,7 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
{
struct script_data *new;
/* start with resonable size, will almost never need extending. */
/* start with reasonable size, will almost never need extending. */
if (size < sizeof(struct script_data) + 200)
size = sizeof(struct script_data) + 200;
@@ -378,8 +392,9 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
memcpy(p, lease->userclass, uclass_len);
p += uclass_len;
}
/* substitute * for space */
for (i = 0; i < hostname_len; i++)
/* substitute * for space: spaces are allowed in hostnames (for DNS-SD)
and are likley to be a security hole in most scripts. */
for (i = 0; i < (int)hostname_len; i++)
if ((daemon->options & OPT_LEASE_RO) && hostname[i] == ' ')
*(p++) = '*';
else

252
src/isc.c
View File

@@ -1,252 +0,0 @@
/* 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
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Code in this file is based on contributions by John Volpe. */
#include "dnsmasq.h"
#ifdef HAVE_ISC_READER
#define MAXTOK 50
struct isc_lease {
char *name, *fqdn;
time_t expires;
struct in_addr addr;
struct isc_lease *next;
};
static struct isc_lease *leases = NULL;
static off_t lease_file_size = (off_t)0;
static ino_t lease_file_inode = (ino_t)0;
static int logged_lease = 0;
static int next_token (char *token, int buffsize, FILE * fp)
{
int c, count = 0;
char *cp = token;
while((c = getc(fp)) != EOF)
{
if (c == '#')
do { c = getc(fp); } while (c != '\n' && c != EOF);
if (c == ' ' || c == '\t' || c == '\n' || c == ';')
{
if (count)
break;
}
else if ((c != '"') && (count<buffsize-1))
{
*cp++ = c;
count++;
}
}
*cp = 0;
return count ? 1 : 0;
}
void load_dhcp(time_t now)
{
char *hostname = daemon->namebuff;
char token[MAXTOK], *dot;
struct in_addr host_address;
time_t ttd, tts;
FILE *fp;
struct isc_lease *lease, *tmp, **up;
struct stat statbuf;
if (stat(daemon->lease_file, &statbuf) == -1)
{
if (!logged_lease)
my_syslog(LOG_WARNING, _("failed to access %s: %s"), daemon->lease_file, strerror(errno));
logged_lease = 1;
return;
}
logged_lease = 0;
if ((statbuf.st_size <= lease_file_size) &&
(statbuf.st_ino == lease_file_inode))
return;
lease_file_size = statbuf.st_size;
lease_file_inode = statbuf.st_ino;
if (!(fp = fopen (daemon->lease_file, "r")))
{
my_syslog (LOG_ERR, _("failed to load %s: %s"), daemon->lease_file, strerror(errno));
return;
}
my_syslog (LOG_INFO, _("reading %s"), daemon->lease_file);
while ((next_token(token, MAXTOK, fp)))
{
if (strcmp(token, "lease") == 0)
{
hostname[0] = '\0';
ttd = tts = (time_t)(-1);
if (next_token(token, MAXTOK, fp) &&
(host_address.s_addr = inet_addr(token)) != (in_addr_t) -1)
{
if (next_token(token, MAXTOK, fp) && *token == '{')
{
while (next_token(token, MAXTOK, fp) && *token != '}')
{
if ((strcmp(token, "client-hostname") == 0) ||
(strcmp(token, "hostname") == 0))
{
if (next_token(hostname, MAXDNAME, fp))
if (!canonicalise(hostname))
{
*hostname = 0;
my_syslog(LOG_ERR, _("bad name in %s"), daemon->lease_file);
}
}
else if ((strcmp(token, "ends") == 0) ||
(strcmp(token, "starts") == 0))
{
struct tm lease_time;
int is_ends = (strcmp(token, "ends") == 0);
if (next_token(token, MAXTOK, fp) && /* skip weekday */
next_token(token, MAXTOK, fp) && /* Get date from lease file */
sscanf (token, "%d/%d/%d",
&lease_time.tm_year,
&lease_time.tm_mon,
&lease_time.tm_mday) == 3 &&
next_token(token, MAXTOK, fp) &&
sscanf (token, "%d:%d:%d:",
&lease_time.tm_hour,
&lease_time.tm_min,
&lease_time.tm_sec) == 3)
{
/* There doesn't seem to be a universally available library function
which converts broken-down _GMT_ time to seconds-in-epoch.
The following was borrowed from ISC dhcpd sources, where
it is noted that it might not be entirely accurate for odd seconds.
Since we're trying to get the same answer as dhcpd, that's just
fine here. */
static const int months [11] = { 31, 59, 90, 120, 151, 181,
212, 243, 273, 304, 334 };
time_t time = ((((((365 * (lease_time.tm_year - 1970) + /* Days in years since '70 */
(lease_time.tm_year - 1969) / 4 + /* Leap days since '70 */
(lease_time.tm_mon > 1 /* Days in months this year */
? months [lease_time.tm_mon - 2]
: 0) +
(lease_time.tm_mon > 2 && /* Leap day this year */
!((lease_time.tm_year - 1972) & 3)) +
lease_time.tm_mday - 1) * 24) + /* Day of month */
lease_time.tm_hour) * 60) +
lease_time.tm_min) * 60) + lease_time.tm_sec;
if (is_ends)
ttd = time;
else
tts = time; }
}
}
/* missing info? */
if (!*hostname)
continue;
if (ttd == (time_t)(-1))
continue;
/* We use 0 as infinite in ttd */
if ((tts != -1) && (ttd == tts - 1))
ttd = (time_t)0;
else if (difftime(now, ttd) > 0)
continue;
if ((dot = strchr(hostname, '.')))
{
if (!daemon->domain_suffix || hostname_isequal(dot+1, daemon->domain_suffix))
{
my_syslog(LOG_WARNING,
_("Ignoring DHCP lease for %s because it has an illegal domain part"),
hostname);
continue;
}
*dot = 0;
}
for (lease = leases; lease; lease = lease->next)
if (hostname_isequal(lease->name, hostname))
{
lease->expires = ttd;
lease->addr = host_address;
break;
}
if (!lease && (lease = whine_malloc(sizeof(struct isc_lease))))
{
lease->expires = ttd;
lease->addr = host_address;
lease->fqdn = NULL;
lease->next = leases;
if (!(lease->name = whine_malloc(strlen(hostname)+1)))
free(lease);
else
{
leases = lease;
strcpy(lease->name, hostname);
if (daemon->domain_suffix &&
(lease->fqdn = whine_malloc(strlen(hostname) + strlen(daemon->domain_suffix) + 2)))
{
strcpy(lease->fqdn, hostname);
strcat(lease->fqdn, ".");
strcat(lease->fqdn, daemon->domain_suffix);
}
}
}
}
}
}
}
fclose(fp);
/* prune expired leases */
for (lease = leases, up = &leases; lease; lease = tmp)
{
tmp = lease->next;
if (lease->expires != (time_t)0 && difftime(now, lease->expires) > 0)
{
*up = lease->next; /* unlink */
free(lease->name);
if (lease->fqdn)
free(lease->fqdn);
free(lease);
}
else
up = &lease->next;
}
/* remove all existing DHCP cache entries */
cache_unhash_dhcp();
for (lease = leases; lease; lease = lease->next)
{
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
cache_add_dhcp_entry(lease->name, &lease->addr, lease->expires);
}
}
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 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
@@ -103,7 +103,7 @@ void lease_init(time_t now)
/* unprotect spaces */
for (p = strchr(daemon->dhcp_buff, '*'); p; p = strchr(p, '*'))
*p = ' ';
lease_set_hostname(lease, daemon->dhcp_buff, daemon->domain_suffix, 0);
lease_set_hostname(lease, daemon->dhcp_buff, 0);
}
/* set these correctly: the "old" events are generated later from
@@ -151,9 +151,9 @@ void lease_update_from_configs(void)
lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
(config->flags & CONFIG_NAME) &&
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
lease_set_hostname(lease, config->hostname, daemon->domain_suffix, 1);
lease_set_hostname(lease, config->hostname, 1);
else if ((name = host_from_dns(lease->addr)))
lease_set_hostname(lease, name, daemon->domain_suffix, 1); /* updates auth flag only */
lease_set_hostname(lease, name, 1); /* updates auth flag only */
}
static void ourprintf(int *errp, char *format, ...)
@@ -254,8 +254,11 @@ void lease_update_dns(void)
for (lease = leases; lease; lease = lease->next)
{
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires);
if (lease->fqdn)
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
if (!(daemon->options & OPT_DHCP_FQDN) && lease->hostname)
cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires);
}
dns_dirty = 0;
@@ -412,11 +415,33 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
}
void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix, int auth)
static void kill_name(struct dhcp_lease *lease)
{
/* run script to say we lost our old name */
/* this shouldn't happen unless updates are very quick and the
script very slow, we just avoid a memory leak if it does. */
free(lease->old_hostname);
/* If we know the fqdn, pass that. The helper will derive the
unqualified name from it, free the unqulaified name here. */
if (lease->fqdn)
{
lease->old_hostname = lease->fqdn;
free(lease->hostname);
}
else
lease->old_hostname = lease->hostname;
lease->hostname = lease->fqdn = NULL;
}
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
{
struct dhcp_lease *lease_tmp;
char *new_name = NULL, *new_fqdn = NULL;
if (lease->hostname && name && hostname_isequal(lease->hostname, name))
{
lease->auth_name = auth;
@@ -433,44 +458,47 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix, int
if (name)
{
for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
if (lease_tmp->hostname && hostname_isequal(lease_tmp->hostname, name))
{
if (lease_tmp->auth_name && !auth)
return;
/* this shouldn't happen unless updates are very quick and the
script very slow, we just avoid a memory leak if it does. */
free(lease_tmp->old_hostname);
lease_tmp->old_hostname = lease_tmp->hostname;
lease_tmp->hostname = NULL;
if (lease_tmp->fqdn)
{
new_fqdn = lease_tmp->fqdn;
lease_tmp->fqdn = NULL;
}
break;
}
if (!new_name && (new_name = whine_malloc(strlen(name) + 1)))
strcpy(new_name, name);
if (suffix && !new_fqdn && (new_fqdn = whine_malloc(strlen(name) + strlen(suffix) + 2)))
if ((new_name = whine_malloc(strlen(name) + 1)))
{
strcpy(new_fqdn, name);
strcat(new_fqdn, ".");
strcat(new_fqdn, suffix);
char *suffix = get_domain(lease->addr);
strcpy(new_name, name);
if (suffix && (new_fqdn = whine_malloc(strlen(new_name) + strlen(suffix) + 2)))
{
strcpy(new_fqdn, name);
strcat(new_fqdn, ".");
strcat(new_fqdn, suffix);
}
}
/* Depending on mode, we check either unqualified name or FQDN. */
for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
{
if (daemon->options & OPT_DHCP_FQDN)
{
if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn) )
continue;
}
else
{
if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
continue;
}
if (lease_tmp->auth_name && !auth)
{
free(new_name);
free(new_fqdn);
return;
}
kill_name(lease_tmp);
break;
}
}
if (lease->hostname)
{
/* run script to say we lost our old name */
free(lease->old_hostname);
lease->old_hostname = lease->hostname;
}
kill_name(lease);
free(lease->fqdn);
lease->hostname = new_name;
lease->fqdn = new_fqdn;
lease->auth_name = auth;
@@ -506,6 +534,13 @@ int do_script_run(time_t now)
{
struct dhcp_lease *lease;
#ifdef HAVE_DBUS
/* If we're going to be sending DBus signals, but the connection is not yet up,
delay everything until it is. */
if ((daemon->options & OPT_DBUS) && !daemon->dbus)
return 0;
#endif
if (old_leases)
{
lease = old_leases;
@@ -522,13 +557,13 @@ int do_script_run(time_t now)
}
else
{
kill_name(lease);
#ifndef NO_FORK
queue_script(ACTION_DEL, lease, lease->hostname, now);
queue_script(ACTION_DEL, lease, lease->old_hostname, now);
#endif
old_leases = lease->next;
free(lease->hostname);
free(lease->fqdn);
free(lease->old_hostname);
free(lease->clid);
free(lease->vendorclass);
free(lease->userclass);
@@ -555,7 +590,8 @@ int do_script_run(time_t now)
(lease->aux_changed && (daemon->options & OPT_LEASE_RO)))
{
#ifndef NO_FORK
queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease, lease->hostname, now);
queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease,
lease->fqdn ? lease->fqdn : lease->hostname, now);
#endif
lease->new = lease->changed = lease->aux_changed = 0;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 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

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 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
@@ -237,7 +237,7 @@ static void nl_err(struct nlmsghdr *h)
failing. */
static void nl_routechange(struct nlmsghdr *h)
{
if (h->nlmsg_type == RTM_NEWROUTE && daemon->srv_save)
if (h->nlmsg_type == RTM_NEWROUTE)
{
struct rtmsg *rtm = NLMSG_DATA(h);
int fd;
@@ -245,17 +245,24 @@ static void nl_routechange(struct nlmsghdr *h)
if (rtm->rtm_type != RTN_UNICAST || rtm->rtm_scope != RT_SCOPE_LINK)
return;
if (daemon->srv_save->sfd)
fd = daemon->srv_save->sfd->fd;
else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
fd = daemon->rfd_save->fd;
else
return;
/* Force re-reading resolv file right now, for luck. */
daemon->last_resolv = 0;
while(sendto(fd, daemon->packet, daemon->packet_len, 0,
&daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send());
if (daemon->srv_save)
{
if (daemon->srv_save->sfd)
fd = daemon->srv_save->sfd->fd;
else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
fd = daemon->rfd_save->fd;
else
return;
while(sendto(fd, daemon->packet, daemon->packet_len, 0,
&daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send());
}
}
}
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 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
@@ -442,7 +442,7 @@ struct listener *create_bound_listeners(void)
}
/* return a UDP socket bound to a random port, have to coper with straying into
/* return a UDP socket bound to a random port, have to cope with straying into
occupied port nos and reserved ones. */
int random_sock(int family)
{
@@ -452,10 +452,7 @@ int random_sock(int family)
{
union mysockaddr addr;
unsigned int ports_avail = 65536u - (unsigned short)daemon->min_port;
int i, tries = 3 * ports_avail;
if (tries > 100)
tries = 100;
int tries = ports_avail < 30 ? 3 * ports_avail : 100;
memset(&addr, 0, sizeof(addr));
addr.sa.sa_family = family;
@@ -463,7 +460,7 @@ int random_sock(int family)
/* don't loop forever if all ports in use. */
if (fix_fd(fd))
for (i = tries; i != 0; i--)
while(tries--)
{
unsigned short port = rand16();

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 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
@@ -60,7 +60,7 @@ struct myoption {
};
#endif
#define OPTSTRING "9531yZDNLERKzowefnbvhdkqr: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:2:4:6:7:8:0:"
#define OPTSTRING "951yZDNLERKzowefnbvhdkqr: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:2:4:6:7:8:0:3:"
/* options which don't have a one-char version */
#define LOPT_RELOAD 256
@@ -96,6 +96,8 @@ struct myoption {
#define LOPT_LOCAL 286
#define LOPT_NAPTR 287
#define LOPT_MINPORT 288
#define LOPT_DHCP_FQDN 289
#define LOPT_CNAME 290
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -160,7 +162,7 @@ static const struct myoption opts[] =
{"localise-queries", 0, 0, 'y'},
{"txt-record", 1, 0, 'Y'},
{"enable-dbus", 0, 0, '1'},
{"bootp-dynamic", 0, 0, '3'},
{"bootp-dynamic", 2, 0, '3'},
{"dhcp-mac", 1, 0, '4'},
{"no-ping", 0, 0, '5'},
{"dhcp-script", 1, 0, '6'},
@@ -200,6 +202,8 @@ static const struct myoption opts[] =
{"dhcp-alternate-port", 2, 0, LOPT_ALTPORT },
{"dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },
{"min-port", 1, 0, LOPT_MINPORT },
{"dhcp-fqdn", 0, 0, LOPT_DHCP_FQDN },
{"cname", 1, 0, LOPT_CNAME },
{ NULL, 0, 0, 0 }
};
@@ -240,8 +244,8 @@ static struct {
{ LOPT_CIRCUIT, ARG_DUP, "<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
{ LOPT_REMOTE, ARG_DUP, "<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
{ LOPT_SUBSCR, ARG_DUP, "<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
{ 'J', ARG_DUP, "<tag>", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
{ LOPT_BROADCAST, ARG_DUP, "<tag>", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
{ 'J', ARG_DUP, "=<id>[,<id>]", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
{ LOPT_BROADCAST, ARG_DUP, "=<id>[,<id>]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
{ 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
{ 'K', OPT_AUTHORITATIVE, NULL, gettext_noop("Assume we are the only DHCP server on the local network."), NULL },
{ 'l', ARG_ONE, "path", gettext_noop("Specify where to store DHCP leases (defaults to %s)."), LEASEFILE },
@@ -261,7 +265,7 @@ static struct {
{ 'r', ARG_DUP, "path", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },
{ 'S', ARG_DUP, "/domain/ipaddr", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL },
{ LOPT_LOCAL, ARG_DUP, "/domain/", gettext_noop("Never forward queries to specified domains."), NULL },
{ 's', ARG_ONE, "<domain>", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL },
{ 's', ARG_DUP, "<domain>[,<range>]", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL },
{ 't', ARG_ONE, "host_name", gettext_noop("Specify default target in an MX record."), NULL },
{ 'T', ARG_ONE, "time", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
{ LOPT_NEGTTL, ARG_ONE, "time", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
@@ -281,7 +285,7 @@ static struct {
{ 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
{ '1', OPT_DBUS, NULL, gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
{ '2', ARG_DUP, "interface", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
{ '3', OPT_BOOTP_DYNAMIC, NULL, gettext_noop("Enable dynamic address allocation for bootp."), NULL },
{ '3', ARG_DUP, "[=<id>[,<id>]]", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
{ '4', ARG_DUP, "<id>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
#ifdef HAVE_BSD_BRIDGE
{ LOPT_BRIDGE, ARG_DUP, "iface,alias,..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL },
@@ -293,7 +297,7 @@ static struct {
{ '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL },
{ '0', ARG_ONE, "<queries>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" },
{ LOPT_RELOAD, OPT_RELOAD, NULL, gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
{ LOPT_NO_NAMES, ARG_DUP, "[=<id>]", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
{ LOPT_NO_NAMES, ARG_DUP, "[=<id>[,<id>]]", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
{ LOPT_OVERRIDE, OPT_NO_OVERRIDE, NULL, gettext_noop("Do NOT reuse filename and server fields for extra DHCP options."), NULL },
{ LOPT_TFTP, OPT_TFTP, NULL, gettext_noop("Enable integrated read-only TFTP server."), NULL },
{ LOPT_PREFIX, ARG_ONE, "<directory>", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
@@ -311,6 +315,8 @@ static struct {
{ LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change script as this user."), NULL },
{ LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
{ LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
{ LOPT_DHCP_FQDN, OPT_DHCP_FQDN, NULL, gettext_noop("Use only fully qualified domain names for DHCP clients."), NULL },
{ LOPT_CNAME, ARG_DUP, "<alias>,<target>", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
{ 0, 0, NULL, NULL, NULL }
};
@@ -373,8 +379,8 @@ static const struct {
{ "T2", 59, OT_INTERNAL },
{ "vendor-class", 60, 0 },
{ "client-id", 61,OT_INTERNAL },
{ "nis-domain", 64, 0 },
{ "nis-server", 65, OT_ADDR_LIST },
{ "nis+-domain", 64, 0 },
{ "nis+-server", 65, OT_ADDR_LIST },
{ "tftp-server", 66, 0 },
{ "bootfile-name", 67, 0 },
{ "mobile-ip-home", 68, OT_ADDR_LIST },
@@ -957,7 +963,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
{
char *file = opt_string_alloc(arg);
if (file)
one_file(file, nest, 0);
{
one_file(file, nest, 0);
free(file);
}
break;
}
@@ -1001,6 +1010,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
}
closedir(dir_stream);
free(directory);
break;
}
@@ -1127,10 +1137,49 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
case 's': /* --domain */
if (strcmp (arg, "#") == 0)
daemon->options |= OPT_RESOLV_DOMAIN;
else if (!canonicalise_opt(arg))
option = '?';
else
daemon->domain_suffix = opt_string_alloc(arg);
{
comma = split(arg);
if (!canonicalise_opt(arg))
option = '?';
else
{
char *d = opt_string_alloc(arg);
if (comma)
{
struct cond_domain *new = safe_malloc(sizeof(struct cond_domain));
unhide_metas(comma);
if ((arg = strchr(comma, '/')))
{
int mask;
*arg++ = 0;
if ((new->start.s_addr = inet_addr(comma)) == (in_addr_t)-1 ||
!atoi_check(arg, &mask))
option = '?';
else
{
mask = (1 << (32 - mask)) - 1;
new->start.s_addr = ntohl(htonl(new->start.s_addr) & ~mask);
new->end.s_addr = new->start.s_addr | htonl(mask);
}
}
else if ((arg = split(comma)))
{
if ((new->start.s_addr = inet_addr(comma)) == (in_addr_t)-1 ||
(new->end.s_addr = inet_addr(arg)) == (in_addr_t)-1)
option = '?';
}
else if ((new->start.s_addr = new->end.s_addr = inet_addr(comma)) == (in_addr_t)-1)
option = '?';
new->domain = d;
new->next = daemon->cond_domain;
daemon->cond_domain = new;
}
else
daemon->domain_suffix = d;
}
}
break;
case 'u': /* --user */
@@ -1406,7 +1455,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
case LOPT_MINPORT: /* --min-port */
if (!atoi_check16(arg, &daemon->min_port))
option = '?';
option = '?';
break;
case '0': /* --dns-forward-max */
@@ -1656,7 +1705,8 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
new = opt_malloc(sizeof(struct dhcp_config));
new->next = daemon->dhcp_conf;
new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
new->hwaddr = NULL;
if ((a[0] = arg))
for (k = 1; k < 6; k++)
@@ -1706,8 +1756,11 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
}
else
{
new->hwaddr_len = parse_hex(a[j], new->hwaddr, DHCP_CHADDR_MAX, &new->wildcard_mask, &new->hwaddr_type);
new->flags |= CONFIG_HWADDR;
struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
newhw->next = new->hwaddr;
new->hwaddr = newhw;
newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
&newhw->wildcard_mask, &newhw->hwaddr_type);
}
}
else if (strchr(a[j], '.') && (in.s_addr = inet_addr(a[j])) != (in_addr_t)-1)
@@ -1768,6 +1821,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
{
new->flags |= CONFIG_NAME;
strcpy(new->hostname, a[j]);
new->domain = NULL;
}
}
}
@@ -1850,7 +1904,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
else
{
struct dhcp_mac *new = opt_malloc(sizeof(struct dhcp_mac));
new->netid.net = opt_string_alloc(arg);
if (strstr(arg, "net:") == arg)
new->netid.net = opt_string_alloc(arg+4);
else
new->netid.net = opt_string_alloc(arg);
unhide_metas(comma);
new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
new->next = daemon->dhcp_macs;
@@ -1873,7 +1930,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
char *p;
int dig = 0;
struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
new->netid.net = opt_string_alloc(arg);
if (strstr(arg, "net:") == arg)
new->netid.net = opt_string_alloc(arg+4);
else
new->netid.net = opt_string_alloc(arg);
/* check for hex string - must digits may include : must not have nothing else,
only allowed for agent-options. */
for (p = comma; *p; p++)
@@ -1944,6 +2004,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
case 'J': /* --dhcp-ignore */
case LOPT_NO_NAMES: /* --dhcp-ignore-names */
case LOPT_BROADCAST: /* --dhcp-broadcast */
case '3': /* --bootp-dynamic */
{
struct dhcp_netid_list *new = opt_malloc(sizeof(struct dhcp_netid_list));
struct dhcp_netid *list = NULL;
@@ -1957,6 +2018,11 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
new->next = daemon->force_broadcast;
daemon->force_broadcast = new;
}
else if (option == '3')
{
new->next = daemon->bootp_dynamic;
daemon->bootp_dynamic = new;
}
else
{
new->next = daemon->dhcp_ignore_names;
@@ -1968,7 +2034,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
comma = split(arg);
member->next = list;
list = member;
member->net = opt_string_alloc(arg);
if (strstr(arg, "net:") == arg)
member->net = opt_string_alloc(arg+4);
else
member->net = opt_string_alloc(arg);
arg = comma;
}
@@ -2033,6 +2102,26 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
new->intr = opt_string_alloc(comma);
break;
}
case LOPT_CNAME: /* --cname */
{
struct cname *new;
if (!(comma = split(arg)))
option = '?';
else
{
for (new = daemon->cnames; new; new = new->next)
if (hostname_isequal(new->alias, arg))
problem = _("duplicate CNAME");
new = opt_malloc(sizeof(struct cname));
new->next = daemon->cnames;
daemon->cnames = new;
new->alias = opt_string_alloc(arg);
new->target = opt_string_alloc(comma);
}
break;
}
case LOPT_PTR: /* --ptr-record */
{
@@ -2387,6 +2476,13 @@ void reread_dhcp(void)
if (configs->flags & CONFIG_BANK)
{
struct hwaddr_config *mac, *tmp;
for (mac = configs->hwaddr; mac; mac = tmp)
{
tmp = mac->next;
free(mac);
}
if (configs->flags & CONFIG_CLID)
free(configs->clid);
if (configs->flags & CONFIG_NETID)
@@ -2394,6 +2490,7 @@ void reread_dhcp(void)
if (configs->flags & CONFIG_NAME)
free(configs->hostname);
*up = configs->next;
free(configs);
}
@@ -2639,4 +2736,6 @@ void read_opts(int argc, char **argv, char *compile_opts)
srv->name = opt_string_alloc(buff);
}
}
else if (daemon->options & OPT_DHCP_FQDN)
die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
}

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 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
@@ -21,8 +21,14 @@ static int add_resource_record(HEADER *header, char *limit, int *truncp,
unsigned long ttl, unsigned int *offset, unsigned short type,
unsigned short class, char *format, ...);
#define CHECK_LEN(header, pp, plen, len) \
((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))
#define ADD_RDLEN(header, pp, plen, len) \
(!CHECK_LEN(header, pp, plen, len) ? 0 : (int)((pp) += (len)), 1)
static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
char *name, int isExtract)
char *name, int isExtract, int extrabytes)
{
unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
unsigned int j, l, hops = 0;
@@ -31,19 +37,47 @@ static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
if (isExtract)
*cp = 0;
while ((l = *p++))
{
unsigned int label_type = l & 0xc0;
while (1)
{
unsigned int label_type;
if (!CHECK_LEN(header, p, plen, 1))
return 0;
if ((l = *p++) == 0)
/* end marker */
{
/* check that there are the correct no of bytes after the name */
if (!CHECK_LEN(header, p, plen, extrabytes))
return 0;
if (isExtract)
{
if (cp != (unsigned char *)name)
cp--;
*cp = 0; /* terminate: lose final period */
}
else if (*cp != 0)
retvalue = 2;
if (p1) /* we jumped via compression */
*pp = p1;
else
*pp = p;
return retvalue;
}
label_type = l & 0xc0;
if (label_type == 0xc0) /* pointer */
{
if ((size_t)(p - (unsigned char *)header) >= plen)
if (!CHECK_LEN(header, p, plen, 1))
return 0;
/* get offset */
l = (l&0x3f) << 8;
l |= *p++;
if (l >= plen)
return 0;
if (!p1) /* first jump, save location to go back to */
p1 = p;
@@ -74,7 +108,7 @@ static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
/* output is \[x<hex>/siz]. which is digs+9 chars */
if (cp - (unsigned char *)name + digs + 9 >= MAXDNAME)
return 0;
if ((size_t)(p - (unsigned char *)header + ((count-1)>>3)) >= plen)
if (!CHECK_LEN(header, p, plen, (count-1)>>3))
return 0;
*cp++ = '\\';
@@ -98,8 +132,9 @@ static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
{ /* label_type = 0 -> label. */
if (cp - (unsigned char *)name + l + 1 >= MAXDNAME)
return 0;
if ((size_t)(p - (unsigned char *)header) >= plen)
if (!CHECK_LEN(header, p, plen, l))
return 0;
for(j=0; j<l; j++, p++)
if (isExtract)
{
@@ -132,26 +167,7 @@ static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
else if (*cp != 0 && *cp++ != '.')
retvalue = 2;
}
if ((unsigned int)(p - (unsigned char *)header) >= plen)
return 0;
}
if (isExtract)
{
if (cp != (unsigned char *)name)
cp--;
*cp = 0; /* terminate: lose final period */
}
else if (*cp != 0)
retvalue = 2;
if (p1) /* we jumped via compression */
*pp = p1;
else
*pp = p;
return retvalue;
}
/* Max size of input string (for IPv6) is 75 chars.) */
@@ -261,15 +277,17 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
return 0;
}
static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen)
static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen, int extrabytes)
{
while(1)
{
unsigned int label_type = (*ansp) & 0xc0;
unsigned int label_type;
if ((unsigned int)(ansp - (unsigned char *)header) >= plen)
if (!CHECK_LEN(header, ansp, plen, 1))
return NULL;
label_type = (*ansp) & 0xc0;
if (label_type == 0xc0)
{
/* pointer for compression. */
@@ -283,6 +301,9 @@ static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen
/* Extended label type */
unsigned int count;
if (!CHECK_LEN(header, ansp, plen, 2))
return NULL;
if (((*ansp++) & 0x3f) != 1)
return NULL; /* we only understand bitstrings */
@@ -296,12 +317,17 @@ static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen
else
{ /* label type == 0 Bottom six bits is length */
unsigned int len = (*ansp++) & 0x3f;
if (!ADD_RDLEN(header, ansp, plen, len))
return NULL;
if (len == 0)
break; /* zero length label marks the end. */
ansp += len;
}
}
if (!CHECK_LEN(header, ansp, plen, extrabytes))
return NULL;
return ansp;
}
@@ -313,12 +339,10 @@ static unsigned char *skip_questions(HEADER *header, size_t plen)
for (q = ntohs(header->qdcount); q != 0; q--)
{
if (!(ansp = skip_name(ansp, header, plen)))
if (!(ansp = skip_name(ansp, header, plen, 4)))
return NULL;
ansp += 4; /* class and type */
}
if ((unsigned int)(ansp - (unsigned char *)header) > plen)
return NULL;
return ansp;
}
@@ -329,13 +353,12 @@ static unsigned char *skip_section(unsigned char *ansp, int count, HEADER *heade
for (i = 0; i < count; i++)
{
if (!(ansp = skip_name(ansp, header, plen)))
if (!(ansp = skip_name(ansp, header, plen, 10)))
return NULL;
ansp += 8; /* type, class, TTL */
GETSHORT(rdlen, ansp);
if ((unsigned int)(ansp + rdlen - (unsigned char *)header) > plen)
if (!ADD_RDLEN(header, ansp, plen, rdlen))
return NULL;
ansp += rdlen;
}
return ansp;
@@ -355,7 +378,7 @@ unsigned int questions_crc(HEADER *header, size_t plen, char *name)
for (q = ntohs(header->qdcount); q != 0; q--)
{
if (!extract_name(header, plen, &p, name, 1))
if (!extract_name(header, plen, &p, name, 1, 4))
return crc; /* bad packet */
for (p1 = (unsigned char *)name; *p1; p1++)
@@ -381,7 +404,7 @@ unsigned int questions_crc(HEADER *header, size_t plen, char *name)
}
p += 4;
if ((unsigned int)(p - (unsigned char *)header) > plen)
if (!CHECK_LEN(header, p, plen, 0))
return crc; /* bad packet */
}
@@ -393,12 +416,13 @@ size_t resize_packet(HEADER *header, size_t plen, unsigned char *pheader, size_t
{
unsigned char *ansp = skip_questions(header, plen);
/* if packet is malformed, just return as-is. */
if (!ansp)
return 0;
return plen;
if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
header, plen)))
return 0;
return plen;
/* restore pseudoheader */
if (pheader && ntohs(header->arcount) == 0)
@@ -432,7 +456,7 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
{
for (i = ntohs(header->qdcount); i != 0; i--)
{
if (!(ansp = skip_name(ansp, header, plen)))
if (!(ansp = skip_name(ansp, header, plen, 4)))
return NULL;
GETSHORT(type, ansp);
@@ -458,7 +482,7 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
for (i = 0; i < arcount; i++)
{
unsigned char *save, *start = ansp;
if (!(ansp = skip_name(ansp, header, plen)))
if (!(ansp = skip_name(ansp, header, plen, 10)))
return NULL;
GETSHORT(type, ansp);
@@ -466,9 +490,8 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
GETSHORT(class, ansp);
ansp += 4; /* TTL */
GETSHORT(rdlen, ansp);
if ((size_t)(ansp + rdlen - (unsigned char *)header) > plen)
if (!ADD_RDLEN(header, ansp, plen, rdlen))
return NULL;
ansp += rdlen;
if (type == T_OPT)
{
if (len)
@@ -508,7 +531,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
for (i = count; i != 0; i--)
{
if (!(p = skip_name(p, header, qlen)))
if (!(p = skip_name(p, header, qlen, 10)))
return 0; /* bad packet */
GETSHORT(qtype, p);
@@ -521,7 +544,10 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
struct doctor *doctor;
struct in_addr addr;
/* alignment */
if (!CHECK_LEN(header, p, qlen, INADDRSZ))
return 0;
/* alignment */
memcpy(&addr, p, INADDRSZ);
for (doctor = daemon->doctors; doctor; doctor = doctor->next)
@@ -536,10 +562,8 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
}
}
p += rdlen;
if ((size_t)(p - (unsigned char *)header) > qlen)
return 0; /* bad packet */
if (!ADD_RDLEN(header, p, qlen, rdlen))
return 0; /* bad packet */
}
return p;
@@ -559,7 +583,7 @@ static int find_soa(HEADER *header, size_t qlen)
for (i = ntohs(header->nscount); i != 0; i--)
{
if (!(p = skip_name(p, header, qlen)))
if (!(p = skip_name(p, header, qlen, 10)))
return 0; /* bad packet */
GETSHORT(qtype, p);
@@ -574,10 +598,10 @@ static int find_soa(HEADER *header, size_t qlen)
minttl = ttl;
/* MNAME */
if (!(p = skip_name(p, header, qlen)))
if (!(p = skip_name(p, header, qlen, 0)))
return 0;
/* RNAME */
if (!(p = skip_name(p, header, qlen)))
if (!(p = skip_name(p, header, qlen, 20)))
return 0;
p += 16; /* SERIAL REFRESH RETRY EXPIRE */
@@ -585,13 +609,10 @@ static int find_soa(HEADER *header, size_t qlen)
if (ttl < minttl)
minttl = ttl;
}
else
p += rdlen;
if ((size_t)(p - (unsigned char *)header) > qlen)
else if (!ADD_RDLEN(header, p, qlen, rdlen))
return 0; /* bad packet */
}
/* rewrite addresses in additioal section too */
if (!do_doctor(p, ntohs(header->arcount), header, qlen))
return 0;
@@ -633,7 +654,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
unsigned long cttl = ULONG_MAX, attl;
namep = p;
if (!extract_name(header, qlen, &p, name, 1))
if (!extract_name(header, qlen, &p, name, 1, 4))
return 0; /* bad packet */
GETSHORT(qtype, p);
@@ -661,8 +682,8 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
{
unsigned char *tmp = namep;
/* the loop body overwrites the original name, so get it back here. */
if (!extract_name(header, qlen, &tmp, name, 1) ||
!(res = extract_name(header, qlen, &p1, name, 0)))
if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
!(res = extract_name(header, qlen, &p1, name, 0, 10)))
return 0; /* bad packet */
GETSHORT(aqtype, p1);
@@ -677,7 +698,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
{
if (!extract_name(header, qlen, &p1, name, 1))
if (!extract_name(header, qlen, &p1, name, 1, 0))
return 0;
if (aqtype == T_CNAME)
@@ -692,7 +713,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
}
p1 = endrr;
if ((size_t)(p1 - (unsigned char *)header) > qlen)
if (!CHECK_LEN(header, p1, qlen, 0))
return 0; /* bad packet */
}
}
@@ -737,7 +758,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
for (j = ntohs(header->ancount); j != 0; j--)
{
if (!(res = extract_name(header, qlen, &p1, name, 0)))
if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
return 0; /* bad packet */
GETSHORT(aqtype, p1);
@@ -763,14 +784,17 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
if (attl < cttl)
cttl = attl;
if (!extract_name(header, qlen, &p1, name, 1))
if (!extract_name(header, qlen, &p1, name, 1, 0))
return 0;
goto cname_loop1;
}
else
{
found = 1;
/* copy address into aligned storage */
if (!CHECK_LEN(header, p1, qlen, addrlen))
return 0; /* bad packet */
memcpy(&addr, p1, addrlen);
/* check for returned address in private space */
@@ -790,7 +814,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
}
p1 = endrr;
if ((size_t)(p1 - (unsigned char *)header) > qlen)
if (!CHECK_LEN(header, p1, qlen, 0))
return 0; /* bad packet */
}
}
@@ -839,7 +863,7 @@ unsigned short extract_request(HEADER *header, size_t qlen, char *name, unsigned
if (ntohs(header->qdcount) != 1 || header->opcode != QUERY)
return 0; /* must be exactly one query. */
if (!extract_name(header, qlen, &p, name, 1))
if (!extract_name(header, qlen, &p, name, 1, 4))
return 0; /* bad packet */
GETSHORT(qtype, p);
@@ -953,7 +977,7 @@ int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
for (i = ntohs(header->ancount); i != 0; i--)
{
if (!extract_name(header, qlen, &p, name, 1))
if (!extract_name(header, qlen, &p, name, 1, 10))
return 0; /* bad packet */
GETSHORT(qtype, p);
@@ -962,19 +986,25 @@ int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
GETSHORT(rdlen, p);
if (qclass == C_IN && qtype == T_A)
for (baddrp = baddr; baddrp; baddrp = baddrp->next)
if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
{
/* Found a bogus address. Insert that info here, since there no SOA record
to get the ttl from in the normal processing */
cache_start_insert();
cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN | F_CONFIG);
cache_end_insert();
return 1;
}
{
if (!CHECK_LEN(header, p, qlen, INADDRSZ))
return 0;
for (baddrp = baddr; baddrp; baddrp = baddrp->next)
if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
{
/* Found a bogus address. Insert that info here, since there no SOA record
to get the ttl from in the normal processing */
cache_start_insert();
cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN | F_CONFIG);
cache_end_insert();
return 1;
}
}
p += rdlen;
if (!ADD_RDLEN(header, p, qlen, rdlen))
return 0;
}
return 0;
@@ -1073,6 +1103,18 @@ static int add_resource_record(HEADER *header, char *limit, int *truncp, unsigne
return 1;
}
static unsigned long crec_ttl(struct crec *crecp, time_t now)
{
/* Return 0 ttl for DHCP entries, which might change
before the lease expires. */
if (crecp->flags & (F_IMMORTAL | F_DHCP))
return daemon->local_ttl;
return crecp->ttd - now;
}
/* return zero if we can't answer from cache, or packet size if we can */
size_t answer_request(HEADER *header, char *limit, size_t qlen,
struct in_addr local_addr, struct in_addr local_netmask, time_t now)
@@ -1137,7 +1179,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
nameoffset = p - (unsigned char *)header;
/* now extract name as .-concatenated string into name */
if (!extract_name(header, qlen, &p, name, 1))
if (!extract_name(header, qlen, &p, name, 1, 4))
return 0; /* bad packet */
GETSHORT(qtype, p);
@@ -1239,18 +1281,11 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
auth = 0;
if (!dryrun)
{
unsigned long ttl;
/* Return 0 ttl for DHCP entries, which might change
before the lease expires. */
if (crecp->flags & (F_IMMORTAL | F_DHCP))
ttl = daemon->local_ttl;
else
ttl = crecp->ttd - now;
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
record_source(daemon->addn_hosts, crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL,
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), NULL,
T_PTR, C_IN, "d", cache_get_name(crecp)))
anscount++;
}
@@ -1358,7 +1393,8 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
if (!dryrun)
{
log_query(crecp->flags, name, NULL, record_source(daemon->addn_hosts, crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, crecp->ttd - now, &nameoffset,
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), &nameoffset,
T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache)))
anscount++;
}
@@ -1391,17 +1427,11 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
ans = 1;
if (!dryrun)
{
unsigned long ttl;
if (crecp->flags & (F_IMMORTAL | F_DHCP))
ttl = daemon->local_ttl;
else
ttl = crecp->ttd - now;
log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
record_source(daemon->addn_hosts, crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL, type, C_IN,
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), NULL, type, C_IN,
type == T_A ? "4" : "6", &crecp->addr))
anscount++;
}
@@ -1529,7 +1559,6 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
crecp = NULL;
while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
{
unsigned long ttl;
#ifdef HAVE_IPV6
int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
#else
@@ -1538,12 +1567,8 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
if (crecp->flags & F_NEG)
continue;
if (crecp->flags & (F_IMMORTAL | F_DHCP))
ttl = daemon->local_ttl;
else
ttl = crecp->ttd - now;
if (add_resource_record(header, limit, NULL, rec->offset, &ansp, ttl, NULL, type, C_IN,
if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
crec_ttl(crecp, now), NULL, type, C_IN,
crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
addncount++;
}

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 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
@@ -90,14 +90,14 @@ static void do_options(struct dhcp_context *context,
struct dhcp_packet *mess,
unsigned char *real_end,
unsigned char *req_options,
char *hostname,
char *hostname,
char *domain, char *config_domain,
struct dhcp_netid *netid,
struct in_addr subnet_addr,
unsigned char fqdn_flags,
int null_term,
unsigned char *agent_id);
static unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int clid_len, unsigned char *clid, int *len_out);
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
@@ -112,13 +112,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
int clid_len = 0, ignore = 0, do_classes = 0, selecting = 0;
struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
unsigned char *end = (unsigned char *)(mess + 1);
char *hostname = NULL, *offer_hostname = NULL, *client_hostname = NULL;
char *hostname = NULL, *offer_hostname = NULL, *client_hostname = NULL, *domain = NULL;
int hostname_auth = 0, borken_opt = 0;
unsigned char *req_options = NULL;
char *message = NULL;
unsigned int time;
struct dhcp_config *config;
struct dhcp_netid *netid = NULL;
struct dhcp_netid *netid;
struct in_addr subnet_addr, fallback, override;
unsigned short fuzz = 0;
unsigned int mess_type = 0;
@@ -126,9 +126,14 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
unsigned char *agent_id = NULL;
unsigned char *emac = NULL;
int emac_len = 0;
struct dhcp_netid known_id;
struct dhcp_netid known_id, iface_id;
subnet_addr.s_addr = override.s_addr = 0;
/* set tag with name == interface */
iface_id.net = iface_name;
iface_id.next = NULL;
netid = &iface_id;
if (mess->op != BOOTREQUEST || mess->hlen > DHCP_CHADDR_MAX)
return 0;
@@ -359,8 +364,11 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
end = mess->options + 64; /* BOOTP vend area is only 64 bytes */
if (have_config(config, CONFIG_NAME))
hostname = config->hostname;
{
hostname = config->hostname;
domain = config->domain;
}
if (have_config(config, CONFIG_NETID))
{
config->netid.next = netid;
@@ -389,8 +397,11 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (!message)
{
int nailed = 0;
if (have_config(config, CONFIG_ADDR))
{
nailed = 1;
logaddr = &config->addr;
mess->yiaddr = config->addr;
if ((lease = lease_find_by_addr(config->addr)) &&
@@ -399,8 +410,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
memcmp(lease->hwaddr, mess->chaddr, lease->hwaddr_len) != 0))
message = _("address in use");
}
else if (!(daemon->options & OPT_BOOTP_DYNAMIC))
message = _("no address configured");
else
{
if (!(lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, NULL, 0)) ||
@@ -419,27 +428,35 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
mess->yiaddr = lease->addr;
}
if (!message && !(context = narrow_context(context, mess->yiaddr, netid)))
message = _("wrong network");
else if (context->netid.net)
{
context->netid.next = netid;
netid = &context->netid;
}
if (!message && !nailed)
{
for (id_list = daemon->bootp_dynamic; id_list; id_list = id_list->next)
if ((!id_list->list) || match_netid(id_list->list, netid, 0))
break;
if (!id_list)
message = _("no address configured");
}
if (!message &&
!lease &&
(!(lease = lease_allocate(mess->yiaddr))))
message = _("no leases left");
if (!message && !(context = narrow_context(context, mess->yiaddr, netid)))
message = _("wrong network");
if (!message)
{
logaddr = &mess->yiaddr;
if (context->netid.net)
{
context->netid.next = netid;
netid = &context->netid;
}
lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0);
if (hostname)
lease_set_hostname(lease, hostname, daemon->domain_suffix, 1);
lease_set_hostname(lease, hostname, 1);
/* infinite lease unless nailed in dhcp-host line. */
lease_set_expires(lease,
have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff,
@@ -447,8 +464,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
lease_set_interface(lease, int_index);
clear_packet(mess, end, NULL);
do_options(context, mess, end, NULL,
hostname, netid, subnet_addr, 0, 0, NULL);
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
domain, netid, subnet_addr, 0, 0, NULL);
}
}
@@ -518,6 +535,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (have_config(config, CONFIG_NAME))
{
hostname = config->hostname;
domain = config->domain;
hostname_auth = 1;
/* be careful not to send an OFFER with a hostname not matching the DISCOVER. */
if (fqdn_flags != 0 || !client_hostname || hostname_isequal(hostname, client_hostname))
@@ -525,9 +543,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
else if (client_hostname)
{
char *d = strip_hostname(client_hostname);
if (d)
my_syslog(LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), d, client_hostname);
domain = strip_hostname(client_hostname);
if (strlen(client_hostname) != 0)
{
@@ -540,7 +556,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0,
mess->chaddr, mess->hlen,
mess->htype, hostname);
if (new && !have_config(new, CONFIG_CLID) && !have_config(new, CONFIG_HWADDR))
if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
{
config = new;
/* set "known" tag for known hosts */
@@ -710,7 +726,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
{
char *addrs = inet_ntoa(config->addr);
if ((ltmp = lease_find_by_addr(config->addr)) && ltmp != lease)
if ((ltmp = lease_find_by_addr(config->addr)) &&
ltmp != lease &&
!config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
{
int len;
unsigned char *mac = extended_hwaddr(ltmp->hwaddr_type, ltmp->hwaddr_len,
@@ -771,8 +789,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_T1, 4, (time/2));
option_put(mess, end, OPTION_T2, 4, (time*7)/8);
}
do_options(context, mess, end, req_options, offer_hostname,
netid, subnet_addr, fqdn_flags, borken_opt, agent_id);
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
domain, netid, subnet_addr, fqdn_flags, borken_opt, agent_id);
return dhcp_packet_size(mess, netid);
@@ -797,14 +815,21 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (option_addr(opt).s_addr != override.s_addr)
return 0;
}
else
else
{
for (; context; context = context->current)
if (context->local.s_addr == option_addr(opt).s_addr)
break;
if (!context)
return 0;
{
/* In auth mode, a REQUEST sent to the wrong server
should be faulted, so that the client establishes
communication with us, otherwise, silently ignore. */
if (!(daemon->options & OPT_AUTHORITATIVE))
return 0;
message = _("wrong server-ID");
}
}
/* If a lease exists for this host and another address, squash it. */
@@ -888,18 +913,33 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else if ((addr_config = config_find_by_address(daemon->dhcp_conf, mess->yiaddr)) && addr_config != config)
message = _("address reserved");
else if ((ltmp = lease_find_by_addr(mess->yiaddr)) && ltmp != lease)
message = _("address in use");
else if (emac_len == 0)
message = _("no unique-id");
else if (!lease)
{
if ((lease = lease_allocate(mess->yiaddr)))
do_classes = 1;
else if (!lease && (ltmp = lease_find_by_addr(mess->yiaddr)))
{
/* If a host is configured with more than one MAC address, it's OK to 'nix
a lease from one of it's MACs to give the address to another. */
if (config && config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
{
my_syslog(LOG_INFO, _("abandoning lease to %s of %s"),
print_mac(daemon->namebuff, ltmp->hwaddr, ltmp->hwaddr_len),
inet_ntoa(ltmp->addr));
lease = ltmp;
}
else
message = _("no leases left");
message = _("address in use");
}
if (!message)
{
if (emac_len == 0)
message = _("no unique-id");
else if (!lease)
{
if ((lease = lease_allocate(mess->yiaddr)))
do_classes = 1;
else
message = _("no leases left");
}
}
}
@@ -984,7 +1024,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
hostname = NULL;
}
if (hostname)
lease_set_hostname(lease, hostname, daemon->domain_suffix, hostname_auth);
lease_set_hostname(lease, hostname, hostname_auth);
lease_set_expires(lease, time, now);
lease_set_interface(lease, int_index);
@@ -1007,8 +1047,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_T1, 4, (time/2) - fuzz);
option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
}
do_options(context, mess, end, req_options, hostname,
netid, subnet_addr, fqdn_flags, borken_opt, agent_id);
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
domain, netid, subnet_addr, fqdn_flags, borken_opt, agent_id);
}
return dhcp_packet_size(mess, netid);
@@ -1063,8 +1103,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
lease_set_interface(lease, int_index);
}
do_options(context, mess, end, req_options, hostname,
netid, subnet_addr, fqdn_flags, borken_opt, agent_id);
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
domain, netid, subnet_addr, fqdn_flags, borken_opt, agent_id);
*is_inform = 1; /* handle reply differently */
return dhcp_packet_size(mess, netid);
@@ -1081,7 +1121,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
then the client-id is using the usual encoding and use the rest of the
client-id: if not we can use the whole client-id. This should give
sane MAC address logs. */
static unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int clid_len, unsigned char *clid, int *len_out)
{
if (hwlen == 0 && clid && clid_len > 3)
@@ -1291,6 +1331,7 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *neti
unsigned char *overload;
size_t ret;
struct dhcp_netid_list *id_list;
struct dhcp_netid *n;
/* We do logging too */
if (netid && (daemon->options & OPT_LOG_OPTS))
@@ -1299,9 +1340,17 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *neti
*p = 0;
for (; netid; netid = netid->next)
{
strncat (p, netid->net, MAXDNAME);
if (netid->next)
strncat (p, ", ", MAXDNAME);
/* kill dupes. */
for (n = netid->next; n; n = n->next)
if (strcmp(netid->net, n->net) == 0)
break;
if (!n)
{
strncat (p, netid->net, MAXDNAME);
if (netid->next)
strncat (p, ", ", MAXDNAME);
}
}
p[MAXDNAME - 1] = 0;
my_syslog(LOG_INFO, _("tags: %s"), p);
@@ -1531,7 +1580,8 @@ static void do_options(struct dhcp_context *context,
struct dhcp_packet *mess,
unsigned char *real_end,
unsigned char *req_options,
char *hostname,
char *hostname,
char *domain, char *config_domain,
struct dhcp_netid *netid,
struct in_addr subnet_addr,
unsigned char fqdn_flags,
@@ -1545,6 +1595,9 @@ static void do_options(struct dhcp_context *context,
unsigned char f0 = 0, s0 = 0;
int done_file = 0, done_server = 0;
if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
my_syslog(LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, hostname);
/* logging */
if ((daemon->options & OPT_LOG_OPTS) && req_options)
{
@@ -1681,9 +1734,9 @@ static void do_options(struct dhcp_context *context,
!option_find2(netid, config_opts, OPTION_DNSSERVER))
option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
if (daemon->domain_suffix && in_list(req_options, OPTION_DOMAINNAME) &&
if (domain && in_list(req_options, OPTION_DOMAINNAME) &&
!option_find2(netid, config_opts, OPTION_DOMAINNAME))
option_put_string(mess, end, OPTION_DOMAINNAME, daemon->domain_suffix, null_term);
option_put_string(mess, end, OPTION_DOMAINNAME, domain, null_term);
/* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */
if (hostname)
@@ -1700,8 +1753,8 @@ static void do_options(struct dhcp_context *context,
else if (null_term)
len++;
if (daemon->domain_suffix)
len += strlen(daemon->domain_suffix) + 1;
if (domain)
len += strlen(domain) + 1;
if ((p = free_space(mess, end, OPTION_CLIENT_FQDN, len)))
{
@@ -1712,19 +1765,19 @@ static void do_options(struct dhcp_context *context,
if (fqdn_flags & 0x04)
{
p = do_rfc1035_name(p, hostname);
if (daemon->domain_suffix)
p = do_rfc1035_name(p, daemon->domain_suffix);
if (domain)
p = do_rfc1035_name(p, domain);
*p++ = 0;
}
else
{
memcpy(p, hostname, strlen(hostname));
p += strlen(hostname);
if (daemon->domain_suffix)
if (domain)
{
*(p++) = '.';
memcpy(p, daemon->domain_suffix, strlen(daemon->domain_suffix));
p += strlen(daemon->domain_suffix);
memcpy(p, domain, strlen(domain));
p += strlen(domain);
}
if (null_term)
*(p++) = 0;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 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

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 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