summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2004-12-13 20:56:23 +0000
committerSimon Kelley <simon@thekelleys.org.uk>2012-01-05 17:31:11 +0000
commitbb01cb9604d6cae2f1514eca174b5db080c716e9 (patch)
treea32fabbcf78959cf8ee3af14bbe511eb689e6eee
parent59353a6b5643cf71f1af21a68d734da68ec95bd1 (diff)
downloaddnsmasq-2.19.tar.gz
import of dnsmasq-2.19.tar.gzv2.19
-rw-r--r--CHANGELOG18
-rw-r--r--FAQ19
-rw-r--r--dnsmasq-rh.spec2
-rw-r--r--dnsmasq-suse.spec2
-rw-r--r--src/config.h2
-rw-r--r--src/dhcp.c38
-rw-r--r--src/dnsmasq.h2
-rw-r--r--src/network.c4
-rw-r--r--src/rfc2131.c100
9 files changed, 121 insertions, 66 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 6c8ccaa..9cc262f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1307,8 +1307,22 @@ version 2.18
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.
diff --git a/FAQ b/FAQ
index dceb8d1..bd800cd 100644
--- a/FAQ
+++ b/FAQ
@@ -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
diff --git a/dnsmasq-rh.spec b/dnsmasq-rh.spec
index 61ddb17..87f3d59 100644
--- a/dnsmasq-rh.spec
+++ b/dnsmasq-rh.spec
@@ -5,7 +5,7 @@
###############################################################################
Name: dnsmasq
-Version: 2.18
+Version: 2.19
Release: 1
Copyright: GPL
Group: System Environment/Daemons
diff --git a/dnsmasq-suse.spec b/dnsmasq-suse.spec
index 9dcb709..8fec85a 100644
--- a/dnsmasq-suse.spec
+++ b/dnsmasq-suse.spec
@@ -5,7 +5,7 @@
###############################################################################
Name: dnsmasq
-Version: 2.18
+Version: 2.19
Release: 1
Copyright: GPL
Group: Productivity/Networking/DNS/Servers
diff --git a/src/config.h b/src/config.h
index 0426447..03747a5 100644
--- a/src/config.h
+++ b/src/config.h
@@ -12,7 +12,7 @@
/* Author's email: simon@thekelleys.org.uk */
-#define VERSION "2.18"
+#define VERSION "2.19"
#define FTABSIZ 150 /* max number of outstanding requests */
#define MAX_PROCS 20 /* max no children for TCP requests */
diff --git a/src/dhcp.c b/src/dhcp.c
index b822a6f..195be30 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -656,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;
+}
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index dd61c41..7f163a2 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -478,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);
diff --git a/src/network.c b/src/network.c
index 7815ae6..5250371 100644
--- a/src/network.c
+++ b/src/network.c
@@ -178,7 +178,7 @@ struct irec *enumerate_interfaces(struct daemon *daemon)
unsigned int plen, scope, flags, if_idx;
char devname[20], addrstring[32];
- while (fscanf(f, "%32s %02x %02x %02x %02x %20s\n",
+ while (fscanf(f, "%32s %x %x %x %x %20s\n",
addrstring, &if_idx, &plen, &scope, &flags, devname) != EOF)
{
int i;
@@ -199,9 +199,7 @@ struct irec *enumerate_interfaces(struct daemon *daemon)
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);
}
diff --git a/src/rfc2131.c b/src/rfc2131.c
index 925aa82..0c33324 100644
--- a/src/rfc2131.c
+++ b/src/rfc2131.c
@@ -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,
@@ -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;
@@ -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,23 +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);
- if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS)))
+ if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
{
- 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;
@@ -379,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);
@@ -401,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;
@@ -415,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";
@@ -442,7 +422,7 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
}
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_LEASE_TIME, 4)))
{
unsigned int req_time = option_uint(opt, 4);
if (time == 0xffffffff || (req_time != 0xffffffff && req_time < time))
@@ -472,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)
@@ -569,7 +549,7 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
}
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_LEASE_TIME, 4)))
{
unsigned int req_time = option_uint(opt, 4);
if (time == 0xffffffff || (req_time != 0xffffffff && req_time < time))
@@ -577,6 +557,8 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
}
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, time == 0xffffffff ? 0 : now + (time_t)time);
@@ -620,6 +602,8 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
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);
@@ -644,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];
}
@@ -756,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);
@@ -771,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;
@@ -785,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;
@@ -798,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;
}