mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-04 13:48:30 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb01cb9604 | ||
|
|
59353a6b56 |
No files matched your search
@@ -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.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -5,7 +5,7 @@
|
||||
###############################################################################
|
||||
|
||||
Name: dnsmasq
|
||||
Version: 2.17
|
||||
Version: 2.19
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: System Environment/Daemons
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
###############################################################################
|
||||
|
||||
Name: dnsmasq
|
||||
Version: 2.17
|
||||
Version: 2.19
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: Productivity/Networking/DNS/Servers
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user