import of dnsmasq-2.6.tar.gz

This commit is contained in:
Simon Kelley
2004-04-03 21:10:00 +01:00
parent 8a911ccc75
commit 33820b7ed9
16 changed files with 865 additions and 365 deletions

View File

@@ -860,4 +860,68 @@ release 2.5
interface a packet was sent to. Thanks to Javier Kohen
for the bug report.
release 2.6
Support Token Ring DHCP. Thanks to Dag Wieers for help
testing. Note that Token ring support only works on Linux
currently.
Fix compilation on MacOS X. Thanks to Bernhard Ehlers for
the patch.
Added new "ignore" keyword for
dhcp-host. "dhcp-host=11:22:33:44:55:66,ignore" will
cause the DHCP server to ignore any host with the given
MAC address, leaving it to other servers on the
network. This also works with client-id and hostnames.
Suggestion by Alex Melt.
Fixed parsing of hex client IDs. Problem spotted by Peter
Fichtner.
Allow conf-file options in configuration file, to
provide an include function.
Re-read /etc/ethers on receipt of SIGHUP.
Added back the ability to read ISC dhcpd lease files, by
popular demand. Note that this is deprecated and for
backwards compatibility only. You can get back the 4K of
memory that the code occupies by undefining
"HAVE_ISC_READER" in src/config.h
Added ability to disable "pool" DHCP address allocation
whilst leaving static leases working. The syntax is
"dhcp-range=192.168.0.0,static"
Thanks to Grzegorz Nosek for the suggestion.
Generalized dnsmasq-rh.spec file to work on Mandrake too,
and removed dnsmasq-mdk.spec. Thanks to Doug Keller.
Allow DHCP options which are tied to specific static
leases in the same way as to specific networks.
Generalised the dhcp-option parser a bit to allow hex
strings as parameters. This is now legal:
dhcp-option=128,e4:45:74:68:00:00
Inspired by a patch from Joel Nordell.
Changed the semantics of argument-less dhcp-options for
the default-setting ones, ie 1, 3, 6 and 28. Now, doing
eg, dhcp-option=3 stops dnsmasq from sending a default
router option at all. Thanks to Scott Emmons for pointing
out that this is useful.
Fixed dnsmasq.conf parsing bug which interpreted port
numbers in server= lines as a comment. To start a
comment, a '#' character must now be a the start of a
line or preceded by whitespace. Thanks to Christian
Haggstrom for the bug report.

35
FAQ
View File

@@ -182,6 +182,41 @@ A: There are a couple of configuration gotchas which have been
address 0.0.0.0 and destination address 255.255.255.255 are not
dropped by iptables/ipchains.
Q: I'm running Debian, and my machines get an address fine with DHCP,
but their names are not appearing in the DNS.
A: By default, none of the DHCP clients send the host-name when asking
for a lease. For most of the clients, you can set the host-name to
send with the "hostname" keyword in /etc/network/interfaces. (See
"man interfaces" for details.) That doesn't work for dhclient, were
you have to add something like "send host-name daisy" to
/etc/dhclient.conf
Q: I'm network booting my machines, and trying to give them static
DHCP-assigned addresses. The machine gets its correct address
whilst booting, but then the OS starts and it seems to get
allocated a different address.
A: What is happening is this: The boot process sends a DHCP
request and gets allocated the static address corresponding to its
MAC address. The boot loader does not send a client-id. Then the OS
starts and repeats the DHCP process, but it it does send a
client-id. Dnsmasq cannot assume that the two requests are from the
same machine (since the client ID's don't match) and even though
the MAC address has a static allocation, that address is still in
use by the first incarnation of the machine (the one from the boot,
without a client ID.) dnsmasq therefore has to give the machine a
dynamic address from its pool. There are two ways to solve this:
(1) persuade your DHCP client not to send a client ID, or (2) set up
the static assignment to the client ID, not the MAC address. The
default client-id will be 01:<MAC address>, so change the dhcp-host
line from "dhcp-host=11:22:33:44:55:66,1.2.3.4" to
"dhcp-host=id:01:11:22:33:44:55:66,1.2.3.4"
Q: What network types are supported by the DHCP server?
A: Ethernet (and 802.11 wireless) are supported on all platforms. On
Linux Token Ring is also supported.

View File

@@ -7,9 +7,11 @@ Version 1.x of dnsmasq includes a facility for reading the dhcp.leases
file written by ISC dhcpd. This allows the names of machines which
have addresses allocated by DHCP to be included in the DNS.
Version 2.x of dnsmasq removes the ISC dhcpd integration and replaces
it with a DHCP server integrated into dnsmasq. This is an incompatible
change in dnsmasq but it has the following advantages:
Version 2.x of dnsmasq replaces the ISC dhcpd integration with a DHCP
server integrated into dnsmasq. Versions 2.0-2.5 removed the ISC
integration completely, but in version 2.6 it was re-enabled for
backwards compatibility purposes. The change to an integrated DHCP
server has the following advantages:
* Small. ISC dhcpd is a large and comprehensive DHCP solution. The
dnsmasq DHCP server adds about 15k to DNS-only dnsmasq and provides
@@ -29,7 +31,6 @@ change in dnsmasq but it has the following advantages:
with the dnsmasq DHCP server.
DHCP configuration
------------------
@@ -56,8 +57,8 @@ Having started dnsmasq, tell any hosts on the network to renew their
DHCP lease, so that dnsmasq's DHCP server becomes aware of them. For
Linux, this is best done by killing-and-restarting the DHCP client
daemon or taking the network interface down and then back up. For
Windows use winipcfg.exe
Windows 9x/Me, use the graphical tool "winipcfg". For Windows
NT/2000/XP, use the command-line "ipconfig /renew"
For more complex DHCP configuration, refer to the doc/setup.html, the
dnsmasq manpage and the annotated example configuration file. Also

View File

