summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2004-01-29 16:48:35 +0000
committerSimon Kelley <simon@thekelleys.org.uk>2012-01-05 17:31:10 +0000
commit1ab84e2f3579b1bcd6b881c10bacfa735e3c5008 (patch)
treee27af20d527853729d50756aca9d04ac2343acbd
parent9e4abcb5acb18aa1adbc22bfc3ce60e9441b02ef (diff)
downloaddnsmasq-2.1.tar.gz
import of dnsmasq-2.1.tar.gzv2.1
-rw-r--r--CHANGELOG48
-rw-r--r--FAQ28
-rw-r--r--UPGRADING_to_2.06
-rw-r--r--dnsmasq-mdk.spec2
-rw-r--r--dnsmasq-rh.spec2
-rw-r--r--dnsmasq-suse.spec4
-rw-r--r--dnsmasq.810
-rw-r--r--dnsmasq.conf.example59
-rw-r--r--rpm/README.susefirewall27
-rw-r--r--src/cache.c9
-rw-r--r--src/config.h2
-rw-r--r--src/dhcp.c15
-rw-r--r--src/dnsmasq.c2
-rw-r--r--src/dnsmasq.h7
-rw-r--r--src/forward.c1
-rw-r--r--src/network.c143
-rw-r--r--src/option.c64
-rw-r--r--src/rfc2131.c33
18 files changed, 356 insertions, 106 deletions
diff --git a/CHANGELOG b/CHANGELOG
index a86b333..467b653 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -666,4 +666,50 @@ release 2.0
domains and IPv6 queries. Thanks to Roy Marples for
helping to track that one down.
-
+release 2.1
+ Tweak include files to allow compilation on FreeBSD 5
+
+ Fix unaligned access warnings on BSD/Alpha.
+
+ Allow empty DHCP options, like so: dhpc-option=44
+
+ Allow single-byte DHCP options like so: dhcp-option=20,1
+
+ Allow comments on the same line as options in
+ /etc/dnsmasq.conf
+
+ Don't complain when the same name and address is
+ allocated to a host using DHCP and /etc/hosts.
+
+ Added to the example configuration the dnsmasq equivalent
+ of the ISC dhcpd settings given in
+ http://www.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt
+
+ Fixed long-existing strangeness in Linux IPv6 interface
+ discovery code. The flags field in /proc/net/if_inet6 is
+ _not_ the interface flags.
+
+ Fail gracefully when getting an ENODEV error when trying
+ to bind an IPv6 socket, rather than bailing out.
+
+ Allow the name->address mapping for static DHCP leases to
+ be set by /etc/hosts. It's now possible to have
+ dhcp-host=<mac addr>,wibble
+ or even
+ dhcp-host=wibble
+ and in /etc/hosts have
+ wibble 1.2.3.4
+ and for the correct thing to happen. Note that some sort
+ of dhcp-host line is still needed, it's not possible for
+ random host to claim an address in /etc/hosts without
+ some explicit configuration.
+
+ Make 0.0.0.0 in a dhcp-option to mean "the machine
+ running dnsmasq".
+
+ Fix lease time spec when specified in dhcp-range and not
+ in dhcp-host, previously this was always one hour.
+
+ Fix problem with setting domains as "local only".
+
+ Added support for max message size DHCP option.
diff --git a/FAQ b/FAQ
index 94af7d1..cbf7a66 100644
--- a/FAQ
+++ b/FAQ
@@ -154,6 +154,34 @@ A: [note: this was written in September 2003, things may well change.]
registries pull the same stunt; there is a list of them all, and
the addresses to block, at http://winware.org/bogus-domains.txt
+Q: This new DHCP server is well and good, but it doesn't work for me.
+ What's the problem?
+
+A: There are a couple of configuration gotchas which have been
+ encountered by people moving from the ISC dhcpd to the dnsmasq
+ integrated DHCP daemon. Both are related to differences in
+ in the way the two daemons bypass the IP stack to do "ground up"
+ IP configuration and can lead to the dnsmasq daemon failing
+ whilst the ISC one works.
+
+ The first thing to check is the broadcast address set for the
+ ethernet interface. This is normally the adddress on the connected
+ network with all ones in the host part. For instance if the
+ address of the ethernet interface is 192.168.55.7 and the netmask
+ is 255.255.255.0 then the broadcast address should be
+ 192.168.55.255. Having a broadcast address which is not on the
+ network to which the interface is connected kills things stone
+ dead.
+
+ The second potential problem relates to firewall rules: since the ISC
+ daemon in some configurations bypasses the kernel firewall rules
+ entirely, the ability to run the ISC daemon does not indicate
+ that the current configuration is OK for the dnsmasq daemon.
+ For the dnsmasq daemon to operate it's vital that UDP packets to
+ and from ports 67 and 68 and broadcast packets with source
+ address 0.0.0.0 and destination address 255.255.255.255 are not
+ dropped by iptables/ipchains.
+
diff --git a/UPGRADING_to_2.0 b/UPGRADING_to_2.0
index d17940c..e1204fa 100644
--- a/UPGRADING_to_2.0
+++ b/UPGRADING_to_2.0
@@ -40,7 +40,7 @@ to store its leases it is necessary to remove the configuration line in
To enable DHCP, simply add a line like this to /etc/dnsmasq.conf
-dhcp-range=192.168.0.100,192,168.0.200,12h
+dhcp-range=192.168.0.100,192.168.0.200,12h
which tells dnsmasq to us the addresses 192.168.0.100 to 192.168.0.200
for dynamic IP addresses, and to issue twelve hour leases.
@@ -60,6 +60,8 @@ Windows use winipcfg.exe
For more complex DHCP configuration, refer to the doc/setup.html, the
-dnsmasq manpage and the annotated example configuration file.
+dnsmasq manpage and the annotated example configuration file. Also
+note that for some ISC dhcpd to dnsmasq DHCP upgrades there may be
+firewall issues: see the FAQ for details of this.
diff --git a/dnsmasq-mdk.spec b/dnsmasq-mdk.spec
index 5ec3664..3829703 100644
--- a/dnsmasq-mdk.spec
+++ b/dnsmasq-mdk.spec
@@ -5,7 +5,7 @@
###############################################################################
Name: dnsmasq
-Version: 2.0
+Version: 2.1
Release: 1
Copyright: GPL
Group: System Environment/Daemons
diff --git a/dnsmasq-rh.spec b/dnsmasq-rh.spec
index 2114ac5..16cb3e6 100644
--- a/dnsmasq-rh.spec
+++ b/dnsmasq-rh.spec
@@ -5,7 +5,7 @@
###############################################################################
Name: dnsmasq
-Version: 2.0
+Version: 2.1
Release: 1
Copyright: GPL
Group: System Environment/Daemons
diff --git a/dnsmasq-suse.spec b/dnsmasq-suse.spec
index 1961942..4a811b6 100644
--- a/dnsmasq-suse.spec
+++ b/dnsmasq-suse.spec
@@ -5,7 +5,7 @@
###############################################################################
Name: dnsmasq
-Version: 2.0
+Version: 2.1
Release: 1
Copyright: GPL
Group: Productivity/Networking/DNS/Servers
@@ -100,7 +100,7 @@ rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
-%doc CHANGELOG COPYING FAQ doc.html setup.html UPGRADING_to_2.0
+%doc CHANGELOG COPYING FAQ doc.html setup.html UPGRADING_to_2.0 rpm/README.susefirewall
%config /etc/init.d/dnsmasq
%config /etc/dnsmasq.conf
/usr/sbin/rcdnsmasq
diff --git a/dnsmasq.8 b/dnsmasq.8
index af4cd29..69f12b5 100644
--- a/dnsmasq.8
+++ b/dnsmasq.8
@@ -251,7 +251,7 @@ an infinite DHCP lease.
.B --dhcp-host=lap,192.168.0.199
tells
dnsmasq to always allocate the machine lap the IP address
-192.168.0.199. Addresses allocated like this are not contrained to be
+192.168.0.199. Addresses allocated like this are not constrained to be
in the range given by the --dhcp-range option, but they must be on the
network being served by the DHCP server. It is allowed to use client identifiers rather than
hardware addresses to identify hosts by prefixing with 'id:'. Thus:
@@ -259,8 +259,12 @@ hardware addresses to identify hosts by prefixing with 'id:'. Thus:
refers to the host with client identifier 01:02:03:04. It is also
allowed to specify the client ID as text, like this:
.B --dhcp-host=id:clientidastext,.....
+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.
.TP
-.B \-O, --dhcp-option=<opt>,<value>[,<value>]
+.B \-O, --dhcp-option=<opt>,[<value>[,<value>]]
Specfify different or extra options to DHCP clients. By default,
dnsmasq sends some standard options to DHCP clients, the netmask and
broadcast address are set to the same as the host running dnsmasq, and
@@ -273,6 +277,8 @@ specfied in RFC2132. For example, to set the default route option to
.B --dhcp-option=3,192.168.4.4
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".
Be careful: no checking is done that the correct type of data for the
option number is sent, and there are option numbers for which it is not
possible to generate the correct data type; it is quite possible to
diff --git a/dnsmasq.conf.example b/dnsmasq.conf.example
index 72e9cf6..7fbe669 100644
--- a/dnsmasq.conf.example
+++ b/dnsmasq.conf.example
@@ -31,6 +31,13 @@ filterwin2k
# somewhere other that /etc/resolv.conf
#resolv-file=
+# By default, dnsmasq will send queries to any of the upstream
+# servers it knows about and tries to favour servers to are known
+# to be up. Uncommenting this forces dnsmasq to try each query
+# with each server strictly in the order they appear in
+# /etc/resolv.conf
+#strict-order
+
# If you don't want dnsmasq to read /etc/resolv.conf or any other
# file, getting its servers for this file instead (see below), then
# uncomment this
@@ -88,9 +95,10 @@ filterwin2k
#dhcp-range=192.168.0.50,192.168.0.150,12h
# Supply parameters for specified hosts using DHCP. There are lots
-# of valid alternatives, do we will give examples of each. Note that
+# of valid alternatives, so we will give examples of each. Note that
# IP addresses DO NOT have to be in the range given above, they just
-# need to be on the same network.
+# need to be on the same network. The order of the parameters in these
+# do not matter, it's permissble to give name,adddress and MAC in any order
# Always allocate the host with ethernet address 11:22:33:44:55:66
# The IP address 192.168.0.60
@@ -116,15 +124,54 @@ filterwin2k
# the IP address 192.168.0.60
#dhcp-host=id:marjorie,192.168.0.60
+# Enable the address given for "judge" in /etc/hosts
+# to be given to a machine presenting the name "judge" when
+# it asks for a DHCP lease.
+#dhcp-host=judge
+
# Send options to hosts which ask for a DHCP lease.
# See RFC 2132 for details of available options.
+# Note that all the common settings, such as netmask and
+# broadcast address, DNS server and default route, are given
+# sane defaults by dnsmasq. You very likely will not need any
+# any dhcp-options. If you use Windows clients and Samba, there
+# are some options which are recommended, they are detailed at the
+# end of this section.
+# For reference, the common options are:
+# subnet mask - 1
+# default router - 3
+# DNS server - 6
+# broadcast address - 28
# Set the NTP time server addresses to 192.168.0.4 and 10.10.0.5
#dhcp-option=42,192.168.0.4,10.10.0.5
+# Set the NTP time server address to be the same machine as
+# is running dnsmasq
+#dhcp-option=42,0.0.0.0
+
# Set the NIS domain name to "welly"
#dhcp-option=40,welly
+# Set the default time-to-live to 50
+#dhcp-option=23,50
+
+# Set the "all subnets are local" flag
+#dhcp-option=27,1
+
+# The following DHCP options set up dnsmasq in the same way as is specified
+# for the ISC dhcpcd in
+# http://www.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt
+# adapted for a typical dnsmasq installation where the host running
+# dnsmasq is also the host running samba.
+# you may want to uncomment them if you use Windows clients and Samba.
+#dhcp-option=19,0 # option ip-forwarding off
+#dhcp-option=44,0.0.0.0 # set netbios-over-TCP/IP nameserver(s) aka WINS server(s)
+#dhcp-option=45,0.0.0.0 # netbios datagram distribution server
+#dhcp-option=46,8 # netbios node type
+#dhcp-option=47 # empty netbios scope.
+
+
# Set the boot filename and tftpd server name and address
# for BOOTP. You will only need this is you want to
# boot machines over the network.
@@ -133,14 +180,10 @@ filterwin2k
# The DHCP server needs somewhere on disk to keep its lease database.
# This defaults to a sane location, but if you want to change it, use
# the line below.
-#dhcp-leasefile=/var/lib/dnsmasq/leases
-
-# Override the default route (which is normally automagically set
-# to be the machine running dnsmasq
-#dhcp-option=2,192,168.4.4
+#dhcp-leasefile=/var/lib/misc/dnsmasq.leases
# Set the cachesize here.
-#cache-size=600
+#cache-size=150
# If you want to disable negative caching, uncomment this.
#no-negcache
diff --git a/rpm/README.susefirewall b/rpm/README.susefirewall
new file mode 100644
index 0000000..2f19ca6
--- /dev/null
+++ b/rpm/README.susefirewall
@@ -0,0 +1,27 @@
+This is a patch against SuSEfirewall2-3.1-206 (SuSE 9.x and older)
+It fixes the depancy from the dns daemon name 'named'
+After appending the patch, the SuSEfirewall is again able to autodetect
+the dnsmasq named service.
+This is a very old bug in the SuSEfirewall script.
+The SuSE people think the name of the dns server will allways 'named'
+
+
+--- /sbin/SuSEfirewall2.orig 2004-01-23 13:30:09.000000000 +0100
++++ /sbin/SuSEfirewall2 2004-01-23 13:31:56.000000000 +0100
+@@ -764,7 +764,7 @@
+ echo 'FW_ALLOW_INCOMING_HIGHPORTS_UDP should be set to yes, if you are running a DNS server!'
+
+ test "$FW_SERVICE_AUTODETECT" = yes -o "$FW_SERVICE_AUTODETECT" = dmz -o "$FW_SERVICE_AUTODETECT" = ext && {
+- test "$FW_SERVICE_DNS" = no -a '!' "$START_NAMED" = no && check_srv named && {
++ test "$FW_SERVICE_DNS" = no -a '!' "$START_NAMED" = no && check_srv dnsmasq && {
+ echo -e 'Warning: detected activated named, enabling FW_SERVICE_DNS!
+ You still have to allow tcp/udp port 53 on internal, dmz and/or external.'
+ FW_SERVICE_DNS=$FW_SERVICE_AUTODETECT
+@@ -878,7 +878,7 @@
+ test -e /etc/resolv.conf || echo "Warning: /etc/resolv.conf not found"
+ # Get ports/IP bindings of NAMED/SQUID
+ test "$FW_SERVICE_DNS" = yes -o "$FW_SERVICE_DNS" = dmz -o "$FW_SERVICE_DNS" = ext -o "$START_NAMED" = yes && DNS_PORT=`$LSOF -i -n -P | \
+- $AWK -F: '/^named .* UDP / {print $2}'| $GREP -vw 53 | $SORT -un`
++ $AWK -F: '/^dnsmasq .* UDP / {print $2}'| $GREP -vw 53 | $SORT -un`
+ test "$FW_SERVICE_SQUID" = yes -o "$FW_SERVICE_SQUID" = dmz -o "$FW_SERVICE_SQUID" = ext -o "$START_SQUID" = yes && SQUID_PORT=`$LSOF -i -n -P | \
+ $AWK -F: '/^squid .* UDP/ {print $2}'| $SORT -un`
diff --git a/src/cache.c b/src/cache.c
index 948207e..7a78d7e 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -639,7 +639,10 @@ void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t
if ((crec = cache_find_by_name(NULL, host_name, 0, F_IPV4)))
{
if (crec->flags & F_HOSTS)
- syslog(LOG_WARNING, "Ignoring DHCP lease for %s because it clashes with an /etc/hosts entry.", host_name);
+ {
+ if (crec->addr.addr.addr4.s_addr != host_address->s_addr)
+ syslog(LOG_WARNING, "Not naming DHCP lease for %s because it clashes with an /etc/hosts entry.", host_name);
+ }
else if (!(crec->flags & F_DHCP))
{
if (crec->flags & F_NEG)
@@ -650,7 +653,7 @@ void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t
goto newrec;
}
else
- syslog(LOG_WARNING, "Ignoring DHCP lease for %s because it clashes with a cached name.", cache_get_name(crec));
+ syslog(LOG_WARNING, "Not naming DHCP lease for %s because it clashes with a cached name.", cache_get_name(crec));
}
return;
}
@@ -671,7 +674,7 @@ void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t
crec->flags |= F_IMMORTAL;
else
crec->ttd = ttd;
- memcpy(&crec->addr, host_address, INADDRSZ);
+ crec->addr.addr.addr4 = *host_address;
crec->name.namep = host_name;
crec->prev = dhcp_inuse;
dhcp_inuse = crec;
diff --git a/src/config.h b/src/config.h
index 07f7b5f..39d2375 100644
--- a/src/config.h
+++ b/src/config.h
@@ -12,7 +12,7 @@
/* Author's email: simon@thekelleys.org.uk */
-#define VERSION "2.0"
+#define VERSION "2.1"
#define FTABSIZ 150 /* max number of outstanding requests */
#define TIMEOUT 40 /* drop queries after TIMEOUT seconds */
diff --git a/src/dhcp.c b/src/dhcp.c
index cbc8bbf..102d1a7 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -269,5 +269,18 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
return NULL;
}
-
+void set_configs_from_cache(struct dhcp_config *configs)
+/* Some people like to keep all static IP addresses in /etc/hosts.
+ This goes through /etc/hosts and sets static addresses for any DHCP config
+ records which don't have an address and whose name matches. */
+{
+ struct dhcp_config *config;
+ struct crec *crec;
+
+ for (config = configs; config; config = config->next)
+ if (config->addr.s_addr == 0 && config->hostname &&
+ (crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
+ (crec->flags & F_HOSTS))
+ config->addr = crec->addr.addr.addr4;
+}
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index 2a7615b..99cbed0 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -158,6 +158,7 @@ int main (int argc, char **argv)
if (!dhcp_tmp->iface)
die("No suitable interface for DHCP service at address %s", inet_ntoa(dhcp_tmp->start));
+ set_configs_from_cache(dhcp_configs);
leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, time(NULL), dhcp_configs);
lease_update_dns(1); /* must follow cache_init and lease_init */
}
@@ -270,6 +271,7 @@ int main (int argc, char **argv)
if (sighup)
{
cache_reload(options, dnamebuff, domain_suffix, addn_hosts);
+ set_configs_from_cache(dhcp_configs);
lease_update_dns(1);
if (resolv && (options & OPT_NO_POLL))
servers = last_server =
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index ba50040..f298f92 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -16,6 +16,8 @@
#define _XOPEN_SOURCE 600
/* but then DNS headers don't compile without.... */
#define _BSD_SOURCE
+/* and also, on FreeBSD 5.0 ..... */
+#define __BSD_VISIBLE 1
/* get these before config.h for IPv6 stuff... */
#include <sys/types.h>
@@ -26,7 +28,6 @@
#include "config.h"
-#include <netinet/in.h>
#include <arpa/nameser.h>
#include <arpa/inet.h>
#include <sys/stat.h>
@@ -229,8 +230,7 @@ struct dhcp_config {
};
struct dhcp_opt {
- unsigned char opt;
- unsigned char len;
+ int opt, len, is_addr;
unsigned char *val;
struct dhcp_opt *next;
};
@@ -360,6 +360,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
unsigned char *clid, int clid_len,
unsigned char *hwaddr, char *hostname);
+void set_configs_from_cache(struct dhcp_config *configs);
/* lease.c */
void lease_update_dns(int force_dns);
int lease_init(char *lease_file, char *domain, char *buff,
diff --git a/src/forward.c b/src/forward.c
index cbbc5e0..e14287d 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -132,6 +132,7 @@ struct server *forward_query(int udpfd, union mysockaddr *udpaddr, HEADER *heade
flags = 0; /* may be better match from previous literal */
domain = serv->domain;
matchlen = domainlen;
+ type = SERV_HAS_DOMAIN;
}
}
}
diff --git a/src/network.c b/src/network.c
index a3bbdbc..43dd402 100644
--- a/src/network.c
+++ b/src/network.c
@@ -76,12 +76,14 @@ static char *add_iface(struct irec **list, unsigned int flags,
specific addresses even if BIND is running and has bound *:53 */
opt = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
- bind(fd, &addr->sa, sa_len(addr)))
+ bind(fd, &addr->sa, sa_len(addr)) == -1)
{
int errsave = errno;
close(fd);
errno = errsave;
- return "failed to bind socket: %s";
+ /* IPv6 interfaces sometimes return ENODEV to bind() for unknown
+ (to me) reasons. Don't treat that as fatal. */
+ return errno == ENODEV ? NULL : "failed to bind socket: %s";
}
/* If OK, add it to the head of the list */
@@ -119,6 +121,7 @@ char *enumerate_interfaces(struct irec **interfacep,
struct irec *iface, *prev;
char *buf, *ptr, *err = NULL;
struct ifconf ifc;
+ struct ifreq *ifr = NULL;
int fd = socket(PF_INET, SOCK_DGRAM, 0);
int rawfd = -1;
@@ -158,12 +161,22 @@ char *enumerate_interfaces(struct irec **interfacep,
for (ptr = buf; ptr < buf + ifc.ifc_len; )
{
- struct ifreq *ifr = (struct ifreq *) ptr;
union mysockaddr addr;
-
#ifdef HAVE_SOCKADDR_SA_LEN
- ptr += ifr->ifr_addr.sa_len + IF_NAMESIZE;
+ /* subsequent entries may not be aligned, so copy into
+ an aligned buffer to avoid nasty complaints about
+ unaligned accesses. */
+ int ifr_len = ((struct ifreq *)ptr)->ifr_addr.sa_len + IF_NAMESIZE;
+ if (!(ifr = realloc(ifr, ifr_len)))
+ {
+ err = "cannot allocate buffer";
+ goto end;
+ }
+
+ memcpy(ifr, ptr, ifr_len);
+ ptr += ifr_len;
#else
+ ifr = (struct ifreq *)ptr;
ptr += sizeof(struct ifreq);
#endif
@@ -198,6 +211,54 @@ char *enumerate_interfaces(struct irec **interfacep,
&addr, names, addrs, except)))
goto end;
+#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;
+
+ 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 *) &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(port);
+ addr.in6.sin6_flowinfo = htonl(0);
+ addr.in6.sin6_scope_id = htonl(scope);
+
+ found = 1;
+ break;
+ }
+ }
+
+ fclose(f);
+ }
+
+ if (found &&
+ (err = add_iface(interfacep, ifr->ifr_flags, ifr->ifr_name,
+ &addr, names, addrs, except)))
+ goto end;
+ }
+
+#endif /* LINUX */
+
/* dhcp is non-null only on the first call: set up the relevant
interface-related DHCP stuff here. DHCP is IPv4 only.
Because errors here are ultimately fatal we can return directly and not bother
@@ -289,32 +350,48 @@ char *enumerate_interfaces(struct irec **interfacep,
}
}
- }
+ }
#ifdef HAVE_BPF
/* now go through the interfaces again, looking for AF_LINK records
to get hardware addresses from */
for (ptr = buf; ptr < buf + ifc.ifc_len; )
{
- struct ifreq *ifr = (struct ifreq *) ptr;
struct dhcp_context *context;
#ifdef HAVE_SOCKADDR_SA_LEN
- ptr += ifr->ifr_addr.sa_len + IF_NAMESIZE;
+ /* subsequent entries may not be aligned, so copy into
+ an aligned buffer to avoid nasty complaints about
+ unaligned accesses. */
+ int ifr_len = ((struct ifreq *)ptr)->ifr_addr.sa_len + IF_NAMESIZE;
+ if (!(ifr = realloc(ifr, ifr_len)))
+ {
+ err = "cannot allocate buffer";
+ goto end;
+ }
+
+ memcpy(ifr, ptr, ifr_len);
+ ptr += ifr_len;
#else
+ ifr = (struct ifreq *)ptr;
ptr += sizeof(struct ifreq);
#endif
+
if (ifr->ifr_addr.sa_family == AF_LINK)
for (context = dhcp; context; context = context->next)
if (context->iface && strcmp(context->iface, ifr->ifr_name) == 0)
memcpy(context->hwaddr, LLADDR((struct sockaddr_dl *)&ifr->ifr_addr), ETHER_ADDR_LEN);
}
#endif
-
+
end:
errsave = errno; /* since errno gets overwritten by close */
if (buf)
free(buf);
+#ifdef HAVE_SOCKADDR_SA_LEN
+ if (ifr)
+ free(ifr);
+#endif
close(fd);
if (err)
{
@@ -322,54 +399,6 @@ char *enumerate_interfaces(struct irec **interfacep,
return err;
}
-#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");
-
- if (f)
- {
- union mysockaddr addr;
- 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)
- {
- int i;
- 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;
- }
-#ifdef HAVE_SOCKADDR_SA_LEN
- /* For completeness - should never be defined on Linux. */
- addr.in6.sin6_len = sizeof(struct sockaddr_in6);
-#endif
- addr.in6.sin6_port = htons(port);
- addr.in6.sin6_flowinfo = htonl(0);
- addr.in6.sin6_scope_id = htonl(scope);
-
- if ((err = add_iface(interfacep, flags, devname, &addr, names, addrs, except)))
- {
- errsave = errno;
- fclose(f);
- errno = errsave;
- return err;
- }
- }
-
- fclose(f);
- }
- }
-#endif /* LINUX */
-
/* now remove interfaces which were not found on this scan */
for(prev = NULL, iface = *interfacep; iface; )
{
diff --git a/src/option.c b/src/option.c
index 3a92671..7a1df98 100644
--- a/src/option.c
+++ b/src/option.c
@@ -175,14 +175,18 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
else
{
char *p;
+ /* dump comments */
+ for (p = buff; *p; p++)
+ if (*p == '#')
+ *p = 0;
/* fgets gets end of line char too. */
while (strlen(buff) > 0 &&
(buff[strlen(buff)-1] == '\n' ||
buff[strlen(buff)-1] == ' ' ||
buff[strlen(buff)-1] == '\t'))
buff[strlen(buff)-1] = 0;
- if (*buff == '#' || *buff == 0)
- continue; /* comment */
+ if (*buff == 0)
+ continue;
if ((p=strchr(buff, '=')))
{
optarg = p+1;
@@ -639,7 +643,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
new->clid = NULL;
new->hostname = NULL;
new->addr.s_addr = 0;
- new->lease_time = DEFLEASE;
+ new->lease_time = 0;
a[0] = optarg;
for (k = 1; k < 4; k++)
@@ -706,8 +710,8 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
{
case 'h':
case 'H':
- fac *= 60;
- /* fall through */
+ fac *= 60;
+ /* fall through */
case 'm':
case 'M':
fac *= 60;
@@ -717,7 +721,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
}
for (cp = a[j]; *cp; cp++)
- if (!isdigit(*cp))
+ if (!isdigit(*cp) && *cp != ' ')
break;
if (*cp)
@@ -739,24 +743,33 @@ 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 = strchr(optarg, ',');
- int addrs;
+ int addrs, is_addr;
new->next = *dhcp_opts;
+ new->len = 0;
+ new->is_addr = 0;
*dhcp_opts = new;
- if (!comma || (*comma = 0) || (new->opt = atoi(optarg)) == 0)
+ if ((new->opt = atoi(optarg)) == 0)
{
option = '?';
break;
}
+ if (!comma)
+ break;
+
+ *comma = 0;
+
/* check for non-address list characters */
- for (addrs = 1, cp = comma+1; *cp; cp++)
+ for (addrs = 1, is_addr = 0, cp = comma+1; *cp; cp++)
if (*cp == ',')
addrs++;
else if (!(*cp == '.' || *cp == ' ' || (*cp >='0' && *cp <= '9')))
break;
-
+ else if (*cp == '.')
+ is_addr = 1;
+
if (*cp)
{
/* text arg */
@@ -768,17 +781,28 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
{
struct in_addr in;
unsigned char *op;
- new->len = INADDRSZ * addrs;
- new->val = op = safe_malloc(new->len);
- while (addrs--)
+
+ if (addrs == 1 && !is_addr)
{
- 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;
+ 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;
+ }
}
}
break;
diff --git a/src/rfc2131.c b/src/rfc2131.c
index 427f627..67dc2be 100644
--- a/src/rfc2131.c
+++ b/src/rfc2131.c
@@ -139,7 +139,7 @@ int dhcp_reply(struct dhcp_context *context, struct dhcp_packet *mess,
/* 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 : context->lease_time;
+ def_time = config && config->lease_time ? config->lease_time : context->lease_time;
if ((opt = option_find(mess, sz, OPTION_LEASE_TIME)))
{
@@ -444,6 +444,9 @@ static unsigned char *do_req_options(struct dhcp_context *context,
if (!req_options)
return p;
+ if (in_list(req_options, OPTION_MAXMESSAGE))
+ p = option_put(p, end, OPTION_MAXMESSAGE, 2, sizeof(struct udp_dhcp_packet));
+
if (in_list(req_options, OPTION_NETMASK) &&
!option_find2(config_opts, OPTION_NETMASK))
p = option_put(p, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
@@ -484,12 +487,34 @@ 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(config_opts, req_options[i]);
- if (req_options[i] != OPTION_HOSTNAME && opt && (p + opt->len + 2 < end))
+ if (req_options[i] != OPTION_HOSTNAME &&
+ req_options[i] != OPTION_MAXMESSAGE &&
+ opt && (p + opt->len + 2 < end))
{
*(p++) = opt->opt;
*(p++) = opt->len;
- memcpy(p, opt->val, opt->len);
- p += opt->len;
+ if (opt->len != 0)
+ {
+ 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, &context->serv_addr, INADDRSZ);
+ else
+ memcpy(p, a, INADDRSZ);
+ p += INADDRSZ;
+ }
+ }
+ else
+ {
+ memcpy(p, opt->val, opt->len);
+ p += opt->len;
+ }
+ }
}
}