Compare commits

..
2 Commits
Author SHA1 Message Date
Simon Kelley bb01cb9604 import of dnsmasq-2.19.tar.gz 2012-01-05 17:31:11 +00:00
Simon Kelley 59353a6b56 import of dnsmasq-2.18.tar.gz 2012-01-05 17:31:11 +00:00
12 changed files with 335 additions and 196 deletions

No files matched your search

+35 -1
View File
@@ -1288,9 +1288,43 @@ version 2.17
clients. Credit to Cedric Duval for spotting this.
Fix rare crash associated with long DNS names and CNAME
records. Thanks to Holger_Hoffstatte and especially Steve
records. Thanks to Holger Hoffstatte and especially Steve
Grecni for help chasing that one down.
version 2.18
Reworked the Linux interface discovery code (again) to
cope with interfaces which have only IPv6 addresses and
interfaces with more than one IPv6 address. Thanks to
Martin Pels for help with that.
Fix problems which occured when more than one dhcp-range
was specified in the same subnet: sometimes parameters
(lease time, network-id tag) from the wrong one would be
used. Thanks to Rory Campbell-Lange for the bug report.
Reset cache statistics when clearing the cache.
Enable long command line options on FreeBSD when the
C library supports them.
version 2.19
Tweaked the Linux-only interface discovery code to cope
with interface-indexes larger than 8 bits in
/proc/net/if_inet6. This only affects Linux, obviously.
Thanks to Richard Atterer for the bug report.
Check for under-length option fields in DHCP packets, a
zero length client-id, in particluar, could seriously
confuse dnsmasq 'till now. Thanks to Will Murname for help
with that.
If a DHCP-allocated address has an associated name in
/etc/hosts, and the client does not provide a hostname
parameter and there is no hostname in a matching dhcp-host
option, send the /etc/hosts name as the hostname in
the DHCP lease. Thanks to Will Murname for the suggestion.
+16 -1
View File
@@ -115,7 +115,7 @@ A: Resolver code sometime does strange things when given names without
--expand-hosts and --domain-suffix options.
Q: Can I get dnsmasq to save the contents of its cache to disk when
I shut my machine down and re-load when it starts again.
I shut my machine down and re-load when it starts again?
A: No, that facility is not provided. Very few names in the DNS have
their time-to-live set for longer than a few hours so most of the
@@ -299,7 +299,22 @@ A: Because when a Gentoo box shuts down, it releases its lease with
dnsmasq ignores it until is times out and restarts the process.
To fix this, set the dhcp-authoritative flag in dnsmasq.
Q: My laptop has two network interfaces, a wired one and a wireless
one. I never use both interfaces at the same time, and I'd like the
same IP and configuration to be used irrespcetive of which
interface is in use. How can I do that.
A: By default, the identity of a machine is determined by using the
MAC address, which is associated with interface hardware. Once an
IP is bound to the MAC address of one interface, it cannot be
associated with another MAC address until after the DHCP lease
expires. The solution to this is to use a client-id as the machine
identity rather than the MAC address. If you arrange for the same
client-id to sent when either interface is in use, the DHCP server
will recognise the same machine, and use the same address. The
method for setting the client-id varies with DHCP client software,
dhcpcd uses the "-I" flag. Windows uses a registry setting,
see http://www.jsiinc.com/SUBF/TIP2800/rh2845.htm
+1 -1
View File
@@ -5,7 +5,7 @@
###############################################################################
Name: dnsmasq
Version: 2.17
Version: 2.19
Release: 1
Copyright: GPL
Group: System Environment/Daemons
+1 -1
View File
@@ -5,7 +5,7 @@
###############################################################################
Name: dnsmasq
Version: 2.17
Version: 2.19
Release: 1
Copyright: GPL
Group: Productivity/Networking/DNS/Servers
+2
View File
@@ -602,6 +602,8 @@ void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *a
struct crec *cache, **up, *tmp;
int i;
cache_inserted = cache_live_freed = 0;
for (i=0; i<hash_size; i++)
for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
{
+12 -5
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2004 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
@@ -12,7 +12,7 @@
/* Author's email: simon@thekelleys.org.uk */
#define VERSION "2.17"
#define VERSION "2.19"
#define FTABSIZ 150 /* max number of outstanding requests */
#define MAX_PROCS 20 /* max no children for TCP requests */
@@ -180,7 +180,7 @@ NOTES:
HAVE_DEV_URANDOM - OpenBSD and FreeBSD and NetBSD
HAVE_DEV_RANDOM - FreeBSD and NetBSD
(OpenBSD with hardware random number generator)
HAVE_GETOPT_LONG - NetBSD
HAVE_GETOPT_LONG - NetBSD, later FreeBSD
(FreeBSD and OpenBSD only if you link GNU getopt)
*/
@@ -205,8 +205,10 @@ NOTES:
#define HAVE_DEV_RANDOM
#undef HAVE_SOCKADDR_SA_LEN
#undef HAVE_PSELECT
/* Don't fork into background on uClinux */
#if defined(__uClinux__)
/* Never use fork() on uClinux. Note that this is subtly different from the
--keep-in-foreground option, since it also suppresses forking new
processes for TCP connections. It's intended for use on MMU-less kernels. */
# define NO_FORK
#endif
@@ -254,7 +256,12 @@ typedef unsigned long in_addr_t;
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
#undef HAVE_LINUX_IPV6_PROC
#undef HAVE_GETOPT_LONG
/* Later verions of FreeBSD have getopt_long() */
#if defined(optional_argument) && defined(required_argument)
# define HAVE_GETOPT_LONG
#else
# undef HAVE_GETOPT_LONG
#endif
#define HAVE_ARC4RANDOM
#define HAVE_RANDOM
#define HAVE_DEV_URANDOM
+64 -4
View File
@@ -375,7 +375,7 @@ void dhcp_packet(struct daemon *daemon, time_t now)
}
}
int address_available(struct dhcp_context *context, struct in_addr taddr)
struct dhcp_context *address_available(struct dhcp_context *context, struct in_addr taddr)
{
/* Check is an address is OK for this network, check all
possible ranges. */
@@ -390,12 +390,34 @@ int address_available(struct dhcp_context *context, struct in_addr taddr)
if (!context->static_only &&
addr >= start &&
addr <= end)
return 1;
return context;
}
return 0;
return NULL;
}
struct dhcp_context *narrow_context(struct dhcp_context *context, struct in_addr taddr)
{
/* We start of with a set of possible contexts, all on the current subnet.
These are chained on ->current.
Here we have an address, and return the actual context correponding to that
address. Note that none may fit, if the address came a dhcp-host and is outside
any dhcp-range. In that case we return a static range is possible, or failing that,
any context on the subnet. (If there's more than one, this is a dodgy configuration:
maybe there should be a warning.) */
struct dhcp_context *tmp = address_available(context, taddr);
if (tmp)
return tmp;
for (tmp = context; tmp; tmp = tmp->current)
if (tmp->static_only)
return tmp;
return context;
}
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
{
struct dhcp_config *config;
@@ -634,3 +656,41 @@ void dhcp_update_configs(struct dhcp_config *configs)
}
}
/* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
for this address. If it has a domain part, that must match the set domain and
it gets stripped. */
char *host_from_dns(struct daemon *daemon, struct in_addr addr)
{
struct crec *lookup = cache_find_by_addr(NULL, (struct all_addr *)&addr, 0, F_IPV4);
char *hostname = NULL;
if (lookup && (lookup->flags & F_HOSTS))
{
hostname = daemon->dhcp_buff;
hostname[256] = 0;
strncpy(hostname, cache_get_name(lookup), 256);
hostname = strip_hostname(daemon, hostname);
}
return hostname;
}
char *strip_hostname(struct daemon *daemon, char *hostname)
{
char *dot = strchr(hostname, '.');
if (dot)
{
if (!daemon->domain_suffix || !hostname_isequal(dot+1, daemon->domain_suffix))
{
syslog(LOG_WARNING, "Ignoring DHCP host name %s because it has an illegal domain part", hostname);
hostname = NULL;
}
else
{
*dot = 0; /* truncate */
if (strlen(hostname) == 0)
hostname = NULL; /* nothing left */
}
}
return hostname;
}
+2
View File
@@ -549,11 +549,13 @@ static void check_dns_listeners(struct daemon *daemon, fd_set *set, time_t now)
if (!match || (num_kids >= MAX_PROCS))
close(confd);
#ifndef NO_FORK
else if (!(daemon->options & OPT_DEBUG) && fork())
{
num_kids++;
close(confd);
}
#endif
else
{
char *buff;
+7 -4
View File
@@ -29,6 +29,9 @@
#include <syslog.h>
#include <arpa/nameser.h>
/* and this. */
#include <getopt.h>
#include "config.h"
#include <arpa/inet.h>
@@ -50,9 +53,6 @@
#include <fcntl.h>
#include <ctype.h>
#include <signal.h>
#ifdef HAVE_GETOPT_LONG
# include <getopt.h>
#endif
#include <time.h>
#include <errno.h>
#include <pwd.h>
@@ -467,7 +467,8 @@ struct listener *create_bound_listeners(struct irec *interfaces, int port);
void dhcp_init(struct daemon *daemon);
void dhcp_packet(struct daemon *daemon, time_t now);
int address_available(struct dhcp_context *context, struct in_addr addr);
struct dhcp_context *address_available(struct dhcp_context *context, struct in_addr addr);
struct dhcp_context *narrow_context(struct dhcp_context *context, struct in_addr taddr);
int address_allocate(struct dhcp_context *context, struct daemon *daemon,
struct in_addr *addrp, unsigned char *hwaddr);
struct dhcp_config *find_config(struct dhcp_config *configs,
@@ -477,6 +478,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
void dhcp_update_configs(struct dhcp_config *configs);
void dhcp_read_ethers(struct daemon *daemon);
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
char *strip_hostname(struct daemon *daemon, char *hostname);
char *host_from_dns(struct daemon *daemon, struct in_addr addr);
/* lease.c */
void lease_update_file(int force, time_t now);
+86 -77
View File
@@ -14,11 +14,33 @@
#include "dnsmasq.h"
static struct irec *add_iface(struct daemon *daemon, struct irec *list, char *name, union mysockaddr *addr)
static struct irec *add_iface(struct daemon *daemon, struct irec *list,
char *name, int is_loopback, union mysockaddr *addr)
{
struct irec *iface;
struct iname *tmp;
/* If we are restricting the set of interfaces to use, make
sure that loopback interfaces are in that set. */
if (daemon->if_names && is_loopback)
{
struct iname *lo;
for (lo = daemon->if_names; lo; lo = lo->next)
if (lo->name && strcmp(lo->name, name) == 0)
{
lo->isloop = 1;
break;
}
if (!lo)
{
lo = safe_malloc(sizeof(struct iname));
lo->name = safe_string_alloc(name);
lo->isloop = lo->used = 1;
lo->next = daemon->if_names;
daemon->if_names = lo;
}
}
/* check blacklist */
if (daemon->if_except)
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
@@ -67,6 +89,10 @@ static struct irec *add_iface(struct daemon *daemon, struct irec *list, char *na
struct irec *enumerate_interfaces(struct daemon *daemon)
{
#if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
FILE *f;
#endif
union mysockaddr addr;
struct irec *iface = NULL;
char *buf, *ptr;
struct ifreq *ifr = NULL;
@@ -74,7 +100,7 @@ struct irec *enumerate_interfaces(struct daemon *daemon)
int lastlen = 0;
int len = 20 * sizeof(struct ifreq);
int fd = socket(PF_INET, SOCK_DGRAM, 0);
if (fd == -1)
die ("cannot create socket to enumerate interfaces: %s", NULL);
@@ -99,9 +125,8 @@ struct irec *enumerate_interfaces(struct daemon *daemon)
free(buf);
}
for (ptr = buf; ptr < buf + len; )
for (ptr = buf; ptr < buf + ifc.ifc_len; )
{
union mysockaddr addr;
#ifdef HAVE_SOCKADDR_SA_LEN
/* subsequent entries may not be aligned, so copy into
an aligned buffer to avoid nasty complaints about
@@ -141,76 +166,45 @@ struct irec *enumerate_interfaces(struct daemon *daemon)
if (ioctl(fd, SIOCGIFFLAGS, ifr) < 0)
die("ioctl error getting interface flags: %m", NULL);
/* If we are restricting the set of interfaces to use, make
sure that loopback interfaces are in that set. */
if (daemon->if_names && (ifr->ifr_flags & IFF_LOOPBACK))
{
struct iname *lo;
for (lo = daemon->if_names; lo; lo = lo->next)
if (lo->name && strcmp(lo->name, ifr->ifr_name) == 0)
{
lo->isloop = 1;
break;
}
if (!lo)
{
lo = safe_malloc(sizeof(struct iname));
lo->name = safe_string_alloc(ifr->ifr_name);
lo->isloop = lo->used = 1;
lo->next = daemon->if_names;
daemon->if_names = lo;
}
}
iface = add_iface(daemon, iface, ifr->ifr_name, &addr);
#if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
/* IPv6 addresses don't seem to work with SIOCGIFCONF. Barf */
/* This code snarfed from net-tools 1.60 and certainly linux specific, though
it shouldn't break on other Unices, and their SIOGIFCONF might work. */
{
FILE *f = fopen(IP6INTERFACES, "r");
int found = 0;
union mysockaddr addr6;
if (f)
{
unsigned int plen, scope, flags, if_idx;
char devname[20], addrstring[32];
while (fscanf(f, "%32s %02x %02x %02x %02x %20s\n",
addrstring, &if_idx, &plen, &scope, &flags, devname) != EOF)
{
if (strcmp(devname, ifr->ifr_name) == 0)
{
int i;
unsigned char *addr6p = (unsigned char *) &addr6.in6.sin6_addr;
memset(&addr6, 0, sizeof(addr6));
addr6.sa.sa_family = AF_INET6;
for (i=0; i<16; i++)
{
unsigned int byte;
sscanf(addrstring+i+i, "%02x", &byte);
addr6p[i] = byte;
}
addr6.in6.sin6_port = htons(daemon->port);
addr6.in6.sin6_flowinfo = htonl(0);
addr6.in6.sin6_scope_id = htonl(scope);
found = 1;
break;
}
}
fclose(f);
}
if (found)
iface = add_iface(daemon, iface, ifr->ifr_name, &addr6);
}
#endif /* LINUX */
iface = add_iface(daemon, iface, ifr->ifr_name, ifr->ifr_flags & IFF_LOOPBACK, &addr);
}
#if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
/* IPv6 addresses don't seem to work with SIOCGIFCONF. Barf */
/* This code snarfed from net-tools 1.60 and certainly linux specific, though
it shouldn't break on other Unices, and their SIOGIFCONF might work. */
if ((f = fopen(IP6INTERFACES, "r")))
{
unsigned int plen, scope, flags, if_idx;
char devname[20], addrstring[32];
while (fscanf(f, "%32s %x %x %x %x %20s\n",
addrstring, &if_idx, &plen, &scope, &flags, devname) != EOF)
{
int i;
struct ifreq sifr;
unsigned char *addr6p = (unsigned char *) &addr.in6.sin6_addr;
memset(&addr, 0, sizeof(addr));
addr.sa.sa_family = AF_INET6;
for (i=0; i<16; i++)
{
unsigned int byte;
sscanf(addrstring+i+i, "%02x", &byte);
addr6p[i] = byte;
}
addr.in6.sin6_port = htons(daemon->port);
addr.in6.sin6_flowinfo = htonl(0);
addr.in6.sin6_scope_id = htonl(scope);
strncpy(sifr.ifr_name, devname, IF_NAMESIZE);
if (ioctl(fd, SIOCGIFFLAGS, &sifr) < 0)
die("ioctl error getting interface flags: %m", NULL);
iface = add_iface(daemon, iface, sifr.ifr_name, sifr.ifr_flags & IFF_LOOPBACK, &addr);
}
fclose(f);
}
#endif /* LINUX */
if (buf)
free(buf);
#ifdef HAVE_SOCKADDR_SA_LEN
@@ -361,7 +355,6 @@ struct listener *create_bound_listeners(struct irec *interfaces, int port)
struct listener *new = safe_malloc(sizeof(struct listener));
new->family = iface->addr.sa.sa_family;
new->next = listeners;
listeners = new;
if ((new->tcpfd = socket(iface->addr.sa.sa_family, SOCK_STREAM, 0)) == -1 ||
(new->fd = socket(iface->addr.sa.sa_family, SOCK_DGRAM, 0)) == -1 ||
setsockopt(new->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
@@ -383,9 +376,25 @@ struct listener *create_bound_listeners(struct irec *interfaces, int port)
#endif
if (bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
bind(new->fd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
listen(new->tcpfd, 5) == -1)
die("failed to bind listening socket: %s", NULL);
bind(new->fd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
{
#ifdef HAVE_IPV6
if (iface->addr.sa.sa_family == AF_INET6 && errno == ENODEV)
{
close(new->tcpfd);
close(new->fd);
free(new);
}
else
#endif
die("failed to bind listening socket: %s", NULL);
}
else
{
listeners = new;
if (listen(new->tcpfd, 5) == -1)
die("failed to listen on socket: %s", NULL);
}
}
return listeners;
+9 -7
View File
@@ -478,8 +478,10 @@ struct daemon *read_opts (int argc, char **argv)
}
case 'a':
{
do {
struct iname *new = safe_malloc(sizeof(struct iname));
if ((comma = strchr(optarg, ',')))
*comma++ = 0;
new->next = daemon->if_addrs;
#ifdef HAVE_IPV6
if (inet_pton(AF_INET, optarg, &new->addr.in.sin_addr))
@@ -510,14 +512,14 @@ struct daemon *read_opts (int argc, char **argv)
{
option = '?'; /* error */
free(new);
new = NULL;
break;
}
if (new)
daemon->if_addrs = new;
break;
}
daemon->if_addrs = new;
optarg = comma;
} while (optarg);
break;
case 'S':
case 'A':
{
+100 -95
View File
@@ -59,13 +59,13 @@ static unsigned char *option_end(unsigned char *p, unsigned char *end, struct dh
static unsigned char *option_put_string(unsigned char *p, unsigned char *end, int opt, char *string);
static void bootp_option_put(struct dhcp_packet *mess,
struct dhcp_boot *boot_opts, struct dhcp_netid *netids);
static int option_len(unsigned char *opt);
static unsigned int option_len(unsigned char *opt);
static void *option_ptr(unsigned char *opt);
static struct in_addr option_addr(unsigned char *opt);
static unsigned int option_uint(unsigned char *opt, int size);
static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr, char *interface, char *string);
static int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool);
static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_type);
static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_type, unsigned int minsize);
static unsigned char *do_req_options(struct dhcp_context *context,
unsigned char *p, unsigned char *end,
unsigned char *req_options,
@@ -94,7 +94,7 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
char *hostname = NULL;
char *req_options = NULL;
char *message = NULL;
unsigned int renewal_time, expires_time, def_time;
unsigned int time;
struct dhcp_config *config;
struct dhcp_netid *netid = NULL;
struct in_addr addr, subnet_addr;
@@ -126,7 +126,7 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
return 0;
/* check for DHCP rather than BOOTP */
if ((opt = option_find(mess, sz, OPTION_MESSAGE_TYPE)))
if ((opt = option_find(mess, sz, OPTION_MESSAGE_TYPE, 1)))
{
mess_type = option_uint(opt, 1);
@@ -136,18 +136,18 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
/* Some buggy clients set ciaddr when they shouldn't, so clear that here since
it can affect the context-determination code. */
if ((option_find(mess, sz, OPTION_REQUESTED_IP) || mess_type == DHCPDISCOVER))
if ((option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ) || mess_type == DHCPDISCOVER))
mess->ciaddr.s_addr = 0;
/* Check for RFC3011 subnet selector */
if ((opt = option_find(mess, sz, OPTION_SUBNET_SELECT)))
if ((opt = option_find(mess, sz, OPTION_SUBNET_SELECT, INADDRSZ)))
subnet_addr = option_addr(opt);
/* If there is no client identifier option, use the hardware address */
if ((opt = option_find(mess, sz, OPTION_CLIENT_ID)))
if ((opt = option_find(mess, sz, OPTION_CLIENT_ID, 1)))
{
clid = option_ptr(opt);
clid_len = option_len(opt);
clid = option_ptr(opt);
}
else
clid = mess->chaddr;
@@ -171,13 +171,6 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
{
context_tmp->current = context;
context = context_tmp;
/* start to build netid chain */
if (context_tmp->netid.net)
{
context_tmp->netid.next = netid;
netid = &context_tmp->netid;
}
}
if (!context)
@@ -205,6 +198,7 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
mess->yiaddr = config->addr;
if (lease_find_by_addr(config->addr))
message = "address in use";
context = narrow_context(context, config->addr);
}
else
message = "no address configured";
@@ -217,6 +211,12 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
if (have_config(config, CONFIG_NAME))
hostname = config->hostname;
if (context->netid.net)
{
context->netid.next = netid;
netid = &context->netid;
}
if (have_config(config, CONFIG_NETID))
{
config->netid.next = netid;
@@ -253,9 +253,9 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
if (have_config(config, CONFIG_NAME))
hostname = config->hostname;
else if ((opt = option_find(mess, sz, OPTION_HOSTNAME)))
else if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
{
int len = option_len(opt);
unsigned int len = option_len(opt);
hostname = daemon->dhcp_buff;
memcpy(hostname, option_ptr(opt), len);
/* May not be zero terminated */
@@ -263,33 +263,14 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
/* ensure there are no strange chars in there */
if (!canonicalise(hostname))
hostname = NULL;
else
else if ((hostname = strip_hostname(daemon, hostname)) && !config)
{
char *dot = strchr(hostname, '.');
if (dot)
{
if (!daemon->domain_suffix || !hostname_isequal(dot+1, daemon->domain_suffix))
{
syslog(LOG_WARNING, "Ignoring DHCP host name %s because it has an illegal domain part", hostname);
hostname = NULL;
}
else
{
*dot = 0; /* truncate */
if (strlen(hostname) == 0)
hostname = NULL; /* nothing left */
}
}
/* Search again now we have a hostname.
Only accept configs without CLID and HWADDR here, (they won't match)
to avoid impersonation by name. */
if (!config)
{
struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0, mess->chaddr, hostname);
if (!have_config(new, CONFIG_CLID) && !have_config(new, CONFIG_HWADDR))
config = new;
}
struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0, mess->chaddr, hostname);
if (!have_config(new, CONFIG_CLID) && !have_config(new, CONFIG_HWADDR))
config = new;
}
}
@@ -307,10 +288,10 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
assume that the option is a single string and non RFC3004 compliant
and just do the substring match. dhclient provides these broken options. */
if ((opt = option_find(mess, sz, OPTION_USER_CLASS)))
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
{
unsigned char *ucp = option_ptr(opt);
int tmp, j;
unsigned int tmp, j;
for (j = 0; j < option_len(opt); j += ucp[j] + 1);
if (j == option_len(opt))
for (j = 0; j < option_len(opt); j = tmp)
@@ -321,9 +302,9 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
}
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
if ((opt = option_find(mess, sz, vendor->is_vendor ? OPTION_VENDOR_ID : OPTION_USER_CLASS)))
if ((opt = option_find(mess, sz, vendor->is_vendor ? OPTION_VENDOR_ID : OPTION_USER_CLASS, 1)))
{
int i;
unsigned int i;
for (i = 0; i <= (option_len(opt) - vendor->len); i++)
if (memcmp(vendor->data, option_ptr(opt)+i, vendor->len) == 0)
{
@@ -348,44 +329,22 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
/* do we have a lease in store? */
lease = lease_find_by_client(clid, clid_len);
def_time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
if ((opt = option_find(mess, sz, OPTION_LEASE_TIME)))
if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
{
unsigned int req_time = option_uint(opt, 4);
if (def_time == 0xffffffff ||
(req_time != 0xffffffff && req_time < def_time))
expires_time = renewal_time = req_time;
else
expires_time = renewal_time = def_time;
}
else
{
renewal_time = def_time;
if (lease)
expires_time = (unsigned int)difftime(lease->expires, now);
else
expires_time = def_time;
}
if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS)))
{
int len = option_len(opt);
req_options = daemon->dhcp_buff2;
memcpy(req_options, option_ptr(opt), len);
req_options[len] = OPTION_END;
memcpy(req_options, option_ptr(opt), option_len(opt));
req_options[option_len(opt)] = OPTION_END;
}
switch (mess_type)
{
case DHCPDECLINE:
if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER)) ||
if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
(iface_addr.s_addr != option_addr(opt).s_addr))
return 0;
/* sanitise any message. Paranoid? Moi? */
if ((opt = option_find(mess, sz, OPTION_MESSAGE)))
if ((opt = option_find(mess, sz, OPTION_MESSAGE, 1)))
{
char *p = option_ptr(opt), *q = daemon->dhcp_buff;
int i;
@@ -400,7 +359,7 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
message = daemon->dhcp_buff;
}
if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
return 0;
log_packet("DECLINE", option_ptr(opt), mess->chaddr, iface_name, message);
@@ -422,7 +381,7 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
return 0;
case DHCPRELEASE:
if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER)) ||
if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
(iface_addr.s_addr != option_addr(opt).s_addr))
return 0;
@@ -436,7 +395,7 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
return 0;
case DHCPDISCOVER:
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
addr = option_addr(opt);
if (ignore || have_config(config, CONFIG_DISABLE))
message = "ignored";
@@ -455,16 +414,33 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
if (message)
return 0;
context = narrow_context(context, mess->yiaddr);
if (context->netid.net)
{
context->netid.next = netid;
netid = &context->netid;
}
time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
if ((opt = option_find(mess, sz, OPTION_LEASE_TIME, 4)))
{
unsigned int req_time = option_uint(opt, 4);
if (time == 0xffffffff || (req_time != 0xffffffff && req_time < time))
time = req_time;
}
else if (lease && lease->expires != 0)
time = (unsigned int)difftime(lease->expires, now);
mess->siaddr = iface_addr;
bootp_option_put(mess, daemon->boot_config, netid);
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
p = option_put(p, end, OPTION_LEASE_TIME, 4, expires_time);
p = option_put(p, end, OPTION_LEASE_TIME, 4, time);
/* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
if (expires_time != 0xffffffff)
if (time != 0xffffffff)
{
p = option_put(p, end, OPTION_T1, 4, (expires_time/2));
p = option_put(p, end, OPTION_T2, 4, ((expires_time * 7)/8));
p = option_put(p, end, OPTION_T1, 4, (time/2));
p = option_put(p, end, OPTION_T2, 4, (time*7)/8);
}
p = do_req_options(context, p, end, req_options, daemon,
NULL, iface_addr, netid, subnet_addr);
@@ -476,12 +452,12 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
case DHCPREQUEST:
if (ignore || have_config(config, CONFIG_DISABLE))
return 0;
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
{
/* SELECTING or INIT_REBOOT */
mess->yiaddr = option_addr(opt);
if ((opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER)))
if ((opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)))
{
/* SELECTING */
if (iface_addr.s_addr != option_addr(opt).s_addr)
@@ -513,9 +489,6 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
/* desynchronise renewals */
fuzz = rand16();
while (fuzz > (renewal_time/16))
fuzz = fuzz/2;
mess->yiaddr = mess->ciaddr;
}
@@ -568,20 +541,39 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
{
log_packet("ACK", &mess->yiaddr, mess->chaddr, iface_name, hostname);
context = narrow_context(context, mess->yiaddr);
if (context->netid.net)
{
context->netid.next = netid;
netid = &context->netid;
}
time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
if ((opt = option_find(mess, sz, OPTION_LEASE_TIME, 4)))
{
unsigned int req_time = option_uint(opt, 4);
if (time == 0xffffffff || (req_time != 0xffffffff && req_time < time))
time = req_time;
}
lease_set_hwaddr(lease, mess->chaddr);
if (!hostname)
hostname = host_from_dns(daemon, mess->yiaddr);
if (hostname)
lease_set_hostname(lease, hostname, daemon->domain_suffix);
lease_set_expires(lease, renewal_time == 0xffffffff ? 0 : now + (time_t)renewal_time);
lease_set_expires(lease, time == 0xffffffff ? 0 : now + (time_t)time);
mess->siaddr = iface_addr;
bootp_option_put(mess, daemon->boot_config, netid);
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
p = option_put(p, end, OPTION_LEASE_TIME, 4, renewal_time);
if (renewal_time != 0xffffffff)
p = option_put(p, end, OPTION_LEASE_TIME, 4, time);
if (time != 0xffffffff)
{
p = option_put(p, end, OPTION_T1, 4, (renewal_time/2) - fuzz);
p = option_put(p, end, OPTION_T2, 4, ((renewal_time * 7)/8) - fuzz);
while (fuzz > (time/16))
fuzz = fuzz/2;
p = option_put(p, end, OPTION_T1, 4, (time/2) - fuzz);
p = option_put(p, end, OPTION_T2, 4, ((time * 7)/8) - fuzz);
}
p = do_req_options(context, p, end, req_options, daemon,
hostname, iface_addr, netid, subnet_addr);
@@ -599,10 +591,19 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
if (message || mess->ciaddr.s_addr == 0)
return 0;
context = narrow_context(context, mess->ciaddr);
if (context->netid.net)
{
context->netid.next = netid;
netid = &context->netid;
}
mess->siaddr = iface_addr;
bootp_option_put(mess, daemon->boot_config, netid);
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
if (!hostname)
hostname = host_from_dns(daemon, mess->yiaddr);
p = do_req_options(context, p, end, req_options, daemon,
hostname, iface_addr, netid, subnet_addr);
p = option_end(p, end, mess);
@@ -627,7 +628,7 @@ static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr,
string ? string : "");
}
static int option_len(unsigned char *opt)
static unsigned int option_len(unsigned char *opt)
{
return opt[1];
}
@@ -739,13 +740,13 @@ static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt
while (*p != OPTION_END)
{
if (end && (p >= end))
if (p >= end)
return 0; /* malformed packet */
else if (*p == OPTION_PAD)
p++;
else if (*p == OPTION_OVERLOAD)
{
if (end && (p >= end - 3))
if (p >= end - 3)
return 0; /* malformed packet */
if (overload)
*overload = *(p+2);
@@ -754,10 +755,10 @@ static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt
else
{
int opt_len;;
if (end && (p >= end - 2))
if (p >= end - 2)
return 0; /* malformed packet */
opt_len = option_len(p);
if (end && (p >= end - (2 + opt_len)))
if (p >= end - (2 + opt_len))
return 0; /* malformed packet */
if (*p == opt)
return p;
@@ -768,7 +769,7 @@ static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt
return NULL;
}
static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_type)
static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_type, unsigned int minsize)
{
int overload = 0;
unsigned char *ret;
@@ -781,7 +782,11 @@ static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_ty
if (!ret && (overload & 2))
ret = option_find1(&mess->sname[0], &mess->file[64], opt_type, &overload);
/* Check the option field is big enough */
if (ret && (option_len(ret) < minsize))
ret = NULL;
return ret;
}