@@ -1,130 +0,0 @@
###############################################################################
#
# General mumbojumbo
#
###############################################################################
Name: dnsmasq
Version: 2.5
Release: 1
Copyright: GPL
Group: System Environment/Daemons
Vendor: Simon Kelley
Packager: Simon Kelley
Distribution: Mandrake Linux
URL: http://www.thekelleys.org.uk/dnsmasq
Source0: %{name}-%{version}.tar.gz
Requires: chkconfig
BuildRoot: /var/tmp/%{name}-%{version}
Summary: A lightweight caching nameserver
%description
Dnsmasq is lightweight, easy to configure DNS forwarder and DHCP server. It
is designed to provide DNS and, optionally, DHCP, to a small network. It can
serve the names of local machines which are not in the global DNS. The DHCP
server integrates with the DNS server and allows machines with DHCP-allocated
addresses to appear in the DNS with names configured either in each host or
in a central configuration file. Dnsmasq supports static and dynamic DHCP
leases and BOOTP for network booting of diskless machines.
###############################################################################
#
# Build
#
###############################################################################
%prep
%setup -q
%build
make
###############################################################################
#
# Install
#
###############################################################################
%install
rm -rf $RPM_BUILD_ROOT
mkdir -p -m 755 $RPM_BUILD_ROOT/usr/sbin
mkdir -p -m 755 $RPM_BUILD_ROOT/etc/rc.d/init.d
mkdir -p -m 755 $RPM_BUILD_ROOT/usr/share/man/man8
cp rpm/dnsmasq.rh $RPM_BUILD_ROOT/etc/rc.d/init.d/dnsmasq
strip src/dnsmasq
cp src/dnsmasq $RPM_BUILD_ROOT/usr/sbin
cp dnsmasq.8 $RPM_BUILD_ROOT/usr/share/man/man8
cp dnsmasq.conf.example $RPM_BUILD_ROOT/etc/dnsmasq.conf
###############################################################################
#
# Clean up
#
###############################################################################
%clean
rm -rf $RPM_BUILD_ROOT
###############################################################################
#
# Post-install scriptlet
#
###############################################################################
%post
/sbin/chkconfig --add dnsmasq
###############################################################################
#
# Pre-uninstall scriptlet
#
# If there's a time when your package needs to have one last look around before
# the user erases it, the place to do it is in the %preun script. Anything that
# a package needs to do immediately prior to RPM taking any action to erase the
# package, can be done here.
#
###############################################################################
%preun
if [ $1 = 0 ]; then # execute this only if we are NOT doing an upgrade
service dnsmasq stop >/dev/null 2>&1
/sbin/chkconfig --del dnsmasq
fi
###############################################################################
#
# Post-uninstall scriptlet
#
# The %postun script executes after the package has been removed. It is the
# last chance for a package to clean up after itself.
#
###############################################################################
%postun
if [ "$1" -ge "1" ]; then
service dnsmasq restart >/dev/null 2>&1
fi
###############################################################################
#
# File list
#
###############################################################################
%files
%defattr(-,root,root)
%doc CHANGELOG COPYING FAQ doc.html setup.html UPGRADING_to_2.0
%attr(0755,root,root) /etc/rc.d/init.d/dnsmasq
%attr(0664,root,root) /etc/dnsmasq.conf
%config /etc/rc.d/init.d/dnsmasq
%config /etc/dnsmasq.conf
%attr(0755,root,root) /usr/sbin/dnsmasq
%attr(0644,root,root) /usr/share/man/man8/dnsmasq.8.bz2

View File

@@ -5,7 +5,7 @@
###############################################################################
Name: dnsmasq
Version: 2.5
Version: 2.6
Release: 1
Copyright: GPL
Group: System Environment/Daemons
@@ -58,7 +58,6 @@ cp rpm/dnsmasq.rh $RPM_BUILD_ROOT/etc/rc.d/init.d/dnsmasq
strip src/dnsmasq
cp src/dnsmasq $RPM_BUILD_ROOT/usr/sbin
cp dnsmasq.8 $RPM_BUILD_ROOT/usr/share/man/man8
gzip $RPM_BUILD_ROOT/usr/share/man/man8/dnsmasq.8
cp dnsmasq.conf.example $RPM_BUILD_ROOT/etc/dnsmasq.conf
###############################################################################
@@ -128,6 +127,6 @@ fi
%attr(0755,root,root) /etc/rc.d/init.d/dnsmasq
%attr(0664,root,root) /etc/dnsmasq.conf
%attr(0755,root,root) /usr/sbin/dnsmasq
%attr(0644,root,root) /usr/share/man/man8/dnsmasq.8.gz
%attr(0644,root,root) /usr/share/man/man8/dnsmasq*

View File

@@ -5,7 +5,7 @@
###############################################################################
Name: dnsmasq
Version: 2.5
Version: 2.6
Release: 1
Copyright: GPL
Group: Productivity/Networking/DNS/Servers

View File

@@ -23,7 +23,10 @@ is lightweight and easy to configure. It is intended as be run on
small router/firewalls and provide a DNS (and optionally, DHCP) service to a LAN.
.SH OPTIONS
Note that in general missing parameters are allowed and switch off
functions, for instance "--pid-file=" disables writing a PID file.
functions, for instance "--pid-file=" disables writing a PID file. On
BSD, unless the GNU getopt library is linked, the long form of the
options does not work on the command line; it is still recognised in
the configuration file.
.TP
.B \-h, --no-hosts
Don't read the hostnames in /etc/hosts.
@@ -271,9 +274,16 @@ given using the
.B interface
option. This limitation currently affects OpenBSD. The optional
network-id is a alphanumeric label which marks this network so that
dhcp options may be specified on a per-network basis.
dhcp options may be specified on a per-network basis. The end address
may be replaced by the keyword
.B static
which tells dnsmasq to enable DHCP for the network specified, but not
to dynamically allocate IP addresses. Only hosts which have static
addresses given via
.B dhcp-host
or from /etc/ethers will be served.
.TP
.B \-G, --dhcp-host=[[<hwaddr>]|[id:<client_id>]][,<ipaddr>][,<hostname>][,<lease_time>]
.B \-G, --dhcp-host=[[<hwaddr>]|[id:<client_id>]][net:<netid>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
Specify per host parameters for the DHCP server. This allows a machine
with a particular hardware address to be always allocated the same
hostname, IP address and lease time. A hostname specified like this
@@ -299,7 +309,16 @@ allowed to specify the client ID as text, like this:
If a name appears in /etc/hosts, the associated address can be
allocated to a DHCP lease, but only if a
.B --dhcp-host
option specifying the name also exists.
option specifying the name also exists. The special keyword "ignore"
tells dnsmasq to never offer a DHCP lease to a machine. The machine
can be specified by hardware address, client ID or hostname, for
instance
.B --dhcp-host=00:20:e0:3b:13:af,ignore
This is
useful when there is another DHCP server on the network which should
be used by some machines. The net:<network-id> parameter enables DHCP options just
for this host in the same way as the the network-id in
.B dhcp-range.
.TP
.B \-Z, --read-ethers
Read /etc/ethers for information about hosts for the DHCP server. The
@@ -323,7 +342,9 @@ specfied in RFC2132. For example, to set the default route option to
and to set the time-server address to 192.168.0.4, do
.B dhcp-option=42,192.168.0.4
The special address 0.0.0.0 is taken to mean "the address of the
machine running dnsmasq". If the optional network-id is given then
machine running dnsmasq". Data types allowed are comma seperated
dotted-quad IP addresses, a decimal number, colon-seperated hex digits
and a text string. If the optional network-id is given then
this option is only sent to machines on the network whose dhcp-range
contains a matching network-id.
Be careful: no checking is done that the correct type of data for the
@@ -344,7 +365,12 @@ create thousands of leases and use lots of memory in the dnsmasq
process.
.TP
.B \-l, --dhcp-leasefile=<path>
Use the specified file to store DHCP lease information.
Use the specified file to store DHCP lease information. If this option
is given but no dhcp-range option is given then dnsmasq version 1
behaviour is activated. The file given is assumed to be an ISC dhcpd
lease file and parsed for leases which are then added to the DNS
system if they have a hostname. This functionality may have been
excluded from dnsmasq at compile time, in which case an error will occur.
.TP
.B \-s, --domain=<domain>
Specifies the domain for the DHCP server. This has two effects;
@@ -361,12 +387,14 @@ Add the domain-suffix to simple names (without a period) in /etc/hosts
in the same way as for DHCP-derived names.
.SH CONFIG FILE
At startup, dnsmasq reads /etc/dnsmasq.conf, if it exists. (On
FreeBSD, the file is /usr/local/etc/dnsmasq.conf) The format of this
FreeBSD and OpenBSD, the file is /usr/local/etc/dnsmasq.conf) The format of this
file consists of one option per line, exactly as the long options detailed
in the OPTIONS section but without the leading "--". Lines starting with # are comments and ignored. For
options which may only be specified once, the configuration file overrides
the command line. Use the --conf-file option to specify a different
configuration file.
configuration file. The conf-file option is also allowed in
configuration files, to include multiple configuration files. Only one
level of nesting is allowed.
.SH NOTES
When it receives a SIGHUP,
.B dnsmasq

View File

@@ -157,6 +157,14 @@ filterwin2k
# it asks for a DHCP lease.
#dhcp-host=judge
# Never offer DHCP service to a machine whose ethernet
# address is 11:22:33:44:55:66
#dhcp-host=11:22:33:44:55:66,ignore
# Send extra options which are tagged as "red" to
# the machine with ethernet address 11:22:33:44:55:66
#dhcp-host=11:22:33:44:55:66,net:red
# If this line is uncommented, dnsmasq will read /etc/ethers and act
# on the ethernet-address/IP pairs found there just as if they had
# been given as --dhcp-host options. Useful if you keep
@@ -193,6 +201,10 @@ filterwin2k
# Set the "all subnets are local" flag
#dhcp-option=27,1
# Send the etherboot magic flag and then etherboot options (a string).
#dhcp-option=128,e4:45:74:68:00:00
#dhcp-option=129,NIC=eepro100
# Specify an option which will only be sent to the "red" network
# (see dhcp-range for the declaration of the "red" network)
#dhcp-option=red,42,192.168.1.1
@@ -250,12 +262,12 @@ filterwin2k
# and this maps 1.2.3.x to 5.6.7.x
#alias=1.2.3.0,5.6.7.0,255.255.255.0
# For debugging purposes, log each DNS query as it passes through
# dnsmasq.
#log-queries
# Include a another lot of configuration options.
#conf-file=/etc/dnsmasq.more.conf

View File

@@ -3,7 +3,7 @@
CFLAGS?= -O2
OBJS = cache.o rfc1035.o util.o option.o forward.o \
OBJS = cache.o rfc1035.o util.o option.o forward.o isc.o \
network.o dnsmasq.o dhcp.o lease.o rfc2131.o
.c.o: dnsmasq.h config.h

View File

@@ -12,12 +12,13 @@
/* Author's email: simon@thekelleys.org.uk */
#define VERSION "2.5"
#define VERSION "2.6"
#define FTABSIZ 150 /* max number of outstanding requests */
#define TIMEOUT 20 /* drop queries after TIMEOUT seconds */
#define LOGRATE 120 /* log table overflows every LOGRATE seconds */
#define CACHESIZ 150 /* default cache size */
#define MAXTOK 50 /* token in DHCP leases */
#define MAXLEASES 150 /* maximum number of DHCP leases */
#define SMALLDNAME 40 /* most domain names are smaller than this */
#define HOSTSFILE "/etc/hosts"
@@ -121,6 +122,10 @@ HAVE_BROKEN_RTC
work on other systems by teaching dnsmasq_time() in utils.c how to
read the system uptime.
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_GETOPT_LONG
define this if you have GNU libc or GNU getopt.
@@ -175,6 +180,16 @@ NOTES:
*/
/* platform independent options. */
#undef HAVE_BROKEN_RTC
#define HAVE_ISC_READER
#if defined(HAVE_BROKEN_RTC) && defined(HAVE_ISC_READER)
# error HAVE_ISC_READER is not compatible with HAVE_BROKEN_RTC
#endif
/* platform dependent options. */
/* Must preceed __linux__ since uClinux defines __linux__ too. */
#if defined(__uClinux__) || defined(__UCLIBC__)
#undef HAVE_LINUX_IPV6_PROC
@@ -255,6 +270,7 @@ typedef unsigned long in_addr_t;
#define HAVE_SOCKADDR_SA_LEN
#undef HAVE_PSELECT
#define HAVE_BPF
#define BIND_8_COMPAT
/* Define before sys/socket.h is included so we get socklen_t */
#define _BSD_SOCKLEN_T_
/* The two below are not defined in Mac OS X arpa/nameserv.h */
@@ -287,3 +303,4 @@ typedef unsigned long in_addr_t;

View File

@@ -362,6 +362,10 @@ int address_available(struct dhcp_context *context, struct in_addr taddr)
start = ntohl(context->start.s_addr);
end = ntohl(context->end.s_addr);
/* static leases only. */
if (start == end)
return 0;
if (addr < start)
return 0;
@@ -383,6 +387,10 @@ int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
struct dhcp_config *config;
struct in_addr start = context->last;
/* start == end means no dynamic leases. */
if (context->end.s_addr == context->start.s_addr)
return 0;
do {
if (context->last.s_addr == context->end.s_addr)
context->last = context->start;
@@ -393,7 +401,7 @@ int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
if (!lease_find_by_addr(context->last))
{
for (config = configs; config; config = config->next)
if (config->addr.s_addr == context->last.s_addr)
if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == context->last.s_addr)
break;
if (!config)
@@ -411,7 +419,7 @@ static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *
{
if (!context)
return 1;
if (config->addr.s_addr == 0)
if (!(config->flags & CONFIG_ADDR))
return 1;
if ((config->addr.s_addr & context->netmask.s_addr) == (context->start.s_addr & context->netmask.s_addr))
return 1;
@@ -428,28 +436,31 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
if (clid_len)
for (config = configs; config; config = config->next)
{
if (config->clid_len == clid_len &&
memcmp(config->clid, clid, clid_len) == 0 &&
is_addr_in_context(context, config))
return config;
if (config->flags & CONFIG_CLID)
{
if (config->clid_len == clid_len &&
memcmp(config->clid, clid, clid_len) == 0 &&
is_addr_in_context(context, config))
return config;
/* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
cope with that here */
if (*clid == 0 && config->clid_len == clid_len-1 &&
memcmp(config->clid, clid+1, clid_len-1) == 0 &&
is_addr_in_context(context, config))
return config;
}
/* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
cope with that here */
if (*clid == 0 && config->clid_len == clid_len-1 &&
memcmp(config->clid, clid+1, clid_len-1) == 0 &&
is_addr_in_context(context, config))
return config;
}
for (config = configs; config; config = config->next)
if (memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0 &&
if ((config->flags & CONFIG_HWADDR) &&
memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0 &&
is_addr_in_context(context, config))
return config;
if (hostname)
for (config = configs; config; config = config->next)
if (config->hostname && hostname_isequal(config->hostname, hostname) &&
if ((config->flags & CONFIG_NAME) &&
hostname_isequal(config->hostname, hostname) &&
is_addr_in_context(context, config))
return config;
@@ -459,28 +470,29 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff)
{
FILE *f = fopen(ETHERSFILE, "r");
unsigned int e0, e1, e2, e3, e4, e5;
char *ip, *cp, *name;
unsigned int flags, e0, e1, e2, e3, e4, e5;
char *ip, *cp;
struct in_addr addr;
unsigned char hwaddr[ETHER_ADDR_LEN];
struct dhcp_config *config;
int count = 0;
if (!f)
die("failed to open " ETHERSFILE ":%s", NULL);
{
syslog(LOG_ERR, "failed to read " ETHERSFILE ":%m");
return configs;
}
while (fgets(buff, MAXDNAME, f))
{
while (strlen(buff) > 0 &&
(buff[strlen(buff)-1] == '\n' ||
buff[strlen(buff)-1] == ' ' ||
buff[strlen(buff)-1] == '\r' ||
buff[strlen(buff)-1] == '\t'))
while (strlen(buff) > 0 && isspace(buff[strlen(buff)-1]))
buff[strlen(buff)-1] = 0;
if ((*buff == '#') || (*buff == '+'))
continue;
for (ip = buff; *ip && *ip != ' ' && *ip != '\t'; ip++);
for(; *ip && (*ip == ' ' || *ip == '\t'); ip++)
for (ip = buff; *ip && !isspace(*ip); ip++);
for(; *ip && isspace(*ip); ip++)
*ip = 0;
if (!*ip)
continue;
@@ -488,6 +500,13 @@ struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff)
if (!sscanf(buff, "%x:%x:%x:%x:%x:%x", &e0, &e1, &e2, &e3, &e4, &e5))
continue;
hwaddr[0] = e0;
hwaddr[1] = e1;
hwaddr[2] = e2;
hwaddr[3] = e3;
hwaddr[4] = e4;
hwaddr[5] = e5;
/* check for name or dotted-quad */
for (cp = ip; *cp; cp++)
if (!(*cp == '.' || (*cp >='0' && *cp <= '9')))
@@ -495,47 +514,64 @@ struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff)
if (!*cp)
{
name = NULL;
if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
continue;
flags = CONFIG_ADDR;
for (config = configs; config; config = config->next)
if (config->addr.s_addr == addr.s_addr)
if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
break;
}
else
{
if (!canonicalise(ip))
continue;
name = ip;
addr.s_addr = 0;
flags = CONFIG_NAME;
for (config = configs; config; config = config->next)
if (config->hostname && hostname_isequal(config->hostname, name))
if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, ip))
break;
}
if (!config)
{
config = safe_malloc(sizeof(struct dhcp_config));
config->clid_len = 0;
config->clid = NULL;
config->lease_time = 0;
config->hostname = safe_string_alloc(name);
config->addr = addr;
config->next = configs;
configs = config;
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_HWADDR) &&
memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
break;
if (!config)
{
if (!(config = malloc(sizeof(struct dhcp_config))))
continue;
config->flags = 0;
config->next = configs;
configs = config;
}
config->flags |= flags;
if (flags & CONFIG_NAME)
{
if ((config->hostname = malloc(strlen(ip)+1)))
strcpy(config->hostname, ip);
else
config->flags &= ~CONFIG_NAME;
}
if (flags & CONFIG_ADDR)
config->addr = addr;
}
config->hwaddr[0] = e0;
config->hwaddr[1] = e1;
config->hwaddr[2] = e2;
config->hwaddr[3] = e3;
config->hwaddr[4] = e4;
config->hwaddr[5] = e5;
config->flags |= CONFIG_HWADDR;
memcpy(config->hwaddr, hwaddr, ETHER_ADDR_LEN);
count++;
}
fclose(f);
syslog(LOG_INFO, "read " ETHERSFILE " - %d addresses", count);
return configs;
}
@@ -549,10 +585,13 @@ void dhcp_update_configs(struct dhcp_config *configs)
struct crec *crec;
for (config = configs; config; config = config->next)
if (config->addr.s_addr == 0 && config->hostname &&
if (!(config->flags & CONFIG_ADDR) &&
(config->flags & CONFIG_NAME) &&
(crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
(crec->flags & F_HOSTS))
config->addr = crec->addr.addr.addr4;
{
config->addr = crec->addr.addr.addr4;
config->flags |= CONFIG_ADDR;
}
}

View File

@@ -120,17 +120,14 @@ int main (int argc, char **argv)
#endif
if (!lease_file)
lease_file = LEASEFILE;
else
{
if (!dhcp)
{
complain("********* dhcp-lease option set, but not dhcp-range.", NULL);
complain("********* Are you trying to use the obsolete ISC dhcpd integration?", NULL);
complain("********* Please configure the dnsmasq integrated DHCP server by using", NULL);
complain("********* the \"dhcp-range\" option, and remove any other DHCP server.", NULL);
}
if (dhcp)
lease_file = LEASEFILE;
}
#ifndef HAVE_ISC_READER
else if (!dhcp)
die("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h", NULL);
#endif
interfaces = enumerate_interfaces(if_names, if_addrs, if_except, port);
if (options & OPT_NOWILD)
@@ -152,11 +149,6 @@ int main (int argc, char **argv)
{
dhcp_init(&dhcpfd, &dhcp_raw_fd);
leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, now, maxleases);
if (options & OPT_ETHERS)
dhcp_configs = dhcp_read_ethers(dhcp_configs, dnamebuff);
lease_update_from_configs(dhcp_configs, domain_suffix); /* must follow cache_init and lease_init */
lease_update_file(0, now);
lease_update_dns();
}
setbuf(stdout, NULL);
@@ -248,7 +240,10 @@ int main (int argc, char **argv)
sprintf(packet, "infinite");
else
sprintf(packet, "%ds", (int)dhcp_tmp->lease_time);
syslog(LOG_INFO, "DHCP, IP range %s -- %s, lease time %s",
syslog(LOG_INFO,
dhcp_tmp->start.s_addr == dhcp_tmp->end.s_addr ?
"DHCP, static leases only on %.0s%s, lease time %s" :
"DHCP, IP range %s -- %s, lease time %s",
dnamebuff, inet_ntoa(dhcp_tmp->end), packet);
}
@@ -271,6 +266,8 @@ int main (int argc, char **argv)
cache_reload(options, dnamebuff, domain_suffix, addn_hosts);
if (dhcp)
{
if (options & OPT_ETHERS)
dhcp_configs = dhcp_read_ethers(dhcp_configs, dnamebuff);
dhcp_update_configs(dhcp_configs);
lease_update_from_configs(dhcp_configs, domain_suffix);
lease_update_file(0, now);
@@ -350,11 +347,17 @@ int main (int argc, char **argv)
if (last == 0 || difftime(now, last) > 1.0)
{
last = now;
#ifdef HAVE_ISC_READER
if (lease_file && !dhcp)
load_dhcp(lease_file, domain_suffix, now, dnamebuff);
#endif
if (!(options & OPT_NO_POLL))
{
struct resolvc *res = resolv, *latest = NULL;
time_t last_change = 0;
struct stat statbuf;
time_t last_change = 0;
/* There may be more than one possible file.
Go through and find the one which changed _last_.
Warn of any which can't be read. */

View File

@@ -238,15 +238,24 @@ struct dhcp_lease {
};
struct dhcp_config {
unsigned int flags;
int clid_len; /* length of client identifier */
unsigned char *clid; /* clientid */
unsigned char hwaddr[ETHER_ADDR_LEN];
char *hostname;
char *hostname, *netid;
struct in_addr addr;
unsigned int lease_time;
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
#define CONFIG_NETID 64
struct dhcp_opt {
int opt, len, is_addr;
unsigned char *val;
@@ -406,3 +415,7 @@ int dhcp_reply(struct dhcp_context *context,
char *domain_suffix, char *dhcp_file, char *dhcp_sname,
struct in_addr dhcp_next_server, struct in_addr router);
/* isc.c */
#ifdef HAVE_ISC_READER
void load_dhcp(char *file, char *suffix, time_t now, char *hostname);
#endif

249
src/isc.c Normal file
View File

@@ -0,0 +1,249 @@
/* dnsmasq is Copyright (c) 2000 - 2004 by 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.
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.
*/
/* Code in this file is based on contributions by John Volpe. */
#include "dnsmasq.h"
#ifdef HAVE_ISC_READER
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(char *file, char *suffix, time_t now, char *hostname)
{
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(file, &statbuf) == -1)
{
if (!logged_lease)
syslog(LOG_WARNING, "failed to access %s: %m", file);
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 (file, "r")))
{
syslog (LOG_ERR, "failed to load %s: %m", file);
return;
}
syslog (LOG_INFO, "reading %s", 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;
syslog(LOG_ERR, "bad name in %s", 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 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 (!suffix || hostname_isequal(dot+1, suffix))
{
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 = malloc(sizeof(struct isc_lease))))
{
lease->expires = ttd;
lease->addr = host_address;
lease->fqdn = NULL;
lease->next = leases;
if (!(lease->name = malloc(strlen(hostname)+1)))
free(lease);
else
{
leases = lease;
strcpy(lease->name, hostname);
if (suffix && (lease->fqdn = malloc(strlen(hostname) + strlen(suffix) + 2)))
{
strcpy(lease->fqdn, hostname);
strcat(lease->fqdn, ".");
strcat(lease->fqdn, 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)
{
if (lease->fqdn)
{
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires, F_REVERSE);
cache_add_dhcp_entry(lease->name, &lease->addr, lease->expires, 0);
}
else
cache_add_dhcp_entry(lease->name, &lease->addr, lease->expires, F_REVERSE);
}
}
#endif

View File

@@ -161,10 +161,10 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
{
int option = 0, i;
unsigned int flags = 0;
FILE *f = NULL;
char *conffile = CONFFILE;
FILE *file_save = NULL, *f = NULL;
char *file_name_save = NULL, *conffile = CONFFILE;
int conffile_set = 0;
int lineno = 0;
int line_save = 0, lineno = 0;
opterr = 0;
*min_leasetime = UINT_MAX;
@@ -179,26 +179,38 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
#endif
else
{ /* f non-NULL, reading from conffile. */
reread:
if (!fgets(buff, MAXDNAME, f))
{
/* At end of file, all done */
fclose(f);
if (file_save)
{
/* may be nested */
conffile = file_name_save;
f = file_save;
file_save = NULL;
lineno = line_save;
goto reread;
}
break;
}
else
{
char *p;
int white;
lineno++;
/* dump comments */
for (p = buff; *p; p++)
if (*p == '#')
*p = 0;
for (white = 1, p = buff; *p; p++)
if (white && *p == '#')
{
*p = 0;
break;
}
else
white = isspace(*p);
/* fgets gets end of line char too. */
while (strlen(buff) > 0 &&
(buff[strlen(buff)-1] == '\n' ||
buff[strlen(buff)-1] == ' ' ||
buff[strlen(buff)-1] == '\r' ||
buff[strlen(buff)-1] == '\t'))
while (strlen(buff) > 0 && isspace(buff[strlen(buff)-1]))
buff[strlen(buff)-1] = 0;
if (*buff == 0)
continue;
@@ -227,6 +239,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
{ /* end of command line args, start reading conffile. */
if (!conffile)
break; /* "confile=" option disables */
fileopen:
option = 0;
if (!(f = fopen(conffile, "r")))
{
@@ -274,9 +287,27 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
switch (option)
{
case 'C':
if (!f)
{
conffile = safe_string_alloc(optarg);
conffile_set = 1;
break;
}
/* nest conffiles one deep */
if (file_save)
{
sprintf(buff, "nested includes not allowed at line %d of %s ", lineno, conffile);
complain(buff, NULL);
continue;
}
file_name_save = conffile;
file_save = f;
line_save = lineno;
conffile = safe_string_alloc(optarg);
conffile_set = 1;
break;
lineno = 0;
goto fileopen;
case 'x':
*runfile = safe_string_alloc(optarg);
@@ -643,11 +674,15 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
*(a[k]++) = 0;
}
if ((k < 2) ||
((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1) ||
((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1))
if ((k < 2) || ((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1))
option = '?';
else if (strcmp(a[1], "static") == 0)
new->end = new->start;
else if ((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1)
option = '?';
if (option == '?')
{
option = '?';
free(new);
break;
}
@@ -700,22 +735,17 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
case 'G':
{
int j, k;
char *a[4] = { NULL, NULL, NULL, NULL };
char *a[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
unsigned int e0, e1, e2, e3, e4, e5;
struct dhcp_config *new = safe_malloc(sizeof(struct dhcp_config));
struct in_addr in;
new->next = *dhcp_conf;
new->flags = 0;
memset(new->hwaddr, 0, ETHER_ADDR_LEN);
new->clid_len = 0;
new->clid = NULL;
new->hostname = NULL;
new->addr.s_addr = 0;
new->lease_time = 0;
a[0] = optarg;
for (k = 1; k < 4; k++)
for (k = 1; k < 6; k++)
{
if (!(a[k] = strchr(a[k-1], ',')))
break;
@@ -723,37 +753,60 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
}
for(j = 0; j < k; j++)
if (strchr(a[j], ':')) /* ethernet address or binary CLID */
if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
{
char *arg = a[j];
if ((arg[0] == 'i' || arg[0] == 'I') &&
(arg[1] == 'd' || arg[1] == 'D') &&
arg[2] == ':')
{
int s, len;
int len;
arg += 3; /* dump id: */
if (strchr(arg, ':'))
{
s = (strlen(arg)/3) + 1;
/* decode in place */
for (len = 0; len < s; len++)
/* decode hex in place */
char *p = arg, *q = arg, *r;
while (*p)
{
if (arg[(len*3)+2] != ':')
option = '?';
arg[(len*3)+2] = 0;
arg[len] = strtol(&arg[len*3], NULL, 16);
for (r = p; *r && *r != ':'; r++);
if (*r)
{
if (r != p)
{
*r = 0;
*(q++) = strtol(p, NULL, 16);
}
p = r+1;
}
else
{
if (*p)
*(q++) = strtol(p, NULL, 16);
break;
}
}
len = q - arg;
}
else
len = strlen(arg);
new->flags |= CONFIG_CLID;
new->clid_len = len;
new->clid = safe_malloc(len);
memcpy(new->clid, arg, len);
}
else if ((arg[0] == 'n' || arg[0] == 'N') &&
(arg[1] == 'e' || arg[1] == 'E') &&
(arg[2] == 't' || arg[3] == 'T') &&
arg[3] == ':')
{
new->flags |= CONFIG_NETID;
new->netid = safe_string_alloc(arg+4);
}
else if (sscanf(a[j], "%x:%x:%x:%x:%x:%x",
&e0, &e1, &e2, &e3, &e4, &e5) == 6)
{
new->flags |= CONFIG_HWADDR;
new->hwaddr[0] = e0;
new->hwaddr[1] = e1;
new->hwaddr[2] = e2;
@@ -765,7 +818,10 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
option = '?';
}
else if (strchr(a[j], '.') && (in.s_addr = inet_addr(a[j])) != (in_addr_t)-1)
new->addr = in;
{
new->addr = in;
new->flags |= CONFIG_ADDR;
}
else
{
char *cp, *lastp = NULL, last = 0;
@@ -800,19 +856,38 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
if (lastp)
*lastp = last;
if (strcmp(a[j], "infinite") == 0)
new->lease_time = 0xffffffff;
{
new->lease_time = 0xffffffff;
new->flags |= CONFIG_TIME;
}
else if (strcmp(a[j], "ignore") == 0)
new->flags |= CONFIG_DISABLE;
else
new->hostname = safe_string_alloc(a[j]);
{
new->hostname = safe_string_alloc(a[j]);
new->flags |= CONFIG_NAME;
}
}
else
new->lease_time = atoi(a[j]) * fac;
{
new->lease_time = atoi(a[j]) * fac;
new->flags |= CONFIG_TIME;
}
}
if (option == '?')
free(new);
{
if (new->flags & CONFIG_NAME)
free(new->hostname);
if (new->flags & CONFIG_CLID)
free(new->clid);
if (new->flags & CONFIG_NETID)
free(new->netid);
free(new);
}
else
{
if (new->lease_time < *min_leasetime)
if ((new->flags & CONFIG_TIME) && new->lease_time < *min_leasetime)
*min_leasetime = new->lease_time;
*dhcp_conf = new;
}
@@ -823,7 +898,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
{
struct dhcp_opt *new = safe_malloc(sizeof(struct dhcp_opt));
char *cp, *comma;
int addrs, is_addr;
int addrs, digs, is_addr, is_hex, is_dec;
new->next = *dhcp_opts;
new->len = 0;
@@ -854,57 +929,112 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
break;
}
*dhcp_opts = new;
if (!comma)
{
*dhcp_opts = new;
break;
}
break;
/* check for non-address list characters */
for (addrs = 1, is_addr = 0, cp = comma+1; *cp; cp++)
/* characterise the value */
is_addr = is_hex = is_dec = 1;
addrs = digs = 1;
for (cp = comma+1; *cp; cp++)
if (*cp == ',')
addrs++;
else if (!(*cp == '.' || *cp == ' ' || (*cp >='0' && *cp <= '9')))
break;
{
addrs++;
is_dec = is_hex = 0;
}
else if (*cp == ':')
{
digs++;
is_dec = is_addr = 0;
}
else if (*cp == '.')
is_addr = 1;
is_dec = is_hex = 0;
else if (!(*cp >='0' && *cp <= '9'))
{
is_dec = is_addr = 0;
if (!((*cp >='A' && *cp <= 'F') ||
(*cp >='a' && *cp <= 'F')))
is_hex = 0;
}
if (*cp)
if (is_hex && digs > 1)
{
char *p = comma+1, *q, *r;
new->len = digs;
q = new->val = safe_malloc(new->len);
while (*p)
{
for (r = p; *r && *r != ':'; r++);
if (*r)
{
if (r != p)
{
*r = 0;
*(q++) = strtol(p, NULL, 16);
}
p = r+1;
}
else
{
if (*p)
*(q++) = strtol(p, NULL, 16);
break;
}
}
}
else if (is_dec)
{
/* Given that we don't know the length,
this applaing hack is the best available */
unsigned int val = atoi(comma+1);
if (val < 256)
{
new->len = 1;
new->val = safe_malloc(1);
*(new->val) = val;
}
else if (val < 65536)
{
new->len = 2;
new->val = safe_malloc(2);
*(new->val) = val>>8;
*(new->val+1) = val;
}
else
{
new->len = 4;
new->val = safe_malloc(4);
*(new->val) = val>>24;
*(new->val+1) = val>>16;
*(new->val+2) = val>>8;
*(new->val+3) = val;
}
}
else if (is_addr)
{
struct in_addr in;
unsigned char *op;
new->len = INADDRSZ * addrs;
new->val = op = safe_malloc(new->len);
new->is_addr = 1;
while (addrs--)
{
cp = comma;
if ((comma = strchr(cp+1, ',')))
*comma = 0;
in.s_addr = inet_addr(cp+1);
memcpy(op, &in, INADDRSZ);
op += INADDRSZ;
}
}
else
{
/* text arg */
new->len = strlen(comma+1);
new->val = safe_malloc(new->len);
memcpy(new->val, comma+1, new->len);
}
else
{
struct in_addr in;
unsigned char *op;
if (addrs == 1 && !is_addr)
{
new->len = 1;
new->val = safe_malloc(1);
*(new->val) = atoi(comma+1);
}
else
{
new->len = INADDRSZ * addrs;
new->val = op = safe_malloc(new->len);
new->is_addr = 1;
while (addrs--)
{
cp = comma;
if (cp && (comma = strchr(cp+1, ',')))
*comma = 0;
if (cp && (in.s_addr = inet_addr(cp+1)) == (in_addr_t)-1)
option = '?';
memcpy(op, &in, INADDRSZ);
op += INADDRSZ;
}
}
}
*dhcp_opts = new;
break;
}

View File

@@ -63,8 +63,12 @@ static unsigned char *do_req_options(struct dhcp_context *context,
char *domainname, char *hostname,
struct in_addr router,
struct in_addr iface_addr,
int iface_mtu);
int iface_mtu, char *netid);
static int have_config(struct dhcp_config *config, unsigned int mask)
{
return config && (config->flags & mask);
}
int dhcp_reply(struct dhcp_context *context,
struct in_addr iface_addr,
@@ -88,13 +92,27 @@ int dhcp_reply(struct dhcp_context *context,
char *message = NULL;
unsigned int renewal_time, expires_time, def_time;
struct dhcp_config *config;
char *netid;
if (mess->op != BOOTREQUEST ||
mess->htype != ARPHRD_ETHER ||
mess->hlen != ETHER_ADDR_LEN ||
mess->cookie != htonl(DHCP_COOKIE))
return 0;
/* Token ring is supported when we have packet sockets
to make the HW headers for us. We don't have the code to build
token ring headers when using BPF. We rely on the fact that
token ring hwaddrs are the same size as ethernet hwaddrs. */
#ifdef HAVE_BPF
if (mess->htype != ARPHRD_ETHER)
return 0;
#else
if (mess->htype != ARPHRD_ETHER &&
mess->htype != ARPHRD_IEEE802)
return 0;
#endif
mess->op = BOOTREPLY;
if ((opt = option_find(mess, sz, OPTION_MAXMESSAGE)))
@@ -132,7 +150,7 @@ int dhcp_reply(struct dhcp_context *context,
}
if ((config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, NULL)) &&
config->hostname)
have_config(config, CONFIG_NAME))
hostname = config->hostname;
else if ((opt = option_find(mess, sz, OPTION_HOSTNAME)))
{
@@ -164,7 +182,8 @@ int dhcp_reply(struct dhcp_context *context,
/* search again now we have a hostname */
config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, hostname);
def_time = config && config->lease_time ? config->lease_time : context->lease_time;
def_time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
netid = have_config(config, CONFIG_NETID) ? config->netid : context->netid;
if ((opt = option_find(mess, sz, OPTION_LEASE_TIME)))
{
@@ -219,11 +238,11 @@ int dhcp_reply(struct dhcp_context *context,
if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
lease_prune(lease, now);
if (config && config->addr.s_addr &&
if (have_config(config, CONFIG_ADDR) &&
config->addr.s_addr == option_addr(opt).s_addr)
{
syslog(LOG_WARNING, "disabling DHCP static address %s", inet_ntoa(config->addr));
config->addr.s_addr = 0;
config->flags &= ~CONFIG_ADDR ;
}
return 0;
@@ -244,9 +263,9 @@ int dhcp_reply(struct dhcp_context *context,
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
mess->yiaddr = option_addr(opt);
log_packet("DISCOVER", opt ? &mess->yiaddr : NULL, mess->chaddr, iface_name, NULL);
if (config && config->addr.s_addr && !lease_find_by_addr(config->addr))
if (have_config(config, CONFIG_DISABLE))
message = "ignored";
else if (have_config(config, CONFIG_ADDR) && !lease_find_by_addr(config->addr))
mess->yiaddr = config->addr;
else if (lease &&
((lease->addr.s_addr & context->netmask.s_addr) ==
@@ -254,10 +273,11 @@ int dhcp_reply(struct dhcp_context *context,
mess->yiaddr = lease->addr;
else if ((!opt || !address_available(context, mess->yiaddr)) &&
!address_allocate(context, dhcp_configs, &mess->yiaddr))
{
syslog(LOG_WARNING, "address pool exhausted");
return 0;
}
message = "no address available";
log_packet("DISCOVER", opt ? &mess->yiaddr : NULL, mess->chaddr, iface_name, message);
if (message)
return 0;
bootp_option_put(mess, dhcp_file, dhcp_sname);
mess->siaddr = dhcp_next_server;
@@ -265,7 +285,7 @@ int dhcp_reply(struct dhcp_context *context,
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 = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix,
NULL, router, iface_addr, iface_mtu);
NULL, router, iface_addr, iface_mtu, netid);
p = option_put(p, end, OPTION_END, 0, 0);
log_packet("OFFER" , &mess->yiaddr, mess->chaddr, iface_name, NULL);
@@ -297,7 +317,7 @@ int dhcp_reply(struct dhcp_context *context,
if (!lease)
{
if (!address_available(context, mess->yiaddr) &&
(!config || config->addr.s_addr == 0 || config->addr.s_addr != mess->yiaddr.s_addr))
(!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
message = "address unavailable";
else if (!(lease = lease_allocate(clid, clid_len, mess->yiaddr)))
message = "no leases left";
@@ -319,6 +339,9 @@ int dhcp_reply(struct dhcp_context *context,
if ((mess->yiaddr.s_addr & context->netmask.s_addr) != (context->start.s_addr & context->netmask.s_addr))
message = "wrong network";
if (have_config(config, CONFIG_DISABLE))
message = "disabled";
log_packet("REQUEST", &mess->yiaddr, mess->chaddr, iface_name, NULL);
if (message)
@@ -354,17 +377,23 @@ int dhcp_reply(struct dhcp_context *context,
p = option_put(p, end, OPTION_T2, 4, ((renewal_time * 7)/8) - fuzz);
}
p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix,
hostname, router, iface_addr, iface_mtu);
hostname, router, iface_addr, iface_mtu, netid);
p = option_put(p, end, OPTION_END, 0, 0);
return p - (unsigned char *)mess;
case DHCPINFORM:
if (have_config(config, CONFIG_DISABLE))
{
log_packet("INFORM", &mess->ciaddr, mess->chaddr, iface_name, "ignored");
return 0;
}
log_packet("INFORM", &mess->ciaddr, mess->chaddr, iface_name, NULL);
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 = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix,
hostname, router, iface_addr, iface_mtu);
hostname, router, iface_addr, iface_mtu, netid);
p = option_put(p, end, OPTION_END, 0, 0);
log_packet("ACK", &mess->ciaddr, mess->chaddr, iface_name, hostname);
@@ -524,11 +553,11 @@ static int in_list(unsigned char *list, int opt)
return 0;
}
static struct dhcp_opt *option_find2(struct dhcp_context *context, struct dhcp_opt *opts, int opt)
static struct dhcp_opt *option_find2(char *netid, struct dhcp_opt *opts, int opt)
{
for (; opts; opts = opts->next)
if (opts->opt == opt &&
(!opts->netid || (context->netid && strcmp(opts->netid, context->netid) == 0)))
(!opts->netid || (netid && strcmp(opts->netid, netid) == 0)))
return opts;
return NULL;
}
@@ -540,7 +569,7 @@ static unsigned char *do_req_options(struct dhcp_context *context,
char *domainname, char *hostname,
struct in_addr router,
struct in_addr iface_addr,
int iface_mtu)
int iface_mtu, char *netid)
{
int i;
@@ -553,24 +582,24 @@ static unsigned char *do_req_options(struct dhcp_context *context,
iface_mtu : DNSMASQ_PACKETSZ);
if (in_list(req_options, OPTION_NETMASK) &&
!option_find2(context, config_opts, OPTION_NETMASK))
!option_find2(netid, config_opts, OPTION_NETMASK))
p = option_put(p, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
if (in_list(req_options, OPTION_BROADCAST) &&
!option_find2(context, config_opts, OPTION_BROADCAST))
!option_find2(netid, config_opts, OPTION_BROADCAST))
p = option_put(p, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
if (in_list(req_options, OPTION_ROUTER) &&
!option_find2(context, config_opts, OPTION_ROUTER))
!option_find2(netid, config_opts, OPTION_ROUTER))
p = option_put(p, end, OPTION_ROUTER, INADDRSZ,
ntohl(router.s_addr));
if (in_list(req_options, OPTION_DNSSERVER) &&
!option_find2(context, config_opts, OPTION_DNSSERVER))
!option_find2(netid, config_opts, OPTION_DNSSERVER))
p = option_put(p, end, OPTION_DNSSERVER, INADDRSZ, ntohl(iface_addr.s_addr));
if (domainname && in_list(req_options, OPTION_DOMAINNAME) &&
!option_find2(context, config_opts, OPTION_DOMAINNAME))
!option_find2(netid, config_opts, OPTION_DOMAINNAME))
p = option_put_string(p, end, OPTION_DOMAINNAME, domainname);
/* Note that we ignore attempts to set the hostname using
@@ -580,38 +609,49 @@ static unsigned char *do_req_options(struct dhcp_context *context,
for (i = 0; req_options[i] != OPTION_END; i++)
{
struct dhcp_opt *opt = option_find2(context, config_opts, req_options[i]);
if (req_options[i] != OPTION_HOSTNAME &&
req_options[i] != OPTION_MAXMESSAGE &&
opt && (p + opt->len + 3 < end))
struct dhcp_opt *opt;
if (req_options[i] == OPTION_HOSTNAME ||
req_options[i] == OPTION_MAXMESSAGE ||
!(opt = option_find2(netid, config_opts, req_options[i])) ||
(p + opt->len + 3 >= end))
continue;
/* For the options we have default values on
dhc-option=<optionno> means "don't include this option"
not "include a zero-length option" */
if (opt->len == 0 &&
(opt->opt == OPTION_NETMASK ||
opt->opt == OPTION_BROADCAST ||
opt->opt == OPTION_ROUTER ||
opt->opt == OPTION_DNSSERVER))
continue;
*(p++) = opt->opt;
*(p++) = opt->len;
if (opt->len == 0)
continue;
if (opt->is_addr)
{
*(p++) = opt->opt;
*(p++) = opt->len;
if (opt->len != 0)
int j;
struct in_addr *a = (struct in_addr *)opt->val;
for (j = 0; j < opt->len; j+=INADDRSZ, a++)
{
if (opt->is_addr)
{
int j;
struct in_addr *a = (struct in_addr *)opt->val;
for (j = 0; j < opt->len; j+=INADDRSZ, a++)
{
/* zero means "self" */
if (a->s_addr == 0)
memcpy(p, &iface_addr, INADDRSZ);
else
memcpy(p, a, INADDRSZ);
p += INADDRSZ;
}
}
/* zero means "self" */
if (a->s_addr == 0)
memcpy(p, &iface_addr, INADDRSZ);
else
{
memcpy(p, opt->val, opt->len);
p += opt->len;
}
memcpy(p, a, INADDRSZ);
p += INADDRSZ;
}
}
else
{
memcpy(p, opt->val, opt->len);
p += opt->len;
}
}
return p;
}