Project import generated by Copybara.

GitOrigin-RevId: 3ad9dca7936f3cd851bd868f1b7351415887f7dc
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/CHANGELOG b/CHANGELOG
new file mode 100755
index 0000000..075fe1a
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,2282 @@
+version 2.78
+        Fix logic of appending ".<layer>" to PXE basename. Thanks to Chris
+	Novakovic for the patch.
+
+	Revert ping-check of address in DHCPDISCOVER if there
+	already exists a lease for the address. Under some
+	circumstances, and netbooted windows installation can reply
+	to pings before if has a DHCP lease and block allocation
+	of the address it already used during netboot. Thanks to
+	Jan Psota for spotting this.
+
+	Fix DHCP relaying, broken in 2.76 and 2.77 by commit
+	ff325644c7afae2588583f935f4ea9b9694eb52e. Thanks to
+	John Fitzgibbon for the diagnosis and patch.
+
+        Try other servers if first returns REFUSED when
+	--strict-order active. Thanks to Hans Dedecker
+	for the patch
+
+	Fix regression in 2.77, ironically added as a security
+	improvement, which resulted in a crash when a DNS
+	query exceeded 512 bytes (or the EDNS0 packet size,
+	if different.) Thanks to Christian Kujau, Arne Woerner
+	Juan Manuel Fernandez and Kevin Darbyshire-Bryant for
+	chasing this one down.  CVE-2017-13704 applies.
+
+	Fix heap overflow in DNS code. This is a potentially serious
+	security hole. It allows an attacker who can make DNS
+	requests to dnsmasq, and who controls the contents of
+	a domain, which is thereby queried, to overflow
+	(by 2 bytes) a heap buffer and either crash, or
+	even take control of, dnsmasq.
+	CVE-2017-14491 applies.
+	Credit to Felix Wilhelm, Fermin J. Serna, Gabriel Campana
+	Kevin Hamacher and Ron Bowes of the Google Security Team for
+	finding this.
+
+	Fix heap overflow in IPv6 router advertisement code.
+	This is a potentially serious security hole, as a
+	crafted RA request can overflow a buffer and crash or
+	control dnsmasq. Attacker must be on the local network.
+	CVE-2017-14492 applies.
+        Credit to Felix Wilhelm, Fermin J. Serna, Gabriel Campana
+	and Kevin Hamacher of the Google Security Team for
+	finding this.
+
+	Fix stack overflow in DHCPv6 code. An attacker who can send
+	a DHCPv6 request to dnsmasq can overflow the stack frame and
+	crash or control dnsmasq.
+	CVE-2017-14493 applies.
+	Credit to Felix Wilhelm, Fermin J. Serna, Gabriel Campana
+	Kevin Hamacher and Ron Bowes of the Google Security Team for
+	finding this.
+
+	Fix information leak in DHCPv6. A crafted DHCPv6 packet can
+	cause dnsmasq to forward memory from outside the packet
+	buffer to a DHCPv6 server when acting as a relay.
+	CVE-2017-14494 applies.
+	Credit to Felix Wilhelm, Fermin J. Serna, Gabriel Campana
+	Kevin Hamacher and Ron Bowes of the Google Security Team for
+	finding this.
+
+	Fix DoS in DNS. Invalid boundary checks in the
+	add_pseudoheader function allows a memcpy call with negative
+	size An attacker which can send malicious DNS queries
+	to dnsmasq can trigger a DoS remotely.
+	dnsmasq is vulnerable only if one of the following option is
+	specified: --add-mac, --add-cpe-id or --add-subnet.
+	CVE-2017-14496 applies.
+	Credit to Felix Wilhelm, Fermin J. Serna, Gabriel Campana
+	Kevin Hamacher and Ron Bowes of the Google Security Team for
+	finding this.
+
+	Fix out-of-memory Dos vulnerability. An attacker which can
+	send malicious DNS queries to dnsmasq can trigger memory
+	allocations in the add_pseudoheader function
+	The allocated memory is never freed which leads to a DoS
+	through memory exhaustion. dnsmasq is vulnerable only
+	if one of the following option is specified:
+	--add-mac, --add-cpe-id or --add-subnet.
+	CVE-2017-14495 applies.
+	Credit to Felix Wilhelm, Fermin J. Serna, Gabriel Campana
+	Kevin Hamacher and Ron Bowes of the Google Security Team for
+	finding this.
+
+
+version 2.77
+	Generate an error when configured with a CNAME loop,
+	rather than a crash. Thanks to George Metz for
+	spotting this problem.
+
+	Calculate the length of TFTP error reply packet 
+	correctly. This fixes a problem when the error 
+	message in a TFTP packet exceeds the arbitrary 
+	limit of 500 characters. The message was correctly
+	truncated, but not the packet length, so 
+	extra data was appended. This is a possible
+	security risk, since the extra data comes from
+	a buffer which is also used for DNS, so that
+	previous DNS queries or replies may be leaked.
+	Thanks to Mozilla for funding the security audit 
+	which spotted this bug.
+
+	Fix logic error in Linux netlink code. This could
+	cause dnsmasq to enter a tight loop on systems
+	with a very large number of network interfaces.
+	Thanks to Ivan Kokshaysky for the diagnosis and
+	patch.
+
+	Fix problem with --dnssec-timestamp whereby receipt
+	of SIGHUP would erroneously engage timestamp checking.
+	Thanks to Kevin Darbyshire-Bryant for this work.
+
+	Bump zone serial on reloading /etc/hosts and friends
+	when providing authoritative DNS. Thanks to Harrald
+	Dunkel for spotting this.
+
+	Handle v4-mapped IPv6 addresses sanely in --synth-domain.
+	These have standard representation like ::ffff:1.2.3.4
+	and are now converted to names like
+	<prefix>--ffff-1-2-3-4.<domain>
+
+	Handle binding upstream servers to an interface 
+	(--server=1.2.3.4@eth0) when the named interface
+	is destroyed and recreated in the kernel. Thanks to 
+	Beniamino Galvani for the patch.
+
+	Allow wildcard CNAME records in authoritative zones.
+	For example --cname=*.example.com,default.example.com
+	Thanks to Pro Backup for sponsoring this development.
+
+	Bump the allowed backlog of TCP connections from 5 to 32,
+	and make this a compile-time configurable option. Thanks
+	to Donatas Abraitis for diagnosing this as a potential
+	problem.
+
+	Add DNSMASQ_REQUESTED_OPTIONS environment variable to the 
+	lease-change script. Thanks to ZHAO Yu for the patch.
+
+	Fix foobar in rrfilter code, that could cause malformed 
+	replies, especially when DNSSEC validation on, and 
+	the upstream server returns answer with the RRs in a 
+	particular order. The only DNS server known to tickle
+	this is Nominum's. Thanks to Dave Täht for spotting the
+	bug and assisting in the fix.
+
+	Fix the manpage which lied that only the primary address
+	of an interface is used by --interface-name.
+
+	Make --localise-queries apply to names from --interface-name.
+	Thanks to Kevin Darbyshire-Bryant and Eric Luehrsen
+	for pushing this.
+
+	Improve connection handling when talking to TCP upstream 
+	servers. Specifically, be prepared to open a new TCP
+	connection when we want to make multiple queries
+	but the upstream server accepts fewer queries per connection.
+
+	Improve logging of upstream servers when there are a lot
+	of "local addresses only" entries. Thanks to Hannu Nyman for
+	the patch.
+
+	Make --bogus-priv apply to IPv6, for the prefixes specified
+	in RFC6303. Thanks to Kevin Darbyshire-Bryant for work on this.
+
+	Allow use of MAC addresses with --tftp-unique-root. Thanks
+	to Floris Bos for the patch.
+
+	Add --dhcp-reply-delay option. Thanks to Floris Bos
+	for the patch.
+
+	Add mtu setting facility to --ra-param. Thanks to David
+	Flamand for the patch.
+
+	Capture STDOUT and STDERR output from dhcp-script and log
+	it as part of the dnsmasq log stream. Makes life easier
+	for diagnosing unexpected problems in scripts.
+	Thanks to Petr Mensik for the patch.
+
+	Generate fatal errors when failing to parse the output
+	of the dhcp-script in "init" mode. Avoids strange errors
+	when the script accidentally emits error messages.
+	Thanks to Petr Mensik for the patch.
+
+	Make --rev-server for an RFC1918 subnet work even in the
+	presence of the --bogus-priv flag. Thanks to
+	Vladislav Grishenko for the patch.
+
+	Extend --ra-param mtu: field to allow an interface name.
+	This allows the MTU of a WAN interface to be advertised on
+	the internal interfaces of a router. Thanks to
+	Vladislav Grishenko for the patch.
+
+	Do ICMP-ping check for address-in-use for DHCPv4 when
+	the client specifies an address in DHCPDISCOVER, and when
+	an address in configured locally. Thanks to Alin Năstac
+	for spotting the problem.
+
+	Add new DHCP tag "known-othernet" which is set when only a
+	dhcp-host exists for another subnet. Can be used to ensure
+	that privileged hosts are not given "guest" addresses by
+	accident. Thanks to Todd Sanket for the suggestion.
+
+	Remove historic automatic inclusion of IDN support when
+	building internationalisation support. This doesn't
+	fit now there is a choice of IDN libraries. Be sure
+	to include either -DHAVE_IDN or -DHAVE_LIBIDN2 for
+	IDN support.
+
+
+version 2.76
+	Include 0.0.0.0/8 in DNS rebind checks. This range 
+	translates to hosts on  the local network, or, at 
+	least, 0.0.0.0 accesses the local host, so could
+	be targets for DNS rebinding. See RFC 5735 section 3 
+	for details. Thanks to Stephen Röttger for the bug report.
+
+	Enhance --add-subnet to allow arbitrary subnet addresses.
+	Thanks to Ed Barsley for the patch.
+
+	Respect the --no-resolv flag in inotify code. Fixes bug
+	which caused dnsmasq to fail to start if a resolv-file 
+	was a dangling symbolic link, even of --no-resolv set.
+	Thanks to Alexander Kurtz for spotting the problem.
+
+	Fix crash when an A or AAAA record is defined locally,
+	in a hosts file, and an upstream server sends a reply
+	that the same name is empty. Thanks to Edwin Török for
+	the patch.
+
+	Fix failure to correctly calculate cache-size when 
+	reading a hosts-file fails. Thanks to André Glüpker 
+	for the patch.
+
+	Fix wrong answer to simple name query when --domain-needed
+	set, but no upstream servers configured. Dnsmasq returned
+	REFUSED, in this case, when it should be the same as when
+	upstream servers are configured - NOERROR. Thanks to 
+	Allain Legacy for spotting the problem.
+
+	Return REFUSED when running out of forwarding table slots,
+	not SERVFAIL.
+
+	Add --max-port configuration. Thanks to Hans Dedecker for
+	the patch.
+
+	Add --script-arp and two new functions for the dhcp-script.
+	These are "arp" and "arp-old" which announce the arrival and
+	removal of entries in the ARP or neighbour tables.
+
+	Extend --add-mac to allow a new encoding of the MAC address 
+	as base64, by configuring --add-mac=base64
+
+	Add --add-cpe-id option.
+
+	Don't crash with divide-by-zero if an IPv6 dhcp-range
+	is declared as a whole /64.
+	(ie xx::0 to xx::ffff:ffff:ffff:ffff) 
+	Thanks to Laurent Bendel for spotting this problem.
+
+	Add support for a TTL parameter in --host-record and
+	--cname.
+
+	Add --dhcp-ttl option.
+
+	Add --tftp-mtu option. Thanks to Patrick McLean for the 
+	initial patch.
+
+	Check return-code of inet_pton() when parsing dhcp-option.
+	Bad addresses could fail to generate errors and result in
+	garbage dhcp-options being sent. Thanks to Marc Branchaud 
+	for spotting this.
+
+	Fix wrong value for EDNS UDP packet size when using 
+	--servers-file to define upstream DNS servers. Thanks to
+	Scott Bonar for the bug report.
+
+	Move the dhcp_release and dhcp_lease_time tools from 
+	contrib/wrt to contrib/lease-tools.
+
+	Add dhcp_release6 to contrib/lease-tools. Many thanks 
+	to Sergey Nechaev for this code.
+
+	To avoid filling logs in configurations which define
+	many upstream nameservers, don't log more that 30 servers.
+	The number to be logged can be changed as SERVERS_LOGGED
+	in src/config.h.
+
+	Swap the values if BC_EFI and x86-64_EFI in --pxe-service. 
+	These were previously wrong due to an error in RFC 4578.
+	If you're using BC_EFI to boot 64-bit EFI machines, you
+	will need to update your config.
+
+	Add ARM32_EFI and ARM64_EFI as valid architectures in
+	--pxe-service.
+
+	Fix PXE booting for UEFI architectures. Modify PXE boot
+	sequence in this case to force the client to talk to dnsmasq
+	over port 4011. This makes PXE and especially proxy-DHCP PXE
+	work with these architectures.
+
+	Workaround problems with UEFI PXE clients. There exist
+	in the wild PXE clients which have problems with PXE
+	boot menus. To work around this, when there's a single
+	--pxe-service which applies to client, then that target
+	will be booted directly, rather then sending a
+	single-item boot menu.
+
+	Many thanks to Jarek Polok, Michael Kuron and Dreamcat4 
+	for their work on the long-standing UEFI PXE problem.
+
+	Subtle change in the semantics of "basename" in
+	--pxe-service. The historical behaviour has always been
+	that the actual filename downloaded from the TFTP server
+	is <basename>.<layer> where <layer> is an integer which
+	corresponds to the layer parameter supplied by the client.
+	It's not clear what the function of the "layer" 
+	actually is in the PXE protocol, and in practise layer 
+	is always zero, so the filename is <basename>.0
+	The new behaviour is the same as the old, except when
+	<basename> includes a file suffix, in which case
+	the layer suffix is no longer added. This allows
+	sensible suffices to be used, rather then the
+	meaningless ".0". Only in the unlikely event that you
+	have a config with a basename which already has a
+	suffix, is this an incompatible change, since the file
+	downloaded will change from name.suffix.0 to just 
+	name.suffix
+
+
+version 2.75
+	Fix reversion on 2.74 which caused 100% CPU use when a 
+	dhcp-script is configured. Thanks to Adrian Davey for
+	reporting the bug and testing the fix.
+
+
+version 2.74
+	Fix reversion in 2.73 where --conf-file would attempt to
+	read the default file, rather than no file.
+
+	Fix inotify code to handle dangling symlinks better and
+	not SEGV in some circumstances.
+
+	DNSSEC fix. In the case of a signed CNAME generated by a
+	wildcard which pointed to an unsigned domain, the wrong
+	status would be logged, and some necessary checks omitted.
+
+
+version 2.73
+	Fix crash at startup when an empty suffix is supplied to
+	--conf-dir, also trivial memory leak. Thanks to 
+	Tomas Hozza for spotting this.
+
+	Remove floor of 4096 on advertised EDNS0 packet size when 
+	DNSSEC in use, the original rationale for this has long gone.
+	Thanks to Anders Kaseorg for spotting this.
+
+	Use inotify for checking on updates to /etc/resolv.conf and
+	friends under Linux. This fixes race conditions when the files are 
+	updated rapidly and saves CPU by noy polling. To build
+	a binary that runs on old Linux kernels without inotify,
+	use make COPTS=-DNO_INOTIFY
+
+	Fix breakage of --domain=<domain>,<subnet>,local - only reverse
+	queries were intercepted. THis appears to have been broken 
+	since 2.69. Thanks to Josh Stone for finding the bug.
+
+	Eliminate IPv6 privacy addresses and deprecated addresses from
+	the answers given by --interface-name. Note that reverse queries
+	(ie looking for names, given addresses) are not affected. 
+	Thanks to Michael Gorbach for the suggestion.
+
+	Fix crash in DNSSEC code with long RRs. Thanks to Marco Davids
+	for the bug report.
+
+	Add --ignore-address option. Ignore replies to A-record 
+	queries which include the specified address. No error is
+	generated, dnsmasq simply continues to listen for another 
+	reply. This is useful to defeat blocking strategies which
+	rely on quickly supplying a forged answer to a DNS 
+	request for certain domains, before the correct answer can
+	arrive. Thanks to Glen Huang for the patch.
+
+	Revisit the part of DNSSEC validation which determines if an 
+	unsigned answer is legit, or is in some part of the DNS 
+	tree which should be signed. Dnsmasq now works from the 
+	DNS root downward looking for the limit of signed 
+	delegations, rather than working bottom up. This is 
+	both more correct, and less likely to trip over broken 
+	nameservers in the unsigned parts of the DNS tree 
+	which don't respond well to DNSSEC queries.
+
+	Add --log-queries=extra option, which makes logs easier
+	to search automatically.
+
+	Add --min-cache-ttl option. I've resisted this for a long 
+	time, on the grounds that disbelieving TTLs is never a 
+	good idea, but I've been persuaded that there are 
+	sometimes reasons to do it. (Step forward, GFW).
+	To avoid misuse, there's a hard limit on the TTL 
+	floor of one hour. Thanks to RinSatsuki for the patch.
+
+	Cope with multiple interfaces with the same link-local 
+	address. (IPv6 addresses are scoped, so this is allowed.)
+	Thanks to Cory Benfield for help with this.
+
+	Add --dhcp-hostsdir. This allows addition of new host
+	configurations to a running dnsmasq instance much more 
+	cheaply than having dnsmasq re-read all its existing
+	configuration each time. 
+
+	Don't reply to DHCPv6 SOLICIT messages if we're not 
+	configured to do stateful DHCPv6. Thanks to Win King Wan 
+	for the patch.
+
+	Fix broken DNSSEC validation of ECDSA signatures.
+
+	Add --dnssec-timestamp option, which provides an automatic
+	way to detect when the system time becomes valid after 
+	boot on systems without an RTC, whilst allowing DNS 
+	queries before the clock is valid so that NTP can run. 
+	Thanks to Kevin Darbyshire-Bryant for developing this idea.
+
+	Add --tftp-no-fail option. Thanks to Stefan Tomanek for
+	the patch.
+
+	Fix crash caused by looking up servers.bind, CHAOS text 
+	record, when more than about five --servers= lines are 
+	in the dnsmasq config. This causes memory corruption 
+	which causes a crash later. Thanks to Matt Coddington for 
+	sterling work chasing this down.
+
+	Fix crash on receipt of certain malformed DNS requests.
+	Thanks to Nick Sampanis for spotting the problem.
+	Note that this is could allow the dnsmasq process's
+	memory to be read by an attacker under certain
+	circumstances, so it has a CVE, CVE-2015-3294 
+
+	Fix crash in authoritative DNS code, if a .arpa zone 
+	is declared as authoritative, and then a PTR query which
+	is not to be treated as authoritative arrived. Normally, 
+	directly declaring .arpa zone as authoritative is not 
+	done, so this crash wouldn't be seen. Instead the 
+	relevant .arpa zone should be specified as a subnet
+	in the auth-zone declaration. Thanks to Johnny S. Lee
+	for the bugreport and initial patch.
+
+	Fix authoritative DNS code to correctly reply to NS 
+	and SOA queries for .arpa zones for which we are 
+	declared authoritative by means of a subnet in auth-zone.
+	Previously we provided correct answers to PTR queries
+	in such zones (including NS and SOA) but not direct
+	NS and SOA queries. Thanks to Johnny S. Lee for 
+	pointing out the problem.
+
+	Fix logging of DHCPREPLY which should be suppressed 
+	by quiet-dhcp6. Thanks to J. Pablo Abonia for 
+	spotting the problem.
+
+	Try and handle net connections with broken fragmentation 
+	that lose large UDP packets. If a server times out, 
+	reduce the maximum UDP packet size field in the EDNS0
+	header to 1280 bytes. If it then answers, make that
+	change permanent.
+
+	Check IPv4-mapped IPv6 addresses when --stop-rebind
+	is active. Thanks to Jordan Milne for spotting this.
+
+	Allow DHCPv4 options T1 and T2 to be set using --dhcp-option.
+	Thanks to Kevin Benton for patches and work on this.
+
+	Fix code for DHCPCONFIRM DHCPv6 messages to confirm addresses
+	in the correct subnet, even of not in dynamic address 
+	allocation range. Thanks to Steve Hirsch for spotting
+	the problem.
+
+	Add AddDhcpLease and DeleteDhcpLease DBus methods. Thanks
+	to Nicolas Cavallari for the patch.
+
+	Allow configuration of router advertisements without the 
+	"on-link" bit set. Thanks to Neil Jerram for the patch.
+
+	Extend --bridge-interface to DHCPv6 and router 
+	advertisements. Thanks to Neil Jerram for the patch.
+
+
+version 2.72
+	Add ra-advrouter mode, for RFC-3775 mobile IPv6 support.
+
+	Add support for "ipsets" in *BSD, using pf. Thanks to 
+	Sven Falempin for the patch.
+
+	Fix race condition which could lock up dnsmasq when an 
+	interface goes down and up rapidly. Thanks to Conrad 
+	Kostecki for helping to chase this down.
+
+	Add DBus methods SetFilterWin2KOption and SetBogusPrivOption
+	Thanks to the Smoothwall project for the patch.
+
+	Fix failure to build against Nettle-3.0. Thanks to Steven 
+	Barth for spotting this and finding the fix. 
+
+	When assigning existing DHCP leases to interfaces by comparing 
+	networks, handle the case that two or more interfaces have the
+	same network part, but different prefix lengths (favour the
+	longer prefix length.) Thanks to Lung-Pin Chang for the 
+	patch.
+
+	Add a mode which detects and removes DNS forwarding loops, ie 
+	a query sent to an upstream server returns as a new query to 
+	dnsmasq, and would therefore be forwarded again, resulting in 
+	a query which loops many times before being dropped. Upstream
+	servers which loop back are disabled and this event is logged.
+	Thanks to Smoothwall for their sponsorship of this feature.
+
+	Extend --conf-dir to allow filtering of files. So
+	--conf-dir=/etc/dnsmasq.d,\*.conf
+	will load all the files in /etc/dnsmasq.d which end in .conf
+
+	Fix bug when resulted in NXDOMAIN answers instead of NODATA in
+	some circumstances.
+
+	Fix bug which caused dnsmasq to become unresponsive if it 
+	failed to send packets due to a network interface disappearing.
+	Thanks to Niels Peen for spotting this.
+
+	Fix problem with --local-service option on big-endian platforms
+	Thanks to Richard Genoud for the patch.
+
+
+version 2.71
+	Subtle change to error handling to help DNSSEC validation 
+	when servers fail to provide NODATA answers for 
+	non-existent DS records.
+
+	Tweak code which removes DNSSEC records from answers when
+	not required. Fixes broken answers when additional section
+	has real records in it. Thanks to Marco Davids for the bug 
+	report.
+
+	Fix DNSSEC validation of ANY queries. Thanks to Marco Davids
+	for spotting that too.
+
+	Fix total DNS failure and 100% CPU use if cachesize set to zero,
+	regression introduced in 2.69. Thanks to James Hunt and
+	the Ubuntu crowd for assistance in fixing this.
+
+
+version 2.70
+	Fix crash, introduced in 2.69, on TCP request when dnsmasq
+	compiled with DNSSEC support, but running without DNSSEC
+	enabled. Thanks to Manish Sing for spotting that one.
+
+	Fix regression which broke ipset functionality. Thanks to 
+	Wang Jian for the bug report.
+
+
+version 2.69
+	Implement dynamic interface discovery on *BSD. This allows
+	the constructor: syntax to be used in dhcp-range for DHCPv6
+	on the BSD platform. Thanks to Matthias Andree for
+	valuable research on how to implement this.
+
+	Fix infinite loop associated with some --bogus-nxdomain
+	configs. Thanks fogobogo for the bug report.
+
+	Fix missing RA RDNS option with configuration like
+	--dhcp-option=option6:23,[::] Thanks to Tsachi Kimeldorfer
+	for spotting the problem.
+
+	Add [fd00::] and [fe80::] as special addresses in DHCPv6
+	options, analogous to [::]. [fd00::] is replaced with the
+	actual ULA of the interface on the machine running
+	dnsmasq, [fe80::] with the link-local address. 
+	Thanks to Tsachi Kimeldorfer for championing this.
+
+	DNSSEC validation and caching. Dnsmasq needs to be
+	compiled with this enabled, with 
+
+	make dnsmasq COPTS=-DHAVE_DNSSEC
+
+	this adds dependencies on the nettle crypto library and the 
+	gmp maths library. It's possible to have these linked
+	statically with
+
+	make dnsmasq COPTS='-DHAVE_DNSSEC -DHAVE_DNSSEC_STATIC'
+
+	which bloats the dnsmasq binary, but saves the size of 
+	the shared libraries which are much bigger.
+
+	To enable, DNSSEC, you will need a set of
+	trust-anchors. Now that the TLDs are signed, this can be
+	the keys for the root zone, and for convenience they are
+	included in trust-anchors.conf in the dnsmasq
+	distribution. You should of course check that these are
+	legitimate and up-to-date. So, adding
+
+	conf-file=/path/to/trust-anchors.conf
+	dnssec
+
+	to your config is all that's needed to get things
+	working. The upstream nameservers have to be DNSSEC-capable
+	too, of course. Many ISP nameservers aren't, but the
+	Google public nameservers (8.8.8.8 and 8.8.4.4) are.
+	When DNSSEC is configured, dnsmasq validates any queries 
+	for domains which are signed. Query results which are 
+	bogus are replaced with SERVFAIL replies, and results 
+	which are correctly signed have the AD bit set. In 
+	addition, and just as importantly, dnsmasq supplies 
+	correct DNSSEC information to clients which are doing 
+	their own validation, and caches DNSKEY, DS and RRSIG
+	records, which significantly improve the performance of 
+	downstream validators. Setting --log-queries will show 
+	DNSSEC in action.
+
+	If a domain is returned from an upstream nameserver without 
+	DNSSEC signature, dnsmasq by default trusts this. This 
+	means that for unsigned zone (still the majority) there 
+	is effectively no cost for having DNSSEC enabled. Of course
+	this allows an attacker to replace a signed record with a 
+	false unsigned record. This is addressed by the 
+	--dnssec-check-unsigned flag, which instructs dnsmasq
+	to prove that an unsigned record is legitimate, by finding  
+	a secure proof that the zone containing the record is not
+	signed. Doing this has costs (typically one or two extra
+	upstream queries). It also has a nasty failure mode if
+	dnsmasq's upstream nameservers are not DNSSEC capable. 
+	Without --dnssec-check-unsigned using such an upstream
+	server will simply result in not queries being validated; 
+	with --dnssec-check-unsigned enabled and a 
+	DNSSEC-ignorant upstream server, _all_ queries will fail.
+
+	Note that DNSSEC requires that the local time is valid and 
+	accurate, if not then DNSSEC validation will fail. NTP 
+	should be running. This presents a problem for routers
+	without a battery-backed clock. To set the time needs NTP 
+	to do DNS lookups, but lookups will fail until NTP has run.
+	To address this, there's a flag, --dnssec-no-timecheck 
+	which disables the time checks (only) in DNSSEC. When dnsmasq
+	is started and the clock is not synced, this flag should
+	be used. As soon as the clock is synced, SIGHUP dnsmasq. 
+	The SIGHUP clears the cache of partially-validated data and
+	resets the no-timecheck flag, so that all DNSSEC checks 
+	henceforward will be complete.
+
+	The development of DNSSEC in dnsmasq was started by 
+	Giovanni Bajo, to whom huge thanks are owed. It has been
+	supported by Comcast, whose techfund grant has allowed for 
+	an invaluable period of full-time work to get it to 
+	a workable state.
+
+	Add --rev-server. Thanks to Dave Taht for suggesting this.
+
+	Add --servers-file. Allows dynamic update of upstream servers 
+	full access to configuration. 
+
+	Add --local-service. Accept DNS queries only from hosts 
+	whose address is on a local subnet, ie a subnet for which 
+	an interface exists on the server. This option
+	only has effect if there are no --interface --except-interface,
+	--listen-address or --auth-server options. It is intended 
+	to be set as a default on installation, to allow
+	unconfigured installations to be useful but also safe from 
+	being used for DNS amplification attacks.
+
+	Fix crashes in cache_get_cname_target() when dangling CNAMEs
+	encountered. Thanks to Andy and the rt-n56u project for
+	find this and helping to chase it down.
+
+	Fix wrong RCODE in authoritative DNS replies to PTR queries. The
+	correct answer was included, but the RCODE was set to NXDOMAIN.
+	Thanks to Craig McQueen for spotting this.
+
+	Make statistics available as DNS queries in the .bind TLD as 
+	well as logging them.
+
+
+version 2.68
+	Use random addresses for DHCPv6 temporary address
+	allocations, instead of algorithmically determined stable
+	addresses.
+
+	Fix bug which meant that the DHCPv6 DUID was not available
+	in DHCP script runs during the lifetime of the dnsmasq
+	process which created the DUID de-novo. Once the DUID was
+	created and stored in the lease file and dnsmasq
+	restarted, this bug disappeared.
+
+	Fix bug introduced in 2.67 which could result in erroneous
+	NXDOMAIN returns to CNAME queries.
+
+	Fix build failures on MacOS X and openBSD.
+
+	Allow subnet specifications in --auth-zone to be interface 
+	names as well as address literals. This makes it possible
+	to configure authoritative DNS when local address ranges
+	are dynamic and works much better than the previous
+	work-around which exempted constructed DHCP ranges from the
+	IP address filtering. As a consequence, that work-around
+	is removed. Under certain circumstances, this change wil
+	break existing configuration: if you're relying on the
+	constructed-range exception, you need to change --auth-zone
+	to specify the same interface as is used to construct your
+	DHCP ranges, probably with a trailing "/6" like this: 
+	--auth-zone=example.com,eth0/6 to limit the addresses to
+	IPv6 addresses of eth0.
+
+	Fix problems when advertising deleted IPv6 prefixes. If
+	the prefix is deleted (rather than replaced), it doesn't
+	get advertised with zero preferred time. Thanks to Tsachi
+	for the bug report. 
+
+	Fix segfault with some locally configured CNAMEs. Thanks
+	to Andrew Childs for spotting the problem.
+
+	Fix memory leak on re-reading /etc/hosts and friends,
+	introduced in 2.67.
+
+	Check the arrival interface of incoming DNS and TFTP
+	requests via IPv6, even in --bind-interfaces mode. This
+	isn't possible for IPv4 and can generate scary warnings,
+	but as it's always possible for IPv6 (the API always
+	exists) then we should do it always. 
+
+	Tweak the rules on prefix-lengths in --dhcp-range for
+	IPv6. The new rule is that the specified prefix length
+	must be larger than or equal to the prefix length of the
+	corresponding address on the local interface. 
+
+
+version 2.67
+	Fix crash if upstream server returns SERVFAIL when
+	--conntrack in use. Thanks to Giacomo Tazzari for finding
+	this and supplying the patch. 
+
+	Repair regression in 2.64. That release stopped sending
+	lease-time information in the reply to DHCPINFORM
+	requests, on the correct grounds that it was a standards
+	violation. However, this broke the dnsmasq-specific
+	dhcp_lease_time utility. Now, DHCPINFORM returns
+	lease-time only if it's specifically requested
+	(maintaining standards) and the dhcp_lease_time utility
+	has been taught to ask for it (restoring functionality). 
+
+	Fix --dhcp-match, --dhcp-vendorclass and --dhcp-userclass
+	to work with BOOTP and well as DHCP. Thanks to Peter
+	Korsgaard for spotting the problem. 
+
+	Add --synth-domain. Thanks to Vishvananda Ishaya for
+	suggesting this.
+
+	Fix failure to compile ipset.c if old kernel headers are
+	in use. Thanks to Eugene Rudoy for pointing this out.
+
+	Handle IPv4 interface-address labels in Linux. These are
+	often used to emulate the old IP-alias addresses. Before,
+	using --interface=eth0 would service all the addresses of
+	eth0, including ones configured as aliases, which appear
+	in ifconfig as eth0:0. Now, only addresses with the label
+	eth0 are active. This is not backwards compatible: if you
+	want to continue to bind the aliases too, you need to add
+	eg. --interface=eth0:0 to the config. 
+
+	Fix "failed to set SO_BINDTODEVICE on DHCP socket: Socket 
+	operation on non-socket" error on startup with
+	configurations which have exactly one --interface option
+	and do RA but _not_ DHCPv6. Thanks to Trever Adams for the
+	bug report.
+
+	Generalise --interface-name to cope with IPv6 addresses
+	and multiple addresses per interface per address family.
+
+	Fix option parsing for --dhcp-host, which was generating a
+	spurious error when all seven possible items were
+	included. Thanks to Zhiqiang Wang for the bug report.
+
+	Remove restriction on prefix-length in --auth-zone. Thanks
+	to Toke Hoiland-Jorgensen for suggesting this.
+
+	Log when the maximum number of concurrent DNS queries is
+	reached. Thanks to Marcelo Salhab Brogliato for the patch.
+
+	If wildcards are used in --interface, don't assume that 
+	there will only ever be one available interface for DHCP
+	just because there is one at start-up. More may appear, so
+	we can't use SO_BINDTODEVICE. Thanks to Natrio for the bug
+	report. 
+
+	Increase timeout/number of retries in TFTP to accommodate
+	AudioCodes Voice Gateways doing streaming writes to flash.
+	Thanks to Damian Kaczkowski for spotting the problem.
+
+	Fix crash with empty DHCP string options when adding zero
+	terminator. Thanks to Patrick McLean for the bug report.
+
+	Allow hostnames to start with a number, as allowed in
+	RFC-1123. Thanks to Kyle Mestery for the patch. 
+
+	Fixes to DHCP FQDN option handling: don't terminate FQDN
+	if domain not known and allow a FQDN option with blank
+	name to request that a FQDN option is returned in the
+	reply. Thanks to Roy Marples for the patch.
+
+	Make --clear-on-reload apply to setting upstream servers
+	via DBus too.
+
+	When the address which triggered the construction of an
+	advertised IPv6 prefix disappears, continue to advertise 
+	the prefix for up to 2 hours, with the preferred lifetime
+	set to zero. This satisfies RFC 6204 4.3 L-13 and makes
+	things work better if a prefix disappears without being
+	deprecated first. Thanks to Uwe Schindler for persuasively
+	arguing for this.
+
+	Fix MAC address enumeration on *BSD. Thanks to Brad Smith
+	for the bug report.
+
+	Support RFC-4242 information-refresh-time options in the 
+	reply to DHCPv6 information-request. The lease time of the
+	smallest valid dhcp-range is sent. Thanks to Uwe Schindler 
+	for suggesting this.
+
+	Make --listen-address higher priority than --except-interface
+	in all circumstances. Thanks to Thomas Hood for the bugreport.
+
+	Provide independent control over which interfaces get TFTP 
+	service. If enable-tftp is given a list of interfaces, then TFTP 
+	is provided on those. Without the list, the previous behaviour
+	(provide TFTP to the same interfaces we provide DHCP to) 
+	is retained. Thanks to Lonnie Abelbeck for the suggestion.
+
+	Add --dhcp-relay config option. Many thanks to vtsl.net
+	for sponsoring this development.
+
+	Fix crash with empty tag: in --dhcp-range. Thanks to
+	Kaspar Schleiser for the bug report.
+
+	Add "baseline" and "bloatcheck" makefile targets, for 
+	revealing size changes during development. Thanks to
+	Vladislav Grishenko for the patch. 
+
+	Cope with DHCPv6 clients which send REQUESTs without
+	address options - treat them as SOLICIT with rapid commit.
+
+	Support identification of clients by MAC address in
+	DHCPv6. When using a relay, the relay must support RFC
+	6939 for this to work. It always works for directly
+	connected clients. Thanks to Vladislav Grishenko
+	for prompting this feature.
+
+	Remove the rule for constructed DHCP ranges that the local
+	address must be either the first or last address in the
+	range. This was originally to avoid SLAAC addresses, but
+	we now explicitly autoconfig and privacy addresses instead.  
+
+	Update Polish translation. Thanks to Jan Psota.
+
+	Fix problem in DHCPv6 vendorclass/userclass matching
+	code. Thanks to Tanguy Bouzeloc for the patch.
+
+	Update Spanish translation. Thanks to Vicente Soriano.
+
+	Add --ra-param option. Thanks to Vladislav Grishenko for
+	inspiration on this.
+
+	Add --add-subnet configuration, to tell upstream DNS
+	servers where the original client is. Thanks to DNSthingy
+	for sponsoring this feature.
+
+	Add --quiet-dhcp, --quiet-dhcp6 and --quiet-ra. Thanks to
+	Kevin Darbyshire-Bryant for the initial patch.
+
+	Allow A/AAAA records created by --interface-name to be the
+	target of --cname. Thanks to Hadmut Danisch for the
+	suggestion. 
+
+	Avoid treating a --dhcp-host which has an IPv6 address
+	as eligible for use with DHCPv4 on the grounds that it has
+	no address, and vice-versa. Thanks to Yury Konovalov for
+	spotting the problem.
+
+	Do a better job caching dangling CNAMEs. Thanks to Yves
+	Dorfsman for spotting the problem.
+
+
+version 2.66
+	Add the ability to act as an authoritative DNS
+	server. Dnsmasq can now answer queries from the wider 'net
+	with local data, as long as the correct NS records are set
+	up. Only local data is provided, to avoid creating an open
+	DNS relay. Zone transfer is supported, to allow secondary
+	servers to be configured.
+
+	Add "constructed DHCP ranges" for DHCPv6. This is intended
+	for IPv6 routers which get prefixes dynamically via prefix
+	delegation. With suitable configuration, stateful DHCPv6
+	and RA can happen automatically as prefixes are delegated
+	and then deprecated, without having  to re-write the
+	dnsmasq configuration file or restart the daemon. Thanks to
+	Steven Barth for extensive testing and development work on
+	this idea.
+
+	Fix crash on startup on Solaris 11. Regression probably
+	introduced in 2.61.  Thanks to Geoff Johnstone for the
+	patch.
+
+	Add code to make behaviour for TCP DNS requests that same
+	as for UDP requests, when a request arrives for an allowed 
+	address, but via a banned interface. This change is only
+	active on Linux, since the relevant API is missing (AFAIK)
+	on other platforms. Many thanks to Tomas Hozza for
+	spotting the problem, and doing invaluable discovery of
+	the obscure and undocumented API required for the solution.
+
+	Don't send the default DHCP option advertising dnsmasq as
+	the local DNS server if dnsmasq is configured to not act
+	as DNS server, or it's configured to a non-standard port.
+
+	Add DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBSCRIBER_ID,
+	DNSMASQ_REMOTE_ID variables to the environment of the
+	lease-change script (and the corresponding Lua). These hold
+	information inserted into the DHCP request by a DHCP relay
+	agent. Thanks to Lakefield Communications for providing a
+	bounty for this addition.
+
+	Fixed crash, introduced in 2.64, whilst handling DHCPv6
+	information-requests with some common configurations.
+	Thanks to Robert M. Albrecht for the bug report and 
+	chasing the problem.
+
+	Add --ipset option. Thanks to Jason A. Donenfeld for the 
+	patch.
+
+	Don't erroneously reject some option names in --dhcp-match
+	options. Thanks to Benedikt Hochstrasser for the bug report.
+
+	Allow a trailing '*' wildcard in all interface-name
+	configurations. Thanks to Christian Parpart for the patch.
+
+	Handle the situation where libc headers define
+	SO_REUSEPORT, but the kernel in use doesn't, to cope with
+	the introduction of this option to Linux. Thanks to Rich
+	Felker for the bug report.
+
+	Update Polish translation. Thanks to Jan Psota.
+
+	Fix crash if the configured DHCP lease limit is
+	reached. Regression occurred in 2.61. Thanks to Tsachi for
+	the bug report. 
+
+	Update the French translation. Thanks to Gildas le Nadan.
+
+
+version 2.65
+	Fix regression which broke forwarding of queries sent via
+	TCP which are not for A and AAAA and which were directed to
+	non-default servers. Thanks to Niax for the bug report.
+
+	Fix failure to build with DHCP support excluded. Thanks to 
+	Gustavo Zacarias for the patch.
+
+	Fix nasty regression in 2.64 which completely broke caching.
+
+
+version 2.64
+	Handle DHCP FQDN options with all flag bits zero and
+	--dhcp-client-update set. Thanks to Bernd Krumbroeck for
+	spotting the problem.
+
+	Finesse the check for /etc/hosts names which conflict with
+	DHCP names. Previously a name/address pair in /etc/hosts
+	which didn't match the name/address of a DHCP lease would
+	generate a warning. Now that only happens if there is not
+	also a match. This allows multiple addresses for a name in 
+	/etc/hosts with one of them assigned via DHCP.
+
+	Fix broken vendor-option processing for BOOTP. Thanks to
+	Hans-Joachim Baader for the bug report.
+
+	Don't report spurious netlink errors, regression in
+	2.63. Thanks to Vladislav Grishenko for the patch.
+
+	Flag DHCP or DHCPv6 in startup logging. Thanks to 
+	Vladislav Grishenko for the patch.
+
+	Add SetServersEx method in DBus interface. Thanks to Dan
+	Williams for the patch.
+
+	Add SetDomainServers method in DBus interface. Thanks to
+	Roy Marples for the patch.
+
+	Fix build with later Lua libraries. Thanks to Cristian
+	Rodriguez for the patch.
+
+	Add --max-cache-ttl option. Thanks to Dennis Kaarsemaker
+	for the patch.
+
+	Fix breakage of --host-record parsing, resulting in
+	infinite loop at startup. Regression in 2.63. Thanks to
+	Haim Gelfenbeyn for spotting this.
+
+	Set SO_REUSEADDRESS and SO_V6ONLY options on the DHCPv6
+	socket, this allows multiple instances of dnsmasq on a
+	single machine, in the same way as for DHCPv4. Thanks to
+	Gene Czarcinski and Vladislav Grishenko for work on this.
+
+	Fix DHCPv6 to do access control correctly when it's 
+	configured with --listen-address. Thanks to
+	Gene Czarcinski for sorting this out. 
+
+	Add a "wildcard" dhcp-range which works for any IPv6
+	subnet, --dhcp-range=::,static Useful for Stateless 
+	DHCPv6. Thanks to Vladislav Grishenko for the patch.
+
+	Don't include lease-time in DHCPACK replies to DHCPINFORM
+	queries, since RFC-2131 says we shouldn't. Thanks to
+	Wouter Ibens for pointing this out.  
+
+	Makefile tweak to do dependency checking on header files.
+	Thanks to Johan Peeters for the patch.
+
+	Check interface for outgoing unsolicited router 
+	advertisements, rather than relying on interface address 
+	configuration. Thanks to Gene Czarinski for the patch.
+
+	Handle better attempts to transmit on interfaces which are
+	still doing DAD, and specifically do not just transmit
+	without setting source address and interface, since this
+	can cause very puzzling effects when a router
+	advertisement goes astray. Thanks again to Gene Czarinski.
+
+	Get RA timers right when there is more than one
+	dhcp-range on a subnet.
+
+
+version 2.63
+	Do duplicate dhcp-host address check in --test mode.
+
+	Check that tftp-root directories are accessible before
+	start-up. Thanks to Daniel Veillard for the initial patch.
+
+	Allow more than one --tfp-root flag. The per-interface
+	stuff is pointless without that.
+
+	Add --bind-dynamic. A hybrid mode between the default and
+	--bind-interfaces which copes with dynamically created
+	interfaces. 
+
+	A couple of fixes to the build system for Android. Thanks
+	to Metin Kaya for the patches.
+
+	Remove the interface:<interface> argument in --dhcp-range, and
+	the interface argument to --enable-tftp. These were a
+	still-born attempt to allow automatic isolated
+	configuration by libvirt, but have never (to my knowledge)
+	been used, had very strange semantics, and have been
+	superseded by other mechanisms. 
+
+	Fixed bug logging filenames when duplicate dhcp-host
+	addresses are found. Thanks to John Hanks for the patch.
+
+	Fix regression in 2.61 which broke caching of CNAME
+	chains. Thanks to Atul Gupta for the bug report.
+
+	Allow the target of a --cname flag to be another --cname.
+
+	Teach DHCPv6 about the RFC 4242 information-refresh-time
+	option, and add parsing if the minutes, hours and days
+	format for options. Thanks to Francois-Xavier Le Bail for
+	the suggestion.
+
+	Allow "w" (for week) as multiplier in lease times, as well
+	as seconds, minutes, hours and days.  Álvaro Gámez Machado 
+	spotted the omission.
+
+	Update French translation. Thanks to Gildas Le Nadan.
+
+	Allow a DBus service name to be given with --enable-dbus
+	which overrides the default,
+	uk.org.thekelleys.dnsmasq. Thanks to Mathieu
+	Trudel-Lapierre for the patch. 
+
+	Set the "prefix on-link" bit in Router
+	Advertisements. Thanks to Gui Iribarren for the patch.
+
+
+version 2.62
+	Update German translation. Thanks to Conrad Kostecki.
+
+	Cope with router-solict packets which don't have a valid 
+	source address. Thanks to Vladislav Grishenko for the patch.
+
+	Fixed bug which caused missing periodic router
+	advertisements with some configurations. Thanks to
+	Vladislav Grishenko for the patch.
+
+	Fixed bug which broke DHCPv6/RA with prefix lengths 
+	which are not divisible by 8. Thanks to Andre Coetzee 
+	for spotting this.
+
+	Fix non-response to router-solicitations when
+	router-advertisement configured, but DHCPv6 not
+	configured. Thanks to Marien Zwart for the patch.
+
+	Add --dns-rr, to allow arbitrary DNS resource records.
+
+	Fixed bug which broke RA scheduling when an interface had
+	two addresses in the same network. Thanks to Jim Bos for
+	his help nailing this.
+
+version 2.61
+	Re-write interface discovery code on *BSD to use
+	getifaddrs. This is more portable, more straightforward,
+	and allows us to find the prefix length for IPv6
+	addresses.
+
+	Add ra-names, ra-stateless and slaac keywords for DHCPv6.
+	Dnsmasq can now synthesise AAAA records for dual-stack 
+	hosts which get IPv6 addresses via SLAAC. It is also now 
+	possible to use SLAAC and stateless DHCPv6, and to 
+	tell clients to use SLAAC addresses as well as DHCP ones.
+	Thanks to Dave Taht for help with this.
+
+	Add --dhcp-duid to allow DUID-EN uids to be used.
+
+	Explicitly send DHCPv6 replies to the correct port, instead
+	of relying on clients to send requests with the correct
+	source address, since at least one client in the wild gets
+	this wrong. Thanks to Conrad Kostecki for help tracking
+	this down.
+
+	Send a preference value of 255 in DHCPv6 replies when 
+	--dhcp-authoritative is in effect. This tells clients not
+	to wait around for other DHCP servers.
+
+	Better logging of DHCPv6 options.
+
+	Add --host-record. Thanks to Rob Zwissler for the
+	suggestion.
+
+	Invoke the DHCP script with action "tftp" when a TFTP file
+	transfer completes. The size of the file, address to which
+	it was sent and complete pathname are supplied. Note that
+	version 2.60 introduced some script incompatibilities
+	associated with DHCPv6, and this is a further change. To
+	be safe, scripts should ignore unknown actions, and if
+	not IPv6-aware, should exit if the environment
+	variable DNSMASQ_IAID is set. The use-case for this is
+	to track netboot/install.  Suggestion from Shantanu
+	Gadgil.
+
+	Update contrib/port-forward/dnsmasq-portforward to reflect
+	the above.
+
+	Set the environment variable DNSMASQ_LOG_DHCP when running
+	the script id --log-dhcp is in effect, so that script can
+	taylor their logging verbosity. Suggestion from Malte
+	Forkel.
+
+	Arrange that addresses specified with --listen-address
+	work even if there is no interface carrying the
+	address. This is chiefly useful for IPv4 loopback
+	addresses, where any address in 127.0.0.0/8 is a valid
+	loopback address, but normally only 127.0.0.1 appears on
+	the lo interface. Thanks to Mathieu Trudel-Lapierre for
+	the idea and initial patch. 
+
+	Fix crash, introduced in 2.60, when a DHCPINFORM is
+	received from a network which has no valid dhcp-range.
+	Thanks to Stephane Glondu for the bug report.
+
+	Add a new DHCP lease time keyword, "deprecated" for
+	--dhcp-range. This is only valid for IPv6, and sets the
+	preferred lease time for both DHCP and RA to zero. The
+	effect is that clients can continue to use the address 
+	for existing connections, but new connections will use
+	other addresses, if they exist. This makes hitless
+	renumbering at least possible.
+
+	Fix bug in address6_available() which caused DHCPv6 lease
+	acquisition to fail if more than one dhcp-range in use.
+
+	Provide RDNSS and DNSSL data in router advertisements,
+	using the settings provided for DHCP options
+	option6:domain-search and option6:dns-server.
+
+	Tweak logo/favicon.ico to add some transparency. Thanks to
+	SamLT for work on this.
+
+	Don't cache data from non-recursive nameservers, since it
+	may erroneously look like a valid CNAME to a non-existent
+	name. Thanks to Ben Winslow for finding this.
+
+	Call SO_BINDTODEVICE on the DHCP socket(s) when doing DHCP
+	on exactly one interface and --bind-interfaces is set. This 
+	makes the OpenStack use-case of one dnsmasq per virtual
+	interface work. This is only available on Linux; it's not
+	supported on other platforms. Thanks to Vishvananda Ishaya
+	and the OpenStack team for the suggestion.
+
+	Updated French translation. Thanks to Gildas Le Nadan.
+
+	Give correct from-cache answers to explicit CNAME queries.
+	Thanks to Rob Zwissler for spotting this.
+
+	Add --tftp-lowercase option. Thanks to Oliver Rath for the
+	patch. 
+
+	Ensure that the DBus DhcpLeaseUpdated events are generated
+	when a lease goes through INIT_REBOOT state, even if the
+	dhcp-script is not in use. Thanks to Antoaneta-Ecaterina
+	Ene for the patch.
+
+	Fix failure of TFTP over IPv4 on OpenBSD platform. Thanks
+	to Brad Smith for spotting this.
+
+
+version 2.60
+	Fix compilation problem in Mac OS X Lion. Thanks to Olaf
+	Flebbe for the patch.
+
+	Fix DHCP when using --listen-address with an IP address
+	which is not the primary address of an interface.
+
+	Add --dhcp-client-update option.
+
+	Add Lua integration. Dnsmasq can now execute a DHCP
+	lease-change script written in Lua. This needs to be
+	enabled at compile time by setting HAVE_LUASCRIPT in 
+	src/config.h or running "make COPTS=-DHAVE_LUASCRIPT"
+	Thanks to Jan-Piet Mens for the idea and proof-of-concept 
+	implementation.
+
+	Tidied src/config.h to distinguish between
+	platform-dependent compile-time options which are selected
+	automatically, and builder-selectable compile time
+	options. Document the latter better, and describe how to
+	set them from the make command line.
+
+	Tidied up IPPROTO_IP/SOL_IP (and IPv6 equivalent)
+	confusion. IPPROTO_IP works everywhere now.
+
+	Set TOS on DHCP sockets, this improves things on busy
+	wireless networks. Thanks to Dave Taht for the patch.
+
+	Determine VERSION automatically based on git magic:
+	release tags or hash values.
+
+	Improve start-up speed when reading large hosts files 
+	containing many distinct addresses.
+
+	Fix problem if dnsmasq is started without the stdin,
+	stdout and stderr file descriptors open. This can manifest
+	itself as 100% CPU use. Thanks to Chris Moore for finding
+	this.
+
+	Fix shell-scripting bug in bld/pkg-wrapper. Thanks to 
+	Mark Mitchell for the patch.
+
+	Allow the TFP server or boot server in --pxe-service, to
+	be a domain name instead of an IP address. This allows for
+	round-robin to multiple servers, in the same way as
+	--dhcp-boot. A good suggestion from Cristiano Cumer.
+
+	Support BUILDDIR variable in the Makefile. Allows builds 
+	for multiple archs from the same source tree with eg.
+	make BUILDDIR=linux             (relative to dnsmasq tree)
+	make BUILDDIR=/tmp/openbsd      (absolute path)
+	If BUILDDIR is not set, compilation happens in the src
+	directory, as before. Suggestion from Mark Mitchell.
+
+	Support DHCPv6. Support is there for the sort of things
+	the existing v4 server does, including tags, options, 
+	static addresses and relay support. Missing is prefix 
+	delegation, which is probably not required in the dnsmasq
+	niche, and an easy way to accept prefix delegations from
+	an upstream DHCPv6 server, which is. Future plans include
+	support for DHCPv6 router option and MAC address option
+	(to make selecting clients by MAC address work like IPv4).
+	These will be added as the standards mature.
+	This code has been tested, but this is the first release,
+	so don't bet the farm on it just yet. Many thanks to all 
+	testers who have got it this far.
+
+	Support IPv6 router advertisements. This is a
+	simple-minded implementation, aimed at providing the
+	vestigial RA needed to go alongside IPv6. Is picks up
+	configuration from the DHCPv6 conf, and should just need
+	enabling with --enable-ra.   
+
+	Fix long-standing wrinkle with --localise-queries that
+	could result in wrong answers when DNS packets arrive
+	via an interface other than the expected one. Thanks to 
+	Lorenzo Milesi and John Hanks for spotting this one.
+
+	Update French translation. Thanks to Gildas Le Nadan.
+
+	Update Polish translation. Thanks to Jan Psota.
+
+
+version 2.59
+	Fix regression in 2.58 which caused failure to start up
+	with some combinations of dnsmasq config and IPv6 kernel
+	network config. Thanks to Brielle Bruns for the bug
+	report.
+
+	Improve dnsmasq's behaviour when network interfaces are
+	still doing duplicate address detection (DAD). Previously,
+	dnsmasq would wait up to 20 seconds at start-up for the
+	DAD state to terminate. This is broken for bridge
+	interfaces on recent Linux kernels, which don't start DAD
+	until the bridge comes up, and so can take arbitrary
+	time. The new behaviour lets dnsmasq poll for an arbitrary
+	time whilst providing service on other interfaces. Thanks
+	to Stephen Hemminger for pointing out the problem.
+
+
+version 2.58
+	Provide a definition of the SA_SIZE macro where it's 
+	missing. Fixes build failure on openBSD.
+
+	Don't include a zero terminator at the end of messages
+	sent to /dev/log when /dev/log is a datagram socket.
+	Thanks to Didier Rabound for spotting the problem.
+
+	Add --dhcp-sequential-ip flag, to force allocation of IP
+	addresses in ascending order. Note that the default
+	pseudo-random mode is in general better but some
+	server-deployment applications need this.
+
+	Fix problem where a server-id of 0.0.0.0 is sent to a
+	client when a dhcp-relay is in use if a client renews a
+	lease after dnsmasq restart and before any clients on the
+	subnet get a new lease. Thanks to Mike Ruiz for assistance
+	in chasing this one down. 
+
+	Don't return NXDOMAIN to an AAAA query if we have CNAME
+	which points to an A record only: NODATA is the correct
+	reply in this case. Thanks to Tom Fernandes for spotting
+	the problem.
+
+	Relax the need to supply a netmask in --dhcp-range for
+	networks which use a DHCP relay. Whilst this is still
+	desirable, in the absence of a netmask dnsmasq will use
+	a default based on the class (A, B, or C) of the address. 
+	This should at least remove a cause of mysterious failure 
+	for people using RFC1918 addresses and relays.
+
+	Add support for Linux conntrack connection marking. If 
+	enabled with --conntrack, the connection mark for incoming
+	DNS queries will be copied  to the outgoing connections
+	used to answer those queries. This allows clever firewall
+	and accounting stuff. Only available if dnsmasq is
+	compiled with HAVE_CONNTRACK and adds a dependency on 
+	libnetfilter-conntrack. Thanks to Ed Wildgoose for the
+	initial idea, testing and sponsorship of this function.
+
+	Provide a sane error message when someone attempts to 
+	match a tag in --dhcp-host.
+
+	Tweak the behaviour of --domain-needed, to avoid problems
+	with recursive nameservers downstream of dnsmasq. The new
+	behaviour only stops A and AAAA queries, and returns
+	NODATA rather than NXDOMAIN replies. 
+
+	Efficiency fix for very large DHCP configurations, thanks
+	to James Gartrell and Mike Ruiz for help with this. 
+
+	Allow the TFTP-server address in --dhcp-boot to be a
+	domain-name which is looked up in /etc/hosts. This can 
+	give multiple IP addresses which are used round-robin,
+	thus doing TFTP server load-balancing. Thanks to Sushil
+	Agrawal for the patch.
+
+	When two tagged dhcp-options for a particular option
+	number are both valid, use the one which is valid without
+	a tag from the dhcp-range. Allows overriding of the value
+	of a DHCP option for a particular host as well as
+	per-network values.  So 
+	--dhcp-range=set:interface1,......
+	--dhcp-host=set:myhost,.....  
+	--dhcp-option=tag:interface1,option:nis-domain,"domain1" 
+	--dhcp-option=tag:myhost,option:nis-domain,"domain2" 
+	will set the NIS-domain to domain1 for hosts in the range, but
+	override that to domain2 for a particular host.
+
+	Fix bug which resulted in truncated files and timeouts for
+	some TFTP transfers. The bug only occurs with netascii
+	transfers and needs an unfortunate relationship between
+	file size, blocksize and the number of newlines in the
+	last block before it manifests itself. Many thanks to 
+	Alkis Georgopoulos for spotting the problem and providing
+	a comprehensive test-case. 
+
+	Fix regression in TFTP server on *BSD platforms introduced
+	in version 2.56, due to confusion with sockaddr
+	length. Many thanks to Loic Pefferkorn for finding this.
+
+	Support scope-ids in IPv6 addresses of nameservers from
+	/etc/resolv.conf and in --server options. Eg
+	nameserver fe80::202:a412:4512:7bbf%eth0 or
+	server=fe80::202:a412:4512:7bbf%eth0. Thanks to 
+	Michael Stapelberg for the suggestion.
+
+	Update Polish translation, thanks to Jan Psota.
+
+	Update French translation. Thanks to Gildas Le Nadan.
+
+
+version 2.57
+	Add patches to allow build under Android.
+
+	Provide our own header for the DNS protocol, rather than
+	relying on arpa/nameser.h. This has proved more or less
+	defective over the years and the final straw is that it's
+	effectively empty on Android.
+
+	Fix regression in 2.56 which caused hex constants in
+	configuration to be rejected if they contain the '*'
+	wildcard.
+
+	Correct wrong casts of arguments to ctype.h functions,
+	isdigit(), isxdigit() etc. Thanks to Matthias Andree for
+	spotting this.
+
+	Allow build with IDN support independently from i18n. 
+	IDN support continues to be included automatically 
+	when i18n is included. 
+	'make COPTS=-DHAVE_IDN' is the magic incantation. 
+
+	Modify check on extraneous command line junk (added in
+	2.56) so that it doesn't complain about extra _empty_ 
+	arguments. Otherwise this breaks libvirt.
+
+
+version 2.56
+	Add a patch to allow dnsmasq to get interface names right in a
+	Solaris zone. Thanks to Dj Padzensky for this.
+
+	Improve data-type parsing heuristics so that
+	--dhcp-option=option:domain-search,. 
+	treats the value as a string and not an IP address.
+	Thanks to Clemens Fischer for spotting that.
+
+	Add IPv6 support to the TFTP server. Many thanks to Jan 
+	'RedBully' Seiffert for the patches.
+
+	Log DNS queries at level LOG_INFO, rather then
+	LOG_DEBUG. This makes things consistent with DHCP
+	logging. Thanks to Adam Pribyl for spotting the problem.
+
+	Ensure that dnsmasq terminates cleanly when using
+	--syslog-async even if it cannot make a connection to the
+	syslogd.
+
+	Add --add-mac option. This is to support currently 
+	experimental DNS filtering facilities. Thanks to Benjamin
+	Petrin for the original patch. 
+
+	Fix bug which meant that tags were ignored in dhcp-range
+	configuration specifying PXE-proxy service. Thanks to
+	Cristiano Cumer for spotting this.
+
+	Raise an error if there is extra junk, not part of an
+	option, on the command line.
+
+	Flag a couple of log messages in cache.c as coming from
+	the DHCP subsystem. Thanks to Olaf Westrik for the patch.
+
+	Omit timestamps from logs when a) logging to stderr and 
+	b) --keep-in-foreground is set. The logging facility on the
+	other end of stderr can be assumed to supply them. Thanks
+	to John Hallam for the patch.
+
+	Don't complain about strings longer than 255 characters in
+	--txt-record, just split the long strings into 255
+	character chunks instead.
+
+	Fix crash on double-free. This bug can only happen when
+	dhcp-script is in use and then only in rare circumstances
+	triggered by high DHCP transaction rate and a slow
+	script. Thanks to Ferenc Wagner for finding the problem.
+
+	Only log that a file has been sent by TFTP after the
+	transfer has completed successfully. 
+
+	A good suggestion from Ferenc Wagner: extend
+	the --domain option to allow this sort of thing:
+	--domain=thekelleys.org.uk,192.168.0.0/24,local
+	which automatically creates
+	--local=/thekelleys.org.uk/
+	--local=/0.168.192.in-addr.arpa/ 
+
+	Tighten up syntax checking of hex constants in the config
+	file.  Thanks to Fred Damen for spotting this.
+
+	Add dnsmasq logo/icon, contributed by Justin Swift. Many
+	thanks for that.
+
+	Never cache DNS replies which have the 'cd' bit set, or
+	which result from queries forwarded with the 'cd' bit
+	set. The 'cd' bit instructs a DNSSEC validating server
+	upstream to ignore signature failures and return replies
+	anyway. Without this change it's possible to pollute the
+	dnsmasq cache with bad data by making a query with the
+	'cd' bit set and subsequent queries would return this data
+	without its being marked as suspect. Thanks to Anders
+	Kaseorg for pointing out this problem.
+
+	Add --proxy-dnssec flag, for compliance with RFC
+	4035. Dnsmasq will now clear the 'ad' bit in answers returned
+	from upstream validating nameservers unless this option is
+	set.
+
+	Allow a filename of "-" for --conf-file to read
+	stdin. Suggestion from Timothy Redaelli.
+
+	Rotate the order of SRV records in replies, to provide
+	round-robin load balancing when all the priorities are
+	equal. Thanks to Peter McKinney for the suggestion. 
+
+	Edit
+	contrib/MacOSX-launchd/uk.org.thekelleys.dnsmasq.plist 
+	so that it doesn't log all queries to a file by
+	default. Thanks again to Peter McKinney.    
+
+	By default, setting an IPv4 address for a domain but not
+	an IPv6 address causes dnsmasq to return
+	an NODATA reply for IPv6 (or vice-versa). So
+	--address=/google.com/1.2.3.4 stops IPv6 queries for
+	*google.com from being forwarded. Make it possible to
+	override this behaviour by defining the semantics if the
+	same domain appears in  both --server and --address.
+	In that case, the --address has priority for the address
+	family in which is appears, but the --server has priority
+	of the address family which doesn't appear in --address  
+	So:
+	--address=/google.com/1.2.3.4
+	--server=/google.com/#
+	will return 1.2.3.4 for IPv4 queries for *.google.com but
+	forward IPv6 queries to the normal upstream nameserver.
+	Similarly when setting an IPv6 address
+	only this will allow forwarding of IPv4 queries. Thanks to
+	William for pointing out the need for this.
+
+	Allow more than one --dhcp-optsfile and --dhcp-hostsfile
+	and make them understand directories as arguments in the
+	same way as --addn-hosts. Suggestion from John Hanks. 
+
+	Ignore rebinding requests for leases we don't know
+	about. Rebind is broadcast, so we might get to overhear a
+	request meant for another DHCP server. NAKing this is
+	wrong. Thanks to Brad D'Hondt for assistance with this.
+
+	Fix cosmetic bug which produced strange output when
+	dumping cache statistics with some configurations. Thanks
+	to Fedor Kozhevnikov for spotting this.
+
+
+version 2.55
+	Fix crash when /etc/ethers is in use. Thanks to 
+	Gianluigi Tiesi for finding this.
+
+	Fix crash in netlink_multicast(). Thanks to Arno Wald for
+	finding this one.
+
+	Allow the empty domain "." in dhcp domain-search (119)
+	options. 
+
+
+version 2.54
+	There is no version 2.54 to avoid confusion with 2.53,
+	which incorrectly identifies itself as 2.54.
+
+
+version 2.53
+	Fix failure to compile on Debian/kFreeBSD. Thanks to 
+	Axel Beckert and Petr Salinger.
+
+	Fix code to avoid scary strict-aliasing warnings
+	generated by gcc 4.4.
+	
+	Added FAQ entry warning about DHCP failures with Vista
+	when firewalls block 255.255.255.255.
+	
+	Fixed bug which caused bad things to happen if a 
+	resolv.conf file which exists is subsequently removed.
+	Thanks to Nikolai Saoukh for the patch.
+
+	Rationalised the DHCP tag system. Every configuration item
+	which can set a tag does so by adding "set:<tag>" and
+	every configuration item which is conditional on a tag is
+	made so by "tag:<tag>". The NOT operator changes to '!',
+	which is a bit more intuitive too. Dhcp-host directives
+	can set more than one tag now. The old '#' NOT, 
+	"net:" prefix and no-prefixes are still honoured, so 
+	no existing config file needs to be changed, but 
+	the documentation and new-style config files should be 
+	much less confusing. 
+
+	Added --tag-if to allow boolean operations on tags. 
+	This allows complicated logic to be clearer and more 
+	general. A great suggestion from Richard Voigt. 
+
+	Add broadcast/unicast information to DHCP logging.
+
+	Allow --dhcp-broadcast to be unconditional.
+
+	Fixed incorrect behaviour with NOT <tag> conditionals in
+	dhcp-options. Thanks to Max Turkewitz for assistance
+	finding this.
+
+	If we send vendor-class encapsulated options based on the
+	vendor-class supplied by the client, and no explicit 
+	vendor-class option is given, echo back the vendor-class
+	from the client.
+	
+	Fix bug which stopped dnsmasq from matching both a
+	circuitid and a remoteid. Thanks to Ignacio Bravo for
+	finding this.
+
+	Add --dhcp-proxy, which makes it possible to configure
+	dnsmasq to use a DHCP relay agent as a full proxy, with
+	all DHCP messages passing through the proxy. This is
+	useful if the relay adds extra information to the packets
+	it forwards, but cannot be configured with the RFC 5107 
+	server-override option.
+
+	Added interface:<iface name> part to dhcp-range. The
+	semantics of this are very odd at first sight, but it
+	allows a single line  of the form
+	dhcp-range=interface:virt0,192.168.0.4,192.168.0.200
+	to be added to dnsmasq configuration which then supplies
+	DHCP and DNS services to that interface, without affecting
+	what services are supplied to other interfaces and 
+	irrespective of the existence or lack of 
+	interface=<interface> 
+	lines elsewhere in the dnsmasq configuration. The idea is
+	that such a line can be added automatically by libvirt
+	or equivalent systems, without disturbing any manual
+	configuration.
+
+	Similarly to the above, allow --enable-tftp=<interface>
+
+	Allow a TFTP root to be set separately for requests via
+	different interfaces, --tftp-root=<path>,<interface>             
+
+	Correctly handle and log clashes between CNAMES and 
+	DNS names being given to DHCP leases. This fixes a bug 
+	which caused nonsense IP addresses to be logged. Thanks to 
+	Sergei Zhirikov for finding and analysing the problem.
+
+	Tweak flush_log so as to avoid leaving the log
+	file in non-blocking mode. O_NONBLOCK is a property of the
+	file, not the process/descriptor.
+
+	Fix contrib/Solaris10/create_package
+	(/usr/man -> /usr/share/man) Thanks to Vita Batrla.
+
+	Fix a problem where, if a client got a lease, then went
+	to another subnet and got another lease, then moved back,
+	it couldn't resume the old lease, but would instead get 
+	a new address. Thanks to Leonardo Rodrigues for spotting
+	this and testing the fix.
+
+	Fix weird bug which sometimes omitted certain characters
+	from the start of quoted strings in dhcp-options. Thanks
+	to Dayton Turner for spotting the problem.
+
+	Add facility to redirect some domains to the standard
+	upstream servers: this allows something like 
+	--server=/google.com/1.2.3.4 --server=/www.google.com/#
+	which will send queries for *.google.com to 1.2.3.4,
+	except *www.google.com which will be forwarded as usual.
+	Thanks to AJ Weber for prompting this addition.
+
+	Improve the hash-algorithm used to generate IP addresses
+	from MAC addresses during initial DHCP address
+	allocation. This improves performance when large numbers
+	of hosts with similar MAC addresses all try and get an IP
+	address at the same time. Thanks to Paul Smith for his
+	work on this.
+
+	Tweak DHCP code so that --bridge-interface can be used to
+	select which IP alias of an interface should be used for
+	DHCP purposes on Linux. If eth0 has an alias eth0:dhcp
+	then adding  --bridge-interface=eth0:dhcp,eth0 will use 
+	the address of eth0:dhcp to determine the correct subnet 
+	for DHCP address allocation. Thanks to Pawel Golaszewski 
+	for prompting this and Eric Cooper for further testing.
+
+	Add --dhcp-generate-names. Suggestion by Ferenc Wagner.
+
+	Tweak DNS server selection algorithm when there is more
+	than one server available for a domain, eg.
+	--server=/mydomain/1.1.1.1
+	--server=/mydomain/2.2.2.2
+	Thanks to Alberto Cuesta-Canada for spotting a weakness
+	here.
+
+	Add --max-ttl. Thanks to Fredrik Ringertz for the patch.
+
+	Allow --log-facility=- to force all logging to
+	stderr. Suggestion from Clemens Fischer.
+
+	Fix regression which caused configuration like
+	--address=/.domain.com/1.2.3.4 to be rejected. The dot to the 
+	left of the domain has been implied and not required for a
+	long time, but it should be accepted for backward
+	compatibility. Thanks to Andrew Burcin for spotting this.
+
+	Add --rebind-domain-ok and --rebind-localhost-ok.
+	Suggestion from Clemens Fischer.
+
+	Log replies to queries of type TXT, when --log-queries 
+	is set.
+
+	Fix compiler warnings when compiled with -DNO_DHCP. Thanks
+	to Shantanu Gadgil for the patch.
+
+	Updated French translation. Thanks to Gildas Le Nadan.
+
+	Updated Polish translation. Thanks to Jan Psota.
+
+	Updated German translation. Thanks to Matthias Andree.
+
+	Added contrib/static-arp, thanks to Darren Hoo.
+
+	Fix corruption of the domain when a name from /etc/hosts
+	overrides one supplied by a DHCP client. Thanks to Fedor
+	Kozhevnikov for spotting the problem.
+
+	Updated Spanish translation. Thanks to Chris Chatham.
+
+
+version 2.52
+	Work around a Linux kernel bug which insists that the 
+	length of the option passed to setsockopt must be at least
+	sizeof(int) bytes, even if we're calling SO_BINDTODEVICE
+	and the device name is "lo".  Note that this is fixed 
+	in kernel 2.6.31, but the workaround is harmless and 
+	allows earlier kernels to be used. Also fix dnsmasq 
+	bug which reported the wrong address when this failed. 
+	Thanks to Fedor for finding this.
+
+	The API for IPv6 PKTINFO changed around Linux kernel
+	2.6.14. Workaround the case where dnsmasq is compiled
+	against newer headers, but then run on an old kernel:
+	necessary for some *WRT distros.
+
+	Re-read the set of network interfaces when re-loading
+	/etc/resolv.conf if --bind-interfaces is not set. This
+	handles the case that loopback interfaces do not exist
+	when dnsmasq is first started.
+
+	Tweak the PXE code to support port 4011. This should
+	reduce broadcasts and make things more reliable when other
+	servers are around. It also improves inter-operability
+	with certain clients.
+
+	Make a pxe-service configuration with no filename or boot 
+	service type legal: this does a local boot. eg.
+	pxe-service=x86PC, "Local boot" 
+
+	Be more conservative in detecting "A for A"
+	queries. Dnsmasq checks if the name in a type=A query looks
+	like a dotted-quad IP address and answers the query itself
+	if so, rather than forwarding it. Previously dnsmasq
+	relied in the library function inet_addr() to convert
+	addresses, and that will accept some things which are
+	confusing in this context, like 1.2.3 or even just
+	1234. Now we only do A for A processing for four decimal
+	numbers delimited by dots.
+
+	A couple of tweaks to fix compilation on Solaris. Thanks
+	to Joel Macklow for help with this.
+
+	Another Solaris compilation tweak, needed for Solaris
+	2009.06. Thanks to Lee Essen for that.
+
+	Added extract packaging stuff from Lee Essen to 
+	contrib/Solaris10.
+
+	Increased the default limit on number of leases to 1000
+	(from 150). This is mainly a defence against DoS attacks,
+	and for the average "one for two class C networks"
+	installation, IP address exhaustion does that just as
+	well. Making the limit greater than the number of IP
+	addresses available in such an installation removes a
+	surprise which otherwise can catch people out.
+
+	Removed extraneous trailing space in the value of the
+	DNSMASQ_TIME_REMAINING DNSMASQ_LEASE_LENGTH and
+	DNSMASQ_LEASE_EXPIRES environment variables. Thanks to
+	Gildas Le Nadan for spotting this.
+
+	Provide the network-id tags for a DHCP transaction to 
+	the lease-change script in the environment variable
+	DNSMASQ_TAGS. A good suggestion from Gildas Le Nadan.  
+
+	Add support for RFC3925 "Vendor-Identifying Vendor
+	Options". The syntax looks like this:  
+	--dhcp-option=vi-encap:<enterprise number>, .........
+
+	Add support to --dhcp-match to allow matching against
+	RFC3925 "Vendor-Identifying Vendor Classes". The syntax
+	looks like this:
+	--dhcp-match=tag,vi-encap<enterprise number>, <value>
+
+	Add some application specific code to assist in
+	implementing the Broadband forum TR069 CPE-WAN
+	specification. The details are in contrib/CPE-WAN/README
+
+	Increase the default DNS packet size limit to 4096, as
+	recommended by RFC5625 section 4.4.3. This can be
+	reconfigured using --edns-packet-max if needed. Thanks to
+	Francis Dupont for pointing this out.
+
+	Rewrite query-ids even for TSIG signed packets, since
+	this is allowed by RFC5625 section 4.5.
+
+	Use getopt_long by default on OS X. It has been supported
+	since version 10.3.0. Thanks to Arek Dreyer for spotting
+	this.
+
+	Added up-to-date startup configuration for MacOSX/launchd
+	in contrib/MacOSX-launchd. Thanks to Arek Dreyer for
+	providing this.
+
+	Fix link error when including Dbus but excluding DHCP. 
+	Thanks to Oschtan for the bug report.
+
+	Updated French translation. Thanks to Gildas Le Nadan.
+
+	Updated Polish translation. Thanks to Jan Psota.
+
+	Updated Spanish translation. Thanks to Chris Chatham.
+
+	Fixed confusion about domains, when looking up DHCP hosts
+	in /etc/hosts. This could cause spurious "Ignoring
+	domain..." messages. Thanks to Fedor Kozhevnikov for
+	finding and analysing the problem.
+
+
+version 2.51
+	Add support for internationalised DNS. Non-ASCII characters
+	in domain names found in /etc/hosts, /etc/ethers and 
+	/etc/dnsmasq.conf will be correctly handled by translation to
+	punycode, as specified in RFC3490. This function is only
+	available if dnsmasq is compiled with internationalisation
+	support, and adds a dependency on GNU libidn. Without i18n
+	support, dnsmasq continues to be compilable with just
+	standard tools. Thanks to Yves Dorfsman for the
+	suggestion. 
+
+	Add two more environment variables for lease-change scripts:
+	First, DNSMASQ_SUPPLIED_HOSTNAME; this is set to the hostname
+	supplied by a client, even if the actual hostname used is
+	over-ridden by dhcp-host or dhcp-ignore-names directives.
+	Also DNSMASQ_RELAY_ADDRESS which gives the address of 
+	a DHCP relay, if used.
+	Suggestions from Michael Rack.
+
+	Fix regression which broke echo of relay-agent
+	options. Thanks to Michael Rack for spotting this.
+
+	Don't treat option 67 as being interchangeable with
+	dhcp-boot parameters if it's specified as
+	dhcp-option-force.
+
+	Make the code to call scripts on lease-change compile-time
+	optional. It can be switched off by editing src/config.h
+	or building with "make COPTS=-DNO_SCRIPT".
+
+	Make the TFTP server cope with filenames from Windows/DOS
+	which use '\' as pathname separator. Thanks to Ralf for
+	the patch.
+
+	Updated Polish translation. Thanks to Jan Psota.
+
+	Warn if an IP address is duplicated in /etc/ethers. Thanks
+	to Felix Schwarz for pointing this out.
+
+	Teach --conf-dir to take an option list of file suffices
+	which will be ignored when scanning the directory. Useful
+	for backup files etc. Thanks to Helmut Hullen for the
+	suggestion. 
+
+	Add new DHCP option named tftpserver-address, which
+	corresponds to the third argument of dhcp-boot. This
+	allows the complete functionality of dhcp-boot to be
+	replicated with dhcp-option. Useful when using 
+	dhcp-optsfile.
+
+	Test which upstream nameserver to use every 10 seconds
+	or 50 queries and not just when a query times out and 
+	is retried. This should improve performance when there
+	is a slow nameserver in the list. Thanks to Joe for the
+	suggestion. 
+
+	Don't do any PXE processing, even for clients with the 
+	correct vendorclass, unless at least one pxe-prompt or 
+	pxe-service option is given. This stops dnsmasq 
+	interfering with proxy PXE subsystems when it is just 
+	the DHCP server. Thanks to Spencer Clark for spotting this.
+
+	Limit the blocksize used for TFTP transfers to a value
+	which avoids packet fragmentation, based on the MTU of the
+	local interface. Many netboot ROMs can't cope with
+	fragmented packets.
+
+	Honour dhcp-ignore configuration for PXE and proxy-PXE 
+	requests. Thanks to Niels Basjes for the bug report.
+
+	Updated French translation. Thanks to Gildas Le Nadan.
+
+
+version 2.50
+	Fix security problem which allowed any host permitted to 
+	do TFTP to possibly compromise dnsmasq by remote buffer 
+	overflow when TFTP enabled. Thanks to Core Security 
+	Technologies and Iván Arce, Pablo Hernán Jorge, Alejandro 
+	Pablo Rodriguez, Martín Coco, Alberto Soliño Testa and
+	Pablo Annetta. This problem has Bugtraq id: 36121 
+	and CVE: 2009-2957
+
+	Fix a problem which allowed a malicious TFTP client to 
+	crash dnsmasq. Thanks to Steve Grubb at Red Hat for 
+	spotting this. This problem has Bugtraq id: 36120 and 
+	CVE: 2009-2958
+
+
+version 2.49
+	Fix regression in 2.48 which disables the lease-change
+	script. Thanks to Jose Luis Duran for spotting this.
+
+	Log TFTP "file not found" errors. These were not logged,
+	since a normal PXELinux boot generates many of them, but
+	the lack of the messages seems to be more confusing than
+	routinely seeing them when there is no real error.
+
+	Update Spanish translation. Thanks to Chris Chatham.
+
+
+version 2.48
+	Archived the extensive, backwards, changelog to
+	CHANGELOG.archive. The current changelog now runs from
+	version 2.43 and runs conventionally.
+
+	Fixed bug which broke binding of servers to physical
+	interfaces when interface names were longer than four
+	characters. Thanks to MURASE Katsunori for the patch.
+
+	Fixed netlink code to check that messages come from the
+	correct source, and not another userspace process. Thanks
+	to Steve Grubb for the patch.
+
+	Maintainability drive: removed bug and missing feature
+	workarounds for some old platforms. Solaris 9, OpenBSD
+	older than 4.1, Glibc older than 2.2, Linux 2.2.x and 
+	DBus older than 1.1.x are no longer supported. 
+
+	Don't read included configuration files more than once:
+	allows complex configuration structures without problems.
+
+	Mark log messages from the various subsystems in dnsmasq:
+	messages from the DHCP subsystem now have the ident string
+	"dnsmasq-dhcp" and messages from TFTP have ident
+	"dnsmasq-tftp". Thanks to Olaf Westrik for the patch.
+
+	Fix possible infinite DHCP protocol loop when an IP
+	address nailed to a hostname (not a MAC address)  and a 
+	host sometimes provides the name, sometimes not.
+
+	Allow --addn-hosts to take a directory: all the files 
+	in the directory are read. Thanks to Phil Cornelius for 
+	the suggestion. 
+
+	Support --bridge-interface on all platforms, not just BSD.
+
+	Added support for advanced PXE functions. It's now
+	possible to define a prompt and menu options which will
+	be displayed when a client PXE boots. It's also possible to
+	hand-off booting to other boot servers. Proxy-DHCP, where
+	dnsmasq just supplies the PXE information and another DHCP
+	server does address allocation, is also allowed. See the
+	--pxe-prompt and --pxe-service keywords. Thanks to 
+	Alkis Georgopoulos for the suggestion and Guilherme Moro
+	and Michael Brown for assistance.
+
+	Improvements to DHCP logging. Thanks to Tom Metro for
+	useful suggestions.
+
+	Add ability to build dnsmasq without DHCP support. To do
+	this, edit src/config.h or build with
+	"make COPTS=-DNO_DHCP". Thanks to Mahavir Jain for the patch. 
+
+	Added --test command-line switch - syntax check
+	configuration files only.
+
+	Updated French translation. Thanks to Gildas Le Nadan.
+
+
+version 2.47
+	Updated French translation. Thanks to Gildas Le Nadan.
+
+	Fixed interface enumeration code to work on NetBSD
+	5.0. Thanks to Roy Marples for the patch. 
+
+	Updated config.h to use the same location for the lease
+	file on NetBSD as the other *BSD variants. Also allow
+	LEASEFILE and CONFFILE symbols to be overridden in CFLAGS.  
+
+	Handle duplicate address detection on IPv6 more
+	intelligently. In IPv6, an interface can have an address
+	which is not usable, because it is still undergoing DAD
+	(such addresses are marked "tentative"). Attempting to
+	bind to an address in this state returns an error,
+	EADDRNOTAVAIL. Previously, on getting such an error,
+	dnsmasq would silently abandon the address, and never
+	listen on it. Now, it retries once per second for 20
+	seconds before generating a fatal error. 20 seconds should
+	be long enough for any DAD process to complete, but can be
+	adjusted in src/config.h if necessary. Thanks to Martin
+	Krafft for the bug report.
+
+	Add DBus introspection. Patch from Jeremy Laine.
+
+	Update Dbus configuration file. Patch from Colin Walters.
+	Fix for this bug:
+	http://bugs.freedesktop.org/show_bug.cgi?id=18961
+
+	Support arbitrarily encapsulated DHCP options, suggestion
+	and initial patch from Samium Gromoff. This is useful for
+	(eg) gPXE, which expect all its private options to be
+	encapsulated inside a single option 175. So, eg, 
+
+	dhcp-option = encap:175, 190, "iscsi-client0"
+	dhcp-option = encap:175, 191, "iscsi-client0-secret"
+
+	will provide iSCSI parameters to gPXE.
+
+	Enhance --dhcp-match to allow testing of the contents of a
+	client-sent option, as well as its presence. This
+	application in mind for this is RFC 4578
+	client-architecture specifiers, but it's generally useful.
+	Joey Korkames suggested the enhancement. 
+
+	Move from using the IP_XMIT_IF ioctl to IP_BOUND_IF on
+	OpenSolaris. Thanks to Bastian Machek for the heads-up.
+
+	No longer complain about blank lines in
+	/etc/ethers. Thanks to Jon Nelson for the patch.
+
+	Fix binding of servers to physical devices, eg
+	--server=/domain/1.2.3.4@eth0 which was broken from 2.43
+	onwards unless --query-port=0 set. Thanks to Peter Naulls
+	for the bug report.
+
+	Reply to DHCPINFORM requests even when the supplied ciaddr
+	doesn't fall in any dhcp-range. In this case it's not
+	possible to supply a complete configuration, but
+	individually-configured options (eg PAC) may be useful.
+
+	Allow the source address of an alias to be a range:
+	--alias=192.168.0.0,10.0.0.0,255.255.255.0 maps the whole
+	subnet 192.168.0.0->192.168.0.255 to 10.0.0.0->10.0.0.255,
+	as before.
+	--alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0
+	maps only the 192.168.0.10->192.168.0.40 region. Thanks to
+	Ib Uhrskov for the suggestion.
+
+	Don't dynamically allocate DHCP addresses which may break
+	Windows.  Addresses which end in .255 or .0 are broken in
+	Windows even when using supernetting.
+	--dhcp-range=192.168.0.1,192.168.1.254,255,255,254.0 means 
+	192.168.0.255 is a valid IP address, but not for Windows. 
+	See Microsoft KB281579. We therefore no longer allocate 
+	these addresses to avoid hard-to-diagnose problems. 
+
+	Update Polish translation. Thanks to Jan Psota.
+
+	Delete the PID-file when dnsmasq shuts down. Note that by
+	this time, dnsmasq is normally not running as root, so
+	this will fail if the PID-file is stored in a root-owned
+	directory; such failure is silently ignored. To take
+	advantage of this feature, the PID-file must be stored in a
+	directory owned and write-able by the user running
+	dnsmasq.
+
+
+version 2.46
+	Allow --bootp-dynamic to take a netid tag, so that it may
+	be selectively enabled. Thanks to Olaf Westrik for the
+	suggestion. 
+
+	Remove ISC-leasefile reading code. This has been
+	deprecated for a long time, and last time I removed it, it
+	ended up going back by request of one user. This time,
+	it's gone for good; otherwise it would need to be
+	re-worked to support multiple domains (see below).
+
+	Support DHCP clients in multiple DNS domains. This is a
+	long-standing request. Clients are assigned to a domain
+	based in their IP address.  
+
+	Add --dhcp-fqdn flag, which changes behaviour if DNS names
+	assigned to DHCP clients. When this is set, there must be
+	a domain associated with each client, and only
+	fully-qualified domain names are added to the DNS. The
+	advantage is that the only the FQDN needs to be unique,
+	so that two or more DHCP clients can share a hostname, as
+	long as they are in different domains.
+
+	Set environment variable DNSMASQ_DOMAIN when invoking
+	lease-change script. This may be useful information to
+	have now that it's variable.
+
+	Tighten up data-checking code for DNS packet
+	handling. Thanks to Steve Dodd who found certain illegal
+	packets which could crash dnsmasq. No memory overwrite was
+	possible, so this is not a security issue beyond the DoS
+	potential.  
+
+	Update example config dhcp option 47, the previous
+	suggestion generated an illegal, zero-length,
+	option. Thanks to Matthias Andree for finding this.
+
+	Rewrite hosts-file reading code to remove the limit of
+	1024 characters per line. John C Meuser found this.
+
+	Create a net-id tag with the name of the interface on
+	which the DHCP request was received.
+
+	Fixed minor memory leak in DBus code, thanks to Jeremy
+	Laine for the patch.
+
+	Emit DBus signals as the DHCP lease database
+	changes. Thanks to Jeremy Laine for the patch.
+
+	Allow for more that one MAC address in a dhcp-host
+	line. This configuration tells dnsmasq that it's OK to
+	abandon a DHCP lease of the fixed address to one MAC
+	address, if another MAC address in the dhcp-host statement 
+	asks for an address. This is useful to give a fixed
+	address to a host which has two network interfaces
+	(say, a laptop with wired and wireless interfaces.) 
+	It's very important to ensure that only one interface 
+	at a time is up, since dnsmasq abandons the first lease 
+	and re-uses the address before the leased time has
+	elapsed. John Gray suggested this.
+
+	Tweak the response to a DHCP request packet with a wrong
+	server-id when --dhcp-authoritative is set; dnsmasq now
+	returns a DHCPNAK, rather than silently ignoring the
+	packet. Thanks to Chris Marget for spotting this
+	improvement.
+
+	Add --cname option. This provides a limited alias
+	function, usable for DHCP names. Thanks to AJ Weber for
+	suggestions on this.
+
+	Updated contrib/webmin with latest version from Neil
+	Fisher.
+
+	Updated Polish translation. Thanks to Jan Psota.
+
+	Correct the text names for DHCP options 64 and 65 to be
+	"nis+-domain" and "nis+-servers".
+
+	Updated Spanish translation. Thanks to Chris Chatham.
+
+	Force re-reading of /etc/resolv.conf when an "interface
+	up" event occurs.
+
+
+version 2.45
+	Fix total DNS failure in release 2.44 unless --min-port 
+	specified. Thanks to Steven Barth and Grant Coady for
+	bugreport. Also reject out-of-range port spec, which could
+	break things too: suggestion from Gilles Espinasse.
+
+
+version 2.44
+	Fix  crash when unknown client attempts to renew a DHCP
+	lease, problem introduced in version 2.43. Thanks to
+	Carlos Carvalho for help chasing this down.
+
+	Fix potential crash when a host which doesn't have a lease
+	does DHCPINFORM. Again introduced in 2.43. This bug has
+	never been reported in the wild.
+
+	Fix crash in netlink code introduced in 2.43. Thanks to
+	Jean Wolter for finding this.
+
+	Change implementation of min_port to work even if min-port
+	is large.
+
+	Patch to enable compilation of latest Mac OS X. Thanks to
+	David Gilman.
+
+	Update Spanish translation. Thanks to Christopher Chatham.
+
+
+version 2.43
+	Updated Polish translation. Thanks to Jan Psota.
+
+	Flag errors when configuration options are repeated
+	illegally.
+
+	Further tweaks for GNU/kFreeBSD
+
+	Add --no-wrap to msgmerge call - provides nicer .po file
+	format.
+
+	Honour lease-time spec in dhcp-host lines even for
+	BOOTP. The user is assumed to known what they are doing in
+	this case. (Hosts without the time spec still get infinite
+	leases for BOOTP, over-riding the default in the
+	dhcp-range.) Thanks to Peter Katzmann for uncovering this.
+
+	Fix problem matching relay-agent ids. Thanks to Michael
+	Rack for the bug report.
+
+	Add --naptr-record option. Suggestion from Johan
+	Bergquist.
+
+	Implement RFC 5107 server-id-override DHCP relay agent
+	option.
+
+	Apply patches from Stefan Kruger for compilation on
+	Solaris 10 under Sun studio.
+
+	Yet more tweaking of Linux capability code, to suppress
+	pointless wingeing from kernel 2.6.25 and above.
+
+	Improve error checking during startup. Previously, some
+	errors which occurred during startup would be worked
+	around, with dnsmasq still starting up. Some were logged,
+	some silent. Now, they all cause a fatal error and dnsmasq 
+	terminates with a non-zero exit code. The errors are those
+	associated with changing uid and gid, setting process 
+	capabilities and writing the pidfile. Thanks to Uwe
+	Gansert and the Suse security team for pointing out 
+	this improvement, and Bill Reimers for good implementation
+	suggestions.
+
+	Provide NO_LARGEFILE compile option to switch off largefile
+	support when compiling against versions of uclibc which
+	don't support it. Thanks to Stephane Billiart for the patch.
+
+	Implement random source ports for interactions with
+	upstream nameservers. New spoofing attacks have been found
+	against nameservers which do not do this, though it is not
+	clear if dnsmasq is vulnerable, since to doesn't implement
+	recursion. By default dnsmasq will now use a different
+	source port (and socket) for each query it sends
+	upstream. This behaviour can suppressed using the
+	--query-port option, and the old default behaviour
+	restored using --query-port=0. Explicit source-port
+	specifications in --server configs are still honoured.
+
+	Replace the random number generator, for better
+	security. On most BSD systems, dnsmasq uses the
+	arc4random() RNG, which is secure, but on other platforms,
+	it relied on the C-library RNG, which may be
+	guessable and therefore allow spoofing. This release
+	replaces the libc RNG with the SURF RNG, from Daniel
+	J. Berstein's DJBDNS package.  
+
+	Don't attempt to change user or group or set capabilities
+	if dnsmasq is run as a non-root user. Without this, the
+	change from soft to hard errors when these fail causes
+	problems for non-root daemons listening on high
+	ports. Thanks to Patrick McLean for spotting this.
+
+	Updated French translation. Thanks to Gildas Le Nadan.
+
+
+version 2.42
+	The changelog for version 2.42 and earlier is 
+	available in CHANGELOG.archive.
diff --git a/CHANGELOG.archive b/CHANGELOG.archive
new file mode 100755
index 0000000..2df495b
--- /dev/null
+++ b/CHANGELOG.archive
@@ -0,0 +1,2509 @@
+release 0.4 - initial public release
+
+release 0.5 - added caching, removed compiler warning on linux PPC
+
+release 0.6 - TCP handling: close socket and return to connect state if we 
+              can't read the first byte. This corrects a problem seen very 
+              occasionally where dnsmasq would loop using all available CPU.
+
+	      Added a patch from Cris Bailiff <c.bailiff@e-secure.com.au>
+	      to set SO_REUSEADDR on the tcp socket which stops problems when
+              dnsmasq is restarted and old connections still exist.
+
+	      Stopped claiming in doc.html that smail is the default Debian
+	      mailer, since it isn't any longer. (Pointed out by
+	      David Karlin <dkarlin@coloradomtn.edu>)
+
+release 0.7   Create a pidfile at /var/run/dnsmasq.pid
+
+	      Extensive armouring against "poison packets" courtesy of
+              Thomas Moestl <tmoestl@gmx.net>
+
+	      Set sockaddr.sa_family on outgoing address, patch from
+	      David Symonds <xoxus@usa.net>
+
+              Patch to clear cache on SIGHUP 
+	      from Jason L. Wagner <nialscorva@yahoo.com> 
+
+	      Fix bad bug resulting from not initialising value-result	
+	      address-length parameter to recvfrom() and accept() - it
+	      worked by luck before!
+
+release 0.95  Major rewrite: remove calls to gethostbyname() and talk
+              directly to the upstream server(s) instead.
+              This has many advantages.
+              (1) Dnsmasq no longer blocks during long lookups.
+              (2) All query types are handled now, (eg MX) not just internet
+                  address queries. Addresses are cached, all other
+                  queries are forwarded directly.
+              (3) Time-to-live data from upstream server is read and
+                  used by dnsmasq to purge entries from the cache.
+              (4) /etc/hosts is still read and its contents served (unless 
+	          the -h option is given).
+              (5) Dnsmasq can get its upstream servers from
+                  a file other than /etc/resolv.conf (-r option) this allows
+                  dnsmasq to serve names to the machine it is running
+                  on (put nameserver 127.0.0.1 in /etc/resolv.conf and
+                  give dnsmasq the option -r /etc/resolv.dnsmasq)
+              (6) Dnsmasq will re-read its servers if the
+                  modification time of resolv.conf changes. Along with
+                  4 above this allows nameservers to be set
+		  automatically by ppp or dhcp.	 
+
+              A really clever NAT-like technique allows the daemon to have lots
+              of queries in progress, but still remain very lightweight.
+	      Dnsmasq has a small footprint and normally doesn't allocate
+              any more memory after start-up. The NAT-like forwarding was
+              inspired by a suggestion from Eli Chen <eli@routefree.com>
+
+release 0.96  Fixed embarrassing thinko in cache linked-list code.
+                             
+release 0.98  Some enhancements and bug-fixes. 
+              Thanks to "Denis Carre" <denis.carre@laposte.net> and Martin 
+              Otte <otte@essc.psu.edu>	
+              
+	      (1) Dnsmasq now always sets the IP source address
+                  of its replies correctly. Older versions would not always
+                  do this on multi-homed and IP aliased hosts, which violates 
+                  the RFC.
+              (2) Dnsmasq no longer crashes if a server loop is created
+	          (ie dnsmasq is told to use itself as an upstream server.)
+                  Now it just logs the problem and doesn't use the bad 
+                  server address.
+              (3) Dnsmasq should now forward (but not cache) inverse queries 
+                  and server status queries; this feature has not been tested.
+              (4) Don't write the pid file when in non-daemon mode.
+	      (5) Create the pid file mode 644, rather then 666 (!).
+              (6) Generate queries to upstream nameservers with unpredictable
+                  ids, to thwart DNS spoofers.
+              (7) Dnsmasq no longer forwards queries when the 
+	          "recursion desired" bit is not set in the header.
+	      (8) Fixed getopt code to work on compilers with unsigned char.
+              
+release 0.991 Added -b flag: when set causes dnsmasq to always answer
+	      reverse queries on the RFC 1918 private IP space itself and
+              never forward them to an upstream server. If the name is not in
+	      /etc/hosts, dnsmasq replies with the dotted-quad address.
+              
+              Fixed a bug which stopped dnsmasq working on a box with
+              two or more interfaces with the same IP address. 
+
+              Fixed caching of CNAMEs. Previously, a CNAME which pointed
+              to  a name with many A records would not have all the addresses
+              returned when being answered from the cache.
+
+	      Thanks to "Steve Hardy" <s.a.hardy@connectux.com> for his input 
+              on these fixes.
+
+              Fixed race which could cause dnsmasq to miss the second of
+              two closely-spaced updates of resolv.conf (Thanks to Eli Chen
+              for pointing this out.)
+
+	      Fixed a bug which could cause dnsmasq to fail to cache some
+              dns names.
+
+release 0.992 Small change to memory allocation so that names in /etc/hosts
+              don't use cache slots. Also make "-c 0" flag meaningfully 
+              disable caching completely.                            
+
+release 0.993 Return only the first (canonical) name from an entry in
+	      /etc/hosts as reply to reverse query.
+              
+              Handle wildcard queries for names/addresses in /etc/hosts
+	      this is mainly to allow reverse lookups by dig to succeed.
+	      (Bug reported by Simon J. Rowe" <srowe@mose.org.uk>)  
+              
+              Subtle change to the logic which selects which of multiple
+	      upstream servers we send queries to. This fixes a problem 
+              where dnsmasq continuously sends queries to a server which
+	      is returning error codes and ignores one which is working.
+              
+release 0.994 Fixed bug which broke lookup of names in /etc/hosts
+              which have upper-case letters in them. Thanks for Joao Clemente
+              for spotting that one. 
+
+	      Output cache statistics on receipt of SIGUSR1. These go
+              to syslog except in debug (-d) mode, when a complete cache
+	      dump goes to stdout. Suggestion from Joao Clemente, code
+              based in John Volpe's.
+              
+	      Accept GNU long options on the command line. Code from 
+	      John Volpe for this. 
+
+              Split source code into multiple files and produced 
+	      a proper makefile. 
+              
+              Included code from John Volpe to parse dhcp.leases file
+              written by ISC dhcpd. The hostnames in the leases file are
+              added to the cache and updated as dhcpd updates the 
+              leases file. The code has been heavily re-worked by me,
+              so any bugs are probably mine.
+
+release 0.995 Small tidy-ups to signal handling and cache code.
+
+release 0.996 Added negative caching: If dnsmasq gets a "no such domain" reply
+              from an upstream nameserver, it will cache that information
+              for a time specified by the SOA RR in the reply. See RFC 2308
+              for details. This is useful with  resolver libraries
+              which append assorted suffices to non-FQDN in an attempt to 
+              resolve them, causing useless cache misses.
+
+              Added -i flag, which restricts dnsmasq to offering name service
+              only on specified interfaces.
+
+release 0.997 Deleted INSTALL script and added "install" target to makefile.
+
+              Stopped distributing binaries in the tarball to avoid 
+              libc version clashes.
+
+              Fixed  interface detection code to
+              remove spurious startup errors in rare circumstances.
+
+              Dnsmasq now changes its uid, irrevocably, to nobody after
+              startup for security reasons. Thanks to Peter Bailey for
+              this patch.
+
+	      Cope with infinite DHCP leases. Patch thanks to 
+	      Yaacov Akiba Slama.
+
+	      Added rpm control files to .tar.gz distribution. Thanks to
+              Peter Baldwin at ClarkConnect for those.
+
+              Improved startup script for rpms. Thanks to Yaacov Akiba Slama.
+
+release 1.0   Stable release: dnsmasq is now considered feature-complete
+              and stable.
+              
+release 1.1   Added --user argument to allow user to change to
+              a different userid.
+
+              Added --mx-target argument to allow mail to be delivered
+              away from the gateway machine running dnsmasq.
+
+              Fixed highly  obscure bug with wildcard queries for
+              DHCP lease derived names.
+
+              Moved manpage from section 1 to section 8.
+
+              Added --no-poll option.
+              Added Suse-rpm support.
+              Thanks to Joerg Mayer for the last two.
+
+release 1.2   Added IPv6 DNS record support. AAAA records are cached
+              and read from /etc/hosts. Reverse-lookups in the
+	      ip6.int and ip6.arpa domains are supported. Dnsmasq can
+              talk to upstream servers via IPv6 if it finds IP6 addresses
+              in /etc/resolv.conf and it offers DNS service automatically
+              if IPv6 support is present in the kernel.
+
+              Extended negative caching to NODATA replies.
+
+              Re-vamped CNAME processing to cope with RFC 2317's use of
+              CNAMES to PTR RRs in CIDR.
+
+              Added config.h and a couple of symbols to aid
+              compilation on non-linux systems.
+
+release 1.3   Some versions of the Linux kernel return EINVAL rather
+              then ENPROTONOSUPPORT when IPv6 is not available, 
+              causing dnsmasq to bomb out. This release fixes that.
+              Thanks to Steve Davis for pointing this one out.
+
+              Trivial change to startup logic so that dnsmasq logs
+              its stuff and reads config files straight away on
+              starting, rather than after the first query - principle 
+              of least surprise applies here.     
+
+release 1.4   Fix a bug with DHCP lease parsing which broke in
+              non-UTC timezones. Thanks to Mark Wormgoor for
+              spotting and diagnosing this. Fixed versions in
+              the .spec files this time. Fixed bug in Suse startup
+              script. Thanks to Didi Niklaus for pointing this out.
+
+release 1.5   Added --filterwin2k option which stops dnsmasq from forwarding
+	      "spam" queries from win2k boxes. This is useful to stop spurious
+              connections over dial-on-demand links. Thanks to Steve Hardy 
+              for this code.
+
+              Clear "truncated" bit in replies we return from upstream. This
+              stops resolvers from switching to TCP, which is pointless since
+              dnsmasq doesn't support TCP. This should solve problems
+              in resolving hotmail.com domains.
+
+              Don't include getopt.h when Gnu-long-options are disabled -
+              hopefully this will allow compilation on FreeBSD.
+
+	      Added the --listen-address and --pid-file flags.
+
+              Fixed a bug which caused old entries in the DHCP leases file
+              to be used in preference to current ones under certain
+              circumstances.
+
+release 1.6   If a machine gets named via DHCP and the DHCP name doesn't have
+              a domain part and domain suffix is set using the -s flag, then
+              that machine has two names with the same address, with and 
+              without the domain suffix. When doing a _reverse_ lookup to
+              get the name, the "without suffix" name used to be returned,
+              now the "with suffix" one gets returned instead. This change
+	      suggested by Arnold Schulz.
+
+              Fixed assorted typos in the documentation. Thanks 
+              to David Kimdon.
+
+              Subtle rearrangement to the downloadable tarball, and stopped
+              distributing .debs, since dnsmasq is now an official Debian
+              package.
+
+release 1.7   Fix a problem with cache not clearing properly
+              on receipt of SIGHUP. Bug spotted by Sat Deshpande.
+
+              In group-id changing code:
+	      1) Drop supplementary groups.
+              2) Change gid before dropping root (patch from Soewono Effendi.)
+              3) Change group to "dip" if it exists, to allow access
+                 to /etc/ppp/resolv.conf (suggestion from Jorg Sommer.)
+              Update docs to reflect above changes.
+
+              Other documentation changes from David Miller.
+              Added suggested script fragment for dhcpcd.exe.
+
+release 1.8   Fix unsafe use of tolower() macro - allows linking against 
+              ulibc. (Patches from Soewono Effendi and Bjorn Andersson.)
+
+              Fix typo in usage string.
+
+	      Added advice about RedHat PPP configuration to
+              documentation. (Thanks to C. Lee Taylor.)
+
+	      Patches to fix problems on BSD systems from Marc Huber
+              and Can Erkin Acar. These add the options
+              HAVE_ARC4RANDOM and HAVE_SOCKADDR_SA_LEN to config.h.
+	      Elaborated config.h - should really use autoconf.
+
+	      Fix time-to-live calculation when chasing CNAMEs.
+
+	      Fix use-after-free and missing initialisation bugs in
+              the cache code. (Thanks to Marc Huber.)
+
+              Builds on Solaris 9. (Thanks to Marc Huber.)           
+
+release 1.9   Fixes to rpm .spec files.
+
+              Don't put expired DHCP entries into the cache only to 
+	      throw them away again.
+
+              Put dnsmasq on a severe memory diet: this reduces both
+              the amount of heap space used and the stack size
+              required. The difference is not really visible with
+              bloated libcs like glibc, but should dramatically reduce
+              memory requirements when linked against ulibc for use on
+              embedded routers, and that's the point really. Thanks to
+              Matthew Natalier for prompting this.   
+
+	      Changed debug mode (-d) so that all logging appears on
+              stderr as well as going to syslogd. 
+
+	      Added HAVE_IPV6 config symbol to allow compilation
+              against a libc which doesn't have IPv6 support.
+
+	      Added a facility to log all queries, enabled with -q flag.
+
+	      Fixed packet size checking bug in address extraction code.
+
+	      Halved default cache size - 300 was way OTT in typical use.
+
+	      Added self-MX function, enabled by -e flag. Thanks to
+              Lyonel Vincent for the patch.
+
+	      Added HAVE_FORK config symbol and stuff to support
+              uClinux. Thanks to Matthew Natalier for uClinux stuff. 
+
+release 1.10  Log warnings if resolv.conf or dhcp.leases are not
+              accessible for any reason, as suggested by Hinrich Eilts.
+
+	      Fixed wrong address printing in error message about
+	      no interface with address.
+
+	      Updated docs and split installation instructions into setup.html.
+
+	      Fix bug in CNAME chasing code: One CNAME pointing
+	      to many A records would lose A records after the 
+	      first. This bug was introduced in version 1.9.
+
+	      Log startup failures at level Critical as well as 
+	      printing them to standard error.
+	      Exit with return code 1 when given bad options.
+
+	      Cleaned up code for no-cache operation.
+
+              Added -o option which forces dnsmasq to use to
+              upstream servers in the order they appear in /etc/resolv.conf.
+
+              Added upstream server use logging.
+
+              Log full cache dump on receipt of SIGUSR1 when query 
+              logging is enabled (-q switch).
+
+	      Added -S option to directly specify upstream servers and
+              added ability to direct queries for specific domains to
+              specific servers. Suggested by Jens Vonderheide.
+
+	      Upgraded random ID generation - patch from Rob Funk.	      
+
+	      Fixed reading of domains in arguments with capital
+              letters or trailing periods.
+
+	      Fixed potential SEGV when given bad options.
+
+	      Read options from /etc/dnsmasq.conf if it exists.
+              Do sensible things with missing parameters, eg 
+              "--resolv-file=" turns off reading /etc/resolv.conf.
+
+release 1.11  Actually implement the -R flag promised in the 1.10 man page.
+
+              Improve and rationalise the return codes in answers to
+              queries. In the case that there are no available
+              upstream servers to forward a query to, return REFUSED.
+              This makes sendmail work better on modem connected
+              systems when the modem link is down (Thanks to Roger Plant).
+	      Cache and return the NXDOMAIN status of failed queries:
+              this makes the `host` command work when traversing search
+              paths (Thanks to Peter Bailey). Set the "authoritative"
+              bit in replies containing names from /etc/hosts or DHCP.
+
+              Tolerate MS-DOS style line ending codes in /etc/hosts
+	      and /etc/resolv.conf, for people who copy from winsock
+              installations.
+
+	      Allow specification of more than one resolv.conf file. This is 
+              intended for laptops which connect via DHCP or
+              PPP. Whichever resolv.conf was updated last is used.
+
+              Allow -S flags which specify a domain but no server
+              address. This gives local domains which are never forwarded.
+
+	      Add -E flag to automatically add the domain suffix to
+              names in /etc/hosts -suggestion from Phil Harman.
+
+	      Always return a zero time-to-live for names derived from 
+	      DHCP which stops anything else caching these
+              names. Previously the TTL was derived from the lease
+              time but that is incorrect since a lease can be given
+              up early: dnsmasq would know this but anything with the
+              name cached with long TTL would not be updated.
+
+	      Extended HAVE_IPV6 config flag to allow compilation on
+	      old systems which don't have modern library routines
+	      like inet_ntop(). Thanks to Phil Harman for the patch.
+
+release 1.12  Allow more than one domain in server config lines and
+	      make "local" a synonym for "server". This makes things
+	      like "local=/localnet/thekelleys.org.uk/" legal. Allow
+              port to specified as part of server address.
+
+	      Allow whole domains to have an IP address specified
+              in /etc/dnsmasq.conf. (/etc/hosts doesn't work domains).
+              address=/doubleclick.net/127.0.0.1 should catch all
+              those nasty banner ads. Inspired by a patch 
+	      from Daniel Gryniewicz
+
+	      Log the source of each query when logging switched on. 
+
+	      Fix bug in script fragment for dhcpcd - thanks to Barry Stewart.
+	      
+	      Fix bug which meant that strict-order and self-mx were
+	      always enabled.
+
+	      Builds with Linux libc5 now - for the Freesco project.
+
+	      Fixed Makefile installation script (patch from Silvan
+	      Minghetti) and added CC and CFLAGS variables.
+
+	      Improve resource allocation to reduce vulnerability to
+	      DOS attacks - the old version could have all queries
+	      blocked by a continuous high-speed stream of
+	      queries. Now some queries will succeed, and the excess
+	      will be rejected with a server fail error. This change also
+	      protects against server-loops; setting up a resolving
+              loop between two instances of dnsmasq is no longer
+	      catastrophic. The servers will continue to run, looped
+	      queries fail and a warning is logged. Thanks to C. Lee
+	      Taylor for help with this.
+	      
+release 1.13  Added support for building rpms suitable for modern Suse 
+	      systems. (patch from Andi <cambeis@netplace.de>)
+	      
+	      Added options --group, --localmx, --local-ttl,
+	      --no-negcache, --addn-host.
+	      
+	      Moved all the various rpm-building bits into /rpm.
+	      
+	      Fix builds with glibc 2.1 (thanks to Cristian
+	      Ionescu-Idbohrn)
+	      
+	      Preserve case in domain names, as per RFC1035.
+	      
+	      Fixed ANY queries to domains with --address specification.
+	      
+	      Fixed FreeBSD build. (thanks to Steven Honson)
+	      
+	      Added -Q option which allows a specified port to be used
+	      to talk to upstream servers. Useful for people who want
+	      very paranoid firewalls which open individual UDP port.
+	      (thanks to David Coe for the patch)
+	      	      
+release 1.14  Fixed man page description of -b option which confused 
+	      /etc/hosts with /etc/resolv.conf. (thanks to Christopher
+	      Weimann)
+	      
+	      Fixed config.h to allow building under MACOS X and glibc
+	      2.0.x. (thanks to Matthew Gregan and Serge Caron)
+	      
+	      Added --except-interface option. (Suggested by Serge Caron)
+
+	      Added SIGUSR2 facility to re-scan for new
+	      interfaces. (Suggested by Serge Caron)
+
+	      Fixed SEGV in option-reading code for invalid options.
+	      (Thanks to Klaas Teschauer)
+
+              Fixed man page to clarify effect of SIGUSR1 on
+	      /etc/resolv.conf.
+	      (Thanks to Klaas Teschauer)
+	      
+	      Check that received queries have only rfc1035-legal characters
+	      in them. This check is mainly to avoid bad strings being
+	      sent to syslog.
+
+	      Fixed &&/& confusion in option.c and added DESTDIR
+	      variable for "make install" (Thanks to Osvaldo 
+              Marques for the patch.)
+
+	      Fixed /etc/hosts parsing code to cope with MS-DOS
+	      line-ends in the file. This was supposed to be done in
+	      version 1.11, but something got missed. (Thanks to Doug
+	      Copestake for helping to find this.)
+
+	      Squash repeated name/address pairs read from hosts
+	      files.
+
+	      Tidied up resource handling in util.c (Thanks to
+	      Cristian Ionescu-Idbohrn).
+
+	      Added hashed searching of domain names. People are starting
+	      to use dnsmasq with larger loads now, and bigger caches,
+	      and large lists of ad-block addresses. This means doing
+	      linear searches can start to use lots of CPU so I added hashed
+	      searching and seriously optimised the cache code for 
+	      algorithmic efficiency. Also upped the limit on cache 
+	      size to 10000.
+
+	      Fixed logging of the source of names from the additional
+	      hosts file and from the "bogus private address" option.
+
+	      Fixed spurious re-reading of empty lease files. (Thanks
+	      to Lewis Baughman for spotting this.)
+
+	      Fixed building under uclibc (patch from Cristian Ionescu-Idbohrn)
+	      
+	      Do some socket tweaking to allow dnsmasq to co-exist
+	      with BIND. Thanks to Stefan 'Sec' Zehl for the patch.
+
+release 1.15  Added --bogus-nxdomain option.
+
+              Restrict checking of resolv.conf and DHCP leases files
+              to once per second. This is intended to improve
+              performance under heavy loads. Also make a system call
+	      to get the current time once per query, rather than four
+              times.
+
+	      Increased number of outstanding queries to 150 in
+	      config.h
+
+release 1.16  Allow "/" characters in domain names - this fixes
+              caching of RFC 2317 CNAME-PTR records.
+
+	      Fixed brain-fart in -B option when GETOPT_LONG not
+	      enabled - thanks to Steven Young and Jason Miller 
+	      for pointing this out.
+
+	      Generalised bogus-nxdomain code: allow more than one
+	      address to check, and deal with replies with multiple
+	      answer records. (Based on contribution from Humberto
+	      Massa.)
+
+	      Updated the documentation to include information about
+	      bogus-nxdomain and the Verisign tragedy.
+
+	      Added libraries needed on Solaris to Makefile.
+
+	      Added facility to set source address in queries to
+	      upstream nameservers. This is useful with multihomed
+	      hosts, especially when using VPNs. Thanks to Tom Fanning
+	      for suggesting this feature.
+
+	      Tweaked logging: log to facility LOCAL0 when in
+	      debug/no-daemon mode and changed level of query logging
+	      from INFO to DEBUG. Make log options controllable in
+	      config.h
+
+release 1.17  Fixed crash with DHCP hostnames > 40 characters.
+
+              Fixed name-comparison routines to not depend on Locale,
+              in theory this versions since 1.15 could lock up or give
+              wrong results when run with locale != 'C'.
+
+	      Fix potential lockup in cache code. (thanks to Henning
+	      Glawe for help chasing this down.)
+
+	      Made lease-file reader bullet-proof.
+
+	      Added -D option, suggested by Peter Fichtner.
+
+release 1.18  Added round-robin DNS for names which have more than one
+              address. In this case all the addresses will be
+              returned, as before, but the order will change on each
+              query.
+
+	      Remove stray tolower() and isalnum() calls missed in 
+	      last release to complete LOCALE independence.
+
+	      Allow port numbers in source-address specifications.
+
+	      For hostnames without a domain part which don't get
+	      forwarded because -D is in effect, return NXDOMAIN not
+	      an empty reply.
+
+	      Add code to return the software version in response to the
+	      correct magic query in the same way as BIND. Use  
+	      "dig version.bind chaos txt" to make the query.
+
+	      Added negative caching for PTR (address to name) records.
+
+	       Ensure that names of the form typically used in PTR queries
+              (ie w.x.yz.in-addr.arpa and IPv6 equivalents) get
+              correct answers when queried as other types. It's
+              unlikely that anyone would do this, but the change makes
+              things pedantically correct.
+
+	      Taught dnsmasq to understand "bitstring" names, as these
+	      are used for PTR lookups of IPv6 addresses by some 
+	      resolvers and lookup tools. Dnsmasq now understands both
+	      the ip6.int domain and the ip6.arpa domain and both
+	      nibble and bitstring formats so it should work with any
+	      client code. Standards for this stuff have flip-flopped
+	      over the last few years, leaving many different clients
+	      in their wake. See RFC2673 for details of bitstrings.
+	      
+	      Allow '_' characters in domain names: Legal characters
+	      are now [a-z][A-Z].-_ Check names read from hosts files
+	      and leases files and reject illegal ones with a message
+	      in syslog. 
+
+	      Make empty domain names in server and address options 
+	      have the special meaning "unqualified
+	      names". (unqualified names are names without any dots in
+	      them). It's now possible to do server=//1.2.3.4 and have 
+	      unqualified names sent to a special nameserver.
+
+release 2.0rc1  
+              Moved source code into src/ directory.
+
+	      Fixes to cure compilation breakage when HAVE_IPV6 not
+	      set, thanks to Claas Hilbrecht.
+
+	      BIG CHANGE: added an integrated DHCP server and removed
+	      the code to read ISC dhcp.leases. This wins in terms 
+	      of ease of setup and configuration flexibility and 
+	      total machine resources consumed. 
+
+	      Re-jiged the signal handling code to remove a race
+	      condition and to be more portable.
+
+release 2.0
+	     Thanks to David Ashworth for feedback which informed many 
+	     of the fixes below.
+
+             Allow hosts to be specified by client ID in dhcp-hosts
+             options. These are now one of 
+             dhcp-host=<hardware addr>,.... 
+             dhcp-host=id:<hex client id>,..... 
+             dhcp-host=id:<ascii client id>,.....
+	     
+	     Allow dhcp-host options to specify any IP address on the
+             DHCP-served network, not just the range available for
+             dynamic allocation.
+
+	     Allow dhcp-host options for the same host with different
+	     IP addresses where the correct one will be selected for
+	     the network the host appears on.
+
+	     Fix parsing of --dhcp-option to allow more than one
+	     IP address and to allow text-type options.	     
+
+	     Inhibit use of --dhcp-option to send hostname DHCP options.
+	     
+	     Update the DNS with DHCP information after re-reading
+	     /etc/hosts so that any DHCP derived names which have been
+	     shadowed by now-deleted hosts entries become visible.
+
+	     Fix typos in dnsmasq.conf.example
+
+	     Fixes to Makefile(s) to help pkgsrc packaging - patch 
+	     from "pancake".
+
+	     Add dhcp-boot option to support network boot.
+
+	     Check for duplicate IP addresses in dhcp-hosts lines
+	     and refuse to run if found. If allowed to remain these 
+	     can provoke an infinite loop in the DHCP protocol.
+
+	     Attempted to rationalise the .spec files for rpm
+	     building. There are now files for Redhat, Suse and
+	     Mandrake. I hope they work OK.
+
+	     Fixed hard-to-reproduce crash involving use of local
+	     domains and IPv6 queries. Thanks to Roy Marples for
+	     helping to track that one down.
+
+release 2.1  
+             Thanks to Matt Swift and Dag Wieers for many suggestions 
+	     which went into this release.
+	    
+	     Tweak include files to allow compilation on FreeBSD 5
+             
+             Fix unaligned access warnings on BSD/Alpha.
+
+	     Allow empty DHCP options, like so: dhcp-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. Thanks
+	     to Jan Ischebeck for feedback on that.
+
+	     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". -
+             thanks to Chris Schank.
+
+	     Added support for max message size DHCP option.
+
+release 2.2
+             Fix total lack for DHCP functionality on
+	     Linux systems with IPv6 enabled. - thanks to
+	     Jonathon Hudson for spotting that.
+
+	     Move default config file under FreeBSD - patch from
+	     Steven Honson 
+
+release 2.3
+             Fix "install" makefile target. (reported by Rob Stevens)
+
+	     Ensure that "local=/domain/" flag is obeyed for all
+	     queries on a domain, not just A and AAAA. (Reported by
+	     Peter Fichtner.)
+
+	     Handle DHCPDECLINE messages and provide an error message
+	     in DHCPNAK messages.
+	     
+	     Add "domain" setting example to
+	     dnsmasq.conf.example. Thanks to K P Kirchdorfer for
+	     spotting that it was missing.
+
+	     Subtle change to the DHCPREQUEST handling code to work
+	     around a bug in the DHCP client in HP Jetdirect printers.
+	     Thanks to Marko Stolle for finding this problem.
+
+	     Return DHCP T1 and T2 times, with "fuzz" to desynchronise lease
+	     renewals, as specified in the RFC.
+	     
+	     Ensure that the END option is always present in DHCP
+	     packets , even if the packet is too small to fit all 
+	     the requested options.
+
+	     Handle larger-than-default DHCP packets if required, up
+	     to the ethernet MTU.
+
+	     Fix a couple of places where the return code from
+	     malloc() was not checked.
+
+	     Cope with a machine taking a DHCP lease and then moving
+	     network so that the lease address is no longer valid.
+
+	     The DHCP server will now work via a BOOTP relay - remote
+	     networks are configured with the dhcp-range option the
+	     same as directly connected ones, but they need an
+	     additional netmask parameter. Eg
+	     --dhcp-range=192.168.4.10,192.168.4.50,255.255,255.0
+             will enable DHCP service via a BOOTP relay on the
+	     192.168.4.0 network. 
+
+	     Add a limit on the number of available DHCP leases,
+	     otherwise the daemon could be DOSed by a malicious
+	     host. The default is 150, but it can be changed by the 
+	     dhcp-lease-max option.
+
+	     Fixed compilation on OpenBSD (thanks to Frederic Brodbeck
+	     for help with that.)
+	     
+	     Reworked the DHCP network handling code for two good
+	     effects: (1) The limit of one network only for DHCP on
+	     FreeBSD is now gone, (2) The DHCP server copes with
+	     dynamically created interfaces. The one-interface
+	     limitation remains for OpenBSD, which is missing
+	     extensions to the socket API which have been in Linux
+	     since version 2.2 and FreeBSD since version 4.8.
+
+	     Reworked the DNS network code to also cope with
+	     dynamically created interfaces. dnsmasq will now listen
+	     to the wildcard address and port 53 by default, so if no
+	     --interface or --address options are given it will handle
+	     dynamically created interfaces. The old behaviour can be
+	     restored with --bind-interfaces for people running BIND
+	     on one interface and dnsmasq on another. Note that
+	     --interface and --address options still work, but the
+	     filtering is done by dnsmasq, rather then the kernel.
+	     This works on Linux, and FreeBSD>=5.0. On systems which
+	     don't support the required API extensions, the old 
+	     behaviour is used, just as if --bind-interfaces had been set.
+
+	     Allow IPv6 support to be disabled at compile time. To do
+	     that, add -DNO_IPV6 to the CFLAGS. Thanks to Oleg
+	     I. Vdovikin for the suggestion to do that.
+
+	     Add ability to set DHCP options per network. This is done
+	     by giving a network an identifier like this:
+	     dhcp-range=red-net,192.168.0.10,192.168.0.50
+	     and then labeling options intended for that network only
+	     like this:
+	     dhcp-option=red-net,6,1.1.1.1
+	     Thanks to Oleg Vdovikin for arguing that one through.
+
+	     Made errors in the configuration file non-fatal: dnsmasq
+	     will now complain bitterly, but continue.
+
+	     Added --read-ethers option, to allow dnsmasq to pull
+	     static DHCP information from that file. 
+	     Thanks to Andi Cambeis for that suggestion.
+
+	     Added HAVE_BROKEN_RTC compilation option to support
+	     embedded systems without a stable RTC. Oleg Vdovikin
+	     helped work out how to make that work.
+
+release 2.4
+	     Fixed inability to start when the lease file doesn't
+	     already exist. Thanks to Dag Wieers for reporting that.
+
+	     Fixed problem were dhcp-host configuration options did
+	     not play well with entries in /etc/ethers for the same
+	     host. Thanks again to Dag Wieers.
+
+	     Tweaked DHCP code to favour moving to a newly-configured
+	     static IP address rather than an old lease when doing
+	     DHCP allocation.
+
+	     Added --alias configuration option. This provides IPv4
+	     rewrite facilities like Cisco "DNS doctoring". Suggested
+	     by Chad Skeeters.
+
+	     Fixed bug in /etc/ethers parsing code triggered by tab
+	     characters. Kudos to Dag Wieers for helping to nail that
+	     one.
+ 	     
+	     Added "bind-interfaces" option correctly.	     
+
+release 2.5
+	     Made "where are we allocating addresses?" code in DHCP
+	     server cope with requests via a relay which is on a
+	     directly connected network for which there is not a
+	     configured netmask. This strange state of affairs occurs
+	     with win4lin. Thanks to Alex Melt and Jim Horner for bug
+	     reports and testing with this. 
+
+	     Fixed trivial-but-irritating missing #include which broke
+	     compilation on *BSD.
+
+	     Force --bind-interfaces if IP-aliased interface
+	     specifications are used, since the sockets API provides
+	     no other sane way to determine which alias of an
+	     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.
+
+release 2.7  
+             Allow the dhcp-host specification of id:* which makes 
+	     dnsmasq ignore any client-id. This is useful to ensure 
+	     that a dual-boot machine sees the same lease when one OS 
+	     gives a client-id and the other doesn't. It's also useful
+	     when PXE boot DHCP does not use client IDs but the OS it boots 
+             does. Thanks to Grzegorz Nosek for suggesting this enhancement.
+
+	     No longer assume that ciaddr is zero in received DHCPDISCOVER 
+	     messages, just for security against broken clients.
+
+	     Set default of siaddr field to the address of the machine running 
+             dnsmasq when not explicitly set using dhcp-boot
+             option. This is the ISC dhcpd behaviour.  
+
+             Send T1 and T2 options in DHCPOFFER packets. This is required
+	     by the DHCP client in some JetDirect printers. Thanks 
+             to Paul Mattal for work on this.
+
+	     Fixed bug with DHCP on OpenBSD reported by Dominique Jacquel.
+	     The code which added loopback interfaces to the list
+	     was confusing the DHCP code, which expected one interface only.
+	     Solved by adding loopback interfaces to address list instead.
+
+	     Add dhcp-vendorclass option to allow options to be sent only
+	     to certain classes of clients.
+
+	     Tweaked option search code so that if a netid-qualified
+	     option is used, any unqualified option is ignored.
+	     
+	     Changed the method of picking new dynamic IP
+	     addresses. This used to use the next consecutive
+	     address as long it was free, now it uses a hash
+	     from the client hardware address. This reduces the amount
+	     of address movement for clients which let their lease
+	     expire and allows consecutive DHCPOFFERS to the same host
+	     to (almost always) be for the same address, without
+	     storing state before a lease is granted.
+ 
+	     Tweaked option handling code to return all possible
+	     options rather than none when DHCP "requested options"
+	     field is missing. This fixes interoperability with
+	     ancient IBM LANMAN DHCP clients. Thanks to Jim Louvau for
+	     help with this.
+
+release 2.8
+	     Pad DHCP packets to a minimum size of 300 bytes. This
+	     fixes interoperability problems with the Linux in-kernel
+	     DHCP/BOOTP client. Thanks to Richard Musil for
+	     diagnosing this and supplying a patch.
+
+	     Fixed option-parsing bug and potential memory leak. Patch
+	     from Richard Musil.
+
+	     Improved vendor class configuration and added user class
+	     configuration. Specifically: (1) options are matched on
+	     the netids from dhcp-range, dhcp-host, vendor class and
+	     user class(es). Multiple net-ids are allowed and options
+	     are searched on them all. (2) matches against vendor class
+	     and user class are now on a substring, if the given
+	     string is a substring of the vendor/user class, then a
+	     match occurs. Thanks again to Richard Musil for prompting
+	     this.
+
+	     Make "#" match any domain on --address and --server
+	     flags. --address=/#/1.2.3.4 will return 1.2.3.4 for _any_
+	     domain not otherwise matched. Of course
+	     --server=/#/1.2.3.4 is exactly equivalent to
+	     --server=1.2.3.4. Special request from Josh Howlett.
+	
+	     Fixed a nasty bug which would cause dnsmasq to lose track
+	     of leases for hosts which had a --dhcp-host flag without
+	     a name specification. The mechanism for this was that
+	     the hostname could get erroneously set as a zero-length
+	     string and then written to the leases file as a
+	     mal-formed line. Restarting dnsmasq would then lose the lease.
+	     Alex Hermann's work helped chase down this problem.
+
+	     Add checks against DHCP clients which return zero-length
+	     hostnames. This avoids the potential lease-loss problems
+	     referred to above. Also, if a client sends a hostname when
+	     it creates a lease but subsequently sends no or a
+	     zero-length hostname whilst renewing, continue to use the
+	     existing hostname, don't wipe it out. 
+	     
+	     Tweaked option parsing to flag some parameter errors.
+
+release 2.9
+	     Fixed interface filter code for two effects: 1) Fixed bug
+	     where queries sent via loopback interface
+	     but to the address of another interface were ignored
+	     unless the loopback interface was explicitly configured.
+	     2) on OpenBSD failure to configure one interface now
+	     causes a fatal error on startup rather than an huge
+	     stream of log messages. Thanks to Erik Jan Tromp for 
+	     finding that bug.
+
+	     Changed server selection strategy to improve performance
+	     when there are many available servers and some are
+	     broken. The new algorithm is to pick as before for the
+	     first try, but if a query is retried, to send to all
+	     available servers in parallel. The first one to reply
+	     then becomes preferred for the next query. This should 
+	     improve reliability without generating significant extra
+	     upstream load.
+
+	     Fixed breakage of special servers/addresses for
+	     unqualified domains introduced in version 2.8 
+	      
+	     Allow fallback to "bind-interfaces" at runtime: Some
+	     versions of *BSD seem to have enough stuff in the header
+	     files to build but no kernel support. Also now log if
+	     "bind-interfaces" is forced on.
+
+	     Log replies from upstream servers which refuse to do
+	     recursion - dnsmasq is not a recursive nameserver and
+	     relies on upstream servers to do the recursion, this
+	     flags a configuration error.
+
+	     Disable client-id matching for hosts whose MAC address is
+	     read from /etc/ethers. Patch from Oleg I. Vdovikin.
+
+	     Extended --mx-host flag to allow arbitrary targets for MX
+	     records, suggested by Moritz Bunkus.
+
+	     Fixed build under NetBSD 2.0 - thanks to Felix Deichmann
+	     for the patch.
+	     
+	     Deal correctly with repeated addresses in /etc/hosts. The
+	     first name found is now returned for reverse lookups,
+	     rather than all of them.
+
+	     Add back fatal errors when nonexistent 
+	     interfaces or interface addresses are given but only in
+	     "bind-interfaces" mode. Principle of least surprise applies.
+	     
+	     Allow # as the argument to --domain, meaning "read the
+	     domain from the first search directive in
+	     /etc.resolv.conf". Feature suggested by Evan Jones.
+
+release 2.10
+	    Allow --query-port to be set to a low port by creating and
+	    binding the socket before dropping root. (Suggestion from
+	    Jamie Lokier) 
+
+	    Support TCP queries. It turned out to be possible to do
+	    this with a couple of hundred lines of code, once I knew
+	    how. The executable size went up by a few K on i386.
+	    There are a few limitations: data obtained via TCP is not
+	    cached, and dynamically-created interfaces may break under
+	    certain circumstances. Source-address or query-port
+	    specifications are ignored for TCP.
+
+	    NAK attempts to renew a DHCP lease where the DHCP range
+	    has changed and the lease is no longer in the allowed
+	    range. Jamie Lokier pointed out this bug.
+
+	    NAK attempts to renew a pool DHCP lease when a statically
+	    allocated address has become available, forcing a host to
+	    move to its allocated address. Lots of people have
+	    suggested this change and been rebuffed (they know who
+	    they are) the straws that broke the camel's back were Tim
+	    Cutts and Jamie Lokier.
+
+	    Remove any nameserver records from answers which are
+	    modified by --alias flags. If the answer is modified, it
+	    cannot any longer be authoritative.
+
+	    Change behaviour of "bogus-priv" option to return NXDOMAIN
+	    rather than a PTR record with the dotted-quad address as
+	    name. The new behaviour doesn't provoke tcpwrappers like
+	    the old behavior did.
+
+	    Added a patch for the Suse rpm. That changes the default
+	    group to one suitable for Suse and disables inclusion of
+	    the ISC lease-file reader code. Thanks to Andy Cambeis for
+	    his ongoing work on Suse packaging.
+
+	    Support forwarding of EDNS.0 The maximum UDP packet size 
+	    defaults to 1280, but may be changed with the
+	    --edns-packet-max option. Detect queries with the do bit
+	    set and always forward them, since DNSSEC records are 
+	    not cached. This behaviour is required to make
+	    DNSSECbis work properly though dnsmasq. Thanks to Simon
+	    Josefsson for help with this.
+
+	    Move default config file location under OpenBSD from
+	    /usr/local/etc/dnsmasq.conf to /etc/dnsmasq.conf. Bug
+	    report from Jonathan Weiss.
+
+	    Use a lease with matching MAC address for a host which
+	    doesn't present a client-id, even if there was a client ID 
+	    at some point in the past. This reduces surprises when
+	    changing DHCP clients, adding id:* to a host, and from the
+	    semantics change of /etc/ethers in 2.9. Thanks to Bernard
+	    Sammer for finding that.
+
+	    Added a "contrib" directory and in it the dnslist utility,
+	    from Thomas Tuttle.
+
+	    Fixed "fail to start up" problems under Linux with IPv6
+	    enabled. It's not clear that these were an issue in
+	    released versions, but they manifested themselves when TCP
+	    support was added. Thanks to Michael Hamilton for
+	    assistance with this.
+
+version 2.11
+	    Fixed DHCP problem which could result in two leases in the
+            database with the same address. This looked much more
+            alarming then it was, since it could only happen when a
+            machine changes MAC address but kept the same name. The
+            old lease would persist until it timed out but things
+            would still work OK. 
+
+	    Check that IP addresses in all dhcp-host directives are
+	    unique and die horribly if they are not, since otherwise
+	    endless protocol loops can occur. 
+	    
+	    Use IPV6_RECVPKTINFO as socket option rather than
+	    IPV6_PKTINFO where available. This keeps late-model FreeBSD
+	    happy.
+
+	    Set source interface when replying to IPv6 UDP
+	    queries. This is needed to cope with link-local addresses.
+
+version 2.12
+            Added extra checks to ensure that DHCP created DNS entries 
+	    cannot generate multiple DNS address->name entries. Thanks to 
+	    Stefan Monnier for finding the exact set of configuration
+            options which could create this.
+
+	    Don't set the the filterwin2k option in the example config
+	    file and add warnings that is breaks Kerberos. Thanks to
+	    Simon Josefsson and Timothy Folks for pointing that out.
+	    
+	    Log types of incoming queries as well as source and domain.
+
+	    Log NODATA replies generated as a result of the
+	    filterwin2k option.
+
+version 2.13
+	    Fixed crash with un-named DHCP hosts introduced in 2.12.
+	    Thanks to Nicolo Wojewoda and Gregory Gathy for bug reports.
+
+version 2.14
+	    Fix DHCP network detection for hosts which talk via a
+	    relay. This makes lease renewal for such hosts work
+	    correctly.
+
+	    Support RFC3011 subnet selectors in the DHCP server.
+
+	    Fix DHCP code to generate RFC-compliant responses
+            to hosts in the INIT-REBOOT state.
+
+	    In the DHCP server, set the receive buffer size on 
+	    the transmit-only packet socket to zero, to avoid 
+	    waste of kernel buffers.
+
+	    Fix DHCP address allocation code to use the whole of
+	    the DHCP range, including the start and end addresses.
+	    
+	    Attempt an ICMP "ping" on new addresses before allocating 
+	    them to leases, to avoid allocating addresses which are in use.
+
+	    Handle rfc951 BOOTP as well as DHCP for hosts which have
+	    MAC address to IP address mapping defined.
+
+	    Fix compilation under MacOS X. Thanks to Chris Tomlinson.
+
+	    Fix compilation under NetBSD. Thanks to Felix Deichmann.
+
+	    Added "keep-in-foreground" option. Thanks to Sean
+	    MacLennan for the patch.
+
+version 2.15
+            Fixed NXDOMAIN/NODATA confusion for locally known
+            names. We now return a NODATA response for names which are
+            locally known. Now a query for (eg AAAA or MX) for a name
+	    with an IPv4 address in /etc/hosts which fails upstream
+            will generate a NODATA response. Note that the query 
+	    is still tried upstream, but a NXDOMAIN reply gets
+            converted to NODATA. Thanks to Eric de Thouars, Eric
+            Spakman and Mike Mestnik for bug reports/testing.
+
+	    Allow multiple dhcp-ranges within the same network. The
+	    original intention was that there would be a dhcp-range
+	    option for each network served, but there's no real reason
+	    not to allow discontinuous ranges within a network so this
+	    release adds support for that.
+
+	    Check for dhcp-ranges which are inconsistent with their 
+	    netmask, and generate errors or warnings.
+	    
+	    Improve error messages when there are problems with
+	    configuration.
+
+version 2.16
+	    Fixed typo in OpenBSD-only code which stopped compilation
+            under that OS. Chris Weinhaupl gets credit for reporting 
+            this.
+
+	    Added dhcp-authoritative option which restores non-RFC 
+	    compliant but desirable behaviour of pre-2.14 versions and
+            avoids long timeouts while DHCP clients try to renew leases
+            which are unknown to dnsmasq. Thanks to John Mastwijk for 
+	    help with this.	 
+
+	    Added support to the DHCP option code to allow RFC-3397 
+	    domain search DHCP option (119) to be sent.
+
+            Set NONBLOCK on all listening sockets to workaround non-POSIX
+            compliance in Linux 2.4 and 2.6. This fixes rare hangs which
+            occurred when corrupted packets were received. Thanks to
+	    Joris van Rantwijk for chasing that down.
+ 
+	    Updated config.h for NetBSD. Thanks to Martin Lambers.
+
+            Do a better job of distinguishing between retransmissions
+	    and new queries when forwarding. This fixes a bug
+	    triggered by the polipo web cache which sends A and AAAA
+	    queries both with the same transaction-ID. Thanks to 
+	    Joachim Berdal Haga and Juliusz Chroboczek for help with this.
+
+	    Rewrote cache code to store CNAMES, rather then chasing
+	    them before storage. This eliminates bad situations when
+	    clients get inconsistent views depending on if data comes
+	    from the cache.
+
+	    Allow for more than one --addn-hosts flag.
+
+	    Clarify logged message when a DHCP lease clashes with an
+	    /etc/hosts entry. Thanks to Mat Swift for the suggestion.
+
+	    Added dynamic-dnsmasq from Peter Willis to the contrib
+	    section.
+
+version 2.17
+	    Correctly deduce the size of numeric dhcp-options, rather
+	    than making wild guesses. Also cope with negative values.
+
+	    Fixed use of C library reserved symbol "index" which broke
+	    under certain combinations of library and compiler.
+
+	    Make bind-interfaces work for IPv6 interfaces too.
+
+	    Warn if an interface is given for listening which doesn't
+	    currently exist when not in bind-interfaces mode. (This is
+	    already a fatal error when bind-interfaces is set.)
+
+	    Allow the --interface and --except-interface options to
+	    take a comma-separated list of interfaces.
+
+	    Tweak --dhcp-userclass matching code to work with the
+	    ISC dhclient which violates RFC3004 unless its
+	    configuration is very warped. Thanks to Cedric Duval for
+	    the bug report. 
+
+	    Allow more than one network-id tag in a dhcp-option. All
+	    the tags must match to enable the option.
+
+	    Added dhcp-ignore option to disable classes of hosts based
+	    on network-id tags. Also allow BOOTP options to be
+	    controlled by network tags.
+
+	    Fill in sname, file and siaddr fields in replies to
+	    DHCPINFORM messages.
+
+	    Don't send NAK replies to DHCPREQUEST packets for disabled
+	    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
+	    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 occurred 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 particular, 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.
+
+version 2.20
+	    Allow more than one instance of dnsmasq to run on a
+	    machine, each providing DHCP service on a different
+	    interface, provided that --bind-interfaces is set. This
+	    configuration used to work, but regressed in version 2.14
+
+	    Fix compilation on Mac OS X. Thanks to Kevin Bullock.
+	
+	    Protect against overlong names and overlong
+	    labels in configuration and from DHCP.
+
+	    Fix interesting corner case in CNAME handling. This occurs
+	    when a CNAME has a target which "shadowed" by a name in
+	    /etc/hosts or from DHCP. Resolving the CNAME would sneak
+	    the upstream value of the CNAME's target into the cache,
+	    alongside the local value. Now that doesn't happen, though
+	    resolving the CNAME still gives the unshadowed value. This
+	    is arguably wrong but rather difficult to fix. The main
+	    thing is to avoid getting strange results for the target
+	    due to the cache pollution when resolving the
+	    CNAME. Thanks to Pierre Habouzit for exploring the corner
+	    and submitting a very clear bug report.
+
+	    Fix subtle bug in the DNS packet parsing code. It's almost
+	    impossible to describe this succinctly, but the one known
+	    manifestation is the inability to cache the A record for
+	    www.apple.com. Thanks to Bob Alexander for spotting that.
+
+	    Support SRV records. Thanks to Robert Kean for the patches
+	    for this.
+
+	    Fixed sign confusion in the vendor-id matching code which
+	    could cause crashes sometimes. (Credit to Mark Wiater for
+	    help finding this.)
+
+	    Added the ability to match the netid tag in a
+	    dhcp-range. Combined with the ability to have multiple
+	    ranges in a single subnet, this provides a means to
+	    segregate hosts on different address ranges based on
+	    vendorclass or userclass. Thanks to Mark Wiater for
+	    prompting this enhancement.    
+
+	    Added preference values for MX records.
+
+	    Added the --localise-queries option.
+
+version 2.21
+            Improve handling of SERVFAIL and REFUSED errors. Receiving
+	    these now initiates search for a new good server, and a 
+	    server which returns them is not a candidate as a good
+            server. Thanks to Istvan Varadi for pointing out the
+            problem.
+
+	    Tweak the time code in BROKEN_RTC mode.
+
+	    Sanity check lease times in dhcp-range and dhcp-host
+	    configurations and force them to be at least two minutes
+	    (120s) leases shorter than a minute confuse some clients,
+	    notably Apple MacOS X. Rory Campbell-Lange found this
+	    problem.
+
+	    Only warn once about an upstream server which is refusing to do
+	    recursive queries.
+
+	    Fix DHCP address allocation problem when netid tags are in
+	    use. Thanks to Will Murname for the bug report and
+	    subsequent testing.
+
+	    Add an additional data section to the reply for MX and SRV
+	    queries. Add support for DNS TXT records. Thanks to Robert 
+	    Kean and John Hampton for prompts and testing of these.
+
+	    Apply address rewriting to records in the additional data section
+	    of DNS packets. This makes things like MX records work
+	    with the alias function. Thanks to Chad Skeeters for
+	    pointing out the need for this.
+
+	    Added support for quoted strings in config file.
+
+	    Detect and defeat cache-poisoning attacks which attempt to
+	    send (malicious) answers to questions we didn't
+	    send. These are ignored now even if the attacker manages
+	    to guess a random query-id.
+
+	    Provide DHCP support for interfaces with multiple IP
+	    addresses or aliases. This in only enabled under Linux.
+	    See the FAQ entry for details.
+
+	    Revisit the MAC-address and client-id matching code to
+	    provide saner behaviour with PXE boots, where some
+	    requests have a client-id and some don't.
+
+	    Fixed off-by-one buffer overflow in lease file reading
+	    code. Thanks to Rob Holland for the bug report.
+
+	    Added wildcard matching for MAC addresses in dhcp-host
+	    options. A sensible suggestion by Nathaniel McCallum.
+
+version 2.22
+            Fixed build problems on (many) systems with older libc
+            headers where <linux/types.h> is required before
+            <linux/netlink.h>. Enabled HAVE_RTNETLINK under uclibc now
+            that this fix is in place.
+
+	    Added support for encapsulated vendor-class-specific DHCP
+	    options. Thanks to Eric Shattow for help with this.
+
+	    Fix regression in 2.21 which broke commas in filenames and
+	    corrupted argv. Thanks to Eric Scott for the bugreport.
+
+	    Fixed stupid thinko which caused dnsmasq to wedge during
+	    startup with certain MX-record options. Another 2.21 regression.
+
+	    Fixed broken-ness when reading /etc/ethers. 2.21 broke
+	    this too.
+
+	    Fixed wedge with certain DHCP options. Yet another 2.21
+	    regression. Rob Holland and Roy Marples chased this one
+	    down.
+
+version 2.23
+	    Added a check to ensure that there cannot be more than one
+	    dhcp-host option for any one IP address, even if the
+	    addresses are assigned indirectly via a hostname and
+	    /etc/hosts.
+
+	    Include a "server identifier" in DHCPNAK replies, as
+	    required by RFC2131.
+
+	    Added method  support for DBus
+	    (http://www.freedesktop.org/Software/dbus)
+	    This is a superior way to re-configure dnsmasq on-the-fly
+	    with different upstream nameservers, as the host moves
+	    between networks. DBus support must be enabled in
+	    src/config.h and should be considered experimental at this
+	    point. See DBus-interface for the specification of the
+	    DBus method calls supported.
+
+	    Added information to the FAQ about setting the DNS domain
+	    in windows XP and Mac OS X, thanks to Rick Hull.
+
+	    Added sanity check to resolv.conf polling code to cope
+	    with backwards-moving clocks. Thanks to Leonardo Canducci
+	    for	help with this.
+
+	    Handle so-called "A-for-A" queries, which are queries for
+	    the address associated with a name which is already a
+	    dotted-quad address. These should be handled by the
+	    resolver code, but sometimes aren't and there's no point
+	    in forwarding them.
+
+	    Added "no-dhcp-interface" option to disable DHCP service
+            on an interface, whilst still providing DNS.
+
+	    Fix format-string problem - config file names get passed
+	    to fprintf as a format string, so % characters could cause
+	    crashes. Thanks to Rob Holland for sleuthing that one.
+
+	    Fixed multiple compiler warnings from gcc 4. Thanks to 
+	    Tim Cutts for the report.
+
+	    Send the hostname option on DHCP offer messages as well as
+	    DHCP ack messages. This is required by the Rio Digital 
+	    Audio Receiver. Thanks to Ron Frederick for the patch.
+ 
+            Add 'd' (for day) as a possible time multiplier in lease 
+	    time specifications. Thanks to Michael Deegan.
+
+	    Make quoting suppress recognition of IP addresses, so
+	    dhcp-option=66,1.2.3.4 now means something different to
+            dhcp-option=66,"1.2.3.4", which sets the option to a
+	    string value. Thanks to Brian Macauley for the bug report.
+
+	    Fixed the option parsing code to avoid segfaults from some
+	    invalid configurations. Thanks to Wookey for spotting that one.
+ 
+            Provide information about which compile-time options were 
+	    selected, both in the log at startup and as part of the output 
+            from dnsmasq --version. Thanks to Dirk Schenkewitz for 
+            the suggestion. 
+
+	    Fix pathological behaviour when a broken client keeps sending
+            DHCPDISCOVER messages repeatedly and fast. Because dealing with
+            each of these takes a few seconds, (because of the ping) then a 
+	    queue of DHCP packets could build up. Now, the results of a ping 
+            test are assumed to be valid for 30 seconds, so repeated waits are
+            not required. Thanks to Luca Landi for finding this.
+
+	    Allow DHCPINFORM requests without hardware address
+	    information. These are generated by some browsers, looking
+	    for proxy information. Thanks to Stanley Jaddoe for the
+	    bug report on that.
+
+	    Add support of the "client FQDN" DHCP option. If present,
+	    this is used to allow the client to tell dnsmasq its name,
+	    in preference to (mis)using the hostname option. See 
+              http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/\
+                draft-ietf-dhc-fqdn-option-10.txt
+            for details of the draft spec.
+
+	    Added startup scripts for MacOS X Tiger/Panther to the 
+            contrib collection. Thanks to Tim Cutts.
+
+	    Tweak DHCP network selection so that clients which turn up
+	    on our network in REBINDING state and with a lease for a
+	    foreign network will get a NAK response. Thanks to Dan
+	    Shechter for work on this and an initial patch and thanks
+	    to Gyorgy Farkas for further testing.
+
+	    Fix DNS query forwarding for empty queries and forward
+	    queries even when the recursion-desired bit is clear. This
+	    allows "dig +trace" to work. Problem report from Uwe
+	    Gansert.
+
+	    Added "const" declarations where appropriate, thanks to
+	    Andreas Mohr for the patch.
+
+	    Added --bootp-dynamic option and associated
+	    functionality. Thanks to Josef Wolf for the suggestion.
+ 
+version 2.24
+            Updated contrib/openvpn/dnsmasq.patch from Joseph Tate.
+
+	    Tweaked DHCP NAK code, a DHCP NAK is now unicast as a
+	    fallback in cases where a broadcast is futile: namely in
+	    response to a unicast REQUEST from a non-local network
+	    which was not sent via a relay.
+
+	    Slightly changed the semantics of domain matching in
+	    --server and --address configs. --server=/domain.com/ still
+	    matches domain.com and sub.domain.com but does not 
+	    now match newdomain.com The semantics of 
+            --server=/.domain.com/ are unchanged. 
+	    Thanks to Chris Blaise for the patch.
+
+	    Added backwards-compatible internationalisation support.
+	    The existing make targets, (all, dnsmasq, install) work as
+	    before. New ones (all-i18n, and install-i18n) add gettext.
+	    The translations live in po/ There are not too many
+	    strings, so if anybody can provide translations (and for
+	    the manpage....) please send them in.
+
+	    Tweak behaviour on receipt of REFUSED or SERVFAIL rcodes,
+	    now the query gets retried on all servers before returning
+	    the error to the source of the query. Thanks to Javier
+	    Kohen for the report.
+ 
+	    Added Polish translation - thanks to Tomasz Sochanski.
+
+	    Changed default manpage install location from /usr/man 
+	    to /usr/share/man 
+
+	    Added Spanish translation - thanks to Christopher Chatham.
+
+	    Log a warning when a DHCP packet is truncated due to lack
+	    of space. (Thanks to Michael Welle for the prompt to do
+	    this.)
+	    
+	    Added French translation - thanks to Lionel Tricon.
+
+	    Added Indonesian translation - thanks to Salman AS.
+
+	    Tweaked the netlink code to cope with interface broadcast
+	    address not set, or set to 0.0.0.0.
+
+	    Fixed problem assigning fixed addresses to hosts when more
+	    than one dhcp-range is available. Thanks to Sorin Panca
+	    for help chasing this down.
+
+	    Added more explicit error messages to the hosts file and
+	    ethers file reading code. Markus Kaiserswerth suffered to
+	    make this happen.
+
+	    Ensure that a hostname supplied by a DHCP client can never
+	    override one configured on the server. Previously, any
+	    host claiming a name would be given it, even if that
+	    over-rode a dhcp-host declaration, leading to potentially 
+            confusing situations.
+
+	    Added Slackware package-build stuff into contrib/ The i18n
+	    effort broke the current scripts, and working ones were
+	    needed for testing, so they ended up here rather than make
+	    Pat re-invent the wheel.
+	    
+	    Added Romanian translation, thanks to Sorin Panca for
+	    that.
+
+version 2.25
+            Fixed RedHat spec file for FC4 - thanks to Werner Hoelzl
+            and Andrew Bird.
+
+            Fixed Suse spec file - thanks to Steven Springl.
+
+	    Fixed DHCP bug when two distinct subnets are on the same
+	    physical interface. Thanks to Pawel Zawora for finding
+	    this and suggesting the fix.
+
+	    Added logging to make it explicit when dnsmasq falls back
+	    from using RT-netlink sockets to the old ioctl API for
+	    getting information about interfaces. Doing this
+	    completely silently made remote debugging hard.
+
+	    Merged uclibc build fixes from the OpenWRT package into
+	    src/config.h 
+
+	    Added Norwegian translation - thanks to Jan Erik Askildt.
+
+version 2.26
+	    Fixed SuSe rpm patch problem - thanks to Steven Springl.
+
+	    Fixed crash when attempting to send a DHCP NAK to a host
+	    which believes it has a lease on an unknown
+	    network. Thanks to Lutz Pressler for the bug report and
+	    patch.
+
+version 2.27
+	    Tweaked DHCP behaviour when a client attempts to renew a lease
+            which dnsmasq doesn't know about. Previously that would always
+            result in a DHCPNAK. Now, in dhcp-authoritative mode, the
+            lease will be created, if it's legal. This makes dnsmasq work
+            better if the lease database is lost, for example on an OpenWRT
+	    system which reboots. Thanks to Stephen Rose for work on
+	    this.
+
+	    Added the ability to support RFC-3442 style destination
+	    descriptors in dhcp-options. This makes classless static
+	    routes easy to do, eg dhcp-option=121,192.168.1.0/24,1.2.3.4
+
+	    Added error-checking to the code which writes the lease
+	    file. If this fails for any reason, an error is logged,
+	    and a retry occurs after one minute. This should improve
+	    things eg when a filesystem is full. Thanks to Jens Holze
+	    for the bug report.
+
+	    Fixed breakage of the "/#/ matches any domain" facility
+	    which happened in 2.24. Thanks to Peter Surda for the bug
+	    report.
+
+	    Use "size_t" and "ssize_t" types where appropriate in the
+	    code.
+
+	    Fix buggy CNAME handling in mixed IPv4 and IPv6
+	    queries. Thanks to Andreas Pelme for help finding that.
+
+	    Added some code to attempt to re-transmit DNS queries when 
+	    a network interface comes up.  This helps on DoD links, 
+	    where frequently the packet which triggers dialling is
+            a DNS query, which then gets lost. By re-sending, we can 
+	    avoid the lookup failing. This function is only active
+	    when netlink support is compiled in, and therefore only
+	    under Linux. Thanks to Jean Wolter for help with this.
+
+	    Tweaked the DHCP tag-matching code to work correctly with
+	    NOT-tag conditions. Thanks to Lutz Pressler for finding
+	    the bug.
+
+	    Generalised netid-tag matching in dhcp-range statements to
+	    allow more than one tag.
+
+	    Added --dhcp-mac to do MAC address matching in the same
+	    way as vendorclass and userclass matching. A good
+	    suggestion from Lutz Pressler.
+
+	    Add workaround for buggy early Microsoft DHCP clients
+	    which need zero-termination in string options.
+	    Thanks to Fabiano Pires for help with this.
+
+	    Generalised the DHCP code to cope with any hardware
+	    address type, at least on Linux. *BSD is still limited to
+	    ethernet only.
+
+version 2.28
+            Eliminated all raw network access when running on
+            Linux. All DHCP network activity now goes through the IP
+            stack. Packet sockets are no longer required. Apart from
+            being a neat hack, this should also allow DHCP over IPsec
+            to work better. On *BSD and OS X, the old method of raw net
+            access through BPF is retained.
+
+	    Simplified build options. Networking is now slimmed down
+	    to a choice of "linux" or "other". Netlink is always used
+	    under Linux. Since netlink has been available since 2.2
+	    and non-optional in an IPv4-configured  kernel since 2.4,
+	    and the dnsmasq netlink code is now well tested, this 
+	    should work out fine. 
+
+	    Removed decayed build support for libc5 and Solaris.
+	    
+	    Removed pselect code: use a pipe for race-free signal
+	    handling instead, as this works everywhere.
+
+	    No longer enable the ISC leasefile reading code in the
+	    distributed sources. I doubt there are many people left
+	    using this 1.x compatibility code. Those that are will
+	    have to explicitly enable it in src/config.h.
+
+	    Don't send the "DHCP maximum message size" option, even if 
+	    requested. RFC2131 says this is a "MUST NOT".
+
+	    Support larger-than-minimum DHCP message. Dnsmasq is now
+	    happy to get larger than 576-byte DHCP messages, and will
+	    return large messages, if permitted by the "maximum
+	    message size" option of the message to which it is
+	    replying. There's now an arbitrary sanity limit of 16384
+	    bytes.
+
+	    Added --no-ping option. This fixes an RFC2131 "SHOULD".
+
+	    Building on the 2.27 MAC-address changes, allow clients to 
+	    provide no MAC address at all, relying on the client-id as
+	    a unique identifier. This should make things like DHCP for
+	    USB come easier.
+
+	    Fixed regression in netlink code under 2.2.x kernels which 
+	    occurred in 2.27. Erik Jan Tromp is the vintage kernel fan 
+	    who found this. P.S. It looks like this "netlink bind:
+	    permission denied" problem occurred in kernels at least as
+	    late a 2.4.18. Good information from Alain Richoux.
+
+	    Added a warning when it's impossible to give a host its
+	    configured address because the address is leased
+	    elsewhere.  A sensible suggestion from Mircea Bardac.
+
+	    Added minimal support for RFC 3046 DHCP relay agent-id
+	    options. The DHCP server now echoes these back to the
+	    relay, as required by the RFC. Also, RFC 3527 link selection 
+	    sub-options are honoured.
+
+	    Set the process "dumpable" flag when running in debug
+	    mode: this makes getting core dumps from root processes
+	    much easier.
+	    
+	    Fixed one-byte buffer overflow which seems to only cause
+	    problems when dnsmasq is linked with uclibc. Thanks to
+	    Eric House and Eric Spakman for help in chasing this down.
+
+	    Tolerate configuration screwups which lead to the DHCP
+	    server attempting to allocate its own address to a
+	    client; eg setting the whole subnet range as a DHCP
+	    range. Addresses in use by the server are now excluded
+	    from use by clients.
+
+	    Did some thinking about HAVE_BROKEN_RTC mode, and made it
+	    much simpler and better. The key is to just keep lease
+	    lengths in the lease file. Since these normally never
+	    change, even as the lease is renewed, the lease file never
+	    needs to change except when machines arrive on the network
+	    or leave. This eliminates the code for timed writes, and
+	    reduces the amount of wear on a flash filesystem to the
+	    absolute minimum. Also re-did the basic time function in
+	    this mode to use the portable times(), rather than parsing
+	    /proc/uptime.
+
+	    Believe the source port number when replying to unicast 
+	    DHCP requests and DHCP requests via a relay, instead of always 
+            using the standard ports.  This will allow relays on 
+            non-standard ports and DHCPINFORM from unprivileged ports
+            to work. The source port sent by unconfigured clients is still 
+            ignored, since this may be unreliable. This means that a DHCP 
+            client must use the standard port to do full configuration.
+ 
+version 2.29
+	    Fixed compilation on OpenBSD (thanks to Tom Hensel for the
+	    report). 
+
+	    Fixed false "no interface" errors when --bind-interfaces is
+	    set along with --interface=lo or --listen-address. Thanks
+	    to Paul Wise for the report.
+
+	    Updated patch for SuSE rpm. Thanks to Steven Springl.
+
+	    It turns out that there are some Linux kernel
+	    configurations which make using the capability system
+	    impossible. If this situation occurs then continue, running
+	    as root, and log a warning. Thanks to Scott Wehrenberg
+	    for help tracking this down.
+
+version 2.30
+            Fixed crash when a DHCP client requested a broadcast
+            reply. This problem was introduced in version 2.28.
+	    Thanks to Sandra Dekkers for the bug report.
+
+version 2.31
+	    Added --dhcp-script option. There have been calls for this
+	    for a long time from many good people. Fabio Muzzi gets
+	    the prize for finally convincing me.
+
+	    Added example dbus config file and moved dbus stuff into
+	    its own directory.
+
+	    Removed horribly outdated Redhat RPM build files. These
+	    are obsolete now that dnsmasq in in Fedora extras. Thanks
+	    to Patrick "Jima" Laughton, the Fedora package
+	    maintainer.
+
+	    Added workaround for Linux kernel bug. This manifests
+	    itself as failure of DHCP on kernels with "support for
+	    classical IP over ATM" configured. That includes most
+	    Debian kernel packages. Many thanks to A. Costa and
+	    Benjamin Kudria for their huge efforts in chasing this
+	    down.
+
+	    Force-kill child processes when dnsmasq is sent a sigterm,
+	    otherwise an unclosed TCP connection could keep dnsmasq
+	    hanging round for a few minutes.
+
+	    Tweaked config.h logic for uclibc build. It will now pick
+	    up MMU and IPV6 status correctly on every system I tested.
+
+version 2.32 
+	    Attempt a better job of replacing previous configuration
+	    when re-reading /etc/hosts and /etc/ethers. SIGHUP is
+	    still not identical to a restart under all circumstances,
+	    but it is for the common case of name->MAC address in
+	    /etc/ethers and name->IP address in /etc/hosts.
+
+	    Fall back to broadcast for DHCP to an unconfigured client
+	    when the MAC address size is greater than 14 bytes.
+
+	    Fix problem in 2.28-onwards releases which breaks DNS on
+	    Mac OS X. Thanks to Doug Fields for the bug report and
+	    testing.
+
+	    Added fix to allow compilation on c89-only compilers.
+	    Thanks to John Mastwijk for the patch.
+	   
+	    Tweak resolv file polling code to work better if there is
+	    a race between updating the mtime and file contents. This
+	    is not normally a problem, but it can be on systems which
+	    replace nameservers whilst active. The code now continues
+	    to read resolv.conf until it gets at least one usable
+	    server. Thanks to Holger Mauermann for help with this.
+
+	    If a client DECLINEs an address which is allocated to it
+	    via dhcp-host or /etc/hosts, lock that address out of use
+	    for ten minutes, instead of forever, and log when it's not
+	    being used because of the lock-out. This should provide
+	    less surprising behaviour when a configured address can't be
+	    used. Thanks to Peter Surda and Heinz Deinhart for input
+	    on this.
+
+	    Fixed *BSD DHCP breakage with only some
+	    arches/compilers, depending on structure padding rules.
+	    Thanks to Jeb Campbell and Tom Hensel for help with this.
+
+	    Added --conf-dir option. Suggestion from Aaron Tygart.
+
+	    Applied patch from Brent Cook which allows netids in
+	    dhcp-option configuration lines to be prefixed by
+	    "net:". This is not required by the syntax, but it is
+	    consistent with other configuration items.
+
+	    Added --log-facility option. Suggestion from Fabio Muzzi.
+
+	    Major update to Spanish translation. Many thanks to Chris
+	    Chatham. 
+
+	    Fixed gcc-4.1 strict-alias compilation warning.
+
+version 2.33
+            Remove bash-specific shellcode from the Makefile.
+
+	    Fix breakage with some DHCP relay implementations which
+	    was introduced in 2.28. Believing the source port in
+	    DHCP requests and sending the reply there is sometimes a
+	    bad thing to do, so I've reverted to always sending to
+	    the relay on port 68. Thanks to Daniel Hamlin and Alex
+	    (alde) for bug reports on this.
+
+	    Moved the SuSe packaging files to contrib. I will no
+	    longer attempt to maintain this in the source tarball. It
+	    will be done externally, in the same way as packaging for
+	    other distros. Suse packages are available from 
+	    ftp://ftp.suse.com/pub/people/ug/
+	    
+	    Merged patch from Gentoo to honour $LDFLAGS environment.
+
+	    Fix bug in resolv.conf processing when more than one file
+	    is being checked.
+
+	    Add --dns-forward-max option.
+
+	    Warn if --resolv-file flags are ignored because of
+	    --no-resolv. Thanks to Martin F Krafft for spotting this
+	    one.
+
+            Add --leasefile-ro option which allows the use of an 
+            external lease database. Many thanks to Steve Horbachuk 
+	    for assistance developing this feature.
+
+	    Provide extra information to lease-change script via its
+	    environment. If the host has a client-id, then
+	    DNSMASQ_CLIENT_ID will be set. Either the lease length (in
+	    DNSMASQ_LEASE_LENGTH) or lease expiry time (in
+	    DNSMASQ_LEASE_EXPIRES) will be set, depending on the
+	    HAVE_BROKEN_RTC compile-time option. This extra
+	    information should make it possible to maintain the lease
+	    database in external storage such as LDAP or a relational
+	    database. Note that while leasefile-ro is set, the script
+            will be called with "old"  events more often, since 
+	    changes to the client-id and lease length
+	    (HAVE_BROKEN_RTC) or lease expiry time (otherwise) 
+	    are now flagged. 
+
+	    Add contrib/wrt/* which is an example implementation of an
+	    external persistent lease database for *WRT distros with 
+	    the nvram command.
+
+	    Add contrib/wrt/dhcp_release.c which is a small utility 
+	    which removes DHCP leases using DHCPRELEASE operation in
+	    the DHCP protocol.
+
+version 2.34
+	    Tweak network-determination code for another corner case:
+	    in this case a host forced to move between dhcp-ranges on
+	    the same physical interface. Thanks to Matthias Andree.
+	    
+	    Improve handling of high DNS loads by throttling acceptance of
+	    new queries when resources are tight. This should be a
+	    better response than the "forwarding table full..."
+	    message which was logged before.
+
+	    Fixed intermittent infinite loop when re-reading
+	    /etc/ethers after SIGHUP. Thanks to Eldon Ziegler for the
+	    bug report.
+
+	    Provide extra information to the lease-change script: when
+	    a lease loses its hostname (because a new lease comes
+	    along and claims the same new), the "old" action is called 
+	    with the current state of the lease, ie no name. The
+	    change is to provide the former name which the lease had
+	    in the environment variable DNSMASQ_OLD_HOSTNAME. This
+	    helps scripts which do stuff based on hostname, rather
+	    than IP address. Also provide vendor-class and user-class
+	    information to the lease-change script when a new lease is
+	    created in the DNSMASQ_VENDOR_CLASS and
+	    DNSMASQ_USER_CLASS<n> environment variables. Suggestion 
+            from Francois-Xavier Le Bail.
+
+	    Run the lease change script as root, even when dnsmasq is
+	    configured to change UID to an unprivileged user. Since
+	    most uses of the lease change script need root, this
+	    allows its use whilst keeping the security advantages of
+	    running the daemon without privs. The script is invoked
+	    via a small helper process which keeps root UID, and
+	    validates all data received from the main process. To get
+	    root, an attacker would have to break dnsmasq and then
+	    break the helper through the restricted comms channel 
+	    linking the two.
+	    
+	    Add contrib/port-forward/* which is a script to set up 
+	    port-forwards using the DHCP lease-change script. It's
+	    possible to add a host to a config file by name, and when
+	    that host gets a DHCP lease, the script will use iptables
+	    to set up port-forwards to configured ports at the address
+	    which the host is allocated. The script also handles
+	    setting up the port-forward iptables entries after reboot,
+	    using the persistent lease database, and removing them
+	    when a host leaves and its DHCP lease expires.
+
+	    Fix unaligned access problem which caused wrong log
+	    messages with some clients on some architectures. Thanks
+	    to Francois-Xavier Le Bail for the bugreport.
+
+	    Fixed problem with DHCPRELEASE and multi-address
+	    interfaces. Enhanced contrib/wrt/dhcp_release to cope
+	    under these circumstances too. Thanks to Eldon Ziegler for
+	    input on this.
+
+	    Updated French translation: thanks to Gildas Le Nadan.
+
+	    Upgraded the name hash function in the DNS cache. Thanks
+	    to Oleg Khovayko for good work on this.
+
+	    Added --clear-on-reload flag.  Suggestion from Johannes
+	    Stezenbach.
+
+	    Treat a nameserver address of 0.0.0.0 as "nothing". Erwin 
+            Cabrera spotted that specifying a nameserver as 0.0.0.0 
+	    breaks things badly; this is because the network stack
+	    treats is as "this host" and an endless loop ensues.
+		   
+            Added Webmin module in contrib/webmin. Thanks to Neil
+            Fisher for that.
+
+version 2.35
+	    Generate an "old" script event when a client does a DHCPREQUEST
+	    in INIT-REBOOT or SELECTING state and the lease already
+	    exists. Supply vendor and user class information to these
+	    script calls.
+
+	    Added support for Dragonfly BSD to src/config.h
+
+	    Removed "Upgrading to 2.0" document, which is ancient
+	    history now.
+
+	    Tweak DHCP networking code for BSD, esp OpenBSD. Added a 
+	    workaround for a bug in OpenBSD 4.0: there should finally
+            be support for multiple interfaces under OpenBSD now.
+	    Note that no version of dnsmasq before 2.35 will work for 
+	    DHCP under OpenBSD 4.0 because of a kernel bug.
+	    Thanks to Claudio Jeker, Jeb Campbell and Cristobal 
+	    Palmer for help with this.
+
+	    Optimised the cache code for the case of large
+	    /etc/hosts. This is mainly to remove the O(n-squared)
+	    algorithm which made reading large (50000 lines) files 
+	    slow, but it also takes into account the size of 
+	    /etc/hosts when building hash tables, so overall 
+	    performance should be better. Thanks to "koko" for 
+	    pointing out the problem.
+
+version 2.36
+	    Added --dhcp-ignore-names flag which tells dnsmasq not to
+	    use names provided by DHCP clients. Suggestion from 
+	    Thomas M Steenholdt.
+
+	    Send netmask and broadcast address DHCP options always,
+	    even if the client doesn't request them. This makes a few
+	    odd clients work better.
+
+	    Added simple TFTP function, optimised for net-boot. It is
+	    now possible to net boot hosts using only dnsmasq. The
+	    TFTP server is read-only, binary-mode only, and designed to be
+	    secure; it adds about 4K to the dnsmasq binary. 
+ 
+	    Support DHCP option 120, SIP servers, (RFC 3361). Both
+            encodings are supported, so both --dhcp-option=120,192.168.2.3
+            and	--dhcp-option=120,sip.example.net will work. Brian
+            Candler pointed out the need for this.
+
+	    Allow spaces in domain names, to support DNS-SD.
+
+	    Add --ptr-record flag, again for DNS-SD. Thanks to Stephan 
+	    Sokolow for the suggestion.
+	    
+	    Tolerate leading space on lines in the config file. Thanks
+	    to Luigi Rizzo for pointing this out.
+
+	    Fixed netlink.c to cope with headers from the Linux 2.6.19
+	    kernel. Thanks to Philip Wall for the bug report.
+
+	    Added --dhcp-bridge option, but only to the FreeBSD
+	    build. This fixes an oddity with a a particular bridged
+	    network configuration on FreeBSD. Thanks to Luigi Rizzo
+	    for the patch.
+
+	    Added FAQ entry about running dnsmasq in a Linux
+	    vserver. Thanks to Gildas le Nadan for the information.  
+
+	    Fixed problem with option parsing which interpreted "/" as
+	    an address and not a string. Thanks to Luigi Rizzo
+	    for the patch.
+
+	    Ignore the --domain-needed flag when forwarding NS
+	    and SOA queries, since NS queries of TLDs are always legit.
+	    Marcus Better pointed out this problem.
+
+	    Take care to forward signed DNS requests bit-perfect, so
+	    as not to affect the validity of the signature. This
+	    should allow DDNS updates to be forwarded.
+
+version 2.37
+            Add better support for RFC-2855 DHCP-over-firewire and RFC
+           -4390 DHCP-over-InfiniBand. A good suggestion from Karl Svec.
+
+	    Some efficiency tweaks to the cache code for very large
+	    /etc/hosts files. Should improve reverse (address->name)
+	    lookups and garbage collection. Thanks to Jan 'RedBully'
+	    Seiffert for input on this.
+
+	    Fix regression in 2.36 which made bogus-nxdomain
+	    and DNS caching unreliable. Thanks to Dennis DeDonatis
+	    and Jan Seiffert for bug reports.
+
+	    Make DHCP encapsulated vendor-class	options sane. Be
+	    warned that some conceivable existing configurations 
+	    using these may break, but they work in a much 
+	    simpler and more logical way now. Prepending
+	    "vendor:<client-id>" to an option encapsulates it 
+	    in option 43, and the option is sent only if the 
+	    client-supplied vendor-class substring-matches with 
+	    the given client-id. Thanks to Dennis DeDonatis for 
+	    help with this.
+
+	    Apply patch from Jan Seiffert to tidy up tftp.c
+
+	    Add support for overloading the filename and servername 
+	    fields in DHCP packet. This gives extra option-space when
+	    these fields are not being used or with a modern client
+	    which supports moving them into options.
+
+	    Added a LIMITS section to the man-page, with guidance on
+	    maximum numbers of clients, file sizes and tuning.
+
+release 2.38
+	    Fix compilation on *BSD. Thanks to Tom Hensel.
+
+	    Don't send length zero DHCP option 43 and cope with 
+	    encapsulated options whose total length exceeds 255 octets
+	    by splitting them into multiple option 43 pieces.
+
+	    Avoid queries being retried forever when --strict-order is
+	    set and an upstream server returns a SERVFAIL
+	    error. Thanks to Johannes Stezenbach for spotting this.
+
+	    Fix BOOTP support, broken in version 2.37.
+
+	    Add example dhcp-options for Etherboot.
+
+	    Add \e (for ASCII ESCape) to the set of valid escapes
+	    in config-file strings.
+
+	    Added --dhcp-option-force flag and examples in the
+	    configuration file which use this to control PXELinux.
+
+	    Added --tftp-no-blocksize option.
+
+	    Set netid tag "bootp" when BOOTP (rather than DHCP) is in
+	    use. This makes it easy to customise which options are
+	    sent to BOOTP clients. (BOOTP allows only 64 octets for
+	    options, so it can be necessary to trim things.)
+
+	    Fix rare hang in cache code, a 2.37 regression. This
+	    probably needs an infinite DHCP lease and some bad luck to
+	    trigger. Thanks to Detlef Reichelt for bug reports and testing.
+
+release 2.39
+	    Apply patch from Mike Baker/OpenWRT to ensure that names
+	    like "localhost." in /etc/hosts with trailing period 
+	    are treated as fully-qualified.
+
+	    Tolerate and ignore spaces around commas in the
+	    configuration file in all circumstances. Note that this
+	    may change the meaning of a few existing config files, for
+	    instance
+	    txt-record=mydomain.com, string
+	    would have a leading space in the string before, and now
+	    will not. To get the old behaviour back, use quotes:
+	    txt-record=mydomain.com," string"
+
+	    /a is no longer a valid escape in quoted strings.
+
+	    Added symbolic DHCP option names. Instead of
+	    dhcp-option = 3, 1.2.3.4 
+	    it is now possible to do
+	    dhcp-option = option:router, 1.2.3.4
+	    To see the list of known DHCP options, use the 
+            command "dnsmasq --help dhcp"
+	    Thanks to Luigi Rizzo for a patch and good work on this.
+
+	    Overhauled the log code so that logging can be asynchronous; 
+	    dnsmasq then no longer blocks waiting for the syslog() library
+	    call. This is important on systems where syslog
+	    is being used to log over the network (and therefore doing
+	    DNS lookups) and syslog is using dnsmasq as its DNS
+	    server. Having dnsmasq block awaiting syslog under 
+	    such circumstances can lead to syslog and dnsmasq 
+	    deadlocking. The new behaviour is enabled with a new
+	     --log-async flag, which can also be used to tune the
+	    queue length. Paul Chambers found and diagnosed 
+	    this trap for the unwary. He also did much testing of 
+	    the solution along with Carlos Carvalho.
+
+	    --log-facility can now take a file-name instead of a 
+	    facility name. When this is done, dnsmasq logs to the 
+	    file and not via syslog. (Failures early in startup, 
+	    whilst reading configuration, will still go to syslog, 
+	    and syslog is used as a log-of-last-resort if the file
+	    cannot be written.)
+
+	    Added --log-dhcp flag. Suggestion from Carlos Carvalho.
+
+	    Made BINDIR, MANDIR and LOCALEDIR independently
+	    over-rideable in the makefile. Suggestion from Thomas
+	    Klausner.
+
+	    Added 127.0.0.0/8 and 169.254.0.0/16 to the address
+	    ranges affected by --bogus-priv. Thanks to  Paul 
+	    Chambers for the patch.
+
+	    Fixed failure of TFTP server with --listen-address. Thanks
+	    to William Dinkel for the bug report.
+
+	    Added --dhcp-circuitid and --dhcp-remoteid for RFC3046
+	    relay agent data matching.
+ 
+	    Added --dhcp-subscrid for RFC3993 subscriber-id relay
+	    agent data matching.
+
+	    Correctly garbage-collect connections when upstream
+	    servers go away as a result of DBus transactions.
+
+	    Allow absolute paths for TFTP transfers even when
+	    --tftp-root is set, as long as the path matches the root,
+	    so /var/ftp/myfile is OK with tftp-root=/var/ftp.
+	    Thanks for Thomas Mizzi for the patch.
+
+	    Updated Spanish translation - thanks to Chris Chatham.
+
+	    Updated French translation - thanks to Gildas Le Nadan.
+
+	    Added to example conf file example of routing PTR queries
+	    for a subnet to a different nameserver. Suggestion from
+	    Jon Nicholson.
+
+	    Added --interface-name option. This provides a facility 
+	    to add a domain name with a dynamic IP address taken from
+	    the address of a local network interface. Useful for
+	    networks with dynamic IPs.
+
+version 2.40
+            Make SIGUSR2 close-and-reopen the logfile when logging 
+	    direct to a file. Thanks to Carlos Carvalho for 
+	    suggesting this. When a logfile is created, change
+	    its ownership to the user dnsmasq will run as, don't
+	    leave it owned by root.
+
+	    Set a special tag, "known" for hosts which are matched by
+	    a dhcp-host or /etc/ethers line. This is especially
+	    useful to be able to do --dhcp-ignore=#known, like ISCs
+	    "deny unknown-clients".
+
+	    Explicitly set a umask before creating the leases file,
+	    rather than relying on whatever we inherited. The
+	    permissions	are set to 644.
+
+	    Fix handling of fully-qualified names in --dhcp-host
+	    directives and in /etc/ethers. These are now rejected 
+	    if the domain doesn't match that given by --domain,	  
+	    and used correctly otherwise. Before, putting
+	    a FQDN here could cause the whole FQDN to be used as
+	    hostname. Thanks to Michael Heimpold for the bug report.
+
+	    Massive but trivial edit to make the "daemon" variable 
+	    global, instead of copying the same value around as the
+	    first argument to half the functions in the program.
+	    
+	    Updated Spanish manpage and message catalog. Thanks 
+	    to Chris Chatham.
+	    
+	    Added patch for support of DNS LOC records in
+	    contrib/dns-loc. Thanks to Lorenz Schori.
+
+	    Fixed error in manpage: dhcp-ignore-name ->
+	    dhcp-ignore-names. Thanks to Daniel Mentz for spotting
+	    this.
+
+	    Use client-id as hash-seed for DHCP address allocation
+	    with Firewire and InfiniBand, as these don't supply an MAC
+	    address. 
+
+	    Tweaked TFTP file-open code to make it behave sensibly
+	    when the filesystem changes under its feet.
+
+	    Added DNSMASQ_TIME_REMAINING environment variable to the 
+	    lease-script.
+
+	    Always send replies to DHCPINFORM requests to the source
+	    of the request and not to the address in ciaddr. This
+	    allows third-party queries.
+	    
+	    Return "lease time remaining" in the reply to a DHCPINFORM
+	    request if there exists a lease for the host sending the
+	    request.
+
+	    Added --dhcp-hostsfile option. This gives a superset of
+	    the functionality provided by /etc/ethers. Thanks to 
+	    Greg Kurtzer for the suggestion.
+
+	    Accept keyword "server" as a synonym for "nameserver" in 
+	    resolv.conf. Thanks to Andrew Bartlett for the report.
+
+	    Add --tftp-unique-root option. Suggestion from Dermot
+	    Bradley.
+
+	    Tweak TFTP retry timer to avoid problems with difficult
+	    clients. Thanks to Dermot Bradley for assistance with
+	    this. 
+	    
+	    Continue to use unqualified hostnames provided by DHCP
+	    clients, even if the domain part is illegal. (The domain
+	    is	ignored, and an error logged.) Previously in this
+	    situation, the whole name would have been
+	    rejected. Thanks to Jima for the patch.
+	    
+	    Handle EINTR returns from wait() correctly and reap
+	    our children's children if necessary. This fixes 
+	    a problem with zombie-creation under *BSD when using
+	    --dhcp-script.
+
+	    Escape spaces in hostnames when they are stored in the
+	    leases file and passed to the lease-change
+	    script. Suggestion from Ben Voigt.
+
+	    Re-run the lease change script with an "old" event for
+	    each lease when dnsmasq receives a SIGHUP.
+
+	    Added more useful exit codes, including passing on a
+	    non-zero exit code from the lease-script "init" call when
+	    --leasefile-ro is set.
+
+	    Log memory allocation failure whilst the daemon is
+	    running. Allocation failures during startup are fatal, 
+	    but lack of memory whilst running is worked around.
+	    This used to be silent, but now is logged.
+
+	    Fixed misaligned memory access which caused problems on
+	    Blackfin CPUs. Thanks to Alex Landau for the patch.
+
+	    Don't include (useless) script-calling code when NO_FORK
+	    is set. Since this tends to be used on very small uclinux 
+	    systems, it's worth-while to save some code-size.
+
+	    Don't set REUSEADDR on TFTP listening socket. There's no
+	    need to do so, and it creates confusing behaviour when
+	    inetd is also listening on the same port. Thanks to Erik
+	    Brown for spotting the problem.
+
+version 2.41
+            Remove deprecated calls when compiled against libdbus 1.1.
+	    
+	    Fix "strict-alias" warning in bpf.c
+
+	    Reduce dependency on Gnu-make in build system: dnsmasq now
+	    builds with system make under OpenBSD.
+
+	    Port to Solaris. Dnsmasq 1.x used to run under Solaris,
+	    and this release does so again, for Solaris 9 or better.
+
+	    Allow the DNS function to be completely disabled, by
+	    setting the port to zero "--port=0". The allows dnsmasq to
+	    be used as a simple DHCP server, simple TFTP server, or
+	    both, but without the DNS server getting in the way.
+
+	    Fix a bug where NXDOMAIN could be returned for a query
+	    even if the name's value was known for a different query
+	    type. This bug could be prodded with 
+            --local=/domain/ --address=/name.domain/1.2.3.4 
+	    An IPv6 query for name.domain would return NXDOMAIN, and
+	    not the correct NOERROR. Thanks to Lars Nooden for
+	    spotting the bug and Jima for diagnosis of the problem.
+
+	    Added per-server stats to the information logged when
+	    dnsmasq gets SIGUSR1.
+
+	    Added counts of queries forwarded and queries answered
+	    locally (from the cache, /etc/hosts or config).
+
+	    Fixed possible crash bug in DBus IPv6 code. Thanks to Matt
+	    Domsch and Jima.
+
+	    Tighten checks for clashes between hosts-file and
+	    DHCP-derived names. Multiple addresses associated with a
+	    name in hosts-file no longer confuses the check.
+
+	    Add --dhcp-no-override option to fix problems with some
+	    combinations of stage zero and stage one
+	    bootloaders. Thanks to Steve Alexander for the bug report.
+  
+	    Add --tftp-port-range option. Thanks to Daniel Mierswa for
+	    the suggestion.
+ 
+	    Add --stop-dns-rebind option. Thanks to Collin Mulliner
+	    for the patch.
+
+	    Added GPL version 3 as a license option.
+ 
+	    Added --all-servers option. Thanks to Peter Naulls for the
+	    patch.
+
+	    Extend source address mechanism so that the interface used
+	    to contact an upstream DNS server can be nailed
+	    down. Something like "--server=1.2.3.4@eth1" will force
+	    the use of eth1 for traffic to DNS-server 1.2.3.4. This
+	    facility is only available on Linux and Solaris. Thanks to
+	    Peter Naulls for prompting this.	     
+	
+	    Add --dhcp-optsfile option. Thanks to Carlos Carvalho for
+            the suggestion.
+
+	    Fixed failure to set source address for server connections
+	    when using TCP. Thanks to Simon Capper for finding this
+	    bug.
+
+	    Refuse to give a DHCP client the address it asks for if
+	    the address range in question is not available to that
+	    particular host. Thanks to Cedric Duval for the bug
+	    report. 
+
+	    Changed behavior of DHCP server to always return total length of
+	    a new lease in DHCPOFFER, even if an existing lease
+	    exists. (It used to return the time remaining on the lease
+	    when one existed.) This fixes problems with the Sony Ericsson
+	    K610i phone. Thanks to Hakon Stordahl for finding and
+	    fixing this.
+
+	    Add DNSMASQ_INTERFACE to the environment of the
+	    lease-change script. Thanks to Nikos Mavrogiannopoulos for
+	    the patch.
+
+	    Fixed broken --alias functionality. Thanks to Michael
+	    Meelis for the bug report.
+
+	    Added French translation of the man page. Thank to Gildas
+	    Le Nadan for that.
+
+	    Add --dhcp-match flag, to check for arbitrary options in
+	    DHCP messages from clients. This enables use of dnsmasq
+	    with gPXE. Thanks to Rance Hall for the suggestion.
+
+	    Added --dhcp-broadcast, to force broadcast replies to DHCP
+	    clients which need them but are too dumb or too old to
+	    ask. Thanks to Bodo Bellut for the suggestion.
+
+	    Disable path-MTU discovery on DHCP and TFTP sockets. This
+	    is never needed, and the presence of DF flags in the IP
+	    header confuses some broken PXE ROMS. Thanks again to Bodo
+	    Bellut for spotting this.
+
+	    Fix problems with addresses which have multiple PTR
+	    records - all but one of these could get lost. 
+
+	    Fix bug with --address and ANY query type seeing REFUSED
+	    return code in replies. Thanks to Mike Wright for spotting
+	    the problem.
+
+	    Update Spanish translation. Thanks to Chris Chatham.
+
+	    Add --neg-ttl option.
+	    
+	    Add warnings about the bad effects of --filterwin2k on
+	    SIP, XMPP and Google-talk to the example config file.
+	    
+	    Fix va_list abuse in log.c. This fixes crashes on powerpc
+	    when debug mode is set. Thanks to Cedric Duval for the
+	    patch. 
+
+version 2.42
+            Define _GNU_SOURCE to avoid problems with later glibc
+            headers. Thanks to Jima for spotting the problem.
+
+	    Add --dhcp-alternate-port option. Thanks to Jan Psota for
+	    the suggestion.
+
+	    Fix typo in code which is only used on BSD, when Dbus and
+	    IPv6 support is enabled. Thanks to Roy Marples.
+	    
+	    Updated Polish translations - thank to Jan Psota.
+
+	    Fix OS detection logic to cope with GNU/FreeBSD.
+
+	    Fix uninitialised variable in DBus code - thanks to Roy
+	    Marples.
+
+	    Fix network enumeration code to work on later NetBSD -
+	    thanks to Roy Marples.
+	    
+	    Provide --dhcp-bridge on all BSD variants.
+
+	    Define _LARGEFILE_SOURCE which removes an arbitrary 2GB
+            limit on logfiles. Thanks to Paul Chambers for spotting 
+            the problem.
+
+	    Fix RFC3046 agent-id echo code, broken for many
+	    releases. Thanks to Jeremy Laine for spotting the problem
+	    and providing a patch.
+
+	    Added Solaris 10 service manifest from David Connelly in
+	    contrib/Solaris10
+ 	    	     
+	    Add --dhcp-scriptuser option.	    
+
+	    Support new capability interface on suitable Linux 
+	    kernels, removes "legacy support in use" messages. Thanks 
+            to Jorge Bastos for pointing this out. 
+
+	    Fix subtle bug in cache code which could cause dnsmasq to
+	    lock spinning CPU in rare circumstances. Thanks to Alex
+	    Chekholko for bug reports and help debugging. 
+
+	    Support netascii transfer mode for TFTP.
+
diff --git a/COPYING b/COPYING
new file mode 100755
index 0000000..60549be
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    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; either version 2 of the License, or
+    (at your option) any later version.
+
+    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.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/COPYING-v3 b/COPYING-v3
new file mode 100755
index 0000000..94a9ed0
--- /dev/null
+++ b/COPYING-v3
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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, either version 3 of the License, or
+    (at your option) any later version.
+
+    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.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/CleanSpec.mk b/CleanSpec.mk
new file mode 100644
index 0000000..b84e1b6
--- /dev/null
+++ b/CleanSpec.mk
@@ -0,0 +1,49 @@
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/FAQ b/FAQ
new file mode 100755
index 0000000..567ad2c
--- /dev/null
+++ b/FAQ
@@ -0,0 +1,565 @@
+Q: Why does dnsmasq open UDP ports >1024 as well as port 53.
+   Is this a security problem/trojan/backdoor?
+
+A: The high ports that dnsmasq opens are for replies from the upstream
+   nameserver(s). Queries from dnsmasq to upstream nameservers are sent
+   from these ports and replies received to them. The reason for doing this is
+   that most firewall setups block incoming packets _to_ port 53, in order
+   to stop DNS queries from the outside world. If dnsmasq sent its queries
+   from port 53 the replies would be _to_ port 53 and get blocked.
+
+   This is not a security hole since dnsmasq will only accept replies to that
+   port: queries are  dropped. The replies must be to oustanding queries
+   which dnsmasq has forwarded, otherwise they are dropped too.
+ 
+   Addendum: dnsmasq now has the option "query-port" (-Q), which allows
+   you to specify the UDP port to be used for this purpose.  If not
+   specified, the operating system will select an available port number
+   just as it did before.
+
+   Second addendum: following the discovery of a security flaw in the
+   DNS protocol, dnsmasq from version 2.43 has changed behavior. It
+   now uses a new, randomly selected, port for each query. The old
+   default behaviour (use one port allocated by the OS) is available by
+   setting --query-port=0, and setting the query port to a positive
+   value still works. You should think hard and know what you are
+   doing before using either of these options.
+ 
+Q: Why doesn't dnsmasq support DNS queries over TCP? Don't the RFC's specify
+   that?
+
+A: Update: from version 2.10, it does. There are a few limitations:
+   data obtained via TCP is not cached, and source-address
+   or query-port specifications are ignored for TCP.
+
+Q: When I send SIGUSR1 to dump the contents of the cache, some entries have
+   no IP address and are for names like mymachine.mydomain.com.mydomain.com.
+   What are these?
+
+A: They are negative entries: that's what the N flag means. Dnsmasq asked 
+   an upstream nameserver to resolve that address and it replied "doesn't 
+   exist, and won't exist for <n> hours" so dnsmasq saved that information so
+   that if _it_ gets asked the same question it can answer directly without
+   having to go back to the upstream server again. The strange repeated domains
+   result from the way resolvers search short names. See "man resolv.conf" for
+   details.
+
+
+Q: Will dnsmasq compile/run on non-Linux systems?
+
+A: Yes, there is explicit support for *BSD and MacOS X and Solaris. 
+   There are start-up scripts for MacOS X Tiger and Panther 
+   in /contrib. Dnsmasq will link with uclibc to provide small
+   binaries suitable for use in embedded systems such as
+   routers. (There's special code to support machines with flash
+   filesystems and no battery-backed RTC.)
+   If you encounter make errors with *BSD, try installing gmake from
+   ports and building dnsmasq with "make MAKE=gmake" 
+   For other systems, try altering the settings in config.h.
+ 
+Q: My company's nameserver knows about some names which aren't in the
+   public DNS. Even though I put it first in /etc/resolv.conf, it
+   doesn't work: dnsmasq seems not to use the nameservers in the order
+   given. What am I doing wrong?
+
+A: By default, dnsmasq treats all the nameservers it knows about as
+   equal: it picks the one to use using an algorithm designed to avoid 
+   nameservers which aren't responding. To make dnsmasq use the
+   servers in order, give it the -o flag. If you want some queries
+   sent to a special server, think about using the -S flag to give the
+   IP address of that server, and telling dnsmasq exactly which
+   domains to use the server for.
+
+Q: OK, I've got queries to a private nameserver working, now how about 
+   reverse queries for a range of IP addresses?
+
+A: Use the standard DNS convention of <reversed address>.in-addr.arpa.
+   For instance to send reverse queries on the range 192.168.0.0 to 
+   192.168.0.255 to a nameserver at 10.0.0.1 do
+   server=/0.168.192.in-addr.arpa/10.0.0.1
+   Note that the "bogus-priv" option take priority over this option,
+   so the above will not work when the bogus-priv option is set.
+
+Q: Dnsmasq fails to start with an error like this: "dnsmasq: bind
+   failed: Cannot assign requested address". What's the problem?
+
+A: This has been seen when a system is bringing up a PPP interface at
+   boot time: by the time dnsmasq start the interface has been
+   created, but not brought up and assigned an address. The easiest
+   solution is to use --interface flags to specify which interfaces
+   dnsmasq should listen on. Since you are unlikely to want dnsmasq to
+   listen on a PPP interface and offer DNS service to the world, the
+   problem is solved.
+
+Q: I'm running on BSD and dnsmasq won't accept long options on the
+   command line. 
+
+A: Dnsmasq when built on some BSD systems doesn't use GNU getopt by
+   default. You can either just use the single-letter options or
+   change config.h and the Makefile to use getopt-long. Note that
+   options in /etc/dnsmasq.conf must always be the long form,
+   on all platforms.
+
+Q: Names on the internet are working fine, but looking up local names 
+   from /etc/hosts or DHCP doesn't seem to work.
+
+A: Resolver code sometime does strange things when given names without
+   any dots in. Win2k and WinXP may not use the DNS at all and just
+   try and look up the name using WINS. On unix look at "options ndots:"
+   in "man resolv.conf" for details on this topic. Testing lookups
+   using "nslookup" or "dig" will work, but then attempting to run
+   "ping" will get a lookup failure, appending a dot to the end of the
+   hostname  will fix things. (ie "ping myhost" fails, but "ping
+   myhost." works. The solution is to make sure that all your hosts
+   have a domain set ("domain" in resolv.conf, or set a domain in 
+   your DHCP server, see below for Windows XP and Mac OS X). 
+   Any domain  will do, but "localnet" is traditional. Now when you
+   resolve "myhost" the resolver will attempt to look up 
+   "myhost.localnet" so you need to have dnsmasq reply to that name. 
+   The way to do that is to include the domain in each name on
+   /etc/hosts  and/or to use the --expand-hosts and --domain options.
+
+Q: How do I set the DNS domain in Windows XP or MacOS X (ref: previous
+   question)?
+
+A: for XP, Control Panel > Network Connections > { Connection to gateway /
+   DNS } > Properties > { Highlight TCP/IP } > Properties > Advanced >
+   DNS Tab > DNS suffix for this connection: 
+
+A: for OS X, System Preferences > Network > {Connection to gateway / DNS } >
+   Search domains:
+
+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?
+
+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
+   cache entries would have expired after a shutdown. For longer-lived
+   names it's much cheaper to just reload them from the upstream
+   server. Note that dnsmasq is not shut down between PPP sessions so
+   go off-line and then on-line again will not lose the contents of
+   the cache.
+
+Q: Who are Verisign, what do they have to do with the bogus-nxdomain
+   option in dnsmasq and why should I wory about it?
+
+A: [note: this was written in September 2003, things may well change.]
+   Verisign run the .com and .net top-level-domains. They have just
+   changed the configuration of their servers so that unknown .com and
+   .net domains, instead of returning an error code NXDOMAIN, (no such
+   domain) return the address of a host at Verisign which runs a web
+   server showing a search page. Most right-thinking people regard
+   this new behaviour as broken :-).  You can test to see if you are
+   suffering Verisign brokenness by run a command like 
+   
+   host jlsdajkdalld.com
+
+   If you get "jlsdajkdalld.com" does not exist, then all is fine, if
+   host returns an IP address, then the DNS is broken. (Try a few
+   different unlikely domains, just in case you picked a weird one
+   which really _is_ registered.)
+
+   Assuming that your DNS is broken, and you want to fix it, simply
+   note the IP address being returned and pass it to dnsmasq using the
+   --bogus-nxdomain flag. Dnsmasq will check for results returning
+   that address and substitute an NXDOMAIN instead. 
+
+   As of writing, the IP address in question for the .com and .net
+   domains is is 64.94.110.11. Various other, less prominent,
+   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 address 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.
+
+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 [Update: the latest dhcpcd packages _do_ send
+   the hostname by default.
+
+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 three 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" or (3) tell dnsmasq to
+   ignore client IDs for a particular MAC address, like this:
+   dhcp-host=11:22:33:44:55:66,id:*
+
+Q: What network types are supported by the DHCP server?
+  
+A: Ethernet (and 802.11 wireless) are supported on all platforms. On
+   Linux all network types (including FireWire) are supported.
+
+Q: What are these strange "bind-interface" and "bind-dynamic" options?
+
+A: Dnsmasq from v2.63 can operate in one of three different "networking
+   modes". This is unfortunate as it requires users configuring dnsmasq
+   to take into account some rather bizarre constraints and select the
+   mode which best fits the requirements of a particular installation.
+   The origin of these are deficiencies in the Unix networking
+   model and APIs and each mode has different advantages and
+   problems. Just to add to the confusion, not all modes are available on
+   all platforms (due the to lack of supporting network APIs).To further
+   add to the confusion, the rules for the DHCP subsystem on dnsmasq are
+   different to the rules for the DNS and TFTP subsystems.
+
+   The three modes are "wildcard", "bind-interfaces" and "bind-dynamic".
+
+   In "wildcard" mode, dnsmasq binds the wildcard IP address (0.0.0.0 or
+   ::). This allows it to receive all the packets sent to the server on
+   the relevant port. Access control (--interface, --except-interface,
+   --listen-address, etc) is implemented by dnsmasq: it queries the
+   kernel to determine the interface on which a packet was received and
+   the address to which it was sent, and applies the configured
+   rules. Wildcard mode is the default if neither of the other modes are
+   specified. 
+
+   In "bind-interfaces" mode, dnsmasq runs through all the network
+   interfaces available when it starts, finds the set of IP addresses on
+   those interfaces, filters that set using the access control
+   configuration, and then binds the set of IP addresses. Only packets
+   sent to the allowed addresses are delivered by the kernel to dnsmasq.
+
+   In "bind-dynamic" mode, access control filtering is done both by
+   binding individual IP addresses, as for bind-interfaces, and by
+   inspecting individual packets on arrival as for wildcard mode. In
+   addition, dnsmasq notices when new interfaces appear or new addresses
+   appear on existing interfaces, and the resulting IP addresses are
+   bound automatically without having to restart dnsmasq.
+
+   The mode chosen has four different effects: co-existence with other
+   servers, semantics of --interface access control, effect of new
+   interfaces, and legality of --interface specifications for
+   non-existent interfaces. We will deal with these in order.
+
+   A dnsmasq instance running in wildcard mode precludes a machine from
+   running a second instance of dnsmasq or any other DNS, TFTP or DHCP
+   server. Attempts to do so will fail with an "address in use" error. 
+   Dnsmasq running in --bind-interfaces or bind-dynamic mode allow other
+   instances of dnsmasq or other servers, as long as no two servers are
+   configured to listen on the same interface address. 
+
+   The semantics of --interface varies subtly between wildcard or
+   bind-dynamic mode and bind-interfaces mode. The situation where this
+   matters is a request which arrives via one interface (A), but with a
+   destination address of a second interface (B) and when dnsmasq is
+   configured to listen only on B. In wildcard or bind-dynamic mode, such
+   a request will be ignored, in bind-interfaces mode, it will be
+   accepted.
+
+   The creation of new network interfaces after dnsmasq starts is ignored
+   by dnsmasq when in --bind-interfaces mode. In wildcard or bind-dynamic
+   mode, such interfaces are handled normally.
+
+   A --interface specification for a non-existent interface is a fatal
+   error at start-up when in --bind-interfaces mode, by just generates a
+   warning in wildcard or bind-dynamic mode.
+
+Q: Why doesn't Kerberos work/why can't I get sensible answers to
+   queries for SRV records.
+
+A: Probably because you have the "filterwin2k" option set. Note that
+   it was on by default in example configuration files included in 
+   versions before 2.12, so you might have it set on without
+   realising.
+
+Q: Can I get email notification when a new version of dnsmasq is
+   released?
+
+A: Yes, new releases of dnsmasq are always announced through
+   freshmeat.net, and they allow you to subscribe to email alerts when
+   new versions of particular projects are released. New releases are
+   also announced in the dnsmasq-discuss mailing list, subscribe at 
+   http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss
+
+Q: What does the dhcp-authoritative option do? 
+
+A: The DHCP spec says that when a DHCP server recieves a renewal request
+   from a client it has no knowledge of, it should just ignore it.
+   This is because it's supported to have more than one DHCP server
+   on a network, and another DHCP server may be dealing with the client.
+   This has the unfortunate effect that when _no_ DHCP replies to 
+   the client, it takes some time for the client to time-out and start 
+   to get a new lease. Setting this option makes dnsmasq violate the
+   standard to the extent that it will send a NAK reply to the client, 
+   causing it to immediately start to get a new lease. This improves 
+   behaviour when machines move networks, and in the case that the DHCP
+   lease database is lost. As long as there are not more tha one DHCP
+   server on the network, it's safe to enable the option.
+
+Q: Why does my Gentoo box pause for a minute before getting a new
+   lease?
+
+A: Because when a Gentoo box shuts down, it releases its lease with
+   the server but remembers it on the client; this seems to be a 
+   Gentoo-specific patch to dhcpcd. On restart it tries to renew
+   a lease which is long gone, as far as dnsmasq is concerned, and
+   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 irrespective 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
+
+Addendum:
+   From version 2.46, dnsmasq has a solution to this which doesn't
+   involve setting client-IDs. It's possible to put more than one MAC
+   address in a --dhcp-host configuration. This tells dnsmasq that it
+   should use the specified IP for any of the specified MAC addresses,
+   and furthermore it gives dnsmasq permission to summarily abandon a
+   lease to one of the MAC addresses if another one comes along. Note
+   that this will work fine only as longer as only one interface is
+   up at any time. There is no way for dnsmasq to enforce this
+   constraint: if you configure multiple MAC addresses and violate 
+   this rule, bad things will happen.
+
+Addendum-II: The link above is dead, the former contents of the link are:
+
+------------------------------------------------------------------------------
+How can I keep the same DHCP client reservation, if the MAC address changes?
+
+When you reserve an IP address for a DHCP client, you provide the
+MAC address of the client's NIC.
+
+It is possible to use a custom identifier, which is sent as 
+option 61 in the client's DHCP Discover and Request packet.
+
+The DhcpClientIdentifier is a REG_DWORD value that is located at:
+
+Windows NT 4.0 SP2+
+
+HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<Adapter Name>'X'\Parameters\Tcpip
+
+where <Adapter Name> is the NIC driver name and 'X' is the number of the NIC.
+
+Windows 2000
+
+HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TcpIp\Parameters\Interfaces\<NIC GUID>
+
+where <NIC GUID> is the GUID of the NIC.
+
+The valid range of data is 0x0 - 0xFFFFFFFF. The custom identifier is send as 4 bytes, 
+8 hexadecimal character, in groups of 2 hexadecimal characters, with the groups being 
+sent in reverse order. If the custom identifier is less than 8 hexadeciaml characters, 
+it is zero padded at the end. Examples:
+
+Custom Client                 Client Reservation
+Identifier                    on DHCP Server
+12345678                      78563412
+123456                        56341200
+1234                          34120000
+1234567                       67452301
+12345                         45230100
+123                           23010000
+A18F42                        428FA100
+CF432                         32F40C00
+C32D1BE                       BED1320C
+
+-------------------------------------------------------------------------------------------------------
+
+
+Q: Can dnsmasq do DHCP on IP-alias interfaces?
+
+A: Yes, from version-2.21. The support is only available running under
+   Linux, on a kernel which provides the RT-netlink facility. All 2.4 
+   and 2.6 kernels provide RT-netlink and it's an option in 2.2
+   kernels. 
+   
+   If a physical interface has more than one IP address or aliases
+   with extra IP addresses, then any dhcp-ranges corresponding to
+   these addresses can be used for address allocation. So if an
+   interface has addresses 192.168.1.0/24 and 192.168.2.0/24 and there
+   are DHCP ranges 192.168.1.100-192.168.1.200 and
+   192.168.2.100-192.168.2.200 then both ranges would be used for host
+   connected to the physical interface. A more typical use might be to
+   have one of the address-ranges as static-only, and have known
+   hosts allocated addresses on that subnet using dhcp-host options,
+   while  anonymous hosts go on the other.
+
+
+Q: Dnsmasq sometimes logs "nameserver xxx.xxx.xxx.xxx refused
+   to do a recursive query" and DNS stops working. What's going on?
+
+A: Probably the nameserver is an authoritative nameserver for a
+   particular domain, but is not configured to answer general DNS
+   queries for an arbitrary domain. It is not suitable for use by
+   dnsmasq as an upstream server and should be removed from the
+   configuration. Note that if you have more than one upstream
+   nameserver configured dnsmasq will load-balance across them and
+   it may be some time before dnsmasq gets around to using a 
+   particular nameserver. This means that a particular configuration
+   may work for sometime with a broken upstream nameserver
+   configuration.
+
+
+Q: Does the dnsmasq DHCP server probe addresses before allocating
+   them, as recommended in RFC2131?
+
+A: Yes, dynamically allocated IP addresses are checked by sending an
+   ICMP echo request (ping). If a reply is received, then dnsmasq
+   assumes that the address is in use, and attempts to allocate an
+   different address. The wait for a reply is between two and three
+   seconds. Because the DHCP server is not re-entrant, it cannot serve
+   other DHCP requests during this time. To avoid dropping requests,
+   the address probe may be skipped when dnsmasq is under heavy load.
+
+
+Q: I'm using dnsmasq on a machine with the Firestarter firewall, and
+   DHCP doesn't work. What's the problem?
+
+A: This a variant on the iptables problem. Explicit details on how to
+   proceed can be found at 
+   http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2005q3/000431.html
+ 
+
+Q: I'm using dnsmasq on a machine with the shorewall firewall, and
+   DHCP doesn't work. What's the problem?
+
+A: This a variant on the iptables problem. Explicit details on how to
+   proceed can be found at 
+   http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2007q4/001764.html
+
+
+Q: Dnsmasq fails to start up with a message about capabilities.
+   Why did that happen and what can do to fix it?
+
+A: Change your kernel configuration: either deselect CONFIG_SECURITY
+   _or_ select CONFIG_SECURITY_CAPABILITIES. Alternatively, you can 
+   remove the need to set capabilities by running dnsmasq as root.
+
+
+Q: Where can I get .rpms Suitable for openSUSE/SLES?
+
+A: Dnsmasq is in openSUSE itself, and the latest releases are also
+   available at http://download.opensuse.org/repositories/network/
+
+
+Q: Can I run dnsmasq in a Linux vserver?
+
+A: Yes, as a DNS server, dnsmasq will just work in a vserver.
+   To use dnsmasq's DHCP function you need to give the vserver
+   extra system capabilities. Please note that doing so will lesser 
+   the overall security of your system. The capabilities 
+   required are NET_ADMIN and NET_RAW. NET_ADMIN is essential, NET_RAW
+   is required to do an ICMP "ping" check on newly allocated
+   addresses. If you don't need this check, you can disable it with
+   --no-ping and omit the NET_RAW capability. 
+   Adding the capabilities is done by adding them, one per line, to
+   either /etc/vservers/<vservername>/ccapabilities for a 2.4 kernel or
+   /etc/vservers/<vservername>/bcapabilities for a 2.6 kernel (please
+   refer to the vserver documentation for more information).
+
+
+Q: What's the problem with syslog and dnsmasq?
+
+A: In almost all cases: none. If you have the normal arrangement with
+   local daemons logging to a local syslog, which then writes to disk,
+   then there's never a problem. If you use network logging, then
+   there's a potential problem with deadlock: the syslog daemon will
+   do DNS lookups so that it can log the source of log messages,
+   these lookups will (depending on exact configuration) go through
+   dnsmasq, which also sends log messages. With bad timing, you can 
+   arrive at a situation where syslog is waiting for dnsmasq, and
+   dnsmasq is waiting for syslog; they will both wait forever. This
+   problem is fixed from dnsmasq-2.39, which introduces asynchronous
+   logging: dnsmasq no longer waits for syslog and the deadlock is
+   broken. There is a remaining problem in 2.39, where "log-queries"
+   is in use. In this case most DNS queries generate two log lines, if
+   these go to a syslog which is doing a DNS lookup for each log line,
+   then those queries will in turn generate two more log lines, and a 
+   chain reaction runaway will occur. To avoid this, use syslog-ng
+   and turn on syslog-ng's dns-cache function.
+
+
+Q: DHCP doesn't work with windows Vista, but everything else is fine.
+
+A: The DHCP client on windows Vista (and possibly later versions)
+   demands that the DHCP server send replies as broadcasts. Most other
+   clients don't do this. The broadcasts are send to
+   255.255.255.255. A badly configured firewall which blocks such
+   packets will show exactly these symptoms (Vista fails, others
+   work).
+
+  
+Q: DHCP doesn't work with windows 7 but everything else is fine.
+
+A: There seems to be a problem if Windows 7 doesn't get a value for
+   DHCP option 252 in DHCP packets it gets from the server. The
+   symptoms have been variously reported as continual DHCPINFORM
+   requests in an attempt to get an option-252, or even ignoring DHCP
+   offers completely (and failing to get an IP address) if there is no
+   option-252 supplied. DHCP option 252 is for WPAD, WWW Proxy 
+   Auto Detection and if you don't want or need to use that, then 
+   simplest fix seems to be to supply an empty option with:
+
+   dhcp-option=252,"\n"
+
+
+
+ 
+
+
+
+
+   
+
+	      
diff --git a/MODULE_LICENSE_GPL b/MODULE_LICENSE_GPL
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_GPL
diff --git a/Makefile b/Makefile
new file mode 100755
index 0000000..73ea23e
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,170 @@
+# dnsmasq is Copyright (c) 2000-2016 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, or
+#  (at your option) version 3 dated 29 June, 2007.
+#
+#  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.
+#    
+#  You should have received a copy of the GNU General Public License
+#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# NOTE: Building the i18n targets requires GNU-make 
+
+
+# Variables you may well want to override.
+
+PREFIX        = /usr/local
+BINDIR        = $(PREFIX)/sbin
+MANDIR        = $(PREFIX)/share/man
+LOCALEDIR     = $(PREFIX)/share/locale
+BUILDDIR      = $(SRC)
+DESTDIR       = 
+CFLAGS        = -Wall -W -O2
+LDFLAGS       = 
+COPTS         = 
+RPM_OPT_FLAGS = 
+LIBS          = 
+
+#################################################################
+
+# Variables you might want to override.
+
+PKG_CONFIG = pkg-config
+INSTALL    = install
+MSGMERGE   = msgmerge
+MSGFMT     = msgfmt
+XGETTEXT   = xgettext
+
+SRC = src
+PO  = po
+MAN = man
+
+#################################################################
+
+# pmake way. (NB no spaces to keep gmake 3.82 happy)
+top!=pwd
+# GNU make way.
+top?=$(CURDIR)
+
+dbus_cflags =   `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1` 
+dbus_libs =     `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1` 
+idn_cflags =    `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn` 
+idn_libs =      `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn` 
+idn2_cflags =   `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 $(PKG_CONFIG) --cflags libidn2`
+idn2_libs =     `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 $(PKG_CONFIG) --libs libidn2`
+ct_cflags =     `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
+ct_libs =       `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
+lua_cflags =    `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.2` 
+lua_libs =      `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.2` 
+nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags nettle hogweed`
+nettle_libs =   `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --libs nettle hogweed`
+gmp_libs =      `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC NO_GMP --copy -lgmp`
+sunos_libs =    `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
+version =     -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
+
+sum?=$(shell $(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' ')
+sum!=$(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' '
+copts_conf = .copts_$(sum)
+
+objs = cache.o rfc1035.o util.o option.o forward.o network.o \
+       dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
+       helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
+       dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
+       domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
+       poll.o rrfilter.o edns0.o arp.o
+
+hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
+       dns-protocol.h radv-protocol.h ip6addr.h
+
+all : $(BUILDDIR)
+	@cd $(BUILDDIR) && $(MAKE) \
+ top="$(top)" \
+ build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
+ build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs)" \
+ -f $(top)/Makefile dnsmasq 
+
+mostly_clean :
+	rm -f $(BUILDDIR)/*.mo $(BUILDDIR)/*.pot 
+	rm -f $(BUILDDIR)/.copts_* $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq
+
+clean : mostly_clean
+	rm -f $(BUILDDIR)/dnsmasq_baseline
+	rm -f core */core
+	rm -f *~ contrib/*/*~ */*~
+
+install : all install-common
+
+install-common :
+	$(INSTALL) -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8
+	$(INSTALL) -m 644 $(MAN)/dnsmasq.8 $(DESTDIR)$(MANDIR)/man8 
+	$(INSTALL) -m 755 $(BUILDDIR)/dnsmasq $(DESTDIR)$(BINDIR)
+
+all-i18n : $(BUILDDIR)
+	@cd $(BUILDDIR) && $(MAKE) \
+ top="$(top)" \
+ i18n=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
+ build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
+ build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs)"  \
+ -f $(top)/Makefile dnsmasq
+	for f in `cd $(PO); echo *.po`; do \
+		cd $(top) && cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile $${f%.po}.mo; \
+	done
+
+install-i18n : all-i18n install-common
+	cd $(BUILDDIR); $(top)/bld/install-mo $(DESTDIR)$(LOCALEDIR) $(INSTALL)
+	cd $(MAN); ../bld/install-man $(DESTDIR)$(MANDIR) $(INSTALL)
+
+merge : 
+	@cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile dnsmasq.pot
+	for f in `cd $(PO); echo *.po`; do \
+		echo -n msgmerge $(PO)/$$f && $(MSGMERGE) --no-wrap -U $(PO)/$$f $(BUILDDIR)/dnsmasq.pot; \
+	done
+
+# Canonicalise .po file.
+%.po : 
+	@cd $(BUILDDIR) && $(MAKE) -f $(top)/Makefile dnsmasq.pot
+	mv $(PO)/$*.po $(PO)/$*.po.orig && $(MSGMERGE) --no-wrap $(PO)/$*.po.orig $(BUILDDIR)/dnsmasq.pot >$(PO)/$*.po; 
+
+$(BUILDDIR):
+	mkdir -p $(BUILDDIR)
+
+# rules below are helpers for size tracking
+
+baseline : mostly_clean all
+	@cd $(BUILDDIR) && \
+	   mv dnsmasq dnsmasq_baseline
+
+bloatcheck : $(BUILDDIR)/dnsmasq_baseline mostly_clean all
+	@cd $(BUILDDIR) && \
+           $(top)/bld/bloat-o-meter dnsmasq_baseline dnsmasq; \
+           size dnsmasq_baseline dnsmasq
+
+# rules below are targets in recursive makes with cwd=$(BUILDDIR)
+
+$(copts_conf): $(hdrs)
+	@rm -f *.o .copts_*
+	@touch $@
+
+$(objs:.o=.c) $(hdrs):
+	ln -s $(top)/$(SRC)/$@ .
+
+$(objs): $(copts_conf) $(hdrs)
+
+.c.o:
+	$(CC) $(CFLAGS) $(COPTS) $(i18n) $(build_cflags) $(RPM_OPT_FLAGS) -c $<	
+
+dnsmasq : $(objs)
+	$(CC) $(LDFLAGS) -o $@ $(objs) $(build_libs) $(LIBS) 
+
+dnsmasq.pot : $(objs:.o=.c) $(hdrs)
+	$(XGETTEXT) -d dnsmasq --foreign-user --omit-header --keyword=_ -o $@ -i $(objs:.o=.c)
+
+%.mo : $(top)/$(PO)/%.po dnsmasq.pot
+	$(MSGMERGE) -o - $(top)/$(PO)/$*.po dnsmasq.pot | $(MSGFMT) -o $*.mo -
+
+.PHONY : all clean mostly_clean install install-common all-i18n install-i18n merge baseline bloatcheck
diff --git a/NOTICE b/NOTICE
new file mode 100755
index 0000000..60549be
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    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; either version 2 of the License, or
+    (at your option) any later version.
+
+    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.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/ThirdPartyProject.prop b/ThirdPartyProject.prop
new file mode 100644
index 0000000..08a49af
--- /dev/null
+++ b/ThirdPartyProject.prop
@@ -0,0 +1,9 @@
+# Copyright 2010 Google Inc. All Rights Reserved.
+#Fri Jul 16 10:03:08 PDT 2010
+currentVersion=2.52
+version=2.51
+isNative=true
+name=dnsmasq
+keywords=dnsmasq
+onDevice=true
+homepage=http\://www.thekelleys.org.uk/dnsmasq/doc.html
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..c012458
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+ (HEAD -> master, tag: v2.78, origin/master, origin/HEAD)
diff --git a/bld/Makefile b/bld/Makefile
new file mode 100755
index 0000000..53dab34
--- /dev/null
+++ b/bld/Makefile
@@ -0,0 +1,17 @@
+CFLAGS = -Wall -W -O2
+
+OBJS = cache.o rfc1035.o util.o option.o forward.o network.o \
+       dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
+       helper.o tftp.o log.o
+
+.c.o:
+	$(CC) $(CFLAGS) $(COPTS) $(I18N) $(DNSMASQ_CFLAGS) $(RPM_OPT_FLAGS) -c $<
+
+dnsmasq : $(OBJS)
+	$(CC) $(LDFLAGS) -o $@  $(OBJS) $(DNSMASQ_LIBS) $(LIBS) 
+ 
+dnsmasq.pot : $(OBJS:.o=.c) dnsmasq.h config.h
+	$(XGETTEXT) -d dnsmasq --foreign-user --omit-header --keyword=_ -o $@ -i $(OBJS:.o=.c)
+
+%.mo : ../po/%.po dnsmasq.pot
+	$(MSGMERGE) -o - ../po/$*.po dnsmasq.pot | $(MSGFMT) -o $*.mo -
diff --git a/bld/bloat-o-meter b/bld/bloat-o-meter
new file mode 100755
index 0000000..6db2a5e
--- /dev/null
+++ b/bld/bloat-o-meter
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+#
+# Copyright 2004 Matt Mackall <mpm@selenic.com>
+#
+# Inspired by perl Bloat-O-Meter (c) 1997 by Andi Kleen
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+import sys, os#, re
+
+def usage():
+    sys.stderr.write("usage: %s [-t] file1 file2\n" % sys.argv[0])
+    sys.exit(-1)
+
+f1, f2 = (None, None)
+flag_timing, dashes = (False, False)
+
+for f in sys.argv[1:]:
+    if f.startswith("-"):
+        if f == "--": # sym_args
+            dashes = True
+            break
+        if f == "-t": # timings
+            flag_timing = True
+    else:
+        if not os.path.exists(f):
+            sys.stderr.write("Error: file '%s' does not exist\n" % f)
+            usage()
+        if f1 is None:
+            f1 = f
+        elif f2 is None:
+            f2 = f
+if flag_timing:
+    import time
+if f1 is None or f2 is None:
+    usage()
+
+sym_args = " ".join(sys.argv[3 + flag_timing + dashes:])
+def getsizes(file):
+    sym, alias, lut = {}, {}, {}
+    for l in os.popen("readelf -W -s %s %s" % (sym_args, file)).readlines():
+        l = l.strip()
+        if not (len(l) and l[0].isdigit() and len(l.split()) == 8):
+            continue
+        num, value, size, typ, bind, vis, ndx, name = l.split()
+        if ndx == "UND": continue # skip undefined
+        if typ in ["SECTION", "FILES"]: continue # skip sections and files
+        if "." in name: name = "static." + name.split(".")[0]
+        value = int(value, 16)
+        size = int(size, 16) if size.startswith('0x') else int(size)
+        if vis != "DEFAULT" and bind != "GLOBAL": # see if it is an alias
+            alias[(value, size)] = {"name" : name}
+        else:
+            sym[name] = {"addr" : value, "size":  size}
+            lut[(value, size)] = 0
+    for addr, sz in iter(alias.keys()):
+        # If the non-GLOBAL sym has an implementation elsewhere then
+        # it's an alias, disregard it.
+        if not (addr, sz) in lut:
+            # If this non-GLOBAL sym does not have an implementation at
+            # another address, then treat it as a normal symbol.
+            sym[alias[(addr, sz)]["name"]] = {"addr" : addr, "size": sz}
+    for l in os.popen("readelf -W -S " + file).readlines():
+        x = l.split()
+        if len(x)<6: continue
+        # Should take these into account too!
+        #if x[1] not in [".text", ".rodata", ".symtab", ".strtab"]: continue
+        if x[1] not in [".rodata"]: continue
+        sym[x[1]] = {"addr" : int(x[3], 16), "size" : int(x[5], 16)}
+    return sym
+
+if flag_timing:
+    start_t1 = int(time.time() * 1e9)
+old = getsizes(f1)
+if flag_timing:
+    end_t1 = int(time.time() * 1e9)
+    start_t2 = int(time.time() * 1e9)
+new = getsizes(f2)
+if flag_timing:
+    end_t2 = int(time.time() * 1e9)
+    start_t3 = int(time.time() * 1e9)
+grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0
+delta, common = [], {}
+
+for name in iter(old.keys()):
+    if name in new:
+        common[name] = 1
+
+for name in old:
+    if name not in common:
+        remove += 1
+        sz = old[name]["size"]
+        down += sz
+        delta.append((-sz, name))
+
+for name in new:
+    if name not in common:
+        add += 1
+        sz = new[name]["size"]
+        up += sz
+        delta.append((sz, name))
+
+for name in common:
+        d = new[name].get("size", 0) - old[name].get("size", 0)
+        if d>0: grow, up = grow+1, up+d
+        elif d<0: shrink, down = shrink+1, down-d
+        else:
+            continue
+        delta.append((d, name))
+
+delta.sort()
+delta.reverse()
+if flag_timing:
+    end_t3 = int(time.time() * 1e9)
+
+print("%-48s %7s %7s %+7s" % ("function", "old", "new", "delta"))
+for d, n in delta:
+    if d:
+        old_sz = old.get(n, {}).get("size", "-")
+        new_sz = new.get(n, {}).get("size", "-")
+        print("%-48s %7s %7s %+7d" % (n, old_sz, new_sz, d))
+print("-"*78)
+total="(add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s)%%sTotal: %s bytes"\
+    % (add, remove, grow, shrink, up, -down, up-down)
+print(total % (" "*(80-len(total))))
+if flag_timing:
+    print("\n%d/%d; %d Parse origin/new; processing nsecs" %
+        (end_t1-start_t1, end_t2-start_t2, end_t3-start_t3))
+    print("total nsecs: %d" % (end_t3-start_t1))
diff --git a/bld/get-version b/bld/get-version
new file mode 100755
index 0000000..e472aab
--- /dev/null
+++ b/bld/get-version
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+# Determine the version string to build into a binary.
+# When building in the git repository, we can use the output 
+# of "git describe" which gives an unequivocal answer.
+#
+# Failing that, we use the contents of the VERSION file
+# which has a set of references substituted into it by git.
+# If we can find one which matches $v[0-9].* then we assume it's
+# a version-number tag, else we just use the whole string.
+# If there is more than one v[0-9].* tag, sort them and use the
+# first. This favours, eg v2.63 over 2.63rc6.
+
+# Change directory to the toplevel source directory.
+if test -z "$1" || ! test -d "$1" || ! cd "$1"; then
+    echo "$0: First argument $1 must be toplevel dir." >&2
+    exit 1
+fi
+
+if which git >/dev/null 2>&1 && \
+    ([ -d .git ] || grep '^gitdir:' .git >/dev/null 2>&1) && \
+    git describe >/dev/null 2>&1; then 
+    git describe | sed 's/^v//'
+elif grep '\$Format:%d\$' $1/VERSION >/dev/null 2>&1; then
+    # unsubstituted VERSION, but no git available.
+    echo UNKNOWN
+else
+     vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep ^v[0-9]`
+
+     if [ $? -eq 0 ]; then
+         echo "${vers}" | sort -r | head -n 1 | sed 's/^v//'
+     else
+         cat $1/VERSION
+     fi
+fi
+
+exit 0
+
diff --git a/bld/install-man b/bld/install-man
new file mode 100755
index 0000000..420c9b1
--- /dev/null
+++ b/bld/install-man
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+for f in *; do
+  if [ -d $f ]; then
+     $2 -m 755 -d $1/$f/man8 
+     $2 -m 644 $f/dnsmasq.8 $1/$f/man8
+     echo installing $f/man8/dnsmasq.8
+  fi
+done
diff --git a/bld/install-mo b/bld/install-mo
new file mode 100755
index 0000000..ab54301
--- /dev/null
+++ b/bld/install-mo
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+for f in *.mo; do
+  $2 -m 755 -d $1/${f%.mo}/LC_MESSAGES
+  $2 -m 644 $f $1/${f%.mo}/LC_MESSAGES/dnsmasq.mo
+  echo installing ${f%.mo}/LC_MESSAGES/dnsmasq.mo
+done
+
+
diff --git a/bld/pkg-wrapper b/bld/pkg-wrapper
new file mode 100755
index 0000000..0ddb678
--- /dev/null
+++ b/bld/pkg-wrapper
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+search=$1
+shift
+pkg=$1
+shift
+op=$1
+shift
+
+in=`cat`
+
+if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
+    echo $in | grep $search >/dev/null 2>&1; then
+# Nasty, nasty, in --copy, arg 2 is another config to search for, use with NO_GMP
+    if [ $op = "--copy" ]; then
+	if grep "^\#[[:space:]]*define[[:space:]]*$pkg" config.h >/dev/null 2>&1 || \
+            echo $in | grep $pkg >/dev/null 2>&1; then
+	    pkg=""
+	else 
+	    pkg="$*"
+	fi
+    elif grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
+	      echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
+	pkg=`$pkg  --static $op $*`
+    else
+	pkg=`$pkg $op $*`
+    fi
+
+    if grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
+	echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
+	if [ $op = "--libs" ] || [ $op = "--copy" ]; then
+	    echo "-Wl,-Bstatic $pkg -Wl,-Bdynamic"
+	else
+	    echo "$pkg" 
+	fi
+    else
+	echo "$pkg"
+    fi
+fi
+
diff --git a/contrib/CPE-WAN/README b/contrib/CPE-WAN/README
new file mode 100644
index 0000000..4d56347
--- /dev/null
+++ b/contrib/CPE-WAN/README
@@ -0,0 +1,36 @@
+Dnsmasq from version 2.52 has a couple of rather application-specific
+features designed to allow for implementation of the DHCP part of CPE
+WAN management protocol.
+
+http://www.broadband-forum.org/technical/download/TR-069_Amendment-2.pdf
+http://en.wikipedia.org/wiki/TR-069
+
+The relevant sections are F.2.1 "Gateway Requirements" and F.2.5 "DHCP
+Vendor Options".
+
+First, dnsmasq checks for DHCP requests which contain an option-125
+vendor-class option which in turn holds a vendor section for IANA
+enterprise number 3561 which contains sub-options codes 1 and 2. If
+this is present  then the network-tag "cpewan-id" is set. 
+This allows dnsmasq to be configured to reply with the correct 
+GatewayManufacturerOUI, GatewaySerialNumber and GatewayProductClass like this:
+
+dhcp-option=cpewan-id,vi-encap:3561,4,"<GatewayManufacturerOUI>"
+dhcp-option=cpewan-id,vi-encap:3561,5,"<SerialNumber>"
+dhcp-option=cpewan-id,vi-encap:3561,6,"<ProductClass>"
+
+Second, the received sub-options 1, 2, and 3 are passed to the DHCP
+lease-change script as the environment variables DNSMASQ_CPEWAN_OUI,
+DNSMASQ_CPEWAN_SERIAL, and DNSMASQ_CPEWAN_CLASS respectively. This allows
+the script to be used to maintain a ManageableDevice table as
+specified in F.2.1. Note that this data is not retained in dnsmasq's
+internal DHCP lease database, so it is not available on every call to 
+the script (this is the same as some other data such as vendor and
+user classes). It will however be available for at least the "add"
+call, and should be stored then against the IP address as primary 
+key for future use.
+
+
+This feature was added to dnsmasq under sponsorship from Ericsson.
+
+
diff --git a/contrib/MacOSX-launchd/launchd-README.txt b/contrib/MacOSX-launchd/launchd-README.txt
new file mode 100644
index 0000000..cf245ff
--- /dev/null
+++ b/contrib/MacOSX-launchd/launchd-README.txt
@@ -0,0 +1,38 @@
+This is a launchd item for Mac OS X and Mac OS X Server.
+For more information about launchd, the
+"System wide and per-user daemon/agent manager", see the launchd
+man page, or the wikipedia page: http://en.wikipedia.org/wiki/Launchd
+
+This launchd item uses the following flags:
+--keep-in-foreground - this is crucial for use with launchd
+--log-queries - this is optional and you can remove it
+--log-facility=/var/log/dnsmasq.log - again optional instead of system.log
+
+To use this launchd item for dnsmasq:
+
+If you don't already have a folder /Library/LaunchDaemons, then create one:
+sudo mkdir /Library/LaunchDaemons
+sudo chown root:admin /Library/LaunchDaemons
+sudo chmod 775 /Library/LaunchDaemons 
+
+Copy uk.org.thekelleys.dnsmasq.plist there and then set ownership/permissions:
+sudo cp uk.org.thekelleys.dnsmasq.plist /Library/LaunchDaemons/
+sudo chown root:admin /Library/LaunchDaemons/uk.org.thekelleys.dnsmasq.plist
+sudo chmod 644 /Library/LaunchDaemons/uk.org.thekelleys.dnsmasq.plist
+
+Optionally, edit your dnsmasq configuration file to your liking.
+
+To start the launchd job, which starts dnsmasq, reboot or use the command:
+sudo launchctl load /Library/LaunchDaemons/uk.org.thekelleys.dnsmasq.plist
+
+To stop the launchd job, which stops dnsmasq, use the command:
+sudo launchctl unload /Library/LaunchDaemons/uk.org.thekelleys.dnsmasq.plist
+
+If you want to permanently stop the launchd job, so it doesn't start the job even after a reboot, use the following command:
+sudo launchctl unload -w /Library/LaunchDaemons/uk.org.thekelleys.dnsmasq.plist
+
+If you make a change to the configuration file, you should relaunch dnsmasq;
+to do this unload and then load again:
+
+sudo launchctl unload /Library/LaunchDaemons/uk.org.thekelleys.dnsmasq.plist
+sudo launchctl load /Library/LaunchDaemons/uk.org.thekelleys.dnsmasq.plist
diff --git a/contrib/MacOSX-launchd/uk.org.thekelleys.dnsmasq.plist b/contrib/MacOSX-launchd/uk.org.thekelleys.dnsmasq.plist
new file mode 100644
index 0000000..87725b1
--- /dev/null
+++ b/contrib/MacOSX-launchd/uk.org.thekelleys.dnsmasq.plist
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>Label</key>
+	<string>uk.org.thekelleys.dnsmasq</string>
+	<key>ProgramArguments</key>
+	<array>
+		<string>/usr/local/sbin/dnsmasq</string>
+		<string>--keep-in-foreground</string>
+	</array>
+	<key>RunAtLoad</key>
+	<true/>
+</dict>
+</plist>
diff --git a/contrib/Solaris10/README b/contrib/Solaris10/README
new file mode 100755
index 0000000..a035875
--- /dev/null
+++ b/contrib/Solaris10/README
@@ -0,0 +1,28 @@
+From: David Connelly <dconnelly@gmail.com>
+Date: Mon, Apr 7, 2008 at 3:31 AM
+Subject: Solaris 10 service manifest
+To: dnsmasq-discuss@lists.thekelleys.org.uk
+
+
+I've found dnsmasq much easier to set up on my home server running Solaris
+10 than the stock dhcp/dns server, which is probably overkill anyway for my
+simple home network needs. Since Solaris now uses SMF (Service Management
+Facility) to manage services I thought I'd create a simple service manifest
+for the dnsmasq service. The manifest currently assumes that dnsmasq has
+been installed in '/usr/local/sbin/dnsmasq' and the configuration file in
+'/usr/local/etc/dnsmasq.conf', so you may have to adjust these paths for
+your local installation. Here are the steps I followed to install and enable
+the dnsmasq service:
+  # svccfg import dnsmasq.xml
+  # svcadm enable dnsmasq
+
+To confirm that the service is enabled and online:
+
+  # svcs -l dnsmasq
+
+I've just started learning about SMF so if anyone has any
+corrections/feedback they are more than welcome.
+
+Thanks,
+David
+
diff --git a/contrib/Solaris10/README-sparc b/contrib/Solaris10/README-sparc
new file mode 100644
index 0000000..327b65c
--- /dev/null
+++ b/contrib/Solaris10/README-sparc
@@ -0,0 +1,8 @@
+Hi Simon,
+
+I just wanted to let you know that I have built a Solaris .pkg install package of your dnsmasq utility for people to use.  Feel free to point them in my direction if you have people who want this sort of thing.
+
+http://ejesconsulting.wordpress.com/2010/05/12/gnu-dnsmasq-for-opensolaris-sparc/
+
+Thanks
+-evan
diff --git a/contrib/Solaris10/README.create_package b/contrib/Solaris10/README.create_package
new file mode 100644
index 0000000..676899a
--- /dev/null
+++ b/contrib/Solaris10/README.create_package
@@ -0,0 +1,25 @@
+Ok, script attached ... seems to be working ok for me, 
+tried to install and remove a few times. It does the
+right thing with the smf when installing, you can then 
+simply enable the service. Upon removal it cleans up the
+files but won't clean up the services (I think until
+a reboot) ... I've only started looking at the new 
+packages stuff in the last day or two, so I could be 
+missing something, but I can't find any way to force
+ a proper cleanup.
+
+It requires that you have a writable repository setup 
+as per the docs on the opensolaris website and it will
+create a dnsmasq package (package name is a variable 
+in the script). The script takes a version number for 
+the package and assumes that it's in the contrib/Solaris10 
+directory, it then works out the base tree directory 
+from $0.
+
+i.e.  $ contrib/Solaris10/create_package 2.52-1
+or   $ cd contrib/Solaris10; ./create_package 2.52-1
+
+It's a bit more complex than it could be because I 
+prefer putting the daemon in /usr/sbin and the config 
+in /etc, so the script will actually create a new 
+version of the existing contrib dnsmasq.xml.
diff --git a/contrib/Solaris10/create_package b/contrib/Solaris10/create_package
new file mode 100644
index 0000000..acfa2a1
--- /dev/null
+++ b/contrib/Solaris10/create_package
@@ -0,0 +1,87 @@
+#!/bin/sh
+
+#
+# For our package, and for the SMF script, we need to define where we
+# want things to go...
+#
+BIN_DIR="/usr/sbin"
+CONF_DIR="/etc"
+MAN_DIR="/usr/share/man/man8"
+
+PACKAGE_NAME="dnsmasq"
+
+#
+# Since we know we are in the contrib directory we can work out where
+# the rest of the tree is...
+#
+BASEDIR="`dirname $0`/../.."
+
+#
+# We need a version number to use for the package creation...
+#
+if [ $# != 1 ]; then
+	echo "Usage: $0 <package_version_number>" >&2
+	exit 1
+fi
+VERSION="$1"
+
+#
+# First thing we do is fix-up the smf file to use the paths we prefer...
+#
+if [ ! -f "${BASEDIR}/contrib/Solaris10/dnsmasq.xml" ]; then
+	echo "$0: unable to find contrib/Solaris10/dnsmasq.xml" >&2
+	exit 1
+fi
+
+echo "Fixing up smf file ... \c"
+cat "${BASEDIR}/contrib/Solaris10/dnsmasq.xml" | \
+	sed 	-e "s%/usr/local/etc%${CONF_DIR}%" \
+		-e "s%/usr/local/sbin%${BIN_DIR}%" \
+		-e "s%/usr/local/man%${MAN_DIR}%" > ${BASEDIR}/contrib/Solaris10/dnsmasq-pkg.xml
+echo "done."
+
+echo "Creating packaging file ... \c"
+cat <<EOF >${BASEDIR}/contrib/Solaris10/dnsmasq_package.inc
+#
+# header
+#
+set name=pkg.name		value="dnsmasq"
+set name=pkg.description	value="dnsmasq daemon - dns, dhcp, tftp etc"
+set name=pkg.detailed_url	value="http://www.thekelleys.org.uk/dnsmasq/doc.html"
+set name=info.maintainer	value="TBD (tbd@tbd.com)"
+set name=info.upstream		value="dnsmasq-discuss@lists.thekelleys.org.uk"
+set name=info.upstream_url	value="http://www.thekelleys.org.uk/dnsmasq/doc.html"
+#
+# dependencies ... none?
+#
+
+#
+# directories
+#
+dir mode=0755 owner=root group=bin path=${BIN_DIR}/
+dir mode=0755 owner=root group=sys path=${CONF_DIR}/
+dir mode=0755 owner=root group=sys path=${MAN_DIR}/
+dir mode=0755 owner=root group=sys path=/var/
+dir mode=0755 owner=root group=sys path=/var/svc
+dir mode=0755 owner=root group=sys path=/var/svc/manifest
+dir mode=0755 owner=root group=sys path=/var/svc/manifest/network
+
+#
+# files
+#
+file ${BASEDIR}/src/dnsmasq mode=0555 owner=root group=bin path=${BIN_DIR}/dnsmasq
+file ${BASEDIR}/man/dnsmasq.8 mode=0555 owner=root group=bin path=${MAN_DIR}/dnsmasq.8
+file ${BASEDIR}/dnsmasq.conf.example mode=0644 owner=root group=sys path=${CONF_DIR}/dnsmasq.conf preserve=strawberry
+file ${BASEDIR}/contrib/Solaris10/dnsmasq-pkg.xml mode=0644 owner=root group=sys path=/var/svc/manifest/network/dnsmasq.xml restart_fmri=svc:/system/manifest-import:default
+
+EOF
+echo "done."
+
+echo "Creating package..."
+eval `pkgsend open ${PACKAGE_NAME}@${VERSION}`
+pkgsend include ${BASEDIR}/contrib/Solaris10/dnsmasq_package.inc
+if [ "$?" = 0 ]; then
+	pkgsend close
+else
+	echo "Errors"
+fi
diff --git a/contrib/Solaris10/dnsmasq.xml b/contrib/Solaris10/dnsmasq.xml
new file mode 100755
index 0000000..7da0253
--- /dev/null
+++ b/contrib/Solaris10/dnsmasq.xml
@@ -0,0 +1,65 @@
+<?xml version='1.0'?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+
+<!-- Service manifest for dnsmasq -->
+
+<service_bundle type='manifest' name='dnsmasq'>
+  <service name='network/dnsmasq' type='service' version='1'>
+
+    <create_default_instance enabled='false'/>
+    <single_instance/>
+
+    <dependency name='multi-user'
+                grouping='require_all'
+                restart_on='refresh'
+                type='service'>
+      <service_fmri value='svc:/milestone/multi-user'/>
+    </dependency>
+
+    <dependency name='config'
+		grouping='require_all'
+		restart_on='restart'
+		type='path'>
+      <service_fmri value='file:///usr/local/etc/dnsmasq.conf'/>
+    </dependency>
+
+    <dependent name='dnsmasq_multi-user-server'
+               grouping='optional_all'
+               restart_on='none'>
+      <service_fmri value='svc:/milestone/multi-user-server' />
+    </dependent>
+
+    <exec_method type='method' name='start'
+                 exec='/usr/local/sbin/dnsmasq -C /usr/local/etc/dnsmasq.conf'
+                 timeout_seconds='60' >
+      <method_context>
+        <method_credential user='root' group='root' privileges='all'/>
+      </method_context>
+    </exec_method>
+
+    <exec_method type='method'
+                 name='stop'
+                 exec=':kill'
+                 timeout_seconds='60'/>
+
+    <exec_method type='method'
+                 name='refresh'
+                 exec=':kill -HUP'
+                 timeout_seconds='60' />
+
+    <template>
+      <common_name>
+        <loctext xml:lang='C'>dnsmasq server</loctext>
+      </common_name>
+      <description>
+        <loctext xml:lang='C'>
+dnsmasq - A lightweight DHCP and caching DNS server.
+        </loctext>
+      </description>
+      <documentation>
+        <manpage title='dnsmasq' section='8' manpath='/usr/local/man'/>
+      </documentation>
+    </template>
+
+  </service>
+</service_bundle>
diff --git a/contrib/Suse/README b/contrib/Suse/README
new file mode 100755
index 0000000..3fdc186
--- /dev/null
+++ b/contrib/Suse/README
@@ -0,0 +1,6 @@
+This packaging is now unmaintained in the dnsmasq source: dnsmasq is
+included in Suse proper, and up-to-date packages are now available
+from 
+
+ftp://ftp.suse.com/pub/people/ug/
+
diff --git a/contrib/Suse/README.susefirewall b/contrib/Suse/README.susefirewall
new file mode 100755
index 0000000..0b94108
--- /dev/null
+++ b/contrib/Suse/README.susefirewall
@@ -0,0 +1,27 @@
+This is a patch against SuSEfirewall2-3.1-206 (SuSE 9.x and older)
+It fixes the dependency 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 always '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/contrib/Suse/dnsmasq-SuSE.patch b/contrib/Suse/dnsmasq-SuSE.patch
new file mode 100755
index 0000000..626245f
--- /dev/null
+++ b/contrib/Suse/dnsmasq-SuSE.patch
@@ -0,0 +1,23 @@
+--- man/dnsmasq.8	2004-08-08 20:57:56.000000000 +0200
++++ man/dnsmasq.8	2004-08-12 00:40:01.000000000 +0200
+@@ -69,7 +69,7 @@
+ .TP
+ .B \-g, --group=<groupname> 
+ Specify the group which dnsmasq will run
+-as. The defaults to "dip", if available, to facilitate access to
++as. The defaults to "dialout", if available, to facilitate access to
+ /etc/ppp/resolv.conf which is not normally world readable.
+ .TP
+ .B \-v, --version
+--- src/config.h	2004-08-11 11:39:18.000000000 +0200
++++ src/config.h	2004-08-12 00:40:01.000000000 +0200
+@@ -44,7 +44,7 @@
+ #endif
+ #define DEFLEASE 3600 /* default lease time, 1 hour */
+ #define CHUSER "nobody"
+-#define CHGRP "dip"
++#define CHGRP "dialout"
+ #define DHCP_SERVER_PORT 67
+ #define DHCP_CLIENT_PORT 68
+ 
+
diff --git a/contrib/Suse/dnsmasq-suse.spec b/contrib/Suse/dnsmasq-suse.spec
new file mode 100755
index 0000000..ff8ba8f
--- /dev/null
+++ b/contrib/Suse/dnsmasq-suse.spec
@@ -0,0 +1,111 @@
+###############################################################################
+#
+# General
+#
+###############################################################################
+
+Name: dnsmasq
+Version: 2.33
+Release: 1
+Copyright: GPL
+Group: Productivity/Networking/DNS/Servers
+Vendor: Simon Kelley
+Packager: Simon Kelley
+URL: http://www.thekelleys.org.uk/dnsmasq
+Provides: dns_daemon
+Conflicts: bind bind8 bind9
+PreReq: %fillup_prereq %insserv_prereq
+Autoreqprov: on
+Source0: %{name}-%{version}.tar.bz2
+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
+patch -p0 <rpm/%{name}-SuSE.patch
+
+%build
+%{?suse_update_config:%{suse_update_config -f}}
+make all-i18n DESTDIR=$RPM_BUILD_ROOT PREFIX=/usr
+
+###############################################################################
+#
+# Install
+#
+###############################################################################
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p ${RPM_BUILD_ROOT}/etc/init.d
+make install-i18n DESTDIR=$RPM_BUILD_ROOT PREFIX=/usr
+install -o root -g root -m 755 rpm/rc.dnsmasq-suse $RPM_BUILD_ROOT/etc/init.d/dnsmasq
+install -o root -g root -m 644 dnsmasq.conf.example $RPM_BUILD_ROOT/etc/dnsmasq.conf
+strip $RPM_BUILD_ROOT/usr/sbin/dnsmasq
+ln -sf ../../etc/init.d/dnsmasq $RPM_BUILD_ROOT/usr/sbin/rcdnsmasq
+
+###############################################################################
+#
+# Clean up
+#
+###############################################################################
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+###############################################################################
+#
+# Post-install scriptlet
+#
+###############################################################################
+
+%post
+%{fillup_and_insserv dnsmasq}
+
+###############################################################################
+#
+# 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
+%{insserv_cleanup}
+
+###############################################################################
+#
+# File list
+#
+###############################################################################
+
+%files
+%defattr(-,root,root)
+%doc CHANGELOG COPYING FAQ doc.html setup.html UPGRADING_to_2.0 rpm/README.susefirewall
+%doc contrib
+%config /etc/init.d/dnsmasq
+%config /etc/dnsmasq.conf
+/usr/sbin/rcdnsmasq
+/usr/sbin/dnsmasq
+/usr/share/locale/*/LC_MESSAGES/*
+%doc %{_mandir}/man8/dnsmasq.8.gz
+%doc %{_mandir}/*/man8/dnsmasq.8.gz
+
+
diff --git a/contrib/Suse/rc.dnsmasq-suse b/contrib/Suse/rc.dnsmasq-suse
new file mode 100755
index 0000000..71f4c72
--- /dev/null
+++ b/contrib/Suse/rc.dnsmasq-suse
@@ -0,0 +1,79 @@
+#! /bin/sh
+#
+# init.d/dnsmasq
+#
+### BEGIN INIT INFO
+# Provides:       dnsmasq
+# Required-Start: $network $remote_fs $syslog
+# Required-Stop:
+# Default-Start:  3 5
+# Default-Stop:
+# Description:    Starts internet name service masq caching server (DNS)
+### END INIT INFO
+
+NAMED_BIN=/usr/sbin/dnsmasq
+NAMED_PID=/var/run/dnsmasq.pid
+NAMED_CONF=/etc/dnsmasq.conf
+
+if [ ! -x $NAMED_BIN ] ; then
+	echo -n "dnsmasq not installed ! "
+	exit 5
+fi
+
+. /etc/rc.status
+rc_reset
+
+case "$1" in
+    start)
+	echo -n "Starting name service masq caching server "
+        checkproc -p $NAMED_PID $NAMED_BIN
+        if [ $? -eq 0 ] ; then
+           echo -n "- Warning: dnsmasq already running ! "
+        else
+           [ -e $NAMED_PID ] && echo -n "- Warning: $NAMED_PID exists ! "
+	fi
+	startproc -p $NAMED_PID $NAMED_BIN -u nobody
+	rc_status -v
+	;;
+    stop)
+	echo -n "Shutting name service masq caching server "
+	checkproc -p $NAMED_PID $NAMED_BIN
+	[ $? -ne 0 ] && echo -n "- Warning: dnsmasq not running ! "
+	killproc -p $NAMED_PID -TERM $NAMED_BIN
+	rc_status -v
+	;;
+    try-restart)
+	$0 stop  &&  $0 start
+	rc_status
+	;;
+    restart)
+	$0 stop
+	$0 start
+	rc_status
+	;;
+    force-reload)
+	$0 reload
+	rc_status
+	;;
+    reload)
+	echo -n "Reloading name service masq caching server "
+	checkproc -p $NAMED_PID $NAMED_BIN
+	[ $? -ne 0 ] && echo -n "- Warning: dnsmasq not running ! "
+	killproc -p $NAMED_PID -HUP $NAMED_BIN
+	rc_status -v
+	;;
+    status)
+	echo -n "Checking for name service masq caching server "
+	checkproc -p $NAMED_PID $NAMED_BIN
+	rc_status -v
+	;;
+    probe)
+	test $NAMED_CONF -nt $NAMED_PID && echo reload
+	;;
+    *)
+	echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}"
+	exit 1
+	;;
+esac
+rc_exit
+
diff --git a/contrib/conntrack/README b/contrib/conntrack/README
new file mode 100644
index 0000000..e883447
--- /dev/null
+++ b/contrib/conntrack/README
@@ -0,0 +1,54 @@
+Linux iptables includes that ability to mark individual network packets
+with a "firewall mark".  Additionally there is a component called
+"conntrack" which tries to string sequences of related packets together
+into a "connection" (it even relates sequences of UDP and ICMP packets).
+ There is a related mark for a connection called a "connection mark".
+Marks can be copied freely between the firewall and connection marks
+
+Using these two features it become possible to tag all related traffic
+in arbitrary ways, eg authenticated users, traffic from a particular IP,
+port, etc. Unfortunately any kind of "proxy" breaks this relationship
+because network packets go in one side of the proxy and a completely new
+connection comes out of the other side.  However, sometimes, we want to
+maintain that relationship through the proxy and continue the connection
+mark on packets upstream of our proxy
+
+Dnsmasq includes such a feature enabled by the --conntrack
+option. This allows, for example, using iptables to mark traffic from
+a particular IP, and that mark to be persisted to requests made *by*
+Dnsmasq. Such a feature could be useful for bandwidth accounting,
+captive portals and the like. Note a similar feature has been 
+implemented in Squid 2.2
+
+
+As an example consider the following iptables rules:
+
+
+1) iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
+2) iptables -t mangle -A PREROUTING -m mark --mark 0 -s 192.168.111.137
+-j MARK --set-mark 137
+3) iptables -t mangle -A PREROUTING -j CONNMARK --save-mark
+
+4) iptables -t mangle -A OUTPUT -m mark ! --mark 0 -j CONNMARK --save-mark
+
+1-3) are all applied to the PREROUTING table and affect all packets
+entering the firewall.
+
+1) copies any existing connection mark into the firewall mark. 2) Checks
+the packet not already marked and if not applies an arbitrary mark based
+on IP address. 3) Saves the firewall mark back to the connection mark
+(which will persist it across related packets)
+
+4) is applied to the OUTPUT table, which is where we first see packets
+generated locally. Dnsmasq will have already copied the firewall mark
+from the request, across to the new packet, and so all that remains is
+for iptables to copy it to the connection mark so it's persisted across
+packets.
+
+Note: iptables can be quite confusing to the beginner. The following
+diagram is extremely helpful in understanding the flows
+	http://linux-ip.net/nf/nfk-traversal.png
+Additionally the following URL contains a useful "starting guide" on
+linux connection tracking/marking
+	http://home.regit.org/netfilter-en/netfilter-connmark/
+
diff --git a/contrib/dbus-test/dbus-test.py b/contrib/dbus-test/dbus-test.py
new file mode 100755
index 0000000..25d8881
--- /dev/null
+++ b/contrib/dbus-test/dbus-test.py
@@ -0,0 +1,43 @@
+#!/usr/bin/python
+import dbus
+
+bus = dbus.SystemBus()
+p = bus.get_object("uk.org.thekelleys.dnsmasq", "/uk/org/thekelleys/dnsmasq")
+l = dbus.Interface(p, dbus_interface="uk.org.thekelleys.dnsmasq")
+
+# The new more flexible SetServersEx method
+array = dbus.Array()
+array.append(["1.2.3.5"])
+array.append(["1.2.3.4#664", "foobar.com"])
+array.append(["1003:1234:abcd::1%eth0", "eng.mycorp.com", "lab.mycorp.com"])
+print l.SetServersEx(array)
+
+# Must create a new object for dnsmasq as the introspection gives the wrong
+# signature for SetServers (av) while the code only expects a bunch of arguments
+# instead of an array of variants
+p = bus.get_object("uk.org.thekelleys.dnsmasq", "/uk/org/thekelleys/dnsmasq", introspect=False)
+l = dbus.Interface(p, dbus_interface="uk.org.thekelleys.dnsmasq")
+
+# The previous method; all addresses in machine byte order
+print l.SetServers(dbus.UInt32(16909060), # 1.2.3.5
+                   dbus.UInt32(16909061), # 1.2.3.4
+                   "foobar.com",
+                   dbus.Byte(0x10),       # 1003:1234:abcd::1
+                   dbus.Byte(0x03),
+                   dbus.Byte(0x12),
+                   dbus.Byte(0x34),
+                   dbus.Byte(0xab),
+                   dbus.Byte(0xcd),
+                   dbus.Byte(0x00),
+                   dbus.Byte(0x00),
+                   dbus.Byte(0x00),
+                   dbus.Byte(0x00),
+                   dbus.Byte(0x00),
+                   dbus.Byte(0x00),
+                   dbus.Byte(0x00),
+                   dbus.Byte(0x00),
+                   dbus.Byte(0x00),
+                   dbus.Byte(0x01),
+                   "eng.mycorp.com",
+                   "lab.mycorp.com")
+
diff --git a/contrib/dns-loc/README b/contrib/dns-loc/README
new file mode 100755
index 0000000..6f43a8d
--- /dev/null
+++ b/contrib/dns-loc/README
@@ -0,0 +1,12 @@
+Hi Simon
+
+Here is a patch against dnsmasq 2.39 which provides support for LOC  
+entries in order to assign location information to dns records  
+(rfc1876). I tested it on OSX and on OpenWRT.
+
+Cheers
+Lorenz
+
+More info:
+http://www.ckdhr.com/dns-loc/
+http://www.faqs.org/rfcs/rfc1876.html
diff --git a/contrib/dns-loc/dnsmasq2-loc-rfc1876.patch b/contrib/dns-loc/dnsmasq2-loc-rfc1876.patch
new file mode 100755
index 0000000..d950321
--- /dev/null
+++ b/contrib/dns-loc/dnsmasq2-loc-rfc1876.patch
@@ -0,0 +1,522 @@
+diff -Nur dnsmasq-2.39-orig/bld/Makefile dnsmasq-2.39/bld/Makefile
+--- dnsmasq-2.39-orig/bld/Makefile	2007-02-17 14:37:06.000000000 +0100
++++ dnsmasq-2.39/bld/Makefile	2007-05-20 18:23:44.000000000 +0200
+@@ -2,7 +2,7 @@
+ PKG_CONFIG ?= pkg-config
+ 
+ 
+-OBJS = cache.o rfc1035.o util.o option.o forward.o isc.o network.o \
++OBJS = cache.o rfc1035.o rfc1876.o util.o option.o forward.o isc.o network.o \
+        dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
+        helper.o tftp.o log.o
+ 
+diff -Nur dnsmasq-2.39-orig/src/dnsmasq.h dnsmasq-2.39/src/dnsmasq.h
+--- dnsmasq-2.39-orig/src/dnsmasq.h	2007-04-20 12:53:38.000000000 +0200
++++ dnsmasq-2.39/src/dnsmasq.h	2007-05-20 19:50:37.000000000 +0200
+@@ -162,6 +162,12 @@
+   struct interface_name *next;
+ };
+ 
++struct loc_record {
++  char *name, loc[16];
++  unsigned short class;
++  struct loc_record *next;
++};
++
+ union bigname {
+   char name[MAXDNAME];
+   union bigname *next; /* freelist */
+@@ -476,6 +482,7 @@
+   struct mx_srv_record *mxnames;
+   struct txt_record *txt;
+   struct ptr_record *ptr;
++	struct loc_record *loc;
+   struct interface_name *int_names;
+   char *mxtarget;
+   char *lease_file; 
+@@ -725,3 +732,6 @@
+ void tftp_request(struct listener *listen, struct daemon *daemon, time_t now);
+ void check_tftp_listeners(struct daemon *daemon, fd_set *rset, time_t now);
+ #endif
++
++/* rfc1876 */
++u_int32_t loc_aton(const char *ascii, u_char *binary);
+diff -Nur dnsmasq-2.39-orig/src/option.c dnsmasq-2.39/src/option.c
+--- dnsmasq-2.39-orig/src/option.c	2007-04-19 23:34:49.000000000 +0200
++++ dnsmasq-2.39/src/option.c	2007-05-20 20:15:15.000000000 +0200
+@@ -43,6 +43,7 @@
+ #define LOPT_REMOTE    269
+ #define LOPT_SUBSCR    270
+ #define LOPT_INTNAME   271
++#define LOPT_LOC       272
+ 
+ #ifdef HAVE_GETOPT_LONG
+ static const struct option opts[] =  
+@@ -122,6 +123,7 @@
+     {"tftp-root", 1, 0, LOPT_PREFIX },
+     {"tftp-max", 1, 0, LOPT_TFTP_MAX },
+     {"ptr-record", 1, 0, LOPT_PTR },
++    {"loc-record", 1, 0, LOPT_LOC },
+ #if defined(__FreeBSD__) || defined(__DragonFly__)
+     {"bridge-interface", 1, 0 , LOPT_BRIDGE },
+ #endif
+@@ -235,6 +237,7 @@
+   { "-y, --localise-queries", gettext_noop("Answer DNS queries based on the interface a query was sent to."), NULL },
+   { "-Y  --txt-record=name,txt....", gettext_noop("Specify TXT DNS record."), NULL },
+   { "    --ptr-record=name,target", gettext_noop("Specify PTR DNS record."), NULL },
++  { "    --loc-record=name,lat lon alt", gettext_noop("Specify LOC DNS record."), NULL },
+   { "    --interface-name=name,interface", gettext_noop("Give DNS name to IPv4 address of interface."), NULL },
+   { "-z, --bind-interfaces", gettext_noop("Bind only to interfaces in use."), NULL },
+   { "-Z, --read-ethers", gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
+@@ -1835,6 +1838,37 @@
+ 	new->intr = safe_string_alloc(comma);
+ 	break;
+       }
++      
++    case LOPT_LOC:
++      {
++	struct loc_record *new;
++	unsigned char *p, *q;
++	
++	comma = split(arg);
++	
++	if (!canonicalise_opt(arg))
++	  {
++	    option = '?';
++	    problem = _("bad LOC record");
++	    break;
++	  }
++	
++	new = safe_malloc(sizeof(struct loc_record));
++	new->next = daemon->loc;
++	daemon->loc = new;
++	new->class = C_IN;
++	if (!comma || loc_aton(comma,new->loc)!=16)
++	  {
++	    option = '?';
++	    problem = _("bad LOC record");
++	    break;
++	  }
++
++	if (comma)
++	  *comma = 0;
++	new->name = safe_string_alloc(arg);
++	break;
++      }
+ 
+     case LOPT_PTR:  /* --ptr-record */
+       {
+diff -Nur dnsmasq-2.39-orig/src/rfc1035.c dnsmasq-2.39/src/rfc1035.c
+--- dnsmasq-2.39-orig/src/rfc1035.c	2007-04-20 12:54:26.000000000 +0200
++++ dnsmasq-2.39/src/rfc1035.c	2007-05-20 18:22:46.000000000 +0200
+@@ -1112,6 +1112,27 @@
+ 	    }
+ 	}
+ 
++      if (qtype == T_LOC || qtype == T_ANY)
++	{
++	  struct loc_record *t;
++	  for(t = daemon->loc; t ; t = t->next)
++	    {
++	      if (t->class == qclass && hostname_isequal(name, t->name))
++		{
++		  ans = 1;
++		  if (!dryrun)
++		    {
++		      log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, 0, NULL, 0);
++		      if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
++					      daemon->local_ttl, NULL,
++					      T_LOC, t->class, "t", 16, t->loc))
++			anscount++;
++
++		    }
++		}
++	    }
++	}
++
+       if (qclass == C_IN)
+ 	{
+ 	  if (qtype == T_PTR || qtype == T_ANY)
+diff -Nur dnsmasq-2.39-orig/src/rfc1876.c dnsmasq-2.39/src/rfc1876.c
+--- dnsmasq-2.39-orig/src/rfc1876.c	1970-01-01 01:00:00.000000000 +0100
++++ dnsmasq-2.39/src/rfc1876.c	2007-05-20 19:50:10.000000000 +0200
+@@ -0,0 +1,379 @@
++/*
++ * routines to convert between on-the-wire RR format and zone file
++ * format.  Does not contain conversion to/from decimal degrees;
++ * divide or multiply by 60*60*1000 for that.
++ */
++
++#include "dnsmasq.h"
++
++static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
++                                 1000000,10000000,100000000,1000000000};
++
++/* takes an XeY precision/size value, returns a string representation.*/
++static const char *
++precsize_ntoa(u_int8_t prec)
++{
++        static char retbuf[sizeof("90000000.00")];
++        unsigned long val;
++        int mantissa, exponent;
++
++        mantissa = (int)((prec >> 4) & 0x0f) % 10;
++        exponent = (int)((prec >> 0) & 0x0f) % 10;
++
++        val = mantissa * poweroften[exponent];
++
++        (void) sprintf(retbuf,"%d.%.2d", val/100, val%100);
++        return (retbuf);
++}
++
++/* converts ascii size/precision X * 10**Y(cm) to 0xXY. moves pointer.*/
++static u_int8_t
++precsize_aton(char **strptr)
++{
++        unsigned int mval = 0, cmval = 0;
++        u_int8_t retval = 0;
++        register char *cp;
++        register int exponent;
++        register int mantissa;
++
++        cp = *strptr;
++
++        while (isdigit(*cp))
++                mval = mval * 10 + (*cp++ - '0');
++
++        if (*cp == '.') {               /* centimeters */
++                cp++;
++                if (isdigit(*cp)) {
++                        cmval = (*cp++ - '0') * 10;
++                        if (isdigit(*cp)) {
++                                cmval += (*cp++ - '0');
++                        }
++                }
++        }
++        cmval = (mval * 100) + cmval;
++
++        for (exponent = 0; exponent < 9; exponent++)
++                if (cmval < poweroften[exponent+1])
++                        break;
++
++        mantissa = cmval / poweroften[exponent];
++        if (mantissa > 9)
++                mantissa = 9;
++
++        retval = (mantissa << 4) | exponent;
++
++        *strptr = cp;
++
++        return (retval);
++}
++
++/* converts ascii lat/lon to unsigned encoded 32-bit number.
++ *  moves pointer. */
++static u_int32_t
++latlon2ul(char **latlonstrptr,int *which)
++{
++        register char *cp;
++        u_int32_t retval;
++        int deg = 0, min = 0, secs = 0, secsfrac = 0;
++
++        cp = *latlonstrptr;
++
++        while (isdigit(*cp))
++                deg = deg * 10 + (*cp++ - '0');
++
++        while (isspace(*cp))
++                cp++;
++
++        if (!(isdigit(*cp)))
++                goto fndhemi;
++
++        while (isdigit(*cp))
++                min = min * 10 + (*cp++ - '0');
++        while (isspace(*cp))
++                cp++;
++
++        if (!(isdigit(*cp)))
++                goto fndhemi;
++
++        while (isdigit(*cp))
++                secs = secs * 10 + (*cp++ - '0');
++
++        if (*cp == '.') {               /* decimal seconds */
++                cp++;
++                if (isdigit(*cp)) {
++                        secsfrac = (*cp++ - '0') * 100;
++                        if (isdigit(*cp)) {
++                                secsfrac += (*cp++ - '0') * 10;
++                                if (isdigit(*cp)) {
++                                        secsfrac += (*cp++ - '0');
++                                }
++                        }
++                }
++        }
++
++        while (!isspace(*cp))   /* if any trailing garbage */
++                cp++;
++
++        while (isspace(*cp))
++                cp++;
++
++ fndhemi:
++        switch (*cp) {
++        case 'N': case 'n':
++        case 'E': case 'e':
++                retval = ((unsigned)1<<31)
++                        + (((((deg * 60) + min) * 60) + secs) * 1000)
++                        + secsfrac;
++                break;
++        case 'S': case 's':
++        case 'W': case 'w':
++                retval = ((unsigned)1<<31)
++                        - (((((deg * 60) + min) * 60) + secs) * 1000)
++                        - secsfrac;
++                break;
++        default:
++                retval = 0;     /* invalid value -- indicates error */
++                break;
++        }
++
++        switch (*cp) {
++        case 'N': case 'n':
++        case 'S': case 's':
++                *which = 1;     /* latitude */
++                break;
++        case 'E': case 'e':
++        case 'W': case 'w':
++                *which = 2;     /* longitude */
++                break;
++        default:
++                *which = 0;     /* error */
++                break;
++        }
++
++        cp++;                   /* skip the hemisphere */
++
++        while (!isspace(*cp))   /* if any trailing garbage */
++                cp++;
++
++        while (isspace(*cp))    /* move to next field */
++                cp++;
++
++        *latlonstrptr = cp;
++
++        return (retval);
++}
++
++/* converts a zone file representation in a string to an RDATA
++ * on-the-wire representation. */
++u_int32_t
++loc_aton(const char *ascii, u_char *binary)
++{
++        const char *cp, *maxcp;
++        u_char *bcp;
++
++        u_int32_t latit = 0, longit = 0, alt = 0;
++        u_int32_t lltemp1 = 0, lltemp2 = 0;
++        int altmeters = 0, altfrac = 0, altsign = 1;
++        u_int8_t hp = 0x16;    /* default = 1e6 cm = 10000.00m = 10km */
++        u_int8_t vp = 0x13;    /* default = 1e3 cm = 10.00m */
++        u_int8_t siz = 0x12;   /* default = 1e2 cm = 1.00m */
++        int which1 = 0, which2 = 0;
++
++        cp = ascii;
++        maxcp = cp + strlen(ascii);
++
++        lltemp1 = latlon2ul(&cp, &which1);
++        lltemp2 = latlon2ul(&cp, &which2);
++
++        switch (which1 + which2) {
++        case 3:                 /* 1 + 2, the only valid combination */
++                if ((which1 == 1) && (which2 == 2)) { /* normal case */
++                        latit = lltemp1;
++                        longit = lltemp2;
++                } else if ((which1 == 2) && (which2 == 1)) {/*reversed*/
++                        longit = lltemp1;
++                        latit = lltemp2;
++                } else {        /* some kind of brokenness */
++                        return 0;
++                }
++                break;
++        default:                /* we didn't get one of each */
++                return 0;
++        }
++
++        /* altitude */
++        if (*cp == '-') {
++                altsign = -1;
++                cp++;
++        }
++
++        if (*cp == '+')
++                cp++;
++
++        while (isdigit(*cp))
++                altmeters = altmeters * 10 + (*cp++ - '0');
++
++        if (*cp == '.') {               /* decimal meters */
++                cp++;
++                if (isdigit(*cp)) {
++                        altfrac = (*cp++ - '0') * 10;
++                        if (isdigit(*cp)) {
++                                altfrac += (*cp++ - '0');
++                        }
++                }
++        }
++
++        alt = (10000000 + (altsign * (altmeters * 100 + altfrac)));
++
++        while (!isspace(*cp) && (cp < maxcp))
++                                           /* if trailing garbage or m */
++                cp++;
++
++        while (isspace(*cp) && (cp < maxcp))
++                cp++;
++        if (cp >= maxcp)
++                goto defaults;
++
++        siz = precsize_aton(&cp);
++
++        while (!isspace(*cp) && (cp < maxcp))/*if trailing garbage or m*/
++                cp++;
++
++        while (isspace(*cp) && (cp < maxcp))
++                cp++;
++
++        if (cp >= maxcp)
++                goto defaults;
++
++        hp = precsize_aton(&cp);
++
++        while (!isspace(*cp) && (cp < maxcp))/*if trailing garbage or m*/
++                cp++;
++
++        while (isspace(*cp) && (cp < maxcp))
++                cp++;
++
++        if (cp >= maxcp)
++                goto defaults;
++
++        vp = precsize_aton(&cp);
++
++ defaults:
++
++        bcp = binary;
++        *bcp++ = (u_int8_t) 0;  /* version byte */
++        *bcp++ = siz;
++        *bcp++ = hp;
++        *bcp++ = vp;
++        PUTLONG(latit,bcp);
++        PUTLONG(longit,bcp);
++        PUTLONG(alt,bcp);
++
++        return (16);            /* size of RR in octets */
++}
++
++/* takes an on-the-wire LOC RR and prints it in zone file
++ * (human readable) format. */
++char *
++loc_ntoa(const u_char *binary,char *ascii)
++{
++        static char tmpbuf[255*3];
++
++        register char *cp;
++        register const u_char *rcp;
++
++        int latdeg, latmin, latsec, latsecfrac;
++        int longdeg, longmin, longsec, longsecfrac;
++        char northsouth, eastwest;
++        int altmeters, altfrac, altsign;
++
++        const int referencealt = 100000 * 100;
++
++        int32_t latval, longval, altval;
++        u_int32_t templ;
++        u_int8_t sizeval, hpval, vpval, versionval;
++
++        char *sizestr, *hpstr, *vpstr;
++
++        rcp = binary;
++        if (ascii)
++                cp = ascii;
++        else {
++                cp = tmpbuf;
++        }
++
++        versionval = *rcp++;
++
++        if (versionval) {
++                sprintf(cp,"; error: unknown LOC RR version");
++                return (cp);
++        }
++
++        sizeval = *rcp++;
++
++        hpval = *rcp++;
++        vpval = *rcp++;
++
++        GETLONG(templ,rcp);
++        latval = (templ - ((unsigned)1<<31));
++
++        GETLONG(templ,rcp);
++        longval = (templ - ((unsigned)1<<31));
++
++        GETLONG(templ,rcp);
++        if (templ < referencealt) { /* below WGS 84 spheroid */
++                altval = referencealt - templ;
++                altsign = -1;
++        } else {
++                altval = templ - referencealt;
++                altsign = 1;
++        }
++
++        if (latval < 0) {
++                northsouth = 'S';
++                latval = -latval;
++        }
++        else
++                northsouth = 'N';
++
++        latsecfrac = latval % 1000;
++        latval = latval / 1000;
++        latsec = latval % 60;
++        latval = latval / 60;
++        latmin = latval % 60;
++        latval = latval / 60;
++        latdeg = latval;
++
++        if (longval < 0) {
++                eastwest = 'W';
++                longval = -longval;
++        }
++        else
++                eastwest = 'E';
++
++        longsecfrac = longval % 1000;
++        longval = longval / 1000;
++        longsec = longval % 60;
++        longval = longval / 60;
++        longmin = longval % 60;
++        longval = longval / 60;
++        longdeg = longval;
++
++        altfrac = altval % 100;
++        altmeters = (altval / 100) * altsign;
++
++        sizestr = strdup(precsize_ntoa(sizeval));
++        hpstr = strdup(precsize_ntoa(hpval));
++        vpstr = strdup(precsize_ntoa(vpval));
++
++        sprintf(cp,
++                "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %d.%.2dm %sm %sm %sm",
++                latdeg, latmin, latsec, latsecfrac, northsouth,
++                longdeg, longmin, longsec, longsecfrac, eastwest,
++                altmeters, altfrac, sizestr, hpstr, vpstr);
++        free(sizestr);
++        free(hpstr);
++        free(vpstr);
++
++        return (cp);
++}
diff --git a/contrib/dnslist/dhcp.css b/contrib/dnslist/dhcp.css
new file mode 100755
index 0000000..79cea39
--- /dev/null
+++ b/contrib/dnslist/dhcp.css
@@ -0,0 +1,57 @@
+body
+{
+	font-family: sans-serif;
+	color: #000;
+}
+
+h1
+{
+	font-size: medium;
+	font-weight: bold;
+}
+
+h1 .updated
+{
+	color: #999;
+}
+
+table
+{
+	border-collapse: collapse;
+	border-bottom: 2px solid #000;
+}
+
+th
+{
+	background: #DDD;
+	border-top: 2px solid #000;
+	text-align: left;
+	font-weight: bold;
+}
+
+/* Any row */
+
+tr
+{
+	border-top: 2px solid #000;
+}
+
+/* Any row but the first or second (overrides above rule) */
+
+tr + tr + tr
+{
+	border-top: 2px solid #999;
+}
+
+tr.offline td.hostname
+{
+	color: #999;
+}
+
+.hostname   { width: 10em; }
+.ip_addr    { width: 10em; background: #DDD; }
+.ether_addr { width: 15em; }
+.client_id  { width: 15em; background: #DDD; }
+.status     { width: 5em;  }
+.since      { width: 10em; background: #DDD; }
+.lease      { width: 10em; }
diff --git a/contrib/dnslist/dnslist.pl b/contrib/dnslist/dnslist.pl
new file mode 100755
index 0000000..7ce2720
--- /dev/null
+++ b/contrib/dnslist/dnslist.pl
@@ -0,0 +1,608 @@
+#!/usr/bin/perl
+
+# dnslist - Read state file from dnsmasq and create a nice web page to display
+#           a list of DHCP clients.
+# 
+# Copyright (C) 2004  Thomas Tuttle
+# 
+# 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; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program*; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+# 
+# * The license is in fact included at the end of this file, and can
+#   either be viewed by reading everything after "__DATA__" or by
+#   running dnslist with the '-l' option.
+# 
+# Version: 0.2
+# Author:  Thomas Tuttle
+# Email:   dnslist.20.thinkinginbinary@spamgourmet.org
+# License: GNU General Public License, version 2.0
+#
+# v. 0.0: Too ugly to publish, thrown out.
+#
+# v. 0.1: First rewrite.
+#         Added master host list so offline hosts can still be displayed.
+#         Fixed modification detection (a newer modification time is lower.)
+#
+# v. 0.2: Fixed Client ID = "*" => "None"
+#         Fixed HTML entities (a client ID of ????<? screwed it up)
+#         Fixed command-line argument processing (apparently, "shift @ARGV" !=
+#             "$_ = shift @ARGV"...)
+#         Added license information.
+
+use Template;
+
+# Location of state file.  (This is the dnsmasq default.)
+# Change with -s <file>
+my $dnsmasq_state_file = '/var/lib/misc/dnsmasq.leases';
+# Location of template.  (Assumed to be in current directory.)
+# Change with -t <file>
+my $html_template_file = 'dnslist.tt2';
+# File to write HTML page to.  (This is where Slackware puts WWW pages.  It may
+# be different on other systems.  Make sure the permissions are set correctly
+# for it.)
+my $html_output_file = '/var/www/htdocs/dhcp.html';
+# Time to wait after each page update.  (The state file is checked for changes
+# before each update but is not read in each time, in case it is very big.  The
+# page is rewritten just so the "(updated __/__ __:__:__)" text changes ;-)
+my $wait_time = 2;
+
+# Read command-line arguments.
+while ($_ = shift @ARGV) {
+	if (/-s/) { $dnsmasq_state_file = shift; next; }
+	if (/-t/) { $html_template_file = shift; next; }
+	if (/-o/) { $html_output_file = shift;   next; }
+	if (/-d/) { $wait_time = shift;          next; }
+	if (/-l/) { show_license();              exit; }
+	die "usage: dnslist [-s state_file] [-t template_file] [-o output_file] [-d delay_time]\n";
+}
+
+# Master list of clients, offline and online.
+my $list = {};
+# Sorted host list.  (It's actually sorted by IP--the sub &byip() compares two
+# IP addresses, octet by octet, and figures out which is higher.)
+my @hosts = ();
+# Last time the state file was changed.
+my $last_state_change;
+
+# Check for a change to the state file.
+sub check_state {
+	if (defined $last_state_change) {
+		if (-M $dnsmasq_state_file < $last_state_change) {
+			print "check_state: state file has been changed.\n";
+			$last_state_change = -M $dnsmasq_state_file;
+			return 1;
+		} else {
+			return 0;
+		}
+	} else {
+		# Last change undefined, so we are running for the first time.
+		print "check_state: reading state file at startup.\n";
+		read_state();
+		$last_state_change = -M $dnsmasq_state_file;
+		return 1;
+	}
+}
+
+# Read data in state file.
+sub read_state {
+	my $old;
+	my $new;
+	# Open file.
+	unless (open STATE, $dnsmasq_state_file) {
+		warn "read_state: can't open $dnsmasq_state_file!\n";
+		return 0;
+	}
+	# Mark all hosts as offline, saving old state.
+	foreach $ether (keys %{$list}) {
+		$list->{$ether}->{'old_online'} = $list->{$ether}->{'online'};
+		$list->{$ether}->{'online'} = 0;
+	}
+	# Read hosts.
+	while (<STATE>) {
+		chomp;
+		@host{qw/raw_lease ether_addr ip_addr hostname raw_client_id/} = split /\s+/;
+		$ether = $host{ether_addr};
+		# Mark each online host as online.
+		$list->{$ether}->{'online'} = 1;
+		# Copy data to master list.
+		foreach $key (keys %host) {
+			$list->{$ether}->{$key} = $host{$key};
+		}
+	}
+	close STATE;
+	# Handle changes in offline/online state.  (The sub &do_host() handles
+	# all of the extra stuff to do with a host's data once it is read.
+	foreach $ether (keys %{$list}) {
+		$old = $list->{$ether}->{'old_online'};
+		$new = $list->{$ether}->{'online'};
+		if (not $old) {
+			if (not $new) {
+				do_host($ether, 'offline');
+			} else {
+				do_host($ether, 'join');
+			}
+		} else {
+			if (not $new) {
+				do_host($ether, 'leave');
+			} else {
+				do_host($ether, 'online');
+			}
+		}
+	}
+	# Sort hosts by IP ;-)
+	@hosts = sort byip values %{$list};
+	# Copy sorted list to template data store.
+	$data->{'hosts'} = [ @hosts ];
+}
+
+# Do stuff per host.
+sub do_host {
+	my ($ether, $status) = @_;
+	
+	# Find textual representation of DHCP client ID.
+	if ($list->{$ether}->{'raw_client_id'} eq '*') {
+		$list->{$ether}->{'text_client_id'} = 'None';
+	} else {
+		my $text = "";
+		foreach $char (split /:/, $list->{$ether}->{'raw_client_id'}) {
+			$char = pack('H2', $char);
+			if (ord($char) >= 32 and ord($char) <= 127) {
+				$text .= $char;
+			} else {
+				$text .= "?";
+			}
+		}
+		$list->{$ether}->{'text_client_id'} = $text;
+	}
+		
+	# Convert lease expiration date/time to text.
+	if ($list->{$ether}->{'raw_lease'} == 0) {
+		$list->{$ether}->{'text_lease'} = 'Never';
+	} else {
+		$list->{$ether}->{'text_lease'} = nice_time($list->{$ether}->{'raw_lease'});
+	}
+	
+	if ($status eq 'offline') {
+		# Nothing to do.
+	} elsif ($status eq 'online') {
+		# Nothing to do.
+	} elsif ($status eq 'join') {
+		# Update times for joining host.
+		print "do_host: $ether joined the network.\n";
+		$list->{$ether}->{'join_time'} = time;
+		$list->{$ether}->{'since'} = nice_time(time);
+	} elsif ($status eq 'leave') {
+		# Update times for leaving host.
+		print "do_host: $ether left the network.\n";
+		$list->{$ether}->{'leave_time'} = time;
+		$list->{$ether}->{'since'} = nice_time(time);
+	}
+	
+}
+
+# Convert time to a string representation.
+sub nice_time {
+	my $time = shift;
+	my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $dst) = localtime($time);
+	$sec = pad($sec, '0', 2);
+	$min = pad($min, '0', 2);
+	$hour = pad($hour, '0', 2);
+	$mon = pad($mon, '0', 2);
+	$mday = pad($mday, '0', 2);
+	return "$mon/$mday $hour:$min:$sec";
+}
+
+# Pad string to a certain length by repeatedly prepending another string.
+sub pad {
+	my ($text, $pad, $length) = @_;
+	while (length($text) < $length) {
+		$text = "$pad$text";
+	}
+	return $text;
+}
+
+# Compare two IP addresses.  (Uses $a and $b from sort.)
+sub byip {
+	# Split into octets.
+	my @a = split /\./, $a->{ip_addr};
+	my @b = split /\./, $b->{ip_addr};
+	# Compare octets.
+	foreach $n (0..3) {
+		return $a[$n] <=> $b[$n] if ($a[$n] != $b[$n]);
+	}
+	# If we get here there is no difference.
+	return 0;
+}
+		
+# Output HTML file.
+sub write_output {
+	# Create new template object.
+	my $template = Template->new(
+		{
+			ABSOLUTE => 1, # /var/www/... is an absolute path
+			OUTPUT => $html_output_file # put it here, not STDOUT
+		}
+	);
+	$data->{'updated'} = nice_time(time); # add "(updated ...)" to file
+	unless ($template->process($html_template_file, $data)) { # do it
+		warn "write_output: Template Toolkit error: " . $template->error() . "\n";
+		return 0;
+	}
+	print "write_output: page updated.\n";
+	return 1;
+}
+
+sub show_license {
+	while (<DATA>) {
+		print;
+		$line++;
+		if ($line == 24) { <>; $line = 1; }
+	}
+}
+
+# Main loop.
+while (1) {
+	# Check for state change.
+	if (check_state()) {
+		read_state();
+		sleep 1; # Sleep for a second just so we don't wear anything
+		         # out.  (By not sleeping the whole time after a change
+			 # we can detect rapid changes more easily--like if 300
+			 # hosts all come back online, they show up quicker.)
+	} else {
+		sleep $wait_time; # Take a nap.
+	}
+	write_output(); # Write the file anyway.
+}
+__DATA__
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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; either version 2 of the License, or
+    (at your option) any later version.
+
+    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.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/contrib/dnslist/dnslist.tt2 b/contrib/dnslist/dnslist.tt2
new file mode 100755
index 0000000..1998e5f
--- /dev/null
+++ b/contrib/dnslist/dnslist.tt2
@@ -0,0 +1,32 @@
+<html>
+	<head>
+		<title>DHCP Clients</title>
+		<link rel="stylesheet" href="dhcp.css"/>
+		<meta http-equiv="Refresh" content="2"/>
+	</head>
+	<body>
+		<h1>DHCP Clients <span class="updated">(updated [% updated %])</span></h1>
+		<table cols="7">
+		<tr>
+			<th class="hostname">Hostname</th>
+			<th class="ip_addr">IP Address</th>
+			<th class="ether_addr">Ethernet Address</th>
+			<th class="client_id">DHCP Client ID</th>
+			<th class="status">Status</th>
+			<th class="since">Since</th>
+			<th class="lease">Lease Expires</th>
+		</tr>
+		[% FOREACH host IN hosts %]
+			<tr class="[% IF host.online %]online[% ELSE %]offline[% END %]">
+				<td class="hostname">[% host.hostname %]</td>
+				<td class="ip_addr">[% host.ip_addr %]</td>
+				<td class="ether_addr">[% host.ether_addr %]</td>
+				<td class="client_id">[% host.text_client_id %] ([% host.raw_client_id %])</td>
+				<td class="status">[% IF host.online %]Online[% ELSE %]Offline[% END %]</td>
+				<td class="since">[% host.since %]</td>
+				<td class="lease">[% host.text_lease %]</td>
+			</tr>
+		[% END %]
+		</table>
+	</body>
+</html>
diff --git a/contrib/dnsmasq_MacOSX-pre10.4/DNSmasq b/contrib/dnsmasq_MacOSX-pre10.4/DNSmasq
new file mode 100755
index 0000000..6b62118
--- /dev/null
+++ b/contrib/dnsmasq_MacOSX-pre10.4/DNSmasq
@@ -0,0 +1,22 @@
+#!/bin/sh
+. /etc/rc.common
+
+StartService() {
+  if [ "${DNSMASQ:=-NO-}" = "-YES-" ] ; then
+    /usr/local/sbin/dnsmasq -q -n
+  fi
+}
+
+StopService() {
+  pid=`GetPID dnsmasq`
+  if [ $? -eq 0 ]; then
+    kill $pid
+  fi
+}
+
+RestartService() {
+  StopService "$@"
+  StartService "$@"
+}
+
+RunService "$1"
diff --git a/contrib/dnsmasq_MacOSX-pre10.4/README.rtf b/contrib/dnsmasq_MacOSX-pre10.4/README.rtf
new file mode 100644
index 0000000..da48411
--- /dev/null
+++ b/contrib/dnsmasq_MacOSX-pre10.4/README.rtf
@@ -0,0 +1,42 @@
+{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;\f1\fnil\fcharset77 Monaco;}
+{\colortbl;\red255\green255\blue255;}
+\paperw11900\paperh16840\margl1440\margr1440\vieww11120\viewh10100\viewkind0
+\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural\pardirnatural
+
+\f0\fs24 \cf0 1. 	If you've used DNSenabler, or if you're using Mac OS X Server, or if you have in any other way activated Mac OS X's built-in DHCP and/or DNS servers, disable them.  This would usually involve checking that they are either set to -NO- or absent altogether in 
+\f1 /etc/hostconfig
+\f0 .  If you've never done anything to do with DNS or DHCP servers on a client version of MacOS X, you won't need to worry about this; it will already be configured for you.\
+\
+2.	Add a configuration item to 
+\f1 /etc/hostconfig
+\f0  as follows:\
+\
+
+\f1 DNSMASQ=-YES-
+\f0 \
+\
+3. 	Create a system-wide StartupItems directory for dnsmasq:\
+\
+
+\f1 sudo mkdir -p /Library/StartupItems/DNSmasq\
+
+\f0 \
+4.	Copy the files 
+\f1 DNSmasq
+\f0  and 
+\f1 StartupParameters.plist
+\f0  into this directory, and make sure the former is executable:\
+\
+
+\f1 sudo cp DNSmasq StartupParameters.plist /Library/StartupItems/DNSmasq\
+sudo chmod 755 /Library/StartupItems/DNSmasq/DNSmasq\
+
+\f0 \
+5.	Start the service:\
+\
+
+\f1 sudo /Library/StartupItems/DNSmasq/DNSmasq start\
+
+\f0 \cf0 \
+That should be all...}
\ No newline at end of file
diff --git a/contrib/dnsmasq_MacOSX-pre10.4/StartupParameters.plist b/contrib/dnsmasq_MacOSX-pre10.4/StartupParameters.plist
new file mode 100644
index 0000000..454bda0
--- /dev/null
+++ b/contrib/dnsmasq_MacOSX-pre10.4/StartupParameters.plist
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>Description</key>
+	<string>DNSmasq</string>
+	<key>OrderPreference</key>
+	<string>None</string>
+	<key>Provides</key>
+	<array>
+		<string>DNSmasq</string>
+	</array>
+	<key>Uses</key>
+	<array>
+		<string>Network</string>
+	</array>
+	</dict>
+</plist>
diff --git a/contrib/dnsmasq_MacOSX/DNSmasq b/contrib/dnsmasq_MacOSX/DNSmasq
new file mode 100755
index 0000000..6b62118
--- /dev/null
+++ b/contrib/dnsmasq_MacOSX/DNSmasq
@@ -0,0 +1,22 @@
+#!/bin/sh
+. /etc/rc.common
+
+StartService() {
+  if [ "${DNSMASQ:=-NO-}" = "-YES-" ] ; then
+    /usr/local/sbin/dnsmasq -q -n
+  fi
+}
+
+StopService() {
+  pid=`GetPID dnsmasq`
+  if [ $? -eq 0 ]; then
+    kill $pid
+  fi
+}
+
+RestartService() {
+  StopService "$@"
+  StartService "$@"
+}
+
+RunService "$1"
diff --git a/contrib/dnsmasq_MacOSX/README.rtf b/contrib/dnsmasq_MacOSX/README.rtf
new file mode 100755
index 0000000..da48411
--- /dev/null
+++ b/contrib/dnsmasq_MacOSX/README.rtf
@@ -0,0 +1,42 @@
+{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;\f1\fnil\fcharset77 Monaco;}
+{\colortbl;\red255\green255\blue255;}
+\paperw11900\paperh16840\margl1440\margr1440\vieww11120\viewh10100\viewkind0
+\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural\pardirnatural
+
+\f0\fs24 \cf0 1. 	If you've used DNSenabler, or if you're using Mac OS X Server, or if you have in any other way activated Mac OS X's built-in DHCP and/or DNS servers, disable them.  This would usually involve checking that they are either set to -NO- or absent altogether in 
+\f1 /etc/hostconfig
+\f0 .  If you've never done anything to do with DNS or DHCP servers on a client version of MacOS X, you won't need to worry about this; it will already be configured for you.\
+\
+2.	Add a configuration item to 
+\f1 /etc/hostconfig
+\f0  as follows:\
+\
+
+\f1 DNSMASQ=-YES-
+\f0 \
+\
+3. 	Create a system-wide StartupItems directory for dnsmasq:\
+\
+
+\f1 sudo mkdir -p /Library/StartupItems/DNSmasq\
+
+\f0 \
+4.	Copy the files 
+\f1 DNSmasq
+\f0  and 
+\f1 StartupParameters.plist
+\f0  into this directory, and make sure the former is executable:\
+\
+
+\f1 sudo cp DNSmasq StartupParameters.plist /Library/StartupItems/DNSmasq\
+sudo chmod 755 /Library/StartupItems/DNSmasq/DNSmasq\
+
+\f0 \
+5.	Start the service:\
+\
+
+\f1 sudo /Library/StartupItems/DNSmasq/DNSmasq start\
+
+\f0 \cf0 \
+That should be all...}
\ No newline at end of file
diff --git a/contrib/dnsmasq_MacOSX/StartupParameters.plist b/contrib/dnsmasq_MacOSX/StartupParameters.plist
new file mode 100755
index 0000000..454bda0
--- /dev/null
+++ b/contrib/dnsmasq_MacOSX/StartupParameters.plist
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>Description</key>
+	<string>DNSmasq</string>
+	<key>OrderPreference</key>
+	<string>None</string>
+	<key>Provides</key>
+	<array>
+		<string>DNSmasq</string>
+	</array>
+	<key>Uses</key>
+	<array>
+		<string>Network</string>
+	</array>
+	</dict>
+</plist>
diff --git a/contrib/dynamic-dnsmasq/dynamic-dnsmasq.pl b/contrib/dynamic-dnsmasq/dynamic-dnsmasq.pl
new file mode 100755
index 0000000..3c4a1f1
--- /dev/null
+++ b/contrib/dynamic-dnsmasq/dynamic-dnsmasq.pl
@@ -0,0 +1,249 @@
+#!/usr/bin/perl
+# dynamic-dnsmasq.pl - update dnsmasq's internal dns entries dynamically
+# Copyright (C) 2004  Peter Willis
+# 
+# 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; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+# 
+# the purpose of this script is to be able to update dnsmasq's dns
+# records from a remote dynamic dns client.
+# 
+# basic use of this script:
+# dynamic-dnsmasq.pl add testaccount 1234 testaccount.mydomain.com
+# dynamic-dnsmasq.pl listen &
+# 
+# this script tries to emulate DynDNS.org's dynamic dns service, so
+# technically you should be able to use any DynDNS.org client to
+# update the records here. tested and confirmed to work with ddnsu
+# 1.3.1. just point the client's host to the IP of this machine,
+# port 9020, and include the hostname, user and pass, and it should
+# work.
+# 
+# make sure "addn-hosts=/etc/dyndns-hosts" is in your /etc/dnsmasq.conf
+# file and "nopoll" is commented out.
+
+use strict;
+use IO::Socket;
+use MIME::Base64;
+use DB_File;
+use Fcntl;
+
+my $accountdb = "accounts.db";
+my $recordfile = "/etc/dyndns-hosts";
+my $dnsmasqpidfile = "/var/run/dnsmasq.pid"; # if this doesn't exist, will look for process in /proc
+my $listenaddress = "0.0.0.0";
+my $listenport = 9020;
+
+# no editing past this point should be necessary
+
+if ( @ARGV < 1 ) {
+	die "Usage: $0 ADD|DEL|LISTUSERS|WRITEHOSTSFILE|LISTEN\n";
+} elsif ( lc $ARGV[0] eq "add" ) {
+	die "Usage: $0 ADD USER PASS HOSTNAME\n" unless @ARGV == 4;
+	add_acct($ARGV[1], $ARGV[2], $ARGV[3]);
+} elsif ( lc $ARGV[0] eq "del" ) {
+	die "Usage: $0 DEL USER\n" unless @ARGV == 2;
+	print "Are you sure you want to delete user \"$ARGV[1]\"? [N/y] ";
+	my $resp = <STDIN>;
+	chomp $resp;
+	if ( lc substr($resp,0,1) eq "y" ) {
+		del_acct($ARGV[1]);
+	}
+} elsif ( lc $ARGV[0] eq "listusers" or lc $ARGV[0] eq "writehostsfile" ) {
+	my $X = tie my %h, "DB_File", $accountdb, O_RDWR|O_CREAT, 0600, $DB_HASH;
+	my $fh;
+	if ( lc $ARGV[0] eq "writehostsfile" ) {
+        	open($fh, ">$recordfile") || die "Couldn't open recordfile \"$recordfile\": $!\n";
+	       	flock($fh, 2);
+	       	seek($fh, 0, 0);
+	       	truncate($fh, 0);
+        }
+	while ( my ($key, $val) = each %h ) {
+		my ($pass, $domain, $ip) = split("\t",$val);
+		if ( lc $ARGV[0] eq "listusers" ) {
+			print "user $key, hostname $domain, ip $ip\n";
+		} else {
+			if ( defined $ip ) {
+				print $fh "$ip\t$domain\n";
+			}
+		}
+	}
+	if ( lc $ARGV[0] eq "writehostsfile" ) {
+		flock($fh, 8);
+		close($fh);
+		dnsmasq_rescan_configs();
+	}
+	undef $X;
+	untie %h;
+} elsif ( lc $ARGV[0] eq "listen" ) {
+	listen_for_updates();
+}
+
+sub listen_for_updates {
+	my $sock = IO::Socket::INET->new(Listen    => 5,
+		LocalAddr => $listenaddress, LocalPort => $listenport,
+		Proto     => 'tcp', ReuseAddr => 1,
+		MultiHomed => 1) || die "Could not open listening socket: $!\n";
+	$SIG{'CHLD'} = 'IGNORE';
+	while ( my $client = $sock->accept() ) {
+		my $p = fork();
+		if ( $p != 0 ) {
+			next;
+		}
+		$SIG{'CHLD'} = 'DEFAULT';
+		my @headers;
+		my %cgi;
+		while ( <$client> ) {
+			s/(\r|\n)//g;
+			last if $_ eq "";
+			push @headers, $_;
+		}
+		foreach my $header (@headers) {
+			if ( $header =~ /^GET \/nic\/update\?([^\s].+) HTTP\/1\.[01]$/ ) {
+				foreach my $element (split('&', $1)) {
+					$cgi{(split '=', $element)[0]} = (split '=', $element)[1];
+				}
+			} elsif ( $header =~ /^Authorization: basic (.+)$/ ) {
+				unless ( defined $cgi{'hostname'} ) {
+					print_http_response($client, undef, "badsys");
+					exit(1);
+				}
+				if ( !exists $cgi{'myip'} ) {
+					$cgi{'myip'} = $client->peerhost();
+				}
+				my ($user,$pass) = split ":", MIME::Base64::decode($1);
+				if ( authorize($user, $pass, $cgi{'hostname'}, $cgi{'myip'}) == 0 ) {
+					print_http_response($client, $cgi{'myip'}, "good");
+					update_dns(\%cgi);
+				} else {
+					print_http_response($client, undef, "badauth");
+					exit(1);
+				}
+				last;
+			}
+		}
+		exit(0);
+	}
+	return(0);
+}
+
+sub add_acct {
+	my ($user, $pass, $hostname) = @_;
+	my $X = tie my %h, "DB_File", $accountdb, O_RDWR|O_CREAT, 0600, $DB_HASH;
+	$X->put($user, join("\t", ($pass, $hostname)));
+	undef $X;
+	untie %h;
+}
+
+sub del_acct {
+        my ($user, $pass, $hostname) = @_;
+        my $X = tie my %h, "DB_File", $accountdb, O_RDWR|O_CREAT, 0600, $DB_HASH;
+        $X->del($user);
+        undef $X;
+        untie %h;
+}
+
+
+sub authorize {
+	my $user = shift;
+	my $pass = shift;
+	my $hostname = shift;
+	my $ip = shift;;
+	my $X = tie my %h, "DB_File", $accountdb, O_RDWR|O_CREAT, 0600, $DB_HASH;
+	my ($spass, $shost) = split("\t", $h{$user});
+	if ( defined $h{$user} and ($spass eq $pass) and ($shost eq $hostname) ) {
+		$X->put($user, join("\t", $spass, $shost, $ip));
+		undef $X;
+		untie %h;
+		return(0);
+	}
+	undef $X;
+	untie %h;
+	return(1);
+}
+
+sub print_http_response {
+	my $sock = shift;
+	my $ip = shift;
+	my $response = shift;
+	print $sock "HTTP/1.0 200 OK\n";
+	my @tmp = split /\s+/, scalar gmtime();
+	print $sock "Date: $tmp[0], $tmp[2] $tmp[1] $tmp[4] $tmp[3] GMT\n";
+	print $sock "Server: Peter's Fake DynDNS.org Server/1.0\n";
+	print $sock "Content-Type: text/plain; charset=ISO-8859-1\n";
+	print $sock "Connection: close\n";
+	print $sock "Transfer-Encoding: chunked\n";
+	print $sock "\n";
+	#print $sock "12\n"; # this was part of the dyndns response but i'm not sure what it is
+	print $sock "$response", defined($ip)? " $ip" : "" . "\n";
+}
+
+sub update_dns {
+	my $hashref = shift;
+	my @records;
+	my $found = 0;
+	# update the addn-hosts file
+	open(FILE, "+<$recordfile") || die "Couldn't open recordfile \"$recordfile\": $!\n";
+	flock(FILE, 2);
+	while ( <FILE> ) {
+		if ( /^(\d+\.\d+\.\d+\.\d+)\s+$$hashref{'hostname'}\n$/si ) {
+			if ( $1 ne $$hashref{'myip'} ) {
+				push @records, "$$hashref{'myip'}\t$$hashref{'hostname'}\n";
+				$found = 1;
+			}
+		} else {
+			push @records, $_;
+		}
+	}
+	unless ( $found ) {
+		push @records, "$$hashref{'myip'}\t$$hashref{'hostname'}\n";
+	}
+	sysseek(FILE, 0, 0);
+	truncate(FILE, 0);
+	syswrite(FILE, join("", @records));
+	flock(FILE, 8);
+	close(FILE);
+	dnsmasq_rescan_configs();
+	return(0);
+}
+
+sub dnsmasq_rescan_configs {
+	# send the HUP signal to dnsmasq
+	if ( -r $dnsmasqpidfile ) {
+		open(PID,"<$dnsmasqpidfile") || die "Could not open PID file \"$dnsmasqpidfile\": $!\n";
+		my $pid = <PID>;
+		close(PID);
+		chomp $pid;
+		if ( kill(0, $pid) ) {
+			kill(1, $pid);
+		} else {
+			goto LOOKFORDNSMASQ;
+		}
+	} else {
+		LOOKFORDNSMASQ:
+		opendir(DIR,"/proc") || die "Couldn't opendir /proc: $!\n";
+		my @dirs = grep(/^\d+$/, readdir(DIR));
+		closedir(DIR);
+		foreach my $process (@dirs) {
+			if ( open(FILE,"</proc/$process/cmdline") ) {
+				my $cmdline = <FILE>;
+				close(FILE);
+				if ( (split(/\0/,$cmdline))[0] =~ /dnsmasq/ ) {
+					kill(1, $process);
+				}
+			}
+		}
+	}
+	return(0);
+}
diff --git a/contrib/lease-access/README b/contrib/lease-access/README
new file mode 100755
index 0000000..fc66bdf
--- /dev/null
+++ b/contrib/lease-access/README
@@ -0,0 +1,20 @@
+Hello,
+
+For some specific application I needed to deny access to a MAC address
+to a lease. For this reason I modified the dhcp-script behavior and is
+called with an extra parameter "access" once a dhcp request or discover
+is received. In that case if the exit code of the script is zero,
+dnsmasq continues normally, and if non-zero the packet is ignored.
+
+This was not added as a security feature but as a mean to handle
+differently some addresses. It is also quite intrusive since it requires
+changes in several other subsystems.
+
+It attach the patch in case someone is interested.
+
+regards,
+Nikos
+
+nmav@gennetsa.com
+
+
diff --git a/contrib/lease-access/lease.access.patch b/contrib/lease-access/lease.access.patch
new file mode 100755
index 0000000..911ee7e
--- /dev/null
+++ b/contrib/lease-access/lease.access.patch
@@ -0,0 +1,578 @@
+Index: src/dnsmasq.c
+===================================================================
+--- src/dnsmasq.c	(revision 696)
++++ src/dnsmasq.c	(revision 821)
+@@ -59,7 +59,6 @@
+ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
+ static void check_dns_listeners(fd_set *set, time_t now);
+ static void sig_handler(int sig);
+-static void async_event(int pipe, time_t now);
+ static void fatal_event(struct event_desc *ev);
+ static void poll_resolv(void);
+ 
+@@ -275,7 +274,7 @@
+   piperead = pipefd[0];
+   pipewrite = pipefd[1];
+   /* prime the pipe to load stuff first time. */
+-  send_event(pipewrite, EVENT_RELOAD, 0); 
++  send_event(pipewrite, EVENT_RELOAD, 0, 0); 
+ 
+   err_pipe[1] = -1;
+   
+@@ -340,7 +339,7 @@
+ 	    }
+ 	  else if (getuid() == 0)
+ 	    {
+-	      send_event(err_pipe[1], EVENT_PIDFILE, errno);
++	      send_event(err_pipe[1], EVENT_PIDFILE, errno, 0);
+ 	      _exit(0);
+ 	    }
+ 	}
+@@ -372,7 +371,7 @@
+ 	  (setgroups(0, &dummy) == -1 ||
+ 	   setgid(gp->gr_gid) == -1))
+ 	{
+-	  send_event(err_pipe[1], EVENT_GROUP_ERR, errno);
++	  send_event(err_pipe[1], EVENT_GROUP_ERR, errno, 0);
+ 	  _exit(0);
+ 	}
+   
+@@ -415,14 +414,14 @@
+ 
+ 	  if (bad_capabilities != 0)
+ 	    {
+-	      send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities);
++	      send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, 0);
+ 	      _exit(0);
+ 	    }
+ 	  
+ 	  /* finally drop root */
+ 	  if (setuid(ent_pw->pw_uid) == -1)
+ 	    {
+-	      send_event(err_pipe[1], EVENT_USER_ERR, errno);
++	      send_event(err_pipe[1], EVENT_USER_ERR, errno, 0);
+ 	      _exit(0);
+ 	    }     
+ 
+@@ -434,7 +433,7 @@
+ 	  /* lose the setuid and setgid capabilities */
+ 	  if (capset(hdr, data) == -1)
+ 	    {
+-	      send_event(err_pipe[1], EVENT_CAP_ERR, errno);
++	      send_event(err_pipe[1], EVENT_CAP_ERR, errno, 0);
+ 	      _exit(0);
+ 	    }
+ #endif
+@@ -647,7 +646,7 @@
+ 	}
+       
+       if (FD_ISSET(piperead, &rset))
+-	async_event(piperead, now);
++	async_event(piperead, now, NULL, 0);
+       
+ #ifdef HAVE_LINUX_NETWORK
+       if (FD_ISSET(daemon->netlinkfd, &rset))
+@@ -674,7 +673,7 @@
+ #endif      
+ 
+       if (daemon->dhcp && FD_ISSET(daemon->dhcpfd, &rset))
+-	dhcp_packet(now);
++	dhcp_packet(piperead, now);
+ 
+ #ifndef NO_FORK
+       if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
+@@ -719,17 +718,18 @@
+       else
+ 	return;
+ 
+-      send_event(pipewrite, event, 0); 
++      send_event(pipewrite, event, 0, 0); 
+       errno = errsave;
+     }
+ }
+ 
+-void send_event(int fd, int event, int data)
++void send_event(int fd, int event, int data, int priv)
+ {
+   struct event_desc ev;
+   
+   ev.event = event;
+   ev.data = data;
++  ev.priv = priv;
+   
+   /* error pipe, debug mode. */
+   if (fd == -1)
+@@ -771,14 +771,17 @@
+       die(_("cannot open %s: %s"), daemon->log_file ? daemon->log_file : "log", EC_FILE);
+     }
+ }	
+-      
+-static void async_event(int pipe, time_t now)
++
++/* returns the private data of the event
++ */
++int async_event(int pipe, time_t now, struct event_desc* event, unsigned int secs)
+ {
+   pid_t p;
+   struct event_desc ev;
+   int i;
+ 
+-  if (read_write(pipe, (unsigned char *)&ev, sizeof(ev), 1))
++  if (read_timeout(pipe, (unsigned char *)&ev, sizeof(ev), now, secs) > 0) 
++    {
+     switch (ev.event)
+       {
+       case EVENT_RELOAD:
+@@ -872,6 +875,14 @@
+ 	flush_log();
+ 	exit(EC_GOOD);
+       }
++    }
++  else
++    return -1; /* timeout */
++
++  if (event)
++    memcpy( event, &ev, sizeof(ev));
++    
++  return 0;
+ }
+ 
+ static void poll_resolv()
+Index: src/config.h
+===================================================================
+--- src/config.h	(revision 696)
++++ src/config.h	(revision 821)
+@@ -51,6 +51,8 @@
+ #define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
+ #define LOG_MAX 5 /* log-queue length */
+ #define RANDFILE "/dev/urandom"
++#define SCRIPT_TIMEOUT 6
++#define LEASE_CHECK_TIMEOUT 10
+ 
+ /* DBUS interface specifics */
+ #define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"
+Index: src/dnsmasq.h
+===================================================================
+--- src/dnsmasq.h	(revision 696)
++++ src/dnsmasq.h	(revision 821)
+@@ -116,6 +116,7 @@
+ /* Async event queue */
+ struct event_desc {
+   int event, data;
++  unsigned int priv;
+ };
+ 
+ #define EVENT_RELOAD    1
+@@ -390,6 +391,7 @@
+ #define ACTION_OLD_HOSTNAME  2
+ #define ACTION_OLD           3
+ #define ACTION_ADD           4
++#define ACTION_ACCESS        5
+ 
+ #define DHCP_CHADDR_MAX 16
+ 
+@@ -709,6 +711,7 @@
+ char *print_mac(char *buff, unsigned char *mac, int len);
+ void bump_maxfd(int fd, int *max);
+ int read_write(int fd, unsigned char *packet, int size, int rw);
++int read_timeout(int fd, unsigned char *packet, int size, time_t now, int secs);
+ 
+ /* log.c */
+ void die(char *message, char *arg1, int exit_code);
+@@ -748,7 +751,7 @@
+ 
+ /* dhcp.c */
+ void dhcp_init(void);
+-void dhcp_packet(time_t now);
++void dhcp_packet(int piperead, time_t now);
+ 
+ struct dhcp_context *address_available(struct dhcp_context *context, 
+ 				       struct in_addr addr,
+@@ -792,14 +795,16 @@
+ void rerun_scripts(void);
+ 
+ /* rfc2131.c */
+-size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
++size_t dhcp_reply(int pipefd, struct dhcp_context *context, char *iface_name, int int_index,
+ 		  size_t sz, time_t now, int unicast_dest, int *is_inform);
+ 
+ /* dnsmasq.c */
+ int make_icmp_sock(void);
+ int icmp_ping(struct in_addr addr);
+-void send_event(int fd, int event, int data);
++void send_event(int fd, int event, int data, int priv);
+ void clear_cache_and_reload(time_t now);
++int wait_for_child(int pipe);
++int async_event(int pipe, time_t now, struct event_desc*, unsigned int timeout);
+ 
+ /* isc.c */
+ #ifdef HAVE_ISC_READER
+@@ -832,9 +837,9 @@
+ /* helper.c */
+ #ifndef NO_FORK
+ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd);
+-void helper_write(void);
++int helper_write(void);
+ void queue_script(int action, struct dhcp_lease *lease, 
+-		  char *hostname, time_t now);
++		  char *hostname, time_t now, unsigned int uid);
+ int helper_buf_empty(void);
+ #endif
+ 
+Index: src/util.c
+===================================================================
+--- src/util.c	(revision 696)
++++ src/util.c	(revision 821)
+@@ -444,3 +444,38 @@
+   return 1;
+ }
+ 
++int read_timeout(int fd, unsigned char *packet, int size, time_t now, int secs)
++{
++  ssize_t n, done;
++  time_t expire;
++  
++  expire = now + secs;
++  
++  for (done = 0; done < size; done += n)
++    {
++    retry:
++      if (secs > 0) alarm(secs);
++      n = read(fd, &packet[done], (size_t)(size - done));
++
++      if (n == 0)
++        return 0;
++      else if (n == -1)
++        {
++          if (errno == EINTR) {
++            my_syslog(LOG_INFO, _("read timed out (errno %d)"), errno);
++            return 0;
++          }
++
++          if (retry_send() || errno == ENOMEM || errno == ENOBUFS || errno == EAGAIN)
++            {
++              if (secs == 0 || (secs > 0 && dnsmasq_time() < expire))
++                goto retry;
++            }
++
++          my_syslog(LOG_INFO, _("error in read (timeout %d, errno %d)"), secs, errno);
++          return 0;
++        }
++    }
++  return 1;
++}
++
+Index: src/dhcp.c
+===================================================================
+--- src/dhcp.c	(revision 696)
++++ src/dhcp.c	(revision 821)
+@@ -103,7 +103,7 @@
+   daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
+ }
+   
+-void dhcp_packet(time_t now)
++void dhcp_packet(int piperead, time_t now)
+ {
+   struct dhcp_packet *mess;
+   struct dhcp_context *context;
+@@ -239,7 +239,8 @@
+   if (!iface_enumerate(&parm, complete_context, NULL))
+     return;
+   lease_prune(NULL, now); /* lose any expired leases */
+-  iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz, 
++
++  iov.iov_len = dhcp_reply(piperead, parm.current, ifr.ifr_name, iface_index, (size_t)sz, 
+ 			   now, unicast_dest, &is_inform);
+   lease_update_file(now);
+   lease_update_dns();
+Index: src/helper.c
+===================================================================
+--- src/helper.c	(revision 696)
++++ src/helper.c	(revision 821)
+@@ -45,6 +45,7 @@
+ #endif
+   unsigned char hwaddr[DHCP_CHADDR_MAX];
+   char interface[IF_NAMESIZE];
++  unsigned int uid;
+ };
+ 
+ static struct script_data *buf = NULL;
+@@ -60,7 +61,7 @@
+      then fork our process. */
+   if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
+     {
+-      send_event(err_fd, EVENT_PIPE_ERR, errno);
++      send_event(err_fd, EVENT_PIPE_ERR, errno, 0);
+       _exit(0);
+     }
+ 
+@@ -87,13 +88,13 @@
+ 	{
+ 	  if (daemon->options & OPT_NO_FORK)
+ 	    /* send error to daemon process if no-fork */
+-	    send_event(event_fd, EVENT_HUSER_ERR, errno);
++	    send_event(event_fd, EVENT_HUSER_ERR, errno, 0);
+ 	  else
+ 	    {
+ 	      /* kill daemon */
+-	      send_event(event_fd, EVENT_DIE, 0);
++	      send_event(event_fd, EVENT_DIE, 0, 0);
+ 	      /* return error */
+-	      send_event(err_fd, EVENT_HUSER_ERR, errno);;
++	      send_event(err_fd, EVENT_HUSER_ERR, errno, 0);
+ 	    }
+ 	  _exit(0);
+ 	}
+@@ -122,6 +123,8 @@
+ 	action_str = "del";
+       else if (data.action == ACTION_ADD)
+ 	action_str = "add";
++      else if (data.action == ACTION_ACCESS)
++	action_str = "access";
+       else if (data.action == ACTION_OLD || data.action == ACTION_OLD_HOSTNAME)
+ 	action_str = "old";
+       else
+@@ -178,9 +181,11 @@
+ 		{
+ 		  /* On error send event back to main process for logging */
+ 		  if (WIFSIGNALED(status))
+-		    send_event(event_fd, EVENT_KILLED, WTERMSIG(status));
+-		  else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
+-		    send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status));
++		    send_event(event_fd, EVENT_KILLED, WTERMSIG(status), data.uid);
++		  else if (WIFEXITED(status))
++		    send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status), data.uid);
++                  else
++		    send_event(event_fd, EVENT_EXITED, -1, data.uid);
+ 		  break;
+ 		}
+ 	      
+@@ -263,7 +268,7 @@
+ 	  err = errno;
+ 	}
+       /* failed, send event so the main process logs the problem */
+-      send_event(event_fd, EVENT_EXEC_ERR, err);
++      send_event(event_fd, EVENT_EXEC_ERR, err, data.uid);
+       _exit(0); 
+     }
+ }
+@@ -295,7 +300,7 @@
+ }
+  
+ /* pack up lease data into a buffer */    
+-void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
++void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now, unsigned int uid)
+ {
+   unsigned char *p;
+   size_t size;
+@@ -332,6 +337,7 @@
+       buf_size = size;
+     }
+ 
++  buf->uid = uid;
+   buf->action = action;
+   buf->hwaddr_len = lease->hwaddr_len;
+   buf->hwaddr_type = lease->hwaddr_type;
+@@ -393,12 +399,15 @@
+   return bytes_in_buf == 0;
+ }
+ 
+-void helper_write(void)
++/* returns -1 if write failed for a reason, 1 if no data exist
++ * and 0 if everything was ok.
++ */
++int helper_write(void)
+ {
+   ssize_t rc;
+ 
+   if (bytes_in_buf == 0)
+-    return;
++    return 1;
+   
+   if ((rc = write(daemon->helperfd, buf, bytes_in_buf)) != -1)
+     {
+@@ -409,9 +418,11 @@
+   else
+     {
+       if (errno == EAGAIN || errno == EINTR)
+-	return;
++	return -1;
+       bytes_in_buf = 0;
+     }
++    
++  return 0;
+ }
+ 
+ #endif
+Index: src/rfc2131.c
+===================================================================
+--- src/rfc2131.c	(revision 696)
++++ src/rfc2131.c	(revision 821)
+@@ -100,8 +100,49 @@
+ 				      int clid_len, unsigned char *clid, int *len_out);
+ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt); 
+ 
++static int check_access_script( int piperead, struct dhcp_lease *lease, struct dhcp_packet *mess, time_t now)
++{
++#ifndef NO_FORK
++unsigned int uid;
++struct event_desc ev;
++int ret;
++struct dhcp_lease _lease;
++
++  if (daemon->lease_change_command == NULL) return 0; /* ok */
++
++  if (!lease) { /* if host has not been seen before lease is NULL */
++      memset(&_lease, 0, sizeof(_lease));
++      lease = &_lease;
++      lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0);
++  }
++
++  uid = rand16();
++  queue_script(ACTION_ACCESS, lease, NULL, now, uid);
++
++  /* send all data to helper process */
++  do 
++    {
++      helper_write();
++    } while (helper_buf_empty() == 0);
++
++  /* wait for our event */
++  ret = 0;
++  do 
++    {
++      ret = async_event( piperead, now, &ev, SCRIPT_TIMEOUT);
++    }
++  while(ev.priv != uid && ret >= 0);
++
++  if (ret < 0 || ev.data != 0) /* timeout or error */
++    {
++      return -1;
++    }
++
++#endif
++  return 0; /* ok */
++}
+ 	  
+-size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
++size_t dhcp_reply(int piperead, struct dhcp_context *context, char *iface_name, int int_index,
+ 		  size_t sz, time_t now, int unicast_dest, int *is_inform)
+ {
+   unsigned char *opt, *clid = NULL;
+@@ -252,7 +293,7 @@
+ 	mac->netid.next = netid;
+ 	netid = &mac->netid;
+       }
+-  
++
+   /* Determine network for this packet. Our caller will have already linked all the 
+      contexts which match the addresses of the receiving interface but if the 
+      machine has an address already, or came via a relay, or we have a subnet selector, 
+@@ -329,7 +370,7 @@
+ 	    my_syslog(LOG_INFO, _("Available DHCP range: %s -- %s"), daemon->namebuff, inet_ntoa(context_tmp->end));
+ 	}
+     }
+-
++    
+   mess->op = BOOTREPLY;
+   
+   config = find_config(daemon->dhcp_conf, context, clid, clid_len, 
+@@ -418,7 +459,7 @@
+ 	      else
+ 		mess->yiaddr = lease->addr;
+ 	    }
+-	  
++
+ 	  if (!message && 
+ 	      !lease && 
+ 	      (!(lease = lease_allocate(mess->yiaddr))))
+@@ -641,7 +682,14 @@
+       memcpy(req_options, option_ptr(opt, 0), option_len(opt));
+       req_options[option_len(opt)] = OPTION_END;
+     }
+-  
++
++  if (mess_type == DHCPREQUEST || mess_type == DHCPDISCOVER)
++    if (check_access_script(piperead, lease, mess, now) < 0)
++      {
++        my_syslog(LOG_INFO, _("Ignoring client due to access script"));
++        return 0;
++      }
++
+   switch (mess_type)
+     {
+     case DHCPDECLINE:
+Index: src/log.c
+===================================================================
+--- src/log.c	(revision 696)
++++ src/log.c	(revision 821)
+@@ -73,7 +73,7 @@
+ 
+   if (!log_reopen(daemon->log_file))
+     {
+-      send_event(errfd, EVENT_LOG_ERR, errno);
++      send_event(errfd, EVENT_LOG_ERR, errno, 0);
+       _exit(0);
+     }
+ 
+Index: src/lease.c
+===================================================================
+--- src/lease.c	(revision 696)
++++ src/lease.c	(revision 821)
+@@ -511,7 +511,7 @@
+       if (lease->old_hostname)
+ 	{
+ #ifndef NO_FORK
+-	  queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
++	  queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now, 0);
+ #endif
+ 	  free(lease->old_hostname);
+ 	  lease->old_hostname = NULL;
+@@ -520,7 +520,7 @@
+       else 
+ 	{
+ #ifndef NO_FORK
+-	  queue_script(ACTION_DEL, lease, lease->hostname, now);
++	  queue_script(ACTION_DEL, lease, lease->hostname, now, 0);
+ #endif
+ 	  old_leases = lease->next;
+ 	  
+@@ -540,7 +540,7 @@
+     if (lease->old_hostname)
+       {	
+ #ifndef NO_FORK
+-	queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
++	queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now, 0);
+ #endif
+ 	free(lease->old_hostname);
+ 	lease->old_hostname = NULL;
+@@ -552,7 +552,7 @@
+ 	(lease->aux_changed && (daemon->options & OPT_LEASE_RO)))
+       {
+ #ifndef NO_FORK
+-	queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease, lease->hostname, now);
++	queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease, lease->hostname, now, 0);
+ #endif
+ 	lease->new = lease->changed = lease->aux_changed = 0;
+ 	
+Index: man/dnsmasq.8
+===================================================================
+--- man/dnsmasq.8	(revision 696)
++++ man/dnsmasq.8	(revision 821)
+@@ -724,12 +724,15 @@
+ .B \-6 --dhcp-script=<path>
+ Whenever a new DHCP lease is created, or an old one destroyed, the
+ binary specified by this option is run. The arguments to the process
+-are "add", "old" or "del", the MAC
++are "add", "old", "access" or "del", the MAC
+ address of the host (or "<null>"), the IP address, and the hostname,
+ if known. "add" means a lease has been created, "del" means it has
+ been destroyed, "old" is a notification of an existing lease when
+ dnsmasq starts or a change to MAC address or hostname of an existing
+ lease (also, lease length or expiry and client-id, if leasefile-ro is set).
++The "access" keyword means that a request was just received and depending
++on the script exit status request for address will be granted, if exit status
++is zero or not if it is non-zero.
+ The process is run as root (assuming that dnsmasq was originally run as
+ root) even if dnsmasq is configured to change UID to an unprivileged user.
+ The environment is inherited from the invoker of dnsmasq, and if the
diff --git a/contrib/lease-tools/Makefile b/contrib/lease-tools/Makefile
new file mode 100644
index 0000000..f38f2ed
--- /dev/null
+++ b/contrib/lease-tools/Makefile
@@ -0,0 +1,6 @@
+CFLAGS?= -O2 -Wall -W
+
+all: dhcp_release dhcp_release6 dhcp_lease_time
+
+clean:
+	rm -f *~ *.o core dhcp_release dhcp_release6 dhcp_lease_time
diff --git a/contrib/lease-tools/dhcp_lease_time.1 b/contrib/lease-tools/dhcp_lease_time.1
new file mode 100644
index 0000000..2fa78d3
--- /dev/null
+++ b/contrib/lease-tools/dhcp_lease_time.1
@@ -0,0 +1,25 @@
+.TH DHCP_LEASE_TIME 1
+.SH NAME
+dhcp_lease_time \- Query remaining time of a lease on a the local dnsmasq DHCP server.
+.SH SYNOPSIS
+.B  dhcp_lease_time <address>
+.SH "DESCRIPTION"
+Send a DHCPINFORM message to a dnsmasq server running on the local host
+and print (to stdout) the time remaining in any lease for the given
+address. The time is given as string printed to stdout.
+
+If an error occurs or no lease exists for the given address, 
+nothing is sent to stdout a message is sent to stderr and a
+non-zero error code is returned.
+
+Requires dnsmasq 2.67 or later and may not work with other DHCP servers.
+
+The address argument is a dotted-quad IP addresses and mandatory.
+.SH LIMITATIONS
+Only works with IPv4 addresses and DHCP leases. 
+.SH SEE ALSO
+.BR dnsmasq (8)
+.SH AUTHOR
+This manual page was written by Simon Kelley <simon@thekelleys.org.uk>.
+
+
diff --git a/contrib/lease-tools/dhcp_lease_time.c b/contrib/lease-tools/dhcp_lease_time.c
new file mode 100644
index 0000000..f9d7a85
--- /dev/null
+++ b/contrib/lease-tools/dhcp_lease_time.c
@@ -0,0 +1,221 @@
+/* Copyright (c) 2007 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.
+*/
+
+/* dhcp_lease_time <address> */
+
+/* Send a DHCPINFORM message to a dnsmasq server running on the local host
+   and print (to stdout) the time remaining in any lease for the given
+   address. The time is given as string printed to stdout.
+
+   If an error occurs or no lease exists for the given address, 
+   nothing is sent to stdout a message is sent to stderr and a
+   non-zero error code is returned.
+
+   This version requires dnsmasq 2.67 or later. 
+*/
+
+#include <sys/types.h> 
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <net/if_arp.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <errno.h>
+
+#define DHCP_CHADDR_MAX          16
+#define BOOTREQUEST              1
+#define DHCP_COOKIE              0x63825363
+#define OPTION_PAD               0
+#define OPTION_LEASE_TIME        51
+#define OPTION_OVERLOAD          52
+#define OPTION_MESSAGE_TYPE      53
+#define OPTION_REQUESTED_OPTIONS 55
+#define OPTION_END               255
+#define DHCPINFORM               8
+#define DHCP_SERVER_PORT         67
+
+#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
+#define option_ptr(opt) ((void *)&(((unsigned char *)(opt))[2]))
+
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+struct dhcp_packet {
+  u8 op, htype, hlen, hops;
+  u32 xid;
+  u16 secs, flags;
+  struct in_addr ciaddr, yiaddr, siaddr, giaddr;
+  u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
+  u32 cookie;
+  unsigned char options[308];
+};
+
+static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize)
+{
+  while (*p != OPTION_END) 
+    {
+      if (p >= end)
+        return NULL; /* malformed packet */
+      else if (*p == OPTION_PAD)
+        p++;
+      else 
+        { 
+          int opt_len;
+          if (p >= end - 2)
+            return NULL; /* malformed packet */
+          opt_len = option_len(p);
+          if (p >= end - (2 + opt_len))
+            return NULL; /* malformed packet */
+          if (*p == opt && opt_len >= minsize)
+            return p;
+          p += opt_len + 2;
+        }
+    }
+  
+  return opt == OPTION_END ? p : NULL;
+}
+ 
+static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize)
+{
+  unsigned char *ret, *overload;
+  
+  /* skip over DHCP cookie; */
+  if ((ret = option_find1(&mess->options[0], ((unsigned char *)mess) + size, opt_type, minsize)))
+    return ret;
+
+  /* look for overload option. */
+  if (!(overload = option_find1(&mess->options[0], ((unsigned char *)mess) + size, OPTION_OVERLOAD, 1)))
+    return NULL;
+  
+  /* Can we look in filename area ? */
+  if ((overload[2] & 1) &&
+      (ret = option_find1(&mess->file[0], &mess->file[128], opt_type, minsize)))
+    return ret;
+
+  /* finally try sname area */
+  if ((overload[2] & 2) &&
+      (ret = option_find1(&mess->sname[0], &mess->sname[64], opt_type, minsize)))
+    return ret;
+
+  return NULL;
+}
+
+static unsigned int option_uint(unsigned char *opt, int size)
+{
+  /* this worries about unaligned data and byte order */
+  unsigned int ret = 0;
+  int i;
+  unsigned char *p = option_ptr(opt);
+  
+  for (i = 0; i < size; i++)
+    ret = (ret << 8) | *p++;
+
+  return ret;
+}
+
+int main(int argc, char **argv)
+{ 
+  struct in_addr lease;
+  struct dhcp_packet packet;
+  unsigned char *p = packet.options;
+  struct sockaddr_in dest;
+  int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+  ssize_t rc;
+  
+  if (argc < 2)
+    { 
+      fprintf(stderr, "usage: dhcp_lease_time <address>\n");
+      exit(1);
+    }
+
+  if (fd == -1)
+    {
+      perror("cannot create socket");
+      exit(1);
+    }
+ 
+  lease.s_addr = inet_addr(argv[1]);
+   
+  memset(&packet, 0, sizeof(packet));
+ 
+  packet.hlen = 0;
+  packet.htype = 0;
+
+  packet.op = BOOTREQUEST;
+  packet.ciaddr = lease;
+  packet.cookie = htonl(DHCP_COOKIE);
+
+  *(p++) = OPTION_MESSAGE_TYPE;
+  *(p++) = 1;
+  *(p++) = DHCPINFORM;
+
+  /* Explicitly request the lease time, it won't be sent otherwise:
+     this is a dnsmasq extension, not standard. */
+  *(p++) = OPTION_REQUESTED_OPTIONS;
+  *(p++) = 1;
+  *(p++) = OPTION_LEASE_TIME;
+  
+  *(p++) = OPTION_END;
+ 
+  dest.sin_family = AF_INET; 
+  dest.sin_addr.s_addr = inet_addr("127.0.0.1");
+  dest.sin_port = ntohs(DHCP_SERVER_PORT);
+  
+  if (sendto(fd, &packet, sizeof(packet), 0, 
+	     (struct sockaddr *)&dest, sizeof(dest)) == -1)
+    {
+      perror("sendto failed");
+      exit(1);
+    }
+
+  alarm(3); /* noddy timeout. */
+
+  rc = recv(fd, &packet, sizeof(packet), 0);
+  
+  if (rc < (ssize_t)(sizeof(packet) - sizeof(packet.options)))
+    {
+      perror("recv failed");
+      exit(1);
+    }
+
+  if ((p = option_find(&packet, (size_t)rc, OPTION_LEASE_TIME, 4)))
+    {
+      unsigned int t = option_uint(p, 4);
+      if (t == 0xffffffff)
+	printf("infinite");
+      else
+	{
+	  unsigned int x;
+	  if ((x = t/86400))
+	    printf("%ud", x);
+	  if ((x = (t/3600)%24))
+	    printf("%uh", x);
+	  if ((x = (t/60)%60))
+	    printf("%um", x);
+	  if ((x = t%60))
+	    printf("%us", x);
+	}
+      return 0;
+    }
+
+  return 1; /* no lease */
+}
diff --git a/contrib/lease-tools/dhcp_release.1 b/contrib/lease-tools/dhcp_release.1
new file mode 100644
index 0000000..e71aba0
--- /dev/null
+++ b/contrib/lease-tools/dhcp_release.1
@@ -0,0 +1,37 @@
+.TH DHCP_RELEASE 1
+.SH NAME
+dhcp_release \- Release a DHCP lease on a the local dnsmasq DHCP server.
+.SH SYNOPSIS
+.B dhcp_release <interface> <address> <MAC address> <client_id>
+.SH "DESCRIPTION"
+A utility which forces the DHCP server running on this machine to release a 
+DHCP lease.
+.PP
+Send a DHCPRELEASE message via the specified interface to tell the
+local DHCP server to delete a particular lease. 
+
+The interface argument is the interface in which a DHCP
+request _would_ be received if it was coming from the client, 
+rather than being faked up here.
+   
+The address argument is a dotted-quad IP addresses and mandatory. 
+   
+The MAC address is colon separated hex, and is mandatory. It may be 
+prefixed by an address-type byte followed by -, eg
+
+10-11:22:33:44:55:66
+
+but if the address-type byte is missing it is assumed to be 1, the type 
+for ethernet. This encoding is the one used in dnsmasq lease files.
+
+The client-id is optional. If it is "*" then it treated as being missing.
+.SH NOTES
+MUST be run as root - will fail otherwise.
+.SH LIMITATIONS
+Only usable on IPv4 DHCP leases.
+.SH SEE ALSO
+.BR dnsmasq (8)
+.SH AUTHOR
+This manual page was written by Simon Kelley <simon@thekelleys.org.uk>.
+
+
diff --git a/contrib/lease-tools/dhcp_release.c b/contrib/lease-tools/dhcp_release.c
new file mode 100644
index 0000000..201fcd3
--- /dev/null
+++ b/contrib/lease-tools/dhcp_release.c
@@ -0,0 +1,332 @@
+/* Copyright (c) 2006 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.
+*/
+
+/* dhcp_release <interface> <address> <MAC address> <client_id>
+   MUST be run as root - will fail otherwise. */
+
+/* Send a DHCPRELEASE message via the specified interface 
+   to tell the local DHCP server to delete a particular lease. 
+   
+   The interface argument is the interface in which a DHCP
+   request _would_ be received if it was coming from the client, 
+   rather than being faked up here.
+   
+   The address argument is a dotted-quad IP addresses and mandatory. 
+   
+   The MAC address is colon separated hex, and is mandatory. It may be 
+   prefixed by an address-type byte followed by -, eg
+
+   10-11:22:33:44:55:66
+
+   but if the address-type byte is missing it is assumed to be 1, the type 
+   for ethernet. This encoding is the one used in dnsmasq lease files.
+
+   The client-id is optional. If it is "*" then it treated as being missing.
+*/
+
+#include <sys/types.h> 
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <net/if_arp.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <errno.h>
+
+#define DHCP_CHADDR_MAX          16
+#define BOOTREQUEST              1
+#define DHCP_COOKIE              0x63825363
+#define OPTION_SERVER_IDENTIFIER 54
+#define OPTION_CLIENT_ID         61
+#define OPTION_MESSAGE_TYPE      53
+#define OPTION_END               255
+#define DHCPRELEASE              7
+#define DHCP_SERVER_PORT         67
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+struct dhcp_packet {
+  u8 op, htype, hlen, hops;
+  u32 xid;
+  u16 secs, flags;
+  struct in_addr ciaddr, yiaddr, siaddr, giaddr;
+  u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
+  u32 cookie;
+  unsigned char options[308];
+};
+
+static struct iovec iov;
+
+static int expand_buf(struct iovec *iov, size_t size)
+{
+  void *new;
+
+  if (size <= iov->iov_len)
+    return 1;
+
+  if (!(new = malloc(size)))
+    {
+      errno = ENOMEM;
+      return 0;
+    }
+
+  if (iov->iov_base)
+    {
+      memcpy(new, iov->iov_base, iov->iov_len);
+      free(iov->iov_base);
+    }
+
+  iov->iov_base = new;
+  iov->iov_len = size;
+
+  return 1;
+}
+
+static ssize_t netlink_recv(int fd)
+{
+  struct msghdr msg;
+  ssize_t rc;
+
+  msg.msg_control = NULL;
+  msg.msg_controllen = 0;
+  msg.msg_name = NULL;
+  msg.msg_namelen = 0;
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+    
+  while (1)
+    {
+      msg.msg_flags = 0;
+      while ((rc = recvmsg(fd, &msg, MSG_PEEK)) == -1 && errno == EINTR);
+      
+      /* 2.2.x doesn't support MSG_PEEK at all, returning EOPNOTSUPP, so we just grab a 
+         big buffer and pray in that case. */
+      if (rc == -1 && errno == EOPNOTSUPP)
+        {
+          if (!expand_buf(&iov, 2000))
+            return -1;
+          break;
+        }
+      
+      if (rc == -1 || !(msg.msg_flags & MSG_TRUNC))
+        break;
+            
+      if (!expand_buf(&iov, iov.iov_len + 100))
+        return -1;
+    }
+
+  /* finally, read it for real */
+  while ((rc = recvmsg(fd, &msg, 0)) == -1 && errno == EINTR);
+  
+  return rc;
+}
+
+static int parse_hex(char *in, unsigned char *out, int maxlen, int *mac_type)
+{
+  int i = 0;
+  char *r;
+    
+  if (mac_type)
+    *mac_type = 0;
+  
+  while (maxlen == -1 || i < maxlen)
+    {
+      for (r = in; *r != 0 && *r != ':' && *r != '-'; r++);
+      if (*r == 0)
+        maxlen = i;
+      
+      if (r != in )
+        {
+          if (*r == '-' && i == 0 && mac_type)
+           {
+              *r = 0;
+              *mac_type = strtol(in, NULL, 16);
+              mac_type = NULL;
+           }
+          else
+            {
+              *r = 0;
+	      out[i] = strtol(in, NULL, 16);
+              i++;
+            }
+        }
+      in = r+1;
+    }
+    return i;
+}
+
+static int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
+{
+  return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
+}
+
+static struct in_addr find_interface(struct in_addr client, int fd, unsigned int index)
+{
+  struct sockaddr_nl addr;
+  struct nlmsghdr *h;
+  ssize_t len;
+ 
+  struct {
+    struct nlmsghdr nlh;
+    struct rtgenmsg g; 
+  } req;
+
+  addr.nl_family = AF_NETLINK;
+  addr.nl_pad = 0;
+  addr.nl_groups = 0;
+  addr.nl_pid = 0; /* address to kernel */
+
+  req.nlh.nlmsg_len = sizeof(req);
+  req.nlh.nlmsg_type = RTM_GETADDR;
+  req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST | NLM_F_ACK; 
+  req.nlh.nlmsg_pid = 0;
+  req.nlh.nlmsg_seq = 1;
+  req.g.rtgen_family = AF_INET; 
+
+  if (sendto(fd, (void *)&req, sizeof(req), 0, 
+	     (struct sockaddr *)&addr, sizeof(addr)) == -1)
+    {
+      perror("sendto failed");
+      exit(1);
+    }
+  
+  while (1)
+    {
+      if ((len = netlink_recv(fd)) == -1)
+	{
+	  perror("netlink");
+	  exit(1);
+	}
+
+      for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
+	if (h->nlmsg_type == NLMSG_DONE)
+	  exit(0);
+	else if (h->nlmsg_type == RTM_NEWADDR)
+          {
+            struct ifaddrmsg *ifa = NLMSG_DATA(h);  
+            struct rtattr *rta;
+            unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa));
+            
+            if (ifa->ifa_index == index && ifa->ifa_family == AF_INET)
+              {
+                struct in_addr netmask, addr;
+                
+                netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
+                addr.s_addr = 0;
+                
+                for (rta = IFA_RTA(ifa); RTA_OK(rta, len1); rta = RTA_NEXT(rta, len1))
+		  if (rta->rta_type == IFA_LOCAL)
+		    addr = *((struct in_addr *)(rta+1));
+		
+                if (addr.s_addr && is_same_net(addr, client, netmask))
+		  return addr;
+	      }
+	  }
+    }
+ 
+  exit(0);
+}
+
+int main(int argc, char **argv)
+{ 
+  struct in_addr server, lease;
+  int mac_type;
+  struct dhcp_packet packet;
+  unsigned char *p = packet.options;
+  struct sockaddr_in dest;
+  struct ifreq ifr;
+  int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+  int nl = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+
+  if (argc < 4 || argc > 5)
+    { 
+      fprintf(stderr, "usage: dhcp_release <interface> <addr> <mac> [<client_id>]\n");
+      exit(1);
+    }
+
+  if (fd == -1 || nl == -1)
+    {
+      perror("cannot create socket");
+      exit(1);
+    }
+  
+  /* This voodoo fakes up a packet coming from the correct interface, which really matters for 
+     a DHCP server */
+  strcpy(ifr.ifr_name, argv[1]);
+  if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1)
+    {
+      perror("cannot setup interface");
+      exit(1);
+    }
+  
+  if (inet_addr(argv[2]) == INADDR_NONE)
+    {
+      perror("invalid ip address");
+      exit(1);
+    }
+  
+  lease.s_addr = inet_addr(argv[2]);
+  server = find_interface(lease, nl, if_nametoindex(argv[1]));
+  
+  memset(&packet, 0, sizeof(packet));
+ 
+  packet.hlen = parse_hex(argv[3], packet.chaddr, DHCP_CHADDR_MAX, &mac_type);
+  if (mac_type == 0)
+    packet.htype = ARPHRD_ETHER;
+  else
+    packet.htype = mac_type;
+
+  packet.op = BOOTREQUEST;
+  packet.ciaddr = lease;
+  packet.cookie = htonl(DHCP_COOKIE);
+
+  *(p++) = OPTION_MESSAGE_TYPE;
+  *(p++) = 1;
+  *(p++) = DHCPRELEASE;
+
+  *(p++) = OPTION_SERVER_IDENTIFIER;
+  *(p++) = sizeof(server);
+  memcpy(p, &server, sizeof(server));
+  p += sizeof(server);
+
+  if (argc == 5 && strcmp(argv[4], "*") != 0)
+    {
+      unsigned int clid_len = parse_hex(argv[4], p+2, 255, NULL);
+      *(p++) = OPTION_CLIENT_ID;
+      *(p++) = clid_len;
+      p += clid_len;
+    }
+  
+  *(p++) = OPTION_END;
+ 
+  dest.sin_family = AF_INET;
+  dest.sin_port = ntohs(DHCP_SERVER_PORT);
+  dest.sin_addr = server;
+
+  if (sendto(fd, &packet, sizeof(packet), 0, 
+	     (struct sockaddr *)&dest, sizeof(dest)) == -1)
+    {
+      perror("sendto failed");
+      exit(1);
+    }
+
+  return 0;
+}
diff --git a/contrib/lease-tools/dhcp_release6.1 b/contrib/lease-tools/dhcp_release6.1
new file mode 100644
index 0000000..763e01c
--- /dev/null
+++ b/contrib/lease-tools/dhcp_release6.1
@@ -0,0 +1,38 @@
+.TH DHCP_RELEASE 1
+.SH NAME
+dhcp_release6 \- Release a DHCPv6 lease on a the local dnsmasq DHCP server.
+.SH SYNOPSIS
+.B dhcp_release6 --iface <interface> --client-id <client-id> --server-id
+server-id --iaid <iaid>  --ip <IP>  [--dry-run] [--help]
+.SH "DESCRIPTION"
+A utility which forces the DHCP server running on this machine to release a 
+DHCPv6 lease.
+.SS OPTIONS
+.IP "-a, --ip"
+IPv6 address to release.
+.IP "-c, --client-id"
+Colon-separated hex string representing DHCPv6 client id. Normally
+it can be found in leases file both on client and server.
+.IP "-d, --dry-run"
+Print hexadecimal representation of generated DHCPv6 release packet to standard
+output and exit.
+.IP "-h, --help"
+print usage information to standard output and exit.
+.IP "-i, --iaid"
+Decimal representation of DHCPv6 IAID. Normally it can be found in leases file
+both on client and server.
+.IP "-n, --iface"
+Network interface to send a DHCPv6 release packet from.
+.IP "-s, --server-id"
+Colon-separated hex string representing DHCPv6 server id. Normally
+it can be found in leases file both on client and server.
+.SH NOTES
+MUST be run as root - will fail otherwise.
+.SH LIMITATIONS
+Only usable on IPv6 DHCP leases.
+.SH SEE ALSO
+.BR dnsmasq (8)
+.SH AUTHOR
+This manual page was written by Simon Kelley <simon@thekelleys.org.uk>.
+
+
diff --git a/contrib/lease-tools/dhcp_release6.c b/contrib/lease-tools/dhcp_release6.c
new file mode 100644
index 0000000..2e0beff
--- /dev/null
+++ b/contrib/lease-tools/dhcp_release6.c
@@ -0,0 +1,445 @@
+/*
+ dhcp_release6 --iface <interface> --client-id <client-id> --server-id
+ server-id --iaid <iaid>  --ip <IP>  [--dry-run] [--help]
+ MUST be run as root - will fail otherwise
+ */
+
+/* Send a DHCPRELEASE message  to IPv6 multicast address  via the specified interface
+ to tell the local DHCP server to delete a particular lease.
+ 
+ The interface argument is the interface in which a DHCP
+ request _would_ be received if it was coming from the client,
+ rather than being faked up here.
+ 
+ The client-id argument is colon-separated hex string and mandatory. Normally
+ it can be found in leases file both on client and server
+
+ The server-id argument is colon-separated hex string and mandatory. Normally
+ it can be found in leases file both on client and server.
+ 
+ The iaid argument is numeric string and mandatory. Normally
+ it can be found in leases file both on client and server.
+ 
+ IP is an IPv6 address to release
+ 
+ If --dry-run is specified, dhcp_release6 just prints hexadecimal representation of
+ packet to send to stdout and exits.
+ 
+ If --help is specified, dhcp_release6 print usage information to stdout and exits
+ 
+ 
+ 
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <getopt.h>
+#include <errno.h>
+#include <unistd.h>
+
+#define NOT_REPLY_CODE 115
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+enum DHCP6_TYPES{
+    SOLICIT = 1,
+    ADVERTISE = 2,
+    REQUEST = 3,
+    CONFIRM = 4,
+    RENEW = 5,
+    REBIND = 6,
+    REPLY = 7,
+    RELEASE = 8,
+    DECLINE = 9,
+    RECONFIGURE = 10,
+    INFORMATION_REQUEST = 11,
+    RELAY_FORW = 12,
+    RELAY_REPL = 13
+    
+};
+enum DHCP6_OPTIONS{
+    CLIENTID = 1,
+    SERVERID = 2,
+    IA_NA = 3,
+    IA_TA = 4,
+    IAADDR = 5,
+    ORO = 6,
+    PREFERENCE = 7,
+    ELAPSED_TIME = 8,
+    RELAY_MSG = 9,
+    AUTH = 11,
+    UNICAST = 12,
+    STATUS_CODE = 13,
+    RAPID_COMMIT = 14,
+    USER_CLASS = 15,
+    VENDOR_CLASS = 16,
+    VENDOR_OPTS = 17,
+    INTERFACE_ID = 18,
+    RECONF_MSG = 19,
+    RECONF_ACCEPT = 20,
+};
+
+enum DHCP6_STATUSES{
+    SUCCESS = 0,
+    UNSPEC_FAIL = 1,
+    NOADDR_AVAIL=2,
+    NO_BINDING  = 3,
+    NOT_ON_LINK = 4,
+    USE_MULTICAST =5
+};
+static struct option longopts[] = {
+    {"ip", required_argument, 0, 'a'},
+    {"server-id", required_argument, 0, 's'},
+    {"client-id", required_argument, 0, 'c'},
+    {"iface", required_argument, 0, 'n'},
+    {"iaid", required_argument, 0, 'i'},
+    {"dry-run", no_argument, 0, 'd'},
+    {"help", no_argument, 0, 'h'},
+    {0,     0,           0,   0}
+};
+
+const short DHCP6_CLIENT_PORT = 546;
+const short DHCP6_SERVER_PORT = 547;
+
+const char*  DHCP6_MULTICAST_ADDRESS = "ff02::1:2";
+
+struct dhcp6_option{
+    uint16_t type;
+    uint16_t len;
+    char  value[1024];
+};
+
+struct dhcp6_iaaddr_option{
+    uint16_t type;
+    uint16_t len;
+    struct in6_addr ip;
+    uint32_t preferred_lifetime;
+    uint32_t valid_lifetime;
+    
+    
+};
+
+struct dhcp6_iana_option{
+    uint16_t type;
+    uint16_t len;
+    uint32_t iaid;
+    uint32_t t1;
+    uint32_t t2;
+    char options[1024];
+};
+
+
+struct dhcp6_packet{
+    size_t len;
+    char buf[2048];
+    
+} ;
+
+size_t pack_duid(const char* str, char* dst){
+    
+    char* tmp = strdup(str);
+    char* tmp_to_free = tmp;
+    char *ptr;
+    uint8_t write_pos = 0;
+    while ((ptr = strtok (tmp, ":"))) {
+        dst[write_pos] = (uint8_t) strtol(ptr, NULL, 16);
+        write_pos += 1;
+        tmp = NULL;
+        
+    }
+    free(tmp_to_free);
+    return write_pos;
+}
+
+struct dhcp6_option create_client_id_option(const char* duid){
+    struct dhcp6_option option;
+    option.type = htons(CLIENTID);
+    bzero(option.value, sizeof(option.value));
+    option.len  = htons(pack_duid(duid, option.value));
+    return option;
+}
+
+struct dhcp6_option create_server_id_option(const char* duid){
+    struct dhcp6_option   option;
+    option.type = htons(SERVERID);
+    bzero(option.value, sizeof(option.value));
+    option.len  = htons(pack_duid(duid, option.value));
+    return option;
+}
+
+struct dhcp6_iaaddr_option create_iaadr_option(const char* ip){
+    struct dhcp6_iaaddr_option result;
+    result.type =htons(IAADDR);
+    /* no suboptions needed here, so length is 24  */
+    result.len = htons(24);
+    result.preferred_lifetime = 0;
+    result.valid_lifetime = 0;
+    int s = inet_pton(AF_INET6, ip, &(result.ip));
+    if (s <= 0) {
+        if (s == 0)
+            fprintf(stderr, "Not in presentation format");
+        else
+            perror("inet_pton");
+        exit(EXIT_FAILURE);
+    }
+    return result;
+}
+struct dhcp6_iana_option  create_iana_option(const char * iaid, struct dhcp6_iaaddr_option  ia_addr){
+    struct dhcp6_iana_option  result;
+    result.type = htons(IA_NA);
+    result.iaid = htonl(atoi(iaid));
+    result.t1 = 0;
+    result.t2 = 0;
+    result.len = htons(12 + ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
+    memcpy(result.options, &ia_addr, ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
+    return result;
+}
+
+struct dhcp6_packet create_release_packet(const char* iaid, const char* ip, const char* client_id, const char* server_id){
+    struct dhcp6_packet result;
+    bzero(result.buf, sizeof(result.buf));
+    /* message_type */
+    result.buf[0] = RELEASE;
+    /* tx_id */
+    bzero(result.buf+1, 3);
+    
+    struct dhcp6_option client_option = create_client_id_option(client_id);
+    struct dhcp6_option server_option = create_server_id_option(server_id);
+    struct dhcp6_iaaddr_option iaaddr_option = create_iaadr_option(ip);
+    struct dhcp6_iana_option iana_option = create_iana_option(iaid, iaaddr_option);
+    int offset = 4;
+    memcpy(result.buf + offset, &client_option, ntohs(client_option.len) + 2*sizeof(uint16_t));
+    offset += (ntohs(client_option.len)+ 2 *sizeof(uint16_t) );
+    memcpy(result.buf + offset, &server_option, ntohs(server_option.len) + 2*sizeof(uint16_t) );
+    offset += (ntohs(server_option.len)+ 2* sizeof(uint16_t));
+    memcpy(result.buf + offset, &iana_option, ntohs(iana_option.len) + 2*sizeof(uint16_t) );
+    offset += (ntohs(iana_option.len)+ 2* sizeof(uint16_t));
+    result.len = offset;
+    return result;
+}
+
+uint16_t parse_iana_suboption(char* buf, size_t len){
+    size_t current_pos = 0;
+    char option_value[1024];
+    while (current_pos < len) {
+        uint16_t option_type, option_len;
+        memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
+        memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
+        option_type = ntohs(option_type);
+        option_len = ntohs(option_len);
+        current_pos += 2 * sizeof(uint16_t);
+        if (option_type == STATUS_CODE){
+            uint16_t status;
+            memcpy(&status, buf + current_pos, sizeof(uint16_t));
+            status = ntohs(status);
+            if (status != SUCCESS){
+                memcpy(option_value, buf + current_pos + sizeof(uint16_t) , option_len - sizeof(uint16_t));
+                option_value[option_len-sizeof(uint16_t)] ='\0';
+                fprintf(stderr, "Error: %s\n", option_value);
+            }
+            return status;
+        }
+    }
+    return -2;
+}
+
+int16_t parse_packet(char* buf, size_t len){
+    uint8_t type  = buf[0];
+    /*skipping tx id. you need it, uncomment following line
+        uint16_t tx_id = ntohs((buf[1] <<16) + (buf[2] <<8) + buf[3]);
+     */
+    size_t current_pos = 4;
+    if (type != REPLY ){
+        return NOT_REPLY_CODE;
+    }
+    char option_value[1024];
+    while (current_pos < len) {
+        uint16_t option_type, option_len;
+        memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
+        memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
+        option_type = ntohs(option_type);
+        option_len = ntohs(option_len);
+        current_pos += 2 * sizeof(uint16_t);
+        if (option_type == STATUS_CODE){
+            uint16_t status;
+            memcpy(&status, buf + current_pos, sizeof(uint16_t));
+            status = ntohs(status);
+            if (status != SUCCESS){
+                memcpy(option_value, buf + current_pos +sizeof(uint16_t) , option_len -sizeof(uint16_t));
+                fprintf(stderr, "Error: %d %s\n", status, option_value);
+                return status;
+            }
+            
+        }
+        if (option_type == IA_NA ){
+            uint16_t result = parse_iana_suboption(buf + current_pos +24, option_len -24);
+            if (result){
+                return result;
+            }
+        }
+        current_pos += option_len;
+
+    }
+    return -1;
+}
+
+void usage(const char* arg, FILE* stream){
+    const char* usage_string ="--ip IPv6 --iface IFACE --server-id SERVER_ID --client-id CLIENT_ID --iaid IAID [--dry-run] | --help";
+    fprintf (stream, "Usage: %s %s\n", arg, usage_string);
+    
+}
+
+int send_release_packet(const char* iface, struct dhcp6_packet* packet){
+    
+    struct sockaddr_in6 server_addr, client_addr;
+    char response[1400];
+    int sock = socket(PF_INET6, SOCK_DGRAM, 0);
+    int i = 0;
+    if (sock < 0) {
+        perror("creating socket");
+        return -1;
+    }
+    if (setsockopt(sock, SOL_SOCKET, 25, iface, strlen(iface)) == -1)  {
+        perror("SO_BINDTODEVICE");
+        close(sock);
+        return -1;
+    }
+    memset(&server_addr, 0, sizeof(server_addr));
+    server_addr.sin6_family = AF_INET6;
+    client_addr.sin6_family = AF_INET6;
+    client_addr.sin6_port = htons(DHCP6_CLIENT_PORT);
+    client_addr.sin6_flowinfo = 0;
+    client_addr.sin6_scope_id =0;
+    inet_pton(AF_INET6, "::", &client_addr.sin6_addr);
+    bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6));
+    inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr);
+    server_addr.sin6_port = htons(DHCP6_SERVER_PORT);
+    int16_t recv_size = 0;
+    for (i = 0; i < 5; i++) {
+        if (sendto(sock, packet->buf, packet->len, 0,
+               (struct sockaddr *)&server_addr,
+               sizeof(server_addr)) < 0) {
+            perror("sendto failed");
+            exit(4);
+        }
+        recv_size = recvfrom(sock, response, sizeof(response), MSG_DONTWAIT, NULL, 0);
+        if (recv_size == -1){
+            if (errno == EAGAIN){
+                sleep(1);
+                continue;
+            }else {
+                perror("recvfrom");
+            }
+        }
+        int16_t result = parse_packet(response, recv_size);
+        if (result == NOT_REPLY_CODE){
+            sleep(1);
+            continue;
+        }
+        return result;
+    }
+    fprintf(stderr, "Response timed out\n");
+    return -1;
+    
+}
+
+
+int main(int argc, char *  const argv[]) {
+    const char* UNINITIALIZED = "";
+    const char* iface = UNINITIALIZED;
+    const char* ip = UNINITIALIZED;
+    const char* client_id = UNINITIALIZED;
+    const char* server_id = UNINITIALIZED;
+    const char* iaid = UNINITIALIZED;
+    int dry_run = 0;
+    while (1) {
+        int option_index = 0;
+        int c = getopt_long(argc, argv, "a:s:c:n:i:hd", longopts, &option_index);
+        if (c == -1){
+            break;
+        }
+        switch(c){
+            case 0:
+                if (longopts[option_index].flag !=0){
+                    break;
+                }
+                printf ("option %s", longopts[option_index].name);
+                if (optarg)
+                    printf (" with arg %s", optarg);
+                printf ("\n");
+                break;
+            case 'i':
+                iaid = optarg;
+                break;
+            case 'n':
+                iface = optarg;
+                break;
+            case 'a':
+                ip = optarg;
+                break;
+            case 'c':
+                client_id = optarg;
+                break;
+            case 'd':
+                dry_run = 1;
+                break;
+            case 's':
+                server_id = optarg;
+                break;
+            case 'h':
+                usage(argv[0], stdout);
+                return 0;
+            case '?':
+                usage(argv[0], stderr);
+                return -1;
+             default:
+                abort();
+                
+        }
+        
+    }
+    if (iaid == UNINITIALIZED){
+        fprintf(stderr, "Missing required iaid parameter\n");
+        usage(argv[0], stderr);
+        return -1;
+    }
+    if (server_id == UNINITIALIZED){
+        fprintf(stderr, "Missing required server-id parameter\n");
+        usage(argv[0], stderr);
+        return -1;
+    }
+    if (client_id == UNINITIALIZED){
+        fprintf(stderr, "Missing required client-id parameter\n");
+        usage(argv[0], stderr);
+        return -1;
+    }
+    if (ip == UNINITIALIZED){
+        fprintf(stderr, "Missing required ip parameter\n");
+        usage(argv[0], stderr);
+        return -1;
+    }
+    if (iface == UNINITIALIZED){
+        fprintf(stderr, "Missing required iface parameter\n");
+        usage(argv[0], stderr);
+        return -1;
+    }
+
+
+
+    struct dhcp6_packet packet = create_release_packet(iaid, ip, client_id, server_id);
+    if (dry_run){
+        uint16_t i;
+        for(i=0;i<packet.len;i++){
+            printf("%hhx", packet.buf[i]);
+        }
+        printf("\n");
+        return 0;
+    }
+    return send_release_packet(iface, &packet);
+    
+}
diff --git a/contrib/mactable/macscript b/contrib/mactable/macscript
new file mode 100755
index 0000000..44a4477
--- /dev/null
+++ b/contrib/mactable/macscript
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+STATUS_FILE="/tmp/dnsmasq-ip-mac.status"
+
+# Script for dnsmasq lease-change hook.
+# Maintains the above file with a IP address/MAC address pairs,
+# one lease per line. Works with IPv4 and IPv6 leases, file is
+# atomically updated, so no races for users of the data.
+
+action="$1"
+mac="$2"   # IPv4
+ip="$3"
+
+# ensure it always exists.
+
+if [ ! -f "$STATUS_FILE" ]; then
+  touch "$STATUS_FILE"
+fi
+
+if [  -n "$DNSMASQ_IAID" ]; then
+    mac="$DNSMASQ_MAC"   # IPv6
+fi
+
+# worry about an add or old action when the MAC address is not known:
+# leave any old one in place in that case.
+
+if [ "$action" = "add" -o "$action" = "old" -o "$action" = "del" ]; then
+  if [ -n "$mac" -o "$action" = "del" ]; then
+    sed "/^${ip//./\.} / d" "$STATUS_FILE" > "$STATUS_FILE".new
+  
+    if [ "$action" = "add" -o "$action" = "old" ]; then
+       echo "$ip $mac" >> "$STATUS_FILE".new
+    fi
+    mv  "$STATUS_FILE".new "$STATUS_FILE" # atomic update.
+  fi
+fi
diff --git a/contrib/openvpn/README b/contrib/openvpn/README
new file mode 100755
index 0000000..dd99600
--- /dev/null
+++ b/contrib/openvpn/README
@@ -0,0 +1,44 @@
+The patch I have attached lets me get the behavior I wish out of
+dnsmasq.  I also include my version of dhclient-enter-hooks as
+required for the switchover from pre-dnsmasq and dhclient.
+
+On 8/16/05, Joseph Tate <dragonstrider@gmail.com> wrote:
+> I'm trying to use dnsmasq on a laptop in order to facilitate openvpn
+> connections.  As such, the only configuration option I'm concerned
+> about is a single server=3D/example.com/192.168.0.1 line.
+>
+> The way I currently have it set up is I modified dhclient to write its
+> resolv.conf data to /etc/resolv.conf.dhclient and configured
+> /etc/dnsmasq.conf to look there for its upstream dns servers.
+> /etc/resolv.conf is set to nameserver 127.0.0.1
+>
+> All of this works great.  When I start the openvpn service, it the
+> routes, and queries to the domain in the server=3D line work just fine.
+>
+> The only problem is that the hostname for my system doesn't get set
+> correctly.  With the resolv.conf data written to something other than
+> /etc/resolv.conf, the ifup scripts don't have a valid dns server to do
+> the ipcalc call to set the laptop's hostname.  If I start dnsmasq
+> before the network comes up, something gets fubar'd.  I'm not sure how
+> to describe it exactly, but network services are slow to load, and
+> restarting networking and dnsmasq doesn't solve the problem.  Perhaps
+> dnsmasq is answering the dhcp request when the network starts?
+> Certainly not desired behavior.
+>
+> Anyway, my question: is there a way to have the best of both worlds?
+> DHCP requests to another server, and DNS lookups that work at all
+> times?
+>
+> My current best idea on how to solve this problem is modifying the
+> dnsmasq initscript to tweak /etc/dhclient-enter-hooks to change where
+> dhclient writes resolv.conf data, and fixing up /etc/resolv.conf on
+> the fly to set 127.0.0.1 to the nameserver (and somehow keep the
+> search domains intact), but I'm hoping that I'm just missing some key
+> piece of the puzzle and that this problem has been solved before.  Any
+> insights?
+>
+> --
+> Joseph Tate
+> Personal e-mail: jtate AT dragonstrider DOT com
+> Web: http://www.dragonstrider.com
+>
diff --git a/contrib/openvpn/dhclient-enter-hooks b/contrib/openvpn/dhclient-enter-hooks
new file mode 100755
index 0000000..cb78e2a
--- /dev/null
+++ b/contrib/openvpn/dhclient-enter-hooks
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+function save_previous() {
+  if [ -e $1 -a ! -e $1.predhclient ]; then
+    mv $1 $1.predhclient 
+  fi
+}
+
+function write_resolv_conf() {
+  RESOLVCONF=$1
+  if [ -n "$new_domain_name" ] || [ -n "$new_domain_name_servers" ]; then
+    save_previous $RESOLVCONF
+    echo '; generated by /etc/dhclient-enter-hooks' > $RESOLVCONF
+    if [ -n "$SEARCH" ]; then
+ 	echo search $SEARCH >> $RESOLVCONF
+    else
+	if [ -n "$new_domain_name" ]; then
+ 	    echo search $new_domain_name >> $RESOLVCONF
+ 	fi
+    fi
+    chmod 644 $RESOLVCONF
+    for nameserver in $new_domain_name_servers; do
+      echo nameserver $nameserver >>$RESOLVCONF
+    done
+  fi
+}
+
+make_resolv_conf() {
+  write_resolv_conf /etc/resolv.conf
+}
diff --git a/contrib/openvpn/dnsmasq.patch b/contrib/openvpn/dnsmasq.patch
new file mode 100755
index 0000000..5c11881
--- /dev/null
+++ b/contrib/openvpn/dnsmasq.patch
@@ -0,0 +1,61 @@
+--- dnsmasq-2.22/rpm/dnsmasq.rh	2005-03-24 09:51:18.000000000 -0500
++++ dnsmasq-2.22/rpm/dnsmasq.rh.new	2005-08-25 10:52:04.310568784 -0400
+@@ -2,7 +2,7 @@
+ #
+ # Startup script for the DNS caching server
+ #
+-# chkconfig: 2345 99 01
++# chkconfig: 2345 07 89
+ # description: This script starts your DNS caching server
+ # processname: dnsmasq
+ # pidfile: /var/run/dnsmasq.pid
+@@ -10,6 +10,25 @@
+ # Source function library.
+ . /etc/rc.d/init.d/functions
+ 
++function setup_dhclient_enter_hooks() {
++    if [ -f /etc/dhclient-enter-hooks ]; then
++        . /etc/dhclient-enter-hooks
++        cp /etc/resolv.conf /etc/resolv.conf.dnsmasq
++        cp /etc/dhclient-enter-hooks /etc/dhclient-enter-hooks.dnsmasq
++        sed -e 's/resolv\.conf$/resolv.conf.dnsmasq/' /etc/dhclient-enter-hooks.dnsmasq > /etc/dhclient-enter-hooks
++        sed -e 's/\(nameserver[ tab]\+\)[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+$/\1127.0.0.1/' /etc/resolv.conf.dnsmasq > /etc/resolv.conf
++    fi
++}
++
++function teardown_dhclient_enter_hooks() {
++    if [ -f /etc/dhclient-enter-hooks -a -f /etc/dhclient-enter-hooks.dnsmasq ]; then
++        if [ -f /etc/resolv.conf.dnsmasq ]; then
++            mv /etc/resolv.conf.dnsmasq /etc/resolv.conf
++        fi
++        mv /etc/dhclient-enter-hooks.dnsmasq /etc/dhclient-enter-hooks
++    fi
++}
++
+ # Source networking configuration.
+ . /etc/sysconfig/network
+ 
+@@ -24,7 +43,7 @@
+ MAILHOSTNAME=""
+ # change this line if you want dns to get its upstream servers from
+ # somewhere other that /etc/resolv.conf 
+-RESOLV_CONF=""
++RESOLV_CONF="/etc/resolv.conf.dnsmasq"
+ # change this if you want dnsmasq to cache any "hostname" or "client-hostname" from
+ # a dhcpd's lease file
+@@ -54,6 +73,7 @@
+ case "$1" in
+   start)
+         echo -n "Starting dnsmasq: "
++        setup_dhclient_enter_hooks
+         daemon $dnsmasq $OPTIONS
+ 	RETVAL=$?
+         echo
+@@ -62,6 +82,7 @@
+   stop)
+         if test "x`pidof dnsmasq`" != x; then
+             echo -n "Shutting down dnsmasq: "
++            teardown_dhclient_enter_hooks
+             killproc dnsmasq
+         fi
+ 	RETVAL=$?
diff --git a/contrib/port-forward/dnsmasq-portforward b/contrib/port-forward/dnsmasq-portforward
new file mode 100755
index 0000000..c2c634f
--- /dev/null
+++ b/contrib/port-forward/dnsmasq-portforward
@@ -0,0 +1,78 @@
+#!/bin/bash
+# 
+# /usr/sbin/dnsmasq-portforward
+#
+# A script which gets run when the dnsmasq DHCP lease database changes.
+# It logs to $LOGFILE, if it exists, and maintains port-forwards using
+# IP-tables so that they always point to the correct host. See
+# $PORTSFILE for details on configuring this. dnsmasq must be version 2.34 
+# or later.
+#
+# To enable this script, add 
+#    dhcp-script=/usr/sbin/dnsmasq-portforward
+# to /etc/dnsmasq.conf
+#
+# To enable logging, touch $LOGFILE
+#
+
+PORTSFILE=/etc/portforward
+LOGFILE=/var/log/dhcp.log
+IPTABLES=/sbin/iptables
+
+action=${1:-0}
+hostname=${4}
+
+# log what's going on.
+if [ -f ${LOGFILE} ] ; then
+    date +"%D %T $*" >>${LOGFILE}
+fi
+
+# If a lease gets stripped of a name, we see that as an "old" action
+# with DNSMASQ_OLD_HOSTNAME set, convert it into a "del" 
+if [ ${DNSMASQ_OLD_HOSTNAME} ] && [ ${action} = old ] ; then
+    action=del
+    hostname=${DNSMASQ_OLD_HOSTNAME}
+fi
+
+# IPv6 leases are not our concern. no NAT there!
+if [ ${DNSMASQ_IAID} ] ; then
+   exit 0
+fi
+
+# action init is not relevant, and will only be seen when leasefile-ro is set.
+if [ ${action} = init ] ; then
+    exit 0
+fi
+
+# action tftp is not relevant.
+if [ ${action} = tftp ] ; then
+    exit 0
+fi
+
+if [ ${hostname} ]; then
+    ports=$(sed -n -e "/^${hostname}\ .*/ s/^.* //p" ${PORTSFILE})
+
+    for port in $ports; do
+	verb=removed
+	protocol=tcp
+	if [ ${port:0:1} = u ] ; then
+	    protocol=udp 
+	    port=${port/u/}
+	fi
+	src=${port/:*/}
+	dst=${port/*:/}
+# delete first, to avoid multiple copies of rules.
+	${IPTABLES} -t nat -D PREROUTING -p $protocol --destination-port $src -j DNAT --to-destination ${3}:$dst
+        if [ ${action} != del ] ; then
+	    ${IPTABLES} -t nat -A PREROUTING -p $protocol --destination-port $src -j DNAT --to-destination ${3}:$dst
+	    verb=added
+	fi
+	if [ -f ${LOGFILE} ] ; then
+	    echo "     DNAT $protocol $src to ${3}:$dst ${verb}." >>${LOGFILE}
+	fi
+    done
+fi
+    
+exit 0
+
+
diff --git a/contrib/port-forward/portforward b/contrib/port-forward/portforward
new file mode 100755
index 0000000..21fdca1
--- /dev/null
+++ b/contrib/port-forward/portforward
@@ -0,0 +1,28 @@
+# This file is read by /usr/sbin/dnsmasq-portforward and used to set up port 
+# forwarding to hostnames. If the dnsmasq-determined hostname matches the
+# first column of this file, then a DNAT port-forward will be set up 
+# to the address which has just been allocated by DHCP . The second field 
+# is port number(s). If there is only one, then the port-forward goes to 
+# the same port on the DHCP-client, if there are two separated with a 
+# colon, then the second number is the port to which the connection 
+# is forwarded on the DHCP-client. By default, forwarding is set up 
+# for TCP, but it can done for UDP instead by prefixing the port to "u". 
+# To forward both TCP and UDP, two lines are required. 
+#
+# eg.
+# wwwserver 80
+# will set up a port forward from port 80 on this host to port 80 
+# at the address allocated to wwwserver whenever wwwserver gets a DHCP lease.
+#
+# wwwserver 8080:80
+# will set up a port forward from port 8080 on this host to port 80
+# on the DHCP-client.
+#
+# dnsserver 53
+# dnsserver u53
+# will port forward port 53 UDP and TCP from this host to port 53 on dnsserver.
+#
+# Port forwards will recreated when dnsmasq restarts after a reboot, and
+# removed when DHCP leases expire. After editing this file, send
+# SIGHUP to dnsmasq to install new iptables entries in the kernel.
+
diff --git a/contrib/reverse-dns/README b/contrib/reverse-dns/README
new file mode 100644
index 0000000..9fd4efb
--- /dev/null
+++ b/contrib/reverse-dns/README
@@ -0,0 +1,18 @@
+The script reads stdin and replaces all IP addresses with names before

+outputting it again. IPs from private networks are reverse looked  up

+via dns. Other IP addresses are searched for in the dnsmasq query log.

+This gives names (CNAMEs if I understand DNS correctly) that are closer

+to the name the client originally asked for then the names obtained by

+reverse lookup. Just run

+

+netstat -n -4 | ./reverse_replace.sh 

+

+to see what it does. It needs 

+

+log-queries

+log-facility=/var/log/dnsmasq.log

+

+in the dnsmasq configuration.

+

+The script runs on debian (with ash installed) and on busybox.

+

diff --git a/contrib/reverse-dns/reverse_replace.sh b/contrib/reverse-dns/reverse_replace.sh
new file mode 100644
index 0000000..c6401fb
--- /dev/null
+++ b/contrib/reverse-dns/reverse_replace.sh
@@ -0,0 +1,125 @@
+#!/bin/ash
+# $Id: reverse_replace.sh 18 2015-03-01 16:12:35Z jo $
+#
+# Usage e.g.: netstat -n -4 | reverse_replace.sh 
+# Parses stdin for IP4 addresses and replaces them 
+# with names retrieved by parsing the dnsmasq log.
+# This currently only gives CNAMEs. But these 
+# usually tell you more than the ones from reverse 
+# lookups. 
+#
+# This has been tested on debian and asuswrt. Please
+# report successful tests on other platforms.
+#
+# Author: Joachim Zobel <jz-2014@heute-morgen.de>
+# License: Consider this MIT style licensed. You can 
+#   do as you ike, but you must not remove my name.
+#
+
+LOG=/var/log/dnsmasq.log
+MAX_LINES=15000
+
+# sed regex do match IPs
+IP_regex='[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'
+# private IP ranges
+IP_private='\(^127\.\)\|\(^192\.168\.\)\|\(^10\.\)\|\(^172\.1[6-9]\.\)\|\(^172\.2[0-9]\.\)\|\(^172\.3[0-1]\.\)'
+
+#######################################################################
+# Find Commands
+  
+HOST=nslookup
+if type host > /dev/null 2>&1; then
+  # echo "No need for nslookup, host is there"
+  HOST=host
+fi
+
+#######################################################################
+# Functions
+
+# Use shell variables for an (IP) lookup table
+create_lookup_table()
+{
+  # Parse log into lookup table
+  local CMDS="$( tail -"$MAX_LINES" "$LOG" | \
+    grep " is $IP_regex" | \
+    sed "s#.* \([^ ]*\) is \($IP_regex\).*#set_val \2 \1;#" )"
+
+  local IFS='
+'
+  for CMD in $CMDS
+  do
+    eval $CMD
+  done
+}
+
+set_val()
+{
+  local _IP=$(echo $1 | tr . _)
+  local KEY="__IP__$_IP"
+  eval "$KEY"=$2
+}
+
+get_val()
+{
+  local _IP=$(echo $1 | tr . _)
+  local KEY="__IP__$_IP"
+  eval echo -n '${'"$KEY"'}'
+}
+
+dns_lookup()
+{
+  local IP=$1
+
+  local RTN="$($HOST $IP | \
+        sed 's#\s\+#\n#g' | \
+        grep -v '^$' | \
+        tail -1 | tr -d '\n' | \
+        sed 's#\.$##')"
+  if echo $RTN | grep -q NXDOMAIN; then
+    echo -n $IP
+  else
+    echo -n "$RTN"
+  fi     
+}
+
+reverse_dns()
+{
+  local IP=$1
+
+  # Skip if it is not an IP
+  if ! echo $IP | grep -q "^$IP_regex$"; then
+    echo -n $IP
+    return 
+  fi
+    
+  # Do a dns lookup, if it is a local IP
+  if echo $IP | grep -q $IP_private; then
+    dns_lookup $IP
+    return
+  fi
+    
+  local NAME="$(get_val $IP)"
+  
+  if [ -z "$NAME" ]; then
+    echo -n $IP
+  else
+    echo -n $NAME
+  fi
+}
+
+#######################################################################
+# Main
+create_lookup_table
+
+while read LINE; do
+  for IP in $(echo "$LINE" | \
+              sed "s#\b\($IP_regex\)\b#\n\1\n#g" | \
+              grep $IP_regex) 
+  do
+    NAME=`reverse_dns $IP `
+    # echo "$NAME $IP"
+    LINE=`echo "$LINE" | sed "s#$IP#$NAME#" ` 
+  done
+  echo $LINE
+done
+
diff --git a/contrib/slackware-dnsmasq/dnsmasq.SlackBuild b/contrib/slackware-dnsmasq/dnsmasq.SlackBuild
new file mode 100755
index 0000000..c5ba083
--- /dev/null
+++ b/contrib/slackware-dnsmasq/dnsmasq.SlackBuild
@@ -0,0 +1,56 @@
+#!/bin/sh
+CWD=`pwd`
+PKG=/tmp/package-dnsmasq
+
+VERSION=2.24
+ARCH=${ARCH:-i486}
+BUILD=${BUILD:-1}
+
+if [ "$ARCH" = "i386" ]; then
+  SLKCFLAGS="-O2 -march=i386 -mcpu=i686"
+elif [ "$ARCH" = "i486" ]; then
+  SLKCFLAGS="-O2 -march=i486 -mcpu=i686"
+elif [ "$ARCH" = "s390" ]; then
+  SLKCFLAGS="-O2"
+elif [ "$ARCH" = "x86_64" ]; then
+  SLKCFLAGS="-O2"
+fi
+
+rm -rf $PKG
+mkdir -p $PKG
+cd /tmp
+rm -rf dnsmasq-$VERSION
+tar xzvf $CWD/dnsmasq-$VERSION.tar.gz
+cd dnsmasq-$VERSION
+zcat $CWD/dnsmasq.leasedir.diff.gz | patch -p1 --verbose --backup --suffix=.orig || exit
+chown -R root.root .
+make install-i18n PREFIX=/usr DESTDIR=$PKG MANDIR=/usr/man
+chmod 755 $PKG/usr/sbin/dnsmasq
+chown -R root.bin $PKG/usr/sbin
+gzip -9 $PKG/usr/man/man8/dnsmasq.8
+for f in $PKG/usr/share/man/*; do 
+   if [ -f $$f/man8/dnsmasq.8 ]; then 
+        gzip -9 $$f/man8/dnsmasq.8 ; 
+   fi 
+done
+gzip -9 $PKG/usr/man/*/man8/dnsmasq.8
+mkdir -p $PKG/var/state/dnsmasq
+( cd $PKG
+  find . | xargs file | grep "executable" | grep ELF | cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null
+  find . | xargs file | grep "shared object" | grep ELF | cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null
+)
+mkdir $PKG/etc
+cat dnsmasq.conf.example > $PKG/etc/dnsmasq.conf.new
+mkdir $PKG/etc/rc.d
+zcat $CWD/rc.dnsmasq.gz > $PKG/etc/rc.d/rc.dnsmasq.new
+mkdir -p $PKG/usr/doc/dnsmasq-$VERSION
+cp -a \
+  CHANGELOG COPYING FAQ UPGRADING_to_2.0 doc.html setup.html \
+  $PKG/usr/doc/dnsmasq-$VERSION
+mkdir -p $PKG/install
+cat $CWD/slack-desc > $PKG/install/slack-desc
+zcat $CWD/doinst.sh.gz > $PKG/install/doinst.sh
+
+cd $PKG
+makepkg -l y -c n ../dnsmasq-$VERSION-$ARCH-$BUILD.tgz
+
diff --git a/contrib/slackware-dnsmasq/dnsmasq.leasedir.diff.gz b/contrib/slackware-dnsmasq/dnsmasq.leasedir.diff.gz
new file mode 100755
index 0000000..22fc32b
--- /dev/null
+++ b/contrib/slackware-dnsmasq/dnsmasq.leasedir.diff.gz
Binary files differ
diff --git a/contrib/slackware-dnsmasq/doinst.sh.gz b/contrib/slackware-dnsmasq/doinst.sh.gz
new file mode 100755
index 0000000..3b44227
--- /dev/null
+++ b/contrib/slackware-dnsmasq/doinst.sh.gz
Binary files differ
diff --git a/contrib/slackware-dnsmasq/rc.dnsmasq.gz b/contrib/slackware-dnsmasq/rc.dnsmasq.gz
new file mode 100755
index 0000000..a86abbb
--- /dev/null
+++ b/contrib/slackware-dnsmasq/rc.dnsmasq.gz
Binary files differ
diff --git a/contrib/slackware-dnsmasq/slack-desc b/contrib/slackware-dnsmasq/slack-desc
new file mode 100755
index 0000000..0a0c577
--- /dev/null
+++ b/contrib/slackware-dnsmasq/slack-desc
@@ -0,0 +1,19 @@
+# HOW TO EDIT THIS FILE:
+# The "handy ruler" below makes it easier to edit a package description.  Line
+# up the first '|' above the ':' following the base package name, and the '|' on
+# the right side marks the last column you can put a character in.  You must make
+# exactly 11 lines for the formatting to be correct.  It's also customary to
+# leave one space after the ':'.
+
+       |-----handy-ruler------------------------------------------------------|
+dnsmasq: dnsmasq (small DNS and DHCP server)
+dnsmasq:
+dnsmasq: Dnsmasq is a lightweight, easy to configure DNS forwarder and DHCP
+dnsmasq: server.  It is designed to provide DNS (and optionally DHCP) to a
+dnsmasq: small network, and can serve the names of local machines which are not
+dnsmasq: in the global DNS. 
+dnsmasq:
+dnsmasq: Dnsmasq was written by Simon Kelley.
+dnsmasq:
+dnsmasq:
+dnsmasq:
diff --git a/contrib/static-arp/static-arp b/contrib/static-arp/static-arp
new file mode 100644
index 0000000..82115b7
--- /dev/null
+++ b/contrib/static-arp/static-arp
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+# Contributed by Darren Hoo <darren.hoo@gmail.com>
+
+# If you use dnsmasq as DHCP server on a router, you may have
+# met with attackers trying ARP Poison Routing (APR) on your
+# local area network. This script will setup a 'permanent' entry
+# in the router's ARP table upon each DHCP transaction so as to
+# make the attacker's efforts less successful.
+
+# Usage:
+# edit /etc/dnsmasq.conf and specify the path of this script
+# to  dhcp-script, for example:
+#  dhcp-script=/usr/sbin/static-arp
+
+# if $1 is add or old, update the static arp table entry.
+# if $1 is del, then delete the entry from the table
+# if $1 is init which is called by dnsmasq at startup, it's ignored
+
+ARP=/usr/sbin/arp
+
+# Arguments.
+# $1 is action (add, del, old)
+# $2 is MAC
+# $3 is address
+# $4 is hostname (optional, may be unset)
+
+if [ ${1} = del ] ; then
+         ${ARP} -d $3
+fi
+
+if [ ${1} = old ] || [ ${1} = add ] ; then
+         ${ARP} -s $3 $2
+fi
+
diff --git a/contrib/systemd/README b/contrib/systemd/README
new file mode 100644
index 0000000..c8046c2
--- /dev/null
+++ b/contrib/systemd/README
@@ -0,0 +1,16 @@
+Hello,
+
+I created a systemd service file for dnsmasq.
+systemd is a sysvinit replacement (see [1] for more information).
+One of the goals of systemd is to encourage standardization between different
+distributions. This means, while I also submitted a ticket in Debian GNU/Linux,
+I would like to ask you to accept this service file as the upstream
+distributor, so that other distributions can use the same service file and
+don’t have to ship their own.
+
+Please include this file in your next release (just like in init script).
+
+
+[1] http://en.wikipedia.org/wiki/Systemd
+
+
diff --git a/contrib/systemd/dbus_activation b/contrib/systemd/dbus_activation
new file mode 100644
index 0000000..38f0822
--- /dev/null
+++ b/contrib/systemd/dbus_activation
@@ -0,0 +1,57 @@
+To: dnsmasq-discuss@lists.thekelleys.org.uk

+From: Alex Elsayed <eternaleye+usenet@gmail.com>

+Date: Tue, 15 May 2012 01:53:54 -0700

+Subject: [Dnsmasq-discuss] [PATCH] Support dbus activation

+

+Introduce dbus service file and turn dbus on in the systemd

+unit.

+

+Note to packagers:

+To add support for dbus activation, you must install the dbus

+service file (dbus/uk.org.thekelleys.dnsmasq.service) into

+$DATADIR/dbus-1/system-services.

+

+---

+ contrib/systemd/dnsmasq.service        |    2 +-

+ dbus/uk.org.thekelleys.dnsmasq.service |    7 +++++++

+ 2 files changed, 8 insertions(+), 1 deletion(-)

+ create mode 100644 dbus/uk.org.thekelleys.dnsmasq.service

+

+diff --git a/contrib/systemd/dnsmasq.service 

+b/contrib/systemd/dnsmasq.service

+index a27fe6d..4a784d3 100644

+--- a/contrib/systemd/dnsmasq.service

++++ b/contrib/systemd/dnsmasq.service

+@@ -5,7 +5,7 @@ Description=A lightweight DHCP and caching DNS server

+ Type=dbus

+ BusName=uk.org.thekelleys.dnsmasq

+ ExecStartPre=/usr/sbin/dnsmasq --test

+-ExecStart=/usr/sbin/dnsmasq -k

++ExecStart=/usr/sbin/dnsmasq -k -1

+ ExecReload=/bin/kill -HUP $MAINPID

+ 

+ [Install]

+diff --git a/dbus/uk.org.thekelleys.dnsmasq.service 

+b/dbus/uk.org.thekelleys.dnsmasq.service

+new file mode 100644

+index 0000000..f5fe98d

+--- /dev/null

++++ b/dbus/uk.org.thekelleys.dnsmasq.service

+@@ -0,0 +1,7 @@

++[D-BUS Service]

++Name=uk.org.thekelleys.dnsmasq

++Exec=/usr/sbin/dnsmasq -k -1

++User=root

++SystemdService=dnsmasq.service

++

++

+-- 

+1.7.10.2

+

+

+

+_______________________________________________

+Dnsmasq-discuss mailing list

+Dnsmasq-discuss@lists.thekelleys.org.uk

+http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss

+

diff --git a/contrib/systemd/dnsmasq.service b/contrib/systemd/dnsmasq.service
new file mode 100644
index 0000000..c70b144
--- /dev/null
+++ b/contrib/systemd/dnsmasq.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=dnsmasq - A lightweight DHCP and caching DNS server
+
+[Service]
+Type=dbus
+BusName=uk.org.thekelleys.dnsmasq
+ExecStartPre=/usr/sbin/dnsmasq --test
+ExecStart=/usr/sbin/dnsmasq -k
+ExecReload=/bin/kill -HUP $MAINPID
+
+[Install]
+WantedBy=multi-user.target
diff --git a/contrib/try-all-ns/README b/contrib/try-all-ns/README
new file mode 100755
index 0000000..224d554
--- /dev/null
+++ b/contrib/try-all-ns/README
@@ -0,0 +1,19 @@
+Date: Thu, 07 Dec 2006 00:41:43 -0500
+From: Bob Carroll <bob.carroll@rit.edu>
+Subject: dnsmasq suggestion
+To: simon@thekelleys.org.uk
+
+
+Hello,
+
+I recently needed a feature in dnsmasq for a very bizarre situation. I 
+placed a list of name servers in a special resolve file and told dnsmasq 
+to use that. But I wanted it to try requests in order and treat NXDOMAIN 
+requests as a failed tcp connection. I wrote the feature into dnsmasq 
+and it seems to work. I prepared a patch in the event that others might 
+find it useful as well.
+
+Thanks and keep up the good work.
+
+--Bob
+
diff --git a/contrib/try-all-ns/README-2.47 b/contrib/try-all-ns/README-2.47
new file mode 100755
index 0000000..bfe4ec7
--- /dev/null
+++ b/contrib/try-all-ns/README-2.47
@@ -0,0 +1,11 @@
+A remake of patch Bob Carroll had posted to dnsmasq,
+now compatible with version 2.47. Hopefully he doesn't 
+mind (sending a copy of this mail to him too).
+
+Maybe the patch in question is not acceptable
+as it doesn't add new switch, rather it binds itself to "strict-order".
+
+What it does is: if you have strict-order in the 
+dnsmasq config file and query a domain that would result 
+in NXDOMAIN, it iterates the whole given nameserver list 
+until the last one says NXDOMAIN.
diff --git a/contrib/try-all-ns/README-2.78 b/contrib/try-all-ns/README-2.78
new file mode 100644
index 0000000..3dfd200
--- /dev/null
+++ b/contrib/try-all-ns/README-2.78
@@ -0,0 +1,10 @@
+Hi,
+I updated the try-all-ns patch to work with the latest version of git. Ended up implementing it on top of master, 2.78test2-7-g63437ff. As that specific if-clause has been changed in the last few commits, it's not compatible for 2.77, sadly.
+
+Find the patch attached.
+
+Regards,
+
+Rasmus Ahlberg
+Software Developer, R&D
+Electrolux Small Appliances
diff --git a/contrib/try-all-ns/dnsmasq-2.35-try-all-ns.patch b/contrib/try-all-ns/dnsmasq-2.35-try-all-ns.patch
new file mode 100755
index 0000000..ec3f3e0
--- /dev/null
+++ b/contrib/try-all-ns/dnsmasq-2.35-try-all-ns.patch
@@ -0,0 +1,61 @@
+diff -Nau dnsmasq-2.35/src/dnsmasq.h dnsmasq/src/dnsmasq.h
+--- dnsmasq-2.35/src/dnsmasq.h	2006-10-18 16:24:50.000000000 -0400
++++ dnsmasq/src/dnsmasq.h	2006-11-16 22:06:31.000000000 -0500
+@@ -112,6 +112,7 @@
+ #define OPT_NO_PING        2097152
+ #define OPT_LEASE_RO       4194304
+ #define OPT_RELOAD         8388608
++#define OPT_TRY_ALL_NS     16777216
+ 
+ struct all_addr {
+   union {
+diff -Nau dnsmasq-2.35/src/forward.c dnsmasq/src/forward.c
+--- dnsmasq-2.35/src/forward.c	2006-10-18 16:24:50.000000000 -0400
++++ dnsmasq/src/forward.c	2006-11-16 22:08:19.000000000 -0500
+@@ -445,6 +445,10 @@
+     {
+        struct server *server = forward->sentto;
+        
++       // If strict-order and try-all-ns are set, treat NXDOMAIN as a failed request
++       if( (daemon->options & OPT_ORDER) && (daemon->options && OPT_TRY_ALL_NS)
++           && header->rcode == NXDOMAIN ) header->rcode = SERVFAIL;
++
+        if ((header->rcode == SERVFAIL || header->rcode == REFUSED) && forward->forwardall == 0)
+ 	 /* for broken servers, attempt to send to another one. */
+ 	 {
+diff -Nau dnsmasq-2.35/src/option.c dnsmasq/src/option.c
+--- dnsmasq-2.35/src/option.c	2006-10-18 16:24:50.000000000 -0400
++++ dnsmasq/src/option.c	2006-11-16 22:10:36.000000000 -0500
+@@ -28,7 +28,7 @@
+ 
+ /* options which don't have a one-char version */
+ #define LOPT_RELOAD 256
+-
++#define LOPT_TRY_ALL_NS 257
+ 
+ #ifdef HAVE_GETOPT_LONG
+ static const struct option opts[] =  
+@@ -102,6 +102,7 @@
+     {"leasefile-ro", 0, 0, '9'},
+     {"dns-forward-max", 1, 0, '0'},
+     {"clear-on-reload", 0, 0, LOPT_RELOAD },
++    {"try-all-ns", 0, 0, LOPT_TRY_ALL_NS },
+     { NULL, 0, 0, 0 }
+   };
+ 
+@@ -134,6 +135,7 @@
+   { '5',            OPT_NO_PING },
+   { '9',            OPT_LEASE_RO },
+   { LOPT_RELOAD,    OPT_RELOAD },
++  { LOPT_TRY_ALL_NS,OPT_TRY_ALL_NS },
+   { 'v',            0},
+   { 'w',            0},
+   { 0, 0 }
+@@ -208,6 +210,7 @@
+   { "-9, --leasefile-ro", gettext_noop("Read leases at startup, but never write the lease file."), NULL },
+   { "-0, --dns-forward-max=<queries>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" }, 
+   { "    --clear-on-reload", gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
++  { "    --try-all-ns", gettext_noop("Try all name servers in tandem on NXDOMAIN replies (use with strict-order)."), NULL },
+   { NULL, NULL, NULL }
+ }; 
+ 
diff --git a/contrib/try-all-ns/dnsmasq-2.47_no_nxdomain_until_end.patch b/contrib/try-all-ns/dnsmasq-2.47_no_nxdomain_until_end.patch
new file mode 100755
index 0000000..7586003
--- /dev/null
+++ b/contrib/try-all-ns/dnsmasq-2.47_no_nxdomain_until_end.patch
@@ -0,0 +1,17 @@
+diff -ur dnsmasq-2.47/src/forward.c dnsmasq-2.47-patched/src/forward.c
+--- dnsmasq-2.47/src/forward.c	2009-02-01 17:59:48.000000000 +0200
++++ dnsmasq-2.47-patched/src/forward.c	2009-03-18 19:10:22.000000000 +0200
+@@ -488,9 +488,12 @@
+     return;
+    
+   server = forward->sentto;
++
++  if ( (header->rcode == NXDOMAIN) && ((daemon->options & OPT_ORDER) != 0) && (server->next != NULL) )
++    header->rcode = SERVFAIL;
+   
+   if ((header->rcode == SERVFAIL || header->rcode == REFUSED) &&
+-      !(daemon->options & OPT_ORDER) &&
++      ((daemon->options & OPT_ORDER) != 0) &&
+       forward->forwardall == 0)
+     /* for broken servers, attempt to send to another one. */
+     {
diff --git a/contrib/try-all-ns/dnsmasq-2.68-try-all-ns b/contrib/try-all-ns/dnsmasq-2.68-try-all-ns
new file mode 100644
index 0000000..66a41f6
--- /dev/null
+++ b/contrib/try-all-ns/dnsmasq-2.68-try-all-ns
@@ -0,0 +1,29 @@
+From: Jesse Glick <jglick@cloudbees.com>
+To: dnsmasq-discuss@lists.thekelleys.org.uk
+Subject: Re: [Dnsmasq-discuss] Ability to delegate to one server but fall
+ back to another after NXDOMAIN?
+
+
+On Wed, Jan 15, 2014 at 12:30 PM, Simon Kelley <simon@thekelleys.org.uk> wrote:
+> > There's a (very old) patch in contrib/try-all-ns that would make a starting point
+This does not apply against trunk, so I tried to rework it. The
+following appears to do what I expect:
+
+diff --git a/src/forward.c b/src/forward.c
+index 8167229..76070b5 100644
+--- a/src/forward.c
++++ b/src/forward.c
+@@ -610,7 +610,11 @@ void reply_query(int fd, int family, time_t now)
+
+   if ((RCODE(header) == SERVFAIL || RCODE(header) == REFUSED) &&
+       !option_bool(OPT_ORDER) &&
+-      forward->forwardall == 0)
++      forward->forwardall == 0 ||
++      /* try each in turn */
++      RCODE(header) == NXDOMAIN &&
++      option_bool(OPT_ORDER) &&
++      server->next != NULL)
+     /* for broken servers, attempt to send to another one. */
+     {
+       unsigned char *pheader;
+
diff --git a/contrib/try-all-ns/dnsmasq-2.78xx-try-all-ns.patch b/contrib/try-all-ns/dnsmasq-2.78xx-try-all-ns.patch
new file mode 100644
index 0000000..700439e
--- /dev/null
+++ b/contrib/try-all-ns/dnsmasq-2.78xx-try-all-ns.patch
@@ -0,0 +1,20 @@
+diff --git a/src/forward.c b/src/forward.c
+index e3fa94b..ecf3b98 100644
+--- a/src/forward.c
++++ b/src/forward.c
+@@ -789,9 +789,12 @@ void reply_query(int fd, int family, time_t now)
+ 
+   /* Note: if we send extra options in the EDNS0 header, we can't recreate
+      the query from the reply. */
+-  if (RCODE(header) == REFUSED &&
+-      forward->forwardall == 0 &&
+-      !(forward->flags & FREC_HAS_EXTRADATA))
++  if ((RCODE(header) == REFUSED &&
++        forward->forwardall == 0 &&
++       !(forward->flags & FREC_HAS_EXTRADATA)) ||
++      /* If strict-order is set, try next server on NXDOMAIN reply */
++      (RCODE(header) == NXDOMAIN && option_bool(OPT_ORDER) &&
++       server->next != NULL))
+     /* for broken servers, attempt to send to another one. */
+     {
+       unsigned char *pheader;
diff --git a/contrib/webmin/README b/contrib/webmin/README
new file mode 100755
index 0000000..2278871
--- /dev/null
+++ b/contrib/webmin/README
@@ -0,0 +1,54 @@
+
+This is the README for the Dnsmasq webmin module.
+
+Problems:
+
+1) There's only basic error checking - if you enter some bad
+addresses or names, they will go straight into the config file
+although we do check for things like IP addresses being of
+the correct form (no letters, 4 groups of up to 3 digits
+separated by dots etc). One thing that ISN'T CHECKED FOR is
+that IP dotted quads are all numbers < 256. Another is that
+netmasks are logical (you could enter a netmask of 255.0.255.0 
+for example). Essentially, if it'll pass the config file
+regex scanner (and the above examples will), it won't be 
+flagged as "bad" even if it is a big no-no for dnsmasq itself. 
+
+2) Code is ugly and a kludge - I ain't a programmer! There are probably 
+a lot of things that could be done to tidy up the code - eg, 
+it probably wouldn't hurt to move some common stuff into the lib file.
+
+3) I've used the %text hash and written an english lang file, but
+I am mono-lingual so no other language support as yet.
+
+4) for reasons unknown to me, the icon does not appear properly
+on the servers page of webmin (at least it doesn't for me!)
+
+5) icons have been shamelessly stolen from the ipfilter module,
+specifically the up and down arrows.
+
+6) if you delete an item, the config file will contain
+an otherwise empty, but commented line. This means that if
+you add some new stuff, then delete it, the config file
+will have a number of lines at the end that are just comments.
+Therefore, the config file could possibly grow quite large.
+
+7) NO INCLUDE FILES!
+if you use an include file, it'll be flagged as an error. 
+OK if the include file line is commented out though.
+
+8) deprecated lines not supported (eg user and group) - they
+may produce an error! (user and group don't, but you can't change
+them)
+
+IOW, it works, it's just not very elegant and not very robust.
+
+Hope you find it useful though - I do, as I prevents me having to ever
+wade through the config file and man pages again.
+
+If you modify it, or add a language file, and you have a spare moment,
+please e-mail me - I won't be upset at all if you fix my poor coding!
+(rather the opposite - I'd be pleased someone found it useful)
+
+Cheers,
+	Neil Fisher <neil@magnecor.com.au>
diff --git a/contrib/webmin/dnsmasq.wbm b/contrib/webmin/dnsmasq.wbm
new file mode 100755
index 0000000..7307e23
--- /dev/null
+++ b/contrib/webmin/dnsmasq.wbm
Binary files differ
diff --git a/contrib/wrt/Makefile b/contrib/wrt/Makefile
new file mode 100755
index 0000000..68e8d32
--- /dev/null
+++ b/contrib/wrt/Makefile
@@ -0,0 +1,6 @@
+CFLAGS?= -O2 -Wall -W
+
+all: dhcp_release dhcp_lease_time
+
+clean:
+	rm -f *~ *.o core dhcp_release dhcp_lease_time
diff --git a/contrib/wrt/README b/contrib/wrt/README
new file mode 100755
index 0000000..981db9f
--- /dev/null
+++ b/contrib/wrt/README
@@ -0,0 +1,81 @@
+This script can be used to implement persistent leases on openWRT, DD-WRT
+etc. Persistent leases are good: if the lease database is lost on a
+reboot, then it will eventually be restored as hosts renew their
+leases. Until a host renews (which may take hours/days) it will
+not exist in the DNS if dnsmasq's DDNS function is in use.
+
+*WRT systems remount all non-volatile filesystems read-only after boot,
+so the normal leasefile will not work. They do, however have NV
+storage, accessed with the nvram command:
+
+/usr/lib #  nvram
+usage: nvram [get name] [set name=value] [unset name] [show]
+
+The principle is that leases are kept in NV variable with data
+corresponding to the line in a leasefile:
+
+dnsmasq_lease_192.168.1.56=3600 00:41:4a:05:80:74 192.168.1.56 * *
+
+By giving dnsmasq the leasefile-ro command, it no longer creates or writes a
+leasefile; responsibility for maintaining the lease database transfers
+to the lease change script. At startup, in leasefile-ro mode,
+dnsmasq will run
+
+"<lease_change_script> init" 
+
+and read whatever that command spits out, expecting it to
+be in dnsmasq leasefile format.
+
+So the lease change script, given "init" as argv[1] will 
+suck existing leases out of the NVRAM and emit them from
+stdout in the correct format.
+
+The second part of the problem is keeping the NVRAM up-to-date: this
+is done by the lease-change script which dnsmasq runs when a lease is
+updated. When it is called with argv[1] as "old", "add", or "del"
+it updates the relevant nvram entry.
+
+So, dnsmasq should be run as :
+
+dnsmasq --leasefile-ro --dhcp-script=/path/to/lease_update.sh
+
+or the same flags added to /etc/dnsmasq.conf
+
+
+
+Notes: 
+
+This needs dnsmasq-2.33 or later to work.
+
+This technique will work with, or without, compilation with
+HAVE_BROKEN_RTC. Compiling with HAVE_BROKEN_RTC is
+_highly_recommended_ for this application since is avoids problems
+with the system clock being warped by NTP, and it vastly reduces the
+number of writes to the NVRAM. With HAVE_BROKEN_RTC, NVRAM is updated
+only when a lease is created or destroyed; without it, a write occurs
+every time a lease is renewed.
+
+It probably makes sense to restrict the number of active DHCP leases
+to an appropriate number using dhcp-lease-max. On a new DD_WRT system,
+there are about 10K bytes free in the NVRAM. Each lease record is
+about 100 bytes, so restricting the number of leases to 50 will limit
+use to half that. (The default limit in the distributed source is 150)
+
+Any UI script which reads the dnsmasq leasefile will have to be
+amended, probably by changing it to read the output of 
+`lease_update init` instead.
+ 
+
+Thanks:
+
+To Steve Horbachuk for checks on the script and debugging beyond the 
+call of duty.
+
+
+Simon Kelley
+Fri Jul 28 11:51:13 BST 2006
+
+
+
+
+
diff --git a/contrib/wrt/dhcp_lease_time.c b/contrib/wrt/dhcp_lease_time.c
new file mode 100755
index 0000000..2866bb5
--- /dev/null
+++ b/contrib/wrt/dhcp_lease_time.c
@@ -0,0 +1,214 @@
+/* Copyright (c) 2007 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.
+*/
+
+/* dhcp_lease_time <address> */
+
+/* Send a DHCPINFORM message to a dnsmasq server running on the local host
+   and print (to stdout) the time remaining in any lease for the given
+   address. The time is given as string printed to stdout.
+
+   If an error occurs or no lease exists for the given address, 
+   nothing is sent to stdout a message is sent to stderr and a
+   non-zero error code is returned.
+
+   Requires dnsmasq 2.40 or later. 
+*/
+
+#include <sys/types.h> 
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <net/if_arp.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <errno.h>
+
+#define DHCP_CHADDR_MAX          16
+#define BOOTREQUEST              1
+#define DHCP_COOKIE              0x63825363
+#define OPTION_PAD               0
+#define OPTION_LEASE_TIME        51
+#define OPTION_OVERLOAD          52
+#define OPTION_MESSAGE_TYPE      53
+#define OPTION_END               255
+#define DHCPINFORM               8
+#define DHCP_SERVER_PORT         67
+
+#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
+#define option_ptr(opt) ((void *)&(((unsigned char *)(opt))[2]))
+
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+struct dhcp_packet {
+  u8 op, htype, hlen, hops;
+  u32 xid;
+  u16 secs, flags;
+  struct in_addr ciaddr, yiaddr, siaddr, giaddr;
+  u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
+  u32 cookie;
+  unsigned char options[308];
+};
+
+static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize)
+{
+  while (*p != OPTION_END) 
+    {
+      if (p >= end)
+        return NULL; /* malformed packet */
+      else if (*p == OPTION_PAD)
+        p++;
+      else 
+        { 
+          int opt_len;
+          if (p >= end - 2)
+            return NULL; /* malformed packet */
+          opt_len = option_len(p);
+          if (p >= end - (2 + opt_len))
+            return NULL; /* malformed packet */
+          if (*p == opt && opt_len >= minsize)
+            return p;
+          p += opt_len + 2;
+        }
+    }
+  
+  return opt == OPTION_END ? p : NULL;
+}
+ 
+static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize)
+{
+  unsigned char *ret, *overload;
+  
+  /* skip over DHCP cookie; */
+  if ((ret = option_find1(&mess->options[0], ((unsigned char *)mess) + size, opt_type, minsize)))
+    return ret;
+
+  /* look for overload option. */
+  if (!(overload = option_find1(&mess->options[0], ((unsigned char *)mess) + size, OPTION_OVERLOAD, 1)))
+    return NULL;
+  
+  /* Can we look in filename area ? */
+  if ((overload[2] & 1) &&
+      (ret = option_find1(&mess->file[0], &mess->file[128], opt_type, minsize)))
+    return ret;
+
+  /* finally try sname area */
+  if ((overload[2] & 2) &&
+      (ret = option_find1(&mess->sname[0], &mess->sname[64], opt_type, minsize)))
+    return ret;
+
+  return NULL;
+}
+
+static unsigned int option_uint(unsigned char *opt, int size)
+{
+  /* this worries about unaligned data and byte order */
+  unsigned int ret = 0;
+  int i;
+  unsigned char *p = option_ptr(opt);
+  
+  for (i = 0; i < size; i++)
+    ret = (ret << 8) | *p++;
+
+  return ret;
+}
+
+int main(int argc, char **argv)
+{ 
+  struct in_addr lease;
+  struct dhcp_packet packet;
+  unsigned char *p = packet.options;
+  struct sockaddr_in dest;
+  int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+  ssize_t rc;
+  
+  if (argc < 2)
+    { 
+      fprintf(stderr, "usage: dhcp_lease_time <address>\n");
+      exit(1);
+    }
+
+  if (fd == -1)
+    {
+      perror("cannot create socket");
+      exit(1);
+    }
+ 
+  lease.s_addr = inet_addr(argv[1]);
+   
+  memset(&packet, 0, sizeof(packet));
+ 
+  packet.hlen = 0;
+  packet.htype = 0;
+
+  packet.op = BOOTREQUEST;
+  packet.ciaddr = lease;
+  packet.cookie = htonl(DHCP_COOKIE);
+
+  *(p++) = OPTION_MESSAGE_TYPE;
+  *(p++) = 1;
+  *(p++) = DHCPINFORM;
+
+  *(p++) = OPTION_END;
+ 
+  dest.sin_family = AF_INET; 
+  dest.sin_addr.s_addr = inet_addr("127.0.0.1");
+  dest.sin_port = ntohs(DHCP_SERVER_PORT);
+  
+  if (sendto(fd, &packet, sizeof(packet), 0, 
+	     (struct sockaddr *)&dest, sizeof(dest)) == -1)
+    {
+      perror("sendto failed");
+      exit(1);
+    }
+
+  alarm(3); /* noddy timeout. */
+
+  rc = recv(fd, &packet, sizeof(packet), 0);
+  
+  if (rc < (ssize_t)(sizeof(packet) - sizeof(packet.options)))
+    {
+      perror("recv failed");
+      exit(1);
+    }
+
+  if ((p = option_find(&packet, (size_t)rc, OPTION_LEASE_TIME, 4)))
+    {
+      unsigned int t = option_uint(p, 4);
+      if (t == 0xffffffff)
+	printf("infinite");
+      else
+	{
+	  unsigned int x;
+	  if ((x = t/86400))
+	    printf("%dd", x);
+	  if ((x = (t/3600)%24))
+	    printf("%dh", x);
+	  if ((x = (t/60)%60))
+	    printf("%dm", x);
+	  if ((x = t%60))
+	    printf("%ds", x);
+	}
+      return 0;
+    }
+
+  return 1; /* no lease */
+}
diff --git a/contrib/wrt/dhcp_release.c b/contrib/wrt/dhcp_release.c
new file mode 100755
index 0000000..c66d3a0
--- /dev/null
+++ b/contrib/wrt/dhcp_release.c
@@ -0,0 +1,331 @@
+/* Copyright (c) 2006 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.
+*/
+
+/* dhcp_release <interface> <address> <MAC address> <client_id>
+   MUST be run as root - will fail otherwise. */
+
+/* Send a DHCPRELEASE message via the specified interface 
+   to tell the local DHCP server to delete a particular lease. 
+   
+   The interface argument is the interface in which a DHCP
+   request _would_ be received if it was coming from the client, 
+   rather than being faked up here.
+   
+   The address argument is a dotted-quad IP addresses and mandatory. 
+   
+   The MAC address is colon separated hex, and is mandatory. It may be 
+   prefixed by an address-type byte followed by -, eg
+
+   10-11:22:33:44:55:66
+
+   but if the address-type byte is missing it is assumed to be 1, the type 
+   for ethernet. This encoding is the one used in dnsmasq lease files.
+
+   The client-id is optional. If it is "*" then it treated as being missing.
+*/
+
+#include <sys/types.h> 
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <net/if_arp.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <errno.h>
+
+#define DHCP_CHADDR_MAX          16
+#define BOOTREQUEST              1
+#define DHCP_COOKIE              0x63825363
+#define OPTION_SERVER_IDENTIFIER 54
+#define OPTION_CLIENT_ID         61
+#define OPTION_MESSAGE_TYPE      53
+#define OPTION_END               255
+#define DHCPRELEASE              7
+#define DHCP_SERVER_PORT         67
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+struct dhcp_packet {
+  u8 op, htype, hlen, hops;
+  u32 xid;
+  u16 secs, flags;
+  struct in_addr ciaddr, yiaddr, siaddr, giaddr;
+  u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
+  u32 cookie;
+  unsigned char options[308];
+};
+
+static struct iovec iov;
+
+static int expand_buf(struct iovec *iov, size_t size)
+{
+  void *new;
+
+  if (size <= iov->iov_len)
+    return 1;
+
+  if (!(new = malloc(size)))
+    {
+      errno = ENOMEM;
+      return 0;
+    }
+
+  if (iov->iov_base)
+    {
+      memcpy(new, iov->iov_base, iov->iov_len);
+      free(iov->iov_base);
+    }
+
+  iov->iov_base = new;
+  iov->iov_len = size;
+
+  return 1;
+}
+
+static ssize_t netlink_recv(int fd)
+{
+  struct msghdr msg;
+  ssize_t rc;
+
+  msg.msg_control = NULL;
+  msg.msg_controllen = 0;
+  msg.msg_name = NULL;
+  msg.msg_namelen = 0;
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+    
+  while (1)
+    {
+      msg.msg_flags = 0;
+      while ((rc = recvmsg(fd, &msg, MSG_PEEK)) == -1 && errno == EINTR);
+      
+      /* 2.2.x doesn't suport MSG_PEEK at all, returning EOPNOTSUPP, so we just grab a 
+         big buffer and pray in that case. */
+      if (rc == -1 && errno == EOPNOTSUPP)
+        {
+          if (!expand_buf(&iov, 2000))
+            return -1;
+          break;
+        }
+      
+      if (rc == -1 || !(msg.msg_flags & MSG_TRUNC))
+        break;
+            
+      if (!expand_buf(&iov, iov.iov_len + 100))
+        return -1;
+    }
+
+  /* finally, read it for real */
+  while ((rc = recvmsg(fd, &msg, 0)) == -1 && errno == EINTR);
+  
+  return rc;
+}
+
+static int parse_hex(char *in, unsigned char *out, int maxlen, int *mac_type)
+{
+  int i = 0;
+  char *r;
+    
+  if (mac_type)
+    *mac_type = 0;
+  
+  while (maxlen == -1 || i < maxlen)
+    {
+      for (r = in; *r != 0 && *r != ':' && *r != '-'; r++);
+      if (*r == 0)
+        maxlen = i;
+      
+      if (r != in )
+        {
+          if (*r == '-' && i == 0 && mac_type)
+           {
+              *r = 0;
+              *mac_type = strtol(in, NULL, 16);
+              mac_type = NULL;
+           }
+          else
+            {
+              *r = 0;
+	      out[i] = strtol(in, NULL, 16);
+              i++;
+            }
+        }
+      in = r+1;
+    }
+    return i;
+}
+
+static int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
+{
+  return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
+}
+
+static struct in_addr find_interface(struct in_addr client, int fd, int index)
+{
+  struct sockaddr_nl addr;
+  struct nlmsghdr *h;
+  ssize_t len;
+ 
+  struct {
+    struct nlmsghdr nlh;
+    struct rtgenmsg g; 
+  } req;
+
+  addr.nl_family = AF_NETLINK;
+  addr.nl_pad = 0;
+  addr.nl_groups = 0;
+  addr.nl_pid = 0; /* address to kernel */
+
+  req.nlh.nlmsg_len = sizeof(req);
+  req.nlh.nlmsg_type = RTM_GETADDR;
+  req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST | NLM_F_ACK; 
+  req.nlh.nlmsg_pid = 0;
+  req.nlh.nlmsg_seq = 1;
+  req.g.rtgen_family = AF_INET; 
+
+  if (sendto(fd, (void *)&req, sizeof(req), 0, 
+	     (struct sockaddr *)&addr, sizeof(addr)) == -1)
+    {
+      perror("sendto failed");
+      exit(1);
+    }
+  
+  while (1)
+    {
+      if ((len = netlink_recv(fd)) == -1)
+	{
+	  perror("netlink");
+	  exit(1);
+	}
+
+      for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
+	if (h->nlmsg_type == NLMSG_DONE)
+	  exit(0);
+	else if (h->nlmsg_type == RTM_NEWADDR)
+          {
+            struct ifaddrmsg *ifa = NLMSG_DATA(h);  
+            struct rtattr *rta;
+            unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa));
+            
+            if (ifa->ifa_index == index && ifa->ifa_family == AF_INET)
+              {
+                struct in_addr netmask, addr;
+                
+                netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
+                addr.s_addr = 0;
+                
+                for (rta = IFA_RTA(ifa); RTA_OK(rta, len1); rta = RTA_NEXT(rta, len1))
+		  if (rta->rta_type == IFA_LOCAL)
+		    addr = *((struct in_addr *)(rta+1));
+		
+                if (addr.s_addr && is_same_net(addr, client, netmask))
+		  return addr;
+	      }
+	  }
+    }
+ 
+  exit(0);
+}
+
+int main(int argc, char **argv)
+{ 
+  struct in_addr server, lease;
+  int mac_type;
+  struct dhcp_packet packet;
+  unsigned char *p = packet.options;
+  struct sockaddr_in dest;
+  struct ifreq ifr;
+  int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+  int nl = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  struct iovec iov;
+ 
+  iov.iov_len = 200;
+  iov.iov_base = malloc(iov.iov_len);
+
+  if (argc < 4 || argc > 5)
+    { 
+      fprintf(stderr, "usage: dhcp_release <interface> <addr> <mac> [<client_id>]\n");
+      exit(1);
+    }
+
+  if (fd == -1 || nl == -1)
+    {
+      perror("cannot create socket");
+      exit(1);
+    }
+  
+  /* This voodoo fakes up a packet coming from the correct interface, which really matters for 
+     a DHCP server */
+  strcpy(ifr.ifr_name, argv[1]);
+  if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1)
+    {
+      perror("cannot setup interface");
+      exit(1);
+    }
+  
+  
+  lease.s_addr = inet_addr(argv[2]);
+  server = find_interface(lease, nl, if_nametoindex(argv[1]));
+  
+  memset(&packet, 0, sizeof(packet));
+ 
+  packet.hlen = parse_hex(argv[3], packet.chaddr, DHCP_CHADDR_MAX, &mac_type);
+  if (mac_type == 0)
+    packet.htype = ARPHRD_ETHER;
+  else
+    packet.htype = mac_type;
+
+  packet.op = BOOTREQUEST;
+  packet.ciaddr = lease;
+  packet.cookie = htonl(DHCP_COOKIE);
+
+  *(p++) = OPTION_MESSAGE_TYPE;
+  *(p++) = 1;
+  *(p++) = DHCPRELEASE;
+
+  *(p++) = OPTION_SERVER_IDENTIFIER;
+  *(p++) = sizeof(server);
+  memcpy(p, &server, sizeof(server));
+  p += sizeof(server);
+
+  if (argc == 5 && strcmp(argv[4], "*") != 0)
+    {
+      unsigned int clid_len = parse_hex(argv[4], p+2, 255, NULL);
+      *(p++) = OPTION_CLIENT_ID;
+      *(p++) = clid_len;
+      p += clid_len;
+    }
+  
+  *(p++) = OPTION_END;
+ 
+  dest.sin_family = AF_INET;
+  dest.sin_port = ntohs(DHCP_SERVER_PORT);
+  dest.sin_addr = server;
+
+  if (sendto(fd, &packet, sizeof(packet), 0, 
+	     (struct sockaddr *)&dest, sizeof(dest)) == -1)
+    {
+      perror("sendto failed");
+      exit(1);
+    }
+
+  return 0;
+}
diff --git a/contrib/wrt/lease_update.sh b/contrib/wrt/lease_update.sh
new file mode 100755
index 0000000..46509b3
--- /dev/null
+++ b/contrib/wrt/lease_update.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+# Copyright (c) 2006 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.
+
+
+# if $1 is add del or old, this is a dnsmasq-called lease-change
+# script, update the nvram database. if $1 is init, emit a 
+# dnsmasq-format lease file to stdout representing the current state of the 
+# database, this is called by dnsmasq at startup.
+
+NVRAM=/usr/sbin/nvram
+PREFIX=dnsmasq_lease_
+
+# Arguments.
+# $1 is action (add, del, old)
+# $2 is MAC 
+# $3 is address
+# $4 is hostname (optional, may be unset)
+
+# env.
+# DNSMASQ_LEASE_LENGTH or DNSMASQ_LEASE_EXPIRES (which depends on HAVE_BROKEN_RTC)
+# DNSMASQ_CLIENT_ID (optional, may be unset)
+
+# File.
+# length|expires MAC addr hostname|* CLID|* 
+
+# Primary key is address.
+
+if [ ${1} = init ] ; then
+     ${NVRAM} show | sed -n -e "/^${PREFIX}.*/ s/^.*=//p"
+else
+     if [ ${1} = del ] ; then
+          ${NVRAM} unset ${PREFIX}${3}
+     fi
+
+     if [ ${1} = old ] || [ ${1} = add ] ; then
+          ${NVRAM} set ${PREFIX}${3}="${DNSMASQ_LEASE_LENGTH:-}${DNSMASQ_LEASE_EXPIRES:-} ${2} ${3} ${4:-*} ${DNSMASQ_CLIENT_ID:-*}"
+     fi
+     ${NVRAM} commit
+fi
+
+
+
+
+ 
diff --git a/dbus/DBus-interface b/dbus/DBus-interface
new file mode 100755
index 0000000..2db5c30
--- /dev/null
+++ b/dbus/DBus-interface
@@ -0,0 +1,282 @@
+DBus support must be enabled at compile-time and run-time. Ensure 
+that src/config.h contains the line
+
+#define HAVE_DBUS.
+
+and that /etc/dnsmasq.conf contains the line
+
+enable-dbus
+
+Because dnsmasq can operate stand-alone from the DBus, and may need to provide
+service before the dbus daemon is available, it will continue to run
+if the DBus connection is not available at startup. The DBus will be polled 
+every 250ms until a connection is established. Start of polling and final
+connection establishment are both logged. When dnsmasq establishes a
+connection to the dbus, it sends the signal "Up". Anything controlling
+the server settings in dnsmasq should re-invoke the SetServers method
+(q.v.) when it sees this signal. This allows dnsmasq to be restarted
+and avoids startup races with the provider of nameserver information.
+
+
+Dnsmasq provides one service on the DBus: uk.org.thekelleys.dnsmasq
+and a single object: /uk/org/thekelleys/dnsmasq 
+The name of the service may be changed by giving an argument to --enable-dbus.
+
+1. METHODS
+----------
+
+Methods are of the form
+
+uk.org.thekelleys.<method>
+
+Available methods are:
+
+GetVersion
+----------
+Returns a string containing the version of dnsmasq running.
+
+ClearCache
+----------
+Returns nothing. Clears the domain name cache and re-reads
+/etc/hosts. The same as sending dnsmasq a HUP signal.
+
+SetFilterWin2KOption
+--------------------
+Takes boolean, sets or resets the --filterwin2k option.
+
+SetBogusPrivOption
+------------------
+Takes boolean, sets or resets the --bogus-priv option.
+
+SetServers
+----------
+Returns nothing. Takes a set of arguments representing the new
+upstream DNS servers to be used by dnsmasq. IPv4 addresses are
+represented as a UINT32 (in network byte order) and IPv6 addresses
+are represented as sixteen BYTEs (since there is no UINT128 type).
+Each server address may be followed by one or more STRINGS, which are
+the domains for which the preceding server should be used.
+
+Examples.
+
+UINT32: <address1>
+UNIT32: <address2>
+
+is equivalent to
+
+--server=<address1> --server=<address2>
+
+
+UINT32 <address1>
+UINT32 <address2>
+STRING "somedomain.com"
+
+is equivalent to
+
+--server=<address1> --server=/somedomain.com/<address2> 
+
+UINT32 <address1>
+UINT32 <address2>
+STRING "somedomain.com"
+UINT32 <address3>
+STRING "anotherdomain.com"
+STRING "thirddomain.com"
+
+is equivalent to
+
+--server=<address1> 
+--server=/somedomain.com/<address2> 
+--server=/anotherdomain.com/thirddomain.com/<address3>
+
+Am IPv4 address of 0.0.0.0 is interpreted as "no address, local only",
+so
+
+UINT32: <0.0.0.0>
+STRING  "local.domain"
+
+is equivalent to
+
+--local=/local.domain/
+
+
+Each call to SetServers completely replaces the set of servers
+specified by via the DBus, but it leaves any servers specified via the
+command line or /etc/dnsmasq.conf or /etc/resolv.conf alone.
+
+SetServersEx
+------------
+
+This function is more flexible and the SetServers function, in that it can
+handle address scoping, port numbers, and is easier for clients to use.
+
+Returns nothing. Takes a set of arguments representing the new
+upstream DNS servers to be used by dnsmasq. All addresses (both IPv4 and IPv6)
+are represented as STRINGS.  Each server address may be followed by one or more
+STRINGS, which are the domains for which the preceding server should be used.
+
+This function takes an array of STRING arrays, where each inner array represents
+a set of DNS servers and domains for which those servers may be used.  Each
+string represents a list of upstream DNS servers first, and domains second.
+Mixing of domains and servers within a the string array is not allowed.
+
+Examples.
+
+[
+  ["1.2.3.4", "foobar.com"],
+  ["1003:1234:abcd::1%eth0", "eng.mycorp.com", "lab.mycorp.com"]
+]
+
+is equivalent to
+
+--server=/foobar.com/1.2.3.4 \
+  --server=/eng.mycorp.com/lab.mycorp.com/1003:1234:abcd::1%eth0
+
+An IPv4 address of 0.0.0.0 is interpreted as "no address, local only",
+so
+
+[ ["0.0.0.0", "local.domain"] ]
+
+is equivalent to
+
+--local=/local.domain/
+
+
+Each call to SetServersEx completely replaces the set of servers
+specified by via the DBus, but it leaves any servers specified via the
+command line or /etc/dnsmasq.conf or /etc/resolv.conf alone.
+
+
+SetDomainServers
+----------------
+
+Yes another variation for setting DNS servers, with the capability of
+SetServersEx, but without using arrays of arrays, which are not
+sendable with dbus-send. The arguments are an array of strings which
+are identical to the equivalent arguments --server, so the example
+for SetServersEx is represented as
+
+[
+  "/foobar.com/1.2.3.4"
+  "/eng.mycorp.com/lab.mycorp.com/1003:1234:abcd::1%eth0"
+]
+
+GetLoopServers
+--------------
+
+(Only available if dnsmasq compiled with HAVE_LOOP)
+
+Return an array of strings, each string is the IP address of an upstream
+server which has been found to loop queries back to this dnsmasq instance, and 
+it therefore not being used.
+
+AddDhcpLease
+------------
+
+Returns nothing. Adds or updates a DHCP or DHCPv6 lease to the internal lease
+database, as if a client requested and obtained a lease.
+
+If a lease for the IPv4 or IPv6 address already exist, it is overwritten.
+
+Note that this function will trigger the DhcpLeaseAdded or DhcpLeaseUpdated
+D-Bus signal and will run the configured DHCP lease script accordingly.
+
+This function takes many arguments which are the lease parameters:
+- A string with the textual representation of the IPv4 or IPv6 address of the
+  client.
+
+  Examples:
+  "192.168.1.115"
+  "1003:1234:abcd::1%eth0"
+  "2001:db8:abcd::1"
+
+- A string representing the hardware address of the client, using the same
+  format as the one used in the lease database.
+
+  Examples:
+
+  "00:23:45:67:89:ab"
+  "06-00:20:e0:3b:13:af" (token ring)
+
+- The hostname of the client, as an array of bytes (so there is no problem
+  with non-ASCII character encoding). May be empty.
+
+  Example (for "hostname.or.fqdn"):
+  [104, 111, 115, 116, 110, 97, 109, 101, 46, 111, 114, 46, 102, 113, 100, 110]
+
+- The client identifier (IPv4) or DUID (IPv6) as an array of bytes. May be
+  empty.
+
+  Examples:
+
+  DHCPv6 DUID:
+  [0, 3, 0, 1, 0, 35, 69, 103, 137, 171]
+  DHCPv4 client identifier:
+  [255, 12, 34, 56, 78, 0, 1, 0, 1, 29, 9, 99, 190, 35, 69, 103, 137, 171]
+
+- The duration of the lease, in seconds. If the lease is updated, then
+  the duration replaces the previous duration.
+
+  Example:
+
+  7200
+
+- The IAID (Identity association identifier) of the DHCPv6 lease, as a network
+  byte-order unsigned integer. For DHCPv4 leases, this must be set to 0.
+
+  Example (for IPv6):
+
+  203569230
+
+- A boolean which, if true, indicates that the DHCPv6 lease is for a temporary
+  address (IA_TA). If false, the DHCPv6 lease is for a non-temporary address
+  (IA_NA). For DHCPv4 leases, this must be set to false.
+
+RemoveDhcpLease
+---------------
+
+Returns nothing. Removes a DHCP or DHCPv6 lease to the internal lease
+database, as if a client sent a release message to abandon a lease.
+
+This function takes only one parameter: the text representation of the
+IPv4 or IPv6 address of the lease to remove.
+
+Note that this function will trigger the DhcpLeaseRemoved signal and the
+configured DHCP lease script will be run with the "del" action.
+
+
+
+2. SIGNALS
+----------
+
+If dnsmasq's DHCP server is active, it will send signals over DBUS whenever
+the DHCP lease database changes. Think of these signals as transactions on
+a database with the IP address acting as the primary key.
+
+Signals are of the form:
+
+uk.org.thekelleys.<signal>
+
+and their parameters are:
+
+STRING "192.168.1.115"
+STRING "01:23:45:67:89:ab"
+STRING "hostname.or.fqdn"
+
+
+Available signals are:
+
+DhcpLeaseAdded
+---------------
+
+This signal is emitted when a DHCP lease for a given IP address is created.
+
+DhcpLeaseDeleted
+----------------
+
+This signal is emitted when a DHCP lease for a given IP address is deleted.
+
+DhcpLeaseUpdated
+----------------
+
+This signal is emitted when a DHCP lease for a given IP address is updated.
+ 
diff --git a/dbus/dnsmasq.conf b/dbus/dnsmasq.conf
new file mode 100755
index 0000000..82b1c76
--- /dev/null
+++ b/dbus/dnsmasq.conf
@@ -0,0 +1,14 @@
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+	<policy user="root">
+		<allow own="uk.org.thekelleys.dnsmasq"/>
+		<allow send_destination="uk.org.thekelleys.dnsmasq"/>
+	</policy>
+	<policy context="default">
+                <deny own="uk.org.thekelleys.dnsmasq"/>
+                <deny send_destination="uk.org.thekelleys.dnsmasq"/>
+        </policy>
+</busconfig>
+
diff --git a/dnsmasq.conf.example b/dnsmasq.conf.example
new file mode 100755
index 0000000..790eaf5
--- /dev/null
+++ b/dnsmasq.conf.example
@@ -0,0 +1,666 @@
+# Configuration file for dnsmasq.
+#
+# Format is one option per line, legal options are the same
+# as the long options legal on the command line. See
+# "/usr/sbin/dnsmasq --help" or "man 8 dnsmasq" for details.
+
+# Listen on this specific port instead of the standard DNS port
+# (53). Setting this to zero completely disables DNS function,
+# leaving only DHCP and/or TFTP.
+#port=5353
+
+# The following two options make you a better netizen, since they
+# tell dnsmasq to filter out queries which the public DNS cannot
+# answer, and which load the servers (especially the root servers)
+# unnecessarily. If you have a dial-on-demand link they also stop
+# these requests from bringing up the link unnecessarily.
+
+# Never forward plain names (without a dot or domain part)
+#domain-needed
+# Never forward addresses in the non-routed address spaces.
+#bogus-priv
+
+# Uncomment these to enable DNSSEC validation and caching:
+# (Requires dnsmasq to be built with DNSSEC option.)
+#conf-file=%%PREFIX%%/share/dnsmasq/trust-anchors.conf
+#dnssec
+
+# Replies which are not DNSSEC signed may be legitimate, because the domain
+# is unsigned, or may be forgeries. Setting this option tells dnsmasq to
+# check that an unsigned reply is OK, by finding a secure proof that a DS 
+# record somewhere between the root and the domain does not exist. 
+# The cost of setting this is that even queries in unsigned domains will need
+# one or more extra DNS queries to verify.
+#dnssec-check-unsigned
+
+# Uncomment this to filter useless windows-originated DNS requests
+# which can trigger dial-on-demand links needlessly.
+# Note that (amongst other things) this blocks all SRV requests,
+# so don't use it if you use eg Kerberos, SIP, XMMP or Google-talk.
+# This option only affects forwarding, SRV records originating for
+# dnsmasq (via srv-host= lines) are not suppressed by it.
+#filterwin2k
+
+# Change this line if you want dns to get its upstream servers from
+# 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 from this file instead (see below), then
+# uncomment this.
+#no-resolv
+
+# If you don't want dnsmasq to poll /etc/resolv.conf or other resolv
+# files for changes and re-read them then uncomment this.
+#no-poll
+
+# Add other name servers here, with domain specs if they are for
+# non-public domains.
+#server=/localnet/192.168.0.1
+
+# Example of routing PTR queries to nameservers: this will send all
+# address->name queries for 192.168.3/24 to nameserver 10.1.2.3
+#server=/3.168.192.in-addr.arpa/10.1.2.3
+
+# Add local-only domains here, queries in these domains are answered
+# from /etc/hosts or DHCP only.
+#local=/localnet/
+
+# Add domains which you want to force to an IP address here.
+# The example below send any host in double-click.net to a local
+# web-server.
+#address=/double-click.net/127.0.0.1
+
+# --address (and --server) work with IPv6 addresses too.
+#address=/www.thekelleys.org.uk/fe80::20d:60ff:fe36:f83
+
+# Add the IPs of all queries to yahoo.com, google.com, and their
+# subdomains to the vpn and search ipsets:
+#ipset=/yahoo.com/google.com/vpn,search
+
+# You can control how dnsmasq talks to a server: this forces
+# queries to 10.1.2.3 to be routed via eth1
+# server=10.1.2.3@eth1
+
+# and this sets the source (ie local) address used to talk to
+# 10.1.2.3 to 192.168.1.1 port 55 (there must be a interface with that
+# IP on the machine, obviously).
+# server=10.1.2.3@192.168.1.1#55
+
+# If you want dnsmasq to change uid and gid to something other
+# than the default, edit the following lines.
+#user=
+#group=
+
+# If you want dnsmasq to listen for DHCP and DNS requests only on
+# specified interfaces (and the loopback) give the name of the
+# interface (eg eth0) here.
+# Repeat the line for more than one interface.
+#interface=
+# Or you can specify which interface _not_ to listen on
+#except-interface=
+# Or which to listen on by address (remember to include 127.0.0.1 if
+# you use this.)
+#listen-address=
+# If you want dnsmasq to provide only DNS service on an interface,
+# configure it as shown above, and then use the following line to
+# disable DHCP and TFTP on it.
+#no-dhcp-interface=
+
+# On systems which support it, dnsmasq binds the wildcard address,
+# even when it is listening on only some interfaces. It then discards
+# requests that it shouldn't reply to. This has the advantage of
+# working even when interfaces come and go and change address. If you
+# want dnsmasq to really bind only the interfaces it is listening on,
+# uncomment this option. About the only time you may need this is when
+# running another nameserver on the same machine.
+#bind-interfaces
+
+# If you don't want dnsmasq to read /etc/hosts, uncomment the
+# following line.
+#no-hosts
+# or if you want it to read another file, as well as /etc/hosts, use
+# this.
+#addn-hosts=/etc/banner_add_hosts
+
+# Set this (and domain: see below) if you want to have a domain
+# automatically added to simple names in a hosts-file.
+#expand-hosts
+
+# Set the domain for dnsmasq. this is optional, but if it is set, it
+# does the following things.
+# 1) Allows DHCP hosts to have fully qualified domain names, as long
+#     as the domain part matches this setting.
+# 2) Sets the "domain" DHCP option thereby potentially setting the
+#    domain of all systems configured by DHCP
+# 3) Provides the domain part for "expand-hosts"
+#domain=thekelleys.org.uk
+
+# Set a different domain for a particular subnet
+#domain=wireless.thekelleys.org.uk,192.168.2.0/24
+
+# Same idea, but range rather then subnet
+#domain=reserved.thekelleys.org.uk,192.68.3.100,192.168.3.200
+
+# Uncomment this to enable the integrated DHCP server, you need
+# to supply the range of addresses available for lease and optionally
+# a lease time. If you have more than one network, you will need to
+# repeat this for each network on which you want to supply DHCP
+# service.
+#dhcp-range=192.168.0.50,192.168.0.150,12h
+
+# This is an example of a DHCP range where the netmask is given. This
+# is needed for networks we reach the dnsmasq DHCP server via a relay
+# agent. If you don't know what a DHCP relay agent is, you probably
+# don't need to worry about this.
+#dhcp-range=192.168.0.50,192.168.0.150,255.255.255.0,12h
+
+# This is an example of a DHCP range which sets a tag, so that
+# some DHCP options may be set only for this network.
+#dhcp-range=set:red,192.168.0.50,192.168.0.150
+
+# Use this DHCP range only when the tag "green" is set.
+#dhcp-range=tag:green,192.168.0.50,192.168.0.150,12h
+
+# Specify a subnet which can't be used for dynamic address allocation,
+# is available for hosts with matching --dhcp-host lines. Note that
+# dhcp-host declarations will be ignored unless there is a dhcp-range
+# of some type for the subnet in question.
+# In this case the netmask is implied (it comes from the network
+# configuration on the machine running dnsmasq) it is possible to give
+# an explicit netmask instead.
+#dhcp-range=192.168.0.0,static
+
+# Enable DHCPv6. Note that the prefix-length does not need to be specified
+# and defaults to 64 if missing/
+#dhcp-range=1234::2, 1234::500, 64, 12h
+
+# Do Router Advertisements, BUT NOT DHCP for this subnet.
+#dhcp-range=1234::, ra-only 
+
+# Do Router Advertisements, BUT NOT DHCP for this subnet, also try and
+# add names to the DNS for the IPv6 address of SLAAC-configured dual-stack 
+# hosts. Use the DHCPv4 lease to derive the name, network segment and 
+# MAC address and assume that the host will also have an
+# IPv6 address calculated using the SLAAC algorithm.
+#dhcp-range=1234::, ra-names
+
+# Do Router Advertisements, BUT NOT DHCP for this subnet.
+# Set the lifetime to 46 hours. (Note: minimum lifetime is 2 hours.)
+#dhcp-range=1234::, ra-only, 48h
+
+# Do DHCP and Router Advertisements for this subnet. Set the A bit in the RA
+# so that clients can use SLAAC addresses as well as DHCP ones.
+#dhcp-range=1234::2, 1234::500, slaac
+
+# Do Router Advertisements and stateless DHCP for this subnet. Clients will
+# not get addresses from DHCP, but they will get other configuration information.
+# They will use SLAAC for addresses.
+#dhcp-range=1234::, ra-stateless
+
+# Do stateless DHCP, SLAAC, and generate DNS names for SLAAC addresses
+# from DHCPv4 leases.
+#dhcp-range=1234::, ra-stateless, ra-names
+
+# Do router advertisements for all subnets where we're doing DHCPv6
+# Unless overridden by ra-stateless, ra-names, et al, the router 
+# advertisements will have the M and O bits set, so that the clients
+# get addresses and configuration from DHCPv6, and the A bit reset, so the 
+# clients don't use SLAAC addresses.
+#enable-ra
+
+# Supply parameters for specified hosts using DHCP. There are lots
+# 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. The order of the parameters in these
+# do not matter, it's permissible to give name, address 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
+#dhcp-host=11:22:33:44:55:66,192.168.0.60
+
+# Always set the name of the host with hardware address
+# 11:22:33:44:55:66 to be "fred"
+#dhcp-host=11:22:33:44:55:66,fred
+
+# Always give the host with Ethernet address 11:22:33:44:55:66
+# the name fred and IP address 192.168.0.60 and lease time 45 minutes
+#dhcp-host=11:22:33:44:55:66,fred,192.168.0.60,45m
+
+# Give a host with Ethernet address 11:22:33:44:55:66 or
+# 12:34:56:78:90:12 the IP address 192.168.0.60. Dnsmasq will assume
+# that these two Ethernet interfaces will never be in use at the same
+# time, and give the IP address to the second, even if it is already
+# in use by the first. Useful for laptops with wired and wireless
+# addresses.
+#dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.60
+
+# Give the machine which says its name is "bert" IP address
+# 192.168.0.70 and an infinite lease
+#dhcp-host=bert,192.168.0.70,infinite
+
+# Always give the host with client identifier 01:02:02:04
+# the IP address 192.168.0.60
+#dhcp-host=id:01:02:02:04,192.168.0.60
+
+# Always give the InfiniBand interface with hardware address
+# 80:00:00:48:fe:80:00:00:00:00:00:00:f4:52:14:03:00:28:05:81 the
+# ip address 192.168.0.61. The client id is derived from the prefix
+# ff:00:00:00:00:00:02:00:00:02:c9:00 and the last 8 pairs of
+# hex digits of the hardware address.
+#dhcp-host=id:ff:00:00:00:00:00:02:00:00:02:c9:00:f4:52:14:03:00:28:05:81,192.168.0.61
+
+# Always give the host with client identifier "marjorie"
+# 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
+
+# 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
+
+# Ignore any client-id presented by the machine with Ethernet
+# address 11:22:33:44:55:66. This is useful to prevent a machine
+# being treated differently when running under different OS's or
+# between PXE boot and OS boot.
+#dhcp-host=11:22:33:44:55:66,id:*
+
+# 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,set:red
+
+# Send extra options which are tagged as "red" to
+# any machine with Ethernet address starting 11:22:33:
+#dhcp-host=11:22:33:*:*:*,set:red
+
+# Give a fixed IPv6 address and name to client with 
+# DUID 00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2
+# Note the MAC addresses CANNOT be used to identify DHCPv6 clients.
+# Note also the they [] around the IPv6 address are obligatory.
+#dhcp-host=id:00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2, fred, [1234::5] 
+
+# Ignore any clients which are not specified in dhcp-host lines
+# or /etc/ethers. Equivalent to ISC "deny unknown-clients".
+# This relies on the special "known" tag which is set when
+# a host is matched.
+#dhcp-ignore=tag:!known
+
+# Send extra options which are tagged as "red" to any machine whose
+# DHCP vendorclass string includes the substring "Linux"
+#dhcp-vendorclass=set:red,Linux
+
+# Send extra options which are tagged as "red" to any machine one
+# of whose DHCP userclass strings includes the substring "accounts"
+#dhcp-userclass=set:red,accounts
+
+# Send extra options which are tagged as "red" to any machine whose
+# MAC address matches the pattern.
+#dhcp-mac=set:red,00:60:8C:*:*:*
+
+# 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
+# MAC-address/host mappings there for other purposes.
+#read-ethers
+
+# Send options to hosts which ask for a DHCP lease.
+# See RFC 2132 for details of available options.
+# Common options can be given to dnsmasq by name:
+# run "dnsmasq --help dhcp" to get a list.
+# 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 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.
+
+# Override the default route supplied by dnsmasq, which assumes the
+# router is the same machine as the one running dnsmasq.
+#dhcp-option=3,1.2.3.4
+
+# Do the same thing, but using the option name
+#dhcp-option=option:router,1.2.3.4
+
+# Override the default route supplied by dnsmasq and send no default
+# route at all. Note that this only works for the options sent by
+# default (1, 3, 6, 12, 28) the same line will send a zero-length option
+# for all other option numbers.
+#dhcp-option=3
+
+# Set the NTP time server addresses to 192.168.0.4 and 10.10.0.5
+#dhcp-option=option:ntp-server,192.168.0.4,10.10.0.5
+
+# Send DHCPv6 option. Note [] around IPv6 addresses.
+#dhcp-option=option6:dns-server,[1234::77],[1234::88]
+
+# Send DHCPv6 option for namservers as the machine running 
+# dnsmasq and another.
+#dhcp-option=option6:dns-server,[::],[1234::88]
+
+# Ask client to poll for option changes every six hours. (RFC4242)
+#dhcp-option=option6:information-refresh-time,6h
+
+# Set option 58 client renewal time (T1). Defaults to half of the
+# lease time if not specified. (RFC2132)
+#dhcp-option=option:T1:1m
+
+# Set option 59 rebinding time (T2). Defaults to 7/8 of the
+# lease time if not specified. (RFC2132)
+#dhcp-option=option:T2:2m
+
+# 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
+
+# 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)
+# Note that the tag: part must precede the option: part.
+#dhcp-option = tag:red, option:ntp-server, 192.168.1.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 some or all of 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
+
+# Send an empty WPAD option. This may be REQUIRED to get windows 7 to behave.
+#dhcp-option=252,"\n"
+
+# Send RFC-3397 DNS domain search DHCP option. WARNING: Your DHCP client
+# probably doesn't support this......
+#dhcp-option=option:domain-search,eng.apple.com,marketing.apple.com
+
+# Send RFC-3442 classless static routes (note the netmask encoding)
+#dhcp-option=121,192.168.1.0/24,1.2.3.4,10.0.0.0/8,5.6.7.8
+
+# Send vendor-class specific options encapsulated in DHCP option 43.
+# The meaning of the options is defined by the vendor-class so
+# options are sent only when the client supplied vendor class
+# matches the class given here. (A substring match is OK, so "MSFT"
+# matches "MSFT" and "MSFT 5.0"). This example sets the
+# mtftp address to 0.0.0.0 for PXEClients.
+#dhcp-option=vendor:PXEClient,1,0.0.0.0
+
+# Send microsoft-specific option to tell windows to release the DHCP lease
+# when it shuts down. Note the "i" flag, to tell dnsmasq to send the
+# value as a four-byte integer - that's what microsoft wants. See
+# http://technet2.microsoft.com/WindowsServer/en/library/a70f1bb7-d2d4-49f0-96d6-4b7414ecfaae1033.mspx?mfr=true
+#dhcp-option=vendor:MSFT,2,1i
+
+# Send the Encapsulated-vendor-class ID needed by some configurations of
+# Etherboot to allow is to recognise the DHCP server.
+#dhcp-option=vendor:Etherboot,60,"Etherboot"
+
+# Send options to PXELinux. Note that we need to send the options even
+# though they don't appear in the parameter request list, so we need
+# to use dhcp-option-force here.
+# See http://syslinux.zytor.com/pxe.php#special for details.
+# Magic number - needed before anything else is recognised
+#dhcp-option-force=208,f1:00:74:7e
+# Configuration file name
+#dhcp-option-force=209,configs/common
+# Path prefix
+#dhcp-option-force=210,/tftpboot/pxelinux/files/
+# Reboot time. (Note 'i' to send 32-bit value)
+#dhcp-option-force=211,30i
+
+# Set the boot filename for netboot/PXE. You will only need
+# this is you want to boot machines over the network and you will need
+# a TFTP server; either dnsmasq's built in TFTP server or an
+# external one. (See below for how to enable the TFTP server.)
+#dhcp-boot=pxelinux.0
+
+# The same as above, but use custom tftp-server instead machine running dnsmasq
+#dhcp-boot=pxelinux,server.name,192.168.1.100
+
+# Boot for Etherboot gPXE. The idea is to send two different
+# filenames, the first loads gPXE, and the second tells gPXE what to
+# load. The dhcp-match sets the gpxe tag for requests from gPXE.
+#dhcp-match=set:gpxe,175 # gPXE sends a 175 option.
+#dhcp-boot=tag:!gpxe,undionly.kpxe
+#dhcp-boot=mybootimage
+
+# Encapsulated options for Etherboot gPXE. All the options are
+# encapsulated within option 175
+#dhcp-option=encap:175, 1, 5b         # priority code
+#dhcp-option=encap:175, 176, 1b       # no-proxydhcp
+#dhcp-option=encap:175, 177, string   # bus-id
+#dhcp-option=encap:175, 189, 1b       # BIOS drive code
+#dhcp-option=encap:175, 190, user     # iSCSI username
+#dhcp-option=encap:175, 191, pass     # iSCSI password
+
+# Test for the architecture of a netboot client. PXE clients are
+# supposed to send their architecture as option 93. (See RFC 4578)
+#dhcp-match=peecees, option:client-arch, 0 #x86-32
+#dhcp-match=itanics, option:client-arch, 2 #IA64
+#dhcp-match=hammers, option:client-arch, 6 #x86-64
+#dhcp-match=mactels, option:client-arch, 7 #EFI x86-64
+
+# Do real PXE, rather than just booting a single file, this is an
+# alternative to dhcp-boot.
+#pxe-prompt="What system shall I netboot?"
+# or with timeout before first available action is taken:
+#pxe-prompt="Press F8 for menu.", 60
+
+# Available boot services. for PXE.
+#pxe-service=x86PC, "Boot from local disk"
+
+# Loads <tftp-root>/pxelinux.0 from dnsmasq TFTP server.
+#pxe-service=x86PC, "Install Linux", pxelinux
+
+# Loads <tftp-root>/pxelinux.0 from TFTP server at 1.2.3.4.
+# Beware this fails on old PXE ROMS.
+#pxe-service=x86PC, "Install Linux", pxelinux, 1.2.3.4
+
+# Use bootserver on network, found my multicast or broadcast.
+#pxe-service=x86PC, "Install windows from RIS server", 1
+
+# Use bootserver at a known IP address.
+#pxe-service=x86PC, "Install windows from RIS server", 1, 1.2.3.4
+
+# If you have multicast-FTP available,
+# information for that can be passed in a similar way using options 1
+# to 5. See page 19 of
+# http://download.intel.com/design/archives/wfm/downloads/pxespec.pdf
+
+
+# Enable dnsmasq's built-in TFTP server
+#enable-tftp
+
+# Set the root directory for files available via FTP.
+#tftp-root=/var/ftpd
+
+# Do not abort if the tftp-root is unavailable
+#tftp-no-fail
+
+# Make the TFTP server more secure: with this set, only files owned by
+# the user dnsmasq is running as will be send over the net.
+#tftp-secure
+
+# This option stops dnsmasq from negotiating a larger blocksize for TFTP
+# transfers. It will slow things down, but may rescue some broken TFTP
+# clients.
+#tftp-no-blocksize
+
+# Set the boot file name only when the "red" tag is set.
+#dhcp-boot=tag:red,pxelinux.red-net
+
+# An example of dhcp-boot with an external TFTP server: the name and IP
+# address of the server are given after the filename.
+# Can fail with old PXE ROMS. Overridden by --pxe-service.
+#dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3
+
+# If there are multiple external tftp servers having a same name
+# (using /etc/hosts) then that name can be specified as the
+# tftp_servername (the third option to dhcp-boot) and in that
+# case dnsmasq resolves this name and returns the resultant IP
+# addresses in round robin fashion. This facility can be used to
+# load balance the tftp load among a set of servers.
+#dhcp-boot=/var/ftpd/pxelinux.0,boothost,tftp_server_name
+
+# Set the limit on DHCP leases, the default is 150
+#dhcp-lease-max=150
+
+# 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/misc/dnsmasq.leases
+
+# Set the DHCP server to authoritative mode. In this mode it will barge in
+# and take over the lease for any client which broadcasts on the network,
+# whether it has a record of the lease or not. This avoids long timeouts
+# when a machine wakes up on a new network. DO NOT enable this if there's
+# the slightest chance that you might end up accidentally configuring a DHCP
+# server for your campus/company accidentally. The ISC server uses
+# the same option, and this URL provides more information:
+# http://www.isc.org/files/auth.html
+#dhcp-authoritative
+
+# Run an executable when a DHCP lease is created or destroyed.
+# The arguments sent to the script are "add" or "del",
+# then the MAC address, the IP address and finally the hostname
+# if there is one.
+#dhcp-script=/bin/echo
+
+# Set the cachesize here.
+#cache-size=150
+
+# If you want to disable negative caching, uncomment this.
+#no-negcache
+
+# Normally responses which come from /etc/hosts and the DHCP lease
+# file have Time-To-Live set as zero, which conventionally means
+# do not cache further. If you are happy to trade lower load on the
+# server for potentially stale date, you can set a time-to-live (in
+# seconds) here.
+#local-ttl=
+
+# If you want dnsmasq to detect attempts by Verisign to send queries
+# to unregistered .com and .net hosts to its sitefinder service and
+# have dnsmasq instead return the correct NXDOMAIN response, uncomment
+# this line. You can add similar lines to do the same for other
+# registries which have implemented wildcard A records.
+#bogus-nxdomain=64.94.110.11
+
+# If you want to fix up DNS results from upstream servers, use the
+# alias option. This only works for IPv4.
+# This alias makes a result of 1.2.3.4 appear as 5.6.7.8
+#alias=1.2.3.4,5.6.7.8
+# 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
+# and this maps 192.168.0.10->192.168.0.40 to 10.0.0.10->10.0.0.40
+#alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0
+
+# Change these lines if you want dnsmasq to serve MX records.
+
+# Return an MX record named "maildomain.com" with target
+# servermachine.com and preference 50
+#mx-host=maildomain.com,servermachine.com,50
+
+# Set the default target for MX records created using the localmx option.
+#mx-target=servermachine.com
+
+# Return an MX record pointing to the mx-target for all local
+# machines.
+#localmx
+
+# Return an MX record pointing to itself for all local machines.
+#selfmx
+
+# Change the following lines if you want dnsmasq to serve SRV
+# records.  These are useful if you want to serve ldap requests for
+# Active Directory and other windows-originated DNS requests.
+# See RFC 2782.
+# You may add multiple srv-host lines.
+# The fields are <name>,<target>,<port>,<priority>,<weight>
+# If the domain part if missing from the name (so that is just has the
+# service and protocol sections) then the domain given by the domain=
+# config option is used. (Note that expand-hosts does not need to be
+# set for this to work.)
+
+# A SRV record sending LDAP for the example.com domain to
+# ldapserver.example.com port 389
+#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389
+
+# A SRV record sending LDAP for the example.com domain to
+# ldapserver.example.com port 389 (using domain=)
+#domain=example.com
+#srv-host=_ldap._tcp,ldapserver.example.com,389
+
+# Two SRV records for LDAP, each with different priorities
+#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,1
+#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,2
+
+# A SRV record indicating that there is no LDAP server for the domain
+# example.com
+#srv-host=_ldap._tcp.example.com
+
+# The following line shows how to make dnsmasq serve an arbitrary PTR
+# record. This is useful for DNS-SD. (Note that the
+# domain-name expansion done for SRV records _does_not
+# occur for PTR records.)
+#ptr-record=_http._tcp.dns-sd-services,"New Employee Page._http._tcp.dns-sd-services"
+
+# Change the following lines to enable dnsmasq to serve TXT records.
+# These are used for things like SPF and zeroconf. (Note that the
+# domain-name expansion done for SRV records _does_not
+# occur for TXT records.)
+
+#Example SPF.
+#txt-record=example.com,"v=spf1 a -all"
+
+#Example zeroconf
+#txt-record=_http._tcp.example.com,name=value,paper=A4
+
+# Provide an alias for a "local" DNS name. Note that this _only_ works
+# for targets which are names from DHCP or /etc/hosts. Give host
+# "bert" another name, bertrand
+#cname=bertand,bert
+
+# For debugging purposes, log each DNS query as it passes through
+# dnsmasq.
+#log-queries
+
+# Log lots of extra information about DHCP transactions.
+#log-dhcp
+
+# Include another lot of configuration options.
+#conf-file=/etc/dnsmasq.more.conf
+#conf-dir=/etc/dnsmasq.d
+
+# Include all the files in a directory except those ending in .bak
+#conf-dir=/etc/dnsmasq.d,.bak
+
+# Include all files in a directory which end in .conf
+#conf-dir=/etc/dnsmasq.d/,*.conf
diff --git a/doc.html b/doc.html
new file mode 100755
index 0000000..26ae731
--- /dev/null
+++ b/doc.html
@@ -0,0 +1,97 @@
+<HTML>
+<HEAD>
+<TITLE> Dnsmasq - network services for small networks.</TITLE>
+<link rel="icon" href="http://www.thekelleys.org.uk/dnsmasq/images/favicon.ico">
+</HEAD>
+<BODY BGCOLOR="WHITE"> 
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+<tr>
+<td align="left" valign="middle"><img border="0" src="http://www.thekelleys.org.uk/dnsmasq/images/icon.png" /></td>
+<td align="middle" valign="middle"><h1>Dnsmasq</h1></td>
+<td align="right" valign="middle"><img border="0" src="http://www.thekelleys.org.uk/dnsmasq/images/icon.png" /></td></tr>
+</table>
+Dnsmasq provides network infrastructure for small networks: DNS, DHCP, router advertisement and network boot. It is designed to be 
+lightweight and have a small footprint, suitable for resource constrained routers and firewalls. It has also been widely used 
+for tethering on smartphones and portable hotspots, and to support virtual networking in virtualisation frameworks.
+Supported platforms include Linux (with glibc and uclibc), Android, *BSD, and Mac OS X. Dnsmasq is included in most
+Linux distributions and the ports systems of FreeBSD, OpenBSD and NetBSD. Dnsmasq provides full IPv6 support.
+
+<P>
+The DNS subsystem provides a local DNS server for the network, with forwarding of all query types to upstream recursive DNS servers and
+caching of common record types (A, AAAA, CNAME and PTR, also DNSKEY and DS when DNSSEC is enabled). 
+<DIR>
+<LI>Local DNS names can be defined by reading /etc/hosts, by importing names from the DHCP subsystem, or by configuration of a wide range of useful record types.</LI>
+<LI>Upstream servers can be configured in a variety of convenient ways, including  dynamic configuration as these change on moving upstream network.
+<LI>Authoritative DNS mode allows local DNS names may be exported to zone in the global DNS. Dnsmasq acts as authoritative server for this zone, and also provides 
+zone transfer to secondaries for the zone, if required.</LI>
+<LI>DNSSEC validation may be performed on DNS replies from upstream nameservers, providing security against spoofing and cache poisoning.</LI>
+<LI>Specified sub-domains can be directed to their own upstream DNS servers, making VPN configuration easy.</LI>
+<LI>Internationalised domain names are supported.
+</DIR>
+<P>
+The DHCP subsystem supports DHCPv4, DHCPv6, BOOTP and PXE.
+<DIR>
+<LI> Both static and dynamic DHCP leases are supported, along with stateless mode in DHCPv6.</LI>
+<LI> The PXE system is a full PXE server, supporting netboot menus and multiple architecture support. It
+includes proxy-mode, where the PXE system co-operates with another DHCP server.</LI>
+<LI> There is a built in read-only TFTP server to support netboot.</LI>
+<LI> Machines which are configured by DHCP have their names automatically 
+included in the DNS and the names can specified by each machine or
+centrally by associating a name with a MAC address or UID in the dnsmasq
+configuration file.</LI>
+</DIR>
+<P>
+The Router Advertisement subsystem provides basic autoconfiguration for IPv6 hosts. It can be used stand-alone or in conjunction with DHCPv6.
+<DIR>
+<LI> The M and O bits are configurable, to control hosts' use of DHCPv6.</LI>
+<LI> Router advertisements can include the RDNSS option.</LI>
+<LI> There is a mode which uses name information from DHCPv4 configuration to provide DNS entries
+ for autoconfigured IPv6 addresses which would otherwise be anonymous.</LI>
+</DIR>
+<P>
+ 
+For extra compactness, unused features may be omitted at compile time.
+
+
+<H2>Get code.</H2>
+
+<A HREF="http://www.thekelleys.org.uk/dnsmasq/">Download</A> dnsmasq here. 
+The tarball includes this documentation, source, and manpage.
+There is also a <A HREF="CHANGELOG"> CHANGELOG</A> and a <A HREF="FAQ">FAQ</A>.
+
+Dnsmasq has a git repository which contains the complete release
+history of version 2 and development history from 2.60. You can 
+<A HREF="http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=summary">browse</A>
+the repo, or get a copy using git protocol with the command
+
+<PRE><TT>git clone git://thekelleys.org.uk/dnsmasq.git </TT></PRE>
+
+<H2>License.</H2>
+Dnsmasq is distributed under the GPL, version 2 or version 3 at your discretion. See the files COPYING and COPYING-v3 in the distribution 
+for details.
+
+<H2>Contact.</H2>
+There is a dnsmasq mailing list at <A
+HREF="http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss">
+http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss</A> which should be the
+first location for queries, bugreports, suggestions etc. The list is mirrored, with a
+search facility, at <A HREF="https://www.mail-archive.com/dnsmasq-discuss@lists.thekelleys.org.uk/">
+https://www.mail-archive.com/dnsmasq-discuss@lists.thekelleys.org.uk/</A>.
+You can contact me at <A
+HREF="mailto:simon@thekelleys.org.uk">simon@thekelleys.org.uk</A>.
+
+<H2>Donations.</H2>
+Dnsmasq is mainly written and maintained by Simon Kelley. For most of its life, dnsmasq has been a spare-time project. 
+These days I'm working on it as my main activity. 
+I don't have an employer or anyone who pays me regularly to work on dnsmasq. If you'd like to make 
+a contribution towards my expenses, please use the donation button below.
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
+<input type="hidden" name="cmd" value="_s-xclick">
+<input type="hidden" name="hosted_button_id" value="V3X9GVW5GX6DA">
+<input type="image" src="https://www.paypalobjects.com/en_US/GB/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal – The safer, easier way to pay online.">
+<img alt="" border="0" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1" height="1">
+</form>
+
+
+</BODY>
+
diff --git a/logo/README b/logo/README
new file mode 100644
index 0000000..05a8250
--- /dev/null
+++ b/logo/README
@@ -0,0 +1,12 @@
+Dnsmasq logo, contributed by Justin Clift.
+
+The source format is Inkscape SVG vector format, which is scalable and
+easy to export to other formats. For convenience I've included a 56x31
+png export and a 16x16 ico suitable for use as a web favicon.
+
+Simon Kelley, 22/10/2010
+
+
+
+
+ 
diff --git a/logo/favicon.ico b/logo/favicon.ico
new file mode 100644
index 0000000..71bc934
--- /dev/null
+++ b/logo/favicon.ico
Binary files differ
diff --git a/logo/icon.png b/logo/icon.png
new file mode 100644
index 0000000..cf48461
--- /dev/null
+++ b/logo/icon.png
Binary files differ
diff --git a/logo/icon.svg b/logo/icon.svg
new file mode 100644
index 0000000..a2f7521
--- /dev/null
+++ b/logo/icon.svg
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   x="0px"
+   y="0px"
+   width="56"
+   height="31"
+   viewBox="0 0 56 31"
+   enable-background="new 0 0 72.833 46.667"
+   xml:space="preserve"
+   id="svg2"
+   inkscape:version="0.47 r22583"
+   sodipodi:docname="dnsmasq_icon.svg"
+   inkscape:export-filename="/x/centos_home/jc/workspace/git_repos/libvirt-media/libvirt-media/png/dnsmasq_icon.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"><metadata
+   id="metadata27"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+   id="defs25"><inkscape:perspective
+   sodipodi:type="inkscape:persp3d"
+   inkscape:vp_x="0 : 23.3335 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_z="72.833 : 23.3335 : 1"
+   inkscape:persp3d-origin="36.4165 : 15.555667 : 1"
+   id="perspective4857" />
+	<filter
+   id="filter3802"
+   inkscape:label="filter1"
+   color-interpolation-filters="sRGB" /><linearGradient
+   inkscape:collect="always"
+   xlink:href="#SVGID_3_"
+   id="linearGradient4929"
+   gradientUnits="userSpaceOnUse"
+   x1="30.564501"
+   y1="-8.8144999"
+   x2="32.937"
+   y2="32.715599" />
+		<linearGradient
+   inkscape:collect="always"
+   xlink:href="#SVGID_3_"
+   id="linearGradient5798"
+   gradientUnits="userSpaceOnUse"
+   x1="30.564501"
+   y1="-8.8144999"
+   x2="32.937"
+   y2="32.715599" /><linearGradient
+   inkscape:collect="always"
+   xlink:href="#SVGID_3_"
+   id="linearGradient5812"
+   gradientUnits="userSpaceOnUse"
+   x1="30.564501"
+   y1="-8.8144999"
+   x2="32.937"
+   y2="32.715599" /><filter
+   id="filter6262"
+   inkscape:label="Drop shadow"
+   width="1.5"
+   height="1.5"
+   x="-0.25"
+   y="-0.25"
+   color-interpolation-filters="sRGB"><feGaussianBlur
+     id="feGaussianBlur6264"
+     in="SourceAlpha"
+     stdDeviation="2.500000"
+     result="blur" /><feColorMatrix
+     id="feColorMatrix6266"
+     result="bluralpha"
+     type="matrix"
+     values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.500000 0 " /><feOffset
+     id="feOffset6268"
+     in="bluralpha"
+     dx="2.700000"
+     dy="2.600000"
+     result="offsetBlur" /><feMerge
+     id="feMerge6270"><feMergeNode
+       id="feMergeNode6272"
+       in="offsetBlur" /><feMergeNode
+       id="feMergeNode6274"
+       in="SourceGraphic" /></feMerge></filter></defs><sodipodi:namedview
+   pagecolor="#ffffff"
+   bordercolor="#666666"
+   borderopacity="1"
+   objecttolerance="10"
+   gridtolerance="10"
+   guidetolerance="10"
+   inkscape:pageopacity="0"
+   inkscape:pageshadow="2"
+   inkscape:window-width="1568"
+   inkscape:window-height="1076"
+   id="namedview23"
+   showgrid="false"
+   inkscape:zoom="8"
+   inkscape:cx="31.966768"
+   inkscape:cy="21.211869"
+   inkscape:window-x="567"
+   inkscape:window-y="328"
+   inkscape:window-maximized="0"
+   inkscape:current-layer="layer1"
+   inkscape:showpageshadow="false"
+   showborder="true" />
+<g
+   inkscape:groupmode="layer"
+   id="layer1"
+   inkscape:label="dnsmasq"
+   style="display:inline"
+   transform="translate(5.2838057,-15.545371)"><g
+     id="g3790"
+     transform="matrix(0.8183832,0,0,0.8183832,65.304897,9.8747678)"
+     style="filter:url(#filter6262)"
+     inkscape:export-xdpi="90"
+     inkscape:export-ydpi="90"><g
+       transform="translate(-91.018462,1.0687099)"
+       id="g9">
+			<path
+   style="fill:#6700ad"
+   inkscape:connector-curvature="0"
+   id="path11"
+   d="M 54.997,12.151 C 50.083,9.132 43.29,7.266 35.791,7.266 c -7.5,0 -14.29,1.866 -19.204,4.885 -4.915,3.016 -7.956,7.184 -7.956,11.789 0,4.604 3.041,8.772 7.956,11.788 4.914,3.02 11.704,-4.271 19.204,-4.271 7.499,0 14.292,7.291 19.206,4.271 4.914,-3.016 7.955,-7.185 7.955,-11.788 0,-4.606 -3.041,-8.773 -7.955,-11.789 z M 24.996,24.318 c -2.698,0 -4.885,-0.922 -4.885,-2.061 0,-1.14 2.187,-2.063 4.885,-2.063 2.697,0 4.885,0.924 4.885,2.063 0,1.139 -2.188,2.061 -4.885,2.061 z m 21.501,0.191 c -2.686,0 -4.861,-0.856 -4.861,-1.912 0,-1.054 2.176,-1.911 4.861,-1.911 2.685,0 4.863,0.857 4.863,1.911 0,1.056 -2.178,1.912 -4.863,1.912 z" />
+			<path
+   style="fill:none;stroke:#ffb616;stroke-width:1.85353255"
+   inkscape:connector-curvature="0"
+   id="path13"
+   d="M 54.997,12.151 C 50.083,9.132 43.29,7.266 35.791,7.266 c -7.5,0 -14.29,1.866 -19.204,4.885 -4.915,3.016 -7.956,7.184 -7.956,11.789 0,4.604 3.041,8.772 7.956,11.788 4.914,3.02 11.704,-4.271 19.204,-4.271 7.499,0 14.292,7.291 19.206,4.271 4.914,-3.016 7.955,-7.185 7.955,-11.788 0,-4.606 -3.041,-8.773 -7.955,-11.789 z M 24.996,24.318 c -2.698,0 -4.885,-0.922 -4.885,-2.061 0,-1.14 2.187,-2.063 4.885,-2.063 2.697,0 4.885,0.924 4.885,2.063 0,1.139 -2.188,2.061 -4.885,2.061 z m 21.501,0.191 c -2.686,0 -4.861,-0.856 -4.861,-1.912 0,-1.054 2.176,-1.911 4.861,-1.911 2.685,0 4.863,0.857 4.863,1.911 0,1.056 -2.178,1.912 -4.863,1.912 z" />
+		</g><g
+       transform="translate(-91.018462,1.0687099)"
+       id="Layer_2">
+	<linearGradient
+   y2="32.715599"
+   x2="32.937"
+   y1="-8.8144999"
+   x1="30.564501"
+   gradientUnits="userSpaceOnUse"
+   id="SVGID_3_">
+		<stop
+   id="stop17"
+   style="stop-color:#FFFFFF;stop-opacity:0.73"
+   offset="0" />
+		<stop
+   id="stop19"
+   style="stop-color:#FFFFFF;stop-opacity:0"
+   offset="1" />
+	</linearGradient>
+	<path
+   inkscape:connector-curvature="0"
+   style="fill:url(#linearGradient5812)"
+   id="path21"
+   d="m 54.1,15.361 c -0.924,1.078 -2.782,1.265 -3.857,1.06 C 38,14.083 22.75,12.75 16.027,23.031 14.858,24.819 11.992,25.39 10.293,23.887 8.631,22.417 13.105,15.804 17.646,13.033 22.194,10.252 28.474,8.53 35.41,8.53 c 6.936,0 13.215,1.722 17.756,4.502 0.731,0.442 1.627,1.52 0.934,2.329 z" />
+</g></g></g></svg>
\ No newline at end of file
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
new file mode 100755
index 0000000..1046a2e
--- /dev/null
+++ b/man/dnsmasq.8
@@ -0,0 +1,2382 @@
+.TH DNSMASQ 8
+.SH NAME
+dnsmasq \- A lightweight DHCP and caching DNS server.
+.SH SYNOPSIS
+.B dnsmasq
+.I [OPTION]...
+.SH "DESCRIPTION"
+.BR dnsmasq
+is a lightweight DNS, TFTP, PXE, router advertisement and DHCP server. It is intended to provide 
+coupled DNS and DHCP service to a LAN.
+.PP
+Dnsmasq accepts DNS queries and either answers them from a small, local,
+cache or forwards them to a real, recursive, DNS server. It loads the
+contents of /etc/hosts so that local hostnames
+which do not appear in the global DNS can be resolved and also answers
+DNS queries for DHCP configured hosts. It can also act as the
+authoritative DNS server for one or more domains, allowing local names
+to appear in the global DNS. It can be configured to do DNSSEC
+validation.
+.PP
+The dnsmasq DHCP server supports static address assignments and multiple
+networks. It automatically
+sends a sensible default set of DHCP options, and can be configured to
+send any desired set of DHCP options, including vendor-encapsulated
+options. It includes a secure, read-only,
+TFTP server to allow net/PXE boot of DHCP hosts and also supports BOOTP. The PXE support is full featured, and includes a proxy mode which supplies PXE information to clients whilst DHCP address allocation is done by another server.
+.PP
+The dnsmasq DHCPv6 server provides the same set of features as the
+DHCPv4 server, and in addition, it includes router advertisements and
+a neat feature which allows nameing for clients which use DHCPv4 and
+stateless autoconfiguration only for IPv6 configuration. There is support for doing address allocation (both DHCPv6 and RA) from subnets which are dynamically delegated via DHCPv6 prefix delegation.
+.PP
+Dnsmasq is coded with small embedded systems in mind. It aims for the smallest possible memory footprint compatible with the supported functions,  and allows unneeded functions to be omitted from the compiled binary.  
+.SH OPTIONS
+Note that in general missing parameters are allowed and switch off
+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 --test
+Read and syntax check configuration file(s). Exit with code 0 if all
+is OK, or a non-zero code otherwise. Do not start up dnsmasq.
+.TP
+.B \-w, --help
+Display all command-line options. 
+.B --help dhcp 
+will display known DHCPv4 configuration options, and 
+.B --help dhcp6 
+will display DHCPv6 options.
+.TP
+.B \-h, --no-hosts
+Don't read the hostnames in /etc/hosts.
+.TP
+.B \-H, --addn-hosts=<file>
+Additional hosts file. Read the specified file as well as /etc/hosts. If -h is given, read
+only the specified file. This option may be repeated for more than one
+additional hosts file. If a directory is given, then read all the files contained in that directory. 
+.TP
+.B --hostsdir=<path>
+Read all the hosts files contained in the directory. New or changed files
+are read automatically. See --dhcp-hostsdir for details.
+.TP
+.B \-E, --expand-hosts
+Add the domain to simple names (without a period) in /etc/hosts
+in the same way as for DHCP-derived names. Note that this does not
+apply to domain names in cnames, PTR records, TXT records etc.
+.TP
+.B \-T, --local-ttl=<time>
+When replying with information from /etc/hosts or configuration or the DHCP leases
+file dnsmasq by default sets the time-to-live field to zero, meaning
+that the requester should not itself cache the information. This is
+the correct thing to do in almost all situations. This option allows a
+time-to-live (in seconds) to be given for these replies. This will
+reduce the load on the server at the expense of clients using stale
+data under some circumstances.
+.TP
+.B --dhcp-ttl=<time>
+As for --local-ttl, but affects only replies with information from DHCP leases. If both are given, --dhcp-ttl applies for DHCP information, and --local-ttl for others. Setting this to zero eliminates the effect of --local-ttl for DHCP.
+.TP
+.B --neg-ttl=<time>
+Negative replies from upstream servers normally contain time-to-live
+information in SOA records which dnsmasq uses for caching. If the
+replies from upstream servers omit this information, dnsmasq does not
+cache the reply. This option gives a default value for time-to-live
+(in seconds) which dnsmasq uses to cache negative replies even in 
+the absence of an SOA record. 
+.TP
+.B --max-ttl=<time>
+Set a maximum TTL value that will be handed out to clients. The specified
+maximum TTL will be given to clients instead of the true TTL value if it is 
+lower. The true TTL value is however kept in the cache to avoid flooding 
+the upstream DNS servers.
+.TP
+.B --max-cache-ttl=<time>
+Set a maximum TTL value for entries in the cache.
+.TP
+.B --min-cache-ttl=<time>
+Extend short TTL values to the time given when caching them. Note that
+artificially extending TTL values is in general a bad idea, do not do it 
+unless you have a good reason, and understand what you are doing. 
+Dnsmasq limits the value of this option to one hour, unless recompiled.
+.TP
+.B --auth-ttl=<time>
+Set the TTL value returned in answers from the authoritative server.
+.TP
+.B \-k, --keep-in-foreground
+Do not go into the background at startup but otherwise run as
+normal. This is intended for use when dnsmasq is run under daemontools
+or launchd.
+.TP
+.B \-d, --no-daemon
+Debug mode: don't fork to the background, don't write a pid file,
+don't change user id, generate a complete cache dump on receipt on
+SIGUSR1, log to stderr as well as syslog, don't fork new processes
+to handle TCP queries. Note that this option is for use in debugging
+only, to stop dnsmasq daemonising in production, use 
+.B -k.
+.TP
+.B \-q, --log-queries
+Log the results of DNS queries handled by dnsmasq. Enable a full cache dump on receipt of SIGUSR1. If the argument "extra" is supplied, ie
+.B --log-queries=extra
+then the log has extra information at the start of each line.
+This consists of a serial number which ties together the log lines associated with an individual query, and the IP address of the requestor.
+.TP
+.B \-8, --log-facility=<facility>
+Set the facility to which dnsmasq will send syslog entries, this
+defaults to DAEMON, and to LOCAL0 when debug mode is in operation. If
+the facility given contains at least one '/' character, it is taken to
+be a filename, and dnsmasq logs to the given file, instead of
+syslog. If the facility is '-' then dnsmasq logs to stderr.
+(Errors whilst reading configuration will still go to syslog,
+but all output from a successful startup, and all output whilst
+running, will go exclusively to the file.) When logging to a file,
+dnsmasq will close and reopen the file when it receives SIGUSR2. This 
+allows the log file to be rotated without stopping dnsmasq.
+.TP
+.B --log-async[=<lines>]
+Enable asynchronous logging and optionally set the limit on the
+number of lines
+which will be queued by dnsmasq when writing to the syslog is slow. 
+Dnsmasq can log asynchronously: this
+allows it to continue functioning without being blocked by syslog, and
+allows syslog to use dnsmasq for DNS queries without risking deadlock.
+If the queue of log-lines becomes full, dnsmasq will log the
+overflow, and the number of messages  lost. The default queue length is
+5, a sane value would be 5-25, and a maximum limit of 100 is imposed.
+.TP
+.B \-x, --pid-file=<path>
+Specify an alternate path for dnsmasq to record its process-id in. Normally /var/run/dnsmasq.pid.
+.TP
+.B \-u, --user=<username>
+Specify the userid to which dnsmasq will change after startup. Dnsmasq must normally be started as root, but it will drop root 
+privileges after startup by changing id to another user. Normally this user is "nobody" but that 
+can be over-ridden with this switch.
+.TP
+.B \-g, --group=<groupname> 
+Specify the group which dnsmasq will run
+as. The defaults to "dip", if available, to facilitate access to
+/etc/ppp/resolv.conf which is not normally world readable.
+.TP
+.B \-v, --version
+Print the version number.
+.TP
+.B \-p, --port=<port>
+Listen on <port> instead of the standard DNS port (53). Setting this
+to zero completely disables DNS function, leaving only DHCP and/or TFTP.
+.TP
+.B \-P, --edns-packet-max=<size>
+Specify the largest EDNS.0 UDP packet which is supported by the DNS
+forwarder. Defaults to 4096, which is the RFC5625-recommended size.
+.TP
+.B \-Q, --query-port=<query_port>
+Send outbound DNS queries from, and listen for their replies on, the
+specific UDP port <query_port> instead of using random ports. NOTE
+that using this option will make dnsmasq less secure against DNS
+spoofing attacks but it may be faster and use less resources.  Setting this option
+to zero makes dnsmasq use a single port allocated to it by the
+OS: this was the default behaviour in versions prior to 2.43. 
+.TP
+.B --min-port=<port>
+Do not use ports less than that given as source for outbound DNS
+queries. Dnsmasq picks random ports as source for outbound queries:
+when this option is given, the ports used will always to larger
+than that specified. Useful for systems behind firewalls. 
+.TP
+.B --max-port=<port>
+Use ports lower than that given as source for outbound DNS queries.
+Dnsmasq picks random ports as source for outbound queries:
+when this option is given, the ports used will always be lower
+than that specified. Useful for systems behind firewalls.
+.TP
+
+.B \-i, --interface=<interface name>
+Listen only on the specified interface(s). Dnsmasq automatically adds
+the loopback (local) interface to the list of interfaces to use when
+the
+.B \--interface
+option  is used. If no
+.B \--interface
+or
+.B \--listen-address
+options are given dnsmasq listens on all available interfaces except any
+given in
+.B \--except-interface
+options. On Linux, when
+.B \--bind-interfaces
+or
+.B \--bind-dynamic
+are in effect, IP alias interface labels (eg "eth1:0") are checked, rather than
+interface names. In the degenerate case when an interface has one address, this amounts to the same thing but when an interface has multiple addresses it
+allows control over which of those addresses are accepted.
+The same effect is achievable in default mode by using
+.B \--listen-address.
+A simple wildcard, consisting of a trailing '*',
+can be used in
+.B \--interface 
+and
+.B \--except-interface
+options. 
+.TP
+.B \-I, --except-interface=<interface name>
+Do not listen on the specified interface. Note that the order of
+.B \--listen-address
+.B --interface
+and
+.B --except-interface
+options does not matter and that 
+.B --except-interface
+options always override the others. The comments about interface labels for
+.B --listen-address
+apply here.
+.TP
+.B --auth-server=<domain>,<interface>|<ip-address>
+Enable DNS authoritative mode for queries arriving at an interface or address. Note that the interface or address
+need not be mentioned in 
+.B --interface
+or 
+.B --listen-address
+configuration, indeed
+.B --auth-server
+will override these and provide a different DNS service on the
+specified interface. The <domain> is the "glue record". It should
+resolve in the global DNS to a A and/or AAAA record which points to
+the address dnsmasq is listening on. When an interface is specified,
+it may be qualified with "/4" or "/6" to specify only the IPv4 or IPv6
+addresses associated with the interface.
+.TP
+.B --local-service
+Accept DNS queries only from hosts whose address is on a local subnet,
+ie a subnet for which an interface exists on the server. This option
+only has effect if there are no --interface --except-interface,
+--listen-address or --auth-server options. It is intended to be set as
+a default on installation, to allow unconfigured installations to be
+useful but also safe from being used for DNS amplification attacks.
+.TP 
+.B \-2, --no-dhcp-interface=<interface name>
+Do not provide DHCP or TFTP on the specified interface, but do provide DNS service.
+.TP
+.B \-a, --listen-address=<ipaddr>
+Listen on the given IP address(es). Both 
+.B \--interface
+and
+.B \--listen-address
+options may be given, in which case the set of both interfaces and
+addresses is used. Note that if no
+.B \--interface
+option is given, but 
+.B \--listen-address
+is, dnsmasq will not automatically listen on the loopback
+interface. To achieve this, its IP address, 127.0.0.1, must be
+explicitly given as a 
+.B \--listen-address
+option.
+.TP
+.B \-z, --bind-interfaces
+On systems which support it, dnsmasq binds the wildcard address,
+even when it is listening on only some interfaces. It then discards
+requests that it shouldn't reply to. This has the advantage of 
+working even when interfaces come and go and change address. This
+option forces dnsmasq to really bind only the interfaces it is
+listening on. About the only time when this is useful is when 
+running another nameserver (or another instance of dnsmasq) on the
+same machine. Setting this option also enables multiple instances of
+dnsmasq which provide DHCP service to run in the same machine.
+.TP
+.B --bind-dynamic
+Enable a network mode which is a hybrid between 
+.B --bind-interfaces
+and the default. Dnsmasq binds the address of individual interfaces,
+allowing multiple dnsmasq instances, but if new interfaces or
+addresses appear, it automatically listens on those (subject to any
+access-control configuration). This makes dynamically created
+interfaces work in the same way as the default. Implementing this
+option requires non-standard networking APIs and it is only available
+under Linux. On other platforms it falls-back to --bind-interfaces mode.
+.TP
+.B \-y, --localise-queries
+Return answers to DNS queries from /etc/hosts and --interface-name which depend on the interface over which the query was
+received. If a name has more than one address associated with
+it, and at least one of those addresses is on the same subnet as the
+interface to which the query was sent, then return only the
+address(es) on that subnet. This allows for a server  to have multiple
+addresses in /etc/hosts corresponding to each of its interfaces, and
+hosts will get the correct address based on which network they are
+attached to. Currently this facility is limited to IPv4.
+.TP
+.B \-b, --bogus-priv
+Bogus private reverse lookups. All reverse lookups for private IP ranges (ie 192.168.x.x, etc)
+which are not found in /etc/hosts or the DHCP leases file are answered
+with "no such domain" rather than being forwarded upstream. The 
+set of prefixes affected is the list given in RFC6303, for IPv4 and IPv6.
+.TP
+.B \-V, --alias=[<old-ip>]|[<start-ip>-<end-ip>],<new-ip>[,<mask>]
+Modify IPv4 addresses returned from upstream nameservers; old-ip is
+replaced by new-ip. If the optional mask is given then any address
+which matches the masked old-ip will be re-written. So, for instance
+.B --alias=1.2.3.0,6.7.8.0,255.255.255.0 
+will map 1.2.3.56 to 6.7.8.56 and 1.2.3.67 to 6.7.8.67. This is what
+Cisco PIX routers call "DNS doctoring". If the old IP is given as
+range, then only addresses in the range, rather than a whole subnet,
+are re-written. So 
+.B --alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0
+maps 192.168.0.10->192.168.0.40 to 10.0.0.10->10.0.0.40
+.TP 
+.B \-B, --bogus-nxdomain=<ipaddr>
+Transform replies which contain the IP address given into "No such
+domain" replies. This is intended to counteract a devious move made by
+Verisign in September 2003 when they started returning the address of
+an advertising web page in response to queries for unregistered names,
+instead of the correct NXDOMAIN response. This option tells dnsmasq to
+fake the correct response when it sees this behaviour. As at Sept 2003
+the IP address being returned by Verisign is 64.94.110.11
+.TP 
+.B --ignore-address=<ipaddr>
+Ignore replies to A-record queries which include the specified address. 
+No error is generated, dnsmasq simply continues to listen for another reply. 
+This is useful to defeat blocking strategies which rely on quickly supplying a
+forged answer to a DNS request for certain domain, before the correct answer can arrive.
+.TP
+.B \-f, --filterwin2k
+Later versions of windows make periodic DNS requests which don't get sensible answers from
+the public DNS and can cause problems by triggering dial-on-demand links. This flag turns on an option
+to filter such requests. The requests blocked are for records of types SOA and SRV, and type ANY where the 
+requested name has underscores, to catch LDAP requests.
+.TP
+.B \-r, --resolv-file=<file>
+Read the IP addresses of the upstream nameservers from <file>, instead of
+/etc/resolv.conf. For the format of this file see
+.BR resolv.conf (5). 
+The only lines relevant to dnsmasq are nameserver ones. Dnsmasq can
+be told to poll more than one resolv.conf file, the first file name  specified
+overrides the default, subsequent ones add to the list. This is only
+allowed when polling; the file with the currently latest modification
+time is the one used. 
+.TP
+.B \-R, --no-resolv
+Don't read /etc/resolv.conf. Get upstream servers only from the command
+line or the dnsmasq configuration file.
+.TP
+.B \-1, --enable-dbus[=<service-name>]
+Allow dnsmasq configuration to be updated via DBus method calls. The
+configuration which can be changed is upstream DNS servers (and
+corresponding domains) and cache clear. Requires that dnsmasq has
+been built with DBus support. If the service name is given, dnsmasq
+provides service at that name, rather than the default which is 
+.B uk.org.thekelleys.dnsmasq
+.TP 
+.B \-o, --strict-order
+By default, dnsmasq will send queries to any of the upstream servers
+it knows about and tries to favour servers that are known to
+be up. Setting this flag forces dnsmasq to try each query with each
+server strictly in the order they appear in /etc/resolv.conf
+.TP
+.B --all-servers
+By default, when dnsmasq has more than one upstream server available,
+it will send queries to just one server. Setting this flag forces
+dnsmasq to send all queries to all available servers. The reply from
+the server which answers first will be returned to the original requester.
+.TP
+.B --dns-loop-detect
+Enable code to detect DNS forwarding loops; ie the situation where a query sent to one 
+of the upstream server eventually returns as a new query to the dnsmasq instance. The
+process works by generating TXT queries of the form <hex>.test and sending them to
+each upstream server. The hex is a UID which encodes the instance of dnsmasq sending the query
+and the upstream server to which it was sent. If the query returns to the server which sent it, then
+the upstream server through which it was sent is disabled and this event is logged. Each time the
+set of upstream servers changes, the test is re-run on all of them, including ones which
+were previously disabled.
+.TP
+.B --stop-dns-rebind
+Reject (and log) addresses from upstream nameservers which are in the
+private IP ranges. This blocks an attack where a browser behind a
+firewall is used to probe machines on the local network.
+.TP
+.B --rebind-localhost-ok
+Exempt 127.0.0.0/8 from rebinding checks. This address range is
+returned by realtime black hole servers, so blocking it may disable
+these services.
+.TP 
+.B  --rebind-domain-ok=[<domain>]|[[/<domain>/[<domain>/]
+Do not detect and block dns-rebind on queries to these domains. The
+argument may be either a single domain, or multiple domains surrounded
+by '/', like the --server syntax, eg. 
+.B  --rebind-domain-ok=/domain1/domain2/domain3/
+.TP
+.B \-n, --no-poll
+Don't poll /etc/resolv.conf for changes.
+.TP
+.B --clear-on-reload
+Whenever /etc/resolv.conf is re-read or the upstream servers are set
+via DBus, clear the DNS cache.
+This is useful when new nameservers may have different
+data than that held in cache.
+.TP
+.B \-D, --domain-needed
+Tells dnsmasq to never forward A or AAAA queries for plain names, without dots
+or domain parts, to upstream nameservers. If the name is not known
+from /etc/hosts or DHCP then a "not found" answer is returned.
+.TP
+.B \-S, --local, --server=[/[<domain>]/[domain/]][<ipaddr>[#<port>][@<source-ip>|<interface>[#<port>]]
+Specify IP address of upstream servers directly. Setting this flag does
+not suppress reading of /etc/resolv.conf, use -R to do that. If one or
+more 
+optional domains are given, that server is used only for those domains
+and they are queried only using the specified server. This is
+intended for private nameservers: if you have a nameserver on your
+network which deals with names of the form
+xxx.internal.thekelleys.org.uk at 192.168.1.1 then giving  the flag 
+.B -S /internal.thekelleys.org.uk/192.168.1.1 
+will send all queries for
+internal machines to that nameserver, everything else will go to the
+servers in /etc/resolv.conf. DNSSEC validation is turned off for such
+private nameservers, UNLESS a
+.B --trust-anchor
+is specified for the domain in question. An empty domain specification,
+.B // 
+has the special meaning of "unqualified names only" ie names without any
+dots in them. A non-standard port may be specified as 
+part of the IP
+address using a # character.
+More than one -S flag is allowed, with
+repeated domain or ipaddr parts as required.
+
+More specific domains take precedence over less specific domains, so:
+.B --server=/google.com/1.2.3.4
+.B --server=/www.google.com/2.3.4.5
+will send queries for *.google.com to 1.2.3.4, except *www.google.com,
+which will go to 2.3.4.5
+
+The special server address '#' means, "use the standard servers", so
+.B --server=/google.com/1.2.3.4
+.B --server=/www.google.com/#
+will send queries for *.google.com to 1.2.3.4, except *www.google.com which will
+be forwarded as usual.
+
+Also permitted is a -S
+flag which gives a domain but no IP address; this tells dnsmasq that
+a domain is local and it may answer queries from /etc/hosts or DHCP
+but should never forward queries on that domain to any upstream
+servers.
+.B local
+is a synonym for
+.B server
+to make configuration files clearer in this case.
+
+IPv6 addresses may include a %interface scope-id, eg
+fe80::202:a412:4512:7bbf%eth0.
+
+The optional string after the @ character tells dnsmasq how to set the source of
+the queries to this nameserver. It can either be an ip-address, an interface
+name or both. The ip-address should belong to the machine on which dnsmasq is
+running, otherwise this server line will be logged and then ignored. If an
+interface name is given, then queries to the server will be forced via that
+interface; if an ip-address is given then the source address of the queries will
+be set to that address; and if both are given then a combination of ip-address
+and interface name will be used to steer requests to the server.
+The query-port flag is ignored for any servers which have a
+source address specified but the port may be specified directly as
+part of the source address. Forcing queries to an interface is not
+implemented on all platforms supported by dnsmasq.
+.TP
+.B --rev-server=<ip-address>/<prefix-len>,<ipaddr>[#<port>][@<source-ip>|<interface>[#<port>]]
+This is functionally the same as 
+.B --server, 
+but provides some syntactic sugar to make specifying address-to-name queries easier. For example
+.B --rev-server=1.2.3.0/24,192.168.0.1
+is exactly equivalent to 
+.B --server=/3.2.1.in-addr.arpa/192.168.0.1
+.TP
+.B \-A, --address=/<domain>[/<domain>...]/[<ipaddr>]
+Specify an IP address to return for any host in the given domains.
+Queries in the domains are never forwarded and always replied to
+with the specified IP address which may be IPv4 or IPv6. To give
+both IPv4 and IPv6 addresses for a domain, use repeated \fB-A\fP flags.
+To include multiple IP addresses for a single query, use
+\fB--addn-hosts=<path>\fP instead.
+Note that /etc/hosts and DHCP leases override this for individual
+names. A common use of this is to redirect the entire doubleclick.net
+domain to some friendly local web server to avoid banner ads. The
+domain specification works in the same was as for \fB--server\fP, with
+the additional facility that \fB/#/\fP matches any domain. Thus
+\fB--address=/#/1.2.3.4\fP will always return \fB1.2.3.4\fP for any
+query not answered from \fB/etc/hosts\fP or DHCP and not sent to an
+upstream nameserver by a more specific \fB--server\fP directive. As for
+\fB--server\fP, one or more domains with no address returns a
+no-such-domain answer, so \fB--address=/example.com/\fP is equivalent to
+\fB--server=/example.com/\fP and returns NXDOMAIN for example.com and
+all its subdomains.
+.TP
+.B --ipset=/<domain>[/<domain>...]/<ipset>[,<ipset>...]
+Places the resolved IP addresses of queries for one or more domains in
+the specified Netfilter IP set. If multiple setnames are given, then the
+addresses are placed in each of them, subject to the limitations of an
+IP set (IPv4 addresses cannot be stored in an IPv6 IP set and vice
+versa).  Domains and subdomains are matched in the same way as
+\fB--address\fP.
+These IP sets must already exist. See
+.BR ipset (8)
+for more details.
+.TP
+.B \-m, --mx-host=<mx name>[[,<hostname>],<preference>]
+Return an MX record named <mx name> pointing to the given hostname (if
+given), or
+the host specified in the --mx-target switch
+or, if that switch is not given, the host on which dnsmasq 
+is running. The default is useful for directing mail from systems on a LAN
+to a central server. The preference value is optional, and defaults to
+1 if not given. More than one MX record may be given for a host.
+.TP 
+.B \-t, --mx-target=<hostname>
+Specify the default target for the MX record returned by dnsmasq. See
+--mx-host.  If --mx-target is given, but not --mx-host, then dnsmasq
+returns a MX record containing the MX target for MX queries on the 
+hostname of the machine on which dnsmasq is running.
+.TP
+.B \-e, --selfmx
+Return an MX record pointing to itself for each local
+machine. Local machines are those in /etc/hosts or with DHCP leases.
+.TP 
+.B \-L, --localmx
+Return an MX record pointing to the host given by mx-target (or the
+machine on which dnsmasq is running) for each
+local machine. Local machines are those in /etc/hosts or with DHCP
+leases.
+.TP
+.B \-W, --srv-host=<_service>.<_prot>.[<domain>],[<target>[,<port>[,<priority>[,<weight>]]]]
+Return a SRV DNS record. See RFC2782 for details. If not supplied, the
+domain defaults to that given by
+.B --domain.
+The default for the target domain is empty, and the default for port
+is one and the defaults for 
+weight and priority are zero. Be careful if transposing data from BIND
+zone files: the port, weight and priority numbers are in a different
+order. More than one SRV record for a given service/domain is allowed,
+all that match are returned.
+.TP
+.B --host-record=<name>[,<name>....],[<IPv4-address>],[<IPv6-address>][,<TTL>]
+Add A, AAAA and PTR records to the DNS. This adds one or more names to
+the DNS with associated IPv4 (A) and IPv6 (AAAA) records. A name may
+appear in more than one 
+.B host-record
+and therefore be assigned more than one address. Only the first
+address creates a PTR record linking the address to the name. This is
+the same rule as is used reading hosts-files. 
+.B host-record
+options are considered to be read before host-files, so a name
+appearing there inhibits PTR-record creation if it appears in
+hosts-file also. Unlike hosts-files, names are not expanded, even when
+.B expand-hosts
+is in effect. Short and long names may appear in the same 
+.B host-record,
+eg. 
+.B --host-record=laptop,laptop.thekelleys.org,192.168.0.1,1234::100
+
+If the time-to-live is given, it overrides the default, which is zero
+or the value of --local-ttl. The value is a positive integer and gives 
+the time-to-live in seconds.
+.TP
+.B \-Y, --txt-record=<name>[[,<text>],<text>]
+Return a TXT DNS record. The value of TXT record is a set of strings,
+so  any number may be included, delimited by commas; use quotes to put
+commas into a string. Note that the maximum length of a single string
+is 255 characters, longer strings are split into 255 character chunks.
+.TP
+.B --ptr-record=<name>[,<target>]
+Return a PTR DNS record.
+.TP
+.B --naptr-record=<name>,<order>,<preference>,<flags>,<service>,<regexp>[,<replacement>]
+Return an NAPTR DNS record, as specified in RFC3403.
+.TP
+.B --cname=<cname>,[<cname>,]<target>[,<TTL>]
+Return a CNAME record which indicates that <cname> is really
+<target>. There are significant limitations on the target; it must be a
+DNS name which is known to dnsmasq from /etc/hosts (or additional
+hosts files), from DHCP, from --interface-name or from another 
+.B --cname.
+If the target does not satisfy this
+criteria, the whole cname is ignored. The cname must be unique, but it
+is permissable to have more than one cname pointing to the same target. Indeed
+it's possible to declare multiple cnames to a target in a single line, like so:
+.B --cname=cname1,cname2,target
+
+If the time-to-live is given, it overrides the default, which is zero
+or the value of -local-ttl. The value is a positive integer and gives 
+the time-to-live in seconds.
+.TP
+.B --dns-rr=<name>,<RR-number>,[<hex data>]
+Return an arbitrary DNS Resource Record. The number is the type of the
+record (which is always in the C_IN class). The value of the record is
+given by the hex data, which may be of the form 01:23:45 or 01 23 45 or
+012345 or any mixture of these.
+.TP
+.B --interface-name=<name>,<interface>[/4|/6]
+Return DNS records associating the name with the address(es) of
+the given interface. This flag specifies an A or AAAA record for the given
+name in the same way as an /etc/hosts line, except that the address is
+not constant, but taken from the given interface. The interface may be
+followed by "/4" or "/6" to specify that only IPv4 or IPv6 addresses
+of the interface should be used. If the interface is
+down, not configured or non-existent, an empty record is returned. The
+matching PTR record is also created, mapping the interface address to
+the name. More than one name may be associated with an interface
+address by repeating the flag; in that case the first instance is used
+for the reverse address-to-name mapping. Note that a name used in 
+--interface-name may not appear in /etc/hosts.
+.TP
+.B --synth-domain=<domain>,<address range>[,<prefix>]
+Create artificial A/AAAA and PTR records for an address range. The
+records use the address, with periods (or colons for IPv6) replaced
+with dashes.
+
+An example should make this clearer.
+.B --synth-domain=thekelleys.org.uk,192.168.0.0/24,internal-
+will result in a query for internal-192-168-0-56.thekelleys.org.uk returning
+192.168.0.56 and a reverse query vice versa. The same applies to IPv6,
+but IPv6 addresses may start with '::'
+but DNS labels may not start with '-' so in this case if no prefix is
+configured a zero is added in front of the label. ::1 becomes 0--1.
+
+V4 mapped IPv6 addresses, which have a representation like ::ffff:1.2.3.4 are handled specially, and become like 0--ffff-1-2-3-4
+
+The address range can be of the form
+<ip address>,<ip address> or <ip address>/<netmask>
+.TP
+.B --add-mac[=base64|text]
+Add the MAC address of the requestor to DNS queries which are
+forwarded upstream. This may be used to DNS filtering by the upstream
+server. The MAC address can only be added if the requestor is on the same
+subnet as the dnsmasq server. Note that the mechanism used to achieve this (an EDNS0 option)
+is not yet standardised, so this should be considered
+experimental. Also note that exposing MAC addresses in this way may
+have security and privacy implications. The warning about caching
+given for --add-subnet applies to --add-mac too. An alternative encoding of the 
+MAC, as base64, is enabled by adding the "base64" parameter and a human-readable encoding of hex-and-colons is enabled by added the "text" parameter.
+.TP
+.B --add-cpe-id=<string>
+Add a arbitrary identifying string to o DNS queries which are
+forwarded upstream.
+.TP 
+.B --add-subnet[[=[<IPv4 address>/]<IPv4 prefix length>][,[<IPv6 address>/]<IPv6 prefix length>]]
+Add a subnet address to the DNS queries which are forwarded
+upstream. If an address is specified in the flag, it will be used,
+otherwise, the address of the requestor will be used. The amount of
+the address forwarded depends on the prefix length parameter: 32 (128
+for IPv6) forwards the whole address, zero forwards none of it but
+still marks the request so that no upstream nameserver will add client
+address information either. The default is zero for both IPv4 and
+IPv6. Note that upstream nameservers may be configured to return
+different results based on this information, but the dnsmasq cache
+does not take account. If a dnsmasq instance is configured such that
+different results may be encountered, caching should be disabled.
+
+For example,
+.B --add-subnet=24,96
+will add the /24 and /96 subnets of the requestor for IPv4 and IPv6 requestors, respectively.
+.B --add-subnet=1.2.3.4/24
+will add 1.2.3.0/24 for IPv4 requestors and ::/0 for IPv6 requestors.
+.B --add-subnet=1.2.3.4/24,1.2.3.4/24
+will add 1.2.3.0/24 for both IPv4 and IPv6 requestors.
+
+.TP
+.B \-c, --cache-size=<cachesize>
+Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching.
+.TP
+.B \-N, --no-negcache
+Disable negative caching. Negative caching allows dnsmasq to remember
+"no such domain" answers from upstream nameservers and answer
+identical queries without forwarding them again. 
+.TP
+.B \-0, --dns-forward-max=<queries>
+Set the maximum number of concurrent DNS queries. The default value is
+150, which should be fine for most setups. The only known situation
+where this needs to be increased is when using web-server log file
+resolvers, which can generate large numbers of concurrent queries.
+.TP
+.B --dnssec
+Validate DNS replies and cache DNSSEC data. When forwarding DNS queries, dnsmasq requests the 
+DNSSEC records needed to validate the replies. The replies are validated and the result returned as 
+the Authenticated Data bit in the DNS packet. In addition the DNSSEC records are stored in the cache, making 
+validation by clients more efficient. Note that validation by clients is the most secure DNSSEC mode, but for
+clients unable to do validation, use of the AD bit set by dnsmasq is useful, provided that the network between 
+the dnsmasq server and the client is trusted. Dnsmasq must be compiled with HAVE_DNSSEC enabled, and DNSSEC
+trust anchors provided, see 
+.B --trust-anchor.
+Because the DNSSEC validation process uses the cache, it is not
+permitted to reduce the cache size below the default when DNSSEC is
+enabled. The nameservers upstream of dnsmasq must be DNSSEC-capable,
+ie capable of returning DNSSEC records with data. If they are not,
+then dnsmasq will not be able to determine the trusted status of
+answers. In the default mode, this means that all replies will be
+marked as untrusted. If 
+.B --dnssec-check-unsigned
+is set and the upstream servers don't support DNSSEC, then DNS service will be entirely broken.
+.TP
+.B --trust-anchor=[<class>],<domain>,<key-tag>,<algorithm>,<digest-type>,<digest>
+Provide DS records to act a trust anchors for DNSSEC
+validation. Typically these will be the DS record(s) for Zone Signing
+key(s) of the root zone,
+but trust anchors for limited domains are also possible. The current
+root-zone trust anchors may be downloaded from https://data.iana.org/root-anchors/root-anchors.xml 
+.TP
+.B --dnssec-check-unsigned
+As a default, dnsmasq does not check that unsigned DNS replies are
+legitimate: they are assumed to be valid and passed on (without the
+"authentic data" bit set, of course). This does not protect against an
+attacker forging unsigned replies for signed DNS zones, but it is
+fast. If this flag is set, dnsmasq will check the zones of unsigned
+replies, to ensure that unsigned replies are allowed in those
+zones. The cost of this is more upstream queries and slower
+performance. See also the warning about upstream servers in the
+section on 
+.B --dnssec
+.TP
+.B --dnssec-no-timecheck
+DNSSEC signatures are only valid for specified time windows, and should be rejected outside those windows. This generates an
+interesting chicken-and-egg problem for machines which don't have a hardware real time clock. For these machines to determine the correct 
+time typically requires use of NTP and therefore DNS, but validating DNS requires that the correct time is already known. Setting this flag
+removes the time-window checks (but not other DNSSEC validation.) only until the dnsmasq process receives SIGHUP. The intention is
+that dnsmasq should be started with this flag when the platform determines that reliable time is not currently available. As soon as 
+reliable time is established, a SIGHUP should be sent to dnsmasq, which enables time checking, and purges the cache of DNS records
+which have not been throughly checked.
+.TP
+.B --dnssec-timestamp=<path>
+Enables an alternative way of checking the validity of the system time for DNSSEC (see --dnssec-no-timecheck). In this case, the 
+system time is considered to be valid once it becomes later than the timestamp on the specified file. The file is created and 
+its timestamp set automatically by dnsmasq. The file must be stored on a persistent filesystem, so that it and its mtime are carried 
+over system restarts. The timestamp file is created after dnsmasq has dropped root, so it must be in a location writable by the 
+unprivileged user that dnsmasq runs as.
+.TP
+.B --proxy-dnssec
+Copy the DNSSEC Authenticated Data bit from upstream servers to downstream clients and cache it.  This is an 
+alternative to having dnsmasq validate DNSSEC, but it depends on the security of the network between 
+dnsmasq and the upstream servers, and the trustworthiness of the upstream servers.
+.TP
+.B --dnssec-debug
+Set debugging mode for the DNSSEC validation, set the Checking Disabled bit on upstream queries, 
+and don't convert replies which do not validate to responses with
+a return code of SERVFAIL. Note that
+setting this may affect DNS behaviour in bad ways, it is not an
+extra-logging flag and should not be set in production.
+.TP
+.B --auth-zone=<domain>[,<subnet>[/<prefix length>][,<subnet>[/<prefix length>].....][,exclude:<subnet>[/<prefix length>]].....]
+Define a DNS zone for which dnsmasq acts as authoritative server. Locally defined DNS records which are in the domain
+will be served. If subnet(s) are given, A and AAAA records must be in one of the
+specified subnets.
+
+As alternative to directly specifying the subnets, it's possible to
+give the name of an interface, in which case the subnets implied by
+that interface's configured addresses and netmask/prefix-length are
+used; this is useful when using constructed DHCP ranges as the actual
+address is dynamic and not known when configuring dnsmasq. The
+interface addresses may be confined to only IPv6 addresses using
+<interface>/6 or to only IPv4 using <interface>/4. This is useful when
+an interface has dynamically determined global IPv6 addresses which should
+appear in the zone, but RFC1918 IPv4 addresses which should not.
+Interface-name and address-literal subnet specifications may be used
+freely in the same --auth-zone declaration.
+
+It's possible to exclude certain IP addresses from responses. It can be
+used, to make sure that answers contain only global routeable IP
+addresses (by excluding loopback, RFC1918 and ULA addresses).
+
+The subnet(s) are also used to define in-addr.arpa and
+ip6.arpa domains which are served for reverse-DNS queries. If not
+specified, the prefix length defaults to 24 for IPv4 and 64 for IPv6.
+For IPv4 subnets, the prefix length should be have the value 8, 16 or 24
+unless you are familiar with RFC 2317 and have arranged the
+in-addr.arpa delegation accordingly. Note that if no subnets are
+specified, then no reverse queries are answered.
+.TP
+.B --auth-soa=<serial>[,<hostmaster>[,<refresh>[,<retry>[,<expiry>]]]]
+Specify fields in the SOA record associated with authoritative
+zones. Note that this is optional, all the values are set to sane defaults.
+.TP
+.B --auth-sec-servers=<domain>[,<domain>[,<domain>...]]
+Specify any secondary servers for a zone for which dnsmasq is
+authoritative. These servers must be configured to get zone data from
+dnsmasq by zone transfer, and answer queries for the same
+authoritative zones as dnsmasq.
+.TP
+.B --auth-peer=<ip-address>[,<ip-address>[,<ip-address>...]]
+Specify the addresses of secondary servers which are allowed to
+initiate zone transfer (AXFR) requests for zones for which dnsmasq is
+authoritative. If this option is not given, then AXFR requests will be
+accepted from any secondary. 
+.TP 
+.B --conntrack
+Read the Linux connection track mark associated with incoming DNS
+queries and set the same mark value on upstream traffic used to answer
+those queries. This allows traffic generated by dnsmasq to be
+associated with the queries which cause it, useful for bandwidth
+accounting and firewalling. Dnsmasq must have conntrack support
+compiled in and the kernel must have conntrack support
+included and configured. This option cannot be combined with
+--query-port. 
+.TP
+.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-addr>[,<end-addr>|<mode>][,<netmask>[,<broadcast>]][,<lease time>]
+.TP
+.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-IPv6addr>[,<end-IPv6addr>|constructor:<interface>][,<mode>][,<prefix-len>][,<lease time>]
+
+Enable the DHCP server. Addresses will be given out from the range
+<start-addr> to <end-addr> and from statically defined addresses given
+in 
+.B dhcp-host
+options. If the lease time is given, then leases
+will be given for that length of time. The lease time is in seconds,
+or minutes (eg 45m) or hours (eg 1h) or "infinite". If not given,
+the default lease time is one hour. The
+minimum lease time is two minutes. For IPv6 ranges, the lease time
+maybe "deprecated"; this sets the preferred lifetime sent in a DHCP
+lease or router advertisement to zero, which causes clients to use
+other addresses, if available, for new connections as a prelude to renumbering.
+
+This option may be repeated, with different addresses, to enable DHCP
+service to more than one network. For directly connected networks (ie,
+networks on which the machine running dnsmasq has an interface) the
+netmask is optional: dnsmasq will determine it from the interface
+configuration. For networks which receive DHCP service via a relay
+agent, dnsmasq cannot determine the netmask itself, so it should be
+specified, otherwise dnsmasq will have to guess, based on the class (A, B or
+C) of the network address. The broadcast address is
+always optional. It is always
+allowed to have more than one dhcp-range in a single subnet. 
+
+For IPv6, the parameters are slightly different: instead of netmask
+and broadcast address, there is an optional prefix length which must
+be equal to or larger then the prefix length on the local interface. If not
+given, this defaults to 64. Unlike the IPv4 case, the prefix length is not
+automatically derived from the interface configuration. The minimum
+size of the prefix length is 64.
+
+IPv6 (only) supports another type of range. In this, the start address and optional end address contain only the network part (ie ::1) and they are followed by
+.B constructor:<interface>.
+This forms a template which describes how to create ranges, based on the addresses assigned to the interface. For instance
+
+.B --dhcp-range=::1,::400,constructor:eth0
+
+will look for addresses on
+eth0 and then create a range from <network>::1 to <network>::400. If
+the interface is assigned more than one network, then the
+corresponding ranges will be automatically created, and then
+deprecated and finally removed again as the address is deprecated and
+then deleted. The interface name may have a final "*" wildcard. Note
+that just any address on eth0 will not do: it must not be an
+autoconfigured or privacy address, or be deprecated.
+
+If a dhcp-range is only being used for stateless DHCP and/or SLAAC,
+then the address can be simply ::
+
+.B --dhcp-range=::,constructor:eth0
+
+
+The optional 
+.B set:<tag> 
+sets an alphanumeric label which marks this network so that
+dhcp options may be specified on a per-network basis. 
+When it is prefixed with 'tag:' instead, then its meaning changes from setting
+a tag to matching it. Only one tag may be set, but more than one tag
+may be matched.
+
+The optional <mode> keyword may be 
+.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. A static-only subnet with address
+all zeros may be used as a "catch-all" address to enable replies to all
+Information-request packets on a subnet which is provided with
+stateless DHCPv6, ie
+.B --dhcp-range=::,static
+
+For IPv4, the <mode> may be 
+.B proxy
+in which case dnsmasq will provide proxy-DHCP on the specified
+subnet. (See 
+.B pxe-prompt
+and 
+.B pxe-service
+for details.)
+
+For IPv6, the mode may be some combination of
+.B ra-only, slaac, ra-names, ra-stateless, ra-advrouter, off-link.
+
+.B ra-only
+tells dnsmasq to offer Router Advertisement only on this subnet,
+and not DHCP. 
+
+.B slaac
+tells dnsmasq to offer Router Advertisement on this subnet and to set
+the A bit in the router advertisement, so that the client will use
+SLAAC addresses. When used with a DHCP range or static DHCP address
+this results in the client having both a DHCP-assigned and a SLAAC
+address.
+
+.B ra-stateless
+sends router advertisements with the O and A bits set, and provides a
+stateless DHCP service. The client will use a SLAAC address, and use
+DHCP for other configuration information.
+
+.B ra-names
+enables a mode
+which gives DNS names to dual-stack hosts which do SLAAC for
+IPv6. Dnsmasq uses the host's IPv4 lease to derive the name, network
+segment and MAC address and assumes that the host will also have an
+IPv6 address calculated using the SLAAC algorithm, on the same network
+segment. The address is pinged, and if a reply is received, an AAAA
+record is added to the DNS for this IPv6
+address. Note that this is only happens for directly-connected
+networks, (not one doing DHCP via a relay) and it will not work 
+if a host is using privacy extensions. 
+.B ra-names
+can be combined  with 
+.B ra-stateless
+and
+.B slaac.
+
+.B ra-advrouter
+enables a mode where router address(es) rather than prefix(es) are included in the advertisements.
+This is described in RFC-3775 section 7.2 and is used in mobile IPv6. In this mode the interval option
+is also included, as described in RFC-3775 section 7.3.
+
+.B off-link
+tells dnsmasq to advertise the prefix without the on-link (aka L) bit set.
+
+.TP
+.B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][,<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
+overrides any supplied by the DHCP client on the machine. It is also
+allowable to omit the hardware address and include the hostname, in
+which case the IP address and lease times will apply to any machine
+claiming that name. For example 
+.B --dhcp-host=00:20:e0:3b:13:af,wap,infinite 
+tells dnsmasq to give
+the machine with hardware address 00:20:e0:3b:13:af the name wap, and
+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 constrained to be
+in the range given by the --dhcp-range option, but they must be in
+the same subnet as some valid dhcp-range.  For
+subnets which don't need a pool of dynamically allocated addresses,
+use the "static" keyword in the dhcp-range declaration.
+
+It is allowed to use client identifiers (called client
+DUID in IPv6-land) rather than
+hardware addresses to identify hosts by prefixing with 'id:'. Thus: 
+.B --dhcp-host=id:01:02:03:04,..... 
+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,..... 
+
+A single
+.B dhcp-host 
+may contain an IPv4 address or an IPv6 address, or both. IPv6 addresses must be bracketed by square brackets thus:
+.B --dhcp-host=laptop,[1234::56]
+IPv6 addresses may contain only the host-identifier part:
+.B --dhcp-host=laptop,[::56]
+in which case they act as wildcards in constructed dhcp ranges, with
+the appropriate network part inserted. 
+Note that in IPv6 DHCP, the hardware address may not be
+available, though it normally is for direct-connected clients, or
+clients using DHCP relays which support RFC 6939.
+
+
+For DHCPv4, the  special option id:* means "ignore any client-id 
+and use MAC addresses only." This is useful when a client presents a client-id sometimes 
+but not others.
+
+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. Only one hostname can be
+given in a 
+.B dhcp-host
+option, but aliases are possible by using CNAMEs. (See 
+.B --cname
+).
+
+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 set:<tag> construct sets the tag
+whenever this dhcp-host directive is in use. This can be used to 
+selectively send DHCP options just for this host. More than one tag
+can be set in a dhcp-host directive (but not in other places where
+"set:<tag>" is allowed). When a host matches any
+dhcp-host directive (or one implied by /etc/ethers) then the special
+tag "known" is set. This allows dnsmasq to be configured to
+ignore requests from unknown machines using
+.B --dhcp-ignore=tag:!known
+If the host matches only a dhcp-host directive which cannot
+be used because it specifies an address on different subnet, the tag "known-othernet" is set.
+Ethernet addresses (but not client-ids) may have
+wildcard bytes, so for example 
+.B --dhcp-host=00:20:e0:3b:13:*,ignore 
+will cause dnsmasq to ignore a range of hardware addresses. Note that
+the "*" will need to be escaped or quoted on a command line, but not
+in the configuration file.
+
+Hardware addresses normally match any
+network (ARP) type, but it is possible to restrict them to a single
+ARP type by preceding them with the ARP-type (in HEX) and "-". so 
+.B --dhcp-host=06-00:20:e0:3b:13:af,1.2.3.4 
+will only match a
+Token-Ring hardware address, since the ARP-address type for token ring
+is 6. 
+
+As a special case, in DHCPv4, it is possible to include more than one
+hardware address. eg:
+.B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2
+This allows an IP address to be associated with
+multiple hardware addresses, and gives dnsmasq permission to abandon a
+DHCP lease to one of the hardware addresses when another one asks for
+a lease. Beware that this is a dangerous thing to do, it will only
+work reliably if only one of the hardware addresses is active at any
+time and there is no way for dnsmasq to enforce this. It is, for instance,
+useful to allocate a stable IP address to a laptop which
+has both wired and wireless interfaces.
+.TP
+.B --dhcp-hostsfile=<path>
+Read DHCP host information from the specified file. If a directory
+is given, then read all the files contained in that directory. The file contains 
+information about one host per line. The format of a line is the same
+as text to the right of '=' in --dhcp-host. The advantage of storing DHCP host information
+in this file is that it can be changed without re-starting dnsmasq:
+the file will be re-read when dnsmasq receives SIGHUP.
+.TP
+.B --dhcp-optsfile=<path>
+Read DHCP option information from the specified file.  If a directory
+is given, then read all the files contained in that directory. The advantage of 
+using this option is the same as for --dhcp-hostsfile: the
+dhcp-optsfile will be re-read when dnsmasq receives SIGHUP. Note that
+it is possible to encode the information in a
+.B --dhcp-boot
+flag as DHCP options, using the options names bootfile-name,
+server-ip-address and tftp-server. This allows these to be included
+in a dhcp-optsfile.
+.TP
+.B --dhcp-hostsdir=<path>
+This is equivalent to dhcp-hostsfile, except for the following. The path MUST be a
+directory, and not an individual file. Changed or new files within
+the directory are read automatically, without the need to send SIGHUP.
+If a file is deleted for changed after it has been read by dnsmasq, then the
+host record it contained will remain until dnsmasq receives a SIGHUP, or 
+is restarted; ie host records are only added dynamically.
+.TP
+.B --dhcp-optsdir=<path>
+This is equivalent to dhcp-optsfile, with the differences noted for --dhcp-hostsdir.
+.TP 
+.B \-Z, --read-ethers
+Read /etc/ethers for information about hosts for the DHCP server. The
+format of /etc/ethers is a hardware address, followed by either a
+hostname or dotted-quad IP address. When read by dnsmasq these lines
+have exactly the same effect as
+.B --dhcp-host
+options containing the same information. /etc/ethers is re-read when 
+dnsmasq receives SIGHUP. IPv6 addresses are NOT read from /etc/ethers.
+.TP
+.B \-O, --dhcp-option=[tag:<tag>,[tag:<tag>,]][encap:<opt>,][vi-encap:<enterprise>,][vendor:[<vendor-class>],][<opt>|option:<opt-name>|option6:<opt>|option6:<opt-name>],[<value>[,<value>]]
+Specify 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
+the DNS server and default route are set to the address of the machine
+running dnsmasq. (Equivalent rules apply for IPv6.) If the domain name option has been set, that is sent.
+This configuration allows these defaults to be overridden,
+or other options specified. The option, to be sent may be given as a
+decimal number or as "option:<option-name>" The option numbers are
+specified in RFC2132 and subsequent RFCs. The set of option-names
+known by dnsmasq can be discovered by running "dnsmasq --help dhcp".
+For example, to set the default route option to 
+192.168.4.4, do 
+.B --dhcp-option=3,192.168.4.4 
+or
+.B --dhcp-option = option:router, 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 
+or 
+.B --dhcp-option = option:ntp-server, 192.168.0.4
+The special address 0.0.0.0 is taken to mean "the address of the
+machine running dnsmasq". 
+
+Data types allowed are comma separated
+dotted-quad IPv4 addresses, []-wrapped IPv6 addresses, a decimal number, colon-separated hex digits
+and a text string. If the optional tags are given then
+this option is only sent when all the tags are matched.
+
+Special processing is done on a text argument for option 119, to
+conform with RFC 3397. Text or dotted-quad IP addresses as arguments
+to option 120 are handled as per RFC 3361. Dotted-quad IP addresses 
+which are followed by a slash and then a netmask size are encoded as
+described in RFC 3442.
+
+IPv6 options are specified using the 
+.B option6:
+keyword, followed by the option number or option name. The IPv6 option
+name space is disjoint from the IPv4 option name space. IPv6 addresses
+in options must be bracketed with square brackets, eg. 
+.B --dhcp-option=option6:ntp-server,[1234::56]
+For IPv6, [::] means "the global address of
+the machine running dnsmasq", whilst [fd00::] is replaced with the
+ULA, if it exists, and [fe80::] with the link-local address.
+
+Be careful: no checking is done that the correct type of data for the
+option number is sent, it is quite possible to
+persuade dnsmasq to generate illegal DHCP packets with injudicious use
+of this flag. When the value is a decimal number, dnsmasq must determine how 
+large the data item is. It does this by examining the option number and/or the
+value, but can be overridden by appending a single letter flag as follows:
+b = one byte, s = two bytes, i = four bytes. This is mainly useful with 
+encapsulated vendor class options (see below) where dnsmasq cannot
+determine data size from the  option number. Option data which
+consists solely of periods and digits will be interpreted by dnsmasq
+as an IP address, and inserted into an option as such. To force a
+literal string, use quotes. For instance when using option 66 to send
+a literal IP address as TFTP server name, it is necessary to do
+.B --dhcp-option=66,"1.2.3.4"
+
+Encapsulated Vendor-class options may also be specified (IPv4 only) using
+--dhcp-option: for instance 
+.B --dhcp-option=vendor:PXEClient,1,0.0.0.0 
+sends the encapsulated vendor
+class-specific option "mftp-address=0.0.0.0" to any client whose
+vendor-class matches "PXEClient". The vendor-class matching is
+substring based (see --dhcp-vendorclass for details). If a
+vendor-class option (number 60) is sent by dnsmasq, then that is used 
+for selecting encapsulated options in preference to any sent by the
+client. It is
+possible to omit the vendorclass completely;
+.B --dhcp-option=vendor:,1,0.0.0.0
+in which case the encapsulated option is always sent. 
+
+Options may be encapsulated (IPv4 only) within other options: for instance
+.B --dhcp-option=encap:175, 190, "iscsi-client0"
+will send option 175, within which is the option 190. If multiple
+options are given which are encapsulated with the same option number
+then they will be correctly combined into one encapsulated option.
+encap: and vendor: are may not both be set in the same dhcp-option.
+
+The final variant on encapsulated options is "Vendor-Identifying
+Vendor Options" as specified by RFC3925. These are denoted like this: 
+.B --dhcp-option=vi-encap:2, 10, "text"
+The number in the vi-encap: section is the IANA enterprise number
+used to identify this option. This form of encapsulation is supported
+in IPv6.
+ 
+The address 0.0.0.0 is not treated specially in
+encapsulated options.
+.TP
+.B --dhcp-option-force=[tag:<tag>,[tag:<tag>,]][encap:<opt>,][vi-encap:<enterprise>,][vendor:[<vendor-class>],]<opt>,[<value>[,<value>]]
+This works in exactly the same way as
+.B --dhcp-option
+except that the option will always be sent, even if the client does
+not ask for it in the parameter request list. This is sometimes
+needed, for example when sending options to PXELinux.
+.TP
+.B --dhcp-no-override
+(IPv4 only) Disable re-use of the DHCP servername and filename fields as extra
+option space. If it can, dnsmasq moves the boot server and filename
+information (from dhcp-boot) out of their dedicated fields into
+DHCP options. This make extra space available in the DHCP packet for
+options but can, rarely, confuse old or broken clients. This flag
+forces "simple and safe" behaviour to avoid problems in such a case.
+.TP
+.B --dhcp-relay=<local address>,<server address>[,<interface]
+Configure dnsmasq to do DHCP relay. The local address is an address
+allocated to an interface on the host running dnsmasq. All DHCP
+requests arriving on that interface will we relayed to a remote DHCP
+server at the server address. It is possible to relay from a single local
+address to multiple remote servers by using multiple dhcp-relay
+configs with the same local address and different server
+addresses. A server address must be an IP literal address, not a
+domain name. In the case of DHCPv6, the server address may be the
+ALL_SERVERS multicast address, ff05::1:3. In this case the interface
+must be given, not be wildcard, and is used to direct the multicast to the
+correct interface to reach the DHCP server. 
+
+Access control for DHCP clients has the same rules as for the DHCP
+server, see --interface, --except-interface, etc. The optional
+interface name in the dhcp-relay config has a different function: it
+controls on which interface DHCP replies from the server will be
+accepted. This is intended for configurations which have three
+interfaces: one being relayed from, a second connecting the DHCP
+server, and a third untrusted network, typically the wider
+internet. It avoids the possibility of spoof replies arriving via this
+third interface.
+
+It is allowed to have dnsmasq act as a DHCP server on one set of
+interfaces and relay from a disjoint set of interfaces. Note that
+whilst it is quite possible to write configurations which appear to
+act as a server and a relay on the same interface, this is not
+supported: the relay function will take precedence.
+
+Both DHCPv4 and DHCPv6 relay is supported. It's not possible to relay
+DHCPv4 to a DHCPv6 server or vice-versa.
+.TP
+.B \-U, --dhcp-vendorclass=set:<tag>,[enterprise:<IANA-enterprise number>,]<vendor-class>
+Map from a vendor-class string to a tag. Most DHCP clients provide a 
+"vendor class" which represents, in some sense, the type of host. This option 
+maps vendor classes to tags, so that DHCP options may be selectively delivered
+to different classes of hosts. For example 
+.B dhcp-vendorclass=set:printers,Hewlett-Packard JetDirect
+will allow options to be set only for HP printers like so:
+.B --dhcp-option=tag:printers,3,192.168.4.4 
+The vendor-class string is
+substring matched against the vendor-class supplied by the client, to
+allow fuzzy matching. The set: prefix is optional but allowed for
+consistency. 
+
+Note that in IPv6 only, vendorclasses are namespaced with an 
+IANA-allocated enterprise number. This is given with enterprise:
+keyword and specifies that only vendorclasses matching the specified
+number should be searched.
+.TP
+.B \-j, --dhcp-userclass=set:<tag>,<user-class>
+Map from a user-class string to a tag (with substring
+matching, like vendor classes). Most DHCP clients provide a 
+"user class" which is configurable. This option
+maps user classes to tags, so that DHCP options may be selectively delivered
+to different classes of hosts. It is possible, for instance to use
+this to set a different printer server for hosts in the class
+"accounts" than for hosts in the class "engineering".
+.TP
+.B \-4, --dhcp-mac=set:<tag>,<MAC address>
+Map from a MAC address to a tag. The MAC address may include
+wildcards. For example
+.B --dhcp-mac=set:3com,01:34:23:*:*:*
+will set the tag "3com" for any host whose MAC address matches the pattern.
+.TP
+.B --dhcp-circuitid=set:<tag>,<circuit-id>, --dhcp-remoteid=set:<tag>,<remote-id>
+Map from RFC3046 relay agent options to tags. This data may
+be provided by DHCP relay agents. The circuit-id or remote-id is
+normally given as colon-separated hex, but is also allowed to be a
+simple string. If an exact match is achieved between the circuit or
+agent ID and one provided by a relay agent, the tag is set. 
+
+.B dhcp-remoteid
+(but not dhcp-circuitid) is supported in IPv6. 
+.TP
+.B --dhcp-subscrid=set:<tag>,<subscriber-id>
+(IPv4 and IPv6) Map from RFC3993 subscriber-id relay agent options to tags.
+.TP
+.B --dhcp-proxy[=<ip addr>]......
+(IPv4 only) A normal DHCP relay agent is only used to forward the initial parts of
+a DHCP interaction to the DHCP server. Once a client is configured, it
+communicates directly with the server. This is undesirable if the
+relay agent is adding extra information to the DHCP packets, such as
+that used by
+.B dhcp-circuitid
+and
+.B dhcp-remoteid.
+A full relay implementation can use the RFC 5107 serverid-override
+option to force the DHCP server to use the relay as a full proxy, with all
+packets passing through it. This flag provides an alternative method
+of doing the same thing, for relays which don't support RFC
+5107. Given alone, it manipulates the server-id for all interactions
+via relays. If a list of IP addresses is given, only interactions via
+relays at those addresses are affected.
+.TP
+.B --dhcp-match=set:<tag>,<option number>|option:<option name>|vi-encap:<enterprise>[,<value>]
+Without a value, set the tag if the client sends a DHCP
+option of the given number or name. When a value is given, set the tag only if
+the option is sent and matches the value. The value may be of the form
+"01:ff:*:02" in which case the value must match (apart from wildcards)
+but the option sent may have unmatched data past the end of the
+value. The value may also be of the same form as in 
+.B dhcp-option
+in which case the option sent is treated as an array, and one element
+must match, so
+
+--dhcp-match=set:efi-ia32,option:client-arch,6
+
+will set the tag "efi-ia32" if the the number 6 appears in the list of
+architectures sent by the client in option 93. (See RFC 4578 for
+details.)  If the value is a string, substring matching is used.
+
+The special form with vi-encap:<enterprise number> matches against
+vendor-identifying vendor classes for the specified enterprise. Please
+see RFC 3925 for more details of these rare and interesting beasts.
+.TP
+.B --tag-if=set:<tag>[,set:<tag>[,tag:<tag>[,tag:<tag>]]]
+Perform boolean operations on tags. Any tag appearing as set:<tag> is set if
+all the tags which appear as tag:<tag> are set, (or unset when tag:!<tag> is used)
+If no tag:<tag> appears set:<tag> tags are set unconditionally.
+Any number of set: and tag: forms may appear, in any order. 
+Tag-if lines ares executed in order, so if the tag in tag:<tag> is a
+tag set by another
+.B tag-if,
+the line which sets the tag must precede the one which tests it.
+.TP
+.B \-J, --dhcp-ignore=tag:<tag>[,tag:<tag>]
+When all the given tags appear in the tag set ignore the host and do
+not allocate it a DHCP lease.
+.TP
+.B --dhcp-ignore-names[=tag:<tag>[,tag:<tag>]]
+When all the given tags appear in the tag set, ignore any hostname
+provided by the host. Note that, unlike dhcp-ignore, it is permissible
+to supply no tags, in which case DHCP-client supplied hostnames
+are always ignored, and DHCP hosts are added to the DNS using only
+dhcp-host configuration in dnsmasq and the contents of /etc/hosts and
+/etc/ethers.
+.TP
+.B --dhcp-generate-names=tag:<tag>[,tag:<tag>]
+(IPv4 only) Generate a name for DHCP clients which do not otherwise have one,
+using the MAC address expressed in hex, separated by dashes. Note that
+if a host provides a name, it will be used by preference to this,
+unless 
+.B --dhcp-ignore-names 
+is set.
+.TP
+.B --dhcp-broadcast[=tag:<tag>[,tag:<tag>]]
+(IPv4 only) When all the given tags appear in the tag set, always use broadcast to
+communicate with the host when it is unconfigured. It is permissible
+to supply no tags, in which case this is unconditional. Most DHCP clients which
+need broadcast replies set a flag in their requests so that this
+happens automatically, some old BOOTP clients do not.
+.TP
+.B \-M, --dhcp-boot=[tag:<tag>,]<filename>,[<servername>[,<server address>|<tftp_servername>]]
+(IPv4 only) Set BOOTP options to be returned by the DHCP server. Server name and
+address are optional: if not provided, the name is left empty, and the
+address set to the address of the machine running dnsmasq. If dnsmasq
+is providing a TFTP service (see 
+.B --enable-tftp
+) then only the filename is required here to enable network booting.
+If the optional tag(s) are given,
+they must match for this configuration to be sent. 
+Instead of an IP address, the TFTP server address can be given as a domain
+name which is looked up in /etc/hosts. This name can be associated in
+/etc/hosts with multiple IP addresses, which are used round-robin.
+This facility can be used to load balance the tftp load among a set of servers.
+.TP
+.B --dhcp-sequential-ip
+Dnsmasq is designed to choose IP addresses for DHCP clients using a
+hash of the client's MAC address. This normally allows a client's
+address to remain stable long-term, even if the client  sometimes allows its DHCP
+lease to expire. In this default mode IP addresses are distributed
+pseudo-randomly over the entire available address range. There are
+sometimes circumstances (typically server deployment) where it is more
+convenient to have IP
+addresses allocated sequentially, starting from the lowest available
+address, and setting this flag enables this mode. Note that in the
+sequential mode, clients which allow a lease to expire are much more
+likely to move IP address; for this reason it should not be generally used.
+.TP
+.B --pxe-service=[tag:<tag>,]<CSA>,<menu text>[,<basename>|<bootservicetype>][,<server address>|<server_name>]
+Most uses of PXE boot-ROMS simply allow the PXE
+system to obtain an IP address and then download the file specified by
+.B dhcp-boot
+and execute it. However the PXE system is capable of more complex
+functions when supported by a suitable DHCP server.
+
+This specifies a boot option which may appear in a PXE boot menu. <CSA> is
+client system type, only services of the correct type will appear in a
+menu. The known types are x86PC, PC98, IA64_EFI, Alpha, Arc_x86,
+Intel_Lean_Client, IA32_EFI,  X86-64_EFI, Xscale_EFI, BC_EFI, ARM32_EFI and ARM64_EFI; an
+integer may be used for other types. The
+parameter after the menu text may be a file name, in which case dnsmasq acts as a
+boot server and directs the PXE client to download the file by TFTP,
+either from itself (
+.B enable-tftp 
+must be set for this to work) or another TFTP server if the final server
+address/name is given.
+Note that the "layer"
+suffix (normally ".0") is supplied by PXE, and need not be added to
+the basename. Alternatively, the basename may be a filename, complete with suffix, in which case
+no layer suffix is added. If an integer boot service type, rather than a basename
+is given, then the PXE client will search for a
+suitable boot service for that type on the network. This search may be done
+by broadcast, or direct to a server if its IP address/name is provided.  
+If no boot service type or filename is provided (or a boot service type of 0 is specified)
+then the menu entry will abort the net boot procedure and
+continue booting from local media. The server address can be given as a domain
+name which is looked up in /etc/hosts. This name can be associated in
+/etc/hosts with multiple IP addresses, which are used round-robin.
+.TP
+.B --pxe-prompt=[tag:<tag>,]<prompt>[,<timeout>]
+Setting this provides a prompt to be displayed after PXE boot. If the
+timeout is given then after the
+timeout has elapsed with no keyboard input, the first available menu
+option will be automatically executed. If the timeout is zero then the first available menu
+item will be executed immediately. If 
+.B pxe-prompt
+is omitted the system will wait for user input if there are multiple
+items in the menu, but boot immediately if
+there is only one. See
+.B pxe-service 
+for details of menu items.
+
+Dnsmasq supports PXE "proxy-DHCP", in this case another DHCP server on
+the network is responsible for allocating IP addresses, and dnsmasq
+simply provides the information given in 
+.B pxe-prompt
+and
+.B pxe-service
+to allow netbooting. This mode is enabled using the
+.B proxy
+keyword in
+.B dhcp-range.
+.TP  
+.B \-X, --dhcp-lease-max=<number>
+Limits dnsmasq to the specified maximum number of DHCP leases. The
+default is 1000. This limit is to prevent DoS attacks from hosts which
+create thousands of leases and use lots of memory in the dnsmasq
+process.
+.TP
+.B \-K, --dhcp-authoritative
+Should be set when dnsmasq is definitely the only DHCP server on a network.
+For DHCPv4, it changes the behaviour from strict RFC compliance so that DHCP requests on
+unknown leases from unknown hosts are not ignored. This allows new hosts
+to get a lease without a tedious timeout under all circumstances. It also 
+allows dnsmasq to rebuild its lease database without each client needing to 
+reacquire a lease, if the database is lost. For DHCPv6 it sets the
+priority in replies to 255 (the maximum) instead of 0 (the minimum).
+.TP
+.B --dhcp-alternate-port[=<server port>[,<client port>]]
+(IPv4 only) Change the ports used for DHCP from the default. If this option is
+given alone, without arguments, it changes the ports used for DHCP
+from 67 and 68 to 1067 and 1068. If a single argument is given, that
+port number is used for the server and the port number plus one used
+for the client. Finally, two port numbers allows arbitrary
+specification of both server and client ports for DHCP.
+.TP
+.B \-3, --bootp-dynamic[=<network-id>[,<network-id>]]
+(IPv4 only) Enable dynamic allocation of IP addresses to BOOTP clients. Use this
+with care, since each address allocated to a BOOTP client is leased
+forever, and therefore becomes permanently unavailable for re-use by
+other hosts. if this is given without tags, then it unconditionally
+enables dynamic allocation. With tags, only when the tags are all
+set. It may be repeated with different tag sets. 
+.TP
+.B \-5, --no-ping
+(IPv4 only) By default, the DHCP server will attempt to ensure that an address is
+not in use before allocating it to a host. It does this by sending an
+ICMP echo request (aka "ping") to the address in question. If it gets
+a reply, then the address must already be in use, and another is
+tried. This flag disables this check. Use with caution.
+.TP
+.B --log-dhcp
+Extra logging for DHCP: log all the options sent to DHCP clients and
+the tags used to determine them.
+.TP
+.B --quiet-dhcp, --quiet-dhcp6, --quiet-ra
+Suppress logging of the routine operation of these protocols. Errors and
+problems will still be logged. --quiet-dhcp and quiet-dhcp6 are
+over-ridden by --log-dhcp.
+.TP
+.B \-l, --dhcp-leasefile=<path>
+Use the specified file to store DHCP lease information.
+.TP 
+.B --dhcp-duid=<enterprise-id>,<uid>
+(IPv6 only) Specify the server persistent UID which the DHCPv6 server
+will use. This option is not normally required as dnsmasq creates a
+DUID automatically when it is first needed. When given, this option
+provides dnsmasq the data required to create a DUID-EN type DUID. Note
+that once set, the DUID is stored in the lease database, so to change between DUID-EN and
+automatically created DUIDs or vice-versa, the lease database must be
+re-initialised. The enterprise-id is assigned by IANA, and the uid is a
+string of hex octets unique to a particular device.
+.TP
+.B \-6 --dhcp-script=<path>
+Whenever a new DHCP lease is created, or an old one destroyed, or a
+TFTP file transfer completes, the
+executable specified by this option is run.  <path>
+must be an absolute pathname, no PATH search occurs. 
+The arguments to the process
+are "add", "old" or "del", the MAC
+address of the host (or DUID for IPv6) , the IP address, and the hostname,
+if known. "add" means a lease has been created, "del" means it has
+been destroyed, "old" is a notification of an existing lease when
+dnsmasq starts or a change to MAC address or hostname of an existing
+lease (also, lease length or expiry and client-id, if leasefile-ro is set).
+If the MAC address is from a network type other than ethernet,
+it will have the network type prepended, eg "06-01:23:45:67:89:ab" for
+token ring. The process is run as root (assuming that dnsmasq was originally run as
+root) even if dnsmasq is configured to change UID to an unprivileged user.
+
+The environment is inherited from the invoker of dnsmasq, with some or
+all of the following variables added
+
+For both IPv4 and IPv6:
+
+DNSMASQ_DOMAIN if the fully-qualified domain name of the host is
+known, this is set to the  domain part. (Note that the hostname passed
+to the script as an argument is never fully-qualified.)
+
+If the client provides a hostname, DNSMASQ_SUPPLIED_HOSTNAME
+
+If the client provides user-classes, DNSMASQ_USER_CLASS0..DNSMASQ_USER_CLASSn 
+
+If dnsmasq was compiled with HAVE_BROKEN_RTC, then
+the length of the lease (in seconds) is stored in
+DNSMASQ_LEASE_LENGTH, otherwise the time of lease expiry is stored in
+DNSMASQ_LEASE_EXPIRES. The number of seconds until lease expiry is
+always stored in DNSMASQ_TIME_REMAINING. 
+
+If a lease used to have a hostname, which is
+removed, an "old" event is generated with the new state of the lease, 
+ie no name, and the former name is provided in the environment 
+variable DNSMASQ_OLD_HOSTNAME. 
+
+DNSMASQ_INTERFACE stores the name of
+the interface on which the request arrived; this is not set for "old"
+actions when dnsmasq restarts. 
+
+DNSMASQ_RELAY_ADDRESS is set if the client
+used a DHCP relay to contact dnsmasq and the IP address of the relay
+is known. 
+
+DNSMASQ_TAGS contains all the tags set during the
+DHCP transaction, separated by spaces.
+
+DNSMASQ_LOG_DHCP is set if
+.B --log-dhcp
+is in effect.
+
+For IPv4 only:
+
+DNSMASQ_CLIENT_ID if the host provided a client-id.
+
+DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBSCRIBER_ID, DNSMASQ_REMOTE_ID if a
+DHCP relay-agent added any of these options.
+ 
+If the client provides vendor-class, DNSMASQ_VENDOR_CLASS.
+
+DNSMASQ_REQUESTED_OPTIONS a string containing the decimal values in the Parameter Request List option, comma separated, if the parameter request list option is provided by the client.
+
+For IPv6 only:
+
+If the client provides vendor-class, DNSMASQ_VENDOR_CLASS_ID,
+containing the IANA enterprise id for the class, and
+DNSMASQ_VENDOR_CLASS0..DNSMASQ_VENDOR_CLASSn for the data.
+
+DNSMASQ_SERVER_DUID containing the DUID of the server: this is the same for
+every call to the script.
+
+DNSMASQ_IAID containing the IAID for the lease. If the lease is a
+temporary allocation, this is prefixed to 'T'.
+
+DNSMASQ_MAC containing the MAC address of the client, if known.
+
+Note that the supplied hostname, vendorclass and userclass data is
+only  supplied for
+"add" actions or "old" actions when a host resumes an existing lease,
+since these data are not held in dnsmasq's lease
+database.
+
+
+
+All file descriptors are
+closed except stdin, which is open to /dev/null, and stdout and stderr which capture output for logging by dnsmasq. 
+(In debug mode, stdio, stdout and stderr file are left as those inherited from the invoker of dnsmasq).
+
+The script is not invoked concurrently: at most one instance
+of the script is ever running (dnsmasq waits for an instance of script to exit
+before running the next). Changes to the lease database are which
+require the script to be invoked are queued awaiting exit of a running instance.
+If this queueing allows multiple state changes occur to a single
+lease before the script can be run then 
+earlier states are discarded and the current state of that lease is
+reflected when the script finally runs. 
+
+At dnsmasq startup, the script will be invoked for
+all existing leases as they are read from the lease file. Expired
+leases will be called with "del" and others with "old". When dnsmasq
+receives a HUP signal, the script will be invoked for existing leases
+with an "old" event.
+
+
+There are four further actions which may appear as the first argument
+to the script, "init", "arp-add", "arp-del" and "tftp". More may be added in the future, so
+scripts should be written to ignore unknown actions. "init" is
+described below in 
+.B --leasefile-ro
+The "tftp" action is invoked when a TFTP file transfer completes: the
+arguments are the file size in bytes, the address to which the file
+was sent, and the complete pathname of the file.
+ 
+The "arp-add" and "arp-del" actions are only called if enabled with
+.B --script-arp
+They are are supplied with a MAC address and IP address as arguments. "arp-add" indicates
+the arrival of a new entry in the ARP or neighbour table, and "arp-del" indicates the deletion of same.
+
+.TP
+.B --dhcp-luascript=<path>
+Specify a script written in Lua, to be run when leases are created,
+destroyed or changed. To use this option, dnsmasq must be compiled
+with the correct support. The Lua interpreter is initialised once, when
+dnsmasq starts, so that global variables persist between lease
+events. The Lua code must define a
+.B lease
+function, and may provide
+.B init
+and
+.B shutdown
+functions, which are called, without arguments when dnsmasq starts up
+and terminates. It may also provide a 
+.B tftp
+function.
+
+The 
+.B lease
+function receives the information detailed in 
+.B --dhcp-script. 
+It gets two arguments, firstly the action, which is a string
+containing, "add", "old" or "del", and secondly a table of tag value
+pairs. The tags mostly correspond to the environment variables
+detailed above, for instance the tag "domain" holds the same data as
+the environment variable DNSMASQ_DOMAIN. There are a few extra tags
+which hold the data supplied as arguments to
+.B --dhcp-script. 
+These are 
+.B mac_address, ip_address
+and 
+.B hostname
+for IPv4, and 
+.B client_duid, ip_address
+and 
+.B hostname
+for IPv6.
+
+The  
+.B tftp
+function is called in the same way as the lease function, and the
+table holds the tags 
+.B destination_address,
+.B file_name
+and 
+.B file_size.
+
+The 
+.B arp
+and
+.B arp-old
+functions are called only when enabled with
+.B --script-arp
+and have a table which holds the tags
+.B mac_address
+and
+.B client_address.
+.TP
+.B --dhcp-scriptuser
+Specify the user as which to run the lease-change script or Lua script. This defaults to root, but can be changed to another user using this flag. 
+.TP
+.B --script-arp
+Enable the "arp" and "arp-old" functions in the dhcp-script and dhcp-luascript.
+.TP
+.B \-9, --leasefile-ro
+Completely suppress use of the lease database file. The file will not
+be created, read, or written. Change the way the lease-change
+script (if one is provided) is called, so that the lease database may
+be maintained in external storage by the script. In addition to the
+invocations  given in 
+.B  --dhcp-script
+the lease-change script is called once, at dnsmasq startup, with the
+single argument "init". When called like this the script should write
+the saved state of the lease database, in dnsmasq leasefile format, to
+stdout and exit with zero exit code. Setting this
+option also forces the leasechange script to be called on changes
+to the client-id and lease length and expiry time.
+.TP
+.B --bridge-interface=<interface>,<alias>[,<alias>]
+Treat DHCP (v4 and v6) request and IPv6 Router Solicit packets
+arriving at any of the <alias> interfaces as if they had arrived at
+<interface>.  This option allows dnsmasq to provide DHCP and RA
+service over unaddressed and unbridged Ethernet interfaces, e.g. on an
+OpenStack compute host where each such interface is a TAP interface to
+a VM, or as in "old style bridging" on BSD platforms.  A trailing '*'
+wildcard can be used in each <alias>.
+.TP
+.B \-s, --domain=<domain>[,<address range>[,local]]
+Specifies DNS domains for the DHCP server. Domains may be be given 
+unconditionally (without the IP range) or for limited IP ranges. This has two effects;
+firstly it causes the DHCP server to return the domain to any hosts
+which request it, and secondly it sets the domain which it is legal
+for DHCP-configured hosts to claim. The intention is to constrain
+hostnames so that an untrusted host on the LAN cannot advertise 
+its name via dhcp as e.g. "microsoft.com" and capture traffic not 
+meant for it. If no domain suffix is specified, then any DHCP
+hostname with a domain part (ie with a period) will be disallowed 
+and logged. If suffix is specified, then hostnames with a domain 
+part are allowed, provided the domain part matches the suffix. In
+addition, when a suffix is set then hostnames without a domain
+part have the suffix added as an optional domain part. Eg on my network I can set 
+.B --domain=thekelleys.org.uk
+and have a machine whose DHCP hostname is "laptop". The IP address for that machine is available from 
+.B dnsmasq
+both as "laptop" and "laptop.thekelleys.org.uk". If the domain is
+given as "#" then the domain is read from the first "search" directive
+in /etc/resolv.conf (or equivalent).
+
+The address range can be of the form
+<ip address>,<ip address> or <ip address>/<netmask> or just a single
+<ip address>. See 
+.B --dhcp-fqdn
+which can change the behaviour of dnsmasq with domains.
+
+If the address range is given as ip-address/network-size, then a
+additional flag "local" may be supplied which has the effect of adding
+--local declarations for forward and reverse DNS queries. Eg.
+.B --domain=thekelleys.org.uk,192.168.0.0/24,local
+is identical to
+.B --domain=thekelleys.org.uk,192.168.0.0/24
+--local=/thekelleys.org.uk/ --local=/0.168.192.in-addr.arpa/
+The network size must be 8, 16 or 24 for this to be legal.
+.TP
+.B --dhcp-fqdn
+In the default mode, dnsmasq inserts the unqualified names of
+DHCP clients into the DNS. For this reason, the names must be unique,
+even if two clients which have the same name are in different
+domains. If a second DHCP client appears which has the same name as an
+existing client, the name is transferred to the new client. If 
+.B --dhcp-fqdn
+is set, this behaviour changes: the unqualified name is no longer
+put in the DNS, only the qualified name. Two DHCP clients with the
+same name may both keep the name, provided that the domain part is
+different (ie the fully qualified names differ.) To ensure that all
+names have a domain part, there must be at least 
+.B --domain 
+without an address specified when 
+.B --dhcp-fqdn 
+is set.
+.TP
+.B --dhcp-client-update
+Normally, when giving a DHCP lease, dnsmasq sets flags in the FQDN
+option to tell the client not to attempt a DDNS update with its name
+and IP address. This is because the name-IP pair is automatically
+added into dnsmasq's DNS view. This flag suppresses that behaviour,
+this is useful, for instance, to allow Windows clients to update
+Active Directory servers. See RFC 4702 for details. 
+.TP
+.B --enable-ra
+Enable dnsmasq's IPv6 Router Advertisement feature. DHCPv6 doesn't
+handle complete network configuration in the same way as DHCPv4. Router
+discovery and (possibly) prefix discovery for autonomous address
+creation are handled by a different protocol. When DHCP is in use,
+only a subset of this is needed, and dnsmasq can handle it, using
+existing DHCP configuration to provide most data. When RA is enabled,
+dnsmasq will advertise a prefix for each dhcp-range, with default
+router  as the relevant link-local address on 
+the machine running dnsmasq. By default, the "managed address" bits are set, and
+the "use SLAAC" bit is reset. This can be changed for individual
+subnets with the mode keywords described in
+.B --dhcp-range.
+RFC6106 DNS parameters are included in the advertisements. By default,
+the relevant link-local address of the machine running dnsmasq is sent
+as recursive DNS server. If provided, the DHCPv6 options dns-server and
+domain-search are used for the DNS server (RDNSS) and the domain search list (DNSSL).
+.TP
+.B --ra-param=<interface>,[mtu:<integer>|<interface>|off,][high,|low,]<ra-interval>[,<router lifetime>]
+Set non-default values for router advertisements sent via an
+interface. The priority field for the router may be altered from the
+default of medium with eg
+.B --ra-param=eth0,high.
+The interval between router advertisements may be set (in seconds) with 
+.B --ra-param=eth0,60.
+The lifetime of the route may be changed or set to zero, which allows
+a router to advertise prefixes but not a route via itself. 
+.B --ra-parm=eth0,0,0
+(A value of zero for the interval means the default value.) All four parameters may be set at once.
+.B --ra-param=eth0,mtu:1280,low,60,1200
+
+The interface field may include a wildcard.
+
+The mtu: parameter may be an arbitrary interface name, in which case the MTU value for that interface is used. This is useful
+for (eg) advertising the MTU of a WAN interface on the other interfaces of a router.
+.TP
+.B --dhcp-reply-delay=[tag:<tag>,]<integer>
+Delays sending DHCPOFFER and proxydhcp replies for at least the specified number of seconds.
+This can be used as workaround for bugs in PXE boot firmware that does not function properly when
+receiving an instant reply.
+This option takes into account the time already spent waiting (e.g. performing ping check) if any.
+.TP
+.B --enable-tftp[=<interface>[,<interface>]]
+Enable the TFTP server function. This is deliberately limited to that
+needed to net-boot a client. Only reading is allowed; the tsize and
+blksize extensions are supported (tsize is only supported in octet
+mode). Without an argument, the TFTP service is provided to the same set of interfaces as DHCP service. 
+If the list of interfaces is provided, that defines which interfaces receive TFTP service.
+.TP
+.B --tftp-root=<directory>[,<interface>]
+Look for files to transfer using TFTP relative to the given
+directory. When this is set, TFTP paths which include ".." are
+rejected, to stop clients getting outside the specified root.
+Absolute paths (starting with /) are allowed, but they must be within
+the tftp-root. If the optional interface argument is given, the
+directory is only used for TFTP requests via that interface.
+.TP
+.B --tftp-no-fail
+Do not abort startup if specified tftp root directories are inaccessible.
+.TP
+.B --tftp-unique-root[=ip|mac]
+Add the IP or hardware address of the TFTP client as a path component on the end
+of the TFTP-root. Only valid if a tftp-root is set and the directory exists.
+Defaults to adding IP address (in standard dotted-quad format).
+For instance, if tftp-root is "/tftp" and client 1.2.3.4 requests file "myfile"
+then the effective path will be "/tftp/1.2.3.4/myfile" if /tftp/1.2.3.4 exists or /tftp/myfile otherwise.
+When "=mac" is specified it will append the MAC address instead, using lowercase zero padded digits
+separated by dashes, e.g.: 01-02-03-04-aa-bb
+Note that resolving MAC addresses is only possible if the client is in the local network or obtained
+a DHCP lease from us.
+.TP
+.B --tftp-secure
+Enable TFTP secure mode: without this, any file which is readable by
+the dnsmasq process under normal unix access-control rules is
+available via TFTP. When the --tftp-secure flag is given, only files
+owned by the user running the dnsmasq process are accessible. If
+dnsmasq is being run as root, different rules apply: --tftp-secure
+has no effect, but only files which have the world-readable bit set
+are accessible. It is not recommended to run dnsmasq as root with TFTP
+enabled, and certainly not without specifying --tftp-root. Doing so
+can expose any world-readable file on the server to any host on the net. 
+.TP
+.B --tftp-lowercase
+Convert filenames in TFTP requests to all lowercase. This is useful
+for requests from Windows machines, which have case-insensitive
+filesystems and tend to play fast-and-loose with case in filenames.
+Note that dnsmasq's tftp server always converts "\\" to "/" in filenames.
+.TP
+.B --tftp-max=<connections>
+Set the maximum number of concurrent TFTP connections allowed. This
+defaults to 50. When serving a large number of TFTP connections,
+per-process file descriptor limits may be encountered. Dnsmasq needs
+one file descriptor for each concurrent TFTP connection and one
+file descriptor per unique file (plus a few others). So serving the
+same file simultaneously to n clients will use require about n + 10 file
+descriptors, serving different files simultaneously to n clients will
+require about (2*n) + 10 descriptors. If 
+.B --tftp-port-range
+is given, that can affect the number of concurrent connections.
+.TP
+.B --tftp-mtu=<mtu size>
+Use size as the ceiling of the MTU supported by the intervening network when 
+negotiating TFTP blocksize, overriding the MTU setting of the local interface  if it is larger.
+.TP
+.B --tftp-no-blocksize
+Stop the TFTP server from negotiating the "blocksize" option with a
+client. Some buggy clients request this option but then behave badly
+when it is granted.
+.TP
+.B --tftp-port-range=<start>,<end>
+A TFTP server listens on a well-known port (69) for connection initiation,
+but it also uses a dynamically-allocated port for each
+connection. Normally these are allocated by the OS, but this option
+specifies a range of ports for use by TFTP transfers. This can be
+useful when TFTP has to traverse a firewall. The start of the range
+cannot be lower than 1025 unless dnsmasq is running as root. The number
+of concurrent TFTP connections is limited by the size of the port range. 
+.TP  
+.B \-C, --conf-file=<file>
+Specify a different configuration file. The conf-file option is also allowed in
+configuration files, to include multiple configuration files. A
+filename of "-" causes dnsmasq to read configuration from stdin.
+.TP
+.B \-7, --conf-dir=<directory>[,<file-extension>......],
+Read all the files in the given directory as configuration
+files. If extension(s) are given, any files which end in those
+extensions are skipped. Any files whose names end in ~ or start with . or start and end
+with # are always skipped. If the extension starts with * then only files 
+which have that extension are loaded. So
+.B --conf-dir=/path/to/dir,*.conf
+loads all files with the suffix .conf in /path/to/dir. This flag may be given on the command
+line or in a configuration file. If giving it on the command line, be sure to
+escape * characters.
+.TP
+.B --servers-file=<file>
+A special case of 
+.B --conf-file
+which differs in two respects. Firstly, only --server and --rev-server are allowed 
+in the configuration file included. Secondly, the file is re-read and the configuration
+therein is updated when dnsmasq receives SIGHUP.
+.SH CONFIG FILE
+At startup, dnsmasq reads
+.I /etc/dnsmasq.conf,
+if it exists. (On
+FreeBSD, the file is 
+.I /usr/local/etc/dnsmasq.conf
+) (but see the 
+.B \-C
+and
+.B \-7
+options.) 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.  Quoting is allowed in a config file:
+between " quotes the special meanings of ,:. and # are removed and the
+following escapes are allowed: \\\\ \\" \\t \\e \\b \\r and \\n. The later 
+corresponding to tab, escape, backspace, return and newline.
+.SH NOTES
+When it receives a SIGHUP, 
+.B dnsmasq 
+clears its cache and then re-loads 
+.I /etc/hosts
+and 
+.I /etc/ethers 
+and any file given by --dhcp-hostsfile, --dhcp-hostsdir, --dhcp-optsfile, 
+--dhcp-optsdir, --addn-hosts or --hostsdir.
+The dhcp lease change script is called for all
+existing DHCP leases. If 
+.B
+--no-poll
+is set SIGHUP also re-reads
+.I /etc/resolv.conf.
+SIGHUP
+does NOT re-read the configuration file.
+.PP
+When it receives a SIGUSR1,
+.B dnsmasq 
+writes statistics to the system log. It writes the cache size,
+the number of names which have had to removed from the cache before
+they expired in order to make room for new names and the total number
+of names that have been inserted into the cache. The number of cache hits and 
+misses and the number of authoritative queries answered are also given. For each upstream
+server it gives the number of queries sent, and the number which
+resulted in an error. In 
+.B --no-daemon
+mode or when full logging is enabled (-q), a complete dump of the
+contents of the cache is made. 
+
+The cache statistics are also available in the DNS as answers to 
+queries of class CHAOS and type TXT in domain bind. The domain names are cachesize.bind, insertions.bind, evictions.bind, 
+misses.bind, hits.bind, auth.bind and servers.bind. An example command to query this, using the 
+.B dig
+utility would be
+
+dig +short chaos txt cachesize.bind
+
+.PP 
+When it receives SIGUSR2 and it is logging direct to a file (see
+.B --log-facility
+) 
+.B dnsmasq
+will close and reopen the log file. Note that during this operation,
+dnsmasq will not be running as root. When it first creates the logfile
+dnsmasq changes the ownership of the file to the non-root user it will run
+as. Logrotate should be configured to create a new log file with
+the ownership which matches the existing one before sending SIGUSR2.
+If TCP DNS queries are in progress, the old logfile will remain open in
+child processes which are handling TCP queries and may continue to be
+written. There is a limit of 150 seconds, after which all existing TCP
+processes will have expired: for this reason, it is not wise to
+configure logfile compression for logfiles which have just been
+rotated. Using logrotate, the required options are 
+.B create 
+and
+.B delaycompress.
+
+ 
+.PP
+Dnsmasq is a DNS query forwarder: it it not capable of recursively
+answering arbitrary queries starting from the root servers but
+forwards such queries to a fully recursive upstream DNS server which is
+typically provided by an ISP. By default, dnsmasq reads
+.I /etc/resolv.conf
+to discover the IP
+addresses of the upstream nameservers it should use, since the
+information is typically stored there. Unless
+.B --no-poll
+is used,
+.B dnsmasq
+checks the modification time of
+.I /etc/resolv.conf
+(or equivalent if 
+.B \--resolv-file 
+is used) and re-reads it if it changes. This allows the DNS servers to
+be set dynamically by PPP or DHCP since both protocols provide the
+information.
+Absence of
+.I /etc/resolv.conf
+is not an error
+since it may not have been created before a PPP connection exists. Dnsmasq 
+simply keeps checking in case
+.I /etc/resolv.conf 
+is created at any
+time. Dnsmasq can be told to parse more than one resolv.conf
+file. This is useful on a laptop, where both PPP and DHCP may be used:
+dnsmasq can be set to poll both 
+.I /etc/ppp/resolv.conf 
+and
+.I /etc/dhcpc/resolv.conf 
+and will use the contents of whichever changed
+last, giving automatic switching between DNS servers.
+.PP
+Upstream servers may also be specified on the command line or in
+the configuration file. These server specifications optionally take a
+domain name which tells dnsmasq to use that server only to find names
+in that particular domain.
+.PP
+In order to configure dnsmasq to act as cache for the host on which it is running, put "nameserver 127.0.0.1" in
+.I /etc/resolv.conf
+to force local processes to send queries to
+dnsmasq. Then either specify the upstream servers directly to dnsmasq
+using 
+.B \--server
+options or put their addresses real in another file, say
+.I /etc/resolv.dnsmasq
+and run dnsmasq with the 
+.B \-r /etc/resolv.dnsmasq
+option. This second technique allows for dynamic update of the server
+addresses by PPP or DHCP.
+.PP
+Addresses in /etc/hosts will "shadow" different addresses for the same
+names in the upstream DNS, so "mycompany.com 1.2.3.4" in /etc/hosts will ensure that
+queries for "mycompany.com" always return 1.2.3.4 even if queries in
+the upstream DNS would otherwise return a different address. There is
+one exception to this: if the upstream DNS contains a CNAME which
+points to a shadowed name, then looking up the CNAME through dnsmasq
+will result in the unshadowed address associated with the target of
+the CNAME. To work around this, add the CNAME to /etc/hosts so that
+the CNAME is shadowed too.
+
+.PP
+The tag system works as follows: For each DHCP request, dnsmasq
+collects a set of valid tags from active configuration lines which
+include set:<tag>, including one from the 
+.B dhcp-range
+used to allocate the address, one from any matching 
+.B dhcp-host
+(and "known" or "known-othernet" if a dhcp-host matches) 
+The tag "bootp" is set for BOOTP requests, and a tag whose name is the 
+name of the interface on which the request arrived is also set.
+
+Any configuration lines which include one or more tag:<tag> constructs
+will only be valid if all that tags are matched in the set derived
+above. Typically this is dhcp-option.
+.B dhcp-option 
+which has tags will be used in preference  to an untagged 
+.B dhcp-option,
+provided that _all_ the tags match somewhere in the
+set collected as described above. The prefix '!' on a tag means 'not'
+so --dhcp-option=tag:!purple,3,1.2.3.4 sends the option when the
+tag purple is not in the set of valid tags. (If using this in a
+command line rather than a configuration file, be sure to escape !,
+which is a shell metacharacter)
+
+When selecting dhcp-options, a tag from dhcp-range is second class
+relative to other tags, to make it easy to override options for
+individual hosts, so 
+.B dhcp-range=set:interface1,......
+.B dhcp-host=set:myhost,.....
+.B dhcp-option=tag:interface1,option:nis-domain,"domain1"
+.B dhcp-option=tag:myhost,option:nis-domain,"domain2"
+will set the NIS-domain to domain1 for hosts in the range, but
+override that to domain2 for a particular host.
+
+.PP
+Note that for 
+.B dhcp-range 
+both tag:<tag> and set:<tag> are allowed, to both select the range in
+use based on (eg) dhcp-host, and to affect the options sent, based on
+the range selected.
+
+This system evolved from an earlier, more limited one and for backward
+compatibility "net:" may be used instead of "tag:" and "set:" may be
+omitted. (Except in 
+.B dhcp-host,
+where "net:" may be used instead of "set:".) For the same reason, '#'
+may be used instead of '!' to indicate NOT.
+.PP 
+The DHCP server in dnsmasq will function as a BOOTP server also,
+provided that the MAC address and IP address for clients are given,
+either using 
+.B dhcp-host 
+configurations or in
+.I /etc/ethers
+, and a
+.B dhcp-range 
+configuration option is present to activate the DHCP server
+on a particular network. (Setting --bootp-dynamic removes the need for
+static address mappings.) The filename
+parameter in a BOOTP request is used as a tag,
+as is the tag "bootp", allowing some control over the options returned to
+different classes of hosts.
+
+.SH AUTHORITATIVE CONFIGURATION
+.PP 
+Configuring dnsmasq to act as an authoritative DNS server is
+complicated by the fact that it involves configuration of external DNS
+servers to provide delegation. We will walk through three scenarios of
+increasing complexity. Prerequisites for all of these scenarios
+are a globally accessible IP address, an A or AAAA record pointing to that address,
+and an external DNS server capable of doing delegation of the zone in
+question. For the first part of this explanation, we will call the A (or AAAA) record
+for the globally accessible address server.example.com, and the zone
+for which dnsmasq is authoritative our.zone.com.
+
+The simplest configuration consists of two lines of dnsmasq configuration; something like
+
+.nf
+.B auth-server=server.example.com,eth0
+.B auth-zone=our.zone.com,1.2.3.0/24
+.fi
+
+and two records in the external DNS
+
+.nf
+server.example.com       A    192.0.43.10
+our.zone.com            NS    server.example.com
+.fi
+
+eth0 is the external network interface on which dnsmasq is listening,
+and has (globally accessible) address 192.0.43.10. 
+
+Note that the external IP address may well be dynamic (ie assigned
+from an ISP by DHCP or PPP) If so, the A record must be linked to this
+dynamic assignment by one of the usual dynamic-DNS systems.
+
+A more complex, but practically useful configuration has the address
+record for the globally accessible IP address residing in the
+authoritative zone which dnsmasq is serving, typically at the root. Now
+we have
+
+.nf
+.B auth-server=our.zone.com,eth0
+.B auth-zone=our.zone.com,1.2.3.0/24
+.fi
+
+.nf
+our.zone.com             A    1.2.3.4
+our.zone.com            NS    our.zone.com
+.fi
+
+The A record for our.zone.com has now become a glue record, it solves
+the chicken-and-egg problem of finding the IP address of the
+nameserver for our.zone.com when the A record is within that
+zone. Note that this is the only role of this record: as dnsmasq is
+now authoritative from our.zone.com it too must provide this
+record. If the external address is static, this can be done with an
+.B /etc/hosts 
+entry or 
+.B --host-record.
+
+.nf
+.B auth-server=our.zone.com,eth0
+.B host-record=our.zone.com,1.2.3.4
+.B auth-zone=our.zone.com,1.2.3.0/24
+.fi
+
+If the external address is dynamic, the address
+associated with our.zone.com must be derived from the address of the
+relevant interface. This is done using 
+.B interface-name
+Something like:
+
+.nf
+.B auth-server=our.zone.com,eth0
+.B interface-name=our.zone.com,eth0
+.B auth-zone=our.zone.com,1.2.3.0/24,eth0
+.fi
+
+(The "eth0" argument in auth-zone adds the subnet containing eth0's
+dynamic address to the zone, so that the interface-name returns the
+address in outside queries.)
+
+Our final configuration builds on that above, but also adds a
+secondary DNS server. This is another DNS server which learns the DNS data
+for the zone by doing zones transfer, and acts as a backup should
+the primary server become inaccessible. The configuration of the
+secondary is beyond the scope of this man-page, but the extra
+configuration of dnsmasq is simple:
+
+.nf
+.B auth-sec-servers=secondary.myisp.com
+.fi
+
+and
+
+.nf
+our.zone.com           NS    secondary.myisp.com
+.fi
+
+Adding auth-sec-servers enables zone transfer in dnsmasq, to allow the
+secondary to collect the DNS data. If you wish to restrict this data
+to particular hosts then
+
+.nf
+.B auth-peer=<IP address of secondary>
+.fi
+
+will do so.
+
+Dnsmasq acts as an authoritative server for  in-addr.arpa and
+ip6.arpa domains associated with the subnets given in auth-zone
+declarations, so reverse (address to name) lookups can be simply
+configured with a suitable NS record, for instance in this example,
+where we allow 1.2.3.0/24 addresses.
+
+.nf
+ 3.2.1.in-addr.arpa  NS    our.zone.com
+.fi
+
+Note that at present, reverse (in-addr.arpa and ip6.arpa) zones are
+not available in zone transfers, so there is no point arranging
+secondary servers for reverse lookups.
+
+.PP
+When dnsmasq is configured to act as an authoritative server, the
+following data is used to populate the authoritative zone.
+.PP
+.B --mx-host, --srv-host, --dns-rr, --txt-record, --naptr-record
+, as long as the record names are in the authoritative domain.
+.PP
+.B --cname
+as long as the record name is in  the authoritative domain. If the
+target of the CNAME is unqualified, then it  is qualified with the
+authoritative zone name. CNAME used in this way (only) may be wildcards, as in
+
+.nf
+.B cname=*.example.com,default.example.com
+.fi
+
+.PP
+IPv4 and IPv6 addresses from /etc/hosts (and 
+.B --addn-hosts
+) and
+.B --host-record
+and 
+.B --interface-name
+provided the address falls into one of the subnets specified in the
+.B --auth-zone.
+.PP
+Addresses of DHCP leases, provided the address falls into one of the subnets specified in the
+.B --auth-zone.
+(If constructed DHCP ranges are is use, which depend on the address dynamically 
+assigned to an interface, then the form of
+.B --auth-zone
+which defines subnets by the dynamic address of an interface should
+be used to ensure this condition is met.)
+.PP 
+In the default mode, where a DHCP lease
+has an unqualified name, and possibly a qualified name constructed
+using 
+.B --domain
+then the name in the authoritative zone is constructed from the
+unqualified name and the zone's domain. This may or may not equal
+that specified by 
+.B --domain.
+If 
+.B --dhcp-fqdn
+is set, then the fully qualified names associated with DHCP leases are
+used, and must match the zone's domain.
+ 
+
+
+.SH EXIT CODES
+.PP
+0 - Dnsmasq successfully forked into the background, or terminated
+normally if backgrounding is not enabled.
+.PP
+1 - A problem with configuration was detected.
+.PP
+2 - A problem with network access occurred (address in use, attempt
+to use privileged ports without permission).
+.PP
+3 - A problem occurred with a filesystem operation (missing
+file/directory, permissions).
+.PP
+4 - Memory allocation failure.
+.PP
+5 - Other miscellaneous problem.
+.PP
+11 or greater - a non zero return code was received from the
+lease-script process "init" call. The exit code from dnsmasq is the
+script's exit code with 10 added. 
+
+.SH LIMITS
+The default values for resource limits in dnsmasq are generally
+conservative, and appropriate for embedded router type devices with
+slow processors and limited memory. On more capable hardware, it is
+possible to increase the limits, and handle many more clients. The
+following applies to dnsmasq-2.37: earlier versions did not scale as well.
+ 
+.PP
+Dnsmasq is capable of handling DNS and DHCP for at least a thousand
+clients. The DHCP lease times should not be very short (less than one hour). The
+value of 
+.B --dns-forward-max 
+can be increased: start with it equal to
+the number of clients and increase if DNS seems slow. Note that DNS
+performance depends too on the performance of the upstream
+nameservers. The size of the DNS cache may be increased: the hard
+limit is 10000 names and the default (150) is very low. Sending
+SIGUSR1 to dnsmasq makes it log information which is useful for tuning
+the cache size. See the 
+.B NOTES
+section for details.
+
+.PP
+The built-in TFTP server is capable of many simultaneous file
+transfers: the absolute limit is related to the number of file-handles
+allowed to a process and the ability of the select() system call to
+cope with large numbers of file handles. If the limit is set too high
+using 
+.B --tftp-max
+it will be scaled down and the actual limit logged at
+start-up. Note that more transfers are possible when the same file is
+being sent than when each transfer sends a different file.
+
+.PP
+It is possible to use dnsmasq to block Web advertising by using a list
+of known banner-ad servers, all resolving to 127.0.0.1 or 0.0.0.0, in
+.B /etc/hosts 
+or an additional hosts file. The list can be very long, 
+dnsmasq has been tested successfully with one million names. That size
+file needs a 1GHz processor and about 60Mb of RAM.
+
+.SH INTERNATIONALISATION
+Dnsmasq can be compiled to support internationalisation. To do this,
+the make targets "all-i18n" and "install-i18n" should be used instead of
+the standard targets "all" and "install". When internationalisation
+is compiled in, dnsmasq will produce log messages in the local
+language and support internationalised domain names (IDN). Domain
+names in /etc/hosts, /etc/ethers and /etc/dnsmasq.conf which contain
+non-ASCII characters will be translated to the DNS-internal punycode
+representation. Note that
+dnsmasq determines both the language for messages and the assumed
+charset for configuration
+files from the LANG environment variable. This should be set to the system
+default value by the script which is responsible for starting
+dnsmasq. When editing the configuration files, be careful to do so
+using only the system-default locale and not user-specific one, since
+dnsmasq has no direct way of determining the charset in use, and must
+assume that it is the system default. 
+ 
+.SH FILES
+.IR /etc/dnsmasq.conf 
+
+.IR /usr/local/etc/dnsmasq.conf
+
+.IR /etc/resolv.conf
+.IR /var/run/dnsmasq/resolv.conf
+.IR /etc/ppp/resolv.conf
+.IR /etc/dhcpc/resolv.conf
+
+.IR /etc/hosts
+
+.IR /etc/ethers
+
+.IR /var/lib/misc/dnsmasq.leases 
+
+.IR /var/db/dnsmasq.leases
+
+.IR /var/run/dnsmasq.pid
+.SH SEE ALSO
+.BR hosts (5), 
+.BR resolver (5)
+.SH AUTHOR
+This manual page was written by Simon Kelley <simon@thekelleys.org.uk>.
+
+
diff --git a/man/es/dnsmasq.8 b/man/es/dnsmasq.8
new file mode 100755
index 0000000..81c745a
--- /dev/null
+++ b/man/es/dnsmasq.8
@@ -0,0 +1,1521 @@
+.TH DNSMASQ 8
+.SH NOMBRE
+dnsmasq \- Un ligero servidor DHCP y DNS con caché.
+.SH SINOPSIS
+.B dnsmasq
+.I [OPCION]...
+.SH "DESCRIPCIÓN"
+.BR dnsmasq
+es un ligero servidor DNS, TFTP y DHCP. Su propósito es proveer servicios DNS
+y DHCP a una red de área local.
+.PP
+Dnsmasq acepta búsquedas DNS y las responde desde un pequeño
+caché local, o las reenvía hacia un servidor DNS real recursivo.
+Carga el contenido de /etc/hosts, de tal forma que nombres de
+hosts locales los cuales no aparecen en el DNS mundial puedan ser
+resueltos. También responde a búsquedas DNS para hosts configurados
+vía DHCP.
+.PP
+El servidor DHCP dnsmasq incluye soporte para asignación de direcciones
+estáticas y redes múltiples. Automáticamente envía un predeterminado sensible de
+opciones DHCP, y puede ser configurado para enviar cualquier opciones DHCP deseadas,
+incluyendo opciones encapsuladas por vendedores. Incluye un servidor seguro
+TFTP solo-lectura para permitir el inicio vía red/PXE de hosts DHCP. Tambíen
+incluye soporte para BOOTP.
+.PP
+Dnsmasq
+incluye soporte IPv6 para DNS, pero no para DHCP.
+.SH OPCIONES
+Nótese que en general parámetros ausentes son permitidos y deshabilitan
+funciones, por ejemplo "--pid-file=" deshabilita la escritura de un
+archivo PID. En BSD, a menos que la librería GNU getopt esté enlazada,
+la forma larga de las opciones no funciona en la línea de comandos,
+pero todavía es reconocida en el archivo de configuración.
+.TP
+.B --test
+Leer archivo(s) de configuración y revisar su sintaxis. Salir con código
+0 si todo está bien, o un código no-cero en cualquier otro caso. No
+iniciar dnsmasq.
+.TP
+.B \-h, --no-hosts
+No leer los nombres de hosts en /etc/hosts.
+.TP
+.B \-H, --addn-hosts=<archivo>
+Archivo de hosts adicional. Leer el archivo especificado adicionalmente
+a /etc/hosts. Si se brinda -h, leer solo el archivo especificado. Esta
+opción puede ser repetida para más de un archivo de hosts adicional. Si
+un directorio es brindado, entonces leer todos los archivos contenidos en
+ese directorio.
+.TP
+.B \-E, --expand-hosts
+Agregar el dominio a nombres sencillos (sin punto) en /etc/hosts de la
+misma manera que con nombres derivados de DHCP. Nótese que esto no
+aplica a nombres de dominio en cnames, expedientes PTR, TXT, etc.
+.TP
+.B \-T, --local-ttl=<tiempo>
+Al responder con información desde /etc/hosts o desde el archivo
+de arriendos DHCP, dnsmasq fija el tiempo de vida (TTL) a cero por
+predeterminado, significando que el remitente no debrá cachear
+la información por sí mismo. Esto es lo correcto a hacer en casi
+todas las situaciones. Esta opción permite que se especifique
+cierto tiempo de vida (en segundos) para estas respuestas. Esto
+reduce la carga sobre el servidor al costo de que los clientes
+usaran datos añejos bajo algunas circunstancias.
+.TP
+.B --neg-ttl=<tiempo>
+Respuestas negativas desde servidores upstream normalmente contienen
+información time-to-live (tiempo de vida) en expedientes SOA que
+dnsmasq usa para hacer caché. Si las respuestas de servidores upstream
+omiten esta información, dnsmasq no mete la respuesta en el caché.
+Esta opción brinda un valor predeterminado para el time-to-live que
+dnsmasq usa para meter respuestas negativas en el caché aún en la
+ausencia de un expediente SOA.
+.TP
+.B --max-ttl=<tiempo>
+Fijar un valor TTL (tiempo de vida) máximo que será entregado a
+clientes. El TTL máximo especificado será otorgado a clientes en vez
+del TTL verdadero si es menor. El valor TTL real es mantenido en el caché
+para prevenir la inundación de los servidores DNS upstream.
+.TP
+.B \-k, --keep-in-foreground
+No ir hacia el fondo al iniciar, pero aparte de eso ejecutar como
+normal. La intención de esto es para cuando dnsmasq es ejecutado
+bajo daemontools o launchd.
+.TP
+.B \-d, --no-daemon
+Modo debug: no hacer un fork hacia el fondo, no crear un archivo PID,
+no cambiar el ID del usuario, generar un cache dump completo al
+recibir un SIGUSR1, bitacorear a stderr al igual que a syslog, no
+forkear procesos nuevos para manejar búsquedas TCP.
+.TP
+.B \-q, --log-queries
+Bitacorear los resultados de búsquedas DNS manejadas por dnsmasq.
+Habilitar un dump de caché completo al recibir un SIGUSR1.
+.TP
+.B \-8, --log-facility=<facilidad>
+Fijar la facilidad a la cual dnsmasq deberá enviar mensajes syslog,
+esto es DAEMON por predeterminado, y LOCAL0 cuando el modo debug está
+en operación. Si la facilidad brindada contiene por lo menos un carácter
+"/", se trata como un nombre de archivo, y dnsmasq bitacoreará a dicho
+archivo, en vez de syslog. Si la facilidad es '-' entonces dnsmasq
+bitacorea a stderr. (Errores durante la lectura de la configuración
+irán a syslog todavía, pero todo output desde un inicio exitoso, y todo
+output mientras en ejecución, irá a este archivo exclusivamente.)
+Al bitacorear a un archivo, dnsmasq cerrará y reabrirá el archivo al
+recibir un SIGUSR2. Esto permite que el archivo de bitácora sea rotado
+sin detener a dnsmasq.
+.TP
+.B --log-async[=<líneas>]
+Habilitar bitacoréo asincrónico y opcionalmente fijar el límite de número
+de líneas que serán enviadas a la coleta por dnsmasq cuando syslog está
+lento. Dnsmasq puede bitacorear asincrónicamente: esto le permite continuar
+funcionando sin ser bloqueado por syslog, y permite a syslog usar dnsmasq
+para búsquedas DNS sin riesgo de tranque. Si la coleta de líneas de bitácora
+se llena, dnsmasq bitacoreará el desbordamiento, y el número de mensajes
+perdidos. El tamaño predeterminado de coleta es 5, un valor sano sería 5-25,
+y un límite de 100 es impuesto.
+.TP
+.B \-x, --pid-file=<path>
+Especificar un path alterno donde dnsmasq debe guardar su PID.
+Normalmente es /var/run/dnsmasq.pid.
+.TP
+.B \-u, --user=<usuario>
+Especificar el userid al cual dnsmasq debe cambiarse despues de iniciar.
+Dnsmasq normalmente debe ser iniciado como root, pero soltará los
+privilegios root despues del inicio, cambiando a otro usuario.
+Normalmente este usuario es "nobody", pero eso se puede cambiar
+con esta opción.
+.TP
+.B \-g, --group=<grupo> 
+Especificar el grupo como el cual dnsmasq correrá. El predeterminado
+es "dip", si está disponible, para facilitar el acceso a
+/etc/ppp/resolv.conf el cuál normálmente no es globalmente leíble.
+.TP
+.B \-v, --version
+Mostrar el número de versión.
+.TP
+.B \-p, --port=<puerto>
+Escuchar en el puerto <puerto> en vez del puerto estándar DNS (53).
+Fijar esto a cero deshabilita completamente la función DNS, dejando
+solo DHCP y/o TFTP.
+.TP
+.B \-P, --edns-packet-max=<tamaño>
+Especificar el paquete UDP EDNS.0 más grande que es soportado por
+el reenviador DNS. Por predeterminado es 4096, lo cual es el
+tamaño recomendado en RFC5625.
+.TP
+.B \-Q, --query-port=<puerto>
+Enviar búsquedas outbound desde, y escuchar por respuestas en,
+el puerto UDP <puerto> en vez de usar puertos aleatorios. Nótese
+que usar esta opción hace que dnsmasq sea menos seguro contra
+ataques de spoofing DNS, pero puede ser más rápido y usar menos
+recursos.
+Fijar esta opción a zero hace que dnsmasq use un solo puerto,
+asignado por el sistema operativo (esto era el comportamiento
+predeterminado en versiones anteriores a 2.43).
+.TP
+.B --min-port=<puerto>
+No usar puertos menores a <puerto> como remitentes para búsquedas
+DNS outbound. Dnsmasq escoje puertos aleatorios como remitentes
+para búsquedas DNS outbound. Cuando esta opción es brindada, los
+puertos usados siempre serán mayores que el especificado. Esto es
+útil para sistemas detras de firewalls.
+.TP
+.B \-i, --interface=<nombre de interface>
+Escuchar solo en las interfaces especificadas. Dnsmasq automáticamente
+agrega la interface loopback a la lista de interfaces para usar cuando
+la opción
+.B \--interface
+es usada. Si ninguna opción
+.B \--interface
+o
+.B \--listen-address
+es brindada, dnsmasq escucha en todas las interfaces disponibles excepto
+cualquiera fijada con opciones
+.B \--except-interface
+Interfaces IP alias (por ejemplo, "eth1:0") no pueden ser utilizadas con
+.B --interface
+o
+.B --except-interface
+, usar --listen-address en vez.
+.TP
+.B \-I, --except-interface=<nombre de interface>
+No escuchar en la interface especificada. Nótese que el orden de
+las opciones
+.B \--listen-address
+.B --interface
+y
+.B --except-interface
+no importa y las opciones
+.B --except-interface
+siempre invalidan a las otras.
+.TP 
+.B \-2, --no-dhcp-interface=<nombre de interface>
+No proveer DHCP ni TFTP en la interface especificada, pero sí
+proveer servicio DNS.
+.TP
+.B \-a, --listen-address=<dirección IP>
+Escuchar en la(s) dirección(es) IP especificada(s). Las opciones
+.B \--interface
+y
+.B \--listen-address
+ambas pueden ser brindadas, y en tal caso el juego de ambas
+direcciones IP y interfaces es usada. Nótese que si ninguna opción
+.B \--interface
+es brindada, pero sí se brinda la opción
+.B \--listen-address
+, entonces dnsmasq no escuchará automáticamente en la interface
+loopback. Para obtener esto, su dirección IP, 127.0.0.1, debe ser
+explícitamente brindada como una opción
+.B \--listen-address
+.TP
+.B \-z, --bind-interfaces
+En sistemas que inluyen el soporte, dnsmasq acopla la dirección
+de comodín, aún cuando está escuchando solamente en algunas
+interfaces. Entonces descarta búsquedas a las cuales no debe
+responder. Esto tiene la ventaja de funcionar aún cuando
+interfaces van y vienen y cambian direcciones. Esta opción forza
+a dnsmasq a acoplarse realmente solo a las interfaces en
+las cuales está escuchando. Casi la única vez que esto es útil
+es cuando se está corriendo otro servidor DNS (o otra instancia
+de dnsmasq) en la misma máquina. Fijar esta opción tambien
+habilita multiples instancias de dnsmasq, las cuales proveen
+servicio DHCP en la misma máquina.
+.TP
+.B \-y, --localise-queries
+Retornar respuestas a búsquedas DNS desde /etc/hosts las cuales dependen
+de la interface donde entró la búsqueda. Si un nombre en /etc/hosts tiene
+mas de una dirección asociada con el, y por lo menos una de esas direcciones
+está en la misma subred de la interface donde fue enviada, entónces
+retornar solo las direcciones en esa subred. Esto permite a un servidor
+tener direcciones múltiples en /etc/hosts correspondientes a cada una de
+sus interfaces y cada host recibirá la respuesta adecuada
+dependiendo de cual red tengan adjunta. Por el momento, esta facilidad
+está limitada a IPv4.
+.TP
+.B \-b, --bogus-priv
+Búsquedas privadas reversas raras. Toda búsqueda reversa para rangos de IP
+privados (192.168.x.x, etc.) los cuales no se encuentren en
+/etc/hosts o en el archivo de arriendos DHCP es respondida con
+"dominio no existente" en vez de ser reenviada upstream.
+.TP
+.B \-V, --alias=[<IP viejo>]|[<IP inicio>-<IP final>],<IP nuevo>[,<máscara>]
+Modificar direcciones IPv4 retornadas desde servidores DNS upstream;
+<IP viejo> es remplazado con <IP nuevo>. Si la máscara opcional
+es brindada, entonces cualquier dirección que coincida con el
+<IP viejo> enmascarado será re-escrita. Así que, por ejemplo,
+.B --alias=1.2.3.0,6.7.8.0,255.255.255.0 trazará 1.2.3.56 a 6.7.8.56
+y 1.2.3.67 a 6.7.8.67. Esto es lo que
+ruteadores Cisco PIX llaman "DNS doctoring". Si la dirección vieja es
+brindada como un rango, entonces solo direcciones en ese rango, y no
+la subred entera, son re-escritas. De tal manera que
+.B --alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0
+relaciona 192.168.0.10->192.168.0.40 a 10.0.0.10->10.0.0.40
+.TP
+.B \-B, --bogus-nxdomain=<dirección IP>
+Transformar respuestas que contienen la dirección IP brindada a
+respuestas tipo "Dominio no existe". La intención de esto es actuar
+en contra de una movida desviada hecha por Verisign en septiembre
+del 2003, cuando comenzaron a retornar la dirección de un servidor
+de publicidad en respuesta a búsquedas por nombres no registrados,
+en vez de la correcta respuesta NXDOMAIN. Esta opción le dice a dnsmasq
+que debe forjear la respuesta correcta cuando ve este comportamiento.
+Para septiembre 2003 la dirección IP siendo retornada por Verisign
+es 64.94.110.11
+.TP
+.B \-f, --filterwin2k
+Algunas versiones de Windows hacen búsquedas DNS periódicas las cuales no
+reciben respuestas sensibles desde el DNS público y pueden causar problemas
+activando enlaces marcación-en-demanda. Esta opción filtra dichas búsquedas.
+Las búsquedas filtradas son para registros tipo SOA y SRV, al igual que
+tipo ANY donde el nombre pedido contiene _, para atrapar búsquedas LDAP.
+.TP
+.B \-r, --resolv-file=<archivo>
+Leer las direcciones IP de servidores DNS upstream desde <archivo>,
+en vez de /etc/resolv.conf. Para el formato de este archivo, ver
+.BR resolv.conf (5)
+Las únicas líneas relevantes a dnsmasq son las de servidores DNS. A
+dnsmasq se le puede decir que revise más de un archivo resolv.conf,
+el primer archivo especificado remplaza al predeterminado, y los
+subsiguientes son agregados a la lista. Esto es solo
+permitido al hacer polling; el archivo con la actual fecha
+de modificación más nueva es el que será usado.
+.TP
+.B \-R, --no-resolv
+No leer /etc/resolv.conf. Obtener los servidores DNS upstream solo
+desde la línea de comandos o desde el archivo de configuración de
+dnsmasq.
+.TP
+.B \-1, --enable-dbus
+Permitir que la configuración de dnsmasq sea actualizada vía llamadas
+de método DBus. La configuración que puede ser cambiada es servidores
+DNS upstream (y dominios correspondientes) y limpieza de caché. Esta
+opción requiere que dnsmasq haya sido compilado con soporte para DBus.
+.TP 
+.B \-o, --strict-order
+Por predeterminado, dnsmasq enviará búsquedas a cualquiera de los
+servidores upstream que conoce, y trata de favorecer servidores los
+cuales sabe que están activos. Fijar esta opción forza a dnsmasq a
+probar cada búsqueda con cada servidor estrictamente en el orden
+que aparecen en /etc/resolv.conf
+.TP
+.B --all-servers
+Por predeterminado, cuando dnsmasq tiene más de un servidor upstream
+disponible, enviará búsquedas a solo un servidor. Fijar esta opción
+forza a dnsmasq a enviar todas las búsquedas a todos los servidores
+disponibles. La respuesta del servidor que responda primero será
+devuelta al solicitante original.
+.TP
+.B --stop-dns-rebind
+Denegar (y bitacorear) direcciones de servidores upstream que están
+dentro de rangos IP privados. Esto bloquea un ataque donde un navegador
+detrás de un firewall es usado para analizar máquinas en la red local.
+.TP
+.B --rebind-localhost-ok
+Eximir a 127.0.0.0/8 de verificaciones de rebinding. Este rango de
+direcciones es retornado por servidores de tiempo real tipo hoyo
+negro, así que bloquearlo puede deshabilitar estos servicios.
+.TP
+.B  --rebind-domain-ok=[<domain>]|[[/<domain>/[<domain>/]
+No detectar y bloquear dns-rebind en búsquedas a estos dominios. El
+argumento puede ser o un dominio sencillo, o múltiples dominios
+rodeados por '/', como el syntax de --server, por ejemplo
+.B  --rebind-domain-ok=/dominio1/dominio2/dominio3/
+.TP
+.B \-n, --no-poll
+No revisar periodicamente a /etc/resolv.conf en busca de cambios.
+.TP
+.B --clear-on-reload
+Cuando sea que /etc/resolv.conf es re-leida, liberar el caché DNS.
+Esto es útil cuando servidores DNS nuevos puedan tener datos diferentes
+a los contenidos en el caché.
+.TP
+.B \-D, --domain-needed
+Le dice a dnsmasq que no debe reenviar búsquedas para nombres sencillos,
+sin puntos o partes de dominios, a servidores upstream. Si el nombre
+no se conoce desde /etc/hosts o desde DHCP entonces una respuesta
+"no encontrado" es devuelta.
+.TP
+.B \-S, --local, --server=[/[<dominio>]/[dominio/]][<dirección IP>[#<puerto>][@<IP de remitente>|<interface>[#<puerto>]]
+Especificar la dirección IP de servidores upstream directamente. Fijar
+esta opción no suprime la lectura de /etc/resolv.conf, use -R para
+hacer eso. Si uno a más dominios opcionales son brindados, ese servidor
+es usado solo para esos dominios y las búsquedas son hechas usando
+el servidor especificado solamente. La intención de esto es para el
+uso con servidores DNS privados: si usted tiene un servidor DNS en su
+red el cual lidea con nombres de la forma
+xxx.internal.thekelleys.org.uk en 192.168.1.1 entonces brindar la
+opción
+.B -S /internal.thekelleys.org.uk/192.168.1.1
+enviará todas las búsquedas de máquinas internas a ese servidor DNS,
+todas las demás búsquedas serán enviadas a los servidores en
+/etc/resolv.conf. Una especificación de dominio en blanco,
+.B //
+tiene el significado especial de "solo nombres no calificados", o
+sea nombres sin ningún punto en ellos. Un puerto no-estándar puede
+ser especificado como parte de la dirección IP usando el caracter
+#. Más de una opción -S es permitida, con partes de dominio o
+dirección IP repetidas como sea necesario.
+
+Dominios más específicos toman precedencia sobre los menos específicos,
+así que:
+.B --server=/google.com/1.2.3.4
+.B --server=/www.google.com/2.3.4.5
+enviará búsquedas por *.google.com hacia 1.2.3.4, excepto
+*www.google.com, el cual irá a 2.3.4.5.
+
+La dirección especial de servidor '#' significa "usar los servidores
+estándares", así que
+.B --server=/google.com/1.2.3.4
+.B --server=/www.google.com/#
+enviará búsquedas por *.google.com hacia 1.2.3.4, excepto
+*www.google.com, el cual será reenviado de manera usual.
+
+También se permite una opción -S la cual brinda un dominio pero
+ninguna dirección IP; esto le dice a dnsmasq que un dominio es local
+y puede responder a búsquedas desde /etc/hosts o DHCP pero nunca
+deberá reenviar búsquedas en ese dominio a ningún servidor upstream.
+.B local
+es un sinónimo de
+.B server
+para hacer los archivos de configuración mas claros en este caso.
+
+El string opcional despues del carácter @ le dice a dnsmasq como fijar
+el remitente de las búsquedas hacia este servidor DNS. Debe ser una
+dirección IP, la cual debe ser perteneciente a la máquina en la cual
+corre dnsmasq, de forma contraria esta línea de servidor será bitacoreada
+y después ignorada, o un nombre de interface. Si un nombre de interface
+es brindado, entonces búsquedas hacia el servidor serán forzadas vía esa
+interface; si una dirección IP es brindada, entonces la dirección de
+remitente de las búsquedas será fijada a esa dirección.
+La etiqueta query-port es ignorada para cualquier servidores que tengan
+una dirección remitente especificada, pero el puerto puede ser
+especificado directamente como parte de la dirección remitente. Forzar
+búsquedas a una interface no está implementado en todas las plataformas
+soportadas por dnsmasq.
+.TP
+.B \-A, --address=/<dominio>/[dominio/]<dirección IP>
+Especificar una dirección IP para retornar por cualquier host en
+los dominios brindados. Búsquedas en estos dominios nunca son
+reenviadas, y siempre son respondidas con la dirección IP
+especificada, la cual puede ser IPv4 o IPv6. Para brindar ambas
+direcciones IPv4 y IPv6 para un dominio, usar opciones -A repetidas.
+Nótese que /etc/hosts y arriendos DHCP invalidan esto para nombres
+individuales. Un uso común para esto es redireccionar el dominio
+doubleclick.net entero a algún servidor web local amigable para
+evitar banners de publicidad. La especificación funciona de la misma
+forma que con --server, con la facilidad adicional que /#/ coincide
+con cualquier dominio. De tal forma, --address=/#/1.2.3.4 siempre
+retornará 1.2.3.4 para cualquier búsqueda no respondida desde
+/etc/hosts o DHCP y que no haya sido enviada a un servidor DNS
+upstream por una directiva --server mas especifica.
+.TP
+.B \-m, --mx-host=<nombre mx>[[,<nombre de host>],<preferencia>]
+Retornar un record llamado <mx name> apuntando hacia el nombre de
+host brindado (opcionalmente), o el host especificado en la opción
+--mx-target, o si esa opción no es brindada, el host en el cual
+dnsmasq está corriendo. El predeterminado es útil para redireccionar
+correo de sistemas en la red local hacia un servidor central. La
+opción de preferencia es opcional, y su predeterminado es 1 si no
+es brindada. Más de un record MX puede ser brindado para un host.
+.TP 
+.B \-t, --mx-target=<nombre de host>
+Especificar el target predeterminado para el record MX devuelto
+por dnsmasq. Ver --mx-host. Si --mx-target es brindado, pero no
+--mx-host, entonces dnsmasq devuelve un record MX conteniendo
+el target MX para búsquedas MX en el nombre de host de la máquina donde
+dnsmasq está corriendo.
+.TP
+.B \-e, --selfmx
+Retornar un record MX apuntándose a sí mismo para cada máquina local.
+Máquinas locales son aquellas en /etc/hosts o con arriendos DHCP.
+.TP 
+.B \-L, --localmx
+Retornar un record MX apuntando al host brindado por mx-target (o
+la máquina donde dnsmasq está corriendo) para cada máquina local.
+Máquinas locales son aquellas en /etc/hosts o con arriendos DHCP.
+.TP
+.B \-W, --srv-host=<_servicio>.<_prot>.[<dominio>],[<target>[,<puerto>[,<prioridad>[,<peso>]]]]
+Retornar un record DNS SRV. Ver RFC2782 para detalles. Si no es
+brindada, el dominio se predetermina a el brindado por
+.B --domain.
+El predeterminado para el dominio target está vacío, el predeterminado
+para puerto es uno, y los predeterminados para peso y prioridad son cero.
+Tener cuidado al transponer data desde archivos de zona BIND: los
+números de puerto, peso, y prioridad están en un orden diferente. Más
+de un record SRV para un servicio/dominio es permitido, todos los que
+coincidan son retornados.
+.TP
+.B \-Y, --txt-record=<nombre>[[,<texto>],<texto>]
+Retornar un récord DNS TXT. El valor del récord TXT es una serie de
+strings, así que cualquier número puede ser incluido, dividido por
+comas.
+.TP
+.B --ptr-record=<nombre>[,<target>]
+Retornar un récord DNS PTR.
+.TP
+.B --naptr-record=<nombre>,<orden>,<preferencia>,<opciones>,<servicio>,<regexp>[,<remplazo>]
+Retornar un récord DNS NAPTR, como especificado en RFC3403.
+.TP
+.B --cname=<cname>,<target>
+Retornar un expediente CNAME que indica que <cname> es realmente <target>. Hay
+limitaciones significativas en el target. Debe ser un nombre DNS que le es conocido
+a dnsmasq desde /etc/hosts (o archivos hosts adicionales) o de DHCP. Si el target
+no satisface este criterio, el cname entero es ignorado. El cname debe ser único,
+pero es permisible tener más de un cname indicando el mismo target.
+.TP
+.B --interface-name=<nombre>,<interface>
+Retornar un expediente DNS, asociando el nombre con la dirección primaria
+en la interface brindada. Esta opción especifica un expediente tipo A
+para el nombre brindado de la misma forma que una línea de /etc/hosts,
+excepto que la dirección no es constante y es en vez tomada de la
+interface brindada. Si la interface está deshabilitada, nó configurada,
+o nó existente, un récord vacío es devuelto. El récord PTR relevante
+tambien es creado, trazando la dirección de la interface a el nombre.
+Más de un nombre puede ser asociado con una dirección de interface,
+repitiendo la opción. En tal caso, la primera instancia es usada para
+la traza reversa dirección-a-nombre.
+.TP
+.B \-c, --cache-size=<tamaño de caché>
+Fijar el tamaño del caché de dnsmasq. El predeterminado es 150 nombres.
+Fijar el tamaño a cero deshabilita el caché.
+.TP
+.B \-N, --no-negcache
+Deshabilitar caché negativo. El caché negativo le permite a dnsmasq
+recordar resultados tipo "dominio no existe" desde servidores DNS
+upstream y responder búsquedas idénticas sin reenviarlas nuevamente.
+.TP
+.B \-0, --dns-forward-max=<búsquedas>
+Fijar el número máximo de búsquedas DNS simultáneas. El valor
+predeterminado es 150, lo cuál debería estar bien para la mayoría
+de casos. La única situación conocida donde esto debe ser incrementado
+es al usar resolvedores de bitácoras de servidores web, los cuales pueden
+generar un número inmenso de búsquedas simultáneas.
+.TP
+.B \-F, --dhcp-range=[interface:<interface>,][tag:<tag>[,tag:<tag>],][set:<tag],]<dirección-inicio>,<dirección-final>[,<netmask>[,<broadcast>]][,<tiempo de arriendo>]
+Habilitar el servidor DHCP. Direcciones serán distribuidas desde el
+rango <dirección-inicio> hasta <dirección-final> y desde direcciones definidas
+estáticamente en opciones
+.B dhcp-host
+Si el tiempo de arriendo es especificado, entonces arriendos serán
+otorgados por esa cantidad de tiempo. El tiempo de arriendo es en
+segundos, o minutos (por ejemplo, 45m), u horas (por ejemplo, 1h), o
+"infinite". Si no es brindada, el tiempo de arriendo predeterminado
+es de una hora. El tiempo de arriendo mínimo es de dos minutos.
+Esta opción puede ser repetida, con diferentes
+direcciones, para habilitar servicio DHCP en más de una red. Para
+redes conectadas diréctamente (en otras palabras, redes en las
+cuales la máquina corriendo dnsmasq tiene una interface) la
+máscara de subred es opcional. Pero, es requerida para redes que
+reciben servicio DHCP vía un agente de relay. La dirección de
+broadcast siempre es opcional. Siempre se permite tener más de
+un rango dhcp (dhcp-range) en una subred.
+
+El parámetro opcional
+.B set:<tag>
+fija una etiqueta alfanumérica la cual marca esta red de
+tal forma que opciones dhcp puedan ser especificadas en base a cada red.
+Cuando es prefijada con 'tag:' en vez, entonces el significado cambia
+de "fijar etiqueta" a "coincidir con etiqueta". Solo una etiqueta puede
+ser fijada, pero más de una puede ser revisada por coincidencias. La
+dirección final puede ser remplazada por la palabra clave
+.B static
+la cual le dice a dnsmasq que debe habilitar DHCP para la red
+especificada, pero no alocar dinámicamente direcciones IP:
+Solo hosts que tienen direcciones estáticas brindadas vía
+.B dhcp-host
+o desde /etc/ethers serán servidas. La dirección final puede ser
+remplazada por la palabra clave
+.B proxy
+caso en el cual dnsmasq proveerá proxy-DHCP en la subred especificada. (Ver
+.B pxe-prompt
+y
+.B pxe-service
+para detalles.)
+
+La sección interface:<interface name> no es normalmente usada. Ver la
+sección NOTAS para detalles sobre esto.
+.TP
+.B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][,<ipaddr>][,<hostname>][,<tiempo_de_arriendo>][,ignorar]
+Especificar parámetros por host para el servidor DHCP. Esto permite
+que una máquina con una dirección de hardware particular sea siempre
+alocada el mismo nombre de host, dirección IP, y tiempo de arriendo.
+Un nombre de host especificado de esta manera toma presedencia
+sobre cualquiera suministrado por el cliente DHCP en la máquina.
+También se permite omitir la direccion de hardware y incluir el
+nombre de host; en tal caso la dirección IP y los tiempos de arriendo
+serán aplicables a cualquier máquina que reclame ese nombre.
+Por ejemplo:
+.B --dhcp-host=00:20:e0:3b:13:af,wap,infinite
+le dice a dnsmasq que debe darle a la máquina con dirección
+ethernet 00:20:e0:3b:13:af el nombre wap, y un arriendo DHCP infinito.
+.B --dhcp-host=lap,192.168.0.199
+le dice a dnsmasq que siempre debe alocarle a la maquina lap
+la dirección IP 192.168.0.199.
+
+Direcciones alocadas de esta manera no tienen que estar dentro
+del rango dado con la opción --dhcp-range, pero deben estar en la subred
+de un rango DHCP (dhcp-range) válido. Para subredes que no necesitan
+una collección de direcciones dinamicamente alocadas, usar la palabra
+clave "static" in la declaración dhcp-range.
+
+Es permitido usar identificadores de cliente en vez de direcciones de
+hardware para identificar hosts prefijando 'id:'. O sea que:
+.B --dhcp-host=id:01:02:03:04,.....
+se refiere al host con identificador de cliente 01:02:03:04.
+También se permite especificar el ID de cliente como texto, así:
+.B --dhcp-host=id:iddeclientecomotexto,.....
+
+La opción especial id:* significa "ignorar cualquier ID de cliente
+y usar solamente direcciones MAC." Esto es útil cuando un cliente
+presenta un ID de cliente algunas veces pero otras no.
+
+Si un nombre aparece en /etc/hosts, la dirección asociada puede
+ser alocada a un arriendo DHCP, pero solo si existe una opción
+.B --dhcp-host
+la cual especifica el nombre también. Solo un hostname puede ser
+brindado en una opción
+.B dhcp-host
+pero aliases son posibles por medio del uso de CNAMEs. (Ver
+.B --cname
+).
+
+La palabra clave "ignore"
+le dice a dnsmasq que no debe ofrecer jamás un arriendo DHCP a
+una máquina. La máquina puede ser especificada por dirección de
+hardware, ID de cliente, o nombre de host, por ejemplo:
+.B --dhcp-host=00:20:e0:3b:13:af,ignore
+Esto es útil cuando hay otro servidor DHCP en la red que debe ser
+usado por algúnas máquinas.
+
+El set:<tag> fija la etiqueta cuando sea que
+esta directiva dhcp-host está en uso. Esto puede ser usado para
+enviar selectivamente opciones DHCP a este host. Más de una etiqueta
+puede ser fijada en una directiva dhcp-host (pero no en otros lugares
+donde "set:<tag>" es permitido). Cuando un host coincide con 
+cualquier directiva dhcp-host (o una implicada por
+/etc/ethers) entonces la etiqueta especial "known" es
+fijada. Esto permite que dnsmasq sea configurado para ignorar
+pedidos desde máquinas desconocidas usando
+.B --dhcp-ignore=tag:!known
+Direcciones ethernet (pero no client-ids) pueden tener bytes
+comodínes, así que por ejemplo
+.B --dhcp-host=00:20:e0:3b:13:*,ignore
+causará que dnsmasq ignore un rango de direcciones ethernet. Nótese
+que el "*" necesitará ser escapado o escrito entre comillas en la
+línea de comandos, pero no en el archivo de configuración.
+
+Direcciones de hardware normalmente coinciden con cualquier
+tipo de red (ARP), pero es posible restringirlas a un tipo ARP
+singular precediendolo con el tipo ARP (en HEX) y "-". Así que
+.B --dhcp-host=06-00:20:e0:3b:13:af,1.2.3.4
+solo coincidiría con una dirección de hardware Token-Ring, dado que
+el tipo ARP para Token-Ring es 6.
+
+Como caso especial, es posible incluir más de una dirección de
+hardware. Ejemplo:
+.B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2
+Esto permite que una dirección IP sea asociada con
+direcciones de hardware múltiples, y le brinda a dnsmasq permiso
+para abandonar un arriendo DHCP a una de las direcciones de hardware
+cuando otra pide un arriendo. Nótese que esto es algo peligroso,
+sólo funcionará dependiblemente si una de las direcciones de hardware
+está activa en cualquier momento y dnsmasq no tiene forma de enforzar
+esto. Pero es útil, por ejemplo, para alocar una dirección IP estable
+a una laptop que tiene interface alámbrica e inalámbrica.
+.TP
+.B --dhcp-hostsfile=<archivo>
+Leer información host DHCP desde el archivo especificado. El archivo contiene información de un host por línea. El formato de una línea es igual que texto hacia la derecha de '=' en --dhcp-host. La ventaja de almacenar información host DHCP en este archivo es que puede ser cambiada sin tener que reiniciar dnsmasq. El archivo será re-leído cuando dnsmasq recibe un SIGHUP.
+.TP
+.B --dhcp-optsfile=<archivo>
+Leer información sobre opciones DHCP desde el archivo especificado. La
+ventaja de usar esta opción es la misma que con --dhcp-hostsfile: el
+archivo dhcp-optsfile será re-leído cuando dnsmasq recibe un SIGHUP.
+Nótese que es posible colocar la información mediante
+.B --dhcp-boot
+como opciones DHCP, usando los nombres de opción bootfile-name,
+server-ip-address, y tftp-server. Esto permite que sean incluidas en
+un archivo dhcp-optsfile.
+.TP
+.B \-Z, --read-ethers
+Leer /etc/ethers en busca de información sobre hosts para el servidor
+DHCP. El formato de /etc/ethers es una dirección de hardware, seguida
+por ya sea un nombre de host o una dirección IP. Al ser leidas por
+dnsmasq, estas líneas tienen exáctamente el mismo efecto que opciones
+.B --dhcp-host
+que contienen la misma información. /etc/ethers es re-leída cuando
+dnsmasq recibe un SIGHUP.
+.TP
+.B \-O, --dhcp-option=[tag:<tag>,[tag:<tag>,]][encap:<opt>,][vi-encap:<enterprise>,][vendor:[<vendor-class>],][<opt>|option:<opt-name>],[<value>[,<value>]]
+Especificar opciones diferentes o extra a clientes DHCP. Por
+predeterminado, dnsmasq envía algunas opciones estándar a clientes
+DHCP. La máscara de subred y dirección broadcast son fijadas igual
+a las del host que corre dnsmasq, y el servidor DNS y ruteador
+a la dirección de la máquina que corre dnsmasq. Si la opción de
+nombre de dominio ha sido fijada, es enviada. Esta opción permite
+que esos predeterminados sean sobrescritos, o que sean especificadas
+otras opciones. La opción a ser enviada puede ser brindada como un
+número decimal o como "option:<option-name>". Los números de opción
+están especificados en RFC2132 y RFCs subsiguientes. El juego de
+option-names conocido por dnsmasq puede ser descubierto ejecutando
+"dnsmasq --help dhcp". Por ejemplo, para fijar la ruta predeterminada a
+192.168.4.4, hágase un
+.B --dhcp-option=3,192.168.4.4
+o
+.B --dhcp-option=option:router, 192.168.4.4
+y para fijar la dirección de servidor de tiempo a 192.168.0.4,
+hágase un
+.B --dhcp-option=42,192.168.0.4
+o
+.B --dhcp-option=option:ntp-server, 192.168.0.4
+La dirección especial 0.0.0.0 es entendida que significa "la
+dirección de la máquina que corre dnsmasq". Tipos de data permitidos
+son direcciones IP de cuatro segmentos, un número decimal, dígitos hex
+separados por colones, y un string de texto. Si las etiquetas
+opcionales son brindadas, entonces esta opción es solo enviada cuando
+todas las etiquetas coinciden.
+
+Procesamiento especial es llevado a cabo en un argumento de texto para
+la opción 119, en conforme con RFC3397. Direcciones IP textuales o de
+cuatro segmentos como argumentos a la opción 120 son manejados mediante
+RFC3361. Direcciones IP de cuatro segmentos que son seguidas por un diagonal
+(slash) y después una máscara son codificados mediante RFC3442.
+
+Tener cuidado: niguna verificación es hecha sobre si el número de tipo
+correcto es enviado, y es muy posible persuadir a dnsmasq para que
+genere paquetes DHCP ilegales mediante uso inadecuado de esta opción.
+Cuando el valor es un número decimal, dnsmasq debe determinar qué tan
+grande es el objeto de data. Esto es hecho mediante una examinación del
+número de opción, y/o el valor, pero puede ser invalidado agregándole
+una opción de una sola letra de esta forma: b = un byte, s = dos bytes,
+i = cuatro bytes. Esto es principalmente útil con opciones encapsuladas
+tipo vendedor (ver abajo) donde dnsmasq no puede determinar el tamaño
+de data usando el número de opción. Data de opción la cual consiste
+solo de puntos y dígitos será interpretada por dnsmasq como una
+dirección IP, y será insertada dentro de una opción de esa manera.
+Para forzar un string literal, usar comillas. Por ejemplo, cuando se
+usa la opción 66 para enviar una IP literal como un nombre de servidor
+TFTP, es necesario hacer:
+.B --dhcp-option=66,"1.2.3.4"
+
+Opciones encapsuladas vendor-class también pueden ser especificadas usando
+--dhcp-option: por ejemplo
+.B --dhcp-option=vendor:PXEClient,1,0.0.0.0
+envía la opción específica de clase de vendedor "mftp-address=0.0.0.0" a
+cualquier cliente cuyo vendor-class
+coincida con "PXEClient". El revisado de coincidencias vendor-class está
+basado en substrings (ver --dhcp-vendorclass para detalles). Si una opción
+vendor-class (número 60) es enviada por dnsmasq, entonces es usada para
+seleccionar opciones encapsuladas en preferencia sobre cualquiera enviada
+por el cliente. Es posible omitir el vendorclass completamente;
+.B --dhcp-option=vendor:,1,0.0.0.0
+caso en el cuál la opción encapsulada siempre es enviada.
+Opciones pueden ser encapsuladas dentro de otras opciones, por ejemplo:
+.B --dhcp-option=encap:175, 190, "iscsi-client0"
+enviará opción 175, dentro de la cual está opción 190. Si múltiples
+opciones son brindadas que están encapsuladas con el mismo número de
+opción entonces serán correctamente combinadas en una opción encapsulada.
+encap: y vendor: no pueden ser fijadas ambas dentro de la misma opción dhcp-option.
+
+La variante final en opciones encapsuladas es "Vendor-Identifying Vendor Options"
+como especificado en RFC3925. Estos son denotados así:
+.B --dhcp-option=rfc3925-encap:2, 10, "text"
+El número en la sección rfc3925-encap: es el número enterprise usado
+para identificar esta opción.
+
+La dirección 0.0.0.0 no es tratada de forma especial en opciones encapsuladas.
+.TP
+.B --dhcp-option-force=[tag:<tag>,[tag:<tag>,]][encap:<opt>,][vi-encap:<enterprise>,][vendor:[<vendor-class>],]<opt>,[<value>[,<value>]]
+Esto funciona exáctamente de la misma forma que
+.B --dhcp-option
+excepto que la opción siempre será enviada, aún si el cliente no la pide en
+la lista de pedido de parámetros. Esto se necesita aveces, por ejemplo cuando
+enviando opciones a PXELinux.
+.TP
+.B --dhcp-no-override
+Deshabilitar la reutilización de los campos DHCP de nombre de servidor y
+archivo como espacio para opciones extra. Si puede, dnsmasq mueve la información
+del servidor boot y del nombre de archivo (de dhcp-boot) de sus campos dedicados
+hacia opciones DHCP. Esto crea espacio extra en el paquete DHCP para opciones,
+pero puede raramente confundir clientes viejos o defectuosos. Esta opción forza
+comportamiento "simple y sencillo" para prevenir problemas en tales casos.
+.TP
+.B \-U, --dhcp-vendorclass=set:<tag>,<vendor-class>
+Trazar desde un string vendor-class a una etiqueta. La mayoría de los
+clientes DHCP proveen una "vendor class" la cual representa, en cierto
+sentido, el tipo de host. Esta opción traza clases de vendedor a network
+ids, de tal forma que opciones DHCP pueden ser selectivamente entregadas
+a diferentes clases de hosts. Por ejemplo
+.B dhcp-vendorclass=set:printers,Hewlett-Packard JetDirect
+peritiría que opciones sean fijadas solo para impresoras HP así:
+.B --dhcp-option=tag:printers,3,192.168.4.4
+El string vendor-class es coordinado con el vendor-class proveido por
+el cliente, para permitir coincidencias borrosas. El prefijo set: es
+opcional, pero permitido por razones de consistencia.
+.TP
+.B \-j, --dhcp-userclass=set:<tag>,<user-class>
+Trazar desde un string user-class a una etiqueta (con coordinación
+substring, como con vendor-class). La mayoría de los clientes DHCP
+proveen un "user class" el cual es configurable. Esta opción traza
+clases user a network ids, de tal manera que opciones DHCP puedan
+ser selectivamente enviadas a diferentes tipos de hosts. Es posible,
+por ejemplo, usar esto para especificar una impresora diferente para
+hosts en la clase "cuentas" que para los de la clase "ingenieria".
+.TP
+.B \-4, --dhcp-mac=set:<tag>,<MAC address>
+Trazar desde una dirección MAC a una etiqueta. La dirección MAC
+puede incluir comodínes. Por ejemplo:
+.B --dhcp-mac=set:3com,01:34:23:*:*:*
+fijaría el tag "3com" a cualquier host el cual su MAC coincida con
+el patrón.
+.TP
+.B --dhcp-circuitid=<network-id>,<circuit-id>, --dhcp-remoteid=<network-id>,<remote-id>
+Trazar de opciones agente de relay RFC3046 a etiquetas. Estos
+datos pueden ser proveídos por agentes de relay DHCP. El circuit-id o
+remote-id es normlamente brindado como hex separado por doblepuntos, pero
+también se permite un string simple. Si se obtiene una coincidencia exacta
+entre el circuit o agent ID y uno proveído por un agente de relay,
+la etiqueta es fijada.
+.TP
+.B --dhcp-subscrid=set:<tag>,<subscriber-id>
+Trazar de opciones relay subscriber-id RFC3993 a etiquetas.
+.TP
+.B --dhcp-proxy[=<ip addr>]......
+Un agente de relay normal es usado solamente para reenviar las partes
+iniciales de una interacción DHCP con el servidor DHCP. Una vez que
+un cliente es configurado, se comunica diectamente con el servidor. Esto
+es indeseable si el agente de relay está agregando información extra a
+los paquetes DHCP, tal como usado por
+.B dhcp-circuitid
+y
+.B dhcp-remoteid.
+Una implementación relay completa puede usar la opción serverid-override
+RFC 5107 para obligar al servidor DHCP a usar el relay como un proxy
+completo, con todos los paquetes pasando a travez de el. Esta opción
+provee una manera alternativa de hacer la misma cosa, para relays que
+no tienen soporte RFC 5107. Brindada por si sola, manipula el server-id
+para todas las interacciones via relays. Si una lista de IPs es brindada,
+solo interacciones via relays en esas direcciones son afectadas.
+.TP
+.B --dhcp-match=set:<tag>,<option number>|option:<option name>|vi-encap:<enterprise>[,<value>]
+Sin un valor, fijar la etiqueta si el cliente envía una opción
+DHCP del número o valor brindado. Cuando un valor es brindado, fijar la
+etiqueta solo si la opción es enviada y coincide con el valor. El valor puede
+ser de la forma "01:ff:*:02", caso en el cual el valor debe coincidir (aparte
+de los comodines) pero la opción enviada puede tener data que no coincide despues
+del final del valor. El valor también puede ser de la misma forma que
+.B dhcp-option
+caso en el cual la opción enviada es tratada como un array, y un elemento debe
+coincidir, así que
+
+--dhcp-match=set:efi-ia32,option:client-arch,6
+
+fijará la etiqueta a "efi-ia32" si el número 6 aparece en la lista de
+architecturas enviada por los clientes en opción 93. (Ver RFC 4578 para
+detalles.) Si el valor es un string, coincidencia substring es usada.
+
+La forma especial con vi-encap:<enterpise number> busca coincidencia con
+clases de vendedor identificadoras para el enterprise especificado. Por
+favor ver RFC 3925 para mas detalles sobre estas bestias raras e interesantes.
+.TP
+.B --tag-if=set:<tag>[,set:<tag>[,tag:<tag>[,tag:<tag>]]]
+Llevar a cabo operaciones boolean en etiquetas. Cualquier etiqueta
+que aparece como set:<tag> es fijada si todas las etiquetas que aparecen
+como tag:<tag> estan fijadas, (o desfijadas cuando tag:!<tag> es
+usado). Si ningún tag:<tag> aparece, etiquetas set:<tag> son fijadas
+incondicionalmente. Cualquier cantidad de formas set: y tag:
+pueden aparecer, en cualquier orden. Líneas tag-if son ejecutadas
+en orden, así que si la etiqueta en tag:<tag> es una etiqueta fijada
+por otra
+.B tag-if,
+la línea que fija la etiqueta debe preceder a la que comprueba.
+.TP
+.B \-J, --dhcp-ignore=tag:<tag>[,tag:<tag>]
+Cuando todoas las etiquetas brindadas aparecen en el juego de etiquetas
+ignorar el host y no brindarle un arriendo DHCP.
+.TP
+.B --dhcp-ignore-names[=tag:<tag>[,tag:<tag>]]
+Cuando todos las etiquetas brindadas aparecen en el juego de etiquetas, ignorar cualquier nombre de host proveido por el host. Nótese que,
+a diferencia de dhcp-ignore, es permisible no brindar ninguna etiqueta,
+y en tal caso nombres de host proveidos por clientes DHCP siempre son
+ignorados, y hosts DHCP son agregados al DNS usando solo la configuración
+dhcp-host en dnsmasq y el contenido de /etc/hosts y /etc/ethers.
+.TP
+.B --dhcp-generate-names=tag:<tag>[,tag:<tag>]
+Generar un nombre para clientes DHCP que de otra forma no tienen uno,
+usando la dirección MAC expresada en hex, separada por guiones. Nótese
+que si un host provee un nombre, será usado preferiblemente sobre este,
+a menos que
+.B --dhcp-ignore-names
+esté fijado.
+.TP
+.B --dhcp-broadcast[=tag:<tag>[,tag:<tag>]]
+Cuando todas las etiquetas aparecen en el juego de etiquetas, siempre
+usar broadcast para comunicar con el host cuando no está configurado.
+Es permisible omitir las etiquetas, caso en el cual esto es
+incondicional. La mayoría de clientes DHCP que necesitan
+respuestas broadcast fijan una opción en sus pedidos para que esto pase automaticamente, algunos clientes BOOTP viejos no lo hacen.
+.TP
+.B \-M, --dhcp-boot=[tag:<tag>,]<filename>,[<servername>[,<server address>]]
+Fijar opciones BOOTP que han de ser devueltas por el servidor DHCP. Nombre
+y dirección de servidor son opcionales: si no son brindadas, el nombre es
+dejado en blanco, y la dirección es fijada a la de la máquina que corre
+dnsmasq. Si dnsmasq está brindando servicio TFTP (ver
+.B --enable-tftp
+) entonces solo el nombre de archivo es requirido aquí para habilitar
+el inicio atravéz de una red. Si las opcionales etiquetas son brindadas,
+ellas deberán coincidir para que esta configuración sea enviada. Nótese
+que network-ids están prefijadas con "net:" para distinguirlas.
+.TP
+.B --pxe-service=[tag:<tag>,]<CSA>,<menu text>[,<basename>|<bootservicetype>][,<server address>]
+La mayoría de usos para boot-ROMS PXE simplemente permiten al sistema PXE
+obtener una dirección IP y entonces bajar el archivo especificado por
+.B dhcp-boot
+y ejecutarlo. Sin embargo, el sistema PXE es capaz de llevar
+a cabo funciones más complejas cuando están soportadas por un
+servidor DHCP adecuado.
+
+Esto especifica una opción boot que puede aparecer en un menú de boot
+PXE. <CSA> es tipo de sistema de cliente, solo servicios del tipo correcto
+aparecerán en un menú. Los tipos conocidos son x86PC, PC98, IA64_EFI,
+Alpha, Arc_x86, Intel_Lean_Client, IA32_EFI, BC_EFI, Xscale_EFI y X86-64_EFI;
+un número entero puede ser utilizado para otros tipos. El parámetro después
+del texto de menú puede ser un nombre de archivo, caso en el cuál dnsmasq
+actúa como un servidor boot y le ordena al cliente PXE bajar el archivo
+vía TFTP, ya sea de sí mismo (
+.B enable-tftp
+debe estar fijado para que esto funcione) o desde otro servidor TFTP si la
+dirección IP final es brindada.
+Nótese que el sufijo "layer" (normalmente ".0") es brindado por PXE, y
+no debe ser agregado al nombre base. Si un número entero es brindado en vez
+de un nombre base, entonces el cliente PXE buscará un servicio boot adecuado
+para ese tipo de red. Esta búsqueda puede ser hecha mediante broadcast,
+o directamente a un servidor si la dirección IP es brindada. Si ningún tipo
+de servicio boot o nombre de archivo es brindado (o un tipo de servicio boot
+de 0 es especificado), entonces la opción de menú abortará el proceso net boot
+y continuará desde el medio local.
+.TP
+.B --pxe-prompt=[tag:<tag>,]<prompt>[,<timeout>]
+Fijar esto hace que un aviso sea expuesto despues del boot PXE. Si el timeout
+es brindado, entonces despues que el timeout se haya vencido sin input del
+teclado, la primera opción del menú sera automaticamente ejecutada. Si el
+timeout es cero entonces la primera opción del menú sera automaticamente
+ejecutada. Si
+.B pxe-prompt
+es omitido, el sistema esperará para el input del usuario si hay múltiples
+artículos en el menú, pero hará boot imediatamente si hay solo uno. Ver
+.B pxe-service
+para detalles sobre artículos de menu.
+
+Dnsmasq tiene soporte para "proxy-DHCP" PXE, en este caso otro servidor
+DHCP en la red es responsable por asignar direcciones IP, y dnsmasq
+simplemente provee la dirección brindada en
+.B pxe-prompt
+y
+.B pxe-service
+para permitir boot a travez de la red. Este modo es habilitado usando
+la palabra clave
+.B proxy
+en
+.B dhcp-range.
+.TP
+.B \-X, --dhcp-lease-max=<número>
+Limita a dnsmasq a el número especificado de arriendos DHCP. El
+predeterminado es 1000. El limite es para prevenir ataques DoS desde
+hosts que crean cientos de arriendos y usan mucha de la memoria del
+proceso dnsmasq.
+.TP
+.B \-K, --dhcp-authoritative
+Esta opción debe ser fijada cuando dnsmasq es definitivamente el único
+servidor DHCP en la red. Cambia el comportamiento de RFC de tal manera
+que pedidos desde hosts no conocidos no serán ignorados. Esto permite que
+hosts nuevos puedan conseguir un arriendo sin sin un timeout bajo toda
+circunstancia. También permite que dnsmasq reconstruya su base de datos
+de arriendos sin que cada cliente necesite readquirir un arriendo
+si la base de datos es perdida.
+.TP
+.B --dhcp-alternate-port[=<puerto de servidor>[,<puerto de cliente>]]
+Cambiar del predeterminado los puertos usados para DHCP. Si esta opción
+es brindada sola, sin argumentos, cambia los puertos usados para DHCP
+de 67 y 68 a 1067 y 1068. Si un solo argumento es brindado, ese puerto
+es usado para el servidor y el número de puerto mas uno es usado
+para el cliente. Finalmente, dos números permiten que se especifiquen
+ambos los puertos de servidor y cliente para DHCP.
+.TP
+.B \-3, --bootp-dynamic[=<network-id>[,<network-id>]]
+Habilitar alocación dinámica de direcciones IP a clientes BOOTP. Usar
+esto con cuidado, ya que cada dirección alocada a un cliente BOOTP
+es arrendada para siempre, y consecuentemente queda no-disponible
+para re-uso por otros hosts. Si esto es brindado sin etiquetas,
+entonces incondicionalmente habilita alocación dinámica. Con
+etiquetas, solo cuando todas las etiquetas están fijadas. Puede
+ser repetido con diferentes juegos de etiquetas.
+.TP
+.B \-5, --no-ping
+Por predetermindado, el servidor DHCP tratará de asegurarse que una
+dirección no esté en uso antes de alocarsela a un host. Hace esto
+enviando un echo ICMP (ping) a la dirección referente. Si recibe una
+respuesta, entonces la dirección debe estar siendo usada, y se repite
+la prueba con otra. Esta opción deshabilita esta prueba. Usar con
+cuidado.
+.TP
+.B --log-dhcp
+Bitacoréo extra para DHCP: Bitacorear todas las opciones enviadas a
+clientes DHCP y las etiquetas usadas para determinarlos.
+.TP
+.B \-l, --dhcp-leasefile=<path>
+Usar el archivo especificado para almacenar información de arriendos
+DHCP.
+.TP
+.B \-6 --dhcp-script=<path>
+Cuando un arriendo DHCP nuevo es creado, o uno viejo es
+destruido, el ejecutable especificado por esta opción es ejecutado.
+<path> debe ser un pathname absoluto, ninguna búsqueda PATH ocurre.
+Los argumentos para el binario son "add", "old", o "del", la dirección
+MAC del host, la dirección IP, y el hostname, si es
+conocido. "add" significa que un arriendo ha sido creado, "del" que
+ha sido destruido, y "old" es una notificación de un arriendo existente
+cuando dnsmasq inicia o un cambio a una MAC o nombre host de un arriendo
+existente (también, tiempo de arriendo o vencimiento y client-id, si
+leasefile-ro está fijado). Si la dirección MAC es de un tipo de red
+que no es ethernet, tendrá el tipo de red precolocado, por ejemplo
+"06-01:23:45:67:89:ab" para token ring. El proceso es ejecutado como root
+(asumiendo que dnsmasq fue originalmente ejecutado como root) aún si dnsmasq
+está configurado para cambiar su UID a un usuario sin privilegios.
+
+
+El ambiente es heredado del usuario que ha invocado a dnsmasq, con algunas
+o todas de las siguientes variables agregadas.
+
+DNSMASQ_CLIENT_ID si el host brindo un client-id.
+
+DNSMASQ_DOMAIN si el nombre de dominio completamente calificado del host
+es conocido, esto es fijado a la parte del dominio.
+
+Si el cliente brinda vendor-class, hostname o user-class, estos son
+brindados en las variables
+DNSMASQ_VENDOR_CLASS, DNSMASQ_SUPPLIED_HOSTNAME, y
+DNSMASQ_USER_CLASS0..DNSMASQ_USER_CLASSn, pero solo para acciones "add"
+y "old" cuando un host reanuda un arriendo existente, dado a que estos
+datos no son almacenados en la base de datos de arriendos de dnsmasq.
+
+Si dnsmasq fue compilado con HAVE_BROKEN_RTC, entonces la duración del
+arriendo (en segundos) es almacenada en DNSMASQ_LEASE_LENGTH, de otra
+manera el tiempo de vencimiento es almacenado en DNSMASQ_LEASE_EXPIRES.
+El número de segundos faltante para el vencimiento del arriendo siempre
+es almacenado en DNSMASQ_TIME_REMAINING.
+
+Si un arriendo solía tener un nombre de host, el cual es removido, un
+evento "old" es generado con el nuevo estado del arriendo, (por ejemplo, sin
+nombre), y el nombre anterior es brindado en la variable de ambiente
+DNSMASQ_OLD_HOSTNAME.
+
+DNSMASQ_INTERFACE almacena el nombre de la interface
+en la cual llegó el pedido; esto no es fijado para acciones "viejas"
+cuando dnsmasq re-inicia.
+
+DNSMASQ_RELAY_ADDRESS es fijado si el cliente
+usó un relay DHCP para contactar a dnsmasq y la dirección IP del relay
+es conocida.
+
+DNSMASQ_TAGS contiene todas las etiquetas network-id fijadas
+durante la transacción DHCP, separadas por espacios.
+
+Todos los descriptores de archivo están cerrados
+excepto stdin, stdout, y stderr los cuales están abiertos a /dev/null
+(excepto en modo debug).
+
+Este guión no es invocado concurrentemente: máximo una instamcia del
+guión está corriendo a la vez (dnsmasq espera a que una instancia de
+guión haga exit antes de correr la siguiente). Cambios a la base de
+datos de arriendos que requieren que el guión sea invocado son puestos
+en cola esperando el exit de una instancia corriente. Si esta cola permite
+que cambios multiples de estado le ocurran a un arriendo individual antes
+de que el guión pueda ser ejecutado entonces estados anteriores son descartados
+y el estado actual del arriendo es reflejado cuando el guión finalmente corre.
+
+Al inicio de dnsmasq, el guión
+será invocado para todos los arriendos existentes mientras van siendo
+leídos desde el archivo de arriendos. Arriendos vencidos serán llamados
+con "del" y otros con "old". <path> debe ser un path absoluto, ninguna
+búsqueda PATH ocurre cuando arriendos dnsmasq serán llamados con "del"
+y otros con "old". Cuando dnsmasq recibe una señal HUP, el guión será
+invocado para arriendos existentes con un evento "old".
+.TP
+.B --dhcp-scriptuser
+Especificar el usuario como el cual se debe correr el archivo
+guión de cambio de arriendos. Este es root por predeterminado,
+pero puede ser cambiado a otro usuario mediante esta opción.
+.TP
+.B \-9, --leasefile-ro
+Suprimir completamente el uso del archivo de arriendos. El archivo no será
+creado, leído, ni escrito. Cambiar la manera en la cuál el archivo guión de
+cambio de arriendo (si es brindado) es llamado, de tal forma que la base de
+datos de arriendospueda ser mantenida en almacenaje externo por el archivo
+guión. Adicionálmente a las invocaciones brindadas en
+.B --dhcp-script
+el archivo de cambio de arriendos es llamado una vez, al inicio de dnsmasq,
+con el único argumento "init". Cuando invocado de esta forma, el guión debería
+escribir el estado guardado de la base de datos de arriendos, en formato de
+archivo de arriendos dnsmasq, a stdout y hacer exit con código exit cero. Fijar
+esta opción también forza que el archivo de cambio de arriendos sea llamado
+cuando hay cambios hechos a el client-id y tiempos de arriendo y vencimiento.
+.TP
+.B --bridge-interface=<nombre de interface>,<alias>[,<alias>]
+Tratar paquetes de pedidos DHCP (v4 y v6) y de IPv6 Router Solicit que
+llegan a cualquiera de las interfaces <alias> como si hubieran llegado
+a la interface <nombre de interface>.  Esta opción permite que dnsmasq
+puede proporcionar los servicios DHCP y RA a través de interfaces
+ethernet sin dirección y sin puente; por ejemplo en un nodo de cálculo
+de OpenStack, donde cada una de esas interfaces es una interfaz TAP
+para una máquina virtual, o al usar bridging estilo viejo en
+plataformas BSD.
+.TP
+.B \-s, --domain=<dominio>[,<rango de IPs>]
+Especifica los dominios DNS para el servidor DHCP. Dominios pueden ser
+brindados incondicionalmente (sin el rango de IPs) o para rangos limitados. Esto
+tiene dos efectos: Primeramente, causa que el servidor DHCP le devuelva el
+dominio a cualquier host que lo pida. Segundamente, fija el dominio para el
+cual es legal para hosts configurados mediante DHCP reclamar. La intención es
+restringir nombres de host para que un host no-confiado en la LAN no
+pueda proclamar su nombre vía DHCP, como por ejemplo "microsoft.com" y
+capturar tráfico no destinado a ella. Si ningún sufijo de dominio es
+especificado, entonces cualquier nombre de host con una parte de dominio
+(o sea con un punto) será negada y bitacorada. Si un sufijo es especificado,
+entonces nombres de host con una parte de dominio son permitidos, con tal
+que la parte de dominio coincida con el sufijo. Adicionalmente, cuando
+un sufijo es fijado, entonces nombres de host sin parte de dominio tienen
+el sufijo agregado como una parte de dominio opcional. Por ejemplo, en
+mi red puedo fijar
+.B --domain=thekelleys.org.uk
+y tener una maquina cuyo nombre host DHCP es "laptop". La dirección IP
+de esa máquina es disponible desde
+.B dnsmasq
+como "laptop" y "laptop.thekelleys.org.uk". Si el dominio es brindado
+como "#" entonces el dominio es leido desde la primera directiva search
+en /etc/resolv.conf (o equivalente). El rango de direcciones puede ser
+<dirección IP>,<dirección IP> or <dirección IP>/<máscara de subred>. Ver
+.B --dhcp-fqdn el cual puede cambiar el comportamiento de dnsmasq con
+dominios.
+.TP
+.B --dhcp-fqdn
+En el modo predeterminado, dnsmasq pone los nombres no-calificados
+de clientes DHCP en el DNS. Por esta razón, los nombres deben ser únicos,
+aún si dos clientes que tienen el mismo nombre están en dominios
+diferentes. Si un segundo cliente DHCP aparece el cual tiene el mismo
+nombre que un cliente existente, el nombre es transferido al cliente nuevo. Si
+.B --dhcp-fqdn
+está fijado, este comportamiento cambia: El nombre no-calificado
+no es puesto en el DNS, solo el nombre calificado. Dos clientes DHCP con
+el mismo nombre pueden ambos quedarse con el nombre, con tal que la parte
+de dominio sea diferente (o sea que los nombres completamente calificados
+difieran). Para asegurar que todos los nombres tengan una parte de dominio,
+debe haber al menos
+.B --domain
+sin una dirección especificada cuando
+.B --dhcp-fqdn
+está fijado.
+.TP
+.B --enable-tftp[=<interface>]
+Habilitar la función de servidor TFTP. Esto está deliberadamente limitado
+a lo necesario para hacerle a un cliente un inicio vía red. Solo lectura es
+permitida; las extensiones tsize y blksize son soportadas (tsize solo es
+soportada en modo octeto). Ver sección de NOTAS para el uso de el argumento
+de interface.
+.TP
+.B --tftp-root=<directory>[,<interface>]
+Buscar, relativo al directorio brindado, archivos para transferir mediante el
+uso de TFTP. Cuando esta opción está fijada, paths TFTP que incluyen ".." son
+rechazados, para prevenir que clientes salgan de la raíz especificada. Paths
+absolutos (los que comienzan con "/") están permitidos, pero deben estar
+dentro del tftp-root. Si el argumento opcional de interface es brindado, el
+directorio es solo usado para pedidos TFTP vía esa interface.
+.TP
+.B --tftp-unique-root
+Agregar la dirección IP del cliente TFTP como un componente path del lado del
+TFTP-root (en formato estándar de cuatro puntos). Solo válido si un tftp-root
+está fijado y el directorio existe. Por ejemplo, si tftp-root es "/tftp" y el
+cliente 1.2.3.4 pide el archivo "miarchivo" entonces el path efectivo será
+"/tftp/1.2.3.4/miarchivo" si /tftp/1.2.3.4 existe o /tftp/miarchivo si no.
+.TP
+.B --tftp-secure
+Habilitar modo TFTP seguro: sin esto, cualquier archivo que es leíble por el
+proceso dnsmasq bajo reglas normales de control de acceso UNIX, está disponible
+vía TFTP. Cuando la opción --tftp-secure es fijada, solo archivos
+pertenecientes al usuario que corre el proceso dnsmasq están accesibles. Si
+dnsmasq está corriendo como root, reglas diferentes aplican: --tftp-secure no
+tiene ningún efecto, pero solo archivos que tienen el bit de lectura global
+fijados están accesibles. No se recomienda correr dnsmasq como root con TFTP
+habilitado, y mucho menos sin especificar --tftp-root, ya que se puede exponer
+cualquier archivo de lectura global en el servidor a cualquier host de la red.
+.TP
+.B --tftp-max=<conecciones>
+Fijar el número máximo permitido de conecciones TFTP simultáneas. Esto es 50
+por predeterminado. Al servir un número grande de conecciones TFTP, límites
+de descriptor de archivo por proceso pueden ser encontrados. Dnsmasq necesita
+un descriptor de archivo por cada coneccion TFTP concurrente, y por archivo
+único (mas algunos otros). De tal manera que servirle el mismo archivo
+simultáneo a n clientes requerirá el uso de n + 10 descriptores de archivo,
+y servirles archivos diferentes simultáneamente requerirá (2*n) + 10
+descriptores. Si
+.B --tftp-port-range
+es brindado, eso puede afectar el número de conexiones simultáneas.
+.TP
+.B --tftp-no-blocksize
+No permitir que el servidor negocie la opción "blocksize" con un cliente.
+Algunos clientes con errores piden esta opción pero se portán mal cuando se
+les brinda.
+.TP
+.B --tftp-port-range=<inicio>,<final>
+Un servidor TFTP escucha por inicios de conexión en un puerto bien conocido
+(69), pero tambien usa un puerto dinamicamente seleccionado para cada
+conexión. Normalmente estos son seleccionados por el sistema operativo,
+pero esta opción especifica un rango de puertos para ser usado por transferencias
+TFTP. Esto puede ser útil cuando TFTP tiene que pasar atraves de un firewall.
+El comienzo del rango no puede ser menor a 1025 a menos que dnsmasq esté corriendo
+como root. El número de conexiones simultáneas está limitado por el tamaño del
+rango de puertos.
+.TP
+.B \-C, --conf-file=<archivo>
+Especificar un archivo de configuración diferente. La opción conf-file
+también es permitida en archivos de configuración, para incluir múltiples
+archivos de configuración.
+.TP
+.B \-7, --conf-dir=<directorio>[,<file-extension>......]
+Leer todos los archivos dentro del directorio brindado como archivos
+de configuración. Si extensiones son brindadas, cualquier archivo que
+termine en esas extensiones son ignorados. Cualquier archivos cuyos nombres
+terminen con ~ o comienzen con . o comienzen y terminen con # siempre son
+ignorados. Esta opción puede ser brindada en la línea de comandos o en un
+archivo de configuración.
+.SH ARCHIVO DE CONFIGURACION
+Al inicio, dnsmasq lee
+.I /etc/dnsmasq.conf,
+si existe. (En FreeBSD, el archivo es
+.I /usr/local/etc/dnsmasq.conf
+) (pero ver las opciónes
+.B \-C
+y
+.B \-7
+porfavor.) El formato de este archivo consiste de una opción por línea,
+exáctamente como las opciones largas detalladas en la sección OPCIONES
+pero sin el "--" al frente. Líneas que comienzan con # son comentarios
+y son ignoradas. Para opciones que solo pueden ser especificadas una
+sola vez, el archivo de configuración invalida la línea de comandos.
+Las comillas son permitidas en el archivo de configuración: entre comillas
+tipo " los significados especiales de ,:. y # son eliminados y los
+siguientes escapes son permitidos: \\\\ \\" \\t \\e \\b \\r y \\n.
+Corresponden a tab, escape, backspace, return y newline.
+.SH NOTAS
+Al recibir un SIGHUP
+.B dnsmasq 
+libera su cache y entonces recarga
+.I /etc/hosts
+y
+.I /etc/ethers
+al igual que cualquier archivo brindado con --dhcp-hostsfile, --dhcp-optsfile,
+o --addn-hosts.
+El archivo guión de cambio de arriendos es llamado para todos los arriendos
+DHCP existentes. Si
+.B
+--no-poll
+está fijado entonces SIGHUP también re-lee
+.I /etc/resolv.conf.
+SIGHUP
+NO re-lee el archivo de configuración.
+.PP
+Al recibir un SIGUSR1,
+.B dnsmasq 
+escribe estadísticas a la bitácora del sistema. Escribe el tamaño
+del caché, el numero de nombres que han tenido que ser removidos del
+caché antes de que vencieran para hacer espacio para nombres nuevos, y el
+número total de nombres que han sido insertados en el caché. Para cada
+servidor upstream brinda el número de búsquedas enviadas, y el
+número que resultaron en error. En modo
+.B --no-daemon
+o cuando bitacoréo completo está habilitado (-q), una descarga completa de
+el contenido del caché es hecha.
+.PP
+Cuando recibe un SIGUSR2 y está bitacoreando diréctamente a un archivo (ver
+.B --log-facility
+)
+.B dnsmasq
+cerrará y reabrirá el archivo de bitácora. Nótese que durante esta
+operación, dnsmasq no estará corriendo como root. Al crear el archivo de
+bitácora, dnsmasq cambia el dueño del archivo a el usuario normal como
+el que correrá. Logrotate debe ser configurado para crear un archivo de
+bitácora nuevo con permisos iguales al existente, antes de enviar
+SIGUSR2. Si búsquedas DNS TCP están en progreso, el archivo de bitácora
+viejo se mantendrá abierto en procesos hijos que están manejando
+búsquedas TCP, y puede continuarse a escribirle. Hay un límite de 150
+segundos, después de lo cual todos los procesos TCP existentes se habrán
+vencido: por esta razón, no es sabio configurar compresión de archivos
+de bitácora para archivos que acaban de ser rotados. Con logrotate, las
+opciones requeridas son
+.B create
+y
+.B delaycompress.
+.PP
+Dnsmasq es un reenviador de búsquedas DNS: no puede responder búsquedas
+arbitrarias comenzando desde los servidores root pero reenvía dichas
+búsquedas a un servidor DNS recursivo, el cual es típicamente proveído
+por el proveedor de Internet. Por predeterminado, dnsmasq lee
+.I /etc/resolv.conf
+para descubir las direcciones IP de los servidores DNS upstream que
+debe usar, dado a que esta información es normalmente almacenada allí.
+Amenos que
+.B --no-poll
+sea usado,
+.B dnsmasq
+revisa el tiempo de modificación de
+.I /etc/resolv.conf
+(o equivalente si
+.B \--resolv-file 
+es usado) y lo re-lee si ha cambiado. Esto permite que servidores DNS séan
+fijados dinámicamente vía PPP o DHCP ya que ambos protocolos brindan esta
+información.
+La ausencia de
+.I /etc/resolv.conf
+no es un error ya que pudo haber sido creada antes de que una conexión PPP
+haya existido. Dnsmasq simplemente sigue revisando en caso de que
+.I /etc/resolv.conf 
+sea creado en algún momento. A dnsmasq se le puede decir que revise más
+de un archivo resolv.conf. Esto es útil en una laptop, donde ambos PPP y
+DHCP podrían estar siendo usados: dnsmasq puede ser fijado para revisar ambos
+.I /etc/ppp/resolv.conf 
+y
+.I /etc/dhcpc/resolv.conf 
+y usará el contenido del que haya cambiado mas recientemente,
+brindando así la habilidad de cambio automático entre servidores DNS.
+.PP
+Servidores upstream también pueden ser especificados en la línea de
+comandos o en el archivo de configuración. Estas especificaciones de
+servidor opcionalmente llevan un nombre de dominio el cual le dice a
+dnsmasq que debe usar ese servidor solo para encontrar nombres en ese
+dominio en particular.
+.PP
+Para configurar dnsmasq como caché para el host donde está
+corriendo, poner un "nameserver 127.0.0.1" en
+.I /etc/resolv.conf
+para así forzar procesos locales a enviar búsquedas a dnsmasq. Entonces,
+o especificar los servidores upstream diréctamente a dnsmasq usando opciones
+.B \--server
+o poniendo sus direcciones reales en otro archivo, digamos
+.I /etc/resolv.dnsmasq
+y correr dnsmasq con la opcion
+.B \-r /etc/resolv.dnsmasq
+Esta segunda técnica permite la actualización dinámica de las direcciones
+de servidor mediante PPP o DHCP.
+.PP
+Direcciones en /etc/hosts "harán sombra" a diferentes direcciones para
+los mismos nombres en servidores DNS upstream, así que
+"miempresa.com 1.2.3.4" en /etc/hosts se asegurará que las búsquedas
+por "miempresa.com" siempre retornarán 1.2.3.4 aún si búsquedas en el
+servidor DNS upstream devolverían una dirección diferente. Hay una
+excepción a esto: si el servidor DNS upstream contiene un CNAME que
+apunta a un nombre sombreado, entonces buscando el CNAME a travéz de
+dnsmasq resultará en que la dirección no-sombreada será asociada con
+el destino del CNAME. Para circumventar esto, agregar el CNAME a
+/etc/hosts de tal manera que el CNAME es sombreado también.
+
+.PP
+El sistema de etiquetas funciona de la siguiente manera: Para cada pedido
+DHCP, dnsmasq colecciona un juego de etiquetas válidas de líneas de
+configuración activas que incluyen set:<tag>, incluyendo una del
+.B dhcp-range
+usado para alocar la dirección, una de cualquier
+.B dhcp-host
+que coincida (y "known" si un dhcp-host coincide).
+La etiqueta "bootp" es fijada para pedidos BOOTP, y una etiqueta cuyo
+nombre es el nombre de la interface donde llegó el pedido tambien es
+fijada.
+
+Cualquier linea de configuración que incluya uno o mas
+construcciones tag:<tag> solo será válida si todas las etiquetas
+coinciden en el juego derivado arriba. Típicamente esto es dhcp-option.
+.B dhcp-option 
+que tenga etiquetas será usada en preferencia de una opción
+.B dhcp-option,
+sin etiqueta, con tal que _todas_ las etiquetas coincidan en alguna
+parte del juego coleccionado describido arriba. El prefijo '!' en una
+etiqueta significa "no" así que --dhcp=option=tag:!purple,3,1.2.3.4 envía
+la opción cuando la etiqueta "purple" no está en el juego
+de etiquetas válidas. (Si se está usando esto en una línea de comandos
+en vez de un archivo de configuración, asegurese de escapar !, el cual
+es un metacaracter de shell.)
+.PP
+Nótese que para
+.B dhcp-range
+ambos tag:<tag> y set:<tag> son permitidos, para seleccionar el rango
+en uso basado en (por ejemplo) dhcp-host, y para afectar las opciones
+enviadas, basadas en el rango seleccionado.
+
+Este sistema evolucionó de uno anterior mas limitado y para compatibildad
+reversa "net:" puede ser usada en vez de "tag:" y "set:" puede ser
+omitida. (Excepto en
+.B dhcp-host,
+donde "net:" puede ser usado en vez de "set:".) Por la misma razón, '#'
+puede ser usado en vez de '!' para indicar NO.
+.PP
+El servidor DHCP de dnsmasq funcionará como servidor BOOTP tambien,
+con tal que las direcciones MAC y IP de los clientes sean brindadas,
+ya sea usando configuraciones
+.B dhcp-host 
+o en
+.I /etc/ethers
+, y una configuración
+.B dhcp-range 
+esté presente para activar el servidor DHCP en una red particular.
+(Fijar --bootp-dynamic elimina la necesidad de trazados estáticos.) El
+parámetro de nombre de archivos en un pedido BOOTP es usado como
+una etiqueta, al igual que la etiqueta "bootp", permitiendo así algún
+control sobre las opciones devueltas a diferentes clases de hosts.
+
+.B dhcp-range
+puede tener un nombre de interface brindado como
+"interface:<interface-name>". La semántica de esto es así:
+Para DHCP, si cualquier otro dhcp-range existe _sin_ un nombre de
+interface, entonces el nombre de interface es ignorado y dnsmasq
+se comporta como si las partes de interface no existieran, de otra forma
+DHCP solo se provee a interfaces mencionadas en declaraciones
+dhcp-range. Para DNS, si no hay opciones
+.B --interface
+o
+.B --listen-address
+el comportamiento no se modifica por la parte de interface. Si cualquiera
+de estas opciones está presente, las interfaces mencionadas en dhcp-ranges
+son agregadas all juego que obtienen servicio DNS.
+
+Similarmente,
+.B enable-tftp
+puede tomar un nombre de interface, el cual habilita TFTP solo para una
+interface en particular, ignorando opciones
+.B --interface
+o
+.B --listen-address.
+Adicionalmente, 
+.B --tftp-secure
+y
+.B --tftp-unique-root
+y
+.B --tftp-no-blocksize
+son ignorados por pedidos desde dichas interfaces. (Una directiva
+.B --tftp-root
+brindando un path raíz y una interface debe ser brindada tambien.)
+
+Estas reglas pueden parecer raras a primera vista, pero permiten que
+una simple linea de la forma
+"dhcp-range=interface:virt0,192.168.0.4,192.168.0.200" sea agregada a
+configuración dnsmasq, lo cual brinda servicios DHCP y DNS a esa interface,
+sin afectar los servicios en otras interfaces y irrespectivamente de
+la existencia o no de lineas "interface=<interface>" en alguna otra parte
+de la configuración dnsmasq.
+"enable-tftp=virt0" y "tftp-root=<root>,virt0" hacen el mismo trabajo
+para TFTP.
+La idea es que una linea así pueda ser agregada automaticamente
+por libvirt o sistemas equivalentes, sin estorbar alguna
+configuración manual.
+
+.SH CÓDIGOS EXIT
+.PP
+0 - Dnsmasq hizo fork hacia el fondo exitosamente, o terminó de manera
+normal si ir al fondo no está habilitado.
+.PP
+1 - Un problema con la configuración ha sido detectado.
+.PP
+2 - Un problema con acceso a redes ocurrió (dirección en uso, intento
+de usar puertos privilegiados sin permiso).
+.PP
+3 - Un problema con una operación de sistema de archivos ocurrió (archivo
+o directorio ausente, permisos).
+.PP
+4 - Falla de alocación de memoria.
+.PP
+5 - Otro problema misceláneo.
+.PP
+11 o mayor - un codigo de retorno no cero fué recibido del llamado "init"
+del proceso de archivo guión de arriendos. El código exit de dnsmasq es
+el código exit del archivo guión con 10 sumado.
+
+.SH LIMITES
+Los valores predeterminados para limites de recursos son generálmente
+conservadores, y apropiados para uso en dispositivos tipo enrutador
+encrustrado con procesadores lentos y poca memoria. En hardware más
+capáz, es posible incrementar los límites, y soportar muchos mas
+clientes. Lo siguiente se aplica a dnsmasq-2.37: versiones previas
+no escalaban tan bien.
+
+.PP
+Dnsmasq es capaz de soportar con DNS y DHCP a por lo menos mil (1,000)
+clientes. Los tiempos de arriendo no deben ser muy cortos (menos
+de una hora). El valor de
+.B --dns-forward-max
+puede ser aumentado: comienze con el equivalente a el número de clientes y
+auméntelo si parece lento el DNS. Nótese que el rendimiento DNS depende
+también de los servidores DNS upstream. El tamaño del caché DNS puede ser
+incrementado: el límite obligatorio es 10,000 nombres y el predeterminado
+(150) es muy bajo. El enviarle un SIGUSR1 a dnsmasq hace que bitacorée
+información que es útil para afinar el tamaño de caché. Ver la sección
+.B NOTAS
+para detalles.
+
+.PP
+El servidor TFTP incorporado es capáz de soportar varias transferencias
+simultáneas de archivos: el límite absoluto está relacionado con el número
+de file-handles permitidos a un proceso y la habilidad del system call
+select() a soportar números grandes de file-handles. Si el límite es fijado
+demasiado alto con
+.B --tftp-max
+será de-escalado y el límite real será bitacoreado al inicio. Nótese que más
+transferencias son posibles cuando el mismo archivo es enviado qué cuando
+cada transferencia envía un archivo diferente.
+
+.PP
+Es posible usar dnsmasq para negar publicidad Web usando una lista de
+servidores de banners bien conocidos, todos resolviendose a 127.0.0.1 o
+0.0.0.0 en
+.B /etc/hosts 
+o en un archivo hosts adicional. La lista puede ser muy larga. Dnsmasq ha sido
+probado exitósamente con un millón de nombres. Ese tamaño de archivo necesita
+un CPU de 1GHz y aproximadamente 60MB de RAM.
+
+.SH INTERNACIONALIZACION
+
+Dnsmasq puede ser compilado con soporte para internacionalización. Para hacer esto,
+los targets make "all-i18n" y "install-i18n" deberán ser usados en vez de
+los targets estándares "all" y "install". Cuando internacionalización es
+compilada, dnsmasq producirá mensajes de bitácora en el lenguaje local y soportará
+dominios internacionalizados (IDN). Nombres de dominio en /etc/hosts, /etc/ethers,
+y /etc/dnsmasq.conf que contienen carácteres no-ASCII serán traducidos a
+representación interna DNS punycode. Nótese que dnsmasq determina ambos el
+lenguaje para mensajes y el juego de carácteres asumido para archivos de configuración
+de la variable ambiental LANG. Esto debe estar fijado al valor predeterminado del sistema
+por el guión responsable de iniciar dnsmasq. Al editar archivos de configuración,
+tener cuidado de hacerlo usando solo el locale predeterminado del sistema y no
+uno especifico del usuario, dado a que dnsmasq no tiene ninguna manera directa de
+determinar el juego de caracteres en uso, y debe asumir que es el predeterminado
+del sistema.
+
+.SH ARCHIVOS
+.IR /etc/dnsmasq.conf 
+
+.IR /usr/local/etc/dnsmasq.conf
+
+.IR /etc/resolv.conf
+
+.IR /etc/hosts
+
+.IR /etc/ethers
+
+.IR /var/lib/misc/dnsmasq.leases 
+
+.IR /var/db/dnsmasq.leases
+
+.IR /var/run/dnsmasq.pid
+.SH VER TAMBIEN
+.BR hosts (5), 
+.BR resolver (5)
+.SH AUTOR
+Este manual fue escrito por Simon Kelley <simon@thekelleys.org.uk>.
+
+Traducido a español por Christopher Chatham <chrislinux@gmail.com>.
diff --git a/man/fr/dnsmasq.8 b/man/fr/dnsmasq.8
new file mode 100755
index 0000000..80cef39
--- /dev/null
+++ b/man/fr/dnsmasq.8
@@ -0,0 +1,2360 @@
+.TH DNSMASQ 8
+.SH NAME
+Dnsmasq \- Un serveur DHCP et cache DNS poids-plume.
+.SH SYNOPSIS
+.B dnsmasq
+.I [OPTION]...
+.SH "DESCRIPTION"
+.BR dnsmasq
+est un serveur à faible empreinte mémoire faisant DNS, TFTP, PXE, annonces de
+routeurs et DHCP. Il offre à la fois les services DNS et DHCP pour un réseau
+local (LAN).
+.PP
+Dnsmasq accepte les requêtes DNS et y réponds soit en utilisant un petit cache
+local, soit en effectuant une requête à un serveur DNS récursif externe (par
+exemple celui de votre fournisseur d'accès internet). Il charge le contenu du
+fichier /etc/hosts afin que les noms locaux n'apparaissant pas dans les DNS
+globaux soient tout de même résolus, et assure également la résolution de nom
+pour les hôtes présents dans le service DHCP. Il peut aussi agir en temps que
+serveur DNS faisant autorité pour un ou plusieurs domaines, permettant à des
+noms locaux d'apparaitre dans le DNS global.
+.PP
+Le serveur DHCP Dnsmasq DHCP supporte les définitions d'adresses statiques et les
+réseaux multiples. Il fournit par défaut un jeu raisonnable de paramètres DHCP,
+et peut être configuré pour fournir n'importe quelle option DHCP.
+Il inclut un serveur TFTP sécurisé en lecture seule permettant le démarrage via
+le réseau/PXE de clients DHCP et supporte également le protocole BOOTP. Le
+support PXE est complet, et comprend un mode proxy permettant de fournir des
+informations PXE aux clients alors que l'allocation DHCP est effectuée par un
+autre serveur.
+.PP
+Le serveur DHCPv6 de dnsmasq possède non seulement les mêmes fonctionalités
+que le serveur DHCPv4, mais aussi le support des annonces de routeurs ainsi
+qu'une fonctionalité permettant l'addition de ressources AAAA pour des
+clients utilisant DHCPv4 et la configuration IPv6 sans état (stateless
+autoconfiguration).
+Il inclut le support d'allocations d'adresses (à la fois en DHCPv6 et en
+annonces de routeurs - RA) pour des sous-réseaux dynamiquement délégués via
+une délégation de préfixe DHCPv6.
+.PP
+Dnsmasq est developpé pour de petits systèmes embarqués. It tends à avoir
+l'empreinte mémoire la plus faible possible pour les fonctions supportées,
+et permet d'exclure les fonctions inutiles du binaire compilé.
+.SH OPTIONS
+Notes : Il est possible d'utiliser des options sans leur donner de paramètre.
+Dans ce cas, la fonction correspondante sera désactivée. Par exemple
+.B --pid-file=
+(sans paramètre après le =) désactive l'écriture du fichier PID.
+Sur BSD, à moins que le logiciel ne soit compilé avec la bibliothèque GNU
+getopt, la forme longue des options ne fonctionne pas en ligne de commande; Elle
+est toujours supportée dans le fichier de configuration.
+.TP
+.B --test
+Vérifie la syntaxe du ou des fichiers de configurations. Se termine avec le
+code de retour 0 si tout est OK, ou un code différent de 0 dans le cas
+contraire. Ne démarre pas Dnsmasq.
+.TP
+.B \-h, --no-hosts
+Ne pas charger les noms du fichier /etc/hosts.
+.TP
+.B \-H, --addn-hosts=<fichier>
+Fichiers d'hôtes additionnels. Lire le fichier spécifié en plus de /etc/hosts.
+Si 
+.B -h
+est spécifié, lire uniquement le fichier spécifié. Cette option peut être
+répétée afin d'ajouter d'autres fichiers. Si un répertoire est donné, lis les
+fichiers contenus dans ce répertoire.
+.TP
+.B \-E, --expand-hosts
+Ajoute le nom de domaine aux noms simples (ne contenant pas de point dans le
+nom) contenus dans le fichier /etc/hosts, de la même façon que pour le service
+DHCP. Notez que cela ne s'applique pas au nom de domaine dans les CNAME, les
+enregistrements PTR, TXT, etc...
+.TP
+.B \-T, --local-ttl=<durée>
+Lorsque Dnsmasq répond avec une information provenant du fichier /etc/hosts ou
+avec un bail DHCP, il donne un temps de vie (time-to-live) positionné à zéro,
+afin d'indiquer à la machine faisant la requête que celle-ci  ne doit pas être
+mise dans un cache. Ceci est le comportement correct dans presque toutes les
+situations.
+Cette option permet de spécifier la valeur de time-to-live à retourner (en
+secondes). Cela permet de réduire la charge sur le serveur, mais les clients
+risquent d'utiliser des données périmées dans certains cas.
+.TP
+.B --neg-ttl=<durée>
+Les réponses négatives provenant des serveurs amonts contiennent normalement
+une information de durée de vie (time-to-live) dans les enregistrements SOA,
+information dont dnsmasq se sert pour mettre la réponse en cache. Si la réponse
+du serveur amont omet cette information, dnsmasq ne cache pas la réponse. Cette
+option permet de doner une valeur de durée de vie par défaut (en secondes) que
+dnsmasq utilise pour mettre les réponses négatives dans son cache, même en
+l'absence d'enregistrement SOA.
+.TP
+.B --max-ttl=<durée>
+Définie la valeur de TTL maximum qui sera fournie aux clients. La valeur maximum
+de TTL spécifiée sera fournie aux clients en remplacement de la vraie valeur de
+TTL si cette dernière est supérieure. La valeur réelle de TTL est cependant
+conservée dans le cache afin d'éviter de saturer les serveurs DNS en amont.
+.TP
+.B --max-cache-ttl=<durée>
+Définie la valeur de TTL maximum pour les entrées dans le cache
+.TP
+.B --auth-ttl=<durée>
+Définie la valeur de TTL retournée pour les réponses du serveur faisant
+autorité.
+.TP
+.B \-k, --keep-in-foreground
+Ne pas aller en tâche de fond au lancement, mais en dehors de cela, fonctionner
+normalement. Ce mode est prévu pour les cas où Dnsmasq est lancé par daemontools
+ou launchd.
+.TP
+.B \-d, --no-daemon
+Mode debug (déverminage) : ne pas aller en tâche de fond, ne pas écrire de
+fichier pid, ne pas changer d'identifiant utilisateur, générer un état complet
+du cache lors de la réception d'un signal SIGUSR1, envoyer les logs sur la
+sortie standard d'erreur ("stderr") de même que dans le syslog, ne pas créer de
+processus fils pour traiter les requêtes TCP. A noter que cette option est à
+user pour du déverminage seulement : pour empêcher dnsmasq se fonctionner en
+mode démon en production, utiliser
+.B -k.
+.TP
+.B \-q, --log-queries
+Enregistrer les résultats des requêtes DNS traitées par Dnsmasq dans un fichier
+de traces ("logs"). Active la génération d'un état complet du cache lors de la
+réception d'un signal SIGUSR1.
+.TP
+.B \-8, --log-facility=<facility>
+Définit la "facility" dans laquelle Dnsmasq enverra ses entrées syslog, par
+défaut DAEMON ou LOCAL0 si le mode debug est activé. Si la "facility" contient
+au moins un caractère "/", alors Dnsmasq considère qu'il s'agit d'un fichier et
+enverra les logs dans le fichier correspondant à la place du syslog. Si la
+"facility" est '-', alors dnsmasq envoie les logs sur la sortie d'erreur
+standard stderr. (Les erreurs lors de la lecture de la configuration vont
+toujours vers le syslog, mais tous les messages postérieurs à un démarrage
+réussi seront exclusivement envoyés vers le fichier de logs).
+Lorsque Dnsmasq est configuré pour envoyer
+ses traces vers un fichier, la réception d'un signal SIGUSR2 entraine la
+fermeture et réouverture du fichier. Cela permet la rotation de fichiers de
+traces sans nécessiter l'arrêt de Dnsmasq.
+.TP
+.B --log-async[=<lignes>]
+Permet l'envoi de traces de manière asynchrone, et de manière optionnelle, le
+nombre de lignes devant être mises dans la file d'attente par Dnsmasq lorsque
+l'écriture vers le syslog est lente.
+Dnsmasq peut envoyer ses logs de manière asynchrone : cela lui permet de
+continuer à fonctionner sans être bloqué par le syslog, et permet à syslog
+d'utiliser Dnsmasq pour les résolutions DNS sans risque d'interblocage.
+Si la file d'attente devient pleine, Dnsmasq loggera le dépassement de file et
+le nombre de messages perdus. La longueur par défaut de la file d'attente est de
+5 et une valeur saine sera comprise entre 5 et 25, avec une limite maximum
+imposée de 100.
+.TP
+.B \-x, --pid-file=<chemin>
+Spécifie un fichier dans lequel stocker le numéro de processus (pid). La valeur
+par défaut est /var/run/dnsmasq.pid.
+.TP
+.B \-u, --user=<nom d'utilisateur>
+Spécifie l'identité (nom d'utilisateur) prise par Dnsmasq après le démarrage.
+Dnsmasq doit normalement être démarré en temps que root ("super-utilisateur"),
+mais abandonne ses privilèges après le démarrage en changeant d'identité.
+Normalement cet utilisateur est l'utilisateur nobody ("personne"), mais il est
+possible d'en définir un autre par le biais de ce paramètre.
+.TP
+.B \-g, --group=<nom de groupe> 
+Spécifie le groupe sous lequel Dnsmasq s'exécute. Par défaut, il s'agit du
+groupe "dip", afin de faciliter l'accès au fichier /etc/ppp/resolv.conf qui
+n'est en général pas en lecture par tout le monde.
+.TP
+.B \-v, --version
+Imprime le numéro de version.
+.TP
+.B \-p, --port=<port>
+Ecoute sur le port numéro <port> au lieu du port DNS standard (53). Paramétrer
+cette valeur à zéro désactive complètement la fonction DNS pour ne laisser actif
+que le DHCP ou le TFTP.
+.TP
+.B \-P, --edns-packet-max=<taille>
+Spécifie la taille maximum de paquet UDP EDNS.0 supporté par le relai DNS. Le
+défaut est de 4096, qui est la valeur recommandée dans la RFC5625.
+.TP
+.B \-Q, --query-port=<numéro de port>
+Envoie et écoute les requêtes DNS sortantes depuis le port UDP spécifié par
+<numéro de port>, et non sur un port aléatoire. NOTE : Cette option rends
+dnsmasq moins sûr contre les attaques par usurpation DNS ("DNS spoofing"), mais
+cela peut permettre d'utiliser moins de ressources et d'être plus rapide. Donner
+une valeur de zéro à cette option restaure le comportement par défaut présent dans
+les versions de dnsmasq inférieures à 2.43 qui consiste à n'allouer qu'un seul port
+alloué par le système d'exploitation.
+.TP
+.B --min-port=<port>
+Ne pas utiliser de port dont le numéro est inférieur à la valeur donnée en paramètre
+pour les requêtes DNS sortantes. Dnsmasq choisis un port source aléatoire pour les
+requêtes sortantes : lorsque cette option est fournie, les ports utilisés seront toujours
+au dessus de la valeur spécifiée. Utile pour des systèmes derrière des dispositifs
+garde-barrières ("firewalls").
+.TP
+.B \-i, --interface=<nom d'interface>
+N'écouter que sur l'interface réseau spécifiée. Dnsmasq aujoute automatiquement
+l'interface locale ("loopback") à la liste des interfaces lorsque l'option
+.B --interface
+est utilisée.
+Si aucune option
+.B --interface
+ou
+.B --listen-address
+n'est donnée, Dnsmasq écoutera sur toutes les interfaces disponibles sauf
+celle(s) spécifiée(s) par l'option
+.B --except-interface.
+Les alias d'interfaces IP (e-g "eth1:0") ne peuvent être utilisés ni avec
+.B --interface
+ni
+.B \--except-interface.
+Utiliser l'option 
+.B --listen-address
+à la place. Un simple joker, consistant d'un '*' final, peut-être utilisé dans
+les options
+.B \--interface 
+et
+.B \--except-interface
+.TP
+.B \-I, --except-interface=<interface name>
+Ne pas écouter sur l'interface spécifiée. Notez que l'ordre dans lesquelles les
+options
+.B \--listen-address
+,
+.B --interface
+et
+.B --except-interface
+sont fournies n'importe pas, et que l'option 
+.B --except-interface
+l'emporte toujours sur les autres.
+.TP
+.B --auth-server=<domaine>,<interface>|<addresse IP>
+Active le mode DNS faisant autorité pour les requêtes arrivant sur cette
+interface ou sur cette adresse. Noter que l'interface ou l'adresse n'ont
+pas besoin d'être mentionées ni dans
+.B --interface
+ni dans
+.B --listen-address
+En effet,
+.B --auth-server
+va passer outre ceux-ci et fournir un service DNS différent sur l'interface
+spécifiée. La valeur de <domaine> est l'enregistrement de type "colle"
+("glue record"). Il doit correspondre dans le service DNS global avec un
+enregistrement de type A et/ou AAAA pointant sur l'adresse sur laquelle dnsmasq
+écoute pour le mode DNS faisant autorité.
+.TP 
+.B \-2, --no-dhcp-interface=<nom d'interface>
+Ne pas fournir de service DHCP sur l'interface spécifiée, mais fournir tout de
+même le service DNS.
+.TP
+.B \-a, --listen-address=<adresse IP>
+Ecouter sur la ou les adresse(s) IP spécifiée(s). Les options 
+.B \--interface
+et
+.B \--listen-address
+peuvent-être spécifiées simultanément, auquel cas un jeu d'interfaces et
+d'adresses seront utilisées. Notez que si
+aucune option
+.B \--interface
+n'est donnée alors qu'une option 
+.B \--listen-address
+l'est, Dnsmasq n'écoutera pas automatiquement sur l'interface locale
+("loopback"). Pour activer l'écoute sur l'interface locale, il est alors
+nécessaire de fournir explicitement son adresse IP, 127.0.0.1 via l'option
+.B \--listen-address.
+.TP
+.B \-z, --bind-interfaces
+Sur les systèmes qui le supporte, Dnsmasq s'associe avec l'interface joker
+("wildcard"), même lorsqu'il ne doit écouter que sur certaines interfaces. Par
+la suite, il rejette les requêtes auxquelles il ne doit pas répondre. Cette
+situation présente l'avantage de fonctionner même lorsque les interfaces vont
+et viennent ou changent d'adresses. L'option 
+.B --bind-interfaces
+force Dnsmasq à ne réellement s'associer qu'avec les interfaces sur lesquelles
+il doit écouter. L'un des seuls cas où cette option est utile est celui où un
+autre serveur de nom (ou une autre instance de Dnsmasq) tourne sur la même
+machine. Utiliser cette option permet également d'avoir plusieurs instances de
+Dnsmasq fournissant un service DHCP sur la même machine.
+.TP
+.B --bind-dynamic
+Autorise un mode réseau intermédiaire entre
+.B --bind-interfaces
+et le mode par défaut. Dnsmasq s'associe à une seule interface, ce qui permet
+plusieurs instances de dnsmasq, mais si une interface ou adresse apparaissent,
+il se mettra automatiquement à écouter sur celles-ci (les règles de contrôle
+d'accès s'appliquent).
+De fait, les interfaces créées dynamiquement fonctionnent de la même façon que
+dans le comportement par défaut. Ce fonctionnement nécessite des APIs réseau
+non standard et n'est disponible que sous Linux. Sur les autres plateformes,
+le fonctionnement est celui du mode --bind-interfaces.
+.TP
+.B \-y, --localise-queries
+Retourne des réponses aux requêtes DNS dépendantes de l'interface sur laquelle
+la requête a été reçue, à partir du fichier /etc/hosts. Si un nom dans
+/etc/hosts a plus d'une adresse associée avec lui, et qu'une des adresses au
+moins est dans le même sous-réseau que l'interface sur laquelle la requête a été
+reçue, alors ne retourne que la(les) adresse(s) du sous-réseau considéré. Cela
+permet d'avoir dans /etc/hosts un serveur avec de multiples adresses, une pour
+chacune de ses interfaces, et de fournir aux hôtes l'adresse correcte (basée sur
+le réseau auquel ils sont attachés). Cette possibilité est actuellement limitée
+à IPv4.
+.TP
+.B \-b, --bogus-priv
+Fausse résolution inverse pour les réseaux privés. Toutes les requêtes DNS
+inverses pour des adresses IP privées (ie 192.168.x.x, etc...) qui ne sont pas
+trouvées dans /etc/hosts ou dans le fichier de baux DHCP se voient retournées
+une réponse "pas de tel domaine" ("no such domain") au lieu d'être transmises
+aux serveurs de nom amont ("upstream server").
+.TP
+.B \-V, --alias=[<ancienne IP>]|[<IP de début>-<IP de fin>],<nouvelle IP>[,<masque>]
+Modifie les adresses IPv4 retournées par les serveurs de nom amont;
+<ancienne IP> est remplacée par <nouvelle IP>. Si le <masque> optionnel est
+fourni, alors toute adresse correspondant à l'adresse <ancienne IP>/<masque>
+sera réécrite. Ainsi par exemple
+.B --alias=1.2.3.0,6.7.8.0,255.255.255.0 
+modifiera 1.2.3.56 en 6.7.8.56 et 1.2.3.67 en 6.7.8.67. 
+Cette fonctionnalité correspond à ce que les routeurs Cisco PIX appellent
+"bidouillage DNS" ("DNS doctoring"). Si l'ancienne IP est donnée sous la forme
+d'une gamme d'adresses, alors seules les adresses dans cette gamme seront
+réecrites, et non le sous-réseau dans son ensemble. Ainsi,
+.B --alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0
+fait correspondre 192.168.0.10->192.168.0.40 à 10.0.0.10->10.0.0.40
+.TP 
+.B \-B, --bogus-nxdomain=<adresse IP>
+Transforme les réponses contenant l'adresse IP fournie en réponses "pas de tel
+domaine" ("no such domain"). Ceci a pour but de neutraliser la modification
+sournoise mise en place par Verisign en septembre 2003, lorsqu'ils ont commencé
+à retourner l'adresse d'un serveur web publicitaire en réponse aux requêtes pour
+les noms de domaines non enregistrés, au lieu de la réponse correcte "NXDOMAIN".
+Cette option demande à Dnsmasq de retourner la réponse correcte lorsqu'il
+constate ce comportement. L'adresse retournée par Verisign en septembre 2003
+est 64.94.110.11.
+.TP
+.B \-f, --filterwin2k
+Les dernières versions de windows font des requêtes DNS périodiques auxquelles
+non seulement les serveurs DNS publics ne peuvent donner de réponse, mais qui,
+de surcroît, peuvent poser des problèmes en déclenchant des connexions
+intempestives pour des liens réseaux avec des connexions "à la demande". Fournir
+cette option active le filtrage des requêtes de ce type. Les requêtes bloquées
+sont les requêtes pour les entrées de type SOA ou SRV, ainsi que les requêtes de
+type ANY avec des noms possédant des caractères sous-lignés (requêtes pour des
+serveurs LDAP).
+.TP
+.B \-r, --resolv-file=<fichier>
+Lis les adresses des serveurs de nom amont dans le fichier de nom <fichier>,
+au lieu du fichier /etc/resolv.conf. Pour le format de ce fichier, voir dans le
+manuel pour
+.BR resolv.conf (5) 
+les entrées correspondant aux serveurs de noms (nameserver). Dnsmasq peut lire
+plusieurs fichiers de type resolv.conf, le premier fichier spécifié remplace le
+fichier par défaut, le contenu des suivants est rajouté dans la liste des
+fichiers à consulter. Seul le fichier ayant la dernière date de modification
+sera chargé en mémoire.
+.TP
+.B \-R, --no-resolv
+Ne pas lire le contenu du fichier /etc/resolv.conf. N'obtenir l'adresse des
+serveurs de nom amont que depuis la ligne de commande ou le fichier de
+configuration de Dnsmasq.
+.TP
+.B \-1, --enable-dbus[=<nom de service>]
+Autoriser la mise à jour de la configuration de Dnsmasq par le biais d'appel de
+méthodes DBus. Il est possible par ce biais de mettre à jour l'adresse de
+serveurs DNS amont (et les domaines correspondants) et de vider le cache. Cette
+option nécessite que Dnsmasq soit compilé avec le support DBus. Si un nom de
+service est fourni, dnsmasq fourni un service à ce nom, plutôt qu'avec la
+valeur par défaut :
+.B uk.org.thekelleys.dnsmasq
+.TP 
+.B \-o, --strict-order
+Par défaut, Dnsmasq envoie les requêtes à n'importe lequel des serveurs amonts
+dont il a connaissance tout en essayant de favoriser les serveurs qu'il sait
+fonctionner. Cette option force Dnsmasq à essayer d'interroger, pour chaque
+requête, les serveurs DNS dans leur ordre d'apparition dans le fichier
+/etc/resolv.conf.
+.TP
+.B --all-servers
+Par défaut, lorsque dnsmasq a plus d'un serveur amont disponible, il n'envoie
+les requêtes qu'à un seul serveur. Spécifier cette option force dnsmasq à
+effectuer ses requêtes à tous les serveurs disponibles. Le résultat renvoyé
+au client sera celui fournit par le premier serveur ayant répondu.
+.TP
+.B --stop-dns-rebind
+Rejete (et enregistre dans le journal d'activité) les adresses dans la gamme
+d'adresses IP privée (au sens RFC1918) qui pourraient être renvoyées par les
+serveurs amonts suite à une résolution de nom. Cela bloque les attaques cherchant
+à détourner de leur usage les logiciels de navigation web ('browser') en s'en
+servant pour découvrir les machines situées sur le réseau local.
+.TP
+.B --rebind-localhost-ok
+Exclue 127.0.0/8 des vérifications de réassociation DNS. Cette gamme d'adresses
+est retournée par les serveurs Realtime Blackhole (RBL, utilisés dans la
+lutte contre le spam), la bloquer peut entraîner des disfonctionnements de ces
+services.
+.TP 
+.B  --rebind-domain-ok=[<domaine>]|[[/<domaine>/[<domaine>/]
+Ne pas détecter ni bloquer les actions de type dns-rebind pour ces domaines.
+Cette option peut prendre comme valeur soit un nom de domaine soit plusieurs
+noms de domains entourés par des '/', selon une syntaxe similaire à l'option
+--server, c-à-d :
+.B  --rebind-domain-ok=/domaine1/domaine2/domaine3/
+.TP
+.B \-n, --no-poll
+Ne pas vérifier régulièrement si le fichier /etc/resolv.conf a été modifié.
+.TP
+.B --clear-on-reload
+Lorsque le fichier /etc/resolv.conf est relu, ou si les serveurs amonts sont
+configurés via DBus, vider le cache DNS.
+Cela est utile si les nouveaux serveurs sont susceptibles d'avoir des données
+différentes de celles stockées dans le cache.
+.TP
+.B \-D, --domain-needed
+Indique à Dnsmasq de ne jamais transmettre en amont de requêtes A ou AAAA pour
+des noms simples, c'est à dire ne comprenant ni points ni nom de domaine. Si un
+nom n'est pas dans /etc/hosts ou dans la liste des baux DHCP, alors une réponse
+de type "non trouvé" est renvoyée.
+.TP
+.B \-S, --local, --server=[/[<domaine>]/[domaine/]][<Adresse IP>[#<port>][@<Adresse IP source>|<interface>[#<port>]]]
+Spécifie directement l'adresse IP d'un serveur de nom amont. Cette option ne
+supprime pas la lecture du fichier /etc/resolv.conf : utiliser pour cela
+l'option
+.B -R .
+Si un ou plusieurs nom(s) de domaine(s) optionnel(s) sont fournis, ce
+serveur sera uniquement utilisé uniquement pour ce(s) domaine(s), et toute
+requête concernant ce(s) domaine(s) sera adressée uniquement à ce serveur.
+Cette option est destinée aux serveurs de nom privés : si vous avez un serveur
+de nom sur votre réseau ayant pour adresse IP 192.168.1.1 et effectuant la
+résolution des noms de la forme xxx.internal.thekelleys.org.uk, alors
+.B -S /internal.thekelleys.org.uk/192.168.1.1 
+enverra toutes les requêtes pour les machines internes vers ce serveur de nom,
+alors que toutes les autres requêtes seront adressées aux serveurs indiqués dans
+le fichier /etc/resolv.conf. Une spécification de nom de domaine vide,
+.B // 
+possède le sens particulier de "pour les noms non qualifiés uniquement",
+c'est-à-dire les noms ne possédant pas de points. Un port non standard peut être
+rajouté à la suite des adresses IP en utilisant le caractère #. Plus d'une
+option
+.B -S
+est autorisée, en répétant les domaines et adresses IP comme requis.
+
+Le domaine le plus spécifique l'emporte sur le domaine le moins spécifique,
+ainsi :
+.B --server=/google.com/1.2.3.4
+.B --server=/www.google.com/2.3.4.5
+enverra les requêtes pour *.google.com à 1.2.3.4, à l'exception des requêtes
+*www.google.com, qui seront envoyées à 2.3.4.5.
+
+L'adresse spéciale '#' signifie "utiliser les serveurs standards", ainsi
+.B --server=/google.com/1.2.3.4
+.B --server=/www.google.com/#
+enverra les requêtes pour *.google.com à 1.2.3.4, à l'exception des requêtes
+pour *www.google.com qui seront envoyées comme d'habitude (c-à-d aux serveurs
+définis par défaut).
+
+Il est également permis de donner une option
+.B -S
+avec un nom de domaine mais sans
+adresse IP; Cela informe Dnsmasq que le domaine est local et qu'il doit répondre
+aux requêtes le concernant depuis les entrées contenues dans le fichier
+/etc/hosts ou les baux DHCP, et ne doit en aucun cas transmettre les requêtes
+aux serveurs amonts.
+.B local
+est synonyme de
+.B server
+("serveur") afin de rendre plus claire l'utilisation de cette option pour cet
+usage particulier.
+
+Les adresses IPv6 peuvent inclure un identifiant de zone sous la forme
+%interface tel que par exemple
+fe80::202:a412:4512:7bbf%eth0.
+
+La chaîne de caractères optionnelle suivant le caractère @ permet de définir
+la source que Dnsmasq doit utiliser pour les réponses à ce
+serveur de nom. Il doit s'agir d'une des adresses IP appartenant à la machine sur
+laquelle tourne Dnsmasq ou sinon la ligne sera ignorée et une erreur sera
+consignée dans le journal des événements, ou alors d'un nom d'interface. Si un nom
+d'interface est donné, alors les requêtes vers le serveur de nom seront envoyées
+depuis cette interface; si une adresse ip est donnée, alors l'adresse source de
+la requête sera l'adresse en question. L'option query-port est ignorée pour tous
+les serveurs ayant une adresse source spécifiée, mais il est possible de la donner
+directement dans la spécification de l'adresse source. Forcer les requêtes à être
+émises depuis une interface spécifique n'est pas possible sur toutes les plateformes
+supportées par dnsmasq.
+.TP
+.B \-A, --address=/<domaine>/[domaine/]<adresse IP>
+Spécifie une adresse IP à retourner pour toute requête pour les domaines fournis
+en option. Les requêtes pour ce(s) domaine(s) ne sont jamais transmises aux
+serveurs amonts et reçoivent comme réponse l'adresse IP spécifiée qui peut être
+une adresse IPv4 ou IPv6. Pour donner à la fois une adresse IPv4 et une adresse
+IPv6 pour un domaine, utiliser plusieurs options
+.B -A.
+Il faut noter que le
+contenu du fichier /etc/hosts et de celui des baux DHCP supplante ceci pour des
+noms individuels. Une utilisation courante de cette option est de rediriger la
+totalité du domaine doubleclick.net vers un serveur web local afin d'éviter les
+bannières publicitaires. La spécification de domaine fonctionne de la même façon
+que
+.B  --server,
+avec la caractéristique supplémentaire que
+.B /#/
+coïncide avec tout domaine. Ainsi,
+.B --address=/#/1.2.3.4
+retournera 1.2.3.4 pour toute requête
+n'ayant de réponse ni dans /etc/hosts, ni dans les baux DHCP, et n'étant pas
+transmise à un serveur spécifique par le biais d'une directive
+.B --server.
+.TP
+.B --ipset=/<domaine>/[domaine/]<ipset>[,<ipset>]
+Obtient les adresses IP des domaines spécifiés et les place dans les groupes
+d'IP netfilter (ipset) indiqués. Domaines et sous-domaines sont résolus de la
+même façon que pour --address. Ces groupes d'IP doivent déjà exister. Voir
+ipset(8) pour plus de détails.
+.TP
+.B \-m, --mx-host=<nom de l'hôte>[[,<nom du MX>],<préference>]
+Spécifie un enregistrement de type MX pour <nom de l'hôte> retournant le nom
+donné dans <nom du MX> (s'il est présent), ou sinon le nom spécifié dans
+l'option
+.B --mx-target
+si elle est présente. Sinon retourne le nom de la machine
+sur laquelle Dnsmasq tourne. La valeur par défaut (spécifiée dans l'option
+.B --mx-target
+) est utile dans un réseau local pour rediriger les courriers
+électroniques vers un serveur central. La valeur de préférence est optionnelle
+et vaut par défaut 1 si elle n'est pas spécifiée. Plus d'une entrée MX peut être
+fournie pour un hôte donné.
+.TP 
+.B \-t, --mx-target=<nom d'hôte>
+Spécifie la réponse par défaut fournie par Dnsmasq pour les requêtes sur des
+enregistrements de type MX. Voir
+.B --mx-host.
+Si
+.B --mx-target
+est donné mais pas de
+.B --mx-host,
+alors Dnsmasq retourne comme réponse un enregistrement MX
+contenant le nom d'hôte spécifié dans l'option
+.B --mx-target
+pour toute requête
+concernant le MX de la machine sur laquelle tourne Dnsmasq.
+.TP
+.B \-e, --selfmx
+Définit, pour toutes les machines locales, un MX correspondant à l'hôte
+considéré. Les machines locales sont celles définies dans le fichier /etc/hosts
+ou dans un bail DHCP.
+.TP 
+.B \-L, --localmx
+Définit, pour toutes les machines locales, un enregistrement MX pointant sur
+l'hôte spécifié par mx-target (ou la machine sur laquelle Dnsmasq tourne). Les
+machines locales sont celles définies dans le fichier /etc/hosts ou dans un bail
+DHCP.
+.TP
+.B \-W --srv-host=<_service>.<_protocole>.[<domaine>],[<cible>[,<port>[,<priorité>[,<poids>]]]]
+Spécifie un enregistrement DNS de type SRV. Voir la RFC2782 pour plus de
+détails. Si le champs <domaine> n'est pas fourni, prends par défaut la valeur
+fournie dans l'option
+.B --domain.
+La valeur par défaut pour le domaine est vide et le port par défaut est 1, alors
+que les poids et priorités par défaut sont 0. Attention lorsque vous transposez
+des valeurs issues d'une configuration BIND : les ports, poids et priorités sont
+dans un ordre différents. Pour un service/domaine donné, plus d'un
+enregistrement SRV est autorisé et tous les enregistrements qui coïncident sont
+retournés dans la réponse.
+.TP
+.B --host-record=<nom>[,<nom>....][<adresse IPv4>],[<adresse IPv6>]
+Ajoute des enregistrements A, AAAA et PTR dans le DNS. Ceci permet d'ajouter
+un ou plusieurs noms dans le DNS et de les associer à des enregistrements IPv4
+(A) ou IPv6 (AAAA). Un nom peut apparaître dans plus d'une entrée
+.B host-record
+et de fait être associé à plus d'une adresse. Seule la première entrée créée
+l'enregistrement PTR associée au nom. Ceci correspond à la même règle que celle
+utilisée lors de la lecture du fichier hosts.
+Les options
+.B host-record
+sont considérées lues avant le fichier hosts, ainsi un nom apparaissant dans
+une option host-record et dans le fichier hosts n'aura pas d'enregistrement
+PTR associé à l'entrée dans le fichier hosts. A l'inverse du fichier hosts, les
+noms ne sont pas étendus, même lorsque l'option
+.B expand-hosts
+est activée. Les noms longs et les noms courts peuvent apparaitre dans la même
+entrée 
+.B host-record,
+c-à-d
+.B --host-record=laptop,laptop.thekelleys.org,192.168.0.1,1234::100
+.TP
+.B \-Y, --txt-record=<nom>[[,<texte>],<texte>]
+Définit un enregistrement DNS de type TXT. La valeur de l'enregistrement TXT est
+un ensemble de chaînes de caractères, donc un nombre variable de chaînes de
+caractères peuvent être spécifiées, séparées par des virgules. Utilisez des
+guillemets pour mettre une virgule dans une chaîne de caractères. Notez que la
+longueur maximale pour une chaîne est de 255 caractères, les chaînes plus
+longues étant découpées en morceaux de 255 caractères de longs.
+.TP
+.B --ptr-record=<nom>[,<cible>]
+Définit un enregistrement DNS de type PTR.
+.TP
+.B --naptr-record=<nom>,<ordre>,<préférence>,<drapeaux>,<service>,<expr. régulière>[,<remplacement>]
+Retourne un enregistrement de type NAPTR, tel que spécifié dans le RFC3403.
+.TP
+.B --cname=<cname>,<cible>
+Retourne un enregistrement de type CNAME qui indique que <cname> est en
+réalité <cible>. Il existe des contraintes importantes sur la valeur
+cible; il doit s'agir d'un nom DNS qui est connu de dnsmasq via /etc/hosts
+(ou un fichier hôtes additionnel), via DHCP, via interface--name ou par un autre
+.B --cname.
+Si une cible ne satisfait pas ces critères, le CNAME est ignoré. Le CNAME
+doit être unique, mais il est autorisé d'avoir plus d'un CNAME pointant
+vers la même cible.
+.TP
+.B --dns-rr=<nom>,<numéro-RR>,[<données hexadécimales>]
+Retourne un enregistrement DNS arbitraire. Le numéro correspond au type
+d'enregistrement (qui est toujours de la classe C_IN). La valeur de
+l'enregistrement est donnée dans les données hexadécimales, qui peuvent
+être de la forme 01:23:45, 01 23 45,+012345 ou n'importe quelle combinaison.
+.TP
+.B --interface-name=<nom>,<interface>
+Définit un entregistrement DNS associant le nom avec l'adresse primaire sur
+l'interface donnée en argument. Cette option spécifie un enregistrement de type
+A pour le nom donné en argument de la même façon que s'il était défini par une
+ligne de /etc/hosts, sauf que l'adresse n'est pas constante mais dépendante de
+l'interface définie. Si l'interface est inactive, non existante ou non
+configurée, une réponse vide est fournie. Un enregistrement inverse (PTR) est
+également créé par cette option, associant l'adresse de l'interface avec le nom.
+Plus d'un nom peut être associé à une interface donnée en répétant cette option
+plusieurs fois; dans ce cas, l'enregistrement inverse pointe vers le nom fourni
+dans la première instance de cette option.
+.TP
+.B --synth-domain=<domaine>,<plage d'adresses>[,<préfixe>]
+Créé des enregistrements A/AAAA ou PTR pour une plage d'adresses. Les
+enregistrements utilisent l'adresse ainsi que les points (ou les deux points
+dans le cas d'IPv6) remplacés par des tirets.
+
+Un exemple devrait rendre cela plus clair :
+La configuration
+.B --synth-domain=thekelleys.org.uk,192.168.0.0/24,internal-
+permet de retourner internal-192-168-0-56.thekelleys.org.uk lors d'une requête
+sur l'adresse 192.168.0.56 et vice-versa pour la requête inverse. La même
+logique s'applique pour IPv6, avec la particularité suivante : les adresses
+IPv6 pouvant commencer par '::', mais les noms DNS ne pouvant pas commencer
+par '-', si aucun préfixe n'est donné, un zéro est ajouté en début de nom.
+Ainsi, ::1 devient 0--1.
+
+La plage d'adresses peut-être de la forme
+<adresse IP>,<adresse IP> ou <adresse IP>/<masque réseau>
+.TP
+.B --add-mac
+Ajoute l'adresse MAC du requêteur aux requêtes DNS transmises aux serveurs
+amonts. Cela peut être utilisé dans un but de filtrage DNS par les serveurs
+amonts. L'adresse MAC peut uniquement être ajoutée si le requêteur est sur le
+même sous-réseau que le serveur dnsmasq. Veuillez noter que le mécanisme
+utilisé pour effectuer cela (une option EDNS0) n'est pas encore standardisée,
+aussi cette fonctionalité doit être considérée comme expérimentale. Notez
+également qu'exposer les adresses MAC de la sorte peut avoir des implications
+en termes de sécurité et de vie privée. L'avertissement donné pour --add-subnet
+s'applique également ici.
+.TP
+.B --add-subnet[[=<longueur de préfixe IPv4>],<longueur de préfixe IPv6>]
+Rajoute l'adresse de sous-réseau du requêteur aux requêtes DNS transmises
+aux serveurs amonts. La quantité d'adresses transmises dépend du paramètre
+longueur du préfixe : 32 (ou 128 dans le cas d'IPv6) transmet la totalité
+de l'adresse, 0 n'en transmet aucun mais marque néanmoins la requête ce qui
+fait qu'aucun serveur amont ne rajoutera d'adresse client. La valeur par
+défaut est zéro et pour IPv4 et pour IPv6. A noter que les serveurs amonts
+peuvent-être configurés pour retourner des valeurs différentes en fonction
+de cette information mais que le cache de dnsmasq n'en tient pas compte.
+Si une instance de dnsmasq est configurée de telle maniêre que des valeurs
+différentes pourraient-être rencontrés, alors le cache devrait être désactivé.
+.TP
+.B \-c, --cache-size=<taille>
+Définit la taille du cache de Dnsmasq. La valeur par défaut est de 150 noms.
+Définir une valeur de zéro désactive le cache.
+.TP
+.B \-N, --no-negcache
+Désactive le "cache négatif". Le "cache négatif" permet à Dnsmasq de se souvenir
+des réponses de type "no such domain" fournies par les serveurs DNS en amont et
+de fournir les réponses sans avoir à re-transmettre les requêtes aux serveurs
+amont.
+.TP
+.B \-0, --dns-forward-max=<nombre de requêtes>
+Définit le nombre maximum de requêtes DNS simultanées. La valeur par défaut est
+150, ce qui devrait être suffisant dans la majorité des configurations. La seule
+situation identifiée dans laquelle cette valeur nécessite d'être augmentée est
+lorsqu'un serveur web a la résolution de nom activée pour l'enregistrement de
+son journal des requêtes, ce qui peut générer un nombre important de requêtes
+simultanées.
+.TP
+.B --proxy-dnssec
+Un resolveur sur une machine cliente peut effectuer la validation DNSSEC de
+deux façons : il peut effectuer lui-même les opérations de chiffrements sur
+la réponse reçue, ou il peut laisser le serveur récursif amont faire la
+validation et positionner un drapeau dans la réponse au cas où celle-ci est
+correcte. Dnsmasq n'est pas un validateur DNSSEC, aussi il ne peut effectuer
+la validation comme un serveur de nom récursif, cependant il peut retransmettre
+les résultats de validation de ses serveurs amonts. Cette option permet
+l'activation de cette fonctionalité. Vous ne devriez utiliser cela que si vous
+faites confiance aux serveurs amonts
+.I ainsi que le réseau entre vous et eux.
+Si vous utilisez le premier mode DNSSEC, la validation par le resolveur des
+clients, cette option n'est pas requise. Dnsmasq retourne toujours toutes les
+données nécessaires par un client pour effectuer la validation lui-même.
+.TP
+
+.B --auth-zone=<domaine>[,<sous-réseau>[/<longueur de préfixe>][,<sous-réseau>[/<longueur de préfixe>].....]]
+Définie une zone DNS pour laquelle dnsmasq agit en temps que serveur faisant
+autorité. Les enregistrements DNS définis localement et correspondant à ce
+domaine seront fournis. Les enregistrements A et AAAA doivent se situer dans
+l'un des sous-réseaux définis, ou dans un réseau correspondant à une plage DHCP
+(ce comportement peut-être désactivé par
+.B constructor-noauth:
+). Le ou les sous-réseaux sont également utilisé(s) pour définir les domaines
+in-addr.arpa et ip6.arpa servant à l'interrogation DNS inverse. Si la longueur
+de préfixe n'est pas spécifiée, elle sera par défaut de 24 pour IPv4 et 64 pour
+IPv6. Dans le cas d'IPv4, la longueur du masque de réseau devrait-être de 8, 16
+ou 24, sauf si en cas de mise en place d'une délégation de la zone in-addr.arpa
+conforme au RFC 2317.
+.TP
+.B --auth-soa=<numéro de série>[,<mainteneur de zone (hostmaster)>[,<rafraichissement>[,<nombre de réessais>[,<expiration>]]]]
+Spécifie les champs de l'enregistrement de type SOA (Start Of Authority)
+associé à une zone pour laquelle le serveur fait autorité. A noter que cela est
+optionnel, les valeurs par défaut devant convenir à la majorité des cas.
+.TP
+.B --auth-sec-servers=<domaine>[,<domaine>[,<domaine>...]]
+Spécifie un ou plusieurs serveur de nom secondaires pour une zone pour
+laquelle dnsmasq fait autorité. Ces serveurs doivent-être configurés pour
+récupérer auprès de dnsmasq les informations liées à la zone au travers d'un
+transfert de zone, et répondre aux requêtes pour toutes les zones pour
+lesquelles dnsmasq fait autorité.
+.TP
+.B --auth-peer=<adresse IP>[,<adresse IP>[,<adresse IP>...]]
+Spécifie la ou les adresses de serveurs secondaires autorisés à initier des
+requêtes de transfert de zone (AXFR) pour les zones pour lesquelles
+dnsmasq fait autorité. Si cette option n'est pas fournie, les requêtes AXFR
+seront acceptées pour tous les serveurs secondaires.
+.TP 
+.B --conntrack
+Lis le marquage de suivi de connexion Linux associé aux requêtes DNS entrantes
+et positionne la même marque au trafic amont utilisé pour répondre à ces
+requétes. Cela permet au trafic généré par Dnsmasq d'étre associé aux requêtes
+l'ayant déclenché, ce qui est pratique pour la gestion de la bande passante
+(accounting) et le filtrage (firewall). Dnsmasq doit pour cela être compilé
+avec le support conntrack, le noyau doit également inclure conntrack et être
+configuré pour cela. Cette option ne peut pas être combinée avec
+--query-port.
+.TP
+.B \-F, --dhcp-range=[tag:<label>[,tag:<label>],][set:<label>],]<adresse de début>[,<adresse de fin>][,<mode>][,<masque de réseau>[,<broadcast>]][,<durée de bail>]
+.TP
+.B \-F, --dhcp-range=[tag:<label>[,tag:<label>],][set:<label>],]<addresse IPv6 de début>[,<adresse IPv6 de fin>|constructor:<interface>][,<mode>][,<longueur de préfixe>][,<durée de bail>]
+
+Active le serveur DHCP. Les adresses seront données dans la plage comprise entre
+<adresse de début> et <adresse de fin> et à partir des adresses définies
+statiquement dans l'option
+.B dhcp-host.
+Si une durée de bail est donnée, alors les baux seront donnés pour cette
+durée. La durée de bail est donnée en secondes, en minutes (exemple : 45m),
+en heures (exemple : 1h) ou être la chaine de caractère "infinite" pour une
+durée indéterminée. Si aucune valeur n'est donnée, une durée de bail par défaut
+de une heure est appliquée. La valeur minimum pour un bail DHCP est de 2
+minutes.
+
+Pour les plages IPv6, la durée de bail peut-être égale au mot-clef "deprecated"
+(obsolète); Cela positionne la durée de vie préférée envoyée dans les baux DHCP
+ou les annonces routeurs à zéro, ce qui incite les clients à utiliser d'autres
+adresses autant que possible, pour toute nouvelle connexion, en préalable à
+la renumérotation.
+
+Cette option peut être répétée, avec différentes adresses,
+pour activer le service DHCP sur plus d'un réseau. Pour des réseaux directement
+connectés (c'est-à-dire des réseaux dans lesquels la machine sur laquelle tourne
+Dnsmasq possède une interface), le masque de réseau est optionnel : Dnsmasq la
+déterminera à partir de la configuration des interfaces.
+
+Pour les réseaux pour lesquels le service DHCP se fait via un relais DHCP
+("relay agent"), Dnsmasq est incapable de déterminer le masque par lui-même,
+aussi il doit être spécifié, faute de quoi Dnsmasq essaiera de le deviner en
+fonction de la classe (A, B ou C) de l'adresse réseau. L'adresse de broadcast
+est toujours optionnelle.
+
+Il est toujours possible d'avoir plus d'une plage DHCP pour un même
+sous-réseau.
+
+Pour IPv6, les paramètres sont légèrement différents : au lieu d'un masque de
+réseau et d'une adresse de broadcast, il existe une longueur de préfixe
+optionnelle. Si elle est omise, la valeur par défaut est 64. À la différence
+d'IPv4, la longueur de préfixe n'est pas automatiquement déduite de la
+configuration de l'interface. La taille minimale pour la longueur de préfixe
+est 64.
+
+Pour IPv6 (et IPv6 uniquement), il est possible de définir les plages d'une
+autre façon. Dans ce cas, l'adresse de départ et l'adresse de fin optionnelle
+contiennent uniquement la partie réseau (par exemple ::1) et sont suivies par
+.B constructor:<interface>.
+Cela forme un modèle décrivant comment construire la plage, à partir des
+adresses assignées à l'interface. Par exemple
+
+.B --dhcp-range=::1,::400,constructor:eth0
+
+provoque la recherche d'adresses de la forme <réseau>::1 sur eth0 et crée une
+plage allant de <réseau>::1 à <réseau>:400. Si une interface est assignée à
+plus d'un réseau, les plages correspondantes seront automatiquement créées,
+rendues obsolètes puis supprimées lorsque l'adress est rendue obsolète puis
+supprimée. Le nom de l'interface peut être spécifié avec un caractère joker '*'
+final.
+
+provoque la recherche d'adresses sur eth0 et crée une plage allant de
+<réseau>::1 à <réseau>:400. Si l'interface est assignée à
+plus d'un réseau, les plages correspondantes seront respectivement
+automatiquement créées, rendues obsolètes et supprimées lorsque l'adresse
+est rendue obsolète et supprimée. Le nom de l'interface peut être spécifié avec
+un caractère joker '*' final. Les adresses autoconfigurées, privées ou
+obsolètes ne conviennent pas.
+
+Si une plage dhcp-range est uniquement utilisée pour du DHCP sans-état
+("stateless") ou de l'autoconfiguration sans état ("SLAAC"), alors l'adresse
+peut-être indiquée sous la forme '::'
+
+.B --dhcp-range=::,constructor:eth0
+
+Il existe une variante de la syntaxe constructor: qui consiste en l'utilisation
+du mot-clef
+.B constructor-noauth.
+Voir
+.B --auth-zone
+pour des explications à ce sujet.
+
+L'identifiant de label optionnel
+.B set:<label>
+fournie une étiquette alphanumérique qui identifie ce réseau, afin de permettre
+la fourniture d'options DHCP spécifiques à chaque réseau.
+Lorsque préfixé par 'tag:', la signification change, et au lieu de définir un
+label, il définit le label pour laquelle la règle s'applique. Un seul label peut-
+être défini mais plusieurs labels peuvent coïncider.
+
+Le mot clef optionnel <mode> peut être égal à
+.B static
+("statique") ce qui indique à Dnsmasq d'activer le service DHCP pour le réseau
+spécifié, mais de ne pas activer l'allocation dynamique d'adresses IP : Seuls
+les hôtes possédant des adresses IP statiques fournies via 
+.B dhcp-host
+ou présentes dans le fichier /etc/ethers seront alors servis par le DHCP. Il est
+possible d'activer un mode "fourre-tout" en définissant un réseau statique
+comportant uniquement des zéros, c'est à dire :
+.B --dhcp=range=::,static
+Cela permet de retourner des réponses à tous les paquets de type
+Information-request (requête d'information) en mode DHCPv6 sans état sur le
+sous-réseau configuré. 
+
+Pour IPv4, le <mode> peut est égal à
+.B proxy
+, auquel cas Dnsmasq fournira un service de DHCP proxy pour le sous-réseau
+spécifié. (voir
+.B pxe-prompt
+et
+.B pxe-service
+pour plus de détails).
+
+Pour IPv6, le mode peut-être une combinaison des valeurs
+.B ra-only, slaac, ra-names, ra-stateless, off-link.
+
+.B ra-only
+indique à dnsmasq de n'effectuer que des annonces de routeur (Router
+Advertisement, RA) sur ce sous-réseau, et de ne pas faire de DHCP.
+
+.B slaac
+indique à dnsmasq d'effectuer des annonces de routeur sur ce sous-réseau
+et de positionner dans celles-ci le bit A, afin que les clients utilisent
+des adresses SLAAC. Lorsqu'utilisé conjointement avec une plage DHCP ou des
+affectations statiques d'adresses DHCP, les clients disposeront à la fois
+d'adresses DHCP assignées et d'adresses SLAAC.
+
+.B ra-stateless
+indique à dnsmasq d'effectuer des annonces de routeur avec les bits 0 et A
+positionnés, et de fournir un service DHCP sans état ("stateless"). Les clients
+utiliseront des adresses SLAAC, et utiliseront DHCP pour toutes les autres
+informations de configuration.
+
+.B ra-names
+active un mode qui fourni des noms DNS aux hôtes fonctionnant en double pile
+("dual stack") et configurés pour faire du SLAAC en IPv6. Dnsmasq utilise le
+bail IPv4 de l'hôte afin de dériver le nom, le segment de réseau et l'adresse
+MAC et assume que l'hôte disposera d'une adresse IPv6 calculée via l'algorithme
+SLAAC, sur le même segment de réseau. Un ping est envoyé à l'adresse, et si une
+réponse est obtenue, un enregistrement AAAA est rajouté dans le DNS pour cette
+adresse IPv6. Veuillez-noter que cela n'arrive que pour les réseaux directement
+connectés (et non ceux pour lesquels DHCP se fait via relai), et ne
+fonctionnera pas si un hôte utilise les "extensions de vie privée"
+("privacy extensions").
+.B ra-names
+peut-être combiné avec
+.B ra-stateless
+et
+.B slaac.
+
+.B off-link
+indique à dnsmasq d'annoncer le préfixe sans le bit L (sur lien).
+
+.TP
+.B \-G, --dhcp-host=[<adresse matérielle>][,id:<identifiant client>|*][,set:<label>][,<adresse IP>][,<nom d'hôte>][,<durée de bail>][,ignore]
+Spécifie les paramètres DHCP relatifs à un hôte. Cela permet à une machine
+possédant une adresse matérielle spécifique de se voir toujours allouée les
+mêmes nom d'hôte, adresse IP et durée de bail. Un nom d'hôte spécifié comme
+ceci remplace le nom fourni par le client DHCP de la machine hôte. Il est
+également possible d'omettre l'adresse matérielle et d'inclure le nom d'hôte,
+auquel cas l'adresse IP et la durée de bail s'appliqueront à toute machine se
+réclamant de ce nom. Par exemple
+.B --dhcp-host=00:20:e0:3b:13:af,wap,infinite 
+spécifie à Dnsmasq de fournir à la machine d'adresse matérielle
+00:20:e0:3b:13:af le nom, et un bail de durée indéterminée.
+
+.B --dhcp-host=lap,192.168.0.199 
+spécifie à Dnsmasq d'allouer toujours à la machine portant le nom lap
+l'adresse IP 192.168.0.199.
+
+Les adresses allouées de la sorte ne sont pas contraintes à une plage d'adresse
+spécifiée par une option --dhcp-range, mais elles se trouver dans le même
+sous-réseau qu'une plage dhcp-range valide. Pour les sous-réseaux qui n'ont pas
+besoin d'adresses dynamiquement allouées, utiliser le mot-clef "static" dans la
+déclaration de plage d'adresses dhcp-range.
+
+Il est possible d'utiliser des identifiants clients (appellé "DUID client" dans
+le monde IPv6) plutôt que des adresses matérielles pour identifier les hôtes,
+en préfixant ceux-ci par 'id:'. Ainsi, 
+.B --dhcp-host=id:01:02:03:04,..... 
+réfère à l'hôte d'identifiant 01:02:03:04. Il est également possible de
+spécifier l'identifiant client sous la forme d'une chaîne de caractères, comme
+ceci :
+.B --dhcp-host=id:identifiantclientsousformedechaine,..... 
+
+Un seul
+.B dhcp-host 
+peut contenir une adresse IPv4, une adresse IPv6, ou les deux en même temps.
+Les adresses IPv6 doivent-être mises entre crochets comme suit :
+.B --dhcp-host=laptop,[1234::56]
+Les adresses IPv6 peuvent ne contenir que la partie identifiant de client :
+.B --dhcp-host=laptop,[::56]
+Dans ce cas, lorsque des plages dhcp sont définies automatiquement par le biais
+de constructeurs, la partie réseau correspondante est rajoutée à l'adresse.
+
+A noter que pour le DHCP IPv6, l'adresse matérielle n'est pas toujours
+disponible, bien que ce soit toujours le cas pour des clients directement
+connectés (sur le même domaine de broadcast) ou pour des clients utilisant
+des relais DHCP qui supportent la RFC 6939.
+
+En DHCPv4, l'option spéciale id:* signifie : "ignorer tout identifiant client et n'utiliser
+que l'adresse matérielle". Cela est utile lorsqu'un client présente un
+identifiant client mais pas les autres.
+
+Si un nom apparaît dans /etc/hosts, l'adresse associée peut être allouée à un
+bail DHCP mais seulement si une option
+.B --dhcp-host
+spécifiant le nom existe par ailleurs. Seul un nom d'hôte peut-être donné dans
+une option
+.B dhcp-host
+, mais les alias sont possibles au travers de l'utilisation des CNAMEs. (Voir
+.B --cname
+).
+Le mot clef "ignore" ("ignorer") indique
+à Dnsmasq de ne jamais fournir de bail DHCP à une machine. La machine peut être
+spécifiée par son adresse matérielle, son identifiant client ou son nom d'hôte.
+Par exemple
+.B --dhcp-host=00:20:e0:3b:13:af,ignore
+Cela est utile lorsqu'un autre serveur DHCP sur le réseau doit être utilisé par
+certaines machines.
+
+Le paramètre set:<identifiant réseau> permet de définir un
+identifiant de réseau lorsque l'option dhcp-host est utilisée. Cela peut servir
+à sélectionner des options DHCP juste pour cet hôte. Plus d'un label peut être
+fourni dans une directive dhcp-host (et dans cette seule directive). Lorsqu'une
+machine coïncide avec une directive dhcp-host (ou une impliquée par
+/etc/ethers), alors le label réservé "known" ("connu") est associé. Cela permet à
+Dnsmasq d'être configuré pour ignorer les requêtes issus de machines inconnue
+ par le biais de 
+.B --dhcp-ignore=tag:!known.
+
+Les adresses ethernet (mais pas les identifiants clients) peuvent être définies
+avec des octets joker, ainsi par exemple
+.B --dhcp-host=00:20:e0:3b:13:*,ignore 
+demande à Dnsmasq d'ignorer une gamme d'adresses matérielles. Il est  à noter
+que "*" doit-être précédé d'un caractère d'échappement ou mis entre guillemets
+lorsque spécifié en option de ligne de commande, mais pas dans le fichier de
+configuration.
+
+Les adresses matérielles coïncident en principe avec n'importe
+quel type de réseau (ARP), mais il est possible de les limiter à un seul type
+ARP en les précédant du type ARP (en Hexadécimal) et de "-". Ainsi
+.B --dhcp-host=06-00:20:e0:3b:13:af,1.2.3.4 
+coïncidera uniquement avec des adresses matérielles Token-Ring, puisque le type
+ARP pour une adresse Token-Ring est 6.
+
+Un cas spécial, pour IPv4, correspond à l'inclusion d'une ou plusieurs adresses
+matérielles, c-à-d :
+.B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2.
+Cela permet à une adresse IP d'être associé à plusieurs adresses
+matérielles, et donne à dnsmasq la permission d'abandonner un bail DHCP
+attribué à l'une de ces adresses lorsqu'une autre adresse dans la liste
+demande un bail. Ceci est une opération dangereuse qui ne fonctionnera
+de manière fiable que si une adresse matérielle est active à un moment
+donné et dnsmasq n'a aucun moyen de s'assurer de cela. Cela est utile,
+par exemple, pour allouer une adresse IP stable à un laptop qui
+aurait à la fois une connexion filaire et sans-fil.
+.TP
+.B --dhcp-hostsfile=<chemin>
+Lis les informations d'hôtes DHCP dans le fichier spécifié. Si l'argument est
+un chemin vers un répertoire, lis tous les fichiers de ce répertoire. Le
+fichier contient des informations à raison d'un hôte par ligne. Le format
+d'une ligne est la même que le texte fourni à la droite sur caractère "=" dans
+l'option
+.B --dhcp-host.
+L'avantage de stocker les informations sur les hôtes DHCP dans ce fichier est
+que celles-ci peuvent être modifiées sans recharger Dnsmasq; le fichier sera
+relu lorsque Dnsmasq reçoit un signal SIGHUP.
+.TP
+.B --dhcp-optsfile=<chemin>
+Lis les informations relatives aux options DHCP dans le fichier spécifié. Si
+l'argument est un chemin vers un répertoire, lis tous les fichiers de ce
+répertoire. L'intérêt d'utiliser cette option est le même que pour
+ --dhcp-hostsfile : le fichier spécifié sera rechargé à la réception par
+dnsmasq d'un signal SIGHUP. Notez qu'il est possible d'encoder l'information
+via
+.B --dhcp-boot
+en utilisant les noms optionnels bootfile-name, server-ip-address et
+tftp-server. Ceci permet d'inclure ces options dans un fichier "dhcp-optsfile".DNSMASQ_SUPPLIED_HOSTNAME
+.TP
+.B \-Z, --read-ethers
+Lis les informations d'hôtes DHCP dans le fichier /etc/ethers. Le format de
+/etc/ethers est une adresse matérielle suivie, soit par un nom d'hôte, soit par
+une adresse IP sous la forme de 4 chiffres séparés par des points. Lorsque lu
+par Dnsmasq, ces lignes ont exactement le même effet que l'option
+.B --dhcp-host
+contenant les mêmes informations. /etc/ethers est relu à la réception d'un
+signal SIGHUP par Dnsmasq. Les adresses IPv6 ne sont PAS lues dans /etc/ethers.
+.TP
+.B \-O, --dhcp-option=[tag:<label>,[tag:<label>]][encap:<option>,][vi-encap:<entreprise>,][vendor:[<classe_vendeur>],][<option>|option:<nom d'option>|option6:<option>|option6:<nom d'option>],[<valeur>[,<valeur>]]
+Spécifie des options différentes ou supplémentaires pour des clients DHCP. Par
+défaut, Dnsmasq envoie un ensemble standard d'options aux clients DHCP : le
+masque de réseau et l'adresse de broadcast sont les mêmes que pour l'hôte
+sur lequel tourne Dnsmasq, et le serveur DNS ainsi que la route par défaut
+prennent comme valeur l'adresse de la machine sur laquelle tourne Dnsmasq. 
+(Des règles équivalentes s'appliquent en IPv6). Si une option de nom de domaine
+a été définie, son contenu est transmis. Cette option de configuration permet
+de changer toutes ces valeurs par défaut, ou de spécifier d'autres options.
+L'option DHCP à transmettre peut être fournie sous forme d'un nombre décimal 
+ou sous la forme "option:<nom d'option>". Les nombres correspondants aux options
+sont définis dans la RFC2132 et suivants. Les noms d'options connus par Dnsmasq 
+peuvent être obtenus via "Dnsmasq --help dhcp". Par exemple, pour définir la
+route par défaut à 192.168.4.4, il est possible de faire
+.B --dhcp-option=3,192.168.4.4 
+ou
+.B --dhcp-option = option:router, 192.168.4.4
+ou encore, pour positionner l'adresse du serveur de temps à 192.168.0.4, on peut
+faire
+.B --dhcp-option = 42,192.168.0.4 
+ou 
+.B --dhcp-option = option:ntp-server, 192.168.0.4
+L'adresse 0.0.0.0 prends ici le sens "d'adresse de la machine sur laquelle
+tourne Dnsmasq". Les types de données autorisées sont des adresses IP sous la
+forme de 4 chiffres séparés par des points, un nombre décimal, une liste de
+caractères hexadécimaux séparés par des 2 points, ou une chaîne de caractères.
+Si des labels optionnels sont fournis, alors cette option n'est envoyée
+qu'aux réseaux dont tous les labels coïncident avec ceux de la requête.
+
+Un traitement spécial est effectué sur les chaînes de caractères fournies pour
+l'option 119, conformément à la RFC 3397. Les chaînes de caractères ou les
+adresses IP sous forme de 4 chiffres séparés par des points donnés en arguments
+de l'option 120 sont traités conforméments à la RFC 3361. Les adresses IP sous
+forme de 4 chiffres séparés par des points suivies par une barre montante "/",
+puis une taille de masque sont encodés conforméments à la RFC 3442.
+
+Les options IPv6 sont fournies en utilisant le mot-clef
+.B option6:
+suivi par le numéro d'option ou le nom d'option. L'espace de nommage des options
+IPv6 est disjint de l'espace de nommage des options IPv4. Les adresses IPv6
+en option doivent être entourées de crochets, comme par exemple :
+.B --dhcp-option=option6:ntp-server,[1234::56]
+
+Attention : aucun test n'étant fait pour vérifier que des données d'un type
+adéquat sont envoyées pour un numéro d'option donné, il est tout à fait possible
+de persuader Dnsmasq de générer des paquets DHCP illégaux par une utilisation
+incorrecte de cette option. Lorsque la valeur est un nombre décimal, Dnsmasq
+doit déterminer la taille des données. Cela est fait en examinant le numéro de
+l'option et/ou la valeur, mais peut-être évité en rajoutant un suffixe d'une
+lettre comme suit :
+b = un octet, s = 2 octets, i = 4 octets. Cela sert essentiellement pour des
+options encapsulées de classes de vendeurs (voir plus bas), pour lesquelles 
+Dnsmasq ne peut déterminer la taille de la valeur. Les données d'options
+consistant uniquement de points et de décimaux sont interprétées par Dnsmasq
+comme des adresses IP, et envoyées comme telles. Pour forcer l'envoi sous forme
+de chaîne de caractère, il est nécessaire d'utiliser des guillemets doubles. Par
+exemple, l'utilisation de l'option 66 pour fournir une adresse IP sous la forme
+d'une chaîne de caractères comme nom de serveur TFTP, il est nécessaire de faire
+comme suit :
+.B --dhcp-option=66,"1.2.3.4"
+
+Les options encapsulées de classes de vendeurs peuvent-être aussi spécifiées 
+(pour IPv4 seulement) en utilisant
+.B --dhcp-option
+: par exemple
+.B --dhcp-option=vendor:PXEClient,1,0.0.0.0
+envoie l'option encapsulée de classe de vendeur "mftp-address=0.0.0.0" à
+n'importe quel client dont la classe de vendeur correspond à "PXEClient". La
+correspondance pour les classes de vendeur s'effectue sur des sous-chaînes de
+caractères (voir
+.B --dhcp-vendorclass
+pour plus de détails). Si une option de
+classe de vendeur (numéro 60) est envoyée par Dnsmasq, alors cela est utilisé
+pour sélectionner les options encapsulées, de préférence à toute option envoyée
+par le client. Il est possible d'omettre complètement une classe de vendeur :
+.B --dhcp-option=vendor:,1,0.0.0.0
+Dans ce cas l'option encapsulée est toujours envoyée.
+
+En IPv4, les options peuvent-être encapsulées au sein d'autres options :
+par exemple
+.B --dhcp-option=encap:175, 190, "iscsi-client0"
+enverra l'option 175, au sein de laquelle se trouve l'option 190.
+Plusieurs options encapsulées avec le même numéro d'option seront correctement
+combinées au sein d'une seule option encapsulée. Il n'est pas possible de
+spécifier encap: et vendor: au sein d'une même option dhcp.
+
+La dernière variante pour les options encapsulées est "l'option de Vendeur
+identifiant le vendeur" ("Vendor-Identifying Vendor Options") telle que
+décrite dans le RFC3925. Celles-ci sont spécifiées comme suit :
+.B --dhcp-option=vi-encap:2, 10, "text"
+Le numéro dans la section vi-encap: est le numéro IANA de l'entreprise servant
+à identifier cette option. Cette forme d'encapsulation est également supportée
+en IPv6.
+
+L'adresse 0.0.0.0 n'est pas traitée de manière particulière lorsque fournie dans
+une option encapsulée.
+.TP
+.B --dhcp-option-force=[tag:<label>,[tag:<label>]][encap:<option>,][vi-encap:<entreprise>,][vendor:[<classe_vendeur>],][<option>|option:<nom d'option>],[<valeur>[,<valeur>]]
+Cela fonctionne exactement de la même façon que
+.B --dhcp-option
+sauf que cette option sera toujours envoyée, même si le client ne la demande pas
+dans la liste de paramêtres requis. Cela est parfois nécessaire, par exemple lors
+de la fourniture d'options à PXELinux.
+.TP
+.B --dhcp-no-override
+(IPv4 seulement) Désactive la réutilisation des champs DHCP nom de serveur et
+nom de fichier comme espace supplémentaire pour les options. Si cela est
+possible, dnsmasq déplace les informations sur le serveur de démarrage
+et le nom de fichier (fournis par 'dhcp-boot') en dehors des champs
+dédiés à cet usage dans les options DHCP. Cet espace supplémentaire est
+alors disponible dans le paquet DHCP pour d'autres options, mais peut, dans
+quelques rares cas, perturber des clients vieux ou défectueux. Cette
+option force le comportement à l'utilisation des valeurs "simples et sûres"
+afin d'éviter des problèmes dans de tels cas.
+.TP
+.B --dhcp-relay=<adresse locale>,<adresse de serveur>[,<interface]
+Configure dnsmasq en temps que relais DHCP.  L'adresse locale est une
+adresse allouée à l'une interface de la machine sur laquelle tourne dnsmasq.
+Toutes les requêtes DHCP arrivant sur cette interface seront relayées au
+serveur DHCP distant correspondant à l'adresse de serveur indiquée. Il est
+possible de relayer depuis une unique adresse locale vers différents serveurs
+distant en spécifiant plusieurs fois l'option dhcp-relay avec la même adresse
+locale et différentes adresses de serveur. L'adresse de serveur doit-être
+sous forme numérique. Dans le cas de DHCPv6, l'adresse de serveur peut-être
+l'adresse de multicast ff05::1:3 correspondant à tous les serveurs DHCP. Dans
+ce cas, l'interface doit-étre spécifiée et ne peut comporter de caractère
+joker. Elle sera utilisée pour indiquer l'interface à partir de laquelle le
+multicast pourra atteindre le serveur DHCP.
+
+Le contrôle d'accès pour les clients DHCP suivent les mêmes règles que pour
+les serveurs DHCP : voir --interface, --except-interface, etc. Le nom
+d'interface optionel dans l'option dhcp-relay comporte une autre fonction :
+il contrôle l'interface sur laquelle la réponse du serveur sera acceptée. Cela
+sert par exemple dans des configurations à 3 interfaces : une à partir de
+laquelle les requêtes sont relayées, une seconde permettant de se connecter à
+un serveur DHCP, et une troisième reliée à un réseau non-sécurisé tel
+qu'internet. Cela permet d'éviter l'arrivée de requêtes usurpées via cette
+troisième interface.
+
+Il est permis de configurer dnsmasq pour fonctionner comme serveur DHCP sur
+certaines interfaces et en temps que relais sur d'autres. Cependant, même s'il
+est possible de configurer dnsmasq de telle manière qu'il soit à la fois
+serveur et relais pour une même interface, cela n'est pas supporté et la
+fonction de relais prendra le dessus.
+
+Le relais DHCPv4 et le relais DHCPv6 sont tous les deux supportés, mais il
+n'est pas possible de relayer des requêtes DHCPv4 à un serveur DHCPv6 et
+vice-versa.
+.TP
+.B \-U, --dhcp-vendorclass=set:<label>,[enterprise:<numéro IANA d'enterprise>,]<classe de vendeur>
+
+Associe une chaîne de classe de vendeur à un label. La plupart
+des clients DHCP fournissent une "classe de vendeur" ("vendor class") qui
+représente, d'une certaine façon, le type d'hôte. Cette option associe des
+classes de vendeur à des labels, de telle sorte que des options DHCP peuvent-être
+fournie de manière sélective aux différentes classes d'hôtes. Par exemple,
+.B dhcp-vendorclass=set:printers,Hewlett-Packard JetDirect
+ou
+.B dhcp-vendorclass=printers,Hewlett-Packard JetDirect
+permet de n'allouer des options qu'aux imprimantes HP de la manière suivante :
+.B --dhcp-option=tag:printers,3,192.168.4.4
+La chaîne de caractères de la classe de vendeur founie en argument est cherchée
+en temps que sous-chaîne de caractères au sein de la classe de vendeur fournie
+par le client, de façon à permettre la recherche d'un sous-ensemble de la chaîne
+de caractères ("fuzzy matching"). Le préfixe set: est optionnel mais autorisé
+afin de conserver une certaine homogénéité.
+
+Notez qu'en IPv6 (et seulement en IPv6), les noms de classes de vendeurs
+sont dans un espace de nom associé au numéro attribué à l'entreprise par
+l'IANA. Ce numéro est fourni par le biais du mot-clef enterprise: et seules
+les classes de vendeurs associées au numéro spécifié seront cherchées.
+.TP
+.B \-j, --dhcp-userclass=set:<label>,<classe utilisateur>
+Associe une chaîne de classe d'utilisateur à un label (effectue la
+recherche sur des sous-chaînes, comme pour les classes de vendeur). La plupart
+des clients permettent de configurer une "classe d'utilisateur". Cette option
+associe une classe d'utilisateur à un label, de telle manière qu'il soit
+possible de fournir des options DHCP spécifiques à différentes classes d'hôtes.
+Il est possible, par exemple, d'utiliser ceci pour définir un serveur
+d'impression différent pour les hôtes de la classe "comptes" et ceux de la
+classe "ingénierie".
+.TP
+.B \-4, --dhcp-mac=set:<label>,<adresse MAC>
+Associe une adresse matérielle (MAC) à un label. L'adresse
+matérielle peut inclure des jokers. Par exemple
+.B --dhcp-mac=set:3com,01:34:23:*:*:*
+permet de définir le label "3com" pour n'importe quel hôte dont l'adresse
+matérielle coïncide avec les critères définis.
+.TP
+.B --dhcp-circuitid=set:<label>,<identifiant de circuit>, --dhcp-remoteid=set:<label>,<identifiant distant>
+Associe des options de relais DHCP issus de la RFC3046 à des labels.
+Cette information peut-être fournie par des relais DHCP. L'identifiant
+de circuit ou l'identifiant distant est normalement fourni sous la forme d'une
+chaîne de valeurs hexadécimales séparées par des ":", mais il est également
+possible qu'elle le soit sous la forme d'une simple chaîne de caractères. Si
+l'identifiant de circuit ou d'agent correspond exactement à celui fourni par le
+relais DHCP, alors le label est apposé.
+.B dhcp-remoteid
+est supporté en IPv6 (mais non dhcp-circuitid).
+.TP
+.B --dhcp-subscrid=set:<label>,<identifiant d'abonné>
+(IPv4 et IPv6) Associe des options de relais DHCP issues de la RFC3993 à des
+labels.
+.TP
+.B --dhcp-proxy[=<adresse ip>]......
+(IPv4 seulement) Un agent relai DHCP normal est uniquement utilisé pour faire
+suivre les éléments initiaux de l'interaction avec le serveur DHCP. Une fois
+que le client est configuré, il communique directement avec le serveur. Cela
+n'est pas souhaitable si le relais rajoute des informations supplémentaires
+aux paquets DHCP, telles que celles utilisées dans
+.B dhcp-circuitid
+et
+.B dhcp-remoteid.
+Une implémentation complète de relai peut utiliser l'option serverid-override
+de la RFC 5107 afin de forcer le serveur DHCP à utiliser le relai en temps que
+proxy complet, de sorte que tous les paquets passent par le relai. Cette option
+permet d'obtenir le même résultat pour des relais ne supportant pas la RFC
+5107. Fournie seule, elle manipule la valeur de server-id pour toutes les
+interactions via des relais. Si une liste d'adresses IP est donnée, seules les
+interactions avec les relais dont l'adresse est dans la liste seront affectées.
+.TP
+.B --dhcp-match=set:<label>,<numéro d'option>|option:<nom d'option>|vi-encap:<entreprise>[,<valeur>]
+Si aucune valeur n'est spécifiée, associe le label si le client
+envoie une option DHCP avec le numéro ou le nom spécifié. Lorsqu'une valeur est
+fournie, positionne le label seulement dans le cas où l'option est fournie et
+correspond à la valeur. La valeur peut-être de la forme "01:ff:*:02", auquel
+cas le début de l'option doit correspondre (en respectant les jokers). La
+valeur peut aussi être de la même forme que dans
+.B dhcp-option
+, auquel cas l'option est traitée comme un tableau de valeur, et un des
+éléments doit correspondre, ainsi
+
+--dhcp-match=set:efi-ia32,option:client-arch,6
+
+spécifie le label "efi-ia32" si le numéro 6 apparaît dnas la liste
+d'architectures envoyé par le client au sein de l'option 93. (se réferer
+au RFC 4578 pour plus de détails). Si la valeur est un chaine de caractères,
+celle-ci est recherchée (correspondance en temps que sous-chaîne).
+
+Pour la forme particulière vi-encap:<numéro d'entreprise>, la comparaison se
+fait avec les classes de vendeur "identifiant de vendeur" ("vendor-identifying
+vendor classes") pour l'entreprise dont le numéro est fourni en option.
+Veuillez vous réferer à la RFC 3925 pour plus de détail.
+.TP
+.B --tag-if=set:<label>[,set:<label>[,tag:<label>[,tag:<label>]]]
+Effectue une opération booléenne sur les labels. Si tous les labels
+apparaissant dans la liste tag:<label> sont positionnés, alors tous les
+la de la liste "set:<labels>" sont positionnés (ou supprimés, dans le cas
+où "tag:!<label>" utilisé).
+Si aucun tag:<label> n'est spécifié, alors tous les labels fournis par
+set:<label> sont positionnés.
+N'importe quel nombre de set: ou tag: peuvent être fournis, et l'ordre est sans
+importance.
+Les lignes tag-if sont executées dans l'ordre, ce qui fait que si un label dans
+tag:<label> est un label positionné par une rêgle
+.B tag-if,
+la ligne qui positionne le label doit précéder celle qui le teste.
+.TP
+.B \-J, --dhcp-ignore=tag:<label>[,tag:<label>]
+Lorsque tous les labels fournis dans l'option sont présents, ignorer l'hôte et
+ne pas donner de bail DHCP.
+.TP
+.B --dhcp-ignore-names[=tag:<label>[,tag:<label>]]
+Lorsque tous les labels fournis dans l'option sont présents, ignorer le
+nom de machine fourni par l'hôte. Il est à noter que, à la différence de
+l'option "dhcp-ignore", il est permis de ne pas fournir de label.
+Dans ce cas, les noms d'hôtes fournis par les clients DHCP seront toujours
+ignorés, et les noms d'hôtes seront ajoutés au DNS en utilisant uniquement la
+configuration dhcp-host de Dnsmasq, ainsi que le contenu des fichiers /etc/hosts
+et /etc/ethers.
+.TP
+.B --dhcp-generate-names=tag:<label>[,tag:<label>]
+(IPv4 seulement) Générer un nom pour les clients DHCP qui autrement n'en aurait
+pas, en utilisant l'adresse MAC sous sa forme hexadécimale, séparée par des
+tirets.
+Noter que si un hôte fourni un nom, celui-ci sera utilisé de préférence au nom
+autogénéré, à moins que
+.B --dhcp-ignore-names 
+ne soit positionné.
+.TP
+.B --dhcp-broadcast=[tag:<label>[,tag:<label>]]
+(IPv4 seulement) Lorsque tous les labels fournis dans l'option sont présents,
+toujours utiliser le broadcast pour communiquer avec l'hôte lorsque celui-ci
+n'est pas configuré. Il est possible de ne spécifier aucun label, auquel cas
+cette option s'applique inconditionnellement. La plupart des clients DHCP
+nécessitant une réponse par le biais d'un broadcast activent une option dans
+leur requête, ce qui fait que cela se fait automatiquement, mais ce n'est pas
+le cas de certains vieux clients BOOTP.
+.TP
+.B \-M, --dhcp-boot=[tag:<label>,]<nom de fichier>,[<nom de serveur>[,<adresse de serveur>|<nom du serveur tftp>]]
+(IPv4 seulement) Spécifie les options BOOTP devant être retournées par le
+serveur DHCP. Le nom de serveur ainsi que l'adresse sont optionnels : s'ils
+ne sont pas fournis, le nom est laissé vide et l'adresse fournie est celle de
+la machine sur laquelle s'exécute Dnsmasq. Si Dnsmasq founit un service TFTP (voir
+.B --enable-tftp
+), alors seul un nom de fichier est requis ici pour permettre un démarrage par
+le réseau.
+Si d'éventuels labels sont fournis, ils doivent coïncider avec
+ceux du client pour que cet élement de configuration lui soit envoyé.
+Une adresse de serveur TFTP peut être spécifiée à la place de l'adresse IP,
+sous la forme d'un nom de domaine qui sera cherché dans le fichier /etc/hosts.
+Ce nom peut être associé dans /etc/hosts avec plusieurs adresses IP, auquel cas
+celles-ci seront utilisées tour à tour (algorithme round-robin).
+Cela peut-être utiliser pour équilibrer la charge tftp sur plusieurs serveurs.
+.TP
+.B --dhcp-sequential-ip
+Dnsmasq est conçu pour choisir l'adresse IP des clients DHCP en utilisant
+un hachage de l'adresse MAC du client. Cela permet en général à l'adresse
+IP du client de rester stable au fil du temps, même lorsque le client laisse
+expirer son bail DHCP de temps en temps. Dans ce mode de fonctionnement par
+défaut, les adresses IP sont distribuées de façon pseudo-aléatoire dans la
+totalité de la plage d'adresses utilisable. Il existe des circonstances (par
+exemples pour du déploiement de serveur) où il est plus pratique d'allouer les
+adresses IP de manière séquentielle, en commençant par la plus petite adresse
+disponible, et c'est ce mode de fonctionnement qui est permis par cette option.
+Veuillez noter que dans ce mode séquentiel, les clients qui laissent expirer
+leur bail ont beaucoup plus de chance de voir leur adresse IP changer, aussi
+cette option ne devrait pas être utilisée dans un cas général.
+.TP
+.B --pxe-service=[tag:<label>,]<CSA>,<entrée de menu>[,<nom de fichier>|<type de service de démarrage>][,<adresse de serveur>|<nom de serveur>]
+La plupart des ROMS de démarrage PXE ne permettent au système PXE que la simple
+obtention d'une adresse IP, le téléchargement du fichier spécifié dans
+.B dhcp-boot
+et son exécution. Cependant, le système PXE est capable de fonctions bien plus
+complexes pour peu que le serveur DHCP soit adapté.
+
+Ceci spécifie l'option de démarrage qui apparaitra dans un menu de démarrage
+PXE. <CSA> est le type du système client. Seuls des types de services valides
+apparaitront dans un menu. Les types connus sont x86PC, PC98, IA64_EFI, Alpha,
+Arc_x86, Intel_Lean_Client, IA32_EFI, BC_EFI, Xscale_EFI et X86-64_EFI;
+D'autres types peuvent-être spécifiés sous la forme d'une valeur entière. Le
+paramètre après le texte correspondant à l'entrée dans le menu peut être un nom
+de fichier, auquel cas Dnsmasq agit comme un serveur de démarrage et indique au
+client PXE qu'il faut télécharger ce fichier via TFTP, soit depuis ce serveur
+(l'option
+.B enable-tftp 
+doit être spécifiée pour que cela marche), soit depuis un autre serveur TFTP
+si une adresse ou un nom de serveur est fournie.
+Veuillez noter que le suffixe de "couche" (en principe ".0") est fourni par PXE
+et ne doit pas être rajouté au nom de fichier. Si une valeur numérique entière
+est fournir pour le type de démarrage, en remplacement du nom de fichier, le
+client PXE devra chercher un service de démarrage de ce type sur le réseau.
+Cette recherche peut être faite via broadcast ou directement auprès d'un
+serveur si son adresse IP ou son nom sont fournis dans l'option.
+Si aucun nom de fichier n'est donné ni aucune valeur de type de service de
+démarrage n'est fournie (ou qu'une valeur de 0 est donnée pour le type de
+service), alors l'entrée de menu provoque l'interruption du démarrage par
+le réseau et la poursuite du démarrage sur un média local. L'adresse de serveur
+peut être donnée sous la forme de nom de domaine qui est recherché dans
+/etc/hosts. Ce nom peut-être associé à plusieurs adresses IP, qui dans ce cas
+sont utilisées à tour de rôle (en "round-robin").
+.TP
+.B --pxe-prompt=[tag:<label>,]<invite>[,<délai>]
+Cette option permet d'afficher une invite à la suite du démarrage PXE. Si un
+délai est fourni, alors la première entrée du menu de démarrage sera
+automatiquement exécutée après ce délai. Si le délai vaut 0, alors la première
+entrée disponible sera exécutée immédiatement. Si
+.B pxe-prompt
+est omis, le système attendra un choix de l'utilisateur s'il existe plusieurs
+entrées dans le menu, ou démarrera immédiatement dans le cas où il n'y a qu'une
+seule entrée. Voir
+.B pxe-service 
+pour plus de détails sur les entrées de menu.
+
+Dnsmasq peut servir de "proxy-DHCP" PXE, dans le cas où un autre serveur DHCP
+sur le réseau est responsable de l'allocation des adresses IP, auquel cas
+Dnsmasq se contente de fournir les informations données dans les options
+.B pxe-prompt
+et
+.B pxe-service
+pour permettre le démarrage par le réseau. Ce mode est activé en utilisant le
+mot-clef
+.B proxy
+dans
+.B dhcp-range.
+.TP
+.B \-X, --dhcp-lease-max=<nombre>
+Limite Dnsmasq à un maximum de <nombre> baux DHCP. Le défaut est de 1000. Cette
+limite permet d'éviter des attaques de déni de service ("DoS") par des hôtes
+créant des milliers de baux et utilisant beaucoup de mémoire dans le processus
+Dnsmasq.
+.TP
+.B \-K, --dhcp-authoritative
+Doit être spécifié lorsque dnsmasq est réellement le seul serveur DHCP
+sur le réseau. Pour DHCPv4, cela change le comportement par défaut qui est
+celui d'un strict respect des RFC, afin que les requêtes DHCP pour des baux
+inconnus par des hôtes inconnus ne soient pas ignorées. Cela permet à de
+nouveaux hôtes d'obtenir des baux sans tenir compte de fastidieuses
+temporisations ("timeout"). Cela permet également à Dnsmasq de reconstruire
+sa base de données contenant les baux sans que les clients n'aient besoin de
+redemander un bail, si celle-ci est perdue.
+Dans le cas de DHCPv6, cela positionne la priorité des réponses à 255 (le
+maximum) au lieu de 0 (le minimum).
+.TP
+.B --dhcp-alternate-port[=<port serveur>[,<port client>]]
+(IPv4 seulement) Change les ports utilisés par défaut pour le DHCP. Si cette
+option est donnée seule sans argument, alors change les ports utilisés pour le
+DHCP de 67 et 68 respectivement à 1067 et 1068. Si un seul argument est donné, ce
+numéro est utilisé pour le port serveur et ce numéro plus 1 est utilisé pour le
+port client. Enfin, en fournissant deux numéros de ports, il est possible de
+spécifier arbitrairement 2 ports à la fois pour le serveur et pour le client DHCP.
+.TP
+.B \-3, --bootp-dynamic[=<identifiant de réseau>[,<identifiant de réseau>]]
+(IPv4 seulement) Permet l'allocation dynamique d'adresses IP à des clients BOOTP.
+Utiliser cette option avec précaution, une adresse allouée à un client BOOTP
+étant perpétuelle, et de fait n'est plus disponibles pour d'autres hôtes. Si
+aucun argument n'est donné, alors cette option permet une allocation dynamique
+dans tous les cas. Si des arguments sont spécifiés, alors l'allocation ne se
+fait que lorsque tous les identifiants coïncident. Il est possible de répeter
+cette option avec plusieurs jeux d'arguments.
+.TP
+.B \-5, --no-ping
+(IPv4 seulement) Par défaut, le serveur DHCP tente de s'assurer qu'une adresse
+n'est pas utilisée avant de l'allouer à un hôte. Cela est fait en envoyant une
+requête ICMP de type "echo request" (aussi connue sous le nom de "ping") à
+l'adresse en question. Si le serveur obtient une réponse, alors l'adresse doit
+déjà être utilisée et une autre est essayée. Cette option permet de supprimer
+cette vérification. A utiliser avec précaution.
+.TP
+.B --log-dhcp
+Traces additionnelles pour le service DHCP : enregistre toutes les options
+envoyées aux clients DHCP et les labels utilisés pour la
+détermination de celles-ci.
+.TP
+.B --quiet-dhcp, --quiet-dhcp6, --quiet-ra
+Supprime les logs des opérations de routine des protocoles concernés. Les
+erreurs et les problèmes seront toujours enregistrés. L'option --log-dhcp
+prends le pas sur --quiet-dhcp et quiet-dhcp6.
+.TP
+.B \-l, --dhcp-leasefile=<chemin de fichier>
+Utilise le fichier dont le chemin est fourni pour stocker les informations de
+baux DHCP.
+.TP
+.B --dhcp-duid=<ID d'entreprise>,<uid>
+(IPv6 seulement) Spécifie le numéro d'UID de serveur persistant que le serveur
+DHCPv6 doit utiliser. Cette option n'est normalement pas requise, Dnsmasq
+créant un DUID automatiquement lorsque cela est nécessaire. Lorsque cette
+option est positionnée, elle fournit à Dnsmasq les données nécessaires à la
+création d'un DUID de type DUID-EN. Veuillez noter qu'une fois créé, le DUID
+est stocké dans la base des baux, aussi changer entre un DUID créé
+automatiquement et un DUID-EN et vice-versa impose de réinitialiser la base de
+baux. Le numéro d'ID d'entreprise est assigné par l'IANA, et l'uid est une
+chaine hexadécimale unique à chaque serveur.
+.TP
+.B \-6 --dhcp-script=<chemin de fichier>
+Lorsqu'un bail DHCP est créé, qu'un ancien est supprimé, ou qu'un transfert
+TFTP est terminé, le fichier dont le
+chemin  est spécifié est exécuté. Le <chemin de fichier> doit être un chemin
+absolu, aucune recherche n'est effectuée via la variable d'environnement PATH.
+Les arguments fournis à celui-ci sont soit
+"add" ("ajouter"), "old" ("ancien") ou "del" ("supprimer"), suivi de l'adresse
+MAC de l'hôte (ou le DUID pour IPv6) puis l'adresse IP et le nom d'hôte si
+celui-ci est connu."add" signifie qu'un bail a été créé, "del" signifie qu'il a
+été supprimé, "old" notifie que le bail existait au lancement de Dnsmasq, ou un
+changement d'adresse MAC ou de nom d'hôte pour un bail existant (ou, dans le cas
+où leasefile-ro est spécifié, un changement de durée de bail ou d'identifiant
+d'hôte). Si l'adresse Mac est d'un type de réseau autre qu'ethernet, il est
+nécessaire de la préceder du type de réseau, par exemple "06-01:23:45:67:89:ab"
+pour du token ring. Le processus est exécuté en temps que super-utilisateur 
+(si Dnsmasq a été lancé en temps que "root"), même si Dnsmasq est configuré 
+pour changer son UID pour celle d'un utilisateur non-privilégié.
+
+L'environnement est hérité de celui de l'invocation du processus Dnsmasq,
+auquel se rajoute quelques unes ou toutes les variables décrites ci-dessous :
+
+Pour IPv4 et IPv6 :
+
+DNSMASQ_DOMAIN si le nom de domaine pleinement qualifié de l'hôte est connu, la
+part relative au domaine y est stockée. (Notez que le nom d'hôte transmis comme
+argument au script n'est jamais pleinement qualifié).
+
+Si le client fournit un nom d'hôte, DNSMASQ_SUPPLIED_HOSTNAME.
+
+Si le client fournit des classes d'utilisateur, DNSMASQ_USER_CLASS0 à
+DNSMASQ_USER_CLASSn.
+
+Si Dnsmasq a été compilé avec l'option HAVE_BROKEN_RTC ("horloge RTC
+défectueuse"), alors la durée du bail (en secondes) est stockée dans la
+variable DNSMASQ_LEASE_LENGTH, sinon la date d'expiration du bail est toujours
+stocké dans la variable d'environnement DNSMASQ_LEASE_EXPIRES. Le nombre de
+secondes avant expiration est toujours stocké dans DNSMASQ_TIME_REMAINING.
+
+Si un bail était associé à un nom d'hôte et
+que celui-ci est supprimé, un évênement de type "old" est généré avec le
+nouveau statut du bail, c-à-d sans nom d'hôte, et le nom initial est fourni
+dans la variable d'environnement DNSMASQ_OLD_HOSTNAME.
+
+La variable DNSMASQ_INTERFACE contient le nom de l'interface sur laquelle la
+requête est arrivée; ceci n'est pas renseigné dans le cas des actions "old"
+ayant lieu après un redémarrage de dnsmasq.
+
+La variable DNSMASQ_RELAY_ADDRESS est renseignée si le client a utilisé un
+relai DHCP pour contacter Dnsmasq, si l'adresse IP du relai est connue.
+
+DNSMASQ_TAGS contient tous les labels fournis pendant la transaction DHCP,
+séparés par des espaces.
+
+DNSMASQ_LOG_DHCP est positionné si
+.B --log-dhcp
+est activé.
+
+Pour IPv4 seulement :
+
+DNSMASQ_CLIENT_ID, si l'hôte a fourni un identifiant de client.
+
+DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBSCRIBER_ID, DNSMASQ_REMOTE_ID si un relai DHCP a
+rajouté l'une de ces options.
+
+Si le client fournit une information de classe de vendeur, DNSMASQ_VENDOR_CLASS.
+
+Pour IPv6 seulement :
+
+Si le client fournit une classe de vendeur (vendor-class), positionne
+DNSMASQ_VENDOR_CLASS_ID avec comme contenu le numéro IANA de l'entreprise pour
+la classe, et DNSMASQ_VENDOR_CLASS0..DNSMASQ_VENDOR_CLASSn pour les données.
+
+DNSMASQ_SERVER_DUID contient le DUID du serveur : cette valeur est la même
+pour chaque appel au script.
+
+DNSMASQ_IAID contenant l'IAID pour le bail. Si le bail est une allocation
+temporaire, cela est préfixé par le caractère 'T'.
+
+DNSMASQ_MAC contient l'adresse MAC du client, si celle-ci est connue.
+
+A noter que le nom d'hôte fourni, la classe de vendeur ou les données de classe
+d'utilisateur sont uniquement fournies pour les actions "add" ou l'action "old"
+lorsqu'un hôte reprend un bail existant, puisque ces informations ne sont pas
+conservées dans la base de baux de dnsmasq.
+
+Tous les descripteurs de fichiers sont fermés, sauf stdin, stdout et stderr qui
+sont ouverts sur /dev/null (sauf en mode déverminage).
+
+Le script n'est pas lancé de manière concurrente : au plus une instance du
+script est executée à la fois (dnsmasq attends qu'une instance de script se
+termine avant de lancer la suivante). Les changements dans la base des baux
+nécessitant le lancement du script sont placé en attente dans une queue jusqu'à
+terminaison d'une instance du script en cours. Si cette mise en queue fait que
+plusieurs changements d'états apparaissent pour un bail donné avant que le
+script puisse être lancé, alors les états les plus anciens sont supprimés et
+lorsque le script sera finalement lancé, ce sera avec l'état courant du bail.
+
+Au démarrage de Dnsmasq, le script sera invoqué pour chacun des baux existants
+dans le fichier des baux. Le script sera lancé avec l'action "del" pour les
+baux expirés, et "old" pour les autres. Lorsque Dnsmasq reçoit un signal HUP,
+le script sera invoqué avec une action "old" pour tous les baux existants.
+
+Il existe deux autres actions pouvant apparaître comme argument au script :
+"init" et "tftp". D'autres sont susceptibles d'être rajoutées dans le futur,
+aussi les scripts devraient-être écrits de sorte à ignorer les actions
+inconnues. "init" est décrite ci-dessous dans
+.B --leasefile-ro.
+L'action "tftp" est invoquée lorsqu'un transfert de fichier TFTP s'est
+terminé. Ses arguments sont la taille du fichier en octets, l'adresse à
+laquelle le fichier a été envoyé, ainsi que le chemin complet du fichier.
+
+.TP
+.B --dhcp-luascript=<chemin>
+Spécifie un script écrit en Lua, devant être exécuté lorsque des baux sont
+créés, détruits ou modifiés. Pour utiliser cette option, dnsmasq doit être
+compilé avec avec le support de Lua. L'interpréteur Lua est initialisé une
+seule fois, lorsque dnsmasq démarre, ce qui fait que les variables globales
+persistent entre les évênements liés aux baux. Le code Lua doit définir une
+fonction
+.B lease
+et peut fournir des fonctions
+.B init
+et
+.B shutdown
+qui sont appellées, sans arguments, lorsque dnsmasq démarre ou s'arrête.
+Il peut également fournir une fonction
+.B tftp.
+
+La fonction
+.B lease
+reçoit les informations détaillées dans
+.B --dhcp-script. 
+Il reçoit deux arguments. Le premier spécifie l'action, qui est une chaîne de
+caractères contenant les valeurs "add" (ajout), "old" (réactivation d'un bail
+existant) ou "del" (suppression). Le deuxième est une table contenant des
+paires de valeurs de labels. Les labels correspondent pour l'essentiel aux
+valeurs d'environnement détaillées ci-dessus, ainsi le label "domain" (domaine)
+contient les mêmes données que la variable d'environnement DNSMASQ_DOMAIN. Il
+existe quelques labels supplémentaires contenant les données fournies comme
+arguments à
+.B --dhcp-script. 
+Ces labels sont
+.B mac_address, ip_address
+(pour respectivement l'adresse MAC et l'adresse IP)
+et
+.B hostname
+(le nom d'hôte) dans le cas d'IPv4, et
+.B client_duid, ip_address
+(valeur DUID du client et adresse IP respectivement)
+ainsi que
+.B hostname
+(le nom d'hôte) dans le cas d'IPv6.
+
+La fonction
+.B tftp
+est appelée de la même façon que la fonction "lease", et la table contient les
+labels
+.B destination_address,
+.B file_name
+et
+.B file_size
+(respectivement "adresse de destination", "nom de fichier" et "taille de fichier").
+.TP
+.B --dhcp-scriptuser
+Spécifie l'utilisateur sous lequel le script shell lease-change ou le script
+doivent être exécutés. La valeur par défaut correspond à l'utilisateur root
+mais peut-être changée par le biais de cette option.
+.TP
+.B \-9, --leasefile-ro
+Supprimer complètement l'usage du fichier servant de base de donnée pour les
+baux DHCP. Le fichier ne sera ni créé, ni lu, ni écrit. Change la façon dont le
+script de changement d'état de bail est lancé (si celui-ci est fourni par le
+biais de l'option
+.B --dhcp-script
+), de sorte que la base de données de baux puisse
+être complètement gérée par le script sur un stockage externe. En addition aux
+actions décrites dans 
+.B  --dhcp-script,
+le script de changement d'état de bail est appellé une fois, au lancement de
+Dnsmasq, avec pour seul argument "init". Lorsqu'appellé de la sorte, le script
+doit fournir l'état de la base de baux, dans le format de fichier de baux de
+Dnsmasq, sur sa sortie standard (stdout) et retourner un code de retour de 0.
+Positionner cette option provoque également une invocation du script de
+changement d'état de bail à chaque changement de l'identifiant de client, de
+longueur de bail ou de date d'expiration.
+.TP
+.B --bridge-interface=<interface>,<alias>[,<alias>]
+Traiter les requêtes DHCP (v4 et v6) et IPv6 Router Solicit arrivant
+sur n'importe laquelle des interfaces <alias> comme si elles
+arrivaient de l'interface <interface>. Cette option permet à dnsmasq
+de fournir les service DHCP et RA sur les interfaces ethernet non
+adressés et non pontés; par exemple sur un hôte de calcul d'OpenStack
+où chaque telle interface est une interface TAP à une machine
+virtuelle, ou lors de l'utilisation de pont ethernet "ancien mode" sur
+plate-forme BSD.  Chaque <alias> peut finir avec un simple '*' joker.
+.TP
+.B \-s, --domain=<domaine>[,<gamme d'adresses>[,local]]
+Spécifie le domaine du serveur DHCP. Le domaine peut être donné de manière
+inconditionnelle (sans spécifier de gamme d'adresses IP) ou pour des gammes
+d'adresses IP limitées. Cela a deux effets; tout d'abord, le
+serveur DHCP retourne le domaine à tous les hôtes le demandant, deuxièmement,
+cela spécifie le domaine valide pour les hôtes DHCP configurés. Le but de cela
+est de contraindre les noms d'hôte afin qu'aucun hôte sur le LAN ne puisse
+fournir via DHCP un nom tel que par exemple "microsoft.com" et capturer du
+trafic de manière illégitime. Si aucun nom de domaine n'est spécifié, alors
+les noms d'hôtes avec un nom de domaine (c-à-d un point dans le nom) seront
+interdits et enregistrés dans le journal (logs). Si un suffixe est fourni, alors
+les noms d'hôtes possédant un domaine sont autorisés, pour peu que le nom de
+domaine coïncide avec le nom fourni. De plus, si un suffixe est fourni, alors
+les noms d'hôtes ne possédant pas de nom de domain se voient rajouter le
+suffixe fourni dans l'option
+.B --domain.
+Ainsi, sur mon réseau, je peux configurer
+.B --domain=thekelleys.org.uk
+et avoir une machine dont le nom DHCP serait "laptop". L'adresse IP de cette
+machine sera disponible à la fois pour "laptop" et "laptop.thekelleys.org.uk".
+Si la valeur fournie pour <domaine> est "#", alors le nom de domaine est
+positionné à la première valeur de la directive "search" du fichier
+/etc/resolv.conf (ou équivalent).
+
+La gamme d'adresses peut être de la forme
+<adresse ip>,<adresse ip> ou <adresse ip>/<masque de réseau> voire une simple
+<adresse ip>. Voir
+.B --dhcp-fqdn
+qui peut changer le comportement de dnsmasq relatif aux domaines.
+
+Si la gamme d'adresse est fournie sous la forme
+<adresse ip>/<taille de réseau>, alors le drapeau "local" peut-être rajouté
+qui a pour effect d'ajouter --local-declarations aux requêtes DNS directes et
+inverses. C-à-d
+.B --domain=thekelleys.org.uk,192.168.0.0/24,local
+est identique à
+.B --domain=thekelleys.org.uk,192.168.0.0/24
+--local=/thekelleys.org.uk/ --local=/0.168.192.in-addr.arpa/
+La taille de réseau doit-être de 8, 16 ou 24 pour être valide.
+.TP
+.B --dhcp-fqdn
+Dans le mode par défaut, dnsmasq insère les noms non-qualifiés des clients
+DHCP dans le DNS. Pour cette raison, les noms doivent être uniques, même si
+deux clients ayant le même nom sont dans deux domaines différents. Si un
+deuxième client DHCP apparaît ayant le même nom qu'un client déjà existant,
+ce nom est transféré au nouveau client. Si
+.B --dhcp-fqdn
+est spécifié, ce comportement change : les noms non qualifiés ne sont plus
+rajoutés dans le DNS, seuls les noms qualifiés le sont. Deux clients DHCP
+avec le même nom peuvent tous les deux garder le nom, pour peu que la partie
+relative au domaine soit différente (c-à-d que les noms pleinements qualifiés
+diffèrent). Pour d'assurer que tous les noms ont une partie domaine, il doit-y
+avoir au moins un
+.B --domain
+sans gamme d'adresses de spécifié lorsque l'option
+.B --dhcp-fqdn 
+est configurée.
+.TP
+.B --dhcp-client-update
+Normalement, lorsque dnsmasq fournit un bail DHCP, il positionne un label
+dans l'option FQDN pour indiquer au client qu'il ne doit pas tenter de faire
+une mise à jour DDNS avec son nom et son adresse IP. Ceci parce que la paire
+Nom-IP est rajoutée automatiquement dans la partie DNS de dnsmasq. Cette option
+inhibe ce comportement ce qui est utile, par exemple, pour permettre aux clients
+Windows de la mise à jour de serveurs Active Directory. Voir la RFC 4702 pour
+plus de détails.
+.TP
+.B --enable-ra
+Active la fonctionalité d'annonces routeurs IPv6 ("IPv6 Router Advertisement").
+DHCPv6 ne gère pas la configuration complète du réseau de la même façon que
+DHCPv4. La découverte de routeurs et la découverte (éventuelle) de préfixes pour
+la création autonome d'adresse sont gérées par un protocole différent.
+Lorsque DHCP est utilisé, seul un sous-ensemble de tout ceci est nécessaire et
+dnsmasq est à même de le gérer, en utilisant la configuration DHCP présente pour
+fournir la majorité des données. Lorsque les annonces routeurs (RA pour "Router
+Advertisement") sont activées, dnsmasq va annoncer un préfixe pour chaque
+dhcp-range et, par défaut, fournir comme valeur de routeur et de DNS récursif
+la valeur d'adresse link-local appropriée parmi celles de la machine sur
+laquelle tourne dnsmasq.
+Par défaut, les bits "managed address" sont positionnés, et le bit "use SLAAC"
+("utiliser SLAAC") est réinitialisé. Cela peut-être changé pour des
+sous-réseaux donnés par le biais du mot clef de mode décris dans
+.B --dhcp-range.
+Les paramètres DNS du RFC6106 sont inclus dans les annonces. Par défaut,
+l'adresse link-local appropriée parmi celles de la machine sur laquelle tourne
+dnsmasq est spécifiée comme DNS récursif. Si elles sont fournies, les
+options dns-server et domain-search sont utilisées respectivement pour RDNSS et
+DNSSL.
+.TP
+.B --ra-param=<interface>,[mtu:<valeur>|<interface>|off,][high,|low,]<intervalle d'annonce routeur>[,<durée de vie route>]
+Configure pour une interface donnée des valeurs pour les annonces routeurs
+différentes des valeurs par défaut. La valeur par défaut du champ priorité
+pour le routeur peut-être changée de "medium" (moyen) à "high" (haute) ou
+"low" (basse). Par exemple :
+.B --ra-param=eth0,high,0.
+Un intervalle (en secondes) entre les annonces routeur peut-être fourni par :
+.B --ra-param=eth0,60.
+La durée de vie de la route peut-être changée ou mise à zéro, auquel cas 
+le routeur peut annoncer les préfixes mais pas de route :
+.B --ra-parm=eth0,0,0
+(une valeur de zéro pour l'intervalle signifie qu'il garde la valeur par défaut).
+Ces quatre paramètres peuvent-être configurés en une fois :
+.B --ra-param=eth0,mtu:1280,low,60,1200
+La valeur pour l'interface peut inclure un caractère joker.
+.TP
+.B --enable-tftp[=<interface>[,<interface>]]
+Active la fonction serveur TFTP. Celui-ci est de manière délibérée limité aux
+fonctions nécessaires au démarrage par le réseau ("net-boot") d'un client. Seul
+un accès en lecture est possible; les extensions tsize et blksize sont supportées
+(tsize est seulement supporté en mode octet). Sans argument optionel, le service
+TFTP est fourni sur les mêmes interfaces que le service DHCP. Si une liste
+d'interfaces est fournie, cela définit les interfaces sur lesquelles le
+service TFTP sera activé.
+.TP
+.B --tftp-root=<répertoire>[,<interface>]
+Les fichiers à fournir dans les transferts TFTP seront cherchés en prenant le
+répertoire fourni comme racine. Lorsque cela est fourni, les chemins TFTP
+incluant ".." sont rejetés, afin d'éviter que les clients ne puissent sortir de
+la racine spécifiée. Les chemins absolus (commençant par "/") sont autorisés,
+mais ils doivent être à la racine TFTP fournie. Si l'option interface est
+spécifiée, le répertoire n'est utilisé que pour les requêtes TFTP reçues sur
+cette interface.
+.TP
+.B --tftp-unique-root
+Ajouter l'adresse IP du client TFTP en temps qu'élément de chemin, à la suite
+de la racine tftp (adresse sous forme de 4 chiffres séparés par des points).
+Uniquement valable si une racine TFTP est spécifiée et si le répertoire
+correspond existe. Ainsi, si la valeur pour tftp-root est "/tftp" et que le
+client d'adresse IP 1.2.3.4 requiert le fichier "monfichier", alors le chemin
+effective résultant sera "/tftp/1.2.3.4/monfichier" si /tftp/1.2.3.4 existe, ou
+"/tftp/monfichier" dans le cas contraire.
+.TP
+.B --tftp-secure
+Active le mode TFTP sécurisé : sans cela, tout fichier lisible
+par Dnsmasq est disponible via TFTP (les règles de contrôle d'accès unix
+habituelles s'appliquent). Lorsque l'option
+.B --tftp-secure
+est spécifiée, seuls les fichiers possédés par l'utilisateur sous lequel tourne
+le processus Dnsmasq sont accessibles. Si Dnsmasq est exécuté en temps que
+super-utilisateur ("root"), des règles différentes s'appliquent :
+.B --tftp-secure
+n'a aucun effet, mais seuls les fichiers ayant un droit de lecture pour tout le
+monde sont accessibles. Il n'est pas recommandé d'exécuter Dnsmasq sous
+l'utilisateur "root" lorsque le service TFTP est activé, et il est formellement
+déconseillé de le faire sans fournir l'option
+.B --tftp-root.
+Sans cela, en effet, l'accès de tous les fichiers du serveur pour lequel le
+droit de lecture pour tout le monde est positionné ("world-readable") devient
+possible par n'importe quel hôte sur le réseau.
+.TP
+.B --tftp-lowercase
+Converti les noms de fichiers des requêtes TFTP en minuscules. Cela est utile
+pour les requêtes effectuées depuis les machines Windows, dont les systèmes
+de fichiers sont insensibles à la casse et pour lesquels la détermination
+de la casse est parfois un peu aléatoire. A noter que le serveur tftp de
+dnsmasq converti systématiquement les "\\" en "/" dans les noms de fichiers.
+.TP
+.B --tftp-max=<connexions>
+Définit le nombre maximum de connexions TFTP simultanées autorisées. La valeur
+par défaut est de 50. Lorsqu'un grand nombre de connexions TFTP est spécifié,
+il se peut que la limite de nombre de descripteurs de fichiers par processus
+soit atteinte. Dnsmasq nécessite quelques descripteurs de fichiers, ainsi qu'un
+descripteur de fichier pour chaque connexion TFTP simultanée et pour chacun des
+fichiers devant être fournis. De fait, servir le même fichier à n clients ne
+nécessitera qu'environ n + 10 descripteurs de fichiers, alors que fournir des
+fichiers tous différents à n clients utilisera environ (2*n) + 10 descripteurs.
+Si elle est donnée, l'option 
+.B --tftp-port-range
+peut affecter le nombre maximum de connexions concurrentes.
+.TP
+.B --tftp-no-blocksize
+Empêche le serveur TFTP de négocier l'option "blocksize" (taille de bloc) avec
+les clients. Certains clients buggés spécifient cette option mais se comportent
+ensuite de manière incorrecte si celle-ci est accordée.
+.TP
+.B --tftp-port-range=<début>,<fin>
+Un serveur TFTP écoute sur le port prédéfini 69 ("well-known port") pour
+l'initiation de la connexion, mais utilise également un port dynamiquement
+alloué pour chaque connexion. Normalement, ces ports sont alloués par
+le système d'exploitation, mais cette option permet de spécifier une gamme
+de ports à utiliser pour les transferts TFTP. Cela peut-être utile si
+TFTP doit traverser un dispositif garde-barrière ("firewall"). La valeur
+de début pour la plage de port ne peut-être inférieure à 1025 sauf si
+dnsmasq tourne en temps que super-utilisateur ("root"). Le nombre de
+connexions TFTP concurrentes est limitée par la taille de la gamme de
+ports ainsi spécifiée.
+.TP
+.B --tftp-port-range=<début>,<fin>
+Un serveur TFTP écoute sur un numéro de port bien connu (69) pour l'initiation
+de la connexion, et alloue dynamiquement un port pour chaque connexion. Ces
+numéros de ports sont en principe alloués par le système d'exploitation, mais
+cette option permet de spécifier une gamme de ports à utiliser pour les
+transferts TFTP. Cela peut-être utile lorsque ceux-ci doivent traverser un
+dispositif garde-barrière ("firewall"). Le début de la plage ne peut-être
+inférieur à 1024 à moins que Dnsmasq ne fonctionne en temps que
+super-utilisateur ("root"). Le nombre maximal de connexions TFTP concurrentes
+est limitée par la taille de la plage de ports ainsi définie. 
+.TP
+.B \-C, --conf-file=<fichier>
+Spécifie un fichier de configuration différent. L'option "conf-file" est
+également autorisée dans des fichiers de configuration, ce qui permet
+l'inclusion de multiples fichiers de configuration. L'utilisation de "-" comme
+nom de fichier permet la lecture par dnsmasq de sa configuration sur l'entrée standard
+stdin.
+.TP
+.B \-7, --conf-dir=<répertoire>[,<extension de fichier>...]
+Lis tous les fichiers du répertoire spécifié et les traite comme des fichiers de
+configuration. Si des extensions sont données, tout fichier finissant par ces
+extensions seront ignorés. Tout fichier dont le nom se termine en ~ ou commence
+par ., ainsi que ceux commençant ou se terminant par # seront systématiquement
+ignorés.
+Cette option peut être donnée en ligne de commande ou dans un fichier de
+configuration.
+.SH FICHIER DE CONFIGURATION
+Au démarrage, Dnsmasq lis
+.I /etc/dnsmasq.conf,
+si ce fichier existe. (Sur FreeBSD, ce fichier est
+.I /usr/local/etc/dnsmasq.conf
+) (voir cependant les options 
+.B \-C
+et
+.B \-7
+). Le format de ce fichier consiste en une option par ligne, exactement comme
+les options longues détaillées dans la section OPTIONS, mais sans être précédées
+par "--". Les lignes commençant par # sont des commentaires et sont ignorées.
+Pour les options qui ne peuvent-être spécifiées qu'une seule fois, celle du
+fichier de configuration prends le pas sur celle fournie en ligne de commande.
+Il est possible d'utiliser des guillemets afin d'éviter que les ",",":","." et
+"#" ne soit interprêtés, et il est possible d'utiliser les séquences
+d'échappement suivantes : \\\\ \\" \\t \\e \\b \\r et \\n. Elles correspondent
+respectivement à la barre oblique descendante ("anti-slash"), guillemets doubles,
+tabulation, caractère d'échappement ("escape"), suppression ("backspace"), retour ("return") et
+nouvelle ligne ("newline").
+.SH NOTES
+A la réception d'un signal SIGHUP,
+.B Dnsmasq
+vide son cache et recharge les fichiers
+.I /etc/hosts
+et
+.I /etc/ethers 
+ainsi que tout autre fichier spécifié par les options
+.B --dhcp-hostsfile
+,
+.B --dhcp-optsfile
+ou
+.B --addn-hosts.
+Le script de changement de bail est appellé pour chaque bail DHCP existant. Si
+l'option
+.B --no-poll
+est positionnée, alors le fichier
+.I /etc/resolv.conf
+est également rechargé.
+SIGHUP ne provoque PAS de rechargement du fichier de configuration.
+.PP
+A la réception d'un signal SIGUSR1,
+.B Dnsmasq 
+écrit des statistiques dans les traces système. Les informations fournies sont :
+la taille du cache, le nombre de noms ayant été supprimés du cache avant
+expiration afin de faire de la place pour les nouveaux noms, ainsi que le nombre
+total d'entrées ayant été insérées dans le cache. Pour chaque serveur amont, il fournit
+le nomnbre de requêtes transmises ainsi que le nombre de requêtes ayant résulté par une
+erreur. Lorsque Dnsmasq a été lancé via
+.B --no-daemon
+ou lorsque la traçabilité maximale a été activée (
+.B -q
+), la totalité du contenu du
+cache est de surcroît fournie.
+.PP 
+A la réception d'un signal SIGUSR2 et lorsqu'il enregistre directement ses
+traces dans un fichier (voir
+.B --log-facility
+), alors 
+.B Dnsmasq
+ferme et re-rouvre le fichier de traces. Il faut noter que pendant cette
+opération Dnsmasq ne s'exécute pas en temps que "root". Lorsqu'il créé un
+fichier de traces pour la première fois, Dnsmasq change le propriétaire du
+fichier afin de le faire appartenir à l'utilisateur non "root" sous lequel
+Dnsmasq s'exécute. Le logiciel de rotation de fichiers de trace logrotate doit
+être configuré pour créer un nouveau fichier avec un propriétaire identique au
+fichier existant avant d'envoyer le signal SIGUSR2. Si une requête DNS TCP est
+en cours, l'ancien fichier de traces reste ouvert dans le processus fils qui
+traite la requête TCP et il peut y être écrit. Il existe cependant une limite
+de 150 secondes après laquelle tous les processus traitant des requêtes TCP
+expirent : pour cette raison, il est préférable de ne pas configurer la
+compression des fichiers de traces venant juste de faire l'objet d'une rotation.
+Dans le cas de l'utilisation du logiciel logrotate, les options requises sont
+.B create 
+et
+.B delaycompress.
+ 
+.PP
+Dnsmasq est un logiciel de transmission de requêtes DNS : il n'est pas capable
+d'effectuer une résolution de nom récursive en partant des serveurs DNS racine,
+mais transmet de telles requêtes à un serveur DNS amont capable de telles
+recherches récursives, ce qui est typiquement le cas d'un serveur DNS de FAI.
+Par défaut, Dnsmasq lis
+.I /etc/resolv.conf
+pour découvrir les adresses IP des serveurs DNS amonts à utiliser, puisque cette
+information est en général stockée à cet endroit. A moins que l'option
+.B --no-poll
+ne soit utilisée,
+.B Dnsmasq
+vérifie la date de modification du fichier
+.I /etc/resolv.conf
+(ou l'équivalent si 
+.B \--resolv-file 
+est utilisé), et le relis lorsqu'il change. Cela permet de définir les serveurs
+DNS amont de manière dynamique lorsque PPP ou DHCP sont utilisés, puisque ces
+protocoles fournissent cette information.
+L'absence du fichier
+.I /etc/resolv.conf
+ne conduit pas à une erreur, puisqu'il peut très bien ne pas être créé avant
+qu'une connexion PPP ne soit établie. Dans ce cas, Dnsmasq vérifie régulièrement
+pour voir si un fichier
+.I /etc/resolv.conf 
+est créé. Dnsmasq peut être configuré pour lire plus d'un fichier resolv.conf.
+Cela est utile sur un ordinateur portable où PPP et DHCP peuvent-être utilisés :
+Dnsmasq peut alors être configuré pour lire à la fois
+.I /etc/ppp/resolv.conf 
+et
+.I /etc/dhcpc/resolv.conf 
+et utilisera le contenu du fichier ayant changé en dernier, ce qui permet de
+passer automatiquement de serveurs DNS à d'autres.
+.PP
+Les serveurs amonts peuvent aussi être spécifiés sur la ligne de commande ou
+dans un fichier de configuration. Ces spécifications de serveurs peuvent
+éventuellement se voir adjoindre d'un nom de domaine qui précise à Dnsmasq quel
+serveur utiliser pour trouver les noms d'un domaine donné.
+.PP
+Pour configurer Dnsmasq afin qu'il se comporte comme un cache pour la machine
+sur laquelle il tourne, mettre "nameserver 127.0.0.1" dans le fichier
+.I /etc/resolv.conf
+afin de forcer les processus locaux à envoyer leurs requêtes à Dnsmasq. Ensuite,
+spécifier les serveurs DNS amont soit en les fournissant directement à Dnsmasq
+via l'option
+.B \--server
+ou alors en mettant leurs adresses dans un autre fichier, par exemple
+.I /etc/resolv.dnsmasq
+et en lançant Dnsmasq avec l'option
+.B \-r /etc/resolv.dnsmasq.
+Cette deuxième technique permet la mise-à-jour dynamique des addresses de
+serveurs DNS amont par le biais de PPP ou DHCP.
+.PP
+Les adresses dans /etc/hosts prennent le dessus sur celles fournies par le
+serveur DNS amont, ainsi "macompagnie.com 1.2.3.4" dans /etc/hosts assure que
+les requêtes pour "macompagnie.com" retourneront toujours 1.2.3.4, même si une
+requête au serveur DNS amont retournerait une adresse différente. Il y a une
+exception à ceci : si le DNS amont contient un CNAME qui pointe vers un nom
+présent dans /etc/hosts, alors la recherche du CNAME via Dnsmasq fournira
+l'adresse DNS amont. Pour contourner cela, il suffit de mettre l'entrée
+correspondant au CNAME dans /etc/hosts.
+.PP
+le système de label fonctionne comme suit : pour chaque requête DHCP, dnsmasq
+associe un ensemble de labels obtenus à partir des lignes de la configuration
+incluant set:<label>, y compris un pour la plage d'adresse (
+.B dhcp-range
+) utilisée pour allouer l'adresse, un pour chaque entrée
+.B dhcp-host
+associée (auquel est rajouté le mot-clef "known" si une entrée dhcp-host
+coïncide).
+
+Le label "bootp" est associé aux requêtes BOOTP, un label dont le nom est le
+nom de l'interface sur laquelle la requête est arrivée.
+
+Pour les lignes de configuration comportant des éléments tag:<label>,
+seules seront valides celles pour lesquels tous les labels correspondants
+seront présents. C'est typiquement le cas des lignes dhcp-options.
+Un
+.B dhcp-option 
+possédant des labels sera utilisé de préférence à un
+.B dhcp-option 
+sans label, pour peu que _tous_ les labels positionnés correspondent à l'ensemble
+de labels décrit plus haut.
+Le préfixe '!' sur un label est un indicateur de négation, ainsi
+.B --dhcp=option=tag:!purple,3,1.2.3.4
+n'envoie l'option que lorsque le label "purple" n'est pas dans la liste de
+labels définis pour l'hôte considéré. (dans le cas de l'utilisation dans une
+ligne de commande au lieu d'un fichier de configuration, ne pas oublier
+d'échapper le caractère !, qui est un méta-caractère d'interpréteur de commande
+shell).
+
+Lors de la sélection d'une option, une étiquette spécifiée par dhcp-range
+passe après les autres étiquettes, ce qui permet de facilement remplacer des
+option génériques pour des hôtes spécifiques, ainsi :
+.B dhcp-range=set:interface1,......
+.B dhcp-host=set:monhote,.....
+.B dhcp-option=tag:interface1,option:nis-domain,"domaine1"
+.B dhcp-option=tag:monhote,option:nis-domain,"domaine2"
+va positionner l'option NIS-domain à domaine1 pour les hôtes dans la plage
+d'adresse, sauf pour monhote pour lequel cette valeur sera domaine2.
+
+.PP
+Veuillez noter que pour
+.B dhcp-range
+, les éléments tag:<label> et set:<label> sont tous les deux autorisés
+pour sélectionner la plage à utiliser selon, par exemple, le dhcp-host,
+et pour affecter l'option envoyée, sur la base de la plage sélectionnée.
+
+Ce système a évolué d'un système plus ancien et aux possibilités plus limitées,
+et pour des raisons de compatibilité "net:" peut être utilisé à la place de
+"tag:" et "set:" peut-être omis (à l'exception de
+.B dhcp-host,
+où "net:" peut-être utilisé à la place de "set:"). Pour les mêmes raisons, '#'
+peut-être utilisé à la place de '!' pour indiquer la négation.
+.PP 
+Le serveur DHCP intégré dans Dnsmasq fonctionne également en temps que serveur
+BOOTP, pour peu que l'adresse MAC et l'adresse IP des clients soient fournies,
+que ce soit par le biais de l'option 
+.B dhcp-host 
+ou dans le fichier
+.I /etc/ethers
+, et que l'option
+.B dhcp-range 
+soit présente afin d'activer le serveur DHCP pour un réseau donné (L'option
+.B --bootp-dynamic
+supprime la nécessité des associations statiques). Le paramètre
+"filename" (nom de fichier) de la requête BOOTP est utilisé comme label, ainsi
+que le label "bootp", permettant un certain contrôle sur les options retournées
+aux différentes classes d'hôtes.
+
+
+.SH CONFIGURATION EN TEMPS QUE SERVEUR FAISANT AUTORITÉ
+.PP 
+Configurer dnsmasq pour agir en temps que serveur DNS faisant autorité est
+compliqué par le fait que cela implique la configuration de serveurs DNS
+externes pour mettre en place la délégation. Seront présentés ci-dessous trois
+scénarios de complexité croissante. Le pré-requis pour chacun de ces scénarios
+est l'existence d'une adresse IP globalement disponible, d'un enregistrement de
+type A ou AAAA pointant vers cette adresse, ainsi que d'un serveur DNS externe
+capable d'effectuer la délégation de la zone en question. Pour la première
+partie de ces explications, nous allons appeller serveur.exemple.com
+l'enregistrement A (ou AAAA) de l'adresse globalement accessible, et
+notre.zone.com la zone pour laquelle dnsmasq fait autorité.
+
+La configuration la plus simple consiste en deux lignes de configuration,
+sous la forme :
+.nf
+.B auth-server=serveur.exemple.com,eth0
+.B auth-zone=notre.zone.com,1.2.3.0/24
+.fi
+
+ainsi que deux enregistrements dans le DNS externe :
+
+.nf
+serveur.exemple.com       A    192.0.43.10
+notre.zone.com            NS    serveur.exemple.com
+.fi
+
+eth0 est l'interface réseau externe sur laquelle dnsmasq écoute, dont l'adresse
+IP (globalement accessible) est 192.0.43.10. 
+
+A noter que l'adresse IP externe peut parfaitement être dynamique (par exemple
+attribuée par un FAI via DHCP ou PPP). Dans ce cas, l'enregistrement de type A
+doit être lié à cet enregistrement dynamique par l'une ou l'autre des techniques
+habituelles de système DNS dynamique.
+
+Un exemple plus complexe mais en pratique plus utile correspond au cas où
+l'adresse IP globalement accessible se trouve dans la zone pour laquelle
+dnsmasq fait autorité, le plus souvent à la racine. Dans ce cas nous avons :
+
+.nf
+.B auth-server=notre.zone.com,eth0
+.B auth-zone=notre.zone.com,1.2.3.0/24
+.fi
+
+.nf
+notre.zone.com             A    1.2.3.4
+notre.zone.com            NS    our.zone.com
+.fi
+
+L'enregistrement A pour notre.zone.com est dorénavant un enregistrement "colle"
+qui résoud le problème de poule et d'oeuf consistant à trouver l'adresse IP
+du serveur de nom pour notre.zone.com lorsque l'enregistrement se trouve dans
+la zone en question. Il s'agit du seul rôle de cet enregistrement : comme dnsmasq
+fait désormais autorité pour notre.zone.com, il doit également fournir cet
+enregistrement. Si l'adresse externe est statique, cela peut-être réalisé par
+le biais d'une entrée dans
+.B /etc/hosts 
+ou via un
+.B --host-record.
+
+.nf
+.B auth-server=notre.zone.com,eth0
+.B host-record=notre.zone.com,1.2.3.4
+.B auth-zone=notre.zone.com,1.2.3.0/24
+.fi
+
+Si l'adresse externe est dynamique, l'adresse associée à notre.zone.com doit
+être dérivée de l'interface correspondante. Cela peut être fait en utilisant
+.B interface-name
+Sous la forme :
+
+.nf
+.B auth-server=notre.zone.com,eth0
+.B interface-name=notre.zone.com,eth0
+.B auth-zone=notre.zone.com,1.2.3.0/24
+.fi
+
+La configuration finale rajoute à cette base un serveur DNS secondaire. Il
+s'agit d'un autre serveur DNS qui apprend les données DNS de la zone en
+effectuant un transfert de zone, et qui joue le rôle de serveur de secours
+au cas où le serveur principal devenait inaccessible. La configuration
+de ce serveur secondaire sort du cadre de cette page de manuel. Les éléments
+de configuration à rajouter dans dnsmasq sont les simples :
+
+.nf
+.B auth-sec-servers=secondaire.monfai.com
+.fi
+
+et
+
+.nf
+notre.zone.com           NS    secondaire.monfai.com
+.fi
+
+L'addition d'une option auth-sec-servers active les transferts de zone dans
+dnsmasq, ce qui permet au serveur secondaire de venir collecter les données
+DNS. Si vous souhaitez restreindre l'accès à ces données à des hôtes
+spécifiques, vous pouvez le faire via :
+
+.nf
+.B auth-peer=<adresse IP du serveur secondaire>
+.fi
+
+Dnsmasq joue le rôle de serveur faisant autorité pour les domaines in-addr.arpa
+et ip6.arpa associés aux sous-réseaux définis dans la déclaration de zone
+auth-zone, ce qui fait que les requêtes DNS inversées (de l'adresse vers
+le nom) peuvent-simplement être configurées avec un enregistrement NS
+adéquat. Par exemple, comme nous définissons plus haut les adresses
+1.2.3.0/24 :
+.nf
+ 3.2.1.in-addr.arpa  NS    notre.zone.com
+.fi
+
+Veuillez noter que pour l'instant, les zones inverses ne sont pas
+disponibles dans les transferts de zone, donc il est inutile de configurer
+de serveur secondaire pour la résolution inverse.
+
+.PP
+Lorsque dnsmasq est configuré en temps que serveur faisant autorité,
+les données suivantes sont utilisées pour peupler la zone considérée :
+.PP
+.B --mx-host, --srv-host, --dns-rr, --txt-record, --naptr-record
+, pour autant que les noms des enregistrements se trouvent dans la zone en
+question.
+.PP
+.B --cname
+pour peu que le nom soit dans le domaine. Si la cible du CNAME n'est
+pas pleinement qualifiée, alors elle est qualifiée avec le nom de la
+zone pour laquelle le serveur fait autorité.
+.PP
+Les adresses IPv4 et IPv6 extraites de /etc/hosts (et
+.B --addn-hosts
+) ainsi que les options
+.B --host-record
+fournissant des adresses situées dans l'un des sous-réseaux spécifiés dans 
+.B --auth-zone.
+.PP
+Adresses spécifiées par
+.B --interface-name.
+Dans ce cas, l'adresse n'est pas limitée à l'un des sous-réseaux donné dans
+.B --auth-zone. 
+
+.PP
+Les adresses de baux DHCP, si l'adresse est située dans l'un des sous-réseaux de
+.B --auth-zone
+OU dans une plage DHCP construite. Dans le mode par défaut, où le bail
+DHCP a un nom non qualifié, et éventuellement pour un nom qualifié construit
+via
+.B --domain
+, alors le nom dans la zone faisant autorité est construit à partir du nom
+non qualifié et du nom de domaine de la zone. Cela peut on non être égal
+celui fourni par
+.B --domain.
+Si l'option
+.B --dhcp-fqdn
+est fournie, alors les noms pleinemenet qualifiés associés aux baux DHCP
+sont utilisés, dès lors qu'ils correspondent au nom de domaine associé
+à la zone.
+
+
+.SH CODES DE SORTIE
+.PP
+0 - Dnsmasq s'est correctement lancé en tâche de fond, ou alors s'est
+correctement terminé si le lancement en tâche de fond n'a pas été activé.
+.PP
+1 - Un problème de configuration a été détecté.
+.PP
+2 - Un problème est survenu avec un accès réseau (adresse déjà utilisée,
+tentative d'utiliser un port privilégié sans les permissions nécessaires).
+.PP
+3 - Un problème est survenu avec une opération sur un système de fichier
+(fichier ou répertoire manquant, permissions).
+.PP
+4 - Impossibilité d'allouer de la mémoire.
+.PP
+5 - Autre problème.
+.PP
+11 ou plus - un code de retour différent de 0 a été reçu lors de l'appel au
+processus "init" du script des bails. Le code de retour de Dnsmasq correspond
+au code de retour du script plus 10.
+
+.SH LIMITES
+Les valeurs par défaut pour les limites de ressources de Dnsmasq sont en général
+conservatrices et appropriées pour des utilisations embarquées sur des machines
+de type routeur ayant des processeurs lents et une mémoire limitée. Sur du
+matériel plus performant, il est possible d'augmenter les limites et de gérer
+plus de clients. Les remarques suivantes s'appliquent à Dnsmasq version 2.37 et
+ultérieur : les versions précédentes ne montaient pas en charge aussi bien.
+ 
+.PP
+Dnsmasq est capable de gérer le DNS et DHCP pour au moins un millier de clients.
+Pour cela, la durée des bail ne doit pas être très courte (moins d'une heure).
+La valeur de
+.B --dns-forward-max 
+peut-être augmentée : commencer par la rendre égale au nombre de clients et
+l'augmenter si le DNS semble lent. Noter que la performance du DNS dépends
+également de la performance des serveurs amonts. La taille du cache DNS peut-
+être augmentée : la limite en dur est de 10000 entrées et la valeur par défaut
+(150) est très basse. Envoyer un signal SIGUSR1 à Dnsmasq le fait émettre des
+informations utiles pour paramétrer la taille de cache. Voir la section
+.B NOTES
+pour plus de détails.
+.PP
+Le serveur TFTP intégré est capable de plusieurs transferts de fichiers
+simultanés : La limite absolue est liée au nombre maximal de descripteurs de
+fichiers alloué à un processus et à la capacité de l'appel système select() à
+gérer un grand nombre de HANDLE de fichier. Si la limite est fixée trop haut par
+le biais de
+.B --tftp-max
+elle sera réduite et la limite actuelle sera enregistrée au démarrage. Il faut
+noter que plus de transferts sont possible lorsque le même fichier est transmis
+au lieu d'avoir un fichier différent pour chaque transfert.
+
+.PP
+Il est possible d'utiliser Dnsmasq pour bloquer la publicité sur la toile
+en associant des serveurs de publicité bien connus à l'adresse 127.0.0.1 ou
+0.0.0.0 par le biais du fichier
+.B /etc/hosts 
+ou d'un fichier d'hôte additionnel. Cette liste peut-être très longue, Dnsmasq
+ayant été testé avec succès avec un million de noms. Cette taille de fichier
+nécessite un processeur à 1 Ghz et environ 60 Mo de RAM.
+
+.SH INTERNATIONALISATION
+Dnsmasq peut être compilé pour supporter l'internationalisation. Pour cela,
+les cibles "all-i18n" et "install-i18n" doivent être données à make, en lieu
+et place des cibles standards "all" et "install". Lorsque compilé avec le
+support de l'internationalisation, dnsmasq supporte les noms de domaines
+internationalisés ("internationalised domain names" ou IDN), et les messages de
+traces ("logs") sont écrits dans la langue locale. Les noms de domaines dans
+/etc/hosts, /etc/ethers et /etc/dnsmasq.conf contenant des caractères
+non-ASCII seront transformés selon la représentation punycode interne
+aux DNS. Veuillez noter que dnsmasq détermine la langue pour les messages
+ainsi que le jeu de caractères susceptible d'être utilisé dans les fichiers
+de configuration à partir de la variable d'environnement LANG. Ceci devrait
+être configuré à la valeur par défaut du système par les scripts démarrant
+dnsmasq. Lorsque les fichiers de configuration sont édités, veuillez faire
+attention à le faire en utilisant la valeur de locale par défaut du système
+et non une valeur spécifique à l'utilisateur, puisque dnsmasq n'a aucun
+moyen de déterminer directement la valeur de jeu de caractère utilisé,
+et assume de ce fait qu'il s'agit de la valeur par défaut du système.
+
+.SH FICHIERS
+.IR /etc/dnsmasq.conf 
+
+.IR /usr/local/etc/dnsmasq.conf
+.IR /var/run/dnsmasq/resolv.conf
+.IR /etc/ppp/resolv.conf
+.IR /etc/dhcpc/resolv.conf
+
+.IR /etc/resolv.conf
+
+.IR /etc/hosts
+
+.IR /etc/ethers
+
+.IR /var/lib/misc/dnsmasq.leases 
+
+.IR /var/db/dnsmasq.leases
+
+.IR /var/run/dnsmasq.pid
+.SH VOIR AUSSI
+.BR hosts (5), 
+.BR resolver (5)
+.SH AUTEUR
+Cette page de manuel a été écrite par Simon Kelley <simon@thekelleys.org.uk>.
+
+La traduction dans un français bancal a été commise par Gildas Le Nadan
+<3ntr0p13@gmail.com> : Toute révision/correction permettant de corriger
+orthographe ou grammaire mais surtout les éventuelles fautes de sens sera la
+bienvenue!
diff --git a/po/de.po b/po/de.po
new file mode 100755
index 0000000..d99c4d2
--- /dev/null
+++ b/po/de.po
@@ -0,0 +1,2297 @@
+# German translations for dnsmasq package.
+#
+# This revised version is (C) Copyright by
+# Matthias Andree <matthias.andree@gmx.de>, 2010.
+# It is subject to the GNU General Public License v2,
+# or at your option, any later version.
+#
+# An older version of this file was originally put in the public domain by
+# Simon Kelley <simon@thekelleys.org.uk>, 2005.
+msgid ""
+msgstr ""
+"Project-Id-Version: dnsmasq 2.77\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-06-18 12:24+0100\n"
+"PO-Revision-Date: 2017-07-17 18:30+0100\n"
+"Last-Translator: Conrad Kostecki <ck@conrad-kostecki.de>\n"
+"Language-Team: German <de@li.org>\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Poedit 2.0.1\n"
+"X-Poedit-SourceCharset: UTF-8\n"
+
+#: cache.c:513
+msgid "Internal error in cache."
+msgstr "Interner Fehler im Cache."
+
+#: cache.c:923
+#, c-format
+msgid "failed to load names from %s: %s"
+msgstr "Fehler beim Laden der Namen von %s: %s"
+
+#: cache.c:949 dhcp.c:867
+#, c-format
+msgid "bad address at %s line %d"
+msgstr "Fehlerhafte Adresse in %s Zeile %d"
+
+#: cache.c:1002 dhcp.c:883
+#, c-format
+msgid "bad name at %s line %d"
+msgstr "Fehlerhafter Name in %s Zeile %d"
+
+#: cache.c:1011 dhcp.c:958
+#, c-format
+msgid "read %s - %d addresses"
+msgstr "%s gelesen - %d Adressen"
+
+#: cache.c:1124
+msgid "cleared cache"
+msgstr "Cache geleert"
+
+#: cache.c:1153
+#, c-format
+msgid "No IPv4 address found for %s"
+msgstr "Keine IPv4-Adresse für %s gefunden"
+
+#: cache.c:1232
+#, c-format
+msgid "%s is a CNAME, not giving it to the DHCP lease of %s"
+msgstr "%s ist ein CNAME, weise es der DHCP-Lease von %s nicht zu"
+
+#: cache.c:1256
+#, c-format
+msgid "not giving name %s to the DHCP lease of %s because the name exists in %s with address %s"
+msgstr "Name %s wurde dem DHCP-Lease von %s nicht zugewiesen, da der Name in %s bereits mit Adresse %s existiert"
+
+#: cache.c:1413
+#, c-format
+msgid "time %lu"
+msgstr "Zeit %lu"
+
+#: cache.c:1414
+#, c-format
+msgid "cache size %d, %d/%d cache insertions re-used unexpired cache entries."
+msgstr "Cache Größe %d, %d/%d Cache-Einfügungen verwendeten nicht abgelaufene Cache-Einträge wieder."
+
+#: cache.c:1416
+#, c-format
+msgid "queries forwarded %u, queries answered locally %u"
+msgstr "%u weitergeleitete Anfragen, %u lokal beantwortete Anfragen"
+
+#: cache.c:1419
+#, c-format
+msgid "queries for authoritative zones %u"
+msgstr "Anfragen nach autoritativen Zonen %u"
+
+#: cache.c:1445
+#, c-format
+msgid "server %s#%d: queries sent %u, retried or failed %u"
+msgstr "Server %s#%d: %u Anfragen gesendet, %u erneut versucht oder fehlgeschlagen"
+
+#: util.c:47
+#, c-format
+msgid "failed to seed the random number generator: %s"
+msgstr "Konnte den Zufallszahlengenerator nicht initialisieren: %s"
+
+#: util.c:224
+msgid "failed to allocate memory"
+msgstr "Konnte Speicher nicht belegen"
+
+#: util.c:277 option.c:619
+msgid "could not get memory"
+msgstr "Speicher nicht verfügbar"
+
+#: util.c:287
+#, c-format
+msgid "cannot create pipe: %s"
+msgstr "Konnte Pipe nicht erzeugen: %s"
+
+#: util.c:295
+#, c-format
+msgid "failed to allocate %d bytes"
+msgstr "Konnte %d Bytes nicht belegen"
+
+# @Simon: not perfect but I cannot get nearer right now.
+#: util.c:464
+#, c-format
+msgid "infinite"
+msgstr "unendlich"
+
+#: option.c:344
+msgid "Specify local address(es) to listen on."
+msgstr "Lokale abzuhörende Adresse(n) angeben."
+
+#: option.c:345
+msgid "Return ipaddr for all hosts in specified domains."
+msgstr "IP-Adresse für alle Hosts in angegebenen Domänen festlegen."
+
+# FIXME: the English test is not to the point. Just use a shortened description
+# from the manpage instead. -- MA
+#: option.c:346
+msgid "Fake reverse lookups for RFC1918 private address ranges."
+msgstr "Für private Adressbereiche nach RFC1918 \"keine solche Domain\" liefern."
+
+#: option.c:347
+msgid "Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."
+msgstr "Diese IP-Adresse als NXDOMAIN interpretieren (wehrt \"Suchhilfen\" ab)."
+
+#: option.c:348
+#, c-format
+msgid "Specify the size of the cache in entries (defaults to %s)."
+msgstr "Größe des Caches (Zahl der Einträge) festlegen (Voreinstellung: %s)."
+
+#: option.c:349
+#, c-format
+msgid "Specify configuration file (defaults to %s)."
+msgstr "Konfigurationsdatei festlegen (Voreinstellung: %s)."
+
+#: option.c:350
+msgid "Do NOT fork into the background: run in debug mode."
+msgstr "NICHT in den Hintergrund gehen: Betrieb im Debug-Modus"
+
+#: option.c:351
+msgid "Do NOT forward queries with no domain part."
+msgstr "Anfragen ohne Domänen-Teil NICHT weiterschicken."
+
+#: option.c:352
+msgid "Return self-pointing MX records for local hosts."
+msgstr "Für lokale Einträge MX-Einträge liefern, die auf sich selbst zeigen."
+
+#: option.c:353
+msgid "Expand simple names in /etc/hosts with domain-suffix."
+msgstr "Erweitere einfache Namen in /etc/hosts mit der Domänen-Endung."
+
+#: option.c:354
+msgid "Don't forward spurious DNS requests from Windows hosts."
+msgstr "'unechte' DNS-Anfragen von Windows-Rechnern nicht weiterleiten"
+
+# @Simon: I'm a bit unsure about "spurious"
+#: option.c:355
+msgid "Enable DHCP in the range given with lease duration."
+msgstr "DHCP für angegebenen Bereich und Dauer einschalten"
+
+#: option.c:356
+#, c-format
+msgid "Change to this group after startup (defaults to %s)."
+msgstr "Nach dem Start in diese Benutzergruppe wechseln (Voreinstellung %s)."
+
+#: option.c:357
+msgid "Set address or hostname for a specified machine."
+msgstr "Adresse oder Hostnamen für einen angegebenen Computer setzen."
+
+#: option.c:358
+msgid "Read DHCP host specs from file."
+msgstr "DHCP-Host-Angaben aus Datei lesen."
+
+#: option.c:359
+msgid "Read DHCP option specs from file."
+msgstr "DHCP-Optionen aus Datei lesen."
+
+#: option.c:360
+msgid "Read DHCP host specs from a directory."
+msgstr "DHCP-Host-Angaben aus einem Verzeichnis lesen."
+
+#: option.c:361
+msgid "Read DHCP options from a directory."
+msgstr "DHCP-Optionen aus einem Verzeichnis lesen."
+
+#: option.c:362
+msgid "Evaluate conditional tag expression."
+msgstr "Auswertung eines Ausdrucks bedingter Marken."
+
+#: option.c:363
+#, c-format
+msgid "Do NOT load %s file."
+msgstr "%s-Datei NICHT laden."
+
+#: option.c:364
+#, c-format
+msgid "Specify a hosts file to be read in addition to %s."
+msgstr "Hosts-Datei festlegen, die zusätzlich zu %s gelesen wird."
+
+#: option.c:365
+msgid "Read hosts files from a directory."
+msgstr "DHCP-Host-Dateien aus einem Verzeichnis lesen."
+
+#: option.c:366
+msgid "Specify interface(s) to listen on."
+msgstr "Schnittstelle(n) zum Empfang festlegen."
+
+#: option.c:367
+msgid "Specify interface(s) NOT to listen on."
+msgstr "Schnittstelle(n) festlegen, die NICHT empfangen sollen."
+
+#: option.c:368
+msgid "Map DHCP user class to tag."
+msgstr "DHCP-Benutzerklasse auf Marke abbilden."
+
+#: option.c:369
+msgid "Map RFC3046 circuit-id to tag."
+msgstr "RFC3046 \"circuit-id\" auf Marke abbilden."
+
+#: option.c:370
+msgid "Map RFC3046 remote-id to tag."
+msgstr "RFC3046 \"remote-id\" auf Marke abbilden."
+
+#: option.c:371
+msgid "Map RFC3993 subscriber-id to tag."
+msgstr "RFC3993 \"subscriber-id\" auf Marke abbilden."
+
+#: option.c:372
+msgid "Don't do DHCP for hosts with tag set."
+msgstr "Kein DHCP für Hosts mit gesetzter Marke verwenden."
+
+#: option.c:373
+msgid "Force broadcast replies for hosts with tag set."
+msgstr "Rundsendung für Hosts mit gesetzter Marke erzwingen."
+
+#: option.c:374
+msgid "Do NOT fork into the background, do NOT run in debug mode."
+msgstr "NICHT in den Hintergrund wechseln, NICHT im Debug-Modus laufen."
+
+#: option.c:375
+msgid "Assume we are the only DHCP server on the local network."
+msgstr "Voraussetzen, dass wir der einzige DHCP-Server im lokalen Netz sind."
+
+#: option.c:376
+#, c-format
+msgid "Specify where to store DHCP leases (defaults to %s)."
+msgstr "Festlegen, wo DHCP-Leases gespeichert werden (Voreinstellung %s)."
+
+#: option.c:377
+msgid "Return MX records for local hosts."
+msgstr "MX-Einträge für lokale Hosts liefern."
+
+#: option.c:378
+msgid "Specify an MX record."
+msgstr "Einen MX-Eintrag festlegen."
+
+#: option.c:379
+msgid "Specify BOOTP options to DHCP server."
+msgstr "BOOTP-Optionen für DHCP-Server festlegen."
+
+#: option.c:380
+#, c-format
+msgid "Do NOT poll %s file, reload only on SIGHUP."
+msgstr "%s-Datei NICHT abfragen, nur bei SIGHUP neu laden."
+
+#: option.c:381
+msgid "Do NOT cache failed search results."
+msgstr "Fehlerhafte Suchergebnisse NICHT zwischenspeichern."
+
+#: option.c:382
+#, c-format
+msgid "Use nameservers strictly in the order given in %s."
+msgstr "Namensserver streng in der in %s angegebenen Reihenfolge verwenden."
+
+#: option.c:383
+msgid "Specify options to be sent to DHCP clients."
+msgstr "Optionen festlegen, die an DHCP-Klienten gesendet werden."
+
+#: option.c:384
+msgid "DHCP option sent even if the client does not request it."
+msgstr "DHCP-Option, die selbst ohne Klientenanfrage gesendet wird."
+
+#: option.c:385
+msgid "Specify port to listen for DNS requests on (defaults to 53)."
+msgstr "Port zum Abhören der DNS-Anfragen festlegen (53 voreingestellt)."
+
+#: option.c:386
+#, c-format
+msgid "Maximum supported UDP packet size for EDNS.0 (defaults to %s)."
+msgstr "Maximale unterstützte UDP-Paketgröße für EDNS.0 (Voreinstellung %s)."
+
+#: option.c:387
+msgid "Log DNS queries."
+msgstr "DNS-Anfragen protokollieren."
+
+#: option.c:388
+msgid "Force the originating port for upstream DNS queries."
+msgstr "Ausgehenden Port erzwingen für DNS-Anfragen an vorgelagerte Server."
+
+#: option.c:389
+msgid "Do NOT read resolv.conf."
+msgstr "resolv.conf NICHT lesen."
+
+#: option.c:390
+#, c-format
+msgid "Specify path to resolv.conf (defaults to %s)."
+msgstr "Pfad zu resolv.conf festlegen (%s voreingestellt)."
+
+#: option.c:391
+msgid "Specify path to file with server= options"
+msgstr " Dateipfad mit der Option server= angeben"
+
+#: option.c:392
+msgid "Specify address(es) of upstream servers with optional domains."
+msgstr "Adresse(n) vorgelagerter Server festlegen, optional mit Domänen."
+
+#: option.c:393
+msgid "Specify address of upstream servers for reverse address queries"
+msgstr "Adresse(n) vorgelagerter Server festlegen, für reverse Adressanfragen"
+
+#: option.c:394
+msgid "Never forward queries to specified domains."
+msgstr "Anfragen für angegebene Domänen niemals weiterleiten."
+
+#: option.c:395
+msgid "Specify the domain to be assigned in DHCP leases."
+msgstr "Domäne festlegen, die für DHCP-Leases zugewiesen wird."
+
+#: option.c:396
+msgid "Specify default target in an MX record."
+msgstr "Voreingestelltes Ziel für MX-Einträge festlegen."
+
+#: option.c:397
+msgid "Specify time-to-live in seconds for replies from /etc/hosts."
+msgstr "Gültigkeitsdauer für Antworten aus /etc/hosts festlegen."
+
+#: option.c:398
+msgid "Specify time-to-live in seconds for negative caching."
+msgstr "Gültigkeitsdauer in Sekunden für Caching negativer Ergebnisse festlegen."
+
+#: option.c:399
+msgid "Specify time-to-live in seconds for maximum TTL to send to clients."
+msgstr "Gültigkeitsdauer in Sekunden für Caching negativer Ergebnisse festlegen."
+
+#: option.c:400
+msgid "Specify time-to-live ceiling for cache."
+msgstr "Spezifiziere time-to-live ceiling für Cache."
+
+#: option.c:401
+msgid "Specify time-to-live floor for cache."
+msgstr "Spezifiziere time-to-live floor für Cache."
+
+#: option.c:402
+#, c-format
+msgid "Change to this user after startup. (defaults to %s)."
+msgstr "Nach dem Start diese Benutzerrechte annehmen (%s voreingestellt)."
+
+#: option.c:403
+msgid "Map DHCP vendor class to tag."
+msgstr "DHCP-\"vendor class\" auf Marke abbilden."
+
+#: option.c:404
+msgid "Display dnsmasq version and copyright information."
+msgstr "dnsmasq-Version und Urheberrecht anzeigen."
+
+#: option.c:405
+msgid "Translate IPv4 addresses from upstream servers."
+msgstr "IPv4-Adressen von vorgelagerten Servern übersetzen."
+
+#: option.c:406
+msgid "Specify a SRV record."
+msgstr "SRV-Eintrag festlegen."
+
+#: option.c:407
+msgid "Display this message. Use --help dhcp or --help dhcp6 for known DHCP options."
+msgstr "Diese Hilfe anzeigen. Benutzen Sie --help dhcp oder --help dhcp6 für bekannte DHCP-Optionen."
+
+#: option.c:408
+#, c-format
+msgid "Specify path of PID file (defaults to %s)."
+msgstr "Dateipfad für Prozesskennung (PID) festlegen (Voreinstellung: %s)."
+
+#: option.c:409
+#, c-format
+msgid "Specify maximum number of DHCP leases (defaults to %s)."
+msgstr "Höchstzahl der DHCP-Leases festlegen (%s voreingestellt)."
+
+#: option.c:410
+msgid "Answer DNS queries based on the interface a query was sent to."
+msgstr "DNS-Anfragen abhängig der Emfpangsschnittstelle beantworten."
+
+#: option.c:411
+msgid "Specify TXT DNS record."
+msgstr "DNS-TXT-Eintrag festlegen."
+
+#: option.c:412
+msgid "Specify PTR DNS record."
+msgstr "DNS-PTR-Eintrag festlegen."
+
+#: option.c:413
+msgid "Give DNS name to IPv4 address of interface."
+msgstr "Schnittstellennamen zur IPv4-Adresse des Interfaces auflösen."
+
+#: option.c:414
+msgid "Bind only to interfaces in use."
+msgstr "Nur an verwendete Schnittstellen binden."
+
+#: option.c:415
+#, c-format
+msgid "Read DHCP static host information from %s."
+msgstr "Statische DHCP-Host-Information aus %s lesen."
+
+#: option.c:416
+msgid "Enable the DBus interface for setting upstream servers, etc."
+msgstr "DBus-Schnittstelle zum Festlegen vorgelagerter Server usw. festlegen."
+
+#: option.c:417
+msgid "Do not provide DHCP on this interface, only provide DNS."
+msgstr "Auf dieser Schnittstelle kein DHCP anbieten, sondern nur DNS."
+
+#: option.c:418
+msgid "Enable dynamic address allocation for bootp."
+msgstr "Dynamische Adressbelegung für bootp einschalten."
+
+#: option.c:419
+msgid "Map MAC address (with wildcards) to option set."
+msgstr "MAC-Adresse (mit Jokerzeichen) auf Netzmarke abbilden."
+
+#: option.c:420
+msgid "Treat DHCP requests on aliases as arriving from interface."
+msgstr "DHCP-Anfragen von Alias-Schnittstellen für die Hauptschnittstelle beantworten."
+
+#: option.c:421
+msgid "Disable ICMP echo address checking in the DHCP server."
+msgstr "ICMP-Echo-Adressprüfung im DHCP-Server abschalten."
+
+#: option.c:422
+msgid "Shell script to run on DHCP lease creation and destruction."
+msgstr "Skript, das bei Erzeugung/Löschung einer DHCP-Lease laufen soll."
+
+#: option.c:423
+msgid "Lua script to run on DHCP lease creation and destruction."
+msgstr "Lua-Skript, welches bei Erzeugung/Löschung eines DHCP-Leases laufen soll."
+
+#: option.c:424
+msgid "Run lease-change scripts as this user."
+msgstr "Lease-Änderungs-Skript mit den Rechten dieses Nutzers ausführen."
+
+#: option.c:425
+msgid "Call dhcp-script with changes to local ARP table."
+msgstr "Rufe dhcp-script mit Änderungen an der lokalen ARP-Tabelle auf."
+
+#: option.c:426
+msgid "Read configuration from all the files in this directory."
+msgstr "Konfiguration aus allen Dateien in diesem Verzeichnis lesen."
+
+#: option.c:427
+msgid "Log to this syslog facility or file. (defaults to DAEMON)"
+msgstr "Für diese Syslog-Anlage oder in Datei loggen (Voreinstellung DAEMON)."
+
+#: option.c:428
+msgid "Do not use leasefile."
+msgstr "Keine Lease-Datei benützen."
+
+#: option.c:429
+#, c-format
+msgid "Maximum number of concurrent DNS queries. (defaults to %s)"
+msgstr "Höchstzahl nebenläufiger DNS-Anfragen (%s voreingestellt)."
+
+#: option.c:430
+#, c-format
+msgid "Clear DNS cache when reloading %s."
+msgstr "DNS-Cache beim Neuladen von %s löschen."
+
+#: option.c:431
+msgid "Ignore hostnames provided by DHCP clients."
+msgstr "Von DHCP-Clients gelieferte Hostnamen ignorieren."
+
+#: option.c:432
+msgid "Do NOT reuse filename and server fields for extra DHCP options."
+msgstr "Dateinamen und Server-Datenfehler für zusätzliche DHCP-Optionen NICHT wiederverwenden."
+
+#: option.c:433
+msgid "Enable integrated read-only TFTP server."
+msgstr "Eingebauten Nur-Lese-TFTP-Server einschalten."
+
+#: option.c:434
+msgid "Export files by TFTP only from the specified subtree."
+msgstr "Nur vom festgelegten Unterbaum Dateien per TFTP exportieren."
+
+#: option.c:435
+#, fuzzy
+msgid "Add client IP or hardware address to tftp-root."
+msgstr "IP-Adresse des Klienten an tftp-root anhängen."
+
+#: option.c:436
+msgid "Allow access only to files owned by the user running dnsmasq."
+msgstr "Zugriff nur auf Dateien gestatten, die dem dnsmasq aufrufenden Benutzer gehören."
+
+#: option.c:437
+msgid "Do not terminate the service if TFTP directories are inaccessible."
+msgstr "Der Dienst sollte nicht beendet werden, wenn die TFTP-Verzeichnisse nicht zugreifbar sind."
+
+#: option.c:438
+#, fuzzy, c-format
+msgid "Maximum number of concurrent TFTP transfers (defaults to %s)."
+msgstr "Höchstzahl nebenläufiger TFTP-Übertragungen (%s voreingestellt)."
+
+#: option.c:439
+msgid "Maximum MTU to use for TFTP transfers."
+msgstr "Maximale MTU für TFTP-Übertragungen erreicht."
+
+#: option.c:440
+msgid "Disable the TFTP blocksize extension."
+msgstr "TFTP-Blockgrößen-Erweiterung abschalten."
+
+#: option.c:441
+msgid "Convert TFTP filenames to lowercase"
+msgstr "Konvertiere TFTP Dateinamen in Kleinschreibung"
+
+#: option.c:442
+msgid "Ephemeral port range for use by TFTP transfers."
+msgstr "Bereich für vorübergehende Ports für TFTP-Übertragungen."
+
+#: option.c:443
+msgid "Extra logging for DHCP."
+msgstr "Erweiterte DHCP-Protokollierung."
+
+#: option.c:444
+msgid "Enable async. logging; optionally set queue length."
+msgstr "Asynchrone Protokollierung einschalten, opt. Warteschlangenlänge festlegen."
+
+#: option.c:445
+msgid "Stop DNS rebinding. Filter private IP ranges when resolving."
+msgstr "DNS-Rebinding unterbinden, private IP-Bereiche bei der Auflösung ausfiltern."
+
+#: option.c:446
+msgid "Allow rebinding of 127.0.0.0/8, for RBL servers."
+msgstr "Auflösung zu 127.0.0.0/8 erlauben, für RBL-Server."
+
+#: option.c:447
+msgid "Inhibit DNS-rebind protection on this domain."
+msgstr "DNS-Rebind-Schutz für diese Domäne sperren."
+
+#: option.c:448
+msgid "Always perform DNS queries to all servers."
+msgstr "DNS-Anfragen immer an alle Server weiterleiten."
+
+#: option.c:449
+msgid "Set tag if client includes matching option in request."
+msgstr "Marke setzen, wenn Klient eine entsprechende Option anfragt."
+
+#: option.c:450
+msgid "Use alternative ports for DHCP."
+msgstr "Alternative Ports für DHCP verwenden."
+
+#: option.c:451
+msgid "Specify NAPTR DNS record."
+msgstr "DNS-NAPTR-Eintrag festlegen."
+
+#: option.c:452
+msgid "Specify lowest port available for DNS query transmission."
+msgstr "Niedrigsten verfügbaren Port für Übertragung von DNS-Anfragen festlegen."
+
+#: option.c:453
+msgid "Specify highest port available for DNS query transmission."
+msgstr "Höchsten verfügbaren Port für Übertragung von DNS-Anfragen festlegen."
+
+#: option.c:454
+msgid "Use only fully qualified domain names for DHCP clients."
+msgstr "Für DHCP-Klienten nur vollständig bestimmte Domänennamen benutzen."
+
+# FIXME: probably typo in original message. -- MA
+#: option.c:455
+msgid "Generate hostnames based on MAC address for nameless clients."
+msgstr "Generiere Hostnamen auf Basis der MAC-Adresse für namenlose Klienten."
+
+#: option.c:456
+msgid "Use these DHCP relays as full proxies."
+msgstr "Diese DHCP-Relais als vollwertige Proxies verwenden."
+
+#: option.c:457
+msgid "Relay DHCP requests to a remote server"
+msgstr "Leute DHCP Anfragen an entfernten Server weiter"
+
+#: option.c:458
+msgid "Specify alias name for LOCAL DNS name."
+msgstr "Alias für LOKALEN DNS-Namen festlegen."
+
+#: option.c:459
+msgid "Prompt to send to PXE clients."
+msgstr "Aufforderung, die an PXE-Klienten geschickt wird."
+
+#: option.c:460
+msgid "Boot service for PXE menu."
+msgstr "Boot-Dienst für PXE-Menü."
+
+#: option.c:461
+msgid "Check configuration syntax."
+msgstr "Konfigurationssyntax prüfen."
+
+#: option.c:462
+msgid "Add requestor's MAC address to forwarded DNS queries."
+msgstr "Anfragende MAC-Adresse in die weiterleitende DNS-Anfrage einfügen."
+
+#: option.c:463
+msgid "Add specified IP subnet to forwarded DNS queries."
+msgstr "Füge spezifiziertes IP-Subnetz an weitergeleiteten DNS-Anfragen hinzu."
+
+#: option.c:464
+msgid "Add client identification to forwarded DNS queries."
+msgstr "Füge Klient Identifikationan weitergeleiteten DNS-Anfragen hinzu."
+
+#: option.c:465
+msgid "Proxy DNSSEC validation results from upstream nameservers."
+msgstr "Proxy-DNSSEC-Validierung-Ergebnisse von Upstream-Namensservern."
+
+#: option.c:466
+msgid "Attempt to allocate sequential IP addresses to DHCP clients."
+msgstr "Versuche sequenzielle IP-Adressen an DHCP-Klienten zu vergeben."
+
+#: option.c:467
+msgid "Copy connection-track mark from queries to upstream connections."
+msgstr "Kopiere \"connection-track mark\" von Anfragen nach Upstream-Verbindungen."
+
+#: option.c:468
+msgid "Allow DHCP clients to do their own DDNS updates."
+msgstr "Erlaube DHCP-Klienten ihre eigenen DDNS-Updates durchzuführen."
+
+#: option.c:469
+msgid "Send router-advertisements for interfaces doing DHCPv6"
+msgstr "Sende \"Router-Advertisments\" für Netzwerkschnittstellen, welche DHCPv6 nutzen"
+
+#: option.c:470
+msgid "Specify DUID_EN-type DHCPv6 server DUID"
+msgstr "Spezifiziere DUID_EN-type DHCPv6 Server DUID"
+
+#: option.c:471
+msgid "Specify host (A/AAAA and PTR) records"
+msgstr "Spezifiziere Host (A/AAAA und PTR) Einträge"
+
+#: option.c:472
+msgid "Specify arbitrary DNS resource record"
+msgstr "Spezifiziere einen beliebiegen DNS Eintrag"
+
+#: option.c:473
+msgid "Bind to interfaces in use - check for new interfaces"
+msgstr "Bindung zu Schnittstellen in Benutzung - prüfe auf neue Schnittstellen"
+
+#: option.c:474
+msgid "Export local names to global DNS"
+msgstr "Exportiere lokale Namen in das globale DNS"
+
+#: option.c:475
+msgid "Domain to export to global DNS"
+msgstr "Domain für das Exportieren des globalen DNS"
+
+#: option.c:476
+msgid "Set TTL for authoritative replies"
+msgstr "Setzte TTL für autoritative Antworten"
+
+#: option.c:477
+#, fuzzy
+msgid "Set authoritative zone information"
+msgstr "Setze autoritative Zoneninformationen"
+
+#: option.c:478
+msgid "Secondary authoritative nameservers for forward domains"
+msgstr "Sekundärer autoritativer Nameserver für weitergeleitete Domains"
+
+#: option.c:479
+msgid "Peers which are allowed to do zone transfer"
+msgstr "Peers welche einen Zonentransfer durchführen dürfen"
+
+#: option.c:480
+msgid "Specify ipsets to which matching domains should be added"
+msgstr "Spezifiziere IPSets zu welcher passende Domains hinzugefügt werden sollen"
+
+#: option.c:481
+msgid "Specify a domain and address range for synthesised names"
+msgstr "Spezifiziere eine Domain und Adressbereich für synthetisierte Namen"
+
+#: option.c:482
+msgid "Activate DNSSEC validation"
+msgstr "Aktiviere DNSSEC-Validierung"
+
+#: option.c:483
+msgid "Specify trust anchor key digest."
+msgstr "Spezifiziere Vertrauensursprung (Trust Anchor) der Schlüssel-Prüfdaten (Key Digest)."
+
+#: option.c:484
+msgid "Disable upstream checking for DNSSEC debugging."
+msgstr "Deaktiviere die Überprüfung vorgelagerter Server für DNSSEC-Debugging."
+
+#: option.c:485
+msgid "Ensure answers without DNSSEC are in unsigned zones."
+msgstr "Stellt sicher, dass Antworten ohne DNSSEC sich in einer unsignierten Zone befinden."
+
+#: option.c:486
+msgid "Don't check DNSSEC signature timestamps until first cache-reload"
+msgstr "DNSSEC Signatur-Zeitstempel nicht prüfen, bis erstmalig der Cache neugeladen wird"
+
+#: option.c:487
+msgid "Timestamp file to verify system clock for DNSSEC"
+msgstr "Zeitstempel-Datei für die Verifizierung der Systemuhrzeit für DNSSEC"
+
+#: option.c:489
+msgid "Specify DHCPv6 prefix class"
+msgstr "Spezifiziere DHCPv6 Prefix Klasse"
+
+#: option.c:491
+#, fuzzy
+msgid "Set MTU, priority, resend-interval and router-lifetime"
+msgstr "Setze Priorität, Intervall des erneuten Sendens und Router Lebenszeit"
+
+#: option.c:492
+msgid "Do not log routine DHCP."
+msgstr "Protokolliere kein DHCP."
+
+#: option.c:493
+msgid "Do not log routine DHCPv6."
+msgstr "Protokolliere kein DHCPv6."
+
+#: option.c:494
+msgid "Do not log RA."
+msgstr "RA nicht protokollieren."
+
+#: option.c:495
+msgid "Accept queries only from directly-connected networks."
+msgstr "Akzeptiere nur Anfragen von direkt verbundenen Netzwerken."
+
+#: option.c:496
+msgid "Detect and remove DNS forwarding loops."
+msgstr "Erkennen und Entfernen von DNS-Weiterleitungsschleifen."
+
+#: option.c:497
+msgid "Ignore DNS responses containing ipaddr."
+msgstr "Ignoriere DNS-Antworten, welche ipaddr enthalten."
+
+#: option.c:498
+msgid "Set TTL in DNS responses with DHCP-derived addresses."
+msgstr "Setzte TTL in DNS-Antworten mit DHCP-abgeleiteten Adressen."
+
+#: option.c:499
+msgid "Delay DHCP replies for at least number of seconds."
+msgstr ""
+
+#: option.c:703
+#, c-format
+msgid ""
+"Usage: dnsmasq [options]\n"
+"\n"
+msgstr ""
+"Verwendung: dnsmasq [Optionen]\n"
+"\n"
+
+#: option.c:705
+#, c-format
+msgid "Use short options only on the command line.\n"
+msgstr "Auf der Befehlszeile nur kurze Optionen verwenden!\n"
+
+#: option.c:707
+#, c-format
+msgid "Valid options are:\n"
+msgstr "Gültige Optionen sind:\n"
+
+#: option.c:754 option.c:868
+msgid "bad address"
+msgstr "Fehlerhafte Adresse."
+
+#: option.c:779 option.c:783
+msgid "bad port"
+msgstr "unzulässiger Port"
+
+#: option.c:797 option.c:826 option.c:861
+msgid "interface binding not supported"
+msgstr "Schnittstellenbindung nicht unterstützt"
+
+#: option.c:821 option.c:856
+msgid "interface can only be specified once"
+msgstr ""
+
+#: option.c:835 option.c:3800
+msgid "bad interface name"
+msgstr "unzulässiger Schnittestellenname"
+
+#: option.c:1062
+msgid "unsupported encapsulation for IPv6 option"
+msgstr "Nicht unterstützte Verkapselung für eine IPv6-Option"
+
+#: option.c:1076
+msgid "bad dhcp-option"
+msgstr "Fehlerhafte DHCP-Option"
+
+#: option.c:1144
+msgid "bad IP address"
+msgstr "Fehlerhafte IP-Adresse"
+
+#: option.c:1147 option.c:1286 option.c:3070
+msgid "bad IPv6 address"
+msgstr "Fehlerhafte IPv6-Adresse"
+
+#: option.c:1240
+msgid "bad IPv4 address"
+msgstr "Fehlerhafte IPv4-Adresse"
+
+#: option.c:1313 option.c:1407
+msgid "bad domain in dhcp-option"
+msgstr "Fehlerhafte Domäne in DHCP-Option"
+
+#: option.c:1445
+msgid "dhcp-option too long"
+msgstr "DHCP-Option zu lang"
+
+#: option.c:1452
+msgid "illegal dhcp-match"
+msgstr "Unzulässige dhcp-match-Option"
+
+#: option.c:1514
+msgid "illegal repeated flag"
+msgstr "unzulässig wiederholte Markierung"
+
+#: option.c:1522
+msgid "illegal repeated keyword"
+msgstr "unzulässig wiederholtes Schlüsselwort"
+
+#: option.c:1593 option.c:4434
+#, c-format
+msgid "cannot access directory %s: %s"
+msgstr "Kann auf Verzeichnis %s nicht zugreifen: %s"
+
+#: option.c:1639 tftp.c:537
+#, c-format
+msgid "cannot access %s: %s"
+msgstr "Kann auf %s nicht zugreifen: %s"
+
+#: option.c:1727
+msgid "setting log facility is not possible under Android"
+msgstr "Die Einstellung Protokolliereinrichtung kann unter Android nicht gesetzt werden"
+
+#: option.c:1736
+msgid "bad log facility"
+msgstr "Falsche Protokolliereinrichtung"
+
+#: option.c:1789
+msgid "bad MX preference"
+msgstr "unzulässige MX-Präferenz-Angabe"
+
+#: option.c:1794
+msgid "bad MX name"
+msgstr "unzulässiger MX-Name"
+
+#: option.c:1808
+msgid "bad MX target"
+msgstr "unzulässiges MX-Ziel"
+
+#: option.c:1820
+msgid "cannot run scripts under uClinux"
+msgstr "unter uClinux ist die Skriptausführung nicht möglich"
+
+#: option.c:1822
+msgid "recompile with HAVE_SCRIPT defined to enable lease-change scripts"
+msgstr "Neuübersetzung mit HAVE_SCRIPT nötig, um Lease-Änderungs-Skripte auszuführen"
+
+#: option.c:1826
+msgid "recompile with HAVE_LUASCRIPT defined to enable Lua scripts"
+msgstr "Um Benutzerdefinierte Lua-Skripte zu ermöglichen, muss mit HAVE_LUASCRIPT neu kompiliert werden"
+
+#: option.c:2095 option.c:2106 option.c:2143 option.c:2199 option.c:2482
+msgid "bad prefix"
+msgstr "unzulässiger Präfix"
+
+#: option.c:2504
+msgid "recompile with HAVE_IPSET defined to enable ipset directives"
+msgstr "Um IPSet-Direktiven zu aktivieren, muss mit HAVE_IPSET neu übersetzt werden"
+
+#: option.c:2713
+msgid "bad port range"
+msgstr "unzulässiger Portbereich"
+
+#: option.c:2738
+msgid "bad bridge-interface"
+msgstr "unzulässige Brücken-Schnittstelle"
+
+#: option.c:2798
+msgid "only one tag allowed"
+msgstr "nur eine Marke zulässig"
+
+#: option.c:2818 option.c:2830 option.c:2939 option.c:2944 option.c:2983
+msgid "bad dhcp-range"
+msgstr "unzulässiger DHCP-Bereich"
+
+#: option.c:2845
+msgid "inconsistent DHCP range"
+msgstr "inkonsistenter DHCP-Bereich"
+
+#: option.c:2907
+msgid "prefix length must be exactly 64 for RA subnets"
+msgstr "Die Präfixlenge muss genau 64 für RA Subnetze sein"
+
+#: option.c:2909
+msgid "prefix length must be exactly 64 for subnet constructors"
+msgstr "Die Präfixlenge muss genau 64 für Subnet Konstruktoren sein"
+
+#: option.c:2913
+msgid "prefix length must be at least 64"
+msgstr "Die Präfixlänge muss mindestens 64 sein"
+
+#: option.c:2916
+msgid "inconsistent DHCPv6 range"
+msgstr "Inkonsistenter DHCPv6-Bereich"
+
+#: option.c:2927
+msgid "prefix must be zero with \"constructor:\" argument"
+msgstr "Prefix muss mit dem \"constructor:\" Argument Null sein"
+
+#: option.c:3040 option.c:3088
+msgid "bad hex constant"
+msgstr "Falscher Hexwert"
+
+#: option.c:3062
+msgid "cannot match tags in --dhcp-host"
+msgstr "Kann die Tags in --dhcp-host nicht abgleichen"
+
+#: option.c:3110
+#, c-format
+msgid "duplicate dhcp-host IP address %s"
+msgstr "doppelte dhcp-host IP-Adresse %s"
+
+#: option.c:3168
+msgid "bad DHCP host name"
+msgstr "unzulässiger DHCP-Hostname"
+
+#: option.c:3250
+msgid "bad tag-if"
+msgstr "unzulässige bedingte Marke (tag-if)"
+
+#: option.c:3607 option.c:4030
+msgid "invalid port number"
+msgstr "unzulässige Portnummer"
+
+#: option.c:3669
+msgid "bad dhcp-proxy address"
+msgstr "Fehlerhafte DHCP-Proxy-Adresse"
+
+#: option.c:3695
+msgid "Bad dhcp-relay"
+msgstr "unzulässiger dhcp-relay"
+
+#: option.c:3736
+msgid "bad RA-params"
+msgstr "unzulässige RA-Parameter"
+
+#: option.c:3745
+msgid "bad DUID"
+msgstr "unzulässige DUID"
+
+#: option.c:3787
+msgid "invalid alias range"
+msgstr "unzulässiger Alias-Bereich"
+
+#: option.c:3841 option.c:3853
+msgid "bad CNAME"
+msgstr "unzulässiger CNAME"
+
+#: option.c:3857
+msgid "duplicate CNAME"
+msgstr "doppelter CNAME"
+
+#: option.c:3880
+msgid "bad PTR record"
+msgstr "unzulässiger PTR-Eintrag"
+
+#: option.c:3911
+msgid "bad NAPTR record"
+msgstr "unzulässiger NAPTR-Eintrag"
+
+#: option.c:3945
+msgid "bad RR record"
+msgstr "unzulässiger RR-Eintrag"
+
+#: option.c:3975
+msgid "bad TXT record"
+msgstr "unzulässiger TXT-Eintrag"
+
+#: option.c:4016
+msgid "bad SRV record"
+msgstr "unzulässiger SRV-Eintrag"
+
+#: option.c:4023
+msgid "bad SRV target"
+msgstr "unzulässiges SRV-Ziel"
+
+#: option.c:4037
+msgid "invalid priority"
+msgstr "unzulässige Priorität"
+
+#: option.c:4040
+msgid "invalid weight"
+msgstr "unzulässige Wichtung"
+
+#: option.c:4064
+msgid "Bad host-record"
+msgstr "unzulässiger host-record"
+
+#: option.c:4088
+msgid "Bad name in host-record"
+msgstr "Unzulässiger Name in host-record"
+
+#: option.c:4153
+msgid "bad trust anchor"
+msgstr "unzulässiger Vertrauensursprung (Trust Anchor)"
+
+#: option.c:4167
+msgid "bad HEX in trust anchor"
+msgstr "unzulässiger Hexwert in Vertrauensursprung (Trust Anchor)"
+
+#: option.c:4177
+msgid "unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"
+msgstr "Nicht unterstützte Option (prüfen Sie, ob DNSMasq mit DHCP/TFTP/DNSSEC/DBus-Unterstützung übersetzt wurde)"
+
+#: option.c:4237
+msgid "missing \""
+msgstr "fehlende \\\""
+
+#: option.c:4294
+msgid "bad option"
+msgstr "unzulässige Option"
+
+#: option.c:4296
+msgid "extraneous parameter"
+msgstr "überschüssiger Parameter"
+
+#: option.c:4298
+msgid "missing parameter"
+msgstr "fehler Parameter"
+
+#: option.c:4300
+msgid "illegal option"
+msgstr "unzulässige Option"
+
+#: option.c:4307
+msgid "error"
+msgstr "Fehler"
+
+#: option.c:4309
+#, c-format
+msgid " at line %d of %s"
+msgstr " in Zeile %d von %s"
+
+#: option.c:4324 option.c:4571 option.c:4607
+#, c-format
+msgid "read %s"
+msgstr "%s gelesen"
+
+#: option.c:4387 option.c:4510 tftp.c:715
+#, c-format
+msgid "cannot read %s: %s"
+msgstr "kann %s nicht lesen: %s"
+
+#: option.c:4676
+msgid "junk found in command line"
+msgstr "Mist in der Kommandozeile gefunden"
+
+#: option.c:4711
+#, c-format
+msgid "Dnsmasq version %s  %s\n"
+msgstr "Dnsmasq Version %s  %s\n"
+
+#: option.c:4712
+#, c-format
+msgid ""
+"Compile time options: %s\n"
+"\n"
+msgstr ""
+"Kompilierungs-Optionen %s\n"
+"\n"
+
+#: option.c:4713
+#, c-format
+msgid "This software comes with ABSOLUTELY NO WARRANTY.\n"
+msgstr "Für diese Software wird ABSOLUT KEINE GARANTIE gewährt.\n"
+
+# FIXME: this must be one long string! -- MA
+#: option.c:4714
+#, c-format
+msgid "Dnsmasq is free software, and you are welcome to redistribute it\n"
+msgstr "Dnsmasq ist freie Software, und du bist willkommen es weiter zu verteilen\n"
+
+#: option.c:4715
+#, c-format
+msgid "under the terms of the GNU General Public License, version 2 or 3.\n"
+msgstr "unter den Bedingungen der GNU General Public Lizenz, Version 2 oder 3.\n"
+
+#: option.c:4726
+msgid "try --help"
+msgstr "versuchen Sie --help"
+
+#: option.c:4728
+msgid "try -w"
+msgstr "versuchen Sie -w"
+
+#: option.c:4730
+#, c-format
+msgid "bad command line options: %s"
+msgstr "unzulässige Optionen auf der Befehlszeile: %s"
+
+#: option.c:4798
+#, c-format
+msgid "CNAME loop involving %s"
+msgstr ""
+
+#: option.c:4834
+#, c-format
+msgid "cannot get host-name: %s"
+msgstr "kann Hostnamen nicht ermitteln: %s"
+
+#: option.c:4862
+msgid "only one resolv.conf file allowed in no-poll mode."
+msgstr "mit -n/--no-poll ist nur eine resolv.conf-Datei zulässig."
+
+#: option.c:4872
+msgid "must have exactly one resolv.conf to read domain from."
+msgstr "Um die Domäne zu lesen, muss genau eine resolv.conf-Datei verwendet werden."
+
+#: option.c:4875 network.c:1612 dhcp.c:816
+#, c-format
+msgid "failed to read %s: %s"
+msgstr "konnte %s nicht lesen: %s"
+
+#: option.c:4892
+#, c-format
+msgid "no search directive found in %s"
+msgstr "keine \"search\"-Anweisung in %s gefunden"
+
+#: option.c:4913
+msgid "there must be a default domain when --dhcp-fqdn is set"
+msgstr "Es muss eine standard Domain gesetzt sein, wenn --dhcp-fqdn gesetzt ist"
+
+#: option.c:4922
+msgid "syntax check OK"
+msgstr "Syntaxprüfung OK"
+
+#: forward.c:102
+#, c-format
+msgid "failed to send packet: %s"
+msgstr "Fehlgeschlagen, folgendes Paket zu senden: %s"
+
+#: forward.c:597
+msgid "discarding DNS reply: subnet option mismatch"
+msgstr "Verwerfe DNS Antwort: Subnetoption stimmt nicht überrein"
+
+#: forward.c:651
+#, c-format
+msgid "nameserver %s refused to do a recursive query"
+msgstr "Namensserver %s hat eine rekursive Anfrage verweigert"
+
+#: forward.c:683
+#, c-format
+msgid "possible DNS-rebind attack detected: %s"
+msgstr "möglichen DNS-Rebind-Angriff entdeckt: %s"
+
+#: forward.c:1244 forward.c:1681
+msgid "Ignoring query from non-local network"
+msgstr "Ignoriere Anfragen vom nicht lokalen Netzwerk"
+
+#: forward.c:2166
+#, c-format
+msgid "Maximum number of concurrent DNS queries reached (max: %d)"
+msgstr "Maximale Anzahl an nebenläufiger DNS-Anfragen erreicht (Max: %d)"
+
+#: network.c:720
+#, c-format
+msgid "failed to create listening socket for %s: %s"
+msgstr "Konnte Empfangs-Socket für %s: %s nicht erzeugen"
+
+#: network.c:1031
+#, c-format
+msgid "LOUD WARNING: listening on %s may accept requests via interfaces other than %s"
+msgstr "LOUD WARNING: Das Abhören von %s kann die Anfragen auf der Schnittstelle akzeptieren anders als %s"
+
+#: network.c:1038
+msgid "LOUD WARNING: use --bind-dynamic rather than --bind-interfaces to avoid DNS amplification attacks via these interface(s)"
+msgstr "LOUD WARNING: Es sollte --bind-dynamic anstatt --bind-interfaces benutzt werden, um DNS-Verstärkungsangriffe auf diesen Schnittstellen zu unterbinden"
+
+#: network.c:1047
+#, fuzzy, c-format
+msgid "warning: using interface %s instead"
+msgstr "Warnung: %s nicht zugreifbar"
+
+#: network.c:1056
+#, c-format
+msgid "warning: no addresses found for interface %s"
+msgstr "Warnung: Keine Adresse für die Schnittstelle %s gefunden"
+
+#: network.c:1114
+#, c-format
+msgid "interface %s failed to join DHCPv6 multicast group: %s"
+msgstr "Schnittstelle %s konnte DHCPv6-Multicast-Gruppe nicht beitreten: %s"
+
+#: network.c:1119
+msgid "try increasing /proc/sys/net/core/optmem_max"
+msgstr "Versuche /proc/sys/net/core/optmem_max zu erhöhen"
+
+#: network.c:1322
+#, c-format
+msgid "failed to bind server socket for %s: %s"
+msgstr "konnte nicht an Server-Socket für %s binden: %s"
+
+#: network.c:1517
+#, c-format
+msgid "ignoring nameserver %s - local interface"
+msgstr "ignoriere Namensserver %s - lokale Schnittstelle"
+
+#: network.c:1528
+#, c-format
+msgid "ignoring nameserver %s - cannot make/bind socket: %s"
+msgstr "ignoriere Namensserver %s - kann Socket nicht erzeugen/binden: %s"
+
+#: network.c:1548
+msgid "(no DNSSEC)"
+msgstr "(kein DNSSEC)"
+
+# FIXME: this isn't translatable - always provide full strings, do not assemble yourself! -- MA
+#: network.c:1551
+msgid "unqualified"
+msgstr "unqualifiziert"
+
+#: network.c:1551
+msgid "names"
+msgstr "Namen"
+
+#: network.c:1553
+msgid "default"
+msgstr "Standard"
+
+#: network.c:1555
+msgid "domain"
+msgstr "Domain"
+
+#: network.c:1561
+#, c-format
+msgid "using local addresses only for %s %s"
+msgstr "Benutze lokale Adressen nur für %s %s"
+
+#: network.c:1564
+#, c-format
+msgid "using standard nameservers for %s %s"
+msgstr "Benutze standard Namensserver für %s %s"
+
+#: network.c:1566
+#, c-format
+msgid "using nameserver %s#%d for %s %s %s"
+msgstr "Benutze Namensserver %s#%d für %s %s %s"
+
+#: network.c:1570
+#, c-format
+msgid "NOT using nameserver %s#%d - query loop detected"
+msgstr "Benutze Namensserver %s#%d NICHT - Anfragenschleife festgetellt"
+
+#: network.c:1573
+#, c-format
+msgid "using nameserver %s#%d(via %s)"
+msgstr "Benutze Namensserver %s#%d(via %s)"
+
+#: network.c:1575
+#, c-format
+msgid "using nameserver %s#%d"
+msgstr "Benutze Namensserver %s#%d"
+
+#: network.c:1580
+#, fuzzy, c-format
+msgid "using %d more local addresses"
+msgstr "Benutze %d mehr Namensserver"
+
+#: network.c:1582
+#, c-format
+msgid "using %d more nameservers"
+msgstr "Benutze %d mehr Namensserver"
+
+#: dnsmasq.c:166
+msgid "dhcp-hostsdir, dhcp-optsdir and hostsdir are not supported on this platform"
+msgstr "dhcp-hostsdir, dhcp-optsdir und hostsdir sind auf dieser Plattform nicht unterstüzt"
+
+#: dnsmasq.c:181
+msgid "no root trust anchor provided for DNSSEC"
+msgstr "Keine Root-Vertrauensursprünge (Root Trust Anchor) für DNSSEC verfügbar"
+
+#: dnsmasq.c:184
+msgid "cannot reduce cache size from default when DNSSEC enabled"
+msgstr "Kann die Standard Cachegröße nicht verkleinern, wenn DNSSEC aktiviert ist"
+
+#: dnsmasq.c:186
+msgid "DNSSEC not available: set HAVE_DNSSEC in src/config.h"
+msgstr "DNSSEC nicht verfügbar: setzen Sie HAVE_DNSSEC in src/config.h"
+
+#: dnsmasq.c:192
+msgid "TFTP server not available: set HAVE_TFTP in src/config.h"
+msgstr "TFTP-Server nicht verfügbar, setzen Sie HAVE_TFTP in src/config.h"
+
+#: dnsmasq.c:197
+msgid "cannot use --conntrack AND --query-port"
+msgstr "Kann nicht --conntrack UND --query-port einsetzen"
+
+#: dnsmasq.c:200
+msgid "conntrack support not available: set HAVE_CONNTRACK in src/config.h"
+msgstr "Conntrack-Unterstützung nicht verfügbar: Aktiviere HAVE_CONNTRACK in src/config.h"
+
+#: dnsmasq.c:205
+msgid "asynchronous logging is not available under Solaris"
+msgstr "asynchrone Protokollierung unter Solaris nicht verfügbar"
+
+#: dnsmasq.c:210
+msgid "asynchronous logging is not available under Android"
+msgstr "Asynchrone Protokollierung unter Android nicht verfügbar"
+
+#: dnsmasq.c:215
+msgid "authoritative DNS not available: set HAVE_AUTH in src/config.h"
+msgstr "Authoritatives DNS nicht verfügbar: Es muss HAVE_AUTH in src/config.h gesetzt sein"
+
+#: dnsmasq.c:220
+msgid "loop detection not available: set HAVE_LOOP in src/config.h"
+msgstr "Loop-Erkennung nicht verfügbar, Aktiviere HAVE_LOOP in src/config.h"
+
+#: dnsmasq.c:227
+msgid "max_port cannot be smaller than min_port"
+msgstr "max_port darf nicht kleiner als min_port sein"
+
+#: dnsmasq.c:234
+msgid "zone serial must be configured in --auth-soa"
+msgstr "Zonen Seriennummer muss mit --auth-soa konfiguriert werden"
+
+#: dnsmasq.c:252
+msgid "dhcp-range constructor not available on this platform"
+msgstr "dhcp-range Konstruktor ist auf dieser Plattform nicht verfübar"
+
+#: dnsmasq.c:298
+msgid "cannot set --bind-interfaces and --bind-dynamic"
+msgstr "Kann nicht --bind-interfaces und --bind-dynamic setzen"
+
+#: dnsmasq.c:301
+#, c-format
+msgid "failed to find list of interfaces: %s"
+msgstr "konnte Schnitstellenliste nicht beziehen: %s"
+
+#: dnsmasq.c:310
+#, c-format
+msgid "unknown interface %s"
+msgstr "unbekannte Schnittstelle %s"
+
+#: dnsmasq.c:374 dnsmasq.c:1037
+#, c-format
+msgid "DBus error: %s"
+msgstr "DBus-Fehler: %s"
+
+#: dnsmasq.c:377
+msgid "DBus not available: set HAVE_DBUS in src/config.h"
+msgstr "DBus nicht verfügbar: setzen Sie HAVE_DBUS in src/config.h"
+
+#: dnsmasq.c:405
+#, c-format
+msgid "unknown user or group: %s"
+msgstr "Unbekannter Benutzer oder Gruppe: %s"
+
+#: dnsmasq.c:460
+#, c-format
+msgid "cannot chdir to filesystem root: %s"
+msgstr "kann nicht ins Wurzelverzeichnis des Dateisystems wechseln: %s"
+
+# FIXME: this and the next would need commas after the version
+#: dnsmasq.c:716
+#, c-format
+msgid "started, version %s DNS disabled"
+msgstr "gestartet, Version %s, DNS abgeschaltet"
+
+#: dnsmasq.c:720
+#, c-format
+msgid "started, version %s cachesize %d"
+msgstr "gestartet, Version %s, Cachegröße %d"
+
+#: dnsmasq.c:722
+#, c-format
+msgid "started, version %s cache disabled"
+msgstr "Gestartet, Version %s Cache deaktiviert"
+
+#: dnsmasq.c:725
+msgid "DNS service limited to local subnets"
+msgstr "DNS-Dienst auf lokale Subnetze eingeschränkt"
+
+#: dnsmasq.c:728
+#, c-format
+msgid "compile time options: %s"
+msgstr "Übersetzungsoptionen: %s"
+
+#: dnsmasq.c:734
+msgid "DBus support enabled: connected to system bus"
+msgstr "DBus-Unterstützung eingeschaltet: mit Systembus verbunden"
+
+#: dnsmasq.c:736
+msgid "DBus support enabled: bus connection pending"
+msgstr "DBus-Unterstützung eingeschaltet: warte auf Systembus-Verbindung"
+
+#: dnsmasq.c:754
+msgid "DNSSEC validation enabled"
+msgstr "DNSSEC-Validierung aktiviert"
+
+#: dnsmasq.c:758
+msgid "DNSSEC signature timestamps not checked until first cache reload"
+msgstr "DNSSEC Signatur-Zeitstempel werden erst ab dem ersten Neuladen des Caches überprüft"
+
+#: dnsmasq.c:761
+msgid "DNSSEC signature timestamps not checked until system time valid"
+msgstr "DNSSEC Signatur-Zeitstempel werden erst überprüft, sobald die Systemuhrzeit gültig ist"
+
+#: dnsmasq.c:766
+#, c-format
+msgid "warning: failed to change owner of %s: %s"
+msgstr "Warnung: konnte den Besitzer von %s nicht ändern: %s"
+
+#: dnsmasq.c:770
+msgid "setting --bind-interfaces option because of OS limitations"
+msgstr "Aktiviere --bind-interfaces wegen Einschränkungen des Betriebssystems"
+
+#: dnsmasq.c:782
+#, c-format
+msgid "warning: interface %s does not currently exist"
+msgstr "Warnung: Schnittstelle %s existiert derzeit nicht"
+
+#: dnsmasq.c:787
+msgid "warning: ignoring resolv-file flag because no-resolv is set"
+msgstr "Warnung: Ignoriere \"resolv-file\", weil \"no-resolv\" aktiv ist"
+
+#: dnsmasq.c:790
+msgid "warning: no upstream servers configured"
+msgstr "Warnung: keine vorgelagerten (Upstream) Server konfiguriert"
+
+#: dnsmasq.c:794
+#, c-format
+msgid "asynchronous logging enabled, queue limit is %d messages"
+msgstr "asynchrone Protokollierung eingeschaltet, Warteschlange fasst %d Nachrichten"
+
+#: dnsmasq.c:815
+msgid "IPv6 router advertisement enabled"
+msgstr "IPv6-Router-Advertisement aktiviert"
+
+#: dnsmasq.c:820
+#, c-format
+msgid "DHCP, sockets bound exclusively to interface %s"
+msgstr "DHCP, Sockets exklusiv an das Interface %s gebunden"
+
+# FIXME: this and the next few must be full strings to be translatable - do not assemble in code"
+#: dnsmasq.c:834
+msgid "root is "
+msgstr "Wurzel ist "
+
+#: dnsmasq.c:834
+msgid "enabled"
+msgstr "Aktiviert"
+
+#: dnsmasq.c:836
+msgid "secure mode"
+msgstr "sicherer Modus"
+
+#: dnsmasq.c:839
+#, c-format
+msgid "warning: %s inaccessible"
+msgstr "Warnung: %s nicht zugreifbar"
+
+#: dnsmasq.c:843
+#, c-format
+msgid "warning: TFTP directory %s inaccessible"
+msgstr "Warnung: Das TFTP-Verzeichnis %s ist nicht zugreifbar"
+
+#: dnsmasq.c:869
+#, c-format
+msgid "restricting maximum simultaneous TFTP transfers to %d"
+msgstr "Begrenze gleichzeitige TFTP-Übertragungen auf maximal %d"
+
+#: dnsmasq.c:1039
+msgid "connected to system DBus"
+msgstr "Mit System-DBus verbunden"
+
+#: dnsmasq.c:1189
+#, c-format
+msgid "cannot fork into background: %s"
+msgstr "kann nicht in den Hintergrund abspalten: %s"
+
+#: dnsmasq.c:1192
+#, c-format
+msgid "failed to create helper: %s"
+msgstr "kann Helfer nicht erzeugen: %s"
+
+#: dnsmasq.c:1195
+#, c-format
+msgid "setting capabilities failed: %s"
+msgstr "kann \"capabilities\" nicht setzen: %s"
+
+#: dnsmasq.c:1198
+#, c-format
+msgid "failed to change user-id to %s: %s"
+msgstr "Kann nicht Benutzerrechte %s annehmen: %s"
+
+#: dnsmasq.c:1201
+#, c-format
+msgid "failed to change group-id to %s: %s"
+msgstr "Kann nicht Gruppenrechte %s annehmen: %s"
+
+#: dnsmasq.c:1204
+#, c-format
+msgid "failed to open pidfile %s: %s"
+msgstr "kann die Prozessidentifikations-(PID)-Datei %s nicht öffnen: %s"
+
+#: dnsmasq.c:1207
+#, c-format
+msgid "cannot open log %s: %s"
+msgstr "Kann Logdatei %s nicht öffnen: %s"
+
+#: dnsmasq.c:1210
+#, c-format
+msgid "failed to load Lua script: %s"
+msgstr "Konnte Lua-Script nicht laden: %s"
+
+#: dnsmasq.c:1213
+#, c-format
+msgid "TFTP directory %s inaccessible: %s"
+msgstr "Das TFTP-Verzeichnis %s ist nicht zugreifbar: %s"
+
+#: dnsmasq.c:1216
+#, c-format
+msgid "cannot create timestamp file %s: %s"
+msgstr "Kann keine timestamp-Datei %s erzeugen: %s "
+
+#: dnsmasq.c:1239
+msgid "now checking DNSSEC signature timestamps"
+msgstr "Prüfe jetzt DNSSEC Signatur-Zeitstempel"
+
+#: dnsmasq.c:1307
+#, c-format
+msgid "script process killed by signal %d"
+msgstr "Scriptprozess durch Signal %d getötet"
+
+#: dnsmasq.c:1311
+#, c-format
+msgid "script process exited with status %d"
+msgstr "Scriptprozess hat sich mit Status %d beendet"
+
+#: dnsmasq.c:1315
+#, c-format
+msgid "failed to execute %s: %s"
+msgstr "konnte %s nicht ausführen: %s"
+
+#: dnsmasq.c:1379 dnssec.c:479 dnssec.c:525
+#, c-format
+msgid "failed to update mtime on %s: %s"
+msgstr "kann die mtime nicht auf %s aktualisieren: %s"
+
+#: dnsmasq.c:1386
+msgid "exiting on receipt of SIGTERM"
+msgstr "beende nach Empfang von SIGTERM"
+
+#: dnsmasq.c:1414
+#, c-format
+msgid "failed to access %s: %s"
+msgstr "konnte auf %s nicht zugreifen: %s"
+
+#: dnsmasq.c:1444
+#, c-format
+msgid "reading %s"
+msgstr "lese %s"
+
+#: dnsmasq.c:1455
+#, c-format
+msgid "no servers found in %s, will retry"
+msgstr "keine Server in %s gefunden, werde es später neu versuchen"
+
+#: dhcp.c:53
+#, c-format
+msgid "cannot create DHCP socket: %s"
+msgstr "kann DHCP-Socket nicht erzeugen: %s"
+
+#: dhcp.c:68
+#, c-format
+msgid "failed to set options on DHCP socket: %s"
+msgstr "kann Optionen für DHCP-Socket nicht setzen: %s"
+
+#: dhcp.c:89
+#, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"
+msgstr "kann SO_REUSE{ADDR|PORT} für DHCP-Socket nicht aktivieren: %s"
+
+#: dhcp.c:101
+#, c-format
+msgid "failed to bind DHCP server socket: %s"
+msgstr "kann nicht an DHCP-Server-Socket binden: %s"
+
+#: dhcp.c:127
+#, c-format
+msgid "cannot create ICMP raw socket: %s."
+msgstr "kann ICMP-Rohdaten-Socket nicht erzeugen: %s."
+
+#: dhcp.c:252 dhcp6.c:173
+#, c-format
+msgid "unknown interface %s in bridge-interface"
+msgstr "unbekannte Schnittstelle %s in bridge-interface"
+
+#: dhcp.c:293
+#, c-format
+msgid "DHCP packet received on %s which has no address"
+msgstr "DHCP-Paket ohne Adresse an Schnittstelle %s empfangen"
+
+#: dhcp.c:427
+#, c-format
+msgid "ARP-cache injection failed: %s"
+msgstr "APR-Cache Injektion fehlgeschlagen: %s"
+
+#: dhcp.c:470
+#, c-format
+msgid "Error sending DHCP packet to %s: %s"
+msgstr "Fehler beim Senden des DHCP-Pakets an %s: %s"
+
+#: dhcp.c:531
+#, c-format
+msgid "DHCP range %s -- %s is not consistent with netmask %s"
+msgstr "DHCP-Bereich %s - %s passt nicht zur Netzmaske %s"
+
+#: dhcp.c:854
+#, c-format
+msgid "bad line at %s line %d"
+msgstr "ungültige Zeile %2$d in Datei %1$s"
+
+#: dhcp.c:897
+#, c-format
+msgid "ignoring %s line %d, duplicate name or IP address"
+msgstr "ignoriere %s Zeile %d, doppelter Name oder doppelte IP-Adresse"
+
+#: dhcp.c:1041 rfc3315.c:2149
+#, c-format
+msgid "DHCP relay %s -> %s"
+msgstr "DHCP Weiterleitung %s -> %s"
+
+#: lease.c:98
+msgid "too many stored leases"
+msgstr "zu viele Leases gespeichert"
+
+#: lease.c:166
+#, c-format
+msgid "cannot open or create lease file %s: %s"
+msgstr "kann Lease-Datei %s nicht öffnen: %s"
+
+#: lease.c:175
+#, c-format
+msgid "failed to parse lease database, invalid line: %s %s %s %s ..."
+msgstr ""
+
+#: lease.c:180
+#, fuzzy, c-format
+msgid "failed to read lease file %s: %s"
+msgstr "konnte %s nicht lesen: %s"
+
+#: lease.c:196
+#, c-format
+msgid "cannot run lease-init script %s: %s"
+msgstr "kann Lease-Start-Skript %s nicht ausführen: %s"
+
+#: lease.c:202
+#, c-format
+msgid "lease-init script returned exit code %s"
+msgstr "Lease-Start-Skript beendete sich mit Code %s"
+
+# FIXME: This should be %u s also in English according to NIST and SI rules. -- MA
+#: lease.c:373
+#, c-format
+msgid "failed to write %s: %s (retry in %us)"
+msgstr "Konnte %s nicht schreiben: %s (Neuversuch in %u s)"
+
+#: lease.c:937
+#, c-format
+msgid "Ignoring domain %s for DHCP host name %s"
+msgstr "Ignoriere Domäne %s für DHCP-Hostnamen %s"
+
+# FIXME: this and the next few are not translatable. Please provide full
+# strings, do not programmatically assemble them.
+#: rfc2131.c:347
+#, c-format
+msgid "no address range available for DHCP request %s %s"
+msgstr "Kein verfügbarer DHCP-Bereich für Anfrage %s %s"
+
+#: rfc2131.c:348
+msgid "with subnet selector"
+msgstr "mit Subnetz-Wähler"
+
+#: rfc2131.c:348
+msgid "via"
+msgstr "via"
+
+#: rfc2131.c:360
+#, c-format
+msgid "%u available DHCP subnet: %s/%s"
+msgstr "%u verfügbare(s) DHCP-Subnetz: %s/%s"
+
+#: rfc2131.c:363 rfc3315.c:306
+#, c-format
+msgid "%u available DHCP range: %s -- %s"
+msgstr "%u verfügbare(r) DHCP-Bereich: %s - %s"
+
+#: rfc2131.c:474
+#, c-format
+msgid "%u vendor class: %s"
+msgstr "%u \"Vendor class\": %s"
+
+#: rfc2131.c:476
+#, c-format
+msgid "%u user class: %s"
+msgstr "%u Benutzerklasse: %s"
+
+# FIXME: do not programmatically assemble strings - untranslatable
+#: rfc2131.c:510
+msgid "disabled"
+msgstr "deaktiviert"
+
+#: rfc2131.c:551 rfc2131.c:1006 rfc2131.c:1430 rfc3315.c:616 rfc3315.c:869
+#: rfc3315.c:1148
+msgid "ignored"
+msgstr "ignoriert"
+
+#: rfc2131.c:566 rfc2131.c:1239 rfc3315.c:919
+msgid "address in use"
+msgstr "Adresse in Nutzung"
+
+#: rfc2131.c:580 rfc2131.c:1060
+msgid "no address available"
+msgstr "Keine Adresse verfügbar"
+
+#: rfc2131.c:587 rfc2131.c:1202
+msgid "wrong network"
+msgstr "Falsches Netzwerk"
+
+#: rfc2131.c:602
+msgid "no address configured"
+msgstr "Keine Adresse konfiguriert"
+
+#: rfc2131.c:608 rfc2131.c:1252
+msgid "no leases left"
+msgstr "Keine Leases übrig"
+
+#: rfc2131.c:703 rfc3315.c:482
+#, c-format
+msgid "%u client provides name: %s"
+msgstr "%u Klient stellt Name bereit: %s"
+
+#: rfc2131.c:808
+msgid "PXE BIS not supported"
+msgstr "PXE BIS nicht unterstützt"
+
+#: rfc2131.c:974 rfc3315.c:1242
+#, c-format
+msgid "disabling DHCP static address %s for %s"
+msgstr "schalte statische DHCP-Adresse %s für %s ab"
+
+# FIXME: do not assemble
+#: rfc2131.c:995
+msgid "unknown lease"
+msgstr "Unbekannter Lease"
+
+#: rfc2131.c:1029
+#, c-format
+msgid "not using configured address %s because it is leased to %s"
+msgstr "benutze konfigurierte Adresse %s nicht, weil sie an %s verleast ist"
+
+#: rfc2131.c:1039
+#, c-format
+msgid "not using configured address %s because it is in use by the server or relay"
+msgstr "benutze konfigurierte Adresse %s nicht, weil sie von Server/Relais verwendet wird"
+
+#: rfc2131.c:1042
+#, c-format
+msgid "not using configured address %s because it was previously declined"
+msgstr "benutze konfigurierte Adresse %s nicht, weil sie zuvor abgelehnt wurde"
+
+# FIXME: do not assemble
+#: rfc2131.c:1058 rfc2131.c:1245
+msgid "no unique-id"
+msgstr "Keine eindeutige ID"
+
+#: rfc2131.c:1140
+msgid "wrong server-ID"
+msgstr "Falsche Server-ID"
+
+#: rfc2131.c:1159
+msgid "wrong address"
+msgstr "Falsche Adresse"
+
+#: rfc2131.c:1177 rfc3315.c:1015
+msgid "lease not found"
+msgstr "Lease nicht gefunden"
+
+#: rfc2131.c:1210
+msgid "address not available"
+msgstr "Adresse nicht verfügbar"
+
+#: rfc2131.c:1221
+msgid "static lease available"
+msgstr "Statischer Lease verfügbar"
+
+#: rfc2131.c:1225
+msgid "address reserved"
+msgstr "Adresse reserviert"
+
+#: rfc2131.c:1233
+#, c-format
+msgid "abandoning lease to %s of %s"
+msgstr "Gebe Lease von %2$s an %1$s auf"
+
+#: rfc2131.c:1757
+#, c-format
+msgid "%u bootfile name: %s"
+msgstr "%u Name der Bootdatei: %s"
+
+#: rfc2131.c:1766
+#, c-format
+msgid "%u server name: %s"
+msgstr "%u Servername: %s"
+
+#: rfc2131.c:1774
+#, c-format
+msgid "%u next server: %s"
+msgstr "%u nächster Server: %s"
+
+#: rfc2131.c:1777
+#, c-format
+msgid "%u broadcast response"
+msgstr "%u Antwort per Rundsendung"
+
+#: rfc2131.c:1840
+#, c-format
+msgid "cannot send DHCP/BOOTP option %d: no space left in packet"
+msgstr "kann DHCP/BOOTP-Opition %d nicht setzen: kein Platz mehr im Paket"
+
+#: rfc2131.c:2131
+msgid "PXE menu too large"
+msgstr "PXE-Menüeintrag zu groß"
+
+#: rfc2131.c:2270 rfc3315.c:1515
+#, c-format
+msgid "%u requested options: %s"
+msgstr "%u angeforderte Optionen: %s"
+
+#: rfc2131.c:2587
+#, c-format
+msgid "cannot send RFC3925 option: too many options for enterprise number %d"
+msgstr "Kann RFC3925-Option nicht senden: zu viele Optionen für Unternehmen Nr. %d"
+
+#: rfc2131.c:2650
+#, c-format
+msgid "%u reply delay: %d"
+msgstr ""
+
+#: netlink.c:77
+#, c-format
+msgid "cannot create netlink socket: %s"
+msgstr "kann Netlink-Socket nicht erzeugen: %s"
+
+#: netlink.c:355
+#, c-format
+msgid "netlink returns error: %s"
+msgstr "Netlink liefert Fehler %s"
+
+#: dbus.c:186
+msgid "attempt to set an IPv6 server address via DBus - no IPv6 support"
+msgstr "Versuch, via DBus eine IPv6-Serveradresse zu setzen: keine IPv6-Unterstützung"
+
+#: dbus.c:439
+#, c-format
+msgid "Enabling --%s option from D-Bus"
+msgstr "Aktiviere --%s Option von D-Bus"
+
+#: dbus.c:444
+#, c-format
+msgid "Disabling --%s option from D-Bus"
+msgstr "Deaktiviere --%s Option von D-Bus"
+
+#: dbus.c:690
+msgid "setting upstream servers from DBus"
+msgstr "vorgelagerte Server von DBus gesetzt"
+
+#: dbus.c:737
+msgid "could not register a DBus message handler"
+msgstr "konnte Steuerungsprogramm für DBus-Nachrichten nicht anmelden"
+
+#: bpf.c:265
+#, c-format
+msgid "cannot create DHCP BPF socket: %s"
+msgstr "konnte DHCP-BPF-Socket nicht einrichten: %s"
+
+#: bpf.c:293
+#, c-format
+msgid "DHCP request for unsupported hardware type (%d) received on %s"
+msgstr "DHCP-Anfrage für nicht unterstützen Hardwaretyp (%d) auf %s empfangen"
+
+#: bpf.c:378
+#, c-format
+msgid "cannot create PF_ROUTE socket: %s"
+msgstr "Kann PF_ROUTE socket nicht erzeugen: %s"
+
+#: bpf.c:399
+msgid "Unknown protocol version from route socket"
+msgstr "Unbekannte Protokollversion vom Route Socket"
+
+#: helper.c:153
+msgid "lease() function missing in Lua script"
+msgstr "Die Funktion lease() fehlt im Lua-Script"
+
+#: tftp.c:319
+msgid "unable to get free port for TFTP"
+msgstr "konnte keinen freien Port für TFTP bekommen"
+
+#: tftp.c:335
+#, c-format
+msgid "unsupported request from %s"
+msgstr "nicht unterstützte Anfrage von %s"
+
+#: tftp.c:483
+#, c-format
+msgid "file %s not found"
+msgstr "Datei %s nicht gefunden"
+
+#: tftp.c:592
+#, c-format
+msgid "error %d %s received from %s"
+msgstr "Fehler %d %s von %s empfangen"
+
+#: tftp.c:634
+#, c-format
+msgid "failed sending %s to %s"
+msgstr "konnte %s nicht an %s senden"
+
+#: tftp.c:634
+#, c-format
+msgid "sent %s to %s"
+msgstr "%s an %s verschickt"
+
+#: log.c:190
+#, c-format
+msgid "overflow: %d log entries lost"
+msgstr "Überlauf: %d Protokolleinträge verloren"
+
+#: log.c:268
+#, c-format
+msgid "log failed: %s"
+msgstr "Protokollierung fehlgeschlagen: %s"
+
+#: log.c:471
+msgid "FAILED to start up"
+msgstr "Start fehlgeschlagen"
+
+#: conntrack.c:65
+#, c-format
+msgid "Conntrack connection mark retrieval failed: %s"
+msgstr "\"Conntrack connection mark\"-Abruf fehlgeschlagen: %s"
+
+#: dhcp6.c:52
+#, c-format
+msgid "cannot create DHCPv6 socket: %s"
+msgstr "Kann DHCPv6-Socket nicht erzeugen: %s"
+
+#: dhcp6.c:73
+#, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"
+msgstr "kann SO_REUSE{ADDR|PORT} für DHCPv6-Socket nicht aktivieren: %s"
+
+#: dhcp6.c:85
+#, c-format
+msgid "failed to bind DHCPv6 server socket: %s"
+msgstr "Kann nicht an DHCPv6-Server-Socket binden: %s"
+
+#: rfc3315.c:157
+#, c-format
+msgid "no address range available for DHCPv6 request from relay at %s"
+msgstr "Kein Adressbereich verfügbar für die DHCPv6-Anfrage vom Relay bei %s"
+
+#: rfc3315.c:166
+#, c-format
+msgid "no address range available for DHCPv6 request via %s"
+msgstr "Kein Adressbereich verfügbar für die DHCPv6-Anfrage via %s"
+
+#: rfc3315.c:303
+#, c-format
+msgid "%u available DHCPv6 subnet: %s/%d"
+msgstr "%u verfügbare(s) DHCPv6-Subnetz: %s/%d"
+
+#: rfc3315.c:386
+#, c-format
+msgid "%u vendor class: %u"
+msgstr "%u Herstellerklasse: %u"
+
+#: rfc3315.c:434
+#, c-format
+msgid "%u client MAC address: %s"
+msgstr "%u Klient MAC-Adresse: %s"
+
+# FIXME: do not assemble
+#: rfc3315.c:673
+#, c-format
+msgid "unknown prefix-class %d"
+msgstr "unbekannte Präfixklasse %d"
+
+#: rfc3315.c:816 rfc3315.c:911
+msgid "address unavailable"
+msgstr "Adresse nicht verfügbar"
+
+#: rfc3315.c:828 rfc3315.c:959 rfc3315.c:1292
+msgid "success"
+msgstr "Erfolg"
+
+#: rfc3315.c:843 rfc3315.c:852 rfc3315.c:967 rfc3315.c:969
+msgid "no addresses available"
+msgstr "Keine Adressen verfügbar"
+
+#: rfc3315.c:946
+msgid "not on link"
+msgstr "nicht on link"
+
+#: rfc3315.c:1019 rfc3315.c:1204 rfc3315.c:1281
+msgid "no binding found"
+msgstr "Keine Bindung gefunden"
+
+#: rfc3315.c:1057
+msgid "deprecated"
+msgstr "veraltet"
+
+#: rfc3315.c:1062
+msgid "address invalid"
+msgstr "Adresse ungültig"
+
+#: rfc3315.c:1109
+msgid "confirm failed"
+msgstr "Bestätigung fehlgeschlagen"
+
+#: rfc3315.c:1125
+msgid "all addresses still on link"
+msgstr "Alle Adressen immer noch on link"
+
+#: rfc3315.c:1213
+msgid "release received"
+msgstr "Freigabe empfangen"
+
+#: rfc3315.c:2140
+msgid "Cannot multicast to DHCPv6 server without correct interface"
+msgstr "Kann nicht zum DHCPv6 Server multicasten ohne korrekte Schnittstelle"
+
+#: dhcp-common.c:145
+#, c-format
+msgid "Ignoring duplicate dhcp-option %d"
+msgstr "Ignoriere doppelt vorhandene DHCP-Option %d"
+
+#: dhcp-common.c:222
+#, c-format
+msgid "%u tags: %s"
+msgstr "%u Marken: %s"
+
+#: dhcp-common.c:407
+#, c-format
+msgid "%s has more than one address in hostsfile, using %s for DHCP"
+msgstr "%s hat mehr als eine Adresse in hosts-Datei, benutze %s für DHCP"
+
+#: dhcp-common.c:430
+#, c-format
+msgid "duplicate IP address %s (%s) in dhcp-config directive"
+msgstr "doppelte IP-Adresse %s (%s) in \"dhcp-config\"-Anweisung"
+
+#: dhcp-common.c:494
+#, c-format
+msgid "failed to set SO_BINDTODEVICE on DHCP socket: %s"
+msgstr "kann SO_BINDTODEVICE für DHCP-Socket nicht aktivieren: %s"
+
+#: dhcp-common.c:615
+#, c-format
+msgid "Known DHCP options:\n"
+msgstr "Bekannte DHCP-Optionen:\n"
+
+#: dhcp-common.c:626
+#, c-format
+msgid "Known DHCPv6 options:\n"
+msgstr "Bekannte DHCPv6-Optionen:\n"
+
+#: dhcp-common.c:823
+msgid ", prefix deprecated"
+msgstr ", Prefix veraltet"
+
+#: dhcp-common.c:826
+#, c-format
+msgid ", lease time "
+msgstr ", Lease Zeit"
+
+#: dhcp-common.c:868
+#, c-format
+msgid "%s stateless on %s%.0s%.0s%s"
+msgstr "%s stateless auf %s%.0s%.0s%s"
+
+#: dhcp-common.c:870
+#, c-format
+msgid "%s, static leases only on %.0s%s%s%.0s"
+msgstr "%s, nur statische Leases auf %.0s%s%s%.0s"
+
+#: dhcp-common.c:872
+#, c-format
+msgid "%s, proxy on subnet %.0s%s%.0s%.0s"
+msgstr "%s, Proxy im Subnetz %.0s%s%.0s%.0s"
+
+#: dhcp-common.c:873
+#, c-format
+msgid "%s, IP range %s -- %s%s%.0s"
+msgstr "%s, IP-Bereich %s -- %s%s%.0s"
+
+#: dhcp-common.c:886
+#, c-format
+msgid "DHCPv4-derived IPv6 names on %s%s"
+msgstr "DHCPv4-abgeleitete IPv6 Namen auf %s%s"
+
+#: dhcp-common.c:889
+#, c-format
+msgid "router advertisement on %s%s"
+msgstr "Router-Advertisment auf %s%s"
+
+#: dhcp-common.c:900
+#, c-format
+msgid "DHCP relay from %s to %s via %s"
+msgstr "DHCP Weiterleitung von %s nach %s über %s"
+
+#: dhcp-common.c:902
+#, c-format
+msgid "DHCP relay from %s to %s"
+msgstr "DHCP Weiterleitung von %s nach %s"
+
+#: radv.c:110
+#, c-format
+msgid "cannot create ICMPv6 socket: %s"
+msgstr "Kann ICMPv6-Socket nicht erzeugen: %s"
+
+#: auth.c:449
+#, c-format
+msgid "ignoring zone transfer request from %s"
+msgstr "ignoriere Zonentransfer-Anfrage von %s"
+
+#: ipset.c:95
+#, c-format
+msgid "failed to find kernel version: %s"
+msgstr "konnte Kernelversion nicht finden: %s"
+
+#: ipset.c:114
+#, c-format
+msgid "failed to create IPset control socket: %s"
+msgstr "konnte IPset-Kontroll-Socket nicht erzeugen: %s"
+
+#: ipset.c:233
+#, fuzzy, c-format
+msgid "failed to update ipset %s: %s"
+msgstr "kann die mtime nicht auf %s aktualisieren: %s"
+
+#: dnssec.c:527
+#, fuzzy
+msgid "system time considered valid, now checking DNSSEC signature timestamps."
+msgstr "Prüfe jetzt DNSSEC Signatur-Zeitstempel"
+
+#: blockdata.c:58
+#, c-format
+msgid "DNSSEC memory in use %u, max %u, allocated %u"
+msgstr "DNSSEC Speicher in Benutzung %u, Max %u, zugewiesen %u"
+
+#: tables.c:61
+#, c-format
+msgid "failed to access pf devices: %s"
+msgstr "konnte auf pf Geräte nicht zugreifen: %s"
+
+#: tables.c:74
+#, c-format
+msgid "warning: no opened pf devices %s"
+msgstr "Warnung: Keine geöffneten pf Geräte %s"
+
+#: tables.c:82
+#, c-format
+msgid "error: cannot use table name %s"
+msgstr "Fehler: Kann Tabellenname %s nicht benutzen"
+
+#: tables.c:90
+#, c-format
+msgid "error: cannot strlcpy table name %s"
+msgstr "Fehler: Kann den Tabellennamen %s nicht strlcpy"
+
+#: tables.c:101
+#, fuzzy, c-format
+msgid "IPset: error:%s"
+msgstr "DBus-Fehler: %s"
+
+#: tables.c:108
+msgid "info: table created"
+msgstr "Info: Tabelle erstellt"
+
+#: tables.c:134
+#, c-format
+msgid "warning: DIOCR%sADDRS: %s"
+msgstr "Warnung: DIOCR%sADDRS: %s"
+
+#: tables.c:138
+#, c-format
+msgid "%d addresses %s"
+msgstr "%d Adressen %s"
+
+#: inotify.c:62
+#, c-format
+msgid "cannot access path %s: %s"
+msgstr "Kann auf Pfad %s nicht zugreifen: %s"
+
+#: inotify.c:95
+#, c-format
+msgid "failed to create inotify: %s"
+msgstr "Kann kein inotify erzeugen: %s"
+
+#: inotify.c:111
+#, c-format
+msgid "too many symlinks following %s"
+msgstr "Zu viele nachfolgende symbolische Links folgend %s"
+
+#: inotify.c:127
+#, c-format
+msgid "directory %s for resolv-file is missing, cannot poll"
+msgstr "Verzeichnis %s für resolv-file fehlt, kann nicht pollen"
+
+#: inotify.c:131 inotify.c:168
+#, c-format
+msgid "failed to create inotify for %s: %s"
+msgstr "Konnte inotify für %s: %s nicht erzeugen"
+
+#: inotify.c:153
+#, c-format
+msgid "bad dynamic directory %s: %s"
+msgstr "fehlerhaftes dynamisches Verzeichnis %s: %s"
+
+#: inotify.c:255
+#, c-format
+msgid "inotify, new or changed file %s"
+msgstr "inotify, neue oder geänderte Datei %s"
+
+#~ msgid "bad TTL"
+#~ msgstr "unzulässige TTL"
+
+#~ msgid "error: fill_addr missused"
+#~ msgstr "Fehler: fill_addr falsch verwendet"
+
+#~ msgid "warning: pfr_add_tables: %s(%d)"
+#~ msgstr "Warnung: pfr_add_tables: %s(%d)"
+
+#~ msgid "cannot cannonicalise resolv-file %s: %s"
+#~ msgstr "Kann die resolv-file %s nicht kanonisieren: %s"
+
+#~ msgid "no interface with address %s"
+#~ msgstr "keine Schnittstelle mit Adresse %s"
+
+#~ msgid "duplicate IP address %s in dhcp-config directive."
+#~ msgstr "doppelte IP-Adresse %s in \"dhcp-config\"-Anweisung"
+
+#, fuzzy
+#~ msgid "Specify path to Lua script (no default)."
+#~ msgstr "Dateipfad für Prozesskennung (PID) festlegen (Voreinstellung: %s)."
+
+#~ msgid "only one dhcp-hostsfile allowed"
+#~ msgstr "nur eine DHCP-Hostdatei (dhcp-hostsfile) zulässig"
+
+#~ msgid "only one dhcp-optsfile allowed"
+#~ msgstr "nur eine DHCP-Optionsdatei (dhcp-optsfile) zulässig"
+
+#~ msgid "files nested too deep in %s"
+#~ msgstr "Dateien in %s zu tief verschachtelt"
+
+#~ msgid "TXT record string too long"
+#~ msgstr "TXT-Eintrag zu lang"
+
+#~ msgid "failed to set IPV6 options on listening socket: %s"
+#~ msgstr "konnte IPV6-Optionen auf Empfangs-Socket nicht einstellen: %s"
+
+#~ msgid "failed to bind listening socket for %s: %s"
+#~ msgstr "konnte Empfangs-Socket nicht an %s binden: %s"
diff --git a/po/es.po b/po/es.po
new file mode 100755
index 0000000..0b30d98
--- /dev/null
+++ b/po/es.po
@@ -0,0 +1,2390 @@
+# Spanish translations for dnsmasq package.
+# This file is put in the public domain.
+# Christopher Chatham <chrislinux@gmail.com>, 2005.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: dnsmasq 2.67\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-06-18 12:24+0100\n"
+"PO-Revision-Date: 2017-07-17 18:30+0100\n"
+"Last-Translator: Vicente Soriano <victek@gmail.com>\n"
+"Language-Team:\n"
+"Language: es\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: cache.c:513
+msgid "Internal error in cache."
+msgstr ""
+
+#: cache.c:923
+#, fuzzy, c-format
+msgid "failed to load names from %s: %s"
+msgstr "no se pudo cargar nombres desde %s: %s"
+
+#: cache.c:949 dhcp.c:867
+#, fuzzy, c-format
+msgid "bad address at %s line %d"
+msgstr "dirección errónea en %s línea %d"
+
+#: cache.c:1002 dhcp.c:883
+#, c-format
+msgid "bad name at %s line %d"
+msgstr "nombre erróneo en %s línea %d"
+
+#: cache.c:1011 dhcp.c:958
+#, c-format
+msgid "read %s - %d addresses"
+msgstr "direcciónes %s - %d leídas"
+
+#: cache.c:1124
+msgid "cleared cache"
+msgstr "el caché fue liberado"
+
+#: cache.c:1153
+#, c-format
+msgid "No IPv4 address found for %s"
+msgstr ""
+
+#: cache.c:1232
+#, c-format
+msgid "%s is a CNAME, not giving it to the DHCP lease of %s"
+msgstr "%s es un CNAME, no se le está dando concesión DHCP de %s"
+
+#: cache.c:1256
+#, c-format
+msgid "not giving name %s to the DHCP lease of %s because the name exists in %s with address %s"
+msgstr "no otorgando nombre %s a concesión DHCP de %s porque el nombre existe en %s con dirección %s"
+
+#: cache.c:1413
+#, c-format
+msgid "time %lu"
+msgstr "tiempo %lu"
+
+#: cache.c:1414
+#, fuzzy, c-format
+msgid "cache size %d, %d/%d cache insertions re-used unexpired cache entries."
+msgstr "tamaño de caché %d, %d/%d inserciónes de caché reutilizaron objetos no vencidos."
+
+#: cache.c:1416
+#, c-format
+msgid "queries forwarded %u, queries answered locally %u"
+msgstr "búsquedas reenviadas %u, búsquedas respondidas localmente %u"
+
+#: cache.c:1419
+#, fuzzy, c-format
+msgid "queries for authoritative zones %u"
+msgstr "Fijar TTL para respuestas autoritarias"
+
+#: cache.c:1445
+#, c-format
+msgid "server %s#%d: queries sent %u, retried or failed %u"
+msgstr "servidor %s#%d: búsquedas enviadas %u, reintentadas o fallidas %u"
+
+#: util.c:47
+#, fuzzy, c-format
+msgid "failed to seed the random number generator: %s"
+msgstr "no se pudo crear valor semilla para el generador de números aleatorios: %s"
+
+#: util.c:224
+#, fuzzy
+msgid "failed to allocate memory"
+msgstr "no se pudo asignar memoria"
+
+#: util.c:277 option.c:619
+msgid "could not get memory"
+msgstr "no se pudo adquirir memoria"
+
+#: util.c:287
+#, fuzzy, c-format
+msgid "cannot create pipe: %s"
+msgstr "no se puede crear pipe: %s"
+
+#: util.c:295
+#, fuzzy, c-format
+msgid "failed to allocate %d bytes"
+msgstr "no se pudo asignar %d bytes"
+
+#: util.c:464
+#, c-format
+msgid "infinite"
+msgstr "infinito"
+
+#: option.c:344
+msgid "Specify local address(es) to listen on."
+msgstr "Especificar dirección(es) locales dónde escuchar."
+
+#: option.c:345
+msgid "Return ipaddr for all hosts in specified domains."
+msgstr "Retornar ipaddr (dirección IP) para todos los hosts en los dominios especificados."
+
+#: option.c:346
+msgid "Fake reverse lookups for RFC1918 private address ranges."
+msgstr "Falsificar búsquedas reversas para rangos de dirección privados RFC1918."
+
+#: option.c:347
+msgid "Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."
+msgstr "Tratar ipaddr (dirección IP) como NXDOMAIN (derrota comodín Verisign)."
+
+#: option.c:348
+#, c-format
+msgid "Specify the size of the cache in entries (defaults to %s)."
+msgstr "Especificar tamaño de caché en cuanto a cantidad de objetos (%s por predeterminado)."
+
+#: option.c:349
+#, c-format
+msgid "Specify configuration file (defaults to %s)."
+msgstr "Especificar archivo de configuración (%s por predeterminado)."
+
+#: option.c:350
+msgid "Do NOT fork into the background: run in debug mode."
+msgstr "NO hacer un fork hacia el fondo: correr en modo debug."
+
+#: option.c:351
+msgid "Do NOT forward queries with no domain part."
+msgstr "NO reenviar búsquedas sin parte de dominio."
+
+#: option.c:352
+msgid "Return self-pointing MX records for local hosts."
+msgstr "Retornar expedientes MX auto-señaladores para hosts locales."
+
+#: option.c:353
+msgid "Expand simple names in /etc/hosts with domain-suffix."
+msgstr "Expandir nombres simples en /etc/hosts con domain-suffix (sufijo de dominio)."
+
+#: option.c:354
+msgid "Don't forward spurious DNS requests from Windows hosts."
+msgstr "No reenviar pedidos DNS falsos desde máquinas Windows."
+
+#: option.c:355
+msgid "Enable DHCP in the range given with lease duration."
+msgstr "Habilitar DHCP dentro del rango brindado con duración de concesión."
+
+#: option.c:356
+#, c-format
+msgid "Change to this group after startup (defaults to %s)."
+msgstr "Cambiar a este grupo después del inicio (%s por predeterminado)."
+
+#: option.c:357
+msgid "Set address or hostname for a specified machine."
+msgstr "Fijar dirección o nombre de host para una máquina especificada."
+
+#: option.c:358
+#, fuzzy
+msgid "Read DHCP host specs from file."
+msgstr "Leer especificaciones DHCP de host desde archivo"
+
+#: option.c:359
+#, fuzzy
+msgid "Read DHCP option specs from file."
+msgstr "Leer opciones DHCP de host desde archivo"
+
+#: option.c:360
+#, fuzzy
+msgid "Read DHCP host specs from a directory."
+msgstr "Leer especificaciones DHCP de host desde archivo"
+
+#: option.c:361
+#, fuzzy
+msgid "Read DHCP options from a directory."
+msgstr "Leer opciones DHCP de host desde archivo"
+
+#: option.c:362
+msgid "Evaluate conditional tag expression."
+msgstr "Evaluar expresión condicional de etiqueta."
+
+#: option.c:363
+#, c-format
+msgid "Do NOT load %s file."
+msgstr "NO cargar archivo %s."
+
+#: option.c:364
+#, c-format
+msgid "Specify a hosts file to be read in addition to %s."
+msgstr "Especificar un archivo de hosts para ser leído adicionalmente a %s."
+
+#: option.c:365
+#, fuzzy
+msgid "Read hosts files from a directory."
+msgstr "Leer especificaciones DHCP de host desde archivo"
+
+#: option.c:366
+msgid "Specify interface(s) to listen on."
+msgstr "Especificar interfase(s) donde escuchar."
+
+#: option.c:367
+msgid "Specify interface(s) NOT to listen on."
+msgstr "Especificar interfase(s) donde NO escuchar."
+
+#: option.c:368
+#, fuzzy
+msgid "Map DHCP user class to tag."
+msgstr "Trazar clase de usuario DHCP a etiqueta."
+
+#: option.c:369
+msgid "Map RFC3046 circuit-id to tag."
+msgstr "Trazar circuit-id (identificación de circuito) RFC3046 a etiqueta."
+
+#: option.c:370
+msgid "Map RFC3046 remote-id to tag."
+msgstr "Trazar remote-id (identificación remota) RFC3046 a etiqueta."
+
+#: option.c:371
+msgid "Map RFC3993 subscriber-id to tag."
+msgstr "Trazar subscriber-id (identificación de suscritor) RFC3993 a etiqueta."
+
+#: option.c:372
+#, fuzzy
+msgid "Don't do DHCP for hosts with tag set."
+msgstr "No hacer DHCP para hosts con etiqueta fijada."
+
+#: option.c:373
+#, fuzzy
+msgid "Force broadcast replies for hosts with tag set."
+msgstr "Forzar respuestas broadcast para hosts con etiqueta fijada."
+
+#: option.c:374
+msgid "Do NOT fork into the background, do NOT run in debug mode."
+msgstr "NO hacer un fork hacia el fondo, NO correr en modo debug."
+
+#: option.c:375
+msgid "Assume we are the only DHCP server on the local network."
+msgstr "Asumir que somos el único servidor DHCP en la red local."
+
+#: option.c:376
+#, c-format
+msgid "Specify where to store DHCP leases (defaults to %s)."
+msgstr "Especificar donde almacenar concesión DHCP (%s por predeterminado)."
+
+#: option.c:377
+msgid "Return MX records for local hosts."
+msgstr "Retornar expedientes MX para hosts locales."
+
+#: option.c:378
+msgid "Specify an MX record."
+msgstr "Especificar un expediente MX."
+
+#: option.c:379
+msgid "Specify BOOTP options to DHCP server."
+msgstr "Especificar opciones BOOTP a servidor DHCP."
+
+#: option.c:380
+#, c-format
+msgid "Do NOT poll %s file, reload only on SIGHUP."
+msgstr "NO revisar archivo %s periódicamente, recargar solo con SIGHUP."
+
+#: option.c:381
+msgid "Do NOT cache failed search results."
+msgstr "NO almacenar en caché resultados de búsquedas fallidas."
+
+#: option.c:382
+#, c-format
+msgid "Use nameservers strictly in the order given in %s."
+msgstr "Usar servidores DNS estrictamente en el órden brindado en %s."
+
+#: option.c:383
+#, fuzzy
+msgid "Specify options to be sent to DHCP clients."
+msgstr "Especificar opciones para ser enviadas a clientes DHCP."
+
+#: option.c:384
+msgid "DHCP option sent even if the client does not request it."
+msgstr "Opción DHCP enviada aún si el cliente no la pide."
+
+#: option.c:385
+msgid "Specify port to listen for DNS requests on (defaults to 53)."
+msgstr "Especificar puerto donde escuchar por búsquedas DNS (53 por predeterminado)."
+
+#: option.c:386
+#, c-format
+msgid "Maximum supported UDP packet size for EDNS.0 (defaults to %s)."
+msgstr "Tamaño máximo de paquetes UDP soportado para EDNS.0 (%s por predeterminado)."
+
+#: option.c:387
+#, fuzzy
+msgid "Log DNS queries."
+msgstr "Bitacorear búsquedas DNS."
+
+#: option.c:388
+#, fuzzy
+msgid "Force the originating port for upstream DNS queries."
+msgstr "Enforzar el puerto original para búsquedas DNS subida."
+
+#: option.c:389
+msgid "Do NOT read resolv.conf."
+msgstr "NO leer resolv.conf."
+
+#: option.c:390
+#, c-format
+msgid "Specify path to resolv.conf (defaults to %s)."
+msgstr "Especificar el path hacia resolv.conf (%s por predeterminado)."
+
+#: option.c:391
+#, fuzzy
+msgid "Specify path to file with server= options"
+msgstr "Especificar path de archivo PID (%s por predeterminado)."
+
+#: option.c:392
+msgid "Specify address(es) of upstream servers with optional domains."
+msgstr "Especificar dirección(es) de servidores subida con dominios opcionales."
+
+#: option.c:393
+#, fuzzy
+msgid "Specify address of upstream servers for reverse address queries"
+msgstr "Especificar dirección(es) de servidores subida con dominios opcionales."
+
+#: option.c:394
+msgid "Never forward queries to specified domains."
+msgstr "Nunca reenviar búsquedas a dominios especificados."
+
+#: option.c:395
+msgid "Specify the domain to be assigned in DHCP leases."
+msgstr "Especificar el dominio para ser asignado en concesión DHCP."
+
+#: option.c:396
+msgid "Specify default target in an MX record."
+msgstr "Especificar destino predeterminado en un expediente MX."
+
+#: option.c:397
+msgid "Specify time-to-live in seconds for replies from /etc/hosts."
+msgstr "Especificar tiempo de vida en segundos para respuestas desde /etc/hosts."
+
+#: option.c:398
+#, fuzzy
+msgid "Specify time-to-live in seconds for negative caching."
+msgstr "Especificar tiempo de vida en segundos para caché negativo."
+
+#: option.c:399
+#, fuzzy
+msgid "Specify time-to-live in seconds for maximum TTL to send to clients."
+msgstr "Especificar tiempo de vida en segundos para respuestas desde /etc/hosts."
+
+#: option.c:400
+#, fuzzy
+msgid "Specify time-to-live ceiling for cache."
+msgstr "Especificar tiempo de vida en segundos para caché negativo."
+
+#: option.c:401
+#, fuzzy
+msgid "Specify time-to-live floor for cache."
+msgstr "Especificar tiempo de vida en segundos para caché negativo."
+
+#: option.c:402
+#, c-format
+msgid "Change to this user after startup. (defaults to %s)."
+msgstr "Cambiar a este usuario despues del inicio (%s por predeterminado)."
+
+#: option.c:403
+#, fuzzy
+msgid "Map DHCP vendor class to tag."
+msgstr "Trazar clase de vendedor DHCP a etiqueta."
+
+#: option.c:404
+msgid "Display dnsmasq version and copyright information."
+msgstr "Mostrar información sobre la versión y copyright de dnsmasq."
+
+#: option.c:405
+msgid "Translate IPv4 addresses from upstream servers."
+msgstr "Traducir direcciones IPv4 desde servidores subida."
+
+#: option.c:406
+msgid "Specify a SRV record."
+msgstr "Especificar un expediente SRV."
+
+#: option.c:407
+#, fuzzy
+msgid "Display this message. Use --help dhcp or --help dhcp6 for known DHCP options."
+msgstr "Mostrar este mensaje. Usar --help dhcp para opciones DHCP conocidas."
+
+#: option.c:408
+#, fuzzy, c-format
+msgid "Specify path of PID file (defaults to %s)."
+msgstr "Especificar path de archivo PID (%s por predeterminado)."
+
+#: option.c:409
+#, c-format
+msgid "Specify maximum number of DHCP leases (defaults to %s)."
+msgstr "Especificar número máximo de concesión DHCP (%s por predeterminado)."
+
+#: option.c:410
+msgid "Answer DNS queries based on the interface a query was sent to."
+msgstr "Responder a búsquedas DNS en base a la interfase a la cuál fueron enviadas."
+
+#: option.c:411
+msgid "Specify TXT DNS record."
+msgstr "Especificar expediente DNS TXT."
+
+#: option.c:412
+#, fuzzy
+msgid "Specify PTR DNS record."
+msgstr "Especificar expediente DNS PTR."
+
+#: option.c:413
+msgid "Give DNS name to IPv4 address of interface."
+msgstr "Otorgar nombre DNS a dirección IPv4 de interfase."
+
+#: option.c:414
+msgid "Bind only to interfaces in use."
+msgstr "Acoplar solo a interfases en uso."
+
+#: option.c:415
+#, c-format
+msgid "Read DHCP static host information from %s."
+msgstr "Leer información sobre hosts DHCP estáticos desde %s."
+
+#: option.c:416
+msgid "Enable the DBus interface for setting upstream servers, etc."
+msgstr "Habilitar la interfase DBus para fijar servidores subida, etc."
+
+#: option.c:417
+msgid "Do not provide DHCP on this interface, only provide DNS."
+msgstr "No proveer DHCP en esta interfase, sólo proveer DNS."
+
+#: option.c:418
+msgid "Enable dynamic address allocation for bootp."
+msgstr "Habilitar alocación dinámica de direcciónes para BOOTP."
+
+#: option.c:419
+#, fuzzy
+msgid "Map MAC address (with wildcards) to option set."
+msgstr "Trazar dirección MAC (con comodínes) a opción fijada."
+
+#: option.c:420
+msgid "Treat DHCP requests on aliases as arriving from interface."
+msgstr "Tratar pedidos DHCP en alias como si llegaran de la interfase."
+
+#: option.c:421
+msgid "Disable ICMP echo address checking in the DHCP server."
+msgstr "Deshabilitar verificación de direcciónes para echo ICMP en el servidor DHCP."
+
+#: option.c:422
+#, fuzzy
+msgid "Shell script to run on DHCP lease creation and destruction."
+msgstr "Archivo guión para ejecutar cuando se crea o destruye una concesión DHCP."
+
+#: option.c:423
+#, fuzzy
+msgid "Lua script to run on DHCP lease creation and destruction."
+msgstr "Archivo guión para ejecutar cuando se crea o destruye una concesión DHCP."
+
+#: option.c:424
+#, fuzzy
+msgid "Run lease-change scripts as this user."
+msgstr "Correr archivo guión de cambio de concesión como este usuario."
+
+#: option.c:425
+msgid "Call dhcp-script with changes to local ARP table."
+msgstr ""
+
+#: option.c:426
+msgid "Read configuration from all the files in this directory."
+msgstr "Leer configuración desde todos los archivos en este directorio."
+
+#: option.c:427
+#, fuzzy
+msgid "Log to this syslog facility or file. (defaults to DAEMON)"
+msgstr "Bitacorear a esta facilidad syslog o archivo. (DAEMON por predeterminado)"
+
+#: option.c:428
+msgid "Do not use leasefile."
+msgstr "No usar archivo de concesión."
+
+#: option.c:429
+#, fuzzy, c-format
+msgid "Maximum number of concurrent DNS queries. (defaults to %s)"
+msgstr "Número máximo de búsquedas DNS simultáneas. (%s por predeterminado)"
+
+#: option.c:430
+#, c-format
+msgid "Clear DNS cache when reloading %s."
+msgstr "Liberar caché DNS al recargar %s."
+
+#: option.c:431
+msgid "Ignore hostnames provided by DHCP clients."
+msgstr "Ignorar nombres de host brindados por clientes DHCP."
+
+#: option.c:432
+msgid "Do NOT reuse filename and server fields for extra DHCP options."
+msgstr "NO reutilizar campos de nombre de archivo y servidor para opciones DHCP extra."
+
+#: option.c:433
+msgid "Enable integrated read-only TFTP server."
+msgstr "Habilitar servidor integrado TFTP solo-lectura."
+
+#: option.c:434
+msgid "Export files by TFTP only from the specified subtree."
+msgstr "Exportar archivos vía TFTP solo del sub-árbol especificado."
+
+#: option.c:435
+#, fuzzy
+msgid "Add client IP or hardware address to tftp-root."
+msgstr "Agregar IP de cliente a tftp-root."
+
+#: option.c:436
+msgid "Allow access only to files owned by the user running dnsmasq."
+msgstr "Permitir acceso solo a archivos pertenecientes al usuario que corre dnsmasq."
+
+#: option.c:437
+msgid "Do not terminate the service if TFTP directories are inaccessible."
+msgstr ""
+
+#: option.c:438
+#, fuzzy, c-format
+msgid "Maximum number of concurrent TFTP transfers (defaults to %s)."
+msgstr "Número máximo de transferencias TFTP simultáneas (%s por predeterminado)."
+
+#: option.c:439
+#, fuzzy
+msgid "Maximum MTU to use for TFTP transfers."
+msgstr "Número máximo de transferencias TFTP simultáneas (%s por predeterminado)."
+
+#: option.c:440
+msgid "Disable the TFTP blocksize extension."
+msgstr "Deshabilitar la extensión TFTP blocksize (tamaño de bloque)."
+
+#: option.c:441
+msgid "Convert TFTP filenames to lowercase"
+msgstr "Convertir a minúsculas los nombres de archivos TFTP"
+
+#: option.c:442
+msgid "Ephemeral port range for use by TFTP transfers."
+msgstr "Rango de puertos efímeros para ser usados en transferencias TFTP."
+
+#: option.c:443
+msgid "Extra logging for DHCP."
+msgstr "Log extra para DHCP."
+
+#: option.c:444
+msgid "Enable async. logging; optionally set queue length."
+msgstr "Habilitar registro asíncrono; opcionalmente fijar tamaño de cola."
+
+#: option.c:445
+msgid "Stop DNS rebinding. Filter private IP ranges when resolving."
+msgstr "Detener revinculación DNS. Filtrar rangos de IP privados al resolver."
+
+#: option.c:446
+msgid "Allow rebinding of 127.0.0.0/8, for RBL servers."
+msgstr "Permitir revinculación de 127.0.0.0/8, para servidores RBL."
+
+#: option.c:447
+msgid "Inhibit DNS-rebind protection on this domain."
+msgstr "Inhibir protección de revinculación DNS en este dominio."
+
+#: option.c:448
+msgid "Always perform DNS queries to all servers."
+msgstr "Siempre realizar búsquedas DNS a todos los servidores."
+
+#: option.c:449
+#, fuzzy
+msgid "Set tag if client includes matching option in request."
+msgstr "Fijar etiqueta si cliente incluye opción coincidente en pedido."
+
+#: option.c:450
+msgid "Use alternative ports for DHCP."
+msgstr "Usar puertos alternativos para DHCP."
+
+#: option.c:451
+#, fuzzy
+msgid "Specify NAPTR DNS record."
+msgstr "Especificar expediente DNS NAPTR."
+
+#: option.c:452
+msgid "Specify lowest port available for DNS query transmission."
+msgstr "Especificar puerto más bajo disponible para transmisión de búsquedas DNS."
+
+#: option.c:453
+#, fuzzy
+msgid "Specify highest port available for DNS query transmission."
+msgstr "Especificar puerto más bajo disponible para transmisión de búsquedas DNS."
+
+#: option.c:454
+msgid "Use only fully qualified domain names for DHCP clients."
+msgstr "Usar solo nombres de dominio completamente calificados para clientes DHCP."
+
+#: option.c:455
+msgid "Generate hostnames based on MAC address for nameless clients."
+msgstr "Generar hostnames basados en direcciones MAC para clientes sin nombre."
+
+#: option.c:456
+msgid "Use these DHCP relays as full proxies."
+msgstr "Usar estos relays DHCP como proxies completos."
+
+#: option.c:457
+msgid "Relay DHCP requests to a remote server"
+msgstr ""
+
+#: option.c:458
+msgid "Specify alias name for LOCAL DNS name."
+msgstr "Especificar nombre alias para nombre DNS LOCAL."
+
+#: option.c:459
+#, fuzzy
+msgid "Prompt to send to PXE clients."
+msgstr "Aviso a ser enviado a clientes PXE."
+
+#: option.c:460
+msgid "Boot service for PXE menu."
+msgstr "Servicio de arranque para menú PXE."
+
+#: option.c:461
+msgid "Check configuration syntax."
+msgstr "Revisar sintaxis de configuración."
+
+#: option.c:462
+msgid "Add requestor's MAC address to forwarded DNS queries."
+msgstr "Añadir direcciones MAC de los peticionarios a los filtros DNS enviados"
+
+#: option.c:463
+#, fuzzy
+msgid "Add specified IP subnet to forwarded DNS queries."
+msgstr "Añadir direcciones MAC de los peticionarios a los filtros DNS enviados"
+
+#: option.c:464
+#, fuzzy
+msgid "Add client identification to forwarded DNS queries."
+msgstr "Añadir direcciones MAC de los peticionarios a los filtros DNS enviados"
+
+#: option.c:465
+#, fuzzy
+msgid "Proxy DNSSEC validation results from upstream nameservers."
+msgstr "Traducir direcciones IPv4 desde servidores subida."
+
+#: option.c:466
+msgid "Attempt to allocate sequential IP addresses to DHCP clients."
+msgstr "Intento de instaurar direcciones IP secuenciales a cliente DHCP"
+
+#: option.c:467
+msgid "Copy connection-track mark from queries to upstream connections."
+msgstr "Copiar la marca de connection-track desde los filtros a las conexiones salientes"
+
+#: option.c:468
+msgid "Allow DHCP clients to do their own DDNS updates."
+msgstr "Permite a clientes DHCP realizar sus propias actualizaciones DDNS"
+
+#: option.c:469
+msgid "Send router-advertisements for interfaces doing DHCPv6"
+msgstr "Enviar anuncios del router a los interfases realizando DHCPv6"
+
+#: option.c:470
+msgid "Specify DUID_EN-type DHCPv6 server DUID"
+msgstr ""
+
+#: option.c:471
+#, fuzzy
+msgid "Specify host (A/AAAA and PTR) records"
+msgstr "Especificar un expediente MX."
+
+#: option.c:472
+#, fuzzy
+msgid "Specify arbitrary DNS resource record"
+msgstr "Especificar expediente DNS TXT."
+
+#: option.c:473
+#, fuzzy
+msgid "Bind to interfaces in use - check for new interfaces"
+msgstr "interfase desconocida %s en bridge-interfase"
+
+#: option.c:474
+msgid "Export local names to global DNS"
+msgstr "Exportar nombres DNS locales a globales"
+
+#: option.c:475
+msgid "Domain to export to global DNS"
+msgstr "Dominio a exportar a DNS global"
+
+#: option.c:476
+msgid "Set TTL for authoritative replies"
+msgstr "Fijar TTL para respuestas autoritarias"
+
+#: option.c:477
+#, fuzzy
+msgid "Set authoritative zone information"
+msgstr "Fijar información de zona autoritaria"
+
+#: option.c:478
+msgid "Secondary authoritative nameservers for forward domains"
+msgstr "Nombres de servidor secundario autoritatorios para dominios enviados"
+
+#: option.c:479
+msgid "Peers which are allowed to do zone transfer"
+msgstr "Colegas autorizados a la zona de transferencia (transfer)"
+
+#: option.c:480
+msgid "Specify ipsets to which matching domains should be added"
+msgstr "Especificar los ipsets coincidentes en dominio que debrían ser añadidos"
+
+#: option.c:481
+#, fuzzy
+msgid "Specify a domain and address range for synthesised names"
+msgstr "Especificar dominio y rango de direcciones para los nombres acrónimos"
+
+#: option.c:482
+msgid "Activate DNSSEC validation"
+msgstr ""
+
+#: option.c:483
+msgid "Specify trust anchor key digest."
+msgstr ""
+
+#: option.c:484
+msgid "Disable upstream checking for DNSSEC debugging."
+msgstr ""
+
+#: option.c:485
+msgid "Ensure answers without DNSSEC are in unsigned zones."
+msgstr ""
+
+#: option.c:486
+msgid "Don't check DNSSEC signature timestamps until first cache-reload"
+msgstr ""
+
+#: option.c:487
+msgid "Timestamp file to verify system clock for DNSSEC"
+msgstr ""
+
+#: option.c:489
+msgid "Specify DHCPv6 prefix class"
+msgstr "Especificar prefijo de clase DHCPv6"
+
+#: option.c:491
+msgid "Set MTU, priority, resend-interval and router-lifetime"
+msgstr ""
+
+#: option.c:492
+msgid "Do not log routine DHCP."
+msgstr ""
+
+#: option.c:493
+msgid "Do not log routine DHCPv6."
+msgstr ""
+
+#: option.c:494
+msgid "Do not log RA."
+msgstr ""
+
+#: option.c:495
+msgid "Accept queries only from directly-connected networks."
+msgstr ""
+
+#: option.c:496
+msgid "Detect and remove DNS forwarding loops."
+msgstr ""
+
+#: option.c:497
+msgid "Ignore DNS responses containing ipaddr."
+msgstr ""
+
+#: option.c:498
+msgid "Set TTL in DNS responses with DHCP-derived addresses."
+msgstr ""
+
+#: option.c:499
+msgid "Delay DHCP replies for at least number of seconds."
+msgstr ""
+
+#: option.c:703
+#, c-format
+msgid ""
+"Usage: dnsmasq [options]\n"
+"\n"
+msgstr ""
+"Modo de uso: dnsmasq [opciones]\n"
+"\n"
+
+#: option.c:705
+#, c-format
+msgid "Use short options only on the command line.\n"
+msgstr "Usar opciones cortas solo en la línea de comandos.\n"
+
+#: option.c:707
+#, fuzzy, c-format
+msgid "Valid options are:\n"
+msgstr "Opciones válidas son :\n"
+
+#: option.c:754 option.c:868
+#, fuzzy
+msgid "bad address"
+msgstr "dirección IP errónea"
+
+#: option.c:779 option.c:783
+msgid "bad port"
+msgstr "puerto erróneo"
+
+#: option.c:797 option.c:826 option.c:861
+msgid "interface binding not supported"
+msgstr "vinculación de interfase no está soportado"
+
+#: option.c:821 option.c:856
+msgid "interface can only be specified once"
+msgstr ""
+
+#: option.c:835 option.c:3800
+#, fuzzy
+msgid "bad interface name"
+msgstr "nombre de interfase erróneo"
+
+#: option.c:1062
+msgid "unsupported encapsulation for IPv6 option"
+msgstr "Encapsulación no soportada para opción IPv6"
+
+#: option.c:1076
+msgid "bad dhcp-option"
+msgstr "opción dhcp-option errónea"
+
+#: option.c:1144
+#, fuzzy
+msgid "bad IP address"
+msgstr "dirección IP errónea"
+
+#: option.c:1147 option.c:1286 option.c:3070
+#, fuzzy
+msgid "bad IPv6 address"
+msgstr "dirección IP errónea"
+
+#: option.c:1240
+#, fuzzy
+msgid "bad IPv4 address"
+msgstr "dirección IP errónea"
+
+#: option.c:1313 option.c:1407
+msgid "bad domain in dhcp-option"
+msgstr "dominio erróneo en dhcp-option"
+
+#: option.c:1445
+msgid "dhcp-option too long"
+msgstr "opción dhcp-option demasiado larga"
+
+#: option.c:1452
+msgid "illegal dhcp-match"
+msgstr "dhcp-match ilegal"
+
+#: option.c:1514
+msgid "illegal repeated flag"
+msgstr "opción repetida ilegal"
+
+#: option.c:1522
+msgid "illegal repeated keyword"
+msgstr "palabra clave repetida ilegal"
+
+#: option.c:1593 option.c:4434
+#, fuzzy, c-format
+msgid "cannot access directory %s: %s"
+msgstr "no se puede acceder a directorio %s: %s"
+
+#: option.c:1639 tftp.c:537
+#, fuzzy, c-format
+msgid "cannot access %s: %s"
+msgstr "no se puede acceder %s: %s"
+
+#: option.c:1727
+msgid "setting log facility is not possible under Android"
+msgstr "la creación de un registro no es posible en Android"
+
+#: option.c:1736
+msgid "bad log facility"
+msgstr "ubicación del registro errónea"
+
+#: option.c:1789
+msgid "bad MX preference"
+msgstr "preferencia MX errónea"
+
+#: option.c:1794
+msgid "bad MX name"
+msgstr "nombre MX erróneo"
+
+#: option.c:1808
+msgid "bad MX target"
+msgstr "destino MX erróneo"
+
+#: option.c:1820
+msgid "cannot run scripts under uClinux"
+msgstr "no se pueden correr archivos 'script' bajo uClinux"
+
+#: option.c:1822
+msgid "recompile with HAVE_SCRIPT defined to enable lease-change scripts"
+msgstr "recompilar con HAVE_SCRIPT definido para habilitar guiónes de cambio de concesión"
+
+#: option.c:1826
+#, fuzzy
+msgid "recompile with HAVE_LUASCRIPT defined to enable Lua scripts"
+msgstr "recompilar con HAVE_SCRIPT definido para habilitar 'scripts' en Lua"
+
+#: option.c:2095 option.c:2106 option.c:2143 option.c:2199 option.c:2482
+#, fuzzy
+msgid "bad prefix"
+msgstr "prefijo erróneo"
+
+#: option.c:2504
+#, fuzzy
+msgid "recompile with HAVE_IPSET defined to enable ipset directives"
+msgstr "recompilar con HAVE_SCRIPT definido para habilitar directivas ipset"
+
+#: option.c:2713
+#, fuzzy
+msgid "bad port range"
+msgstr "rango de puertos erróneo"
+
+#: option.c:2738
+msgid "bad bridge-interface"
+msgstr "opción bridge-interface (interfase puente) errónea"
+
+#: option.c:2798
+msgid "only one tag allowed"
+msgstr "solo una etiqueta permitida"
+
+#: option.c:2818 option.c:2830 option.c:2939 option.c:2944 option.c:2983
+msgid "bad dhcp-range"
+msgstr "opción dhcp-range (rango DHCP) errónea"
+
+#: option.c:2845
+msgid "inconsistent DHCP range"
+msgstr "rango DHCP inconsistente"
+
+#: option.c:2907
+msgid "prefix length must be exactly 64 for RA subnets"
+msgstr "la longitud del prefijo debe ser 64 exacto para subredes RA"
+
+#: option.c:2909
+msgid "prefix length must be exactly 64 for subnet constructors"
+msgstr "la longitud del prefijo debe ser 64 exacto para subredes constructoras"
+
+#: option.c:2913
+msgid "prefix length must be at least 64"
+msgstr "la longitud del prefijo debe ser al menos 64"
+
+#: option.c:2916
+#, fuzzy
+msgid "inconsistent DHCPv6 range"
+msgstr "rango DHCP inconsistente"
+
+#: option.c:2927
+msgid "prefix must be zero with \"constructor:\" argument"
+msgstr "prefijo debe ser cero con argumento \"constructor:\""
+
+#: option.c:3040 option.c:3088
+#, fuzzy
+msgid "bad hex constant"
+msgstr "constante hexadecimal errónea"
+
+#: option.c:3062
+msgid "cannot match tags in --dhcp-host"
+msgstr "no coinciden etiquetas en --dhcp-host"
+
+#: option.c:3110
+#, fuzzy, c-format
+msgid "duplicate dhcp-host IP address %s"
+msgstr "dirección IP duplicada %s en %s."
+
+#: option.c:3168
+#, fuzzy
+msgid "bad DHCP host name"
+msgstr "nombre de host DHCP erróneo"
+
+#: option.c:3250
+#, fuzzy
+msgid "bad tag-if"
+msgstr "etiqueta tag-if errónea"
+
+#: option.c:3607 option.c:4030
+msgid "invalid port number"
+msgstr "número de puerto inválido"
+
+#: option.c:3669
+#, fuzzy
+msgid "bad dhcp-proxy address"
+msgstr "dirección IP errónea"
+
+#: option.c:3695
+#, fuzzy
+msgid "Bad dhcp-relay"
+msgstr "opción dhcp-range (rango DHCP) errónea"
+
+#: option.c:3736
+msgid "bad RA-params"
+msgstr ""
+
+#: option.c:3745
+msgid "bad DUID"
+msgstr "DUID erróneo"
+
+#: option.c:3787
+#, fuzzy
+msgid "invalid alias range"
+msgstr "rango alias inválido"
+
+#: option.c:3841 option.c:3853
+msgid "bad CNAME"
+msgstr "CNAME erróneo"
+
+#: option.c:3857
+msgid "duplicate CNAME"
+msgstr "CNAME duplicado"
+
+#: option.c:3880
+#, fuzzy
+msgid "bad PTR record"
+msgstr "registro PTR erróneo"
+
+#: option.c:3911
+#, fuzzy
+msgid "bad NAPTR record"
+msgstr "registro NAPTR erróneo"
+
+#: option.c:3945
+#, fuzzy
+msgid "bad RR record"
+msgstr "registro PTR erróneo"
+
+#: option.c:3975
+msgid "bad TXT record"
+msgstr "registro TXT erróneo"
+
+#: option.c:4016
+msgid "bad SRV record"
+msgstr "registro SRV erróneo"
+
+#: option.c:4023
+msgid "bad SRV target"
+msgstr "destino SRV erróneo"
+
+#: option.c:4037
+msgid "invalid priority"
+msgstr "prioridad inválida"
+
+#: option.c:4040
+msgid "invalid weight"
+msgstr "peso inválido"
+
+#: option.c:4064
+#, fuzzy
+msgid "Bad host-record"
+msgstr "registro PTR erróneo"
+
+#: option.c:4088
+#, fuzzy
+msgid "Bad name in host-record"
+msgstr "nombre erróneo en %s"
+
+#: option.c:4153
+#, fuzzy
+msgid "bad trust anchor"
+msgstr "rango de puertos erróneo"
+
+#: option.c:4167
+msgid "bad HEX in trust anchor"
+msgstr ""
+
+#: option.c:4177
+#, fuzzy
+msgid "unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"
+msgstr "opción no soportada (verificar que dnsmasq fue compilado con soporte para DHCP/TFTP/DBus)"
+
+#: option.c:4237
+msgid "missing \""
+msgstr "falta \""
+
+#: option.c:4294
+msgid "bad option"
+msgstr "opción errónea"
+
+#: option.c:4296
+msgid "extraneous parameter"
+msgstr "parámetro extraño"
+
+#: option.c:4298
+msgid "missing parameter"
+msgstr "parámetro ausente"
+
+#: option.c:4300
+#, fuzzy
+msgid "illegal option"
+msgstr "opción errónea"
+
+#: option.c:4307
+msgid "error"
+msgstr "error"
+
+#: option.c:4309
+#, fuzzy, c-format
+msgid " at line %d of %s"
+msgstr "%s en línea %d de %%s"
+
+#: option.c:4324 option.c:4571 option.c:4607
+#, fuzzy, c-format
+msgid "read %s"
+msgstr "lee %s"
+
+#: option.c:4387 option.c:4510 tftp.c:715
+#, c-format
+msgid "cannot read %s: %s"
+msgstr "no se puede leer %s: %s"
+
+#: option.c:4676
+msgid "junk found in command line"
+msgstr "basura encontrada en linea de comando"
+
+#: option.c:4711
+#, c-format
+msgid "Dnsmasq version %s  %s\n"
+msgstr "Versión dnsmasq %s  %s\n"
+
+#: option.c:4712
+#, fuzzy, c-format
+msgid ""
+"Compile time options: %s\n"
+"\n"
+msgstr ""
+"Opciones de compilación %s\n"
+"\n"
+
+#: option.c:4713
+#, c-format
+msgid "This software comes with ABSOLUTELY NO WARRANTY.\n"
+msgstr "Este software viene SIN NINGUNA GARANTIA.\n"
+
+#: option.c:4714
+#, c-format
+msgid "Dnsmasq is free software, and you are welcome to redistribute it\n"
+msgstr "Dnsmasq es software libre, y usted está autorizado a redistribuirlo\n"
+
+#: option.c:4715
+#, fuzzy, c-format
+msgid "under the terms of the GNU General Public License, version 2 or 3.\n"
+msgstr "bajo los términos de la GNU General Public License, versión 2 o 3.\n"
+
+#: option.c:4726
+msgid "try --help"
+msgstr "pruebe --help"
+
+#: option.c:4728
+msgid "try -w"
+msgstr "pruebe -w"
+
+#: option.c:4730
+#, fuzzy, c-format
+msgid "bad command line options: %s"
+msgstr "opciones de línea de comandos erróneas: %s"
+
+#: option.c:4798
+#, c-format
+msgid "CNAME loop involving %s"
+msgstr ""
+
+#: option.c:4834
+#, c-format
+msgid "cannot get host-name: %s"
+msgstr "no se puede obtener host-name (nombre de host): %s"
+
+#: option.c:4862
+msgid "only one resolv.conf file allowed in no-poll mode."
+msgstr "solo un archivo resolv.conf está permitido en modo no-poll."
+
+#: option.c:4872
+msgid "must have exactly one resolv.conf to read domain from."
+msgstr "debe haber exáctamente un resolv.conf desde donde leer dominio."
+
+#: option.c:4875 network.c:1612 dhcp.c:816
+#, fuzzy, c-format
+msgid "failed to read %s: %s"
+msgstr "no se pudo leer %s: %s"
+
+#: option.c:4892
+#, c-format
+msgid "no search directive found in %s"
+msgstr "ninguna directiva de búsqueda encontrada en %s"
+
+#: option.c:4913
+#, fuzzy
+msgid "there must be a default domain when --dhcp-fqdn is set"
+msgstr "debe haber un dominio predeterminado cuando --dhcp-fqdn está fijado"
+
+#: option.c:4922
+msgid "syntax check OK"
+msgstr "revisión de sintaxis OK"
+
+#: forward.c:102
+#, fuzzy, c-format
+msgid "failed to send packet: %s"
+msgstr "no se pudo escuchar en socket: %s"
+
+#: forward.c:597
+msgid "discarding DNS reply: subnet option mismatch"
+msgstr ""
+
+#: forward.c:651
+#, c-format
+msgid "nameserver %s refused to do a recursive query"
+msgstr "servidor DNS %s rechazó realizar una búsqueda recursiva"
+
+#: forward.c:683
+#, fuzzy, c-format
+msgid "possible DNS-rebind attack detected: %s"
+msgstr "posible ataque de revinculación DNS detectado"
+
+#: forward.c:1244 forward.c:1681
+msgid "Ignoring query from non-local network"
+msgstr ""
+
+#: forward.c:2166
+#, fuzzy, c-format
+msgid "Maximum number of concurrent DNS queries reached (max: %d)"
+msgstr "Número máximo de búsquedas DNS simultáneas alcanzado. (%s por predeterminado)"
+
+#: network.c:720
+#, fuzzy, c-format
+msgid "failed to create listening socket for %s: %s"
+msgstr "no se pudo crear un zócalo de escucha: %s"
+
+#: network.c:1031
+#, c-format
+msgid "LOUD WARNING: listening on %s may accept requests via interfaces other than %s"
+msgstr ""
+
+#: network.c:1038
+msgid "LOUD WARNING: use --bind-dynamic rather than --bind-interfaces to avoid DNS amplification attacks via these interface(s)"
+msgstr ""
+
+#: network.c:1047
+#, fuzzy, c-format
+msgid "warning: using interface %s instead"
+msgstr "advertencia: interfase %s no existe actualmente"
+
+#: network.c:1056
+#, fuzzy, c-format
+msgid "warning: no addresses found for interface %s"
+msgstr "usando direcciones locales solo para %s %s"
+
+#: network.c:1114
+#, fuzzy, c-format
+msgid "interface %s failed to join DHCPv6 multicast group: %s"
+msgstr "el interfase % falló al unirse al grupo multicast DHCPv6: %s"
+
+#: network.c:1119
+msgid "try increasing /proc/sys/net/core/optmem_max"
+msgstr ""
+
+#: network.c:1322
+#, fuzzy, c-format
+msgid "failed to bind server socket for %s: %s"
+msgstr "no se pudo acoplar al zócalo del servidor para %s: %s"
+
+#: network.c:1517
+#, c-format
+msgid "ignoring nameserver %s - local interface"
+msgstr "ignorando servidor DNS %s - interfase local"
+
+#: network.c:1528
+#, fuzzy, c-format
+msgid "ignoring nameserver %s - cannot make/bind socket: %s"
+msgstr "ignorando servidor DNS %s - no se puede crear/acoplar zócalo: %s"
+
+#: network.c:1548
+msgid "(no DNSSEC)"
+msgstr ""
+
+#: network.c:1551
+msgid "unqualified"
+msgstr "no cualificado"
+
+#: network.c:1551
+msgid "names"
+msgstr "nombres"
+
+#: network.c:1553
+msgid "default"
+msgstr "predeterminado"
+
+#: network.c:1555
+msgid "domain"
+msgstr "dominio"
+
+#: network.c:1561
+#, c-format
+msgid "using local addresses only for %s %s"
+msgstr "usando direcciones locales solo para %s %s"
+
+#: network.c:1564
+#, fuzzy, c-format
+msgid "using standard nameservers for %s %s"
+msgstr "usando nombres estándar %s#%d para %s %s"
+
+#: network.c:1566
+#, fuzzy, c-format
+msgid "using nameserver %s#%d for %s %s %s"
+msgstr "usando nombre de servidor %s#%d para %s %s"
+
+#: network.c:1570
+#, fuzzy, c-format
+msgid "NOT using nameserver %s#%d - query loop detected"
+msgstr "usando nombre de servidor %s#%d para %s %s"
+
+#: network.c:1573
+#, fuzzy, c-format
+msgid "using nameserver %s#%d(via %s)"
+msgstr "usando nombre de servidor %s#%d(vía %s)"
+
+#: network.c:1575
+#, c-format
+msgid "using nameserver %s#%d"
+msgstr "usando nombre de servidor %s#%d"
+
+#: network.c:1580
+#, fuzzy, c-format
+msgid "using %d more local addresses"
+msgstr "usando nombre de servidor %s#%d"
+
+#: network.c:1582
+#, fuzzy, c-format
+msgid "using %d more nameservers"
+msgstr "usando nombre de servidor %s#%d"
+
+#: dnsmasq.c:166
+msgid "dhcp-hostsdir, dhcp-optsdir and hostsdir are not supported on this platform"
+msgstr ""
+
+#: dnsmasq.c:181
+msgid "no root trust anchor provided for DNSSEC"
+msgstr ""
+
+#: dnsmasq.c:184
+msgid "cannot reduce cache size from default when DNSSEC enabled"
+msgstr ""
+
+#: dnsmasq.c:186
+#, fuzzy
+msgid "DNSSEC not available: set HAVE_DNSSEC in src/config.h"
+msgstr "DBus no disponible: fijar HAVE_DBUS en src/config.h"
+
+#: dnsmasq.c:192
+#, fuzzy
+msgid "TFTP server not available: set HAVE_TFTP in src/config.h"
+msgstr "servidor TFTP no disponible: fijar HAVE_TFTP en src/config.h"
+
+#: dnsmasq.c:197
+#, fuzzy
+msgid "cannot use --conntrack AND --query-port"
+msgstr "No puede usar --conntrack AND --query-port"
+
+#: dnsmasq.c:200
+#, fuzzy
+msgid "conntrack support not available: set HAVE_CONNTRACK in src/config.h"
+msgstr "servidor TFTP no disponible: fijar HAVE_TFTP en src/config.h"
+
+#: dnsmasq.c:205
+#, fuzzy
+msgid "asynchronous logging is not available under Solaris"
+msgstr "registro asíncrono no está disponible bajo Solaris"
+
+#: dnsmasq.c:210
+#, fuzzy
+msgid "asynchronous logging is not available under Android"
+msgstr "registro asíncrono no está disponible bajo Solaris"
+
+#: dnsmasq.c:215
+#, fuzzy
+msgid "authoritative DNS not available: set HAVE_AUTH in src/config.h"
+msgstr "DBus no disponible: fijar HAVE_DBUS en src/config.h"
+
+#: dnsmasq.c:220
+#, fuzzy
+msgid "loop detection not available: set HAVE_LOOP in src/config.h"
+msgstr "servidor TFTP no disponible: fijar HAVE_TFTP en src/config.h"
+
+#: dnsmasq.c:227
+msgid "max_port cannot be smaller than min_port"
+msgstr ""
+
+#: dnsmasq.c:234
+msgid "zone serial must be configured in --auth-soa"
+msgstr "zona serie debe ser configurada en --auth-soa"
+
+#: dnsmasq.c:252
+msgid "dhcp-range constructor not available on this platform"
+msgstr "constructor rango dhcp no disponible en esta plataforma"
+
+#: dnsmasq.c:298
+msgid "cannot set --bind-interfaces and --bind-dynamic"
+msgstr "no puede usar --bind-interfases y --bind-dynamic"
+
+#: dnsmasq.c:301
+#, c-format
+msgid "failed to find list of interfaces: %s"
+msgstr "no se pudo encontrar lista de interfases: %s"
+
+#: dnsmasq.c:310
+#, c-format
+msgid "unknown interface %s"
+msgstr "interfase desconocida %s"
+
+#: dnsmasq.c:374 dnsmasq.c:1037
+#, c-format
+msgid "DBus error: %s"
+msgstr "error DBus: %s"
+
+#: dnsmasq.c:377
+msgid "DBus not available: set HAVE_DBUS in src/config.h"
+msgstr "DBus no disponible: fijar HAVE_DBUS en src/config.h"
+
+#: dnsmasq.c:405
+#, c-format
+msgid "unknown user or group: %s"
+msgstr "usuario o grupo desconocido: %s"
+
+#: dnsmasq.c:460
+#, c-format
+msgid "cannot chdir to filesystem root: %s"
+msgstr "no se puede cambiar directorio a raíz de sistema de archivos: %s"
+
+#: dnsmasq.c:716
+#, fuzzy, c-format
+msgid "started, version %s DNS disabled"
+msgstr "iniciado, versión %s DNS deshabilitado"
+
+#: dnsmasq.c:720
+#, c-format
+msgid "started, version %s cachesize %d"
+msgstr "iniciado, versión %s tamaño de caché %d"
+
+#: dnsmasq.c:722
+#, c-format
+msgid "started, version %s cache disabled"
+msgstr "iniciado, versión %s caché deshabilitado"
+
+#: dnsmasq.c:725
+msgid "DNS service limited to local subnets"
+msgstr ""
+
+#: dnsmasq.c:728
+#, c-format
+msgid "compile time options: %s"
+msgstr "opciones de compilación: %s"
+
+#: dnsmasq.c:734
+msgid "DBus support enabled: connected to system bus"
+msgstr "soporte DBus habilitado: conectado a bus de sistema"
+
+#: dnsmasq.c:736
+msgid "DBus support enabled: bus connection pending"
+msgstr "soporte DBus habilitado: conexión a bus pendiente"
+
+#: dnsmasq.c:754
+msgid "DNSSEC validation enabled"
+msgstr ""
+
+#: dnsmasq.c:758
+msgid "DNSSEC signature timestamps not checked until first cache reload"
+msgstr ""
+
+#: dnsmasq.c:761
+msgid "DNSSEC signature timestamps not checked until system time valid"
+msgstr ""
+
+#: dnsmasq.c:766
+#, fuzzy, c-format
+msgid "warning: failed to change owner of %s: %s"
+msgstr "advertencia: no se pudo cambiar propietario de %s: %s"
+
+#: dnsmasq.c:770
+msgid "setting --bind-interfaces option because of OS limitations"
+msgstr "fijando opción --bind-interfases debido a limitaciones de sistema operativo"
+
+#: dnsmasq.c:782
+#, c-format
+msgid "warning: interface %s does not currently exist"
+msgstr "advertencia: interfase %s no existe actualmente"
+
+#: dnsmasq.c:787
+msgid "warning: ignoring resolv-file flag because no-resolv is set"
+msgstr "advertencia: ignorando opción resolv-file porque no-resolv está fijado"
+
+#: dnsmasq.c:790
+#, fuzzy
+msgid "warning: no upstream servers configured"
+msgstr "advertencia: ningún servidor de subida configurado"
+
+#: dnsmasq.c:794
+#, c-format
+msgid "asynchronous logging enabled, queue limit is %d messages"
+msgstr "registro asíncrono habilitado, el límite de la cola es %d mensajes"
+
+#: dnsmasq.c:815
+msgid "IPv6 router advertisement enabled"
+msgstr "Anuncio de router IPv6 habilitado"
+
+#: dnsmasq.c:820
+#, c-format
+msgid "DHCP, sockets bound exclusively to interface %s"
+msgstr ""
+
+#: dnsmasq.c:834
+msgid "root is "
+msgstr "root está "
+
+#: dnsmasq.c:834
+#, fuzzy
+msgid "enabled"
+msgstr "habilitado"
+
+#: dnsmasq.c:836
+msgid "secure mode"
+msgstr "modo seguro"
+
+#: dnsmasq.c:839
+#, c-format
+msgid "warning: %s inaccessible"
+msgstr ""
+
+#: dnsmasq.c:843
+#, fuzzy, c-format
+msgid "warning: TFTP directory %s inaccessible"
+msgstr "directorio TFTP % inaccesible: %s"
+
+#: dnsmasq.c:869
+#, c-format
+msgid "restricting maximum simultaneous TFTP transfers to %d"
+msgstr "limitando número máximo de transferencias TFTP simultáneas a %d"
+
+#: dnsmasq.c:1039
+msgid "connected to system DBus"
+msgstr "conectado a DBus de sistema"
+
+#: dnsmasq.c:1189
+#, c-format
+msgid "cannot fork into background: %s"
+msgstr "no se puede hacer fork en background: %s"
+
+#: dnsmasq.c:1192
+#, fuzzy, c-format
+msgid "failed to create helper: %s"
+msgstr "no se pudo crear ayudante: %s"
+
+#: dnsmasq.c:1195
+#, fuzzy, c-format
+msgid "setting capabilities failed: %s"
+msgstr "configuración de capacidades ha fallado: %s"
+
+#: dnsmasq.c:1198
+#, fuzzy, c-format
+msgid "failed to change user-id to %s: %s"
+msgstr "no se pudo cambiar user-id a %s: %s"
+
+#: dnsmasq.c:1201
+#, fuzzy, c-format
+msgid "failed to change group-id to %s: %s"
+msgstr "no se pudo cambiar group-id a %s: %s"
+
+#: dnsmasq.c:1204
+#, fuzzy, c-format
+msgid "failed to open pidfile %s: %s"
+msgstr "no se pudo abrir archivo PID %s: %s"
+
+#: dnsmasq.c:1207
+#, fuzzy, c-format
+msgid "cannot open log %s: %s"
+msgstr "no se puede abrir registro %s: %s"
+
+#: dnsmasq.c:1210
+#, fuzzy, c-format
+msgid "failed to load Lua script: %s"
+msgstr "no se pudo cargar script Lua %s: %s"
+
+#: dnsmasq.c:1213
+#, c-format
+msgid "TFTP directory %s inaccessible: %s"
+msgstr "directorio TFTP % inaccesible: %s"
+
+#: dnsmasq.c:1216
+#, fuzzy, c-format
+msgid "cannot create timestamp file %s: %s"
+msgstr "no se puede abrir o crear archivo de concesión %s: %s"
+
+#: dnsmasq.c:1239
+msgid "now checking DNSSEC signature timestamps"
+msgstr ""
+
+#: dnsmasq.c:1307
+#, fuzzy, c-format
+msgid "script process killed by signal %d"
+msgstr "proceso script eliminado por señal %d"
+
+#: dnsmasq.c:1311
+#, fuzzy, c-format
+msgid "script process exited with status %d"
+msgstr "proceso script salió con con estado %d"
+
+#: dnsmasq.c:1315
+#, fuzzy, c-format
+msgid "failed to execute %s: %s"
+msgstr "no se pudo ejecutar %s: %s"
+
+#: dnsmasq.c:1379 dnssec.c:479 dnssec.c:525
+#, fuzzy, c-format
+msgid "failed to update mtime on %s: %s"
+msgstr "no se pudo abrir archivo PID %s: %s"
+
+#: dnsmasq.c:1386
+msgid "exiting on receipt of SIGTERM"
+msgstr "saliendo al recibir SIGTERM"
+
+#: dnsmasq.c:1414
+#, fuzzy, c-format
+msgid "failed to access %s: %s"
+msgstr "no se pudo acceder %s: %s"
+
+#: dnsmasq.c:1444
+#, c-format
+msgid "reading %s"
+msgstr "leyendo %s"
+
+#: dnsmasq.c:1455
+#, fuzzy, c-format
+msgid "no servers found in %s, will retry"
+msgstr "ningún servidor encontrado en %s, se reintentará"
+
+#: dhcp.c:53
+#, c-format
+msgid "cannot create DHCP socket: %s"
+msgstr "no se puede crear zócalo DHCP: %s"
+
+#: dhcp.c:68
+#, c-format
+msgid "failed to set options on DHCP socket: %s"
+msgstr "no se pudo fijar opciones en zócalo DHCP: %s"
+
+#: dhcp.c:89
+#, fuzzy, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"
+msgstr "no se pudo fijar SO_REUSE{ADDR|PORT} en zócalo DHCP: %s"
+
+#: dhcp.c:101
+#, c-format
+msgid "failed to bind DHCP server socket: %s"
+msgstr "no se pudo acoplar zócalo de servidor DHCP: %s"
+
+#: dhcp.c:127
+#, c-format
+msgid "cannot create ICMP raw socket: %s."
+msgstr "no se puede crear zócalo puro ICMP: %s."
+
+#: dhcp.c:252 dhcp6.c:173
+#, fuzzy, c-format
+msgid "unknown interface %s in bridge-interface"
+msgstr "interfase desconocida %s en bridge-interface"
+
+#: dhcp.c:293
+#, c-format
+msgid "DHCP packet received on %s which has no address"
+msgstr "Paquete DHCP recibido en %s que no tiene dirección"
+
+#: dhcp.c:427
+#, c-format
+msgid "ARP-cache injection failed: %s"
+msgstr ""
+
+#: dhcp.c:470
+#, c-format
+msgid "Error sending DHCP packet to %s: %s"
+msgstr ""
+
+#: dhcp.c:531
+#, c-format
+msgid "DHCP range %s -- %s is not consistent with netmask %s"
+msgstr "rango DHCP %s -- %s no coincide con máscara de subred %s"
+
+#: dhcp.c:854
+#, fuzzy, c-format
+msgid "bad line at %s line %d"
+msgstr "línea errónea en %s línea %d"
+
+#: dhcp.c:897
+#, c-format
+msgid "ignoring %s line %d, duplicate name or IP address"
+msgstr "ignorando %s línea %d, nombre o dirección IP duplicada"
+
+#: dhcp.c:1041 rfc3315.c:2149
+#, c-format
+msgid "DHCP relay %s -> %s"
+msgstr "DHCP relay %s -> %s"
+
+#: lease.c:98
+msgid "too many stored leases"
+msgstr "demasiadas concesiones almacenadas"
+
+#: lease.c:166
+#, fuzzy, c-format
+msgid "cannot open or create lease file %s: %s"
+msgstr "no se puede abrir o crear archivo de concesión %s: %s"
+
+#: lease.c:175
+#, c-format
+msgid "failed to parse lease database, invalid line: %s %s %s %s ..."
+msgstr ""
+
+#: lease.c:180
+#, fuzzy, c-format
+msgid "failed to read lease file %s: %s"
+msgstr "no se pudo leer %s: %s"
+
+#: lease.c:196
+#, fuzzy, c-format
+msgid "cannot run lease-init script %s: %s"
+msgstr "no se puede ejecutar archivo script lease-init %s: %s"
+
+#: lease.c:202
+#, c-format
+msgid "lease-init script returned exit code %s"
+msgstr "archivo guión lease-init retornó código de salida %s"
+
+#: lease.c:373
+#, fuzzy, c-format
+msgid "failed to write %s: %s (retry in %us)"
+msgstr "error al escribir %s: %s (reintentar en %us)"
+
+#: lease.c:937
+#, c-format
+msgid "Ignoring domain %s for DHCP host name %s"
+msgstr "Ignorando dominio %s para nombre de host DHCP %s"
+
+#: rfc2131.c:347
+#, c-format
+msgid "no address range available for DHCP request %s %s"
+msgstr "ningún rango de direcciónes disponible para pedido DHCP %s %s"
+
+#: rfc2131.c:348
+msgid "with subnet selector"
+msgstr "con selector de subred"
+
+#: rfc2131.c:348
+msgid "via"
+msgstr "vía"
+
+#: rfc2131.c:360
+#, fuzzy, c-format
+msgid "%u available DHCP subnet: %s/%s"
+msgstr "%u Subred DHCP disponible: %s/%s"
+
+#: rfc2131.c:363 rfc3315.c:306
+#, fuzzy, c-format
+msgid "%u available DHCP range: %s -- %s"
+msgstr "%u Rango DHCP disponible: %s -- %s"
+
+#: rfc2131.c:474
+#, fuzzy, c-format
+msgid "%u vendor class: %s"
+msgstr "%u Clase de vendedor: %s"
+
+#: rfc2131.c:476
+#, fuzzy, c-format
+msgid "%u user class: %s"
+msgstr "%u Clase de usuario: %s"
+
+#: rfc2131.c:510
+msgid "disabled"
+msgstr "deshabilitado"
+
+#: rfc2131.c:551 rfc2131.c:1006 rfc2131.c:1430 rfc3315.c:616 rfc3315.c:869
+#: rfc3315.c:1148
+msgid "ignored"
+msgstr "ignorado"
+
+#: rfc2131.c:566 rfc2131.c:1239 rfc3315.c:919
+msgid "address in use"
+msgstr "dirección en uso"
+
+#: rfc2131.c:580 rfc2131.c:1060
+msgid "no address available"
+msgstr "ninguna dirección disponible"
+
+#: rfc2131.c:587 rfc2131.c:1202
+msgid "wrong network"
+msgstr "red equivocada"
+
+#: rfc2131.c:602
+msgid "no address configured"
+msgstr "ninguna dirección configurada"
+
+#: rfc2131.c:608 rfc2131.c:1252
+msgid "no leases left"
+msgstr "no sobra ninguna concesión"
+
+#: rfc2131.c:703 rfc3315.c:482
+#, fuzzy, c-format
+msgid "%u client provides name: %s"
+msgstr "%u cliente provee nombre: %s"
+
+#: rfc2131.c:808
+msgid "PXE BIS not supported"
+msgstr "no hay soporte para BIS PXE"
+
+#: rfc2131.c:974 rfc3315.c:1242
+#, fuzzy, c-format
+msgid "disabling DHCP static address %s for %s"
+msgstr "deshabilitando dirección DHCP estática %s para %s"
+
+#: rfc2131.c:995
+msgid "unknown lease"
+msgstr "concesión desconocida"
+
+#: rfc2131.c:1029
+#, c-format
+msgid "not using configured address %s because it is leased to %s"
+msgstr "no usando dirección configurada %s porque está concedida a %s"
+
+#: rfc2131.c:1039
+#, fuzzy, c-format
+msgid "not using configured address %s because it is in use by the server or relay"
+msgstr "no usando dirección configurada %s porque está en uso por el servidor o relay"
+
+#: rfc2131.c:1042
+#, fuzzy, c-format
+msgid "not using configured address %s because it was previously declined"
+msgstr "no usando dirección configurada %s porque fué previamente denegada"
+
+#: rfc2131.c:1058 rfc2131.c:1245
+msgid "no unique-id"
+msgstr "ningún unique-id (identificación única)"
+
+#: rfc2131.c:1140
+msgid "wrong server-ID"
+msgstr "ID de servidor equivocada"
+
+#: rfc2131.c:1159
+msgid "wrong address"
+msgstr "dirección equivocada"
+
+#: rfc2131.c:1177 rfc3315.c:1015
+msgid "lease not found"
+msgstr "concesión no encontrada"
+
+#: rfc2131.c:1210
+msgid "address not available"
+msgstr "dirección no disponible"
+
+#: rfc2131.c:1221
+msgid "static lease available"
+msgstr "concesión estática disponible"
+
+#: rfc2131.c:1225
+msgid "address reserved"
+msgstr "dirección reservada"
+
+#: rfc2131.c:1233
+#, c-format
+msgid "abandoning lease to %s of %s"
+msgstr "abandonando concesión a %s de %s"
+
+#: rfc2131.c:1757
+#, c-format
+msgid "%u bootfile name: %s"
+msgstr "%u nombre de bootfile: %s"
+
+#: rfc2131.c:1766
+#, c-format
+msgid "%u server name: %s"
+msgstr "%u nombre de servidor: %s"
+
+#: rfc2131.c:1774
+#, fuzzy, c-format
+msgid "%u next server: %s"
+msgstr "%u siguiente servidor: %s"
+
+#: rfc2131.c:1777
+#, c-format
+msgid "%u broadcast response"
+msgstr "%u respuesta broadcast"
+
+#: rfc2131.c:1840
+#, fuzzy, c-format
+msgid "cannot send DHCP/BOOTP option %d: no space left in packet"
+msgstr "no se puede enviar opción DHCP/BOOTP %d: no queda espacio en el paquete"
+
+#: rfc2131.c:2131
+msgid "PXE menu too large"
+msgstr "menú PXE demasiado largo"
+
+#: rfc2131.c:2270 rfc3315.c:1515
+#, fuzzy, c-format
+msgid "%u requested options: %s"
+msgstr "%u opciones solicitadas: %s"
+
+#: rfc2131.c:2587
+#, c-format
+msgid "cannot send RFC3925 option: too many options for enterprise number %d"
+msgstr "no se puede enviar opción RFC3925: demasiadas opciones para número enterprise %d"
+
+#: rfc2131.c:2650
+#, c-format
+msgid "%u reply delay: %d"
+msgstr ""
+
+#: netlink.c:77
+#, fuzzy, c-format
+msgid "cannot create netlink socket: %s"
+msgstr "no se puede crear zócalo netlink: %s"
+
+#: netlink.c:355
+#, fuzzy, c-format
+msgid "netlink returns error: %s"
+msgstr "netlink retorna error: %s"
+
+#: dbus.c:186
+msgid "attempt to set an IPv6 server address via DBus - no IPv6 support"
+msgstr "intento de fijar dirección de servidor IPv6 vía DBus - no hay soporte IPv6"
+
+#: dbus.c:439
+#, c-format
+msgid "Enabling --%s option from D-Bus"
+msgstr ""
+
+#: dbus.c:444
+#, c-format
+msgid "Disabling --%s option from D-Bus"
+msgstr ""
+
+#: dbus.c:690
+msgid "setting upstream servers from DBus"
+msgstr "fijando servidores subida desde DBus"
+
+#: dbus.c:737
+msgid "could not register a DBus message handler"
+msgstr "no se pudo registrar un manejador de mensajes DBus"
+
+#: bpf.c:265
+#, c-format
+msgid "cannot create DHCP BPF socket: %s"
+msgstr "no se puede crear zócalo BPF DHCP: %s"
+
+#: bpf.c:293
+#, fuzzy, c-format
+msgid "DHCP request for unsupported hardware type (%d) received on %s"
+msgstr "pedido DHCP por tipo de hardware no-soportado (%d) recibido en %s"
+
+#: bpf.c:378
+#, fuzzy, c-format
+msgid "cannot create PF_ROUTE socket: %s"
+msgstr "no se puede crear zócalo DHCP: %s"
+
+#: bpf.c:399
+msgid "Unknown protocol version from route socket"
+msgstr ""
+
+#: helper.c:153
+msgid "lease() function missing in Lua script"
+msgstr "la función lease() no se encuentra en el script Lua"
+
+#: tftp.c:319
+msgid "unable to get free port for TFTP"
+msgstr "incapaz de conseguir puerto libre para TFTP"
+
+#: tftp.c:335
+#, c-format
+msgid "unsupported request from %s"
+msgstr "pedido no-soportado desde %s"
+
+#: tftp.c:483
+#, fuzzy, c-format
+msgid "file %s not found"
+msgstr "archivo %s no encontrado"
+
+#: tftp.c:592
+#, fuzzy, c-format
+msgid "error %d %s received from %s"
+msgstr "error TFTP %d %s recibido de %s"
+
+#: tftp.c:634
+#, fuzzy, c-format
+msgid "failed sending %s to %s"
+msgstr "TFTP no pudo enviar %s a %s"
+
+#: tftp.c:634
+#, fuzzy, c-format
+msgid "sent %s to %s"
+msgstr "TFTP envió %s a %s"
+
+#: log.c:190
+#, c-format
+msgid "overflow: %d log entries lost"
+msgstr "desbordamiento: %d entradas de registro perdidas"
+
+#: log.c:268
+#, c-format
+msgid "log failed: %s"
+msgstr "registro falló: %s"
+
+#: log.c:471
+msgid "FAILED to start up"
+msgstr "el inicio ha FALLADO"
+
+#: conntrack.c:65
+#, c-format
+msgid "Conntrack connection mark retrieval failed: %s"
+msgstr "Conexión conntrack con marca recuperación falló"
+
+#: dhcp6.c:52
+#, fuzzy, c-format
+msgid "cannot create DHCPv6 socket: %s"
+msgstr "no se puede crear zócalo DHCP: %s"
+
+#: dhcp6.c:73
+#, fuzzy, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"
+msgstr "no se pudo fijar SO_REUSE{ADDR|PORT} en zócalo DHCP: %s"
+
+#: dhcp6.c:85
+#, fuzzy, c-format
+msgid "failed to bind DHCPv6 server socket: %s"
+msgstr "no se pudo acoplar zócalo de servidor DHCP: %s"
+
+#: rfc3315.c:157
+#, fuzzy, c-format
+msgid "no address range available for DHCPv6 request from relay at %s"
+msgstr "ningún rango de direcciónes disponible para pedido DHCP %s %s"
+
+#: rfc3315.c:166
+#, fuzzy, c-format
+msgid "no address range available for DHCPv6 request via %s"
+msgstr "ningún rango de direcciónes disponible para pedido DHCP %s %s"
+
+#: rfc3315.c:303
+#, fuzzy, c-format
+msgid "%u available DHCPv6 subnet: %s/%d"
+msgstr "%u Subred DHCP disponible: %s/%s"
+
+#: rfc3315.c:386
+#, fuzzy, c-format
+msgid "%u vendor class: %u"
+msgstr "%u Clase de vendedor: %s"
+
+#: rfc3315.c:434
+#, fuzzy, c-format
+msgid "%u client MAC address: %s"
+msgstr "%u cliente provee nombre: %s"
+
+#: rfc3315.c:673
+#, fuzzy, c-format
+msgid "unknown prefix-class %d"
+msgstr "clase de prefijo desconocida"
+
+#: rfc3315.c:816 rfc3315.c:911
+#, fuzzy
+msgid "address unavailable"
+msgstr "dirección no disponible"
+
+#: rfc3315.c:828 rfc3315.c:959 rfc3315.c:1292
+msgid "success"
+msgstr ""
+
+#: rfc3315.c:843 rfc3315.c:852 rfc3315.c:967 rfc3315.c:969
+#, fuzzy
+msgid "no addresses available"
+msgstr "ninguna dirección disponible"
+
+#: rfc3315.c:946
+msgid "not on link"
+msgstr "no en el enlace"
+
+#: rfc3315.c:1019 rfc3315.c:1204 rfc3315.c:1281
+msgid "no binding found"
+msgstr "uniones no encontradas"
+
+#: rfc3315.c:1057
+msgid "deprecated"
+msgstr "descartado"
+
+#: rfc3315.c:1062
+#, fuzzy
+msgid "address invalid"
+msgstr "dirección en uso"
+
+#: rfc3315.c:1109
+msgid "confirm failed"
+msgstr "confirmación falló"
+
+#: rfc3315.c:1125
+#, fuzzy
+msgid "all addresses still on link"
+msgstr "dirección errónea en %s línea %d"
+
+#: rfc3315.c:1213
+msgid "release received"
+msgstr "concesión recibida"
+
+#: rfc3315.c:2140
+msgid "Cannot multicast to DHCPv6 server without correct interface"
+msgstr "No puede hacer multicast DHCPv6 sin el interfase correcto"
+
+#: dhcp-common.c:145
+#, c-format
+msgid "Ignoring duplicate dhcp-option %d"
+msgstr "Ignorando opción DHCP duplicada"
+
+#: dhcp-common.c:222
+#, c-format
+msgid "%u tags: %s"
+msgstr "%u etiquetas: %s"
+
+#: dhcp-common.c:407
+#, c-format
+msgid "%s has more than one address in hostsfile, using %s for DHCP"
+msgstr "%s tiene más de una dirección en hostsfile, usando %s para DHCP"
+
+#: dhcp-common.c:430
+#, c-format
+msgid "duplicate IP address %s (%s) in dhcp-config directive"
+msgstr "dirección IP duplicada %s (%s) en directiva dhcp-config"
+
+#: dhcp-common.c:494
+#, fuzzy, c-format
+msgid "failed to set SO_BINDTODEVICE on DHCP socket: %s"
+msgstr "no se pudo fijar SO_REUSE{ADDR|PORT} en socket DHCP: %s"
+
+#: dhcp-common.c:615
+#, c-format
+msgid "Known DHCP options:\n"
+msgstr "Opciones DHCP conocidas:\n"
+
+#: dhcp-common.c:626
+#, fuzzy, c-format
+msgid "Known DHCPv6 options:\n"
+msgstr "Opciones DHCP conocidas:\n"
+
+#: dhcp-common.c:823
+msgid ", prefix deprecated"
+msgstr ", prefijo descartado"
+
+#: dhcp-common.c:826
+#, c-format
+msgid ", lease time "
+msgstr ", tiempo de concesión"
+
+#: dhcp-common.c:868
+#, c-format
+msgid "%s stateless on %s%.0s%.0s%s"
+msgstr "%s apátrida en %s%.0s%.0s%s"
+
+#: dhcp-common.c:870
+#, fuzzy, c-format
+msgid "%s, static leases only on %.0s%s%s%.0s"
+msgstr "DHCP, concesión estática solo en %.0s%s, tiempo de concesión %s"
+
+#: dhcp-common.c:872
+#, fuzzy, c-format
+msgid "%s, proxy on subnet %.0s%s%.0s%.0s"
+msgstr "DHCP, proxy en subred %.0s%s%.0s"
+
+#: dhcp-common.c:873
+#, fuzzy, c-format
+msgid "%s, IP range %s -- %s%s%.0s"
+msgstr "DHCP, rango de IPs %s -- %s, tiempo de concesión %s"
+
+#: dhcp-common.c:886
+#, c-format
+msgid "DHCPv4-derived IPv6 names on %s%s"
+msgstr ""
+
+#: dhcp-common.c:889
+#, fuzzy, c-format
+msgid "router advertisement on %s%s"
+msgstr "DHCP, concesión estáticos solo en %.0s%s, tiempo de concesión %s"
+
+#: dhcp-common.c:900
+#, c-format
+msgid "DHCP relay from %s to %s via %s"
+msgstr ""
+
+#: dhcp-common.c:902
+#, c-format
+msgid "DHCP relay from %s to %s"
+msgstr ""
+
+#: radv.c:110
+#, fuzzy, c-format
+msgid "cannot create ICMPv6 socket: %s"
+msgstr "no se puede crear socket DHCP: %s"
+
+#: auth.c:449
+#, fuzzy, c-format
+msgid "ignoring zone transfer request from %s"
+msgstr "pedido no-soportado desde %s"
+
+#: ipset.c:95
+#, fuzzy, c-format
+msgid "failed to find kernel version: %s"
+msgstr "no se pudo acoplar socket de servidor DHCP: %s"
+
+#: ipset.c:114
+#, fuzzy, c-format
+msgid "failed to create IPset control socket: %s"
+msgstr "no se pudo crear socket TFTP: %s"
+
+#: ipset.c:233
+#, fuzzy, c-format
+msgid "failed to update ipset %s: %s"
+msgstr "no se pudo abrir archivo PID %s: %s"
+
+#: dnssec.c:527
+msgid "system time considered valid, now checking DNSSEC signature timestamps."
+msgstr ""
+
+#: blockdata.c:58
+#, c-format
+msgid "DNSSEC memory in use %u, max %u, allocated %u"
+msgstr ""
+
+#: tables.c:61
+#, fuzzy, c-format
+msgid "failed to access pf devices: %s"
+msgstr "no se pudo acceder %s: %s"
+
+#: tables.c:74
+#, fuzzy, c-format
+msgid "warning: no opened pf devices %s"
+msgstr "usando direcciones locales solo para %s %s"
+
+#: tables.c:82
+#, fuzzy, c-format
+msgid "error: cannot use table name %s"
+msgstr "no se puede obtener host-name (nombre de host): %s"
+
+#: tables.c:90
+#, c-format
+msgid "error: cannot strlcpy table name %s"
+msgstr ""
+
+#: tables.c:101
+#, fuzzy, c-format
+msgid "IPset: error:%s"
+msgstr "error DBus: %s"
+
+#: tables.c:108
+msgid "info: table created"
+msgstr ""
+
+#: tables.c:134
+#, c-format
+msgid "warning: DIOCR%sADDRS: %s"
+msgstr ""
+
+#: tables.c:138
+#, fuzzy, c-format
+msgid "%d addresses %s"
+msgstr "dirección IP errónea"
+
+#: inotify.c:62
+#, fuzzy, c-format
+msgid "cannot access path %s: %s"
+msgstr "no se puede acceder %s: %s"
+
+#: inotify.c:95
+#, fuzzy, c-format
+msgid "failed to create inotify: %s"
+msgstr "no se pudo crear ayudante: %s"
+
+#: inotify.c:111
+#, c-format
+msgid "too many symlinks following %s"
+msgstr ""
+
+#: inotify.c:127
+#, c-format
+msgid "directory %s for resolv-file is missing, cannot poll"
+msgstr ""
+
+#: inotify.c:131 inotify.c:168
+#, fuzzy, c-format
+msgid "failed to create inotify for %s: %s"
+msgstr "no se pudo crear un zócalo de escucha: %s"
+
+#: inotify.c:153
+#, fuzzy, c-format
+msgid "bad dynamic directory %s: %s"
+msgstr "no se puede acceder a directorio %s: %s"
+
+#: inotify.c:255
+#, c-format
+msgid "inotify, new or changed file %s"
+msgstr ""
+
+#, fuzzy
+#~ msgid "cannot cannonicalise resolv-file %s: %s"
+#~ msgstr "no se puede abrir o crear archivo de concesión %s: %s"
+
+#~ msgid "no interface with address %s"
+#~ msgstr "ninguna interfase con dirección %s"
+
+#~ msgid "duplicate IP address %s in dhcp-config directive."
+#~ msgstr "dirección IP duplicada %s en directiva dhcp-config."
+
+#, fuzzy
+#~ msgid "Specify path to Lua script (no default)."
+#~ msgstr "Especificar path de archivo PID (%s por predeterminado)."
+
+#, fuzzy
+#~ msgid "only one dhcp-hostsfile allowed"
+#~ msgstr "solo un dhcp-hostsfile permitido"
+
+#, fuzzy
+#~ msgid "only one dhcp-optsfile allowed"
+#~ msgstr "solo un dhcp-optsfile permitido"
+
+#~ msgid "files nested too deep in %s"
+#~ msgstr "archivos jerarquizados demasiado profundo en %s"
+
+#~ msgid "TXT record string too long"
+#~ msgstr "expediente TXT demasiado largo"
+
+#~ msgid "failed to set IPV6 options on listening socket: %s"
+#~ msgstr "no se pudo fijar opciones IPv6 sobre socket escuchador: %s"
+
+#~ msgid "failed to bind listening socket for %s: %s"
+#~ msgstr "no se pudo acoplar socket escuchador para %s: %s"
+
+#~ msgid "DHCP packet: transaction-id is %u"
+#~ msgstr "paquete DHCP: transaction-id (identificación de transacción) es %u"
+
+#~ msgid "must set exactly one interface on broken systems without IP_RECVIF"
+#~ msgstr "debe fijarse exáctamente una interfase en sistemas rotos sin IP_RECVIF"
+
+#~ msgid "Ignoring DHCP lease for %s because it has an illegal domain part"
+#~ msgstr "Ignorando concesión DHCP para %s porque tiene una parte ilegal de dominio"
+
+#~ msgid "ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h"
+#~ msgstr "integración dhcpd ISC no disponible: fijar HAVE_ISC_READER en src/config.h"
+
+#, fuzzy
+#~ msgid "illegal domain %s in dhcp-config directive."
+#~ msgstr "dominio ilegal %s en directiva dhcp-config."
+
+#~ msgid "illegal domain %s in %s."
+#~ msgstr "dominio ilegal %s en %s."
+
+#~ msgid "running as root"
+#~ msgstr "corriendo como root"
+
+#~ msgid "Read leases at startup, but never write the lease file."
+#~ msgstr "Leer concesión al inicio, pero nunca escribir el archivo de concesión."
+
+#, fuzzy
+#~ msgid "read %s - %d hosts"
+#~ msgstr "direcciónes %s - %d leídas"
+
+#~ msgid "Limit of %d leases exceeded."
+#~ msgstr "Límite de %d concesión excedido."
+
+#~ msgid "domains"
+#~ msgstr "dominios"
+
+#~ msgid "Ignoring DHCP host name %s because it has an illegal domain part"
+#~ msgstr "Ignorando nombre de host DHCP %s porque contiene una parte ilegal de dominio"
+
+#~ msgid "Display this message."
+#~ msgstr "Mostrar este mensaje."
+
+#~ msgid "failed to read %s: %m"
+#~ msgstr "no se pudo leer %s: %m"
+
+#~ msgid "failed to read %s:%m"
+#~ msgstr "no se pudo leer %s:%m"
diff --git a/po/fi.po b/po/fi.po
new file mode 100755
index 0000000..0f35582
--- /dev/null
+++ b/po/fi.po
@@ -0,0 +1,2226 @@
+# Finnish translations for dnsmasq package.
+# This file is put in the public domain.
+# Simon Kelley <simon@thekelleys.org.uk>, 2005.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: dnsmasq 2.24\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-06-18 12:24+0100\n"
+"PO-Revision-Date: 2017-07-17 18:30+0100\n"
+"Last-Translator: Simon Kelley <simon@thekelleys.org.uk>\n"
+"Language-Team: Finnish <translation-team-fi@lists.sourceforge.net>\n"
+"Language: fi\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ASCII\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: cache.c:513
+msgid "Internal error in cache."
+msgstr ""
+
+#: cache.c:923
+#, c-format
+msgid "failed to load names from %s: %s"
+msgstr ""
+
+#: cache.c:949 dhcp.c:867
+#, c-format
+msgid "bad address at %s line %d"
+msgstr ""
+
+#: cache.c:1002 dhcp.c:883
+#, c-format
+msgid "bad name at %s line %d"
+msgstr ""
+
+#: cache.c:1011 dhcp.c:958
+#, c-format
+msgid "read %s - %d addresses"
+msgstr ""
+
+#: cache.c:1124
+msgid "cleared cache"
+msgstr ""
+
+#: cache.c:1153
+#, c-format
+msgid "No IPv4 address found for %s"
+msgstr ""
+
+#: cache.c:1232
+#, c-format
+msgid "%s is a CNAME, not giving it to the DHCP lease of %s"
+msgstr ""
+
+#: cache.c:1256
+#, c-format
+msgid "not giving name %s to the DHCP lease of %s because the name exists in %s with address %s"
+msgstr ""
+
+#: cache.c:1413
+#, c-format
+msgid "time %lu"
+msgstr ""
+
+#: cache.c:1414
+#, c-format
+msgid "cache size %d, %d/%d cache insertions re-used unexpired cache entries."
+msgstr ""
+
+#: cache.c:1416
+#, c-format
+msgid "queries forwarded %u, queries answered locally %u"
+msgstr ""
+
+#: cache.c:1419
+#, c-format
+msgid "queries for authoritative zones %u"
+msgstr ""
+
+#: cache.c:1445
+#, c-format
+msgid "server %s#%d: queries sent %u, retried or failed %u"
+msgstr ""
+
+#: util.c:47
+#, c-format
+msgid "failed to seed the random number generator: %s"
+msgstr ""
+
+#: util.c:224
+msgid "failed to allocate memory"
+msgstr ""
+
+#: util.c:277 option.c:619
+msgid "could not get memory"
+msgstr ""
+
+#: util.c:287
+#, c-format
+msgid "cannot create pipe: %s"
+msgstr ""
+
+#: util.c:295
+#, c-format
+msgid "failed to allocate %d bytes"
+msgstr ""
+
+#: util.c:464
+#, c-format
+msgid "infinite"
+msgstr ""
+
+#: option.c:344
+msgid "Specify local address(es) to listen on."
+msgstr ""
+
+#: option.c:345
+msgid "Return ipaddr for all hosts in specified domains."
+msgstr ""
+
+#: option.c:346
+msgid "Fake reverse lookups for RFC1918 private address ranges."
+msgstr ""
+
+#: option.c:347
+msgid "Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."
+msgstr ""
+
+#: option.c:348
+#, c-format
+msgid "Specify the size of the cache in entries (defaults to %s)."
+msgstr ""
+
+#: option.c:349
+#, c-format
+msgid "Specify configuration file (defaults to %s)."
+msgstr ""
+
+#: option.c:350
+msgid "Do NOT fork into the background: run in debug mode."
+msgstr ""
+
+#: option.c:351
+msgid "Do NOT forward queries with no domain part."
+msgstr ""
+
+#: option.c:352
+msgid "Return self-pointing MX records for local hosts."
+msgstr ""
+
+#: option.c:353
+msgid "Expand simple names in /etc/hosts with domain-suffix."
+msgstr ""
+
+#: option.c:354
+msgid "Don't forward spurious DNS requests from Windows hosts."
+msgstr ""
+
+#: option.c:355
+msgid "Enable DHCP in the range given with lease duration."
+msgstr ""
+
+#: option.c:356
+#, c-format
+msgid "Change to this group after startup (defaults to %s)."
+msgstr ""
+
+#: option.c:357
+msgid "Set address or hostname for a specified machine."
+msgstr ""
+
+#: option.c:358
+msgid "Read DHCP host specs from file."
+msgstr ""
+
+#: option.c:359
+msgid "Read DHCP option specs from file."
+msgstr ""
+
+#: option.c:360
+msgid "Read DHCP host specs from a directory."
+msgstr ""
+
+#: option.c:361
+msgid "Read DHCP options from a directory."
+msgstr ""
+
+#: option.c:362
+msgid "Evaluate conditional tag expression."
+msgstr ""
+
+#: option.c:363
+#, c-format
+msgid "Do NOT load %s file."
+msgstr ""
+
+#: option.c:364
+#, c-format
+msgid "Specify a hosts file to be read in addition to %s."
+msgstr ""
+
+#: option.c:365
+msgid "Read hosts files from a directory."
+msgstr ""
+
+#: option.c:366
+msgid "Specify interface(s) to listen on."
+msgstr ""
+
+#: option.c:367
+msgid "Specify interface(s) NOT to listen on."
+msgstr ""
+
+#: option.c:368
+msgid "Map DHCP user class to tag."
+msgstr ""
+
+#: option.c:369
+msgid "Map RFC3046 circuit-id to tag."
+msgstr ""
+
+#: option.c:370
+msgid "Map RFC3046 remote-id to tag."
+msgstr ""
+
+#: option.c:371
+msgid "Map RFC3993 subscriber-id to tag."
+msgstr ""
+
+#: option.c:372
+msgid "Don't do DHCP for hosts with tag set."
+msgstr ""
+
+#: option.c:373
+msgid "Force broadcast replies for hosts with tag set."
+msgstr ""
+
+#: option.c:374
+msgid "Do NOT fork into the background, do NOT run in debug mode."
+msgstr ""
+
+#: option.c:375
+msgid "Assume we are the only DHCP server on the local network."
+msgstr ""
+
+#: option.c:376
+#, c-format
+msgid "Specify where to store DHCP leases (defaults to %s)."
+msgstr ""
+
+#: option.c:377
+msgid "Return MX records for local hosts."
+msgstr ""
+
+#: option.c:378
+msgid "Specify an MX record."
+msgstr ""
+
+#: option.c:379
+msgid "Specify BOOTP options to DHCP server."
+msgstr ""
+
+#: option.c:380
+#, c-format
+msgid "Do NOT poll %s file, reload only on SIGHUP."
+msgstr ""
+
+#: option.c:381
+msgid "Do NOT cache failed search results."
+msgstr ""
+
+#: option.c:382
+#, c-format
+msgid "Use nameservers strictly in the order given in %s."
+msgstr ""
+
+#: option.c:383
+msgid "Specify options to be sent to DHCP clients."
+msgstr ""
+
+#: option.c:384
+msgid "DHCP option sent even if the client does not request it."
+msgstr ""
+
+#: option.c:385
+msgid "Specify port to listen for DNS requests on (defaults to 53)."
+msgstr ""
+
+#: option.c:386
+#, c-format
+msgid "Maximum supported UDP packet size for EDNS.0 (defaults to %s)."
+msgstr ""
+
+#: option.c:387
+msgid "Log DNS queries."
+msgstr ""
+
+#: option.c:388
+msgid "Force the originating port for upstream DNS queries."
+msgstr ""
+
+#: option.c:389
+msgid "Do NOT read resolv.conf."
+msgstr ""
+
+#: option.c:390
+#, c-format
+msgid "Specify path to resolv.conf (defaults to %s)."
+msgstr ""
+
+#: option.c:391
+msgid "Specify path to file with server= options"
+msgstr ""
+
+#: option.c:392
+msgid "Specify address(es) of upstream servers with optional domains."
+msgstr ""
+
+#: option.c:393
+msgid "Specify address of upstream servers for reverse address queries"
+msgstr ""
+
+#: option.c:394
+msgid "Never forward queries to specified domains."
+msgstr ""
+
+#: option.c:395
+msgid "Specify the domain to be assigned in DHCP leases."
+msgstr ""
+
+#: option.c:396
+msgid "Specify default target in an MX record."
+msgstr ""
+
+#: option.c:397
+msgid "Specify time-to-live in seconds for replies from /etc/hosts."
+msgstr ""
+
+#: option.c:398
+msgid "Specify time-to-live in seconds for negative caching."
+msgstr ""
+
+#: option.c:399
+msgid "Specify time-to-live in seconds for maximum TTL to send to clients."
+msgstr ""
+
+#: option.c:400
+msgid "Specify time-to-live ceiling for cache."
+msgstr ""
+
+#: option.c:401
+msgid "Specify time-to-live floor for cache."
+msgstr ""
+
+#: option.c:402
+#, c-format
+msgid "Change to this user after startup. (defaults to %s)."
+msgstr ""
+
+#: option.c:403
+msgid "Map DHCP vendor class to tag."
+msgstr ""
+
+#: option.c:404
+msgid "Display dnsmasq version and copyright information."
+msgstr ""
+
+#: option.c:405
+msgid "Translate IPv4 addresses from upstream servers."
+msgstr ""
+
+#: option.c:406
+msgid "Specify a SRV record."
+msgstr ""
+
+#: option.c:407
+msgid "Display this message. Use --help dhcp or --help dhcp6 for known DHCP options."
+msgstr ""
+
+#: option.c:408
+#, c-format
+msgid "Specify path of PID file (defaults to %s)."
+msgstr ""
+
+#: option.c:409
+#, c-format
+msgid "Specify maximum number of DHCP leases (defaults to %s)."
+msgstr ""
+
+#: option.c:410
+msgid "Answer DNS queries based on the interface a query was sent to."
+msgstr ""
+
+#: option.c:411
+msgid "Specify TXT DNS record."
+msgstr ""
+
+#: option.c:412
+msgid "Specify PTR DNS record."
+msgstr ""
+
+#: option.c:413
+msgid "Give DNS name to IPv4 address of interface."
+msgstr ""
+
+#: option.c:414
+msgid "Bind only to interfaces in use."
+msgstr ""
+
+#: option.c:415
+#, c-format
+msgid "Read DHCP static host information from %s."
+msgstr ""
+
+#: option.c:416
+msgid "Enable the DBus interface for setting upstream servers, etc."
+msgstr ""
+
+#: option.c:417
+msgid "Do not provide DHCP on this interface, only provide DNS."
+msgstr ""
+
+#: option.c:418
+msgid "Enable dynamic address allocation for bootp."
+msgstr ""
+
+#: option.c:419
+msgid "Map MAC address (with wildcards) to option set."
+msgstr ""
+
+#: option.c:420
+msgid "Treat DHCP requests on aliases as arriving from interface."
+msgstr ""
+
+#: option.c:421
+msgid "Disable ICMP echo address checking in the DHCP server."
+msgstr ""
+
+#: option.c:422
+msgid "Shell script to run on DHCP lease creation and destruction."
+msgstr ""
+
+#: option.c:423
+msgid "Lua script to run on DHCP lease creation and destruction."
+msgstr ""
+
+#: option.c:424
+msgid "Run lease-change scripts as this user."
+msgstr ""
+
+#: option.c:425
+msgid "Call dhcp-script with changes to local ARP table."
+msgstr ""
+
+#: option.c:426
+msgid "Read configuration from all the files in this directory."
+msgstr ""
+
+#: option.c:427
+msgid "Log to this syslog facility or file. (defaults to DAEMON)"
+msgstr ""
+
+#: option.c:428
+msgid "Do not use leasefile."
+msgstr ""
+
+#: option.c:429
+#, c-format
+msgid "Maximum number of concurrent DNS queries. (defaults to %s)"
+msgstr ""
+
+#: option.c:430
+#, c-format
+msgid "Clear DNS cache when reloading %s."
+msgstr ""
+
+#: option.c:431
+msgid "Ignore hostnames provided by DHCP clients."
+msgstr ""
+
+#: option.c:432
+msgid "Do NOT reuse filename and server fields for extra DHCP options."
+msgstr ""
+
+#: option.c:433
+msgid "Enable integrated read-only TFTP server."
+msgstr ""
+
+#: option.c:434
+msgid "Export files by TFTP only from the specified subtree."
+msgstr ""
+
+#: option.c:435
+msgid "Add client IP or hardware address to tftp-root."
+msgstr ""
+
+#: option.c:436
+msgid "Allow access only to files owned by the user running dnsmasq."
+msgstr ""
+
+#: option.c:437
+msgid "Do not terminate the service if TFTP directories are inaccessible."
+msgstr ""
+
+#: option.c:438
+#, c-format
+msgid "Maximum number of concurrent TFTP transfers (defaults to %s)."
+msgstr ""
+
+#: option.c:439
+msgid "Maximum MTU to use for TFTP transfers."
+msgstr ""
+
+#: option.c:440
+msgid "Disable the TFTP blocksize extension."
+msgstr ""
+
+#: option.c:441
+msgid "Convert TFTP filenames to lowercase"
+msgstr ""
+
+#: option.c:442
+msgid "Ephemeral port range for use by TFTP transfers."
+msgstr ""
+
+#: option.c:443
+msgid "Extra logging for DHCP."
+msgstr ""
+
+#: option.c:444
+msgid "Enable async. logging; optionally set queue length."
+msgstr ""
+
+#: option.c:445
+msgid "Stop DNS rebinding. Filter private IP ranges when resolving."
+msgstr ""
+
+#: option.c:446
+msgid "Allow rebinding of 127.0.0.0/8, for RBL servers."
+msgstr ""
+
+#: option.c:447
+msgid "Inhibit DNS-rebind protection on this domain."
+msgstr ""
+
+#: option.c:448
+msgid "Always perform DNS queries to all servers."
+msgstr ""
+
+#: option.c:449
+msgid "Set tag if client includes matching option in request."
+msgstr ""
+
+#: option.c:450
+msgid "Use alternative ports for DHCP."
+msgstr ""
+
+#: option.c:451
+msgid "Specify NAPTR DNS record."
+msgstr ""
+
+#: option.c:452
+msgid "Specify lowest port available for DNS query transmission."
+msgstr ""
+
+#: option.c:453
+msgid "Specify highest port available for DNS query transmission."
+msgstr ""
+
+#: option.c:454
+msgid "Use only fully qualified domain names for DHCP clients."
+msgstr ""
+
+#: option.c:455
+msgid "Generate hostnames based on MAC address for nameless clients."
+msgstr ""
+
+#: option.c:456
+msgid "Use these DHCP relays as full proxies."
+msgstr ""
+
+#: option.c:457
+msgid "Relay DHCP requests to a remote server"
+msgstr ""
+
+#: option.c:458
+msgid "Specify alias name for LOCAL DNS name."
+msgstr ""
+
+#: option.c:459
+msgid "Prompt to send to PXE clients."
+msgstr ""
+
+#: option.c:460
+msgid "Boot service for PXE menu."
+msgstr ""
+
+#: option.c:461
+msgid "Check configuration syntax."
+msgstr ""
+
+#: option.c:462
+msgid "Add requestor's MAC address to forwarded DNS queries."
+msgstr ""
+
+#: option.c:463
+msgid "Add specified IP subnet to forwarded DNS queries."
+msgstr ""
+
+#: option.c:464
+msgid "Add client identification to forwarded DNS queries."
+msgstr ""
+
+#: option.c:465
+msgid "Proxy DNSSEC validation results from upstream nameservers."
+msgstr ""
+
+#: option.c:466
+msgid "Attempt to allocate sequential IP addresses to DHCP clients."
+msgstr ""
+
+#: option.c:467
+msgid "Copy connection-track mark from queries to upstream connections."
+msgstr ""
+
+#: option.c:468
+msgid "Allow DHCP clients to do their own DDNS updates."
+msgstr ""
+
+#: option.c:469
+msgid "Send router-advertisements for interfaces doing DHCPv6"
+msgstr ""
+
+#: option.c:470
+msgid "Specify DUID_EN-type DHCPv6 server DUID"
+msgstr ""
+
+#: option.c:471
+msgid "Specify host (A/AAAA and PTR) records"
+msgstr ""
+
+#: option.c:472
+msgid "Specify arbitrary DNS resource record"
+msgstr ""
+
+#: option.c:473
+msgid "Bind to interfaces in use - check for new interfaces"
+msgstr ""
+
+#: option.c:474
+msgid "Export local names to global DNS"
+msgstr ""
+
+#: option.c:475
+msgid "Domain to export to global DNS"
+msgstr ""
+
+#: option.c:476
+msgid "Set TTL for authoritative replies"
+msgstr ""
+
+#: option.c:477
+msgid "Set authoritative zone information"
+msgstr ""
+
+#: option.c:478
+msgid "Secondary authoritative nameservers for forward domains"
+msgstr ""
+
+#: option.c:479
+msgid "Peers which are allowed to do zone transfer"
+msgstr ""
+
+#: option.c:480
+msgid "Specify ipsets to which matching domains should be added"
+msgstr ""
+
+#: option.c:481
+msgid "Specify a domain and address range for synthesised names"
+msgstr ""
+
+#: option.c:482
+msgid "Activate DNSSEC validation"
+msgstr ""
+
+#: option.c:483
+msgid "Specify trust anchor key digest."
+msgstr ""
+
+#: option.c:484
+msgid "Disable upstream checking for DNSSEC debugging."
+msgstr ""
+
+#: option.c:485
+msgid "Ensure answers without DNSSEC are in unsigned zones."
+msgstr ""
+
+#: option.c:486
+msgid "Don't check DNSSEC signature timestamps until first cache-reload"
+msgstr ""
+
+#: option.c:487
+msgid "Timestamp file to verify system clock for DNSSEC"
+msgstr ""
+
+#: option.c:489
+msgid "Specify DHCPv6 prefix class"
+msgstr ""
+
+#: option.c:491
+msgid "Set MTU, priority, resend-interval and router-lifetime"
+msgstr ""
+
+#: option.c:492
+msgid "Do not log routine DHCP."
+msgstr ""
+
+#: option.c:493
+msgid "Do not log routine DHCPv6."
+msgstr ""
+
+#: option.c:494
+msgid "Do not log RA."
+msgstr ""
+
+#: option.c:495
+msgid "Accept queries only from directly-connected networks."
+msgstr ""
+
+#: option.c:496
+msgid "Detect and remove DNS forwarding loops."
+msgstr ""
+
+#: option.c:497
+msgid "Ignore DNS responses containing ipaddr."
+msgstr ""
+
+#: option.c:498
+msgid "Set TTL in DNS responses with DHCP-derived addresses."
+msgstr ""
+
+#: option.c:499
+msgid "Delay DHCP replies for at least number of seconds."
+msgstr ""
+
+#: option.c:703
+#, c-format
+msgid ""
+"Usage: dnsmasq [options]\n"
+"\n"
+msgstr ""
+
+#: option.c:705
+#, c-format
+msgid "Use short options only on the command line.\n"
+msgstr ""
+
+#: option.c:707
+#, c-format
+msgid "Valid options are:\n"
+msgstr ""
+
+#: option.c:754 option.c:868
+msgid "bad address"
+msgstr ""
+
+#: option.c:779 option.c:783
+msgid "bad port"
+msgstr ""
+
+#: option.c:797 option.c:826 option.c:861
+msgid "interface binding not supported"
+msgstr ""
+
+#: option.c:821 option.c:856
+msgid "interface can only be specified once"
+msgstr ""
+
+#: option.c:835 option.c:3800
+msgid "bad interface name"
+msgstr ""
+
+#: option.c:1062
+msgid "unsupported encapsulation for IPv6 option"
+msgstr ""
+
+#: option.c:1076
+msgid "bad dhcp-option"
+msgstr ""
+
+#: option.c:1144
+msgid "bad IP address"
+msgstr ""
+
+#: option.c:1147 option.c:1286 option.c:3070
+msgid "bad IPv6 address"
+msgstr ""
+
+#: option.c:1240
+msgid "bad IPv4 address"
+msgstr ""
+
+#: option.c:1313 option.c:1407
+msgid "bad domain in dhcp-option"
+msgstr ""
+
+#: option.c:1445
+msgid "dhcp-option too long"
+msgstr ""
+
+#: option.c:1452
+msgid "illegal dhcp-match"
+msgstr ""
+
+#: option.c:1514
+msgid "illegal repeated flag"
+msgstr ""
+
+#: option.c:1522
+msgid "illegal repeated keyword"
+msgstr ""
+
+#: option.c:1593 option.c:4434
+#, c-format
+msgid "cannot access directory %s: %s"
+msgstr ""
+
+#: option.c:1639 tftp.c:537
+#, c-format
+msgid "cannot access %s: %s"
+msgstr ""
+
+#: option.c:1727
+msgid "setting log facility is not possible under Android"
+msgstr ""
+
+#: option.c:1736
+msgid "bad log facility"
+msgstr ""
+
+#: option.c:1789
+msgid "bad MX preference"
+msgstr ""
+
+#: option.c:1794
+msgid "bad MX name"
+msgstr ""
+
+#: option.c:1808
+msgid "bad MX target"
+msgstr ""
+
+#: option.c:1820
+msgid "cannot run scripts under uClinux"
+msgstr ""
+
+#: option.c:1822
+msgid "recompile with HAVE_SCRIPT defined to enable lease-change scripts"
+msgstr ""
+
+#: option.c:1826
+msgid "recompile with HAVE_LUASCRIPT defined to enable Lua scripts"
+msgstr ""
+
+#: option.c:2095 option.c:2106 option.c:2143 option.c:2199 option.c:2482
+msgid "bad prefix"
+msgstr ""
+
+#: option.c:2504
+msgid "recompile with HAVE_IPSET defined to enable ipset directives"
+msgstr ""
+
+#: option.c:2713
+msgid "bad port range"
+msgstr ""
+
+#: option.c:2738
+msgid "bad bridge-interface"
+msgstr ""
+
+#: option.c:2798
+msgid "only one tag allowed"
+msgstr ""
+
+#: option.c:2818 option.c:2830 option.c:2939 option.c:2944 option.c:2983
+msgid "bad dhcp-range"
+msgstr ""
+
+#: option.c:2845
+msgid "inconsistent DHCP range"
+msgstr ""
+
+#: option.c:2907
+msgid "prefix length must be exactly 64 for RA subnets"
+msgstr ""
+
+#: option.c:2909
+msgid "prefix length must be exactly 64 for subnet constructors"
+msgstr ""
+
+#: option.c:2913
+msgid "prefix length must be at least 64"
+msgstr ""
+
+#: option.c:2916
+msgid "inconsistent DHCPv6 range"
+msgstr ""
+
+#: option.c:2927
+msgid "prefix must be zero with \"constructor:\" argument"
+msgstr ""
+
+#: option.c:3040 option.c:3088
+msgid "bad hex constant"
+msgstr ""
+
+#: option.c:3062
+msgid "cannot match tags in --dhcp-host"
+msgstr ""
+
+#: option.c:3110
+#, c-format
+msgid "duplicate dhcp-host IP address %s"
+msgstr ""
+
+#: option.c:3168
+msgid "bad DHCP host name"
+msgstr ""
+
+#: option.c:3250
+msgid "bad tag-if"
+msgstr ""
+
+#: option.c:3607 option.c:4030
+msgid "invalid port number"
+msgstr ""
+
+#: option.c:3669
+msgid "bad dhcp-proxy address"
+msgstr ""
+
+#: option.c:3695
+msgid "Bad dhcp-relay"
+msgstr ""
+
+#: option.c:3736
+msgid "bad RA-params"
+msgstr ""
+
+#: option.c:3745
+msgid "bad DUID"
+msgstr ""
+
+#: option.c:3787
+msgid "invalid alias range"
+msgstr ""
+
+#: option.c:3841 option.c:3853
+msgid "bad CNAME"
+msgstr ""
+
+#: option.c:3857
+msgid "duplicate CNAME"
+msgstr ""
+
+#: option.c:3880
+msgid "bad PTR record"
+msgstr ""
+
+#: option.c:3911
+msgid "bad NAPTR record"
+msgstr ""
+
+#: option.c:3945
+msgid "bad RR record"
+msgstr ""
+
+#: option.c:3975
+msgid "bad TXT record"
+msgstr ""
+
+#: option.c:4016
+msgid "bad SRV record"
+msgstr ""
+
+#: option.c:4023
+msgid "bad SRV target"
+msgstr ""
+
+#: option.c:4037
+msgid "invalid priority"
+msgstr ""
+
+#: option.c:4040
+msgid "invalid weight"
+msgstr ""
+
+#: option.c:4064
+msgid "Bad host-record"
+msgstr ""
+
+#: option.c:4088
+msgid "Bad name in host-record"
+msgstr ""
+
+#: option.c:4153
+msgid "bad trust anchor"
+msgstr ""
+
+#: option.c:4167
+msgid "bad HEX in trust anchor"
+msgstr ""
+
+#: option.c:4177
+msgid "unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"
+msgstr ""
+
+#: option.c:4237
+msgid "missing \""
+msgstr ""
+
+#: option.c:4294
+msgid "bad option"
+msgstr ""
+
+#: option.c:4296
+msgid "extraneous parameter"
+msgstr ""
+
+#: option.c:4298
+msgid "missing parameter"
+msgstr ""
+
+#: option.c:4300
+msgid "illegal option"
+msgstr ""
+
+#: option.c:4307
+msgid "error"
+msgstr ""
+
+#: option.c:4309
+#, c-format
+msgid " at line %d of %s"
+msgstr ""
+
+#: option.c:4324 option.c:4571 option.c:4607
+#, c-format
+msgid "read %s"
+msgstr ""
+
+#: option.c:4387 option.c:4510 tftp.c:715
+#, c-format
+msgid "cannot read %s: %s"
+msgstr ""
+
+#: option.c:4676
+msgid "junk found in command line"
+msgstr ""
+
+#: option.c:4711
+#, c-format
+msgid "Dnsmasq version %s  %s\n"
+msgstr ""
+
+#: option.c:4712
+#, c-format
+msgid ""
+"Compile time options: %s\n"
+"\n"
+msgstr ""
+
+#: option.c:4713
+#, c-format
+msgid "This software comes with ABSOLUTELY NO WARRANTY.\n"
+msgstr ""
+
+#: option.c:4714
+#, c-format
+msgid "Dnsmasq is free software, and you are welcome to redistribute it\n"
+msgstr ""
+
+#: option.c:4715
+#, c-format
+msgid "under the terms of the GNU General Public License, version 2 or 3.\n"
+msgstr ""
+
+#: option.c:4726
+msgid "try --help"
+msgstr ""
+
+#: option.c:4728
+msgid "try -w"
+msgstr ""
+
+#: option.c:4730
+#, c-format
+msgid "bad command line options: %s"
+msgstr ""
+
+#: option.c:4798
+#, c-format
+msgid "CNAME loop involving %s"
+msgstr ""
+
+#: option.c:4834
+#, c-format
+msgid "cannot get host-name: %s"
+msgstr ""
+
+#: option.c:4862
+msgid "only one resolv.conf file allowed in no-poll mode."
+msgstr ""
+
+#: option.c:4872
+msgid "must have exactly one resolv.conf to read domain from."
+msgstr ""
+
+#: option.c:4875 network.c:1612 dhcp.c:816
+#, c-format
+msgid "failed to read %s: %s"
+msgstr ""
+
+#: option.c:4892
+#, c-format
+msgid "no search directive found in %s"
+msgstr ""
+
+#: option.c:4913
+msgid "there must be a default domain when --dhcp-fqdn is set"
+msgstr ""
+
+#: option.c:4922
+msgid "syntax check OK"
+msgstr ""
+
+#: forward.c:102
+#, c-format
+msgid "failed to send packet: %s"
+msgstr ""
+
+#: forward.c:597
+msgid "discarding DNS reply: subnet option mismatch"
+msgstr ""
+
+#: forward.c:651
+#, c-format
+msgid "nameserver %s refused to do a recursive query"
+msgstr ""
+
+#: forward.c:683
+#, c-format
+msgid "possible DNS-rebind attack detected: %s"
+msgstr ""
+
+#: forward.c:1244 forward.c:1681
+msgid "Ignoring query from non-local network"
+msgstr ""
+
+#: forward.c:2166
+#, c-format
+msgid "Maximum number of concurrent DNS queries reached (max: %d)"
+msgstr ""
+
+#: network.c:720
+#, c-format
+msgid "failed to create listening socket for %s: %s"
+msgstr ""
+
+#: network.c:1031
+#, c-format
+msgid "LOUD WARNING: listening on %s may accept requests via interfaces other than %s"
+msgstr ""
+
+#: network.c:1038
+msgid "LOUD WARNING: use --bind-dynamic rather than --bind-interfaces to avoid DNS amplification attacks via these interface(s)"
+msgstr ""
+
+#: network.c:1047
+#, c-format
+msgid "warning: using interface %s instead"
+msgstr ""
+
+#: network.c:1056
+#, c-format
+msgid "warning: no addresses found for interface %s"
+msgstr ""
+
+#: network.c:1114
+#, c-format
+msgid "interface %s failed to join DHCPv6 multicast group: %s"
+msgstr ""
+
+#: network.c:1119
+msgid "try increasing /proc/sys/net/core/optmem_max"
+msgstr ""
+
+#: network.c:1322
+#, c-format
+msgid "failed to bind server socket for %s: %s"
+msgstr ""
+
+#: network.c:1517
+#, c-format
+msgid "ignoring nameserver %s - local interface"
+msgstr ""
+
+#: network.c:1528
+#, c-format
+msgid "ignoring nameserver %s - cannot make/bind socket: %s"
+msgstr ""
+
+#: network.c:1548
+msgid "(no DNSSEC)"
+msgstr ""
+
+#: network.c:1551
+msgid "unqualified"
+msgstr ""
+
+#: network.c:1551
+msgid "names"
+msgstr ""
+
+#: network.c:1553
+msgid "default"
+msgstr ""
+
+#: network.c:1555
+msgid "domain"
+msgstr ""
+
+#: network.c:1561
+#, c-format
+msgid "using local addresses only for %s %s"
+msgstr ""
+
+#: network.c:1564
+#, c-format
+msgid "using standard nameservers for %s %s"
+msgstr ""
+
+#: network.c:1566
+#, c-format
+msgid "using nameserver %s#%d for %s %s %s"
+msgstr ""
+
+#: network.c:1570
+#, c-format
+msgid "NOT using nameserver %s#%d - query loop detected"
+msgstr ""
+
+#: network.c:1573
+#, c-format
+msgid "using nameserver %s#%d(via %s)"
+msgstr ""
+
+#: network.c:1575
+#, c-format
+msgid "using nameserver %s#%d"
+msgstr ""
+
+#: network.c:1580
+#, c-format
+msgid "using %d more local addresses"
+msgstr ""
+
+#: network.c:1582
+#, c-format
+msgid "using %d more nameservers"
+msgstr ""
+
+#: dnsmasq.c:166
+msgid "dhcp-hostsdir, dhcp-optsdir and hostsdir are not supported on this platform"
+msgstr ""
+
+#: dnsmasq.c:181
+msgid "no root trust anchor provided for DNSSEC"
+msgstr ""
+
+#: dnsmasq.c:184
+msgid "cannot reduce cache size from default when DNSSEC enabled"
+msgstr ""
+
+#: dnsmasq.c:186
+msgid "DNSSEC not available: set HAVE_DNSSEC in src/config.h"
+msgstr ""
+
+#: dnsmasq.c:192
+msgid "TFTP server not available: set HAVE_TFTP in src/config.h"
+msgstr ""
+
+#: dnsmasq.c:197
+msgid "cannot use --conntrack AND --query-port"
+msgstr ""
+
+#: dnsmasq.c:200
+msgid "conntrack support not available: set HAVE_CONNTRACK in src/config.h"
+msgstr ""
+
+#: dnsmasq.c:205
+msgid "asynchronous logging is not available under Solaris"
+msgstr ""
+
+#: dnsmasq.c:210
+msgid "asynchronous logging is not available under Android"
+msgstr ""
+
+#: dnsmasq.c:215
+msgid "authoritative DNS not available: set HAVE_AUTH in src/config.h"
+msgstr ""
+
+#: dnsmasq.c:220
+msgid "loop detection not available: set HAVE_LOOP in src/config.h"
+msgstr ""
+
+#: dnsmasq.c:227
+msgid "max_port cannot be smaller than min_port"
+msgstr ""
+
+#: dnsmasq.c:234
+msgid "zone serial must be configured in --auth-soa"
+msgstr ""
+
+#: dnsmasq.c:252
+msgid "dhcp-range constructor not available on this platform"
+msgstr ""
+
+#: dnsmasq.c:298
+msgid "cannot set --bind-interfaces and --bind-dynamic"
+msgstr ""
+
+#: dnsmasq.c:301
+#, c-format
+msgid "failed to find list of interfaces: %s"
+msgstr ""
+
+#: dnsmasq.c:310
+#, c-format
+msgid "unknown interface %s"
+msgstr ""
+
+#: dnsmasq.c:374 dnsmasq.c:1037
+#, c-format
+msgid "DBus error: %s"
+msgstr ""
+
+#: dnsmasq.c:377
+msgid "DBus not available: set HAVE_DBUS in src/config.h"
+msgstr ""
+
+#: dnsmasq.c:405
+#, c-format
+msgid "unknown user or group: %s"
+msgstr ""
+
+#: dnsmasq.c:460
+#, c-format
+msgid "cannot chdir to filesystem root: %s"
+msgstr ""
+
+#: dnsmasq.c:716
+#, c-format
+msgid "started, version %s DNS disabled"
+msgstr ""
+
+#: dnsmasq.c:720
+#, c-format
+msgid "started, version %s cachesize %d"
+msgstr ""
+
+#: dnsmasq.c:722
+#, c-format
+msgid "started, version %s cache disabled"
+msgstr ""
+
+#: dnsmasq.c:725
+msgid "DNS service limited to local subnets"
+msgstr ""
+
+#: dnsmasq.c:728
+#, c-format
+msgid "compile time options: %s"
+msgstr ""
+
+#: dnsmasq.c:734
+msgid "DBus support enabled: connected to system bus"
+msgstr ""
+
+#: dnsmasq.c:736
+msgid "DBus support enabled: bus connection pending"
+msgstr ""
+
+#: dnsmasq.c:754
+msgid "DNSSEC validation enabled"
+msgstr ""
+
+#: dnsmasq.c:758
+msgid "DNSSEC signature timestamps not checked until first cache reload"
+msgstr ""
+
+#: dnsmasq.c:761
+msgid "DNSSEC signature timestamps not checked until system time valid"
+msgstr ""
+
+#: dnsmasq.c:766
+#, c-format
+msgid "warning: failed to change owner of %s: %s"
+msgstr ""
+
+#: dnsmasq.c:770
+msgid "setting --bind-interfaces option because of OS limitations"
+msgstr ""
+
+#: dnsmasq.c:782
+#, c-format
+msgid "warning: interface %s does not currently exist"
+msgstr ""
+
+#: dnsmasq.c:787
+msgid "warning: ignoring resolv-file flag because no-resolv is set"
+msgstr ""
+
+#: dnsmasq.c:790
+msgid "warning: no upstream servers configured"
+msgstr ""
+
+#: dnsmasq.c:794
+#, c-format
+msgid "asynchronous logging enabled, queue limit is %d messages"
+msgstr ""
+
+#: dnsmasq.c:815
+msgid "IPv6 router advertisement enabled"
+msgstr ""
+
+#: dnsmasq.c:820
+#, c-format
+msgid "DHCP, sockets bound exclusively to interface %s"
+msgstr ""
+
+#: dnsmasq.c:834
+msgid "root is "
+msgstr ""
+
+#: dnsmasq.c:834
+msgid "enabled"
+msgstr ""
+
+#: dnsmasq.c:836
+msgid "secure mode"
+msgstr ""
+
+#: dnsmasq.c:839
+#, c-format
+msgid "warning: %s inaccessible"
+msgstr ""
+
+#: dnsmasq.c:843
+#, c-format
+msgid "warning: TFTP directory %s inaccessible"
+msgstr ""
+
+#: dnsmasq.c:869
+#, c-format
+msgid "restricting maximum simultaneous TFTP transfers to %d"
+msgstr ""
+
+#: dnsmasq.c:1039
+msgid "connected to system DBus"
+msgstr ""
+
+#: dnsmasq.c:1189
+#, c-format
+msgid "cannot fork into background: %s"
+msgstr ""
+
+#: dnsmasq.c:1192
+#, c-format
+msgid "failed to create helper: %s"
+msgstr ""
+
+#: dnsmasq.c:1195
+#, c-format
+msgid "setting capabilities failed: %s"
+msgstr ""
+
+#: dnsmasq.c:1198
+#, c-format
+msgid "failed to change user-id to %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1201
+#, c-format
+msgid "failed to change group-id to %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1204
+#, c-format
+msgid "failed to open pidfile %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1207
+#, c-format
+msgid "cannot open log %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1210
+#, c-format
+msgid "failed to load Lua script: %s"
+msgstr ""
+
+#: dnsmasq.c:1213
+#, c-format
+msgid "TFTP directory %s inaccessible: %s"
+msgstr ""
+
+#: dnsmasq.c:1216
+#, c-format
+msgid "cannot create timestamp file %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1239
+msgid "now checking DNSSEC signature timestamps"
+msgstr ""
+
+#: dnsmasq.c:1307
+#, c-format
+msgid "script process killed by signal %d"
+msgstr ""
+
+#: dnsmasq.c:1311
+#, c-format
+msgid "script process exited with status %d"
+msgstr ""
+
+#: dnsmasq.c:1315
+#, c-format
+msgid "failed to execute %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1379 dnssec.c:479 dnssec.c:525
+#, c-format
+msgid "failed to update mtime on %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1386
+msgid "exiting on receipt of SIGTERM"
+msgstr ""
+
+#: dnsmasq.c:1414
+#, c-format
+msgid "failed to access %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1444
+#, c-format
+msgid "reading %s"
+msgstr ""
+
+#: dnsmasq.c:1455
+#, c-format
+msgid "no servers found in %s, will retry"
+msgstr ""
+
+#: dhcp.c:53
+#, c-format
+msgid "cannot create DHCP socket: %s"
+msgstr ""
+
+#: dhcp.c:68
+#, c-format
+msgid "failed to set options on DHCP socket: %s"
+msgstr ""
+
+#: dhcp.c:89
+#, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"
+msgstr ""
+
+#: dhcp.c:101
+#, c-format
+msgid "failed to bind DHCP server socket: %s"
+msgstr ""
+
+#: dhcp.c:127
+#, c-format
+msgid "cannot create ICMP raw socket: %s."
+msgstr ""
+
+#: dhcp.c:252 dhcp6.c:173
+#, c-format
+msgid "unknown interface %s in bridge-interface"
+msgstr ""
+
+#: dhcp.c:293
+#, c-format
+msgid "DHCP packet received on %s which has no address"
+msgstr ""
+
+#: dhcp.c:427
+#, c-format
+msgid "ARP-cache injection failed: %s"
+msgstr ""
+
+#: dhcp.c:470
+#, c-format
+msgid "Error sending DHCP packet to %s: %s"
+msgstr ""
+
+#: dhcp.c:531
+#, c-format
+msgid "DHCP range %s -- %s is not consistent with netmask %s"
+msgstr ""
+
+#: dhcp.c:854
+#, c-format
+msgid "bad line at %s line %d"
+msgstr ""
+
+#: dhcp.c:897
+#, c-format
+msgid "ignoring %s line %d, duplicate name or IP address"
+msgstr ""
+
+#: dhcp.c:1041 rfc3315.c:2149
+#, c-format
+msgid "DHCP relay %s -> %s"
+msgstr ""
+
+#: lease.c:98
+msgid "too many stored leases"
+msgstr ""
+
+#: lease.c:166
+#, c-format
+msgid "cannot open or create lease file %s: %s"
+msgstr ""
+
+#: lease.c:175
+#, c-format
+msgid "failed to parse lease database, invalid line: %s %s %s %s ..."
+msgstr ""
+
+#: lease.c:180
+#, c-format
+msgid "failed to read lease file %s: %s"
+msgstr ""
+
+#: lease.c:196
+#, c-format
+msgid "cannot run lease-init script %s: %s"
+msgstr ""
+
+#: lease.c:202
+#, c-format
+msgid "lease-init script returned exit code %s"
+msgstr ""
+
+#: lease.c:373
+#, c-format
+msgid "failed to write %s: %s (retry in %us)"
+msgstr ""
+
+#: lease.c:937
+#, c-format
+msgid "Ignoring domain %s for DHCP host name %s"
+msgstr ""
+
+#: rfc2131.c:347
+#, c-format
+msgid "no address range available for DHCP request %s %s"
+msgstr ""
+
+#: rfc2131.c:348
+msgid "with subnet selector"
+msgstr ""
+
+#: rfc2131.c:348
+msgid "via"
+msgstr ""
+
+#: rfc2131.c:360
+#, c-format
+msgid "%u available DHCP subnet: %s/%s"
+msgstr ""
+
+#: rfc2131.c:363 rfc3315.c:306
+#, c-format
+msgid "%u available DHCP range: %s -- %s"
+msgstr ""
+
+#: rfc2131.c:474
+#, c-format
+msgid "%u vendor class: %s"
+msgstr ""
+
+#: rfc2131.c:476
+#, c-format
+msgid "%u user class: %s"
+msgstr ""
+
+#: rfc2131.c:510
+msgid "disabled"
+msgstr ""
+
+#: rfc2131.c:551 rfc2131.c:1006 rfc2131.c:1430 rfc3315.c:616 rfc3315.c:869
+#: rfc3315.c:1148
+msgid "ignored"
+msgstr ""
+
+#: rfc2131.c:566 rfc2131.c:1239 rfc3315.c:919
+msgid "address in use"
+msgstr ""
+
+#: rfc2131.c:580 rfc2131.c:1060
+msgid "no address available"
+msgstr ""
+
+#: rfc2131.c:587 rfc2131.c:1202
+msgid "wrong network"
+msgstr ""
+
+#: rfc2131.c:602
+msgid "no address configured"
+msgstr ""
+
+#: rfc2131.c:608 rfc2131.c:1252
+msgid "no leases left"
+msgstr ""
+
+#: rfc2131.c:703 rfc3315.c:482
+#, c-format
+msgid "%u client provides name: %s"
+msgstr ""
+
+#: rfc2131.c:808
+msgid "PXE BIS not supported"
+msgstr ""
+
+#: rfc2131.c:974 rfc3315.c:1242
+#, c-format
+msgid "disabling DHCP static address %s for %s"
+msgstr ""
+
+#: rfc2131.c:995
+msgid "unknown lease"
+msgstr ""
+
+#: rfc2131.c:1029
+#, c-format
+msgid "not using configured address %s because it is leased to %s"
+msgstr ""
+
+#: rfc2131.c:1039
+#, c-format
+msgid "not using configured address %s because it is in use by the server or relay"
+msgstr ""
+
+#: rfc2131.c:1042
+#, c-format
+msgid "not using configured address %s because it was previously declined"
+msgstr ""
+
+#: rfc2131.c:1058 rfc2131.c:1245
+msgid "no unique-id"
+msgstr ""
+
+#: rfc2131.c:1140
+msgid "wrong server-ID"
+msgstr ""
+
+#: rfc2131.c:1159
+msgid "wrong address"
+msgstr ""
+
+#: rfc2131.c:1177 rfc3315.c:1015
+msgid "lease not found"
+msgstr ""
+
+#: rfc2131.c:1210
+msgid "address not available"
+msgstr ""
+
+#: rfc2131.c:1221
+msgid "static lease available"
+msgstr ""
+
+#: rfc2131.c:1225
+msgid "address reserved"
+msgstr ""
+
+#: rfc2131.c:1233
+#, c-format
+msgid "abandoning lease to %s of %s"
+msgstr ""
+
+#: rfc2131.c:1757
+#, c-format
+msgid "%u bootfile name: %s"
+msgstr ""
+
+#: rfc2131.c:1766
+#, c-format
+msgid "%u server name: %s"
+msgstr ""
+
+#: rfc2131.c:1774
+#, c-format
+msgid "%u next server: %s"
+msgstr ""
+
+#: rfc2131.c:1777
+#, c-format
+msgid "%u broadcast response"
+msgstr ""
+
+#: rfc2131.c:1840
+#, c-format
+msgid "cannot send DHCP/BOOTP option %d: no space left in packet"
+msgstr ""
+
+#: rfc2131.c:2131
+msgid "PXE menu too large"
+msgstr ""
+
+#: rfc2131.c:2270 rfc3315.c:1515
+#, c-format
+msgid "%u requested options: %s"
+msgstr ""
+
+#: rfc2131.c:2587
+#, c-format
+msgid "cannot send RFC3925 option: too many options for enterprise number %d"
+msgstr ""
+
+#: rfc2131.c:2650
+#, c-format
+msgid "%u reply delay: %d"
+msgstr ""
+
+#: netlink.c:77
+#, c-format
+msgid "cannot create netlink socket: %s"
+msgstr ""
+
+#: netlink.c:355
+#, c-format
+msgid "netlink returns error: %s"
+msgstr ""
+
+#: dbus.c:186
+msgid "attempt to set an IPv6 server address via DBus - no IPv6 support"
+msgstr ""
+
+#: dbus.c:439
+#, c-format
+msgid "Enabling --%s option from D-Bus"
+msgstr ""
+
+#: dbus.c:444
+#, c-format
+msgid "Disabling --%s option from D-Bus"
+msgstr ""
+
+#: dbus.c:690
+msgid "setting upstream servers from DBus"
+msgstr ""
+
+#: dbus.c:737
+msgid "could not register a DBus message handler"
+msgstr ""
+
+#: bpf.c:265
+#, c-format
+msgid "cannot create DHCP BPF socket: %s"
+msgstr ""
+
+#: bpf.c:293
+#, c-format
+msgid "DHCP request for unsupported hardware type (%d) received on %s"
+msgstr ""
+
+#: bpf.c:378
+#, c-format
+msgid "cannot create PF_ROUTE socket: %s"
+msgstr ""
+
+#: bpf.c:399
+msgid "Unknown protocol version from route socket"
+msgstr ""
+
+#: helper.c:153
+msgid "lease() function missing in Lua script"
+msgstr ""
+
+#: tftp.c:319
+msgid "unable to get free port for TFTP"
+msgstr ""
+
+#: tftp.c:335
+#, c-format
+msgid "unsupported request from %s"
+msgstr ""
+
+#: tftp.c:483
+#, c-format
+msgid "file %s not found"
+msgstr ""
+
+#: tftp.c:592
+#, c-format
+msgid "error %d %s received from %s"
+msgstr ""
+
+#: tftp.c:634
+#, c-format
+msgid "failed sending %s to %s"
+msgstr ""
+
+#: tftp.c:634
+#, c-format
+msgid "sent %s to %s"
+msgstr ""
+
+#: log.c:190
+#, c-format
+msgid "overflow: %d log entries lost"
+msgstr ""
+
+#: log.c:268
+#, c-format
+msgid "log failed: %s"
+msgstr ""
+
+#: log.c:471
+msgid "FAILED to start up"
+msgstr ""
+
+#: conntrack.c:65
+#, c-format
+msgid "Conntrack connection mark retrieval failed: %s"
+msgstr ""
+
+#: dhcp6.c:52
+#, c-format
+msgid "cannot create DHCPv6 socket: %s"
+msgstr ""
+
+#: dhcp6.c:73
+#, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"
+msgstr ""
+
+#: dhcp6.c:85
+#, c-format
+msgid "failed to bind DHCPv6 server socket: %s"
+msgstr ""
+
+#: rfc3315.c:157
+#, c-format
+msgid "no address range available for DHCPv6 request from relay at %s"
+msgstr ""
+
+#: rfc3315.c:166
+#, c-format
+msgid "no address range available for DHCPv6 request via %s"
+msgstr ""
+
+#: rfc3315.c:303
+#, c-format
+msgid "%u available DHCPv6 subnet: %s/%d"
+msgstr ""
+
+#: rfc3315.c:386
+#, c-format
+msgid "%u vendor class: %u"
+msgstr ""
+
+#: rfc3315.c:434
+#, c-format
+msgid "%u client MAC address: %s"
+msgstr ""
+
+#: rfc3315.c:673
+#, c-format
+msgid "unknown prefix-class %d"
+msgstr ""
+
+#: rfc3315.c:816 rfc3315.c:911
+msgid "address unavailable"
+msgstr ""
+
+#: rfc3315.c:828 rfc3315.c:959 rfc3315.c:1292
+msgid "success"
+msgstr ""
+
+#: rfc3315.c:843 rfc3315.c:852 rfc3315.c:967 rfc3315.c:969
+msgid "no addresses available"
+msgstr ""
+
+#: rfc3315.c:946
+msgid "not on link"
+msgstr ""
+
+#: rfc3315.c:1019 rfc3315.c:1204 rfc3315.c:1281
+msgid "no binding found"
+msgstr ""
+
+#: rfc3315.c:1057
+msgid "deprecated"
+msgstr ""
+
+#: rfc3315.c:1062
+msgid "address invalid"
+msgstr ""
+
+#: rfc3315.c:1109
+msgid "confirm failed"
+msgstr ""
+
+#: rfc3315.c:1125
+msgid "all addresses still on link"
+msgstr ""
+
+#: rfc3315.c:1213
+msgid "release received"
+msgstr ""
+
+#: rfc3315.c:2140
+msgid "Cannot multicast to DHCPv6 server without correct interface"
+msgstr ""
+
+#: dhcp-common.c:145
+#, c-format
+msgid "Ignoring duplicate dhcp-option %d"
+msgstr ""
+
+#: dhcp-common.c:222
+#, c-format
+msgid "%u tags: %s"
+msgstr ""
+
+#: dhcp-common.c:407
+#, c-format
+msgid "%s has more than one address in hostsfile, using %s for DHCP"
+msgstr ""
+
+#: dhcp-common.c:430
+#, c-format
+msgid "duplicate IP address %s (%s) in dhcp-config directive"
+msgstr ""
+
+#: dhcp-common.c:494
+#, c-format
+msgid "failed to set SO_BINDTODEVICE on DHCP socket: %s"
+msgstr ""
+
+#: dhcp-common.c:615
+#, c-format
+msgid "Known DHCP options:\n"
+msgstr ""
+
+#: dhcp-common.c:626
+#, c-format
+msgid "Known DHCPv6 options:\n"
+msgstr ""
+
+#: dhcp-common.c:823
+msgid ", prefix deprecated"
+msgstr ""
+
+#: dhcp-common.c:826
+#, c-format
+msgid ", lease time "
+msgstr ""
+
+#: dhcp-common.c:868
+#, c-format
+msgid "%s stateless on %s%.0s%.0s%s"
+msgstr ""
+
+#: dhcp-common.c:870
+#, c-format
+msgid "%s, static leases only on %.0s%s%s%.0s"
+msgstr ""
+
+#: dhcp-common.c:872
+#, c-format
+msgid "%s, proxy on subnet %.0s%s%.0s%.0s"
+msgstr ""
+
+#: dhcp-common.c:873
+#, c-format
+msgid "%s, IP range %s -- %s%s%.0s"
+msgstr ""
+
+#: dhcp-common.c:886
+#, c-format
+msgid "DHCPv4-derived IPv6 names on %s%s"
+msgstr ""
+
+#: dhcp-common.c:889
+#, c-format
+msgid "router advertisement on %s%s"
+msgstr ""
+
+#: dhcp-common.c:900
+#, c-format
+msgid "DHCP relay from %s to %s via %s"
+msgstr ""
+
+#: dhcp-common.c:902
+#, c-format
+msgid "DHCP relay from %s to %s"
+msgstr ""
+
+#: radv.c:110
+#, c-format
+msgid "cannot create ICMPv6 socket: %s"
+msgstr ""
+
+#: auth.c:449
+#, c-format
+msgid "ignoring zone transfer request from %s"
+msgstr ""
+
+#: ipset.c:95
+#, c-format
+msgid "failed to find kernel version: %s"
+msgstr ""
+
+#: ipset.c:114
+#, c-format
+msgid "failed to create IPset control socket: %s"
+msgstr ""
+
+#: ipset.c:233
+#, c-format
+msgid "failed to update ipset %s: %s"
+msgstr ""
+
+#: dnssec.c:527
+msgid "system time considered valid, now checking DNSSEC signature timestamps."
+msgstr ""
+
+#: blockdata.c:58
+#, c-format
+msgid "DNSSEC memory in use %u, max %u, allocated %u"
+msgstr ""
+
+#: tables.c:61
+#, c-format
+msgid "failed to access pf devices: %s"
+msgstr ""
+
+#: tables.c:74
+#, c-format
+msgid "warning: no opened pf devices %s"
+msgstr ""
+
+#: tables.c:82
+#, c-format
+msgid "error: cannot use table name %s"
+msgstr ""
+
+#: tables.c:90
+#, c-format
+msgid "error: cannot strlcpy table name %s"
+msgstr ""
+
+#: tables.c:101
+#, c-format
+msgid "IPset: error:%s"
+msgstr ""
+
+#: tables.c:108
+msgid "info: table created"
+msgstr ""
+
+#: tables.c:134
+#, c-format
+msgid "warning: DIOCR%sADDRS: %s"
+msgstr ""
+
+#: tables.c:138
+#, c-format
+msgid "%d addresses %s"
+msgstr ""
+
+#: inotify.c:62
+#, c-format
+msgid "cannot access path %s: %s"
+msgstr ""
+
+#: inotify.c:95
+#, c-format
+msgid "failed to create inotify: %s"
+msgstr ""
+
+#: inotify.c:111
+#, c-format
+msgid "too many symlinks following %s"
+msgstr ""
+
+#: inotify.c:127
+#, c-format
+msgid "directory %s for resolv-file is missing, cannot poll"
+msgstr ""
+
+#: inotify.c:131 inotify.c:168
+#, c-format
+msgid "failed to create inotify for %s: %s"
+msgstr ""
+
+#: inotify.c:153
+#, c-format
+msgid "bad dynamic directory %s: %s"
+msgstr ""
+
+#: inotify.c:255
+#, c-format
+msgid "inotify, new or changed file %s"
+msgstr ""
diff --git a/po/fr.po b/po/fr.po
new file mode 100755
index 0000000..426e3d5
--- /dev/null
+++ b/po/fr.po
@@ -0,0 +1,2378 @@
+# French translations for dnsmasq package.
+# This file is put in the public domain.
+# Lionel Tricon <lionel.tricon@free.fr>, 2005.
+# Translation completed by Gildas Le Nadan <3ntr0p13@gmail.com>
+msgid ""
+msgstr ""
+"Project-Id-Version: dnsmasq 2.67\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-06-18 12:24+0100\n"
+"PO-Revision-Date: 2017-07-17 18:30+0100\n"
+"Last-Translator:  Gildas Le Nadan <3ntr0p13@gmail.com>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: cache.c:513
+msgid "Internal error in cache."
+msgstr ""
+
+#: cache.c:923
+#, c-format
+msgid "failed to load names from %s: %s"
+msgstr "Impossible de charger les noms à partir de %s : %s"
+
+#: cache.c:949 dhcp.c:867
+#, c-format
+msgid "bad address at %s line %d"
+msgstr "mauvaise adresse dans %s ligne %d"
+
+#: cache.c:1002 dhcp.c:883
+#, c-format
+msgid "bad name at %s line %d"
+msgstr "mauvais nom dans %s ligne %d"
+
+#: cache.c:1011 dhcp.c:958
+#, c-format
+msgid "read %s - %d addresses"
+msgstr "lecture %s - %d adresses"
+
+#: cache.c:1124
+msgid "cleared cache"
+msgstr "cache vidé"
+
+#: cache.c:1153
+#, c-format
+msgid "No IPv4 address found for %s"
+msgstr "Aucune adresse IPv4 trouvée pour %s"
+
+#: cache.c:1232
+#, c-format
+msgid "%s is a CNAME, not giving it to the DHCP lease of %s"
+msgstr "%s est un CNAME, il ne sera pas donné au bail DHCP de %s"
+
+#: cache.c:1256
+#, c-format
+msgid "not giving name %s to the DHCP lease of %s because the name exists in %s with address %s"
+msgstr "ne donne pas de nom %s au bail DHCP de %s parce-que le nom existe dans %s avec l'adresse %s"
+
+#: cache.c:1413
+#, c-format
+msgid "time %lu"
+msgstr "horodatage %lu"
+
+#: cache.c:1414
+#, c-format
+msgid "cache size %d, %d/%d cache insertions re-used unexpired cache entries."
+msgstr "taille de cache %d, %d/%d insertions dans le cache entrées non-expirées réutilisées"
+
+#: cache.c:1416
+#, c-format
+msgid "queries forwarded %u, queries answered locally %u"
+msgstr "requêtes transmises %u, requêtes résolues localement %u"
+
+#: cache.c:1419
+#, fuzzy, c-format
+msgid "queries for authoritative zones %u"
+msgstr "Configure la durée de vie (Time To Live) pour les réponses faisant autorité"
+
+#: cache.c:1445
+#, c-format
+msgid "server %s#%d: queries sent %u, retried or failed %u"
+msgstr "serveur %s#%d: requêtes envoyées %u, requêtes réessayées ou échouées %u"
+
+#: util.c:47
+#, c-format
+msgid "failed to seed the random number generator: %s"
+msgstr "impossible d'initialiser le générateur de nombre aléatoire : %s"
+
+#: util.c:224
+msgid "failed to allocate memory"
+msgstr "impossible d'allouer la mémoire"
+
+#: util.c:277 option.c:619
+msgid "could not get memory"
+msgstr "impossible d'allouer de la mémoire"
+
+#: util.c:287
+#, c-format
+msgid "cannot create pipe: %s"
+msgstr "Ne peut pas créer le tube %s : %s"
+
+#: util.c:295
+#, c-format
+msgid "failed to allocate %d bytes"
+msgstr "impossible d'allouer %d octets"
+
+#: util.c:464
+#, c-format
+msgid "infinite"
+msgstr "illimité(e)"
+
+#: option.c:344
+msgid "Specify local address(es) to listen on."
+msgstr "Spécifie la ou les adresse(s) locales où le démon doit se mettre à l'écoute."
+
+#: option.c:345
+msgid "Return ipaddr for all hosts in specified domains."
+msgstr "Retourne les adresses IP pour toutes les machines présentes dans les domaines spécifiés"
+
+#: option.c:346
+msgid "Fake reverse lookups for RFC1918 private address ranges."
+msgstr "Traduction inverse truquée pour la plage d'adresse privée RFC1918"
+
+#: option.c:347
+msgid "Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."
+msgstr "Traite l'adresse IP comme un domaine inexistant NXDOMAIN (contourne le systeme de redirection de Verisign)"
+
+#: option.c:348
+#, c-format
+msgid "Specify the size of the cache in entries (defaults to %s)."
+msgstr "Spécifie le nombre d'entrées que contiendra le cache (par défaut : %s)."
+
+#: option.c:349
+#, c-format
+msgid "Specify configuration file (defaults to %s)."
+msgstr "Spécifie le nom du fichier de configuration (par défaut : %s)"
+
+#: option.c:350
+msgid "Do NOT fork into the background: run in debug mode."
+msgstr "Ne passe pas en tâche de fond : démarre en mode debug"
+
+#: option.c:351
+msgid "Do NOT forward queries with no domain part."
+msgstr "Ne retransmet pas les requêtes qui n'ont pas de domaine."
+
+#: option.c:352
+msgid "Return self-pointing MX records for local hosts."
+msgstr "Retourne les champs MX pour les machines locales."
+
+#: option.c:353
+msgid "Expand simple names in /etc/hosts with domain-suffix."
+msgstr "Etend les noms uniques des machines dans /etc/hosts avec le suffixe du domaine."
+
+#: option.c:354
+msgid "Don't forward spurious DNS requests from Windows hosts."
+msgstr "Ne retransmet pas les fausses requêtes DNS en provenance des machines Windows."
+
+#: option.c:355
+msgid "Enable DHCP in the range given with lease duration."
+msgstr "Autorise DHCP dans la plage d'adresses donnée sur la durée de validité du bail."
+
+#: option.c:356
+#, c-format
+msgid "Change to this group after startup (defaults to %s)."
+msgstr "On change pour ce groupe après le démarrage (par défaut : %s)."
+
+#: option.c:357
+msgid "Set address or hostname for a specified machine."
+msgstr "On assigne une adresse ou un nom pour une machine spécifiée."
+
+#: option.c:358
+msgid "Read DHCP host specs from file."
+msgstr "Lecture des spécifications d'hôtes DHCP à partir du fichier"
+
+#: option.c:359
+msgid "Read DHCP option specs from file."
+msgstr "Lecture des options DHCP à partir du fichier"
+
+#: option.c:360
+#, fuzzy
+msgid "Read DHCP host specs from a directory."
+msgstr "Lecture des spécifications d'hôtes DHCP à partir du fichier"
+
+#: option.c:361
+#, fuzzy
+msgid "Read DHCP options from a directory."
+msgstr "Lecture des options DHCP à partir du fichier"
+
+#: option.c:362
+msgid "Evaluate conditional tag expression."
+msgstr "Expression d'évaluation conditionnelle d'étiquette"
+
+#: option.c:363
+#, c-format
+msgid "Do NOT load %s file."
+msgstr "Ne charge PAS le fichier %s."
+
+#: option.c:364
+#, c-format
+msgid "Specify a hosts file to be read in addition to %s."
+msgstr "Spécifie un nom de fichier hosts à lire en complément de %s"
+
+#: option.c:365
+#, fuzzy
+msgid "Read hosts files from a directory."
+msgstr "Lecture des spécifications d'hôtes DHCP à partir du fichier"
+
+#: option.c:366
+msgid "Specify interface(s) to listen on."
+msgstr "Spécifie la ou les interface(s) où le démon doit se mettre à l'écoute."
+
+#: option.c:367
+msgid "Specify interface(s) NOT to listen on."
+msgstr "Spécifie la ou les interface(s) que le démon ne doit PAS traiter."
+
+#
+#: option.c:368
+msgid "Map DHCP user class to tag."
+msgstr "Associe les classes d'utilisateurs ('user class') DHCP aux options."
+
+#: option.c:369
+msgid "Map RFC3046 circuit-id to tag."
+msgstr "Associe les identifiants de circuits RFC3046 ('circuit-id') aux options"
+
+#: option.c:370
+msgid "Map RFC3046 remote-id to tag."
+msgstr "Associe les identifiants distants RFC3046 ('remote-id') aux options"
+
+#: option.c:371
+msgid "Map RFC3993 subscriber-id to tag."
+msgstr "Associe les identifiants de souscripteurs RFC3993 ('subscriber-id') aux options"
+
+#
+#: option.c:372
+msgid "Don't do DHCP for hosts with tag set."
+msgstr "Ne pas autoriser DHCP pour les machines énumerées dans les options."
+
+#
+#: option.c:373
+msgid "Force broadcast replies for hosts with tag set."
+msgstr "Forcer les réponses par 'broadcast' pour les machines énumerées dans les options."
+
+#: option.c:374
+msgid "Do NOT fork into the background, do NOT run in debug mode."
+msgstr "Ne passe pas en tâche de fond, ne pas s'exécuter en mode debug."
+
+#: option.c:375
+msgid "Assume we are the only DHCP server on the local network."
+msgstr "On considère que l'on est le seul serveur DHCP sur le réseau local."
+
+#: option.c:376
+#, c-format
+msgid "Specify where to store DHCP leases (defaults to %s)."
+msgstr "Spécifie où il faut sauvegarder les baux DHCP (par défaut : %s)."
+
+#: option.c:377
+msgid "Return MX records for local hosts."
+msgstr "Retourne les champs MX pour les machines locales."
+
+#: option.c:378
+msgid "Specify an MX record."
+msgstr "Spécifie un champ MX."
+
+#: option.c:379
+msgid "Specify BOOTP options to DHCP server."
+msgstr "Spécifie les options BOOTP pour le serveur DHCP."
+
+#: option.c:380
+#, c-format
+msgid "Do NOT poll %s file, reload only on SIGHUP."
+msgstr "Ne pas scruter le fichier %s, ne recharger les modifications que sur réception du signal SIGHUP."
+
+#: option.c:381
+msgid "Do NOT cache failed search results."
+msgstr "Ne place pas en cache le résultat des requêtes qui ont échouées."
+
+#: option.c:382
+#, c-format
+msgid "Use nameservers strictly in the order given in %s."
+msgstr "Utilise les serveurs de noms dans l'ordre donné dans %s."
+
+#
+#: option.c:383
+msgid "Specify options to be sent to DHCP clients."
+msgstr "Options supplémentaires à associer aux clients DHCP."
+
+#: option.c:384
+msgid "DHCP option sent even if the client does not request it."
+msgstr "Option DHCP envoyée même si le client de la demande pas."
+
+#: option.c:385
+msgid "Specify port to listen for DNS requests on (defaults to 53)."
+msgstr "Spécifie le port où il faut écouter les requêtes DNS (par défaut : 53)."
+
+#: option.c:386
+#, c-format
+msgid "Maximum supported UDP packet size for EDNS.0 (defaults to %s)."
+msgstr "Taille maximale des paquets UDP supportés pour EDNS.0 (par défaut : %s)."
+
+#
+#: option.c:387
+msgid "Log DNS queries."
+msgstr "Enregistre les requêtes DNS dans un journal d'activité."
+
+#
+#: option.c:388
+msgid "Force the originating port for upstream DNS queries."
+msgstr "Force le port d'origine pour les requêtes vers les serveurs amonts."
+
+#: option.c:389
+msgid "Do NOT read resolv.conf."
+msgstr "Ne pas lire le fichier resolv.conf."
+
+#: option.c:390
+#, c-format
+msgid "Specify path to resolv.conf (defaults to %s)."
+msgstr "Spécifie le chemin pour le fichier resolv.conf (par défaut : %s)."
+
+#: option.c:391
+#, fuzzy
+msgid "Specify path to file with server= options"
+msgstr "Spécifie un chemin pour le fichier PID (par défaut : %s)."
+
+#: option.c:392
+msgid "Specify address(es) of upstream servers with optional domains."
+msgstr "Spécifie la ou les adresses des serveurs amonts avec des domaines optionels."
+
+#: option.c:393
+#, fuzzy
+msgid "Specify address of upstream servers for reverse address queries"
+msgstr "Spécifie la ou les adresses des serveurs amonts avec des domaines optionels."
+
+#: option.c:394
+msgid "Never forward queries to specified domains."
+msgstr "Ne jamais retransmettre les requêtes pour les domaines spécifiés."
+
+#: option.c:395
+msgid "Specify the domain to be assigned in DHCP leases."
+msgstr "Spécifie le domaine qui doit etre assigné aux baux DHCP."
+
+#: option.c:396
+msgid "Specify default target in an MX record."
+msgstr "Spécifie la cible par défaut dans un champ MX."
+
+#: option.c:397
+msgid "Specify time-to-live in seconds for replies from /etc/hosts."
+msgstr "Spécifie le TTL en secondes pour les réponses qui utilisent /etc/hosts."
+
+#
+#: option.c:398
+msgid "Specify time-to-live in seconds for negative caching."
+msgstr "Spécifie le TTL en secondes pour les réponses qui utilisent /etc/hosts."
+
+#: option.c:399
+msgid "Specify time-to-live in seconds for maximum TTL to send to clients."
+msgstr "Spécifie, en secondes, la valeur maximum de TTL à renvoyer aux clients."
+
+#
+#: option.c:400
+#, fuzzy
+msgid "Specify time-to-live ceiling for cache."
+msgstr "Spécifie le TTL en secondes pour les réponses qui utilisent /etc/hosts."
+
+#
+#: option.c:401
+#, fuzzy
+msgid "Specify time-to-live floor for cache."
+msgstr "Spécifie le TTL en secondes pour les réponses qui utilisent /etc/hosts."
+
+#: option.c:402
+#, c-format
+msgid "Change to this user after startup. (defaults to %s)."
+msgstr "Change pour cet utilisateur après le démarrage (par défaut : %s)."
+
+#
+#: option.c:403
+msgid "Map DHCP vendor class to tag."
+msgstr "Associe les classes de fournisseurs ('vendor class') DHCP aux options."
+
+#: option.c:404
+msgid "Display dnsmasq version and copyright information."
+msgstr "Affiche la version de Dnsmasq et les informations liées au copyright."
+
+#: option.c:405
+msgid "Translate IPv4 addresses from upstream servers."
+msgstr "Traduit les adresses IPV4 des serveurs amonts."
+
+#: option.c:406
+msgid "Specify a SRV record."
+msgstr "Spécifie un champ SRV."
+
+#: option.c:407
+#, fuzzy
+msgid "Display this message. Use --help dhcp or --help dhcp6 for known DHCP options."
+msgstr "Afficher ce message. Utiliser --help dhcp pour obtenir la liste des options DHCP connues."
+
+#: option.c:408
+#, c-format
+msgid "Specify path of PID file (defaults to %s)."
+msgstr "Spécifie un chemin pour le fichier PID (par défaut : %s)."
+
+#: option.c:409
+#, c-format
+msgid "Specify maximum number of DHCP leases (defaults to %s)."
+msgstr "Spécifie le nombre maximum de baux DHCP (par défaut : %s)."
+
+#: option.c:410
+msgid "Answer DNS queries based on the interface a query was sent to."
+msgstr "Repond aux requêtes DNS en se basant sur l'interface ou a été envoyée la requête."
+
+#: option.c:411
+msgid "Specify TXT DNS record."
+msgstr "Spécifie un champ DNS TXT"
+
+#
+#: option.c:412
+msgid "Specify PTR DNS record."
+msgstr "Spécifie un champ DNS PTR"
+
+#: option.c:413
+msgid "Give DNS name to IPv4 address of interface."
+msgstr "Donne le nom DNS pour l'adresse IPv4 de l'interface."
+
+#: option.c:414
+msgid "Bind only to interfaces in use."
+msgstr "Association uniquement aux interfaces réseau actuellement actives."
+
+#: option.c:415
+#, c-format
+msgid "Read DHCP static host information from %s."
+msgstr "Lecture des informations de DHCP statique à partir de %s."
+
+#: option.c:416
+msgid "Enable the DBus interface for setting upstream servers, etc."
+msgstr "Autorise l'interface DBus pour la configuration des serveurs amonts, etc."
+
+#: option.c:417
+msgid "Do not provide DHCP on this interface, only provide DNS."
+msgstr "Ne pas assurer de fonction DHCP sur cette interface, mais seulement la fonction DNS."
+
+#: option.c:418
+msgid "Enable dynamic address allocation for bootp."
+msgstr "Autorise l'allocation dynamique d'adresse pour bootp."
+
+#
+#: option.c:419
+msgid "Map MAC address (with wildcards) to option set."
+msgstr "Associe l'adresse MAC (avec les jokers) aux options."
+
+#: option.c:420
+msgid "Treat DHCP requests on aliases as arriving from interface."
+msgstr "Traiter les requêtes DHCP sur les alias comme arrivant de l'interface."
+
+#: option.c:421
+msgid "Disable ICMP echo address checking in the DHCP server."
+msgstr "Supprime la vérification d'adresse sur le serveur au moyen de paquets ICMP echo"
+
+#: option.c:422
+msgid "Shell script to run on DHCP lease creation and destruction."
+msgstr "Script shell à exécuter lors de la création ou destruction de bail DHCP."
+
+#: option.c:423
+msgid "Lua script to run on DHCP lease creation and destruction."
+msgstr "Script Lua à exécuter lors de la création ou destruction de bail DHCP."
+
+#: option.c:424
+msgid "Run lease-change scripts as this user."
+msgstr "Lancer le script 'lease-change' avec cet utilisateur."
+
+#: option.c:425
+msgid "Call dhcp-script with changes to local ARP table."
+msgstr ""
+
+#: option.c:426
+msgid "Read configuration from all the files in this directory."
+msgstr "Lecture de la configuration dans tous les fichiers de ce répertoire."
+
+#
+#: option.c:427
+msgid "Log to this syslog facility or file. (defaults to DAEMON)"
+msgstr "Enregistrer les journaux d'activité dans cette facilité syslog. (défaut : DAEMON)"
+
+#: option.c:428
+msgid "Do not use leasefile."
+msgstr "Ne pas utiliser de fichier de baux."
+
+#: option.c:429
+#, c-format
+msgid "Maximum number of concurrent DNS queries. (defaults to %s)"
+msgstr "Spécifie le nombre maximum de requêtes DHCP concurrentes (par défaut : %s)."
+
+#: option.c:430
+#, c-format
+msgid "Clear DNS cache when reloading %s."
+msgstr "Vider le cache DNS lors du rechargement de %s."
+
+#: option.c:431
+msgid "Ignore hostnames provided by DHCP clients."
+msgstr "Ignorer les noms d'hôtes fournis par les clients DHCP"
+
+#: option.c:432
+msgid "Do NOT reuse filename and server fields for extra DHCP options."
+msgstr "Ne pas réutiliser les champs nom de fichier et serveur dans les options DHCP supplémentaires."
+
+#: option.c:433
+msgid "Enable integrated read-only TFTP server."
+msgstr "Activer le server TFTP intégré (fonctionnant en lecture seulement)"
+
+#: option.c:434
+msgid "Export files by TFTP only from the specified subtree."
+msgstr "N'exporter par TFTP que les fichiers de l'arborescence de fichier spécifiée"
+
+#: option.c:435
+#, fuzzy
+msgid "Add client IP or hardware address to tftp-root."
+msgstr "Ajouter les adresses IP clientes à la racine tftp ('tftp-root')."
+
+#: option.c:436
+msgid "Allow access only to files owned by the user running dnsmasq."
+msgstr "Accès aux seuls fichiers appartenants à l'utilisateur sous lequel tourne dnsmasq"
+
+#: option.c:437
+msgid "Do not terminate the service if TFTP directories are inaccessible."
+msgstr ""
+
+#: option.c:438
+#, fuzzy, c-format
+msgid "Maximum number of concurrent TFTP transfers (defaults to %s)."
+msgstr "Spécifie le nombre maximum de transfert TFTP concurrents (défaut : %s)."
+
+#: option.c:439
+#, fuzzy
+msgid "Maximum MTU to use for TFTP transfers."
+msgstr "Spécifie le nombre maximum de transfert TFTP concurrents (défaut : %s)."
+
+#: option.c:440
+msgid "Disable the TFTP blocksize extension."
+msgstr "Désactivation de l'extension TFTP « taille de bloc »"
+
+#: option.c:441
+msgid "Convert TFTP filenames to lowercase"
+msgstr "Convertis les noms de fichiers TFTP en minuscule"
+
+#: option.c:442
+msgid "Ephemeral port range for use by TFTP transfers."
+msgstr "Gamme de ports dans laquelle seront choisis les ports temporaires utilisés dans les transferts TFTP."
+
+#: option.c:443
+msgid "Extra logging for DHCP."
+msgstr "Traces supplémentaires pour le DHCP."
+
+#: option.c:444
+msgid "Enable async. logging; optionally set queue length."
+msgstr "Active l'écriture de traces en mode asynchrone. Peut prendre en option la valeur de la longueur de la queue."
+
+#: option.c:445
+msgid "Stop DNS rebinding. Filter private IP ranges when resolving."
+msgstr "Stopper la réassociation DNS ('DNS rebinding'). Filtre les gammes d'adresses IP privées lors de la résolution."
+
+#: option.c:446
+msgid "Allow rebinding of 127.0.0.0/8, for RBL servers."
+msgstr "Autorise la réassociation de 127.0.0/8, pour les serveurs RBL (Realtime Blackhole List)"
+
+#: option.c:447
+msgid "Inhibit DNS-rebind protection on this domain."
+msgstr "Désactive la protection contre les réassociation DNS pour ce domaine"
+
+#: option.c:448
+msgid "Always perform DNS queries to all servers."
+msgstr "Toujours effectuer les requêtes DNS à tous les serveurs."
+
+#
+#: option.c:449
+msgid "Set tag if client includes matching option in request."
+msgstr "Spécifie le label si le client inclus l'option dans la requête."
+
+#: option.c:450
+msgid "Use alternative ports for DHCP."
+msgstr "Utiliser des ports alternatifs pour le DHCP."
+
+#
+#: option.c:451
+msgid "Specify NAPTR DNS record."
+msgstr "Spécifie un champ DNS NAPTR."
+
+#: option.c:452
+msgid "Specify lowest port available for DNS query transmission."
+msgstr "Définie le plus petit port utilisé pour la transmission d'une requête DNS."
+
+#: option.c:453
+#, fuzzy
+msgid "Specify highest port available for DNS query transmission."
+msgstr "Définie le plus petit port utilisé pour la transmission d'une requête DNS."
+
+#: option.c:454
+msgid "Use only fully qualified domain names for DHCP clients."
+msgstr "Utilise seulement les noms de domaine pleinement qualifiés pour les clients DHCP."
+
+#: option.c:455
+msgid "Generate hostnames based on MAC address for nameless clients."
+msgstr "Génère les noms d'hôtes à partir de l'adresse MAC pour les clients sans nom."
+
+#: option.c:456
+msgid "Use these DHCP relays as full proxies."
+msgstr "Utilise ces relais DHCP en temps que proxy complets."
+
+#: option.c:457
+msgid "Relay DHCP requests to a remote server"
+msgstr "Requêtes de relais DHCP à un serveur distant"
+
+#: option.c:458
+msgid "Specify alias name for LOCAL DNS name."
+msgstr "Spécifie un alias pour un nom DNS local."
+
+#
+#: option.c:459
+msgid "Prompt to send to PXE clients."
+msgstr "Invite à envoyer aux clients PXE."
+
+#: option.c:460
+msgid "Boot service for PXE menu."
+msgstr "Service de démarrage pour menu PXE."
+
+#: option.c:461
+msgid "Check configuration syntax."
+msgstr "vérification de la syntaxe de la configuration."
+
+#: option.c:462
+msgid "Add requestor's MAC address to forwarded DNS queries."
+msgstr "Ajoute l'adresse MAC du requêteur aux requêtes DNS transmises"
+
+#: option.c:463
+#, fuzzy
+msgid "Add specified IP subnet to forwarded DNS queries."
+msgstr "Ajoute l'adresse MAC du requêteur aux requêtes DNS transmises"
+
+#: option.c:464
+#, fuzzy
+msgid "Add client identification to forwarded DNS queries."
+msgstr "Ajoute l'adresse MAC du requêteur aux requêtes DNS transmises"
+
+#: option.c:465
+msgid "Proxy DNSSEC validation results from upstream nameservers."
+msgstr "Copie dans la réponse DNS le résultat de la validation DNSSEC effectuée par les serveurs DNS amonts."
+
+#: option.c:466
+msgid "Attempt to allocate sequential IP addresses to DHCP clients."
+msgstr "Essaie d'allouer des adresses IP séquentielles aux clients DHCP."
+
+#: option.c:467
+msgid "Copy connection-track mark from queries to upstream connections."
+msgstr "Copie les marques de suivi de connexion pour les requêtes amont."
+
+#: option.c:468
+msgid "Allow DHCP clients to do their own DDNS updates."
+msgstr "Autoriser les clients DHCP à faire leurs propres mises à jour DDNS (Dynamic DNS)"
+
+#: option.c:469
+msgid "Send router-advertisements for interfaces doing DHCPv6"
+msgstr "Envoyer des annonces de routeurs pour toutes les interfaces faisant du DHCPv6"
+
+#: option.c:470
+msgid "Specify DUID_EN-type DHCPv6 server DUID"
+msgstr "Spécifie pour le serveur DHCPv6 un identifiant unique DHCP (DUID) basé sur un numéro unique de vendeur (DUID_EN)"
+
+#: option.c:471
+msgid "Specify host (A/AAAA and PTR) records"
+msgstr "Spécifie les enregistrements (A/AAAA et PTR) d'un hôte."
+
+#: option.c:472
+msgid "Specify arbitrary DNS resource record"
+msgstr "Définie une resource DNS d'un type spécifique"
+
+#: option.c:473
+msgid "Bind to interfaces in use - check for new interfaces"
+msgstr "Se lie aux interfaces préexistantes - vérifie l'apparition de nouvelles interfaces"
+
+#: option.c:474
+msgid "Export local names to global DNS"
+msgstr "Exporte les noms locaux dans le DNS global"
+
+#: option.c:475
+msgid "Domain to export to global DNS"
+msgstr "Domaine à exporter dans le DNS global"
+
+#: option.c:476
+msgid "Set TTL for authoritative replies"
+msgstr "Configure la durée de vie (Time To Live) pour les réponses faisant autorité"
+
+#: option.c:477
+#, fuzzy
+msgid "Set authoritative zone information"
+msgstr "Configure les informations pour une zone de nom faisant autorité"
+
+#: option.c:478
+msgid "Secondary authoritative nameservers for forward domains"
+msgstr "Serveurs de noms secondaires faisant autorité pour les domaines délégués"
+
+#: option.c:479
+msgid "Peers which are allowed to do zone transfer"
+msgstr "Pairs autorisés à faire des transferts de zone"
+
+#: option.c:480
+msgid "Specify ipsets to which matching domains should be added"
+msgstr "Spécifie les ipsets auxquels les domaines correspondants doivent-être ajoutés"
+
+#: option.c:481
+#, fuzzy
+msgid "Specify a domain and address range for synthesised names"
+msgstr "Spécifie un domaine et une plage d'adresses pour les noms auto-générés"
+
+#: option.c:482
+msgid "Activate DNSSEC validation"
+msgstr ""
+
+#: option.c:483
+msgid "Specify trust anchor key digest."
+msgstr ""
+
+#: option.c:484
+msgid "Disable upstream checking for DNSSEC debugging."
+msgstr ""
+
+#: option.c:485
+msgid "Ensure answers without DNSSEC are in unsigned zones."
+msgstr ""
+
+#: option.c:486
+msgid "Don't check DNSSEC signature timestamps until first cache-reload"
+msgstr ""
+
+#: option.c:487
+msgid "Timestamp file to verify system clock for DNSSEC"
+msgstr ""
+
+#: option.c:489
+msgid "Specify DHCPv6 prefix class"
+msgstr "Spécifie le préfixe de classe DHCPv6"
+
+#: option.c:491
+msgid "Set MTU, priority, resend-interval and router-lifetime"
+msgstr ""
+
+#: option.c:492
+msgid "Do not log routine DHCP."
+msgstr ""
+
+#: option.c:493
+msgid "Do not log routine DHCPv6."
+msgstr ""
+
+#: option.c:494
+msgid "Do not log RA."
+msgstr ""
+
+#: option.c:495
+msgid "Accept queries only from directly-connected networks."
+msgstr ""
+
+#: option.c:496
+msgid "Detect and remove DNS forwarding loops."
+msgstr ""
+
+#: option.c:497
+msgid "Ignore DNS responses containing ipaddr."
+msgstr ""
+
+#: option.c:498
+msgid "Set TTL in DNS responses with DHCP-derived addresses."
+msgstr ""
+
+#: option.c:499
+msgid "Delay DHCP replies for at least number of seconds."
+msgstr ""
+
+#: option.c:703
+#, c-format
+msgid ""
+"Usage: dnsmasq [options]\n"
+"\n"
+msgstr ""
+"Usage : dnsmasq [options]\n"
+"\n"
+
+#: option.c:705
+#, c-format
+msgid "Use short options only on the command line.\n"
+msgstr "Utilisez les options courtes uniquement sur la ligne de commande.\n"
+
+#: option.c:707
+#, c-format
+msgid "Valid options are:\n"
+msgstr "Les options valides sont :\n"
+
+#
+#: option.c:754 option.c:868
+msgid "bad address"
+msgstr "mauvaise adresse"
+
+#: option.c:779 option.c:783
+msgid "bad port"
+msgstr "numéro de port incorrect"
+
+#: option.c:797 option.c:826 option.c:861
+msgid "interface binding not supported"
+msgstr "association d'interface non supportée"
+
+#: option.c:821 option.c:856
+msgid "interface can only be specified once"
+msgstr ""
+
+#
+#: option.c:835 option.c:3800
+msgid "bad interface name"
+msgstr "nom d'interface invalide"
+
+#: option.c:1062
+msgid "unsupported encapsulation for IPv6 option"
+msgstr "encapsulation d'option non supportée pour IPv6"
+
+#: option.c:1076
+msgid "bad dhcp-option"
+msgstr "mauvaise valeur de 'dhcp-option'"
+
+#
+#: option.c:1144
+msgid "bad IP address"
+msgstr "mauvaise adresse IP"
+
+#
+#: option.c:1147 option.c:1286 option.c:3070
+msgid "bad IPv6 address"
+msgstr "mauvaise adresse IPv6"
+
+#
+#: option.c:1240
+#, fuzzy
+msgid "bad IPv4 address"
+msgstr "mauvaise adresse IPv6"
+
+#: option.c:1313 option.c:1407
+msgid "bad domain in dhcp-option"
+msgstr "mauvais domaine dans dhcp-option"
+
+#: option.c:1445
+msgid "dhcp-option too long"
+msgstr "dhcp-option trop long"
+
+#: option.c:1452
+msgid "illegal dhcp-match"
+msgstr "valeur illégale pour 'dhcp-match'"
+
+#: option.c:1514
+msgid "illegal repeated flag"
+msgstr "Une option ne pouvant être spécifié qu'une seule fois à été donnée plusieurs fois"
+
+#: option.c:1522
+msgid "illegal repeated keyword"
+msgstr "Mot-clef ne pouvant être répété"
+
+#: option.c:1593 option.c:4434
+#, c-format
+msgid "cannot access directory %s: %s"
+msgstr "Ne peut pas lire le répertoire %s : %s"
+
+#: option.c:1639 tftp.c:537
+#, c-format
+msgid "cannot access %s: %s"
+msgstr "Ne peut pas lire %s : %s"
+
+#: option.c:1727
+msgid "setting log facility is not possible under Android"
+msgstr "Sous android, impossible de positionner la cible (facility) pour les traces (logs)."
+
+#: option.c:1736
+msgid "bad log facility"
+msgstr "Mauvaise cible (facility) pour les traces."
+
+#: option.c:1789
+msgid "bad MX preference"
+msgstr "préference MX incorrecte"
+
+#: option.c:1794
+msgid "bad MX name"
+msgstr "nom MX incorrect"
+
+#: option.c:1808
+msgid "bad MX target"
+msgstr "valeur MX cible incorrecte"
+
+#: option.c:1820
+msgid "cannot run scripts under uClinux"
+msgstr "ne peut exécuter de script sous uClinux"
+
+#: option.c:1822
+msgid "recompile with HAVE_SCRIPT defined to enable lease-change scripts"
+msgstr "recompiler en définissant HAVE_SCRIPT pour permettre l'exécution de scripts shell au changement de bail (lease-change)"
+
+#: option.c:1826
+msgid "recompile with HAVE_LUASCRIPT defined to enable Lua scripts"
+msgstr "recompiler en définissant HAVE_LUASCRIPT pour permettre l'exécution de scripts LUA au changement de bail (lease-change)"
+
+#: option.c:2095 option.c:2106 option.c:2143 option.c:2199 option.c:2482
+msgid "bad prefix"
+msgstr "mauvais préfixe"
+
+#: option.c:2504
+msgid "recompile with HAVE_IPSET defined to enable ipset directives"
+msgstr "recompiler en définissant HAVE_IPSET pour permettre l'utilisation de directives de groupes d'IP (IPset)"
+
+#
+#: option.c:2713
+msgid "bad port range"
+msgstr "gamme de ports incorrecte"
+
+#: option.c:2738
+msgid "bad bridge-interface"
+msgstr "interface-pont incorrecte"
+
+#: option.c:2798
+msgid "only one tag allowed"
+msgstr "une seule étiquette est autorisée"
+
+#: option.c:2818 option.c:2830 option.c:2939 option.c:2944 option.c:2983
+msgid "bad dhcp-range"
+msgstr "plage d'adresses DHCP (dhcp-range) incorrecte"
+
+#: option.c:2845
+msgid "inconsistent DHCP range"
+msgstr "plage d'adresses DHCP incohérente"
+
+#: option.c:2907
+msgid "prefix length must be exactly 64 for RA subnets"
+msgstr "la taille du préfixe doit être exactement 64 pour les sous-réseaux d'annonces de routeurs (RA)"
+
+#: option.c:2909
+msgid "prefix length must be exactly 64 for subnet constructors"
+msgstr "la taille du préfixe doit être exactement 64 pour le constructeur de sous-réseaux"
+
+#: option.c:2913
+msgid "prefix length must be at least 64"
+msgstr "la taille de préfixe doit être au minimum 64"
+
+#: option.c:2916
+msgid "inconsistent DHCPv6 range"
+msgstr "plage d'adresses DHCPv6 incohérente"
+
+#: option.c:2927
+msgid "prefix must be zero with \"constructor:\" argument"
+msgstr "le préfixe doit avoir une taille de 0 lorsque l'argument \"constructor:\" est utilisé"
+
+#: option.c:3040 option.c:3088
+msgid "bad hex constant"
+msgstr "mauvaise constante hexadecimale"
+
+#: option.c:3062
+msgid "cannot match tags in --dhcp-host"
+msgstr "L'utilisation de labels est prohibée dans --dhcp-host"
+
+#: option.c:3110
+#, c-format
+msgid "duplicate dhcp-host IP address %s"
+msgstr "adresse IP dhcp-host dupliquée dans %s."
+
+#
+#: option.c:3168
+msgid "bad DHCP host name"
+msgstr "nom d'hôte DHCP incorrect"
+
+#: option.c:3250
+msgid "bad tag-if"
+msgstr "mauvaise étiquette tag-if"
+
+#: option.c:3607 option.c:4030
+msgid "invalid port number"
+msgstr "numéro de port invalide"
+
+#
+#: option.c:3669
+msgid "bad dhcp-proxy address"
+msgstr "adresse dhcp-proxy incorrecte"
+
+#: option.c:3695
+msgid "Bad dhcp-relay"
+msgstr "valeur incorrecte pour le relais DHCP (dhcp-relay)"
+
+#: option.c:3736
+msgid "bad RA-params"
+msgstr ""
+
+#: option.c:3745
+msgid "bad DUID"
+msgstr "mauvais identifiant unique DHCP (DUID)"
+
+#
+#: option.c:3787
+msgid "invalid alias range"
+msgstr "poids invalide"
+
+#: option.c:3841 option.c:3853
+msgid "bad CNAME"
+msgstr "mauvais CNAME"
+
+#: option.c:3857
+msgid "duplicate CNAME"
+msgstr "ce CNAME existe déja"
+
+#
+#: option.c:3880
+msgid "bad PTR record"
+msgstr "mauvais champ PTR"
+
+#
+#: option.c:3911
+msgid "bad NAPTR record"
+msgstr "mauvais champ NAPTR"
+
+#
+#: option.c:3945
+msgid "bad RR record"
+msgstr "mauvais enregistrement RR"
+
+#: option.c:3975
+msgid "bad TXT record"
+msgstr "champ TXT invalide"
+
+#: option.c:4016
+msgid "bad SRV record"
+msgstr "champ SRV invalide"
+
+#: option.c:4023
+msgid "bad SRV target"
+msgstr "cible SRV invalide"
+
+#: option.c:4037
+msgid "invalid priority"
+msgstr "priorité invalide"
+
+#: option.c:4040
+msgid "invalid weight"
+msgstr "poids invalide"
+
+#
+#: option.c:4064
+msgid "Bad host-record"
+msgstr "mauvais champ host-record"
+
+#: option.c:4088
+msgid "Bad name in host-record"
+msgstr "mauvais nom dans le champ host-record"
+
+#
+#: option.c:4153
+#, fuzzy
+msgid "bad trust anchor"
+msgstr "gamme de ports incorrecte"
+
+#: option.c:4167
+msgid "bad HEX in trust anchor"
+msgstr ""
+
+#: option.c:4177
+#, fuzzy
+msgid "unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"
+msgstr "option non supportée (vérifier que Dnsmasq a été compilé avec le support DHCP/TFTP/DBus)"
+
+#: option.c:4237
+msgid "missing \""
+msgstr "il manque \""
+
+#: option.c:4294
+msgid "bad option"
+msgstr "mauvaise option"
+
+#: option.c:4296
+msgid "extraneous parameter"
+msgstr "paramètre en trop"
+
+#: option.c:4298
+msgid "missing parameter"
+msgstr "paramètre manquant"
+
+#: option.c:4300
+#, fuzzy
+msgid "illegal option"
+msgstr "mauvaise option"
+
+#: option.c:4307
+msgid "error"
+msgstr "erreur"
+
+#: option.c:4309
+#, c-format
+msgid " at line %d of %s"
+msgstr "à la ligne %d de %s"
+
+#: option.c:4324 option.c:4571 option.c:4607
+#, c-format
+msgid "read %s"
+msgstr "Lecture de %s"
+
+#: option.c:4387 option.c:4510 tftp.c:715
+#, c-format
+msgid "cannot read %s: %s"
+msgstr "Ne peut pas lire %s : %s"
+
+#: option.c:4676
+msgid "junk found in command line"
+msgstr "la ligne de commande contient des éléments indésirables ou incompréhensibles"
+
+#: option.c:4711
+#, c-format
+msgid "Dnsmasq version %s  %s\n"
+msgstr "Version de Dnsmasq %s  %s\n"
+
+#: option.c:4712
+#, c-format
+msgid ""
+"Compile time options: %s\n"
+"\n"
+msgstr ""
+"Options à la compilation %s\n"
+"\n"
+
+#: option.c:4713
+#, c-format
+msgid "This software comes with ABSOLUTELY NO WARRANTY.\n"
+msgstr "Ce logiciel est fourni sans AUCUNE GARANTIE.\n"
+
+#: option.c:4714
+#, c-format
+msgid "Dnsmasq is free software, and you are welcome to redistribute it\n"
+msgstr "Dnsmasq est un logiciel libre, il vous est permis de le redistribuer\n"
+
+#: option.c:4715
+#, c-format
+msgid "under the terms of the GNU General Public License, version 2 or 3.\n"
+msgstr "sous les termes de la licence GPL (GNU General Public License), version 2 ou 3.\n"
+
+#: option.c:4726
+msgid "try --help"
+msgstr "essayez avec --help"
+
+#: option.c:4728
+msgid "try -w"
+msgstr "essayez avec -w"
+
+#: option.c:4730
+#, c-format
+msgid "bad command line options: %s"
+msgstr "mauvaises options en ligne de commande : %s."
+
+#: option.c:4798
+#, c-format
+msgid "CNAME loop involving %s"
+msgstr ""
+
+#: option.c:4834
+#, c-format
+msgid "cannot get host-name: %s"
+msgstr "ne peut pas obtenir le nom de la machine : %s"
+
+#: option.c:4862
+msgid "only one resolv.conf file allowed in no-poll mode."
+msgstr "seul un fichier resolv.conf est autorisé dans le mode no-poll"
+
+#: option.c:4872
+msgid "must have exactly one resolv.conf to read domain from."
+msgstr "un fichier resolv.conf (et un seul) est nécessaire pour y récuperer le nom de domaine."
+
+#: option.c:4875 network.c:1612 dhcp.c:816
+#, c-format
+msgid "failed to read %s: %s"
+msgstr "impossible de lire %s : %s"
+
+#: option.c:4892
+#, c-format
+msgid "no search directive found in %s"
+msgstr "pas de directive de recherche trouvée dans %s"
+
+#: option.c:4913
+msgid "there must be a default domain when --dhcp-fqdn is set"
+msgstr "un domaine par défaut doit être spécifié lorsque l'option --dhcp-fqdn est utilisée"
+
+#: option.c:4922
+msgid "syntax check OK"
+msgstr "vérification de syntaxe OK"
+
+#: forward.c:102
+#, c-format
+msgid "failed to send packet: %s"
+msgstr "impossible d'envoyer le paquet : %s"
+
+#: forward.c:597
+msgid "discarding DNS reply: subnet option mismatch"
+msgstr ""
+
+#: forward.c:651
+#, c-format
+msgid "nameserver %s refused to do a recursive query"
+msgstr "le serveur de nom %s a refusé de faire une recherche récursive"
+
+#: forward.c:683
+#, c-format
+msgid "possible DNS-rebind attack detected: %s"
+msgstr "détection d'une possible attaque de type DNS-rebind: %s"
+
+#: forward.c:1244 forward.c:1681
+msgid "Ignoring query from non-local network"
+msgstr ""
+
+#: forward.c:2166
+#, c-format
+msgid "Maximum number of concurrent DNS queries reached (max: %d)"
+msgstr "Nombre maximum de requêtes DNS concurrentes atteint (maximum : %d)."
+
+#: network.c:720
+#, c-format
+msgid "failed to create listening socket for %s: %s"
+msgstr "impossible de créer une socket d'écoute pour %s : %s"
+
+#: network.c:1031
+#, c-format
+msgid "LOUD WARNING: listening on %s may accept requests via interfaces other than %s"
+msgstr ""
+
+#: network.c:1038
+msgid "LOUD WARNING: use --bind-dynamic rather than --bind-interfaces to avoid DNS amplification attacks via these interface(s)"
+msgstr ""
+
+#: network.c:1047
+#, fuzzy, c-format
+msgid "warning: using interface %s instead"
+msgstr "attention : l'interface %s n'existe pas actuellement"
+
+#: network.c:1056
+#, fuzzy, c-format
+msgid "warning: no addresses found for interface %s"
+msgstr "utilise les adresses locales seulement pour %s %s"
+
+#: network.c:1114
+#, c-format
+msgid "interface %s failed to join DHCPv6 multicast group: %s"
+msgstr "impossible de faire rejoindre l'interface %s dans le groupe multicast DHCPv6 %s"
+
+#: network.c:1119
+msgid "try increasing /proc/sys/net/core/optmem_max"
+msgstr ""
+
+#: network.c:1322
+#, c-format
+msgid "failed to bind server socket for %s: %s"
+msgstr "impossible de lier la socket de serveur pour %s : %s"
+
+#: network.c:1517
+#, c-format
+msgid "ignoring nameserver %s - local interface"
+msgstr "ignore le serveur de nom %s - interface locale"
+
+#: network.c:1528
+#, c-format
+msgid "ignoring nameserver %s - cannot make/bind socket: %s"
+msgstr "ignore le serveur de nom %s - ne peut construire/lier la socket : %m"
+
+#: network.c:1548
+msgid "(no DNSSEC)"
+msgstr ""
+
+#: network.c:1551
+msgid "unqualified"
+msgstr "non-qualifié(e)"
+
+#: network.c:1551
+msgid "names"
+msgstr "noms"
+
+#: network.c:1553
+msgid "default"
+msgstr "défaut"
+
+#: network.c:1555
+msgid "domain"
+msgstr "domaine"
+
+#: network.c:1561
+#, c-format
+msgid "using local addresses only for %s %s"
+msgstr "utilise les adresses locales seulement pour %s %s"
+
+#: network.c:1564
+#, c-format
+msgid "using standard nameservers for %s %s"
+msgstr "utilisation des serveurs de nom standards pour %s %s"
+
+#: network.c:1566
+#, fuzzy, c-format
+msgid "using nameserver %s#%d for %s %s %s"
+msgstr "utilise le serveur de nom %s#%d pour %s %s"
+
+#: network.c:1570
+#, fuzzy, c-format
+msgid "NOT using nameserver %s#%d - query loop detected"
+msgstr "utilise le serveur de nom %s#%d pour %s %s"
+
+#: network.c:1573
+#, c-format
+msgid "using nameserver %s#%d(via %s)"
+msgstr "utilise le serveur de nom %s#%d (via %s)"
+
+#: network.c:1575
+#, c-format
+msgid "using nameserver %s#%d"
+msgstr "utilise le serveur de nom %s#%d"
+
+#: network.c:1580
+#, fuzzy, c-format
+msgid "using %d more local addresses"
+msgstr "utilise le serveur de nom %s#%d"
+
+#: network.c:1582
+#, fuzzy, c-format
+msgid "using %d more nameservers"
+msgstr "utilise le serveur de nom %s#%d"
+
+#: dnsmasq.c:166
+msgid "dhcp-hostsdir, dhcp-optsdir and hostsdir are not supported on this platform"
+msgstr ""
+
+#: dnsmasq.c:181
+msgid "no root trust anchor provided for DNSSEC"
+msgstr ""
+
+#: dnsmasq.c:184
+msgid "cannot reduce cache size from default when DNSSEC enabled"
+msgstr ""
+
+#: dnsmasq.c:186
+#, fuzzy
+msgid "DNSSEC not available: set HAVE_DNSSEC in src/config.h"
+msgstr "DBus n'est pas disponible : activez HAVE_DBUS dans src/config.h"
+
+#
+#: dnsmasq.c:192
+msgid "TFTP server not available: set HAVE_TFTP in src/config.h"
+msgstr "TFTP n'est pas disponible : activez HAVE_TFTP dans src/config.h"
+
+#: dnsmasq.c:197
+#, fuzzy
+msgid "cannot use --conntrack AND --query-port"
+msgstr "impossible d'utiliser conjointement --conntrack et --query-port"
+
+#
+#: dnsmasq.c:200
+#, fuzzy
+msgid "conntrack support not available: set HAVE_CONNTRACK in src/config.h"
+msgstr "Support de suivi de connexion non disponible : activez HAVE_CONNTRACK dans src/config.h"
+
+#: dnsmasq.c:205
+msgid "asynchronous logging is not available under Solaris"
+msgstr "l'écriture de traces en mode asynchrone n'est pas disponible sous Solaris."
+
+#: dnsmasq.c:210
+msgid "asynchronous logging is not available under Android"
+msgstr "l'écriture de traces en mode asynchrone n'est pas disponible sous Android."
+
+#: dnsmasq.c:215
+msgid "authoritative DNS not available: set HAVE_AUTH in src/config.h"
+msgstr "le mode « autorité DNS » n'est pas disponible : activez HAVE_AUTH dans src/config.h"
+
+#
+#: dnsmasq.c:220
+#, fuzzy
+msgid "loop detection not available: set HAVE_LOOP in src/config.h"
+msgstr "TFTP n'est pas disponible : activez HAVE_TFTP dans src/config.h"
+
+#: dnsmasq.c:227
+msgid "max_port cannot be smaller than min_port"
+msgstr ""
+
+#: dnsmasq.c:234
+msgid "zone serial must be configured in --auth-soa"
+msgstr "le numéro de série de la zone doit être configuré dans --auth-soa"
+
+#: dnsmasq.c:252
+msgid "dhcp-range constructor not available on this platform"
+msgstr "le constructeur de plage dhcp n'est pas disponible sur cette plate-forme"
+
+#: dnsmasq.c:298
+msgid "cannot set --bind-interfaces and --bind-dynamic"
+msgstr "--bind-interfaces et --bind-dynamic sont mutuellement exclusives"
+
+#: dnsmasq.c:301
+#, c-format
+msgid "failed to find list of interfaces: %s"
+msgstr "impossible de trouver la liste des interfaces : %s"
+
+#: dnsmasq.c:310
+#, c-format
+msgid "unknown interface %s"
+msgstr "interface %s inconnue"
+
+#: dnsmasq.c:374 dnsmasq.c:1037
+#, c-format
+msgid "DBus error: %s"
+msgstr "Erreur DBus : %s"
+
+#: dnsmasq.c:377
+msgid "DBus not available: set HAVE_DBUS in src/config.h"
+msgstr "DBus n'est pas disponible : activez HAVE_DBUS dans src/config.h"
+
+#: dnsmasq.c:405
+#, c-format
+msgid "unknown user or group: %s"
+msgstr "utilisateur ou groupe inconnu : %s"
+
+#: dnsmasq.c:460
+#, c-format
+msgid "cannot chdir to filesystem root: %s"
+msgstr "Ne peut effectuer un 'chdir' à la racine du système de fichier : %s"
+
+#: dnsmasq.c:716
+#, c-format
+msgid "started, version %s DNS disabled"
+msgstr "démarrage avec le DNS désactivé (version %s)"
+
+#: dnsmasq.c:720
+#, c-format
+msgid "started, version %s cachesize %d"
+msgstr "demarré, version %s (taille de cache %d)"
+
+#: dnsmasq.c:722
+#, c-format
+msgid "started, version %s cache disabled"
+msgstr "démarrage avec le cache désactivé (version %s)"
+
+#: dnsmasq.c:725
+msgid "DNS service limited to local subnets"
+msgstr ""
+
+#: dnsmasq.c:728
+#, c-format
+msgid "compile time options: %s"
+msgstr "options à la compilation : %s"
+
+#: dnsmasq.c:734
+msgid "DBus support enabled: connected to system bus"
+msgstr "Support DBus autorisé : connecté au bus système"
+
+#: dnsmasq.c:736
+msgid "DBus support enabled: bus connection pending"
+msgstr "Support DBus autorisé : connexion au bus en attente"
+
+#: dnsmasq.c:754
+msgid "DNSSEC validation enabled"
+msgstr ""
+
+#: dnsmasq.c:758
+msgid "DNSSEC signature timestamps not checked until first cache reload"
+msgstr ""
+
+#: dnsmasq.c:761
+msgid "DNSSEC signature timestamps not checked until system time valid"
+msgstr ""
+
+#: dnsmasq.c:766
+#, c-format
+msgid "warning: failed to change owner of %s: %s"
+msgstr "Impossible de changer pour l'utilisateur %s : %s"
+
+#: dnsmasq.c:770
+msgid "setting --bind-interfaces option because of OS limitations"
+msgstr "active l'option --bind-interfaces à cause de limitations dans le système d'exploitation"
+
+#: dnsmasq.c:782
+#, c-format
+msgid "warning: interface %s does not currently exist"
+msgstr "attention : l'interface %s n'existe pas actuellement"
+
+#: dnsmasq.c:787
+msgid "warning: ignoring resolv-file flag because no-resolv is set"
+msgstr "attention : l'option « resolv-file » sera ignorée car « no-resolv » a été spécifié"
+
+#
+#: dnsmasq.c:790
+msgid "warning: no upstream servers configured"
+msgstr "attention : aucun serveur amont n'est configuré"
+
+#: dnsmasq.c:794
+#, c-format
+msgid "asynchronous logging enabled, queue limit is %d messages"
+msgstr "mode asynchrone d'écriture de traces, la taille maximum de la queue est de %d messages."
+
+#: dnsmasq.c:815
+msgid "IPv6 router advertisement enabled"
+msgstr "annonces de routeur IPv6 activées"
+
+#: dnsmasq.c:820
+#, c-format
+msgid "DHCP, sockets bound exclusively to interface %s"
+msgstr ""
+
+#: dnsmasq.c:834
+msgid "root is "
+msgstr "root est"
+
+#
+#: dnsmasq.c:834
+msgid "enabled"
+msgstr "activé"
+
+#: dnsmasq.c:836
+msgid "secure mode"
+msgstr "mode sécurisé"
+
+#: dnsmasq.c:839
+#, c-format
+msgid "warning: %s inaccessible"
+msgstr ""
+
+#: dnsmasq.c:843
+#, fuzzy, c-format
+msgid "warning: TFTP directory %s inaccessible"
+msgstr "répertoire TFTP %s inaccessible : %s"
+
+#: dnsmasq.c:869
+#, c-format
+msgid "restricting maximum simultaneous TFTP transfers to %d"
+msgstr "le nombre maximum de transferts TFTP simultanés sera restreint à %d"
+
+#: dnsmasq.c:1039
+msgid "connected to system DBus"
+msgstr "connecté au systeme DBus"
+
+#: dnsmasq.c:1189
+#, c-format
+msgid "cannot fork into background: %s"
+msgstr "Ne peut se lancer en tâche de fond : %s"
+
+#: dnsmasq.c:1192
+#, c-format
+msgid "failed to create helper: %s"
+msgstr "impossible de créer le 'helper' : %s"
+
+#: dnsmasq.c:1195
+#, c-format
+msgid "setting capabilities failed: %s"
+msgstr "impossible de configurer la capacité %s"
+
+#: dnsmasq.c:1198
+#, c-format
+msgid "failed to change user-id to %s: %s"
+msgstr "Impossible de changer l'identifiant utilisateur pour %s : %s"
+
+#: dnsmasq.c:1201
+#, c-format
+msgid "failed to change group-id to %s: %s"
+msgstr "Impossible de changer l'identifiant de groupe pour %s : %s"
+
+#: dnsmasq.c:1204
+#, c-format
+msgid "failed to open pidfile %s: %s"
+msgstr "impossible de lire le fichier de PID %s : %s"
+
+#: dnsmasq.c:1207
+#, c-format
+msgid "cannot open log %s: %s"
+msgstr "Ne peut ouvrir le fichier de log %s : %s"
+
+#
+#: dnsmasq.c:1210
+#, c-format
+msgid "failed to load Lua script: %s"
+msgstr "impossible de charger le script Lua : %s"
+
+#: dnsmasq.c:1213
+#, c-format
+msgid "TFTP directory %s inaccessible: %s"
+msgstr "répertoire TFTP %s inaccessible : %s"
+
+#: dnsmasq.c:1216
+#, fuzzy, c-format
+msgid "cannot create timestamp file %s: %s"
+msgstr "ne peut ouvrir ou créer le fichiers de baux %s : %s"
+
+#: dnsmasq.c:1239
+msgid "now checking DNSSEC signature timestamps"
+msgstr ""
+
+#: dnsmasq.c:1307
+#, c-format
+msgid "script process killed by signal %d"
+msgstr "Le script a été terminé par le signal %d"
+
+#: dnsmasq.c:1311
+#, c-format
+msgid "script process exited with status %d"
+msgstr "Le script s'est terminé avec le statut %d"
+
+#: dnsmasq.c:1315
+#, c-format
+msgid "failed to execute %s: %s"
+msgstr "impossible d'exécuter à %s : %s"
+
+#: dnsmasq.c:1379 dnssec.c:479 dnssec.c:525
+#, fuzzy, c-format
+msgid "failed to update mtime on %s: %s"
+msgstr "impossible de lire le fichier de PID %s : %s"
+
+#: dnsmasq.c:1386
+msgid "exiting on receipt of SIGTERM"
+msgstr "sortie sur réception du signal SIGTERM"
+
+#: dnsmasq.c:1414
+#, c-format
+msgid "failed to access %s: %s"
+msgstr "impossible d'accéder à %s : %s"
+
+#: dnsmasq.c:1444
+#, c-format
+msgid "reading %s"
+msgstr "Lecture de %s"
+
+#: dnsmasq.c:1455
+#, c-format
+msgid "no servers found in %s, will retry"
+msgstr "aucun serveur trouvé dans %s, va réessayer"
+
+#: dhcp.c:53
+#, c-format
+msgid "cannot create DHCP socket: %s"
+msgstr "ne peut créer la socket DHCP: %s"
+
+#: dhcp.c:68
+#, c-format
+msgid "failed to set options on DHCP socket: %s"
+msgstr "impossible d'appliquer les options sur la socket DHCP : %s"
+
+#: dhcp.c:89
+#, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"
+msgstr "impossible de déclarer SO_REUSE{ADDR|PORT} sur la socket DHCP : %s"
+
+#: dhcp.c:101
+#, c-format
+msgid "failed to bind DHCP server socket: %s"
+msgstr "impossible de lier la socket serveur DHCP : %s"
+
+#: dhcp.c:127
+#, c-format
+msgid "cannot create ICMP raw socket: %s."
+msgstr "ne peut créer de socket en mode raw pour ICMP : %s."
+
+#: dhcp.c:252 dhcp6.c:173
+#, c-format
+msgid "unknown interface %s in bridge-interface"
+msgstr "interface %s inconnue spécifiée comme interface de pont"
+
+#: dhcp.c:293
+#, c-format
+msgid "DHCP packet received on %s which has no address"
+msgstr "Paquet DHCP reçu sur %s qui n'a pas d'adresse"
+
+#: dhcp.c:427
+#, c-format
+msgid "ARP-cache injection failed: %s"
+msgstr ""
+
+#: dhcp.c:470
+#, c-format
+msgid "Error sending DHCP packet to %s: %s"
+msgstr ""
+
+#: dhcp.c:531
+#, c-format
+msgid "DHCP range %s -- %s is not consistent with netmask %s"
+msgstr "La plage d'adresses DHCP %s -- %s n'est pas cohérente avec le masque de réseau %s"
+
+#: dhcp.c:854
+#, c-format
+msgid "bad line at %s line %d"
+msgstr "mauvaise ligne dans %s ligne %d"
+
+#: dhcp.c:897
+#, c-format
+msgid "ignoring %s line %d, duplicate name or IP address"
+msgstr "ignore %s à la ligne %d : duplication de nom ou d'adresse IP"
+
+#: dhcp.c:1041 rfc3315.c:2149
+#, c-format
+msgid "DHCP relay %s -> %s"
+msgstr "Relais DHCP %s -> %s"
+
+#: lease.c:98
+msgid "too many stored leases"
+msgstr "beaucoup trop de baux enregistrés"
+
+#: lease.c:166
+#, c-format
+msgid "cannot open or create lease file %s: %s"
+msgstr "ne peut ouvrir ou créer le fichiers de baux %s : %s"
+
+#: lease.c:175
+#, c-format
+msgid "failed to parse lease database, invalid line: %s %s %s %s ..."
+msgstr ""
+
+#: lease.c:180
+#, fuzzy, c-format
+msgid "failed to read lease file %s: %s"
+msgstr "impossible de lire %s : %s"
+
+#: lease.c:196
+#, c-format
+msgid "cannot run lease-init script %s: %s"
+msgstr "Ne peut pas exécuter le script lease-init %s : %s"
+
+#: lease.c:202
+#, c-format
+msgid "lease-init script returned exit code %s"
+msgstr "le script lease-init a retourné le code %s"
+
+#: lease.c:373
+#, c-format
+msgid "failed to write %s: %s (retry in %us)"
+msgstr "impossible de lire %s : %s (prochain essai dans %us)"
+
+#: lease.c:937
+#, c-format
+msgid "Ignoring domain %s for DHCP host name %s"
+msgstr "Le domaine %s est ignoré pour l'hôte DHCP %s"
+
+#: rfc2131.c:347
+#, c-format
+msgid "no address range available for DHCP request %s %s"
+msgstr "pas de plage d'adresse disponible pour la requête DHCP %s %s"
+
+#: rfc2131.c:348
+msgid "with subnet selector"
+msgstr "avec sélecteur de sous-reseau"
+
+#: rfc2131.c:348
+msgid "via"
+msgstr "par l'intermédiaire de"
+
+#: rfc2131.c:360
+#, c-format
+msgid "%u available DHCP subnet: %s/%s"
+msgstr "%u sous-réseaux DHCP disponibles : %s/%s"
+
+#: rfc2131.c:363 rfc3315.c:306
+#, c-format
+msgid "%u available DHCP range: %s -- %s"
+msgstr "%u la gamme DHCP disponible est : %s -- %s"
+
+#: rfc2131.c:474
+#, c-format
+msgid "%u vendor class: %s"
+msgstr "%u Classe de vendeur ('Vendor Class') : %s"
+
+#: rfc2131.c:476
+#, c-format
+msgid "%u user class: %s"
+msgstr "%u Classe d'utilisateur : %s"
+
+#: rfc2131.c:510
+msgid "disabled"
+msgstr "désactivé"
+
+#: rfc2131.c:551 rfc2131.c:1006 rfc2131.c:1430 rfc3315.c:616 rfc3315.c:869
+#: rfc3315.c:1148
+msgid "ignored"
+msgstr "ignoré"
+
+#: rfc2131.c:566 rfc2131.c:1239 rfc3315.c:919
+msgid "address in use"
+msgstr "adresse déjà utilisée"
+
+#: rfc2131.c:580 rfc2131.c:1060
+msgid "no address available"
+msgstr "pas d'adresse disponible"
+
+#: rfc2131.c:587 rfc2131.c:1202
+msgid "wrong network"
+msgstr "mauvais réseau"
+
+#: rfc2131.c:602
+msgid "no address configured"
+msgstr "pas d'adresse configurée"
+
+#: rfc2131.c:608 rfc2131.c:1252
+msgid "no leases left"
+msgstr "plus aucun bail disponible"
+
+#: rfc2131.c:703 rfc3315.c:482
+#, c-format
+msgid "%u client provides name: %s"
+msgstr "le client %u fourni le nom : %s"
+
+#: rfc2131.c:808
+msgid "PXE BIS not supported"
+msgstr "Service PXE BIS (Boot Integrity Services) non supporté"
+
+#: rfc2131.c:974 rfc3315.c:1242
+#, c-format
+msgid "disabling DHCP static address %s for %s"
+msgstr "désactive l'adresse statique DHCP %s pour %s"
+
+#: rfc2131.c:995
+msgid "unknown lease"
+msgstr "bail inconnu"
+
+#: rfc2131.c:1029
+#, c-format
+msgid "not using configured address %s because it is leased to %s"
+msgstr "L'adresse statique %s ne sera pas utilisée car un bail est déjà attribué à %s"
+
+#: rfc2131.c:1039
+#, c-format
+msgid "not using configured address %s because it is in use by the server or relay"
+msgstr "L'adresse statique %s ne sera pas utilisée car elle est utilisée par le serveur ou un relai"
+
+#: rfc2131.c:1042
+#, c-format
+msgid "not using configured address %s because it was previously declined"
+msgstr "L'adresse statique %s ne sera pas utilisée car elle a préalablement été refusée"
+
+#: rfc2131.c:1058 rfc2131.c:1245
+msgid "no unique-id"
+msgstr "pas d'identifiant unique"
+
+#: rfc2131.c:1140
+msgid "wrong server-ID"
+msgstr "mauvais identifiant de serveur"
+
+#: rfc2131.c:1159
+msgid "wrong address"
+msgstr "mauvaise adresse"
+
+#: rfc2131.c:1177 rfc3315.c:1015
+msgid "lease not found"
+msgstr "bail non trouvé"
+
+#: rfc2131.c:1210
+msgid "address not available"
+msgstr "adresse non disponible"
+
+#: rfc2131.c:1221
+msgid "static lease available"
+msgstr "bail statique disponible"
+
+#: rfc2131.c:1225
+msgid "address reserved"
+msgstr "adresse reservée"
+
+#: rfc2131.c:1233
+#, c-format
+msgid "abandoning lease to %s of %s"
+msgstr "abandon du bail de %s pour %s"
+
+#: rfc2131.c:1757
+#, c-format
+msgid "%u bootfile name: %s"
+msgstr "%u nom de fichier 'bootfile' : %s"
+
+#: rfc2131.c:1766
+#, c-format
+msgid "%u server name: %s"
+msgstr "%u nom du serveur : %s"
+
+#: rfc2131.c:1774
+#, c-format
+msgid "%u next server: %s"
+msgstr "%u serveur suivant : %s"
+
+#: rfc2131.c:1777
+#, c-format
+msgid "%u broadcast response"
+msgstr "%u réponse broadcast"
+
+#: rfc2131.c:1840
+#, c-format
+msgid "cannot send DHCP/BOOTP option %d: no space left in packet"
+msgstr "Impossible d'envoyer l'option DHCP/BOOTP %d : pas assez d'espace dans le paquet"
+
+#: rfc2131.c:2131
+msgid "PXE menu too large"
+msgstr "menu PXE trop grand"
+
+#: rfc2131.c:2270 rfc3315.c:1515
+#, c-format
+msgid "%u requested options: %s"
+msgstr "%u options demandées : %s"
+
+#: rfc2131.c:2587
+#, c-format
+msgid "cannot send RFC3925 option: too many options for enterprise number %d"
+msgstr "ne peux envoyer l'option RFC3925 : trop d'options pour le numéro d'entreprise %d"
+
+#: rfc2131.c:2650
+#, c-format
+msgid "%u reply delay: %d"
+msgstr ""
+
+#: netlink.c:77
+#, c-format
+msgid "cannot create netlink socket: %s"
+msgstr "ne peux lier une socket netlink : %s"
+
+#: netlink.c:355
+#, c-format
+msgid "netlink returns error: %s"
+msgstr "Erreur netlink : %s"
+
+#: dbus.c:186
+msgid "attempt to set an IPv6 server address via DBus - no IPv6 support"
+msgstr "tentative de lier une adresse serveur IPV6 via DBus - pas de support IPV6"
+
+#: dbus.c:439
+#, c-format
+msgid "Enabling --%s option from D-Bus"
+msgstr ""
+
+#: dbus.c:444
+#, c-format
+msgid "Disabling --%s option from D-Bus"
+msgstr ""
+
+#: dbus.c:690
+msgid "setting upstream servers from DBus"
+msgstr "configuration des serveurs amonts à partir de DBus"
+
+#: dbus.c:737
+msgid "could not register a DBus message handler"
+msgstr "ne peut enregistrer une routine de traitement des messages DBus"
+
+#: bpf.c:265
+#, c-format
+msgid "cannot create DHCP BPF socket: %s"
+msgstr "impossible de créer une socket BPF pour DHCP : %s"
+
+#: bpf.c:293
+#, c-format
+msgid "DHCP request for unsupported hardware type (%d) received on %s"
+msgstr "requête DHCP pour un type de matériel non supporté (%d) reçue sur %s"
+
+#: bpf.c:378
+#, fuzzy, c-format
+msgid "cannot create PF_ROUTE socket: %s"
+msgstr "ne peut créer la socket DHCP: %s"
+
+#: bpf.c:399
+msgid "Unknown protocol version from route socket"
+msgstr ""
+
+#: helper.c:153
+msgid "lease() function missing in Lua script"
+msgstr "la fonction lease() est absente du script Lua"
+
+#: tftp.c:319
+msgid "unable to get free port for TFTP"
+msgstr "impossible d'obtenir un port libre pour TFTP"
+
+#: tftp.c:335
+#, c-format
+msgid "unsupported request from %s"
+msgstr "requête de %s non supportée"
+
+#: tftp.c:483
+#, c-format
+msgid "file %s not found"
+msgstr "fichier %s non trouvé"
+
+#: tftp.c:592
+#, c-format
+msgid "error %d %s received from %s"
+msgstr "erreur %d %s reçu de %s"
+
+#: tftp.c:634
+#, c-format
+msgid "failed sending %s to %s"
+msgstr "impossible d'envoyer %s à %s"
+
+#: tftp.c:634
+#, c-format
+msgid "sent %s to %s"
+msgstr "envoyé %s à %s"
+
+#: log.c:190
+#, c-format
+msgid "overflow: %d log entries lost"
+msgstr "débordement : %d traces perdues"
+
+#: log.c:268
+#, c-format
+msgid "log failed: %s"
+msgstr "trace perdue : %s"
+
+#: log.c:471
+msgid "FAILED to start up"
+msgstr "IMPOSSIBLE de démarrer"
+
+#: conntrack.c:65
+#, c-format
+msgid "Conntrack connection mark retrieval failed: %s"
+msgstr "La récupération de la marque de suivi de connexion a échoué : %s"
+
+#: dhcp6.c:52
+#, c-format
+msgid "cannot create DHCPv6 socket: %s"
+msgstr "ne peut créer la socket DHCPv6: %s"
+
+#: dhcp6.c:73
+#, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"
+msgstr "impossible de déclarer SO_REUSE{ADDR|PORT} sur la socket DHCPv6 : %s"
+
+#: dhcp6.c:85
+#, c-format
+msgid "failed to bind DHCPv6 server socket: %s"
+msgstr "impossible de lier la socket serveur DHCPv6 : %s"
+
+#: rfc3315.c:157
+#, c-format
+msgid "no address range available for DHCPv6 request from relay at %s"
+msgstr "pas de plage d'adresse disponible pour la requête DHCPv6 transmise via le relai %s"
+
+#: rfc3315.c:166
+#, c-format
+msgid "no address range available for DHCPv6 request via %s"
+msgstr "pas de plage d'adresse disponible pour la requête DHCPv6 via %s"
+
+#: rfc3315.c:303
+#, c-format
+msgid "%u available DHCPv6 subnet: %s/%d"
+msgstr "%u sous-réseaux DHCPv6 disponibles : %s/%d"
+
+#: rfc3315.c:386
+#, c-format
+msgid "%u vendor class: %u"
+msgstr "%u Classe de vendeur ('Vendor Class') : %u"
+
+#: rfc3315.c:434
+#, c-format
+msgid "%u client MAC address: %s"
+msgstr "%u MAC adresse du client : %s"
+
+#: rfc3315.c:673
+#, c-format
+msgid "unknown prefix-class %d"
+msgstr "préfixe de classe inconnu %d"
+
+#: rfc3315.c:816 rfc3315.c:911
+msgid "address unavailable"
+msgstr "adresse non disponible"
+
+#: rfc3315.c:828 rfc3315.c:959 rfc3315.c:1292
+msgid "success"
+msgstr "réussi"
+
+#: rfc3315.c:843 rfc3315.c:852 rfc3315.c:967 rfc3315.c:969
+msgid "no addresses available"
+msgstr "pas d'adresse disponible"
+
+#: rfc3315.c:946
+msgid "not on link"
+msgstr "pas sur ce lien"
+
+#: rfc3315.c:1019 rfc3315.c:1204 rfc3315.c:1281
+msgid "no binding found"
+msgstr "aucune liaison trouvée"
+
+#: rfc3315.c:1057
+msgid "deprecated"
+msgstr "obsolète"
+
+#: rfc3315.c:1062
+msgid "address invalid"
+msgstr "adresse non valide"
+
+#: rfc3315.c:1109
+msgid "confirm failed"
+msgstr "confirmation d'échec"
+
+#: rfc3315.c:1125
+msgid "all addresses still on link"
+msgstr "toutes les adresses sont toujours sur le lien"
+
+#: rfc3315.c:1213
+msgid "release received"
+msgstr "libération reçue"
+
+#: rfc3315.c:2140
+msgid "Cannot multicast to DHCPv6 server without correct interface"
+msgstr "Impossible de faire du multicast au server DHCPv6 sans interface valide"
+
+#: dhcp-common.c:145
+#, c-format
+msgid "Ignoring duplicate dhcp-option %d"
+msgstr "L'option dhcp-option redondante %d sera ignorée"
+
+#: dhcp-common.c:222
+#, c-format
+msgid "%u tags: %s"
+msgstr "%u options: %s"
+
+#: dhcp-common.c:407
+#, c-format
+msgid "%s has more than one address in hostsfile, using %s for DHCP"
+msgstr "%s a plus d'une adresse dans le fichier d'hôte, utilisation de %s pour le DHCP."
+
+#: dhcp-common.c:430
+#, c-format
+msgid "duplicate IP address %s (%s) in dhcp-config directive"
+msgstr "adresse IP %s (%s) dupliquée dans la directive dhcp-config."
+
+#: dhcp-common.c:494
+#, c-format
+msgid "failed to set SO_BINDTODEVICE on DHCP socket: %s"
+msgstr "impossible de déclarer SO_BINDTODEVICE sur la socket DHCP : %s"
+
+#: dhcp-common.c:615
+#, c-format
+msgid "Known DHCP options:\n"
+msgstr "Options DHCP connues :\n"
+
+#: dhcp-common.c:626
+#, c-format
+msgid "Known DHCPv6 options:\n"
+msgstr "Options DHCPv6 connues :\n"
+
+#: dhcp-common.c:823
+msgid ", prefix deprecated"
+msgstr ", préfixe obsolète"
+
+#: dhcp-common.c:826
+#, c-format
+msgid ", lease time "
+msgstr ", durée de bail "
+
+#: dhcp-common.c:868
+#, c-format
+msgid "%s stateless on %s%.0s%.0s%s"
+msgstr "%s sans état (stateless) sur %s%.0s%.0s%s"
+
+#: dhcp-common.c:870
+#, c-format
+msgid "%s, static leases only on %.0s%s%s%.0s"
+msgstr "%s, baux statiques seulement sur %.0s%s%s%.0s"
+
+#: dhcp-common.c:872
+#, c-format
+msgid "%s, proxy on subnet %.0s%s%.0s%.0s"
+msgstr "%s, proxy sur le sous-réseau %.0s%s%.0s"
+
+#: dhcp-common.c:873
+#, c-format
+msgid "%s, IP range %s -- %s%s%.0s"
+msgstr "%s, plage d'adresses IP %s -- %s%s%.0s"
+
+#: dhcp-common.c:886
+#, c-format
+msgid "DHCPv4-derived IPv6 names on %s%s"
+msgstr "noms IPv6 dérivés de DHCPv4 sur %s%s"
+
+#: dhcp-common.c:889
+#, c-format
+msgid "router advertisement on %s%s"
+msgstr "annonces de routeurs sur %s%s"
+
+#: dhcp-common.c:900
+#, c-format
+msgid "DHCP relay from %s to %s via %s"
+msgstr "Relais DHCP de %s à %s via %s"
+
+#: dhcp-common.c:902
+#, c-format
+msgid "DHCP relay from %s to %s"
+msgstr "Relais DHCP de %s à %s"
+
+#: radv.c:110
+#, c-format
+msgid "cannot create ICMPv6 socket: %s"
+msgstr "ne peut créer la socket ICMPv6: %s"
+
+#: auth.c:449
+#, c-format
+msgid "ignoring zone transfer request from %s"
+msgstr "la requête de transfert de zone en provenance de %s est ignorée"
+
+#: ipset.c:95
+#, c-format
+msgid "failed to find kernel version: %s"
+msgstr "impossible de trouver la version de noyau : %s"
+
+#: ipset.c:114
+#, c-format
+msgid "failed to create IPset control socket: %s"
+msgstr "impossible de créer une socket de contrôle IPset : %s"
+
+#: ipset.c:233
+#, fuzzy, c-format
+msgid "failed to update ipset %s: %s"
+msgstr "impossible de lire le fichier de PID %s : %s"
+
+#: dnssec.c:527
+msgid "system time considered valid, now checking DNSSEC signature timestamps."
+msgstr ""
+
+#: blockdata.c:58
+#, c-format
+msgid "DNSSEC memory in use %u, max %u, allocated %u"
+msgstr ""
+
+#: tables.c:61
+#, fuzzy, c-format
+msgid "failed to access pf devices: %s"
+msgstr "impossible d'accéder à %s : %s"
+
+#: tables.c:74
+#, fuzzy, c-format
+msgid "warning: no opened pf devices %s"
+msgstr "utilise les adresses locales seulement pour %s %s"
+
+#: tables.c:82
+#, fuzzy, c-format
+msgid "error: cannot use table name %s"
+msgstr "ne peut pas obtenir le nom de la machine : %s"
+
+#: tables.c:90
+#, c-format
+msgid "error: cannot strlcpy table name %s"
+msgstr ""
+
+#: tables.c:101
+#, fuzzy, c-format
+msgid "IPset: error:%s"
+msgstr "Erreur DBus : %s"
+
+#: tables.c:108
+msgid "info: table created"
+msgstr ""
+
+#: tables.c:134
+#, c-format
+msgid "warning: DIOCR%sADDRS: %s"
+msgstr ""
+
+#
+#: tables.c:138
+#, fuzzy, c-format
+msgid "%d addresses %s"
+msgstr "mauvaise adresse"
+
+#: inotify.c:62
+#, fuzzy, c-format
+msgid "cannot access path %s: %s"
+msgstr "Ne peut pas lire %s : %s"
+
+#: inotify.c:95
+#, fuzzy, c-format
+msgid "failed to create inotify: %s"
+msgstr "impossible de créer le 'helper' : %s"
+
+#: inotify.c:111
+#, c-format
+msgid "too many symlinks following %s"
+msgstr ""
+
+#: inotify.c:127
+#, c-format
+msgid "directory %s for resolv-file is missing, cannot poll"
+msgstr ""
+
+#: inotify.c:131 inotify.c:168
+#, fuzzy, c-format
+msgid "failed to create inotify for %s: %s"
+msgstr "impossible de créer une socket d'écoute pour %s : %s"
+
+#: inotify.c:153
+#, fuzzy, c-format
+msgid "bad dynamic directory %s: %s"
+msgstr "Ne peut pas lire le répertoire %s : %s"
+
+#: inotify.c:255
+#, c-format
+msgid "inotify, new or changed file %s"
+msgstr ""
+
+#, fuzzy
+#~ msgid "cannot cannonicalise resolv-file %s: %s"
+#~ msgstr "ne peut ouvrir ou créer le fichiers de baux %s : %s"
+
+#~ msgid "Always send frequent router-advertisements"
+#~ msgstr "Envoyer des annonces de routeurs fréquentes"
+
+#~ msgid "no interface with address %s"
+#~ msgstr "pas d'interface avec l'adresse %s"
+
+#~ msgid "duplicate IP address %s in dhcp-config directive."
+#~ msgstr "adresse IP %s dupliquée dans la directive dhcp-config."
+
+#~ msgid "Specify path to Lua script (no default)."
+#~ msgstr "Spécifie un chemin pour le fichier PID (par défaut : %s)."
+
+#
+#~ msgid "only one dhcp-hostsfile allowed"
+#~ msgstr "une seule valeur est autorisée pour 'dhcp-hostsfile'"
+
+#
+#~ msgid "only one dhcp-optsfile allowed"
+#~ msgstr "une seule valeur est autorisée pour 'dhcp-optsfile'"
+
+#~ msgid "files nested too deep in %s"
+#~ msgstr "trop de niveaux de récursion pour les fichiers dans %s"
+
+#~ msgid "TXT record string too long"
+#~ msgstr "chaîne du champ TXT trop longue"
+
+#~ msgid "failed to set IPV6 options on listening socket: %s"
+#~ msgstr "impossible d'activer les options IPV6 sur la socket de lecture : %s"
+
+#~ msgid "failed to bind listening socket for %s: %s"
+#~ msgstr "impossible de lier la socket de lecture pour %s : %s"
+
+#~ msgid "DHCP packet: transaction-id is %u"
+#~ msgstr "paquet DHCP : l'identifiant de transaction ('transaction-id') est %u"
+
+#~ msgid "failed to read %s:%s"
+#~ msgstr "impossible de lire %s : %s"
+
+#~ msgid "must set exactly one interface on broken systems without IP_RECVIF"
+#~ msgstr "Une interface et une seule doit être déclarée sur les systèmes sans IP_RECVIF"
+
+#~ msgid "Ignoring DHCP lease for %s because it has an illegal domain part"
+#~ msgstr "On ignore le bail DHCP pour %s car il possède un nom de domaine illégal"
+
+#~ msgid "ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h"
+#~ msgstr "L'intégration DHCP ISC n'est pas disponible : activez HAVE_ISC_READER dans src/config.h"
+
+#
+#~ msgid "illegal domain %s in dhcp-config directive."
+#~ msgstr "domaine %s dupliqué dans la directive dhcp-config."
+
+#~ msgid "illegal domain %s in %s."
+#~ msgstr "domaine %s illégal dans %s."
+
+#~ msgid "running as root"
+#~ msgstr "executé en temps que root"
+
+#~ msgid "Read leases at startup, but never write the lease file."
+#~ msgstr "Lecture des baux au démarrage, mais aucune écriture de fichier de baux"
+
+#
+#~ msgid "read %s - %d hosts"
+#~ msgstr "lecture %s - %d hôtes"
+
+#~ msgid "domains"
+#~ msgstr "domaines"
+
+#~ msgid "Ignoring DHCP host name %s because it has an illegal domain part"
+#~ msgstr "Le nom de machine DHCP %s sera ignoré parce qu'il possède un nom de domaine illégal"
+
+#~ msgid "Display this message."
+#~ msgstr "Affiche ce message."
+
+#~ msgid "failed to read %s: %m"
+#~ msgstr "impossible de lire %s : %m"
+
+#~ msgid "failed to read %s:%m"
+#~ msgstr "impossible de lire %s : %m"
+
+#
+#~ msgid "cannot send encapsulated option %d: no space left in wrapper"
+#~ msgstr "Impossible d'envoyer l'option DHCP %d : pas assez d'espace dans le paquet"
+
+#~ msgid "More than one vendor class matches, using %s"
+#~ msgstr "Plusieurs classes de fournisseurs correspondent, %s sera utilisé"
diff --git a/po/id.po b/po/id.po
new file mode 100755
index 0000000..60556c0
--- /dev/null
+++ b/po/id.po
@@ -0,0 +1,2663 @@
+# Indonesian translations for dnsmasq package.
+# This file is put in the public domain.
+# Salman AS <sas@salman.or.id>, 2005.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: dnsmasq 2.24\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-06-18 12:24+0100\n"
+"PO-Revision-Date: 2017-07-17 18:30+0100\n"
+"Last-Translator: Salman AS <sas@salman.or.id>\n"
+"Language-Team: Indonesian <translation-team-id@lists.sourceforge.net>\n"
+"Language: id\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ASCII\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: cache.c:513
+msgid "Internal error in cache."
+msgstr ""
+
+# OK
+#: cache.c:923
+#, fuzzy, c-format
+msgid "failed to load names from %s: %s"
+msgstr "gagal memuat nama-nama dari %s: %s"
+
+# OK
+#: cache.c:949 dhcp.c:867
+#, fuzzy, c-format
+msgid "bad address at %s line %d"
+msgstr "kesalahan nama pada %s baris %d"
+
+# OK
+#: cache.c:1002 dhcp.c:883
+#, c-format
+msgid "bad name at %s line %d"
+msgstr "kesalahan nama pada %s baris %d"
+
+# OK
+#: cache.c:1011 dhcp.c:958
+#, c-format
+msgid "read %s - %d addresses"
+msgstr "membaca %s - %d alamat"
+
+# OK
+#: cache.c:1124
+msgid "cleared cache"
+msgstr "cache telah dihapus"
+
+#: cache.c:1153
+#, c-format
+msgid "No IPv4 address found for %s"
+msgstr ""
+
+#: cache.c:1232
+#, c-format
+msgid "%s is a CNAME, not giving it to the DHCP lease of %s"
+msgstr ""
+
+# OK
+#: cache.c:1256
+#, c-format
+msgid "not giving name %s to the DHCP lease of %s because the name exists in %s with address %s"
+msgstr "tidak memberikan nama %s kepada lease DHCP %s karena nama telah ada dalam %sdengan alamat %s"
+
+#: cache.c:1413
+#, c-format
+msgid "time %lu"
+msgstr ""
+
+# OK
+#: cache.c:1414
+#, fuzzy, c-format
+msgid "cache size %d, %d/%d cache insertions re-used unexpired cache entries."
+msgstr "ukuran cache %d, %d/%d penyisipan cache menimpa cache yang belum kadaluwarsa"
+
+#: cache.c:1416
+#, c-format
+msgid "queries forwarded %u, queries answered locally %u"
+msgstr ""
+
+#: cache.c:1419
+#, c-format
+msgid "queries for authoritative zones %u"
+msgstr ""
+
+#: cache.c:1445
+#, c-format
+msgid "server %s#%d: queries sent %u, retried or failed %u"
+msgstr ""
+
+# OK
+#: util.c:47
+#, fuzzy, c-format
+msgid "failed to seed the random number generator: %s"
+msgstr "gagal mendengarkan di socket: %s"
+
+# OK
+#: util.c:224
+#, fuzzy
+msgid "failed to allocate memory"
+msgstr "gagal memuat %S: %m"
+
+# OK
+#: util.c:277 option.c:619
+msgid "could not get memory"
+msgstr "tidak bisa mendapatkan memory"
+
+# OK
+#: util.c:287
+#, fuzzy, c-format
+msgid "cannot create pipe: %s"
+msgstr "tidak bisa membaca %s: %s"
+
+# OK
+#: util.c:295
+#, fuzzy, c-format
+msgid "failed to allocate %d bytes"
+msgstr "gagal memuat %S: %m"
+
+# OK
+#: util.c:464
+#, c-format
+msgid "infinite"
+msgstr "tak terbatas"
+
+# OK
+#: option.c:344
+msgid "Specify local address(es) to listen on."
+msgstr "Tentukan alamat lokal untuk mendengarkan."
+
+# OK
+#: option.c:345
+msgid "Return ipaddr for all hosts in specified domains."
+msgstr "Menghasilkan ipaddr untuk semua host dalam domain yang dipilih."
+
+# OK
+#: option.c:346
+msgid "Fake reverse lookups for RFC1918 private address ranges."
+msgstr "Fake pencarian balik untuk alamat private sesuai dengan RFC1918."
+
+# OK
+#: option.c:347
+msgid "Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."
+msgstr "Perlakukan ipaddr sebagai NXDOMAIN (mengalahkan wildcard Verisign)."
+
+# OK
+#: option.c:348
+#, c-format
+msgid "Specify the size of the cache in entries (defaults to %s)."
+msgstr "Tentukan ukuran cache, dalam jumlah isian (default %s)."
+
+# OK
+#: option.c:349
+#, c-format
+msgid "Specify configuration file (defaults to %s)."
+msgstr "Tentukan file konfigurasi (default %s)."
+
+# OK
+#: option.c:350
+msgid "Do NOT fork into the background: run in debug mode."
+msgstr "JANGAN berjalan di background: berjalan dalam modus debug."
+
+# OK
+#: option.c:351
+msgid "Do NOT forward queries with no domain part."
+msgstr "JANGAN teruskan permintaan tanpa bagian domain."
+
+# OK
+#: option.c:352
+msgid "Return self-pointing MX records for local hosts."
+msgstr "Mengembalikan record MX untuk diri sendiri host-host lokal."
+
+# OK
+#: option.c:353
+msgid "Expand simple names in /etc/hosts with domain-suffix."
+msgstr "Melengkapi nama-nama di /etc/hosts dengan akhiran domain."
+
+# OK
+#: option.c:354
+msgid "Don't forward spurious DNS requests from Windows hosts."
+msgstr "Jangan meneruskan permintaan DNS spurious dari host-host Windows."
+
+# OK
+#: option.c:355
+msgid "Enable DHCP in the range given with lease duration."
+msgstr "Bolehkan DHCP dalam jangkauan yang diberikan dengan durasi lease."
+
+# OK
+#: option.c:356
+#, c-format
+msgid "Change to this group after startup (defaults to %s)."
+msgstr "Ubah ke group ini setelah mulai (default %s)."
+
+# OK
+#: option.c:357
+msgid "Set address or hostname for a specified machine."
+msgstr "Setel alamat atau nama host untuk mesin yang disebutkan."
+
+# OK
+#: option.c:358
+#, fuzzy
+msgid "Read DHCP host specs from file."
+msgstr "nama MX salah"
+
+#: option.c:359
+msgid "Read DHCP option specs from file."
+msgstr ""
+
+# OK
+#: option.c:360
+#, fuzzy
+msgid "Read DHCP host specs from a directory."
+msgstr "nama MX salah"
+
+# OK
+#: option.c:361
+#, fuzzy
+msgid "Read DHCP options from a directory."
+msgstr "nama MX salah"
+
+#: option.c:362
+msgid "Evaluate conditional tag expression."
+msgstr ""
+
+# OK
+#: option.c:363
+#, c-format
+msgid "Do NOT load %s file."
+msgstr "JANGAN muat file %s."
+
+# OK
+#: option.c:364
+#, c-format
+msgid "Specify a hosts file to be read in addition to %s."
+msgstr "Sebutkan sebuah file hosts yang harus dibaca sebagai tambahan untuk %s."
+
+# OK
+#: option.c:365
+#, fuzzy
+msgid "Read hosts files from a directory."
+msgstr "nama MX salah"
+
+# OK
+#: option.c:366
+msgid "Specify interface(s) to listen on."
+msgstr "Sebutkan antarmuka untuk mendengarkan."
+
+# OK
+#: option.c:367
+msgid "Specify interface(s) NOT to listen on."
+msgstr "Sebutkan antarmuka untuk TIDAK mendengarkan."
+
+# OK
+#: option.c:368
+#, fuzzy
+msgid "Map DHCP user class to tag."
+msgstr "Petakan kelas user DHCP ke setelan yang dipilih."
+
+#: option.c:369
+msgid "Map RFC3046 circuit-id to tag."
+msgstr ""
+
+#: option.c:370
+msgid "Map RFC3046 remote-id to tag."
+msgstr ""
+
+#: option.c:371
+msgid "Map RFC3993 subscriber-id to tag."
+msgstr ""
+
+# OK
+#: option.c:372
+#, fuzzy
+msgid "Don't do DHCP for hosts with tag set."
+msgstr "Jangan menggunakan DHCP untuk host-host yang dipilih."
+
+# OK
+#: option.c:373
+#, fuzzy
+msgid "Force broadcast replies for hosts with tag set."
+msgstr "Jangan menggunakan DHCP untuk host-host yang dipilih."
+
+# OK
+#: option.c:374
+msgid "Do NOT fork into the background, do NOT run in debug mode."
+msgstr "JANGAN berjalan di background, jangan berjalan dalam modus debug."
+
+# OK
+#: option.c:375
+msgid "Assume we are the only DHCP server on the local network."
+msgstr "Berpikir bahwa kita satu-satunya DHCP server dalam jaringan."
+
+# OK
+#: option.c:376
+#, c-format
+msgid "Specify where to store DHCP leases (defaults to %s)."
+msgstr "Sebutkan lokasi untuk menyimpan lease DHCP (default %s)."
+
+# OK
+#: option.c:377
+msgid "Return MX records for local hosts."
+msgstr "Kembalikan rekord MX untuk host-host lokal."
+
+# OK
+#: option.c:378
+msgid "Specify an MX record."
+msgstr "Sebutkan sebuah rekord MX."
+
+# OK
+#: option.c:379
+msgid "Specify BOOTP options to DHCP server."
+msgstr "Sebutkan pilihan-pilihan BOOTP untuk DHCP server."
+
+#: option.c:380
+#, c-format
+msgid "Do NOT poll %s file, reload only on SIGHUP."
+msgstr "Jangan kumpulkan file %s, muat kembali saat SIGHUP."
+
+# OK
+#: option.c:381
+msgid "Do NOT cache failed search results."
+msgstr "JANGAN menyimpan hasil pencarian yang gagal."
+
+# OK
+#: option.c:382
+#, c-format
+msgid "Use nameservers strictly in the order given in %s."
+msgstr "Gunakan secara ketat namaserver yang disebutkan sesuai urutan di %s."
+
+# OK
+#: option.c:383
+#, fuzzy
+msgid "Specify options to be sent to DHCP clients."
+msgstr "Setel pilihan-pilihan tambahan yang akan disetel untuk klien-klien DHCP."
+
+#: option.c:384
+msgid "DHCP option sent even if the client does not request it."
+msgstr ""
+
+# OK
+#: option.c:385
+msgid "Specify port to listen for DNS requests on (defaults to 53)."
+msgstr "Sebutkan port untuk mendengarkan permintaan DNS (default port 53)."
+
+# OK
+#: option.c:386
+#, c-format
+msgid "Maximum supported UDP packet size for EDNS.0 (defaults to %s)."
+msgstr "Ukuran maksimum paket UDP yang didukung untuk EDNS.0 (default %s)."
+
+# OK
+#: option.c:387
+#, fuzzy
+msgid "Log DNS queries."
+msgstr "Permintaan log."
+
+# OK
+#: option.c:388
+#, fuzzy
+msgid "Force the originating port for upstream DNS queries."
+msgstr "Paksa port asal untuk permintaan ke atas."
+
+# OK
+#: option.c:389
+msgid "Do NOT read resolv.conf."
+msgstr "JANGAN baca resolv.conf."
+
+# OK
+#: option.c:390
+#, c-format
+msgid "Specify path to resolv.conf (defaults to %s)."
+msgstr "Sebutkan path ke resolv.conf (default %s)."
+
+# OK
+#: option.c:391
+#, fuzzy
+msgid "Specify path to file with server= options"
+msgstr "Sebutkan path file PID. (default %s)."
+
+# OK
+#: option.c:392
+msgid "Specify address(es) of upstream servers with optional domains."
+msgstr "Sebutkan alamat-alamat server di atas, boleh dilengkapi dengan nama domain."
+
+# OK
+#: option.c:393
+#, fuzzy
+msgid "Specify address of upstream servers for reverse address queries"
+msgstr "Sebutkan alamat-alamat server di atas, boleh dilengkapi dengan nama domain."
+
+# OK
+#: option.c:394
+msgid "Never forward queries to specified domains."
+msgstr "JANGAN pernah meneruskan permintaan ke domain yang disebutkan."
+
+# OK
+#: option.c:395
+msgid "Specify the domain to be assigned in DHCP leases."
+msgstr "Sebutkan domain yang digunakan dalam lease DHCP."
+
+# OK
+#: option.c:396
+msgid "Specify default target in an MX record."
+msgstr "Sebutkan tujuan default dalam rekord MX."
+
+# OK
+#: option.c:397
+msgid "Specify time-to-live in seconds for replies from /etc/hosts."
+msgstr "Sebutkan time-to-live dalam detik untuk jawaban dari /etc/hosts."
+
+# OK
+#: option.c:398
+#, fuzzy
+msgid "Specify time-to-live in seconds for negative caching."
+msgstr "Sebutkan time-to-live dalam detik untuk jawaban dari /etc/hosts."
+
+# OK
+#: option.c:399
+#, fuzzy
+msgid "Specify time-to-live in seconds for maximum TTL to send to clients."
+msgstr "Sebutkan time-to-live dalam detik untuk jawaban dari /etc/hosts."
+
+# OK
+#: option.c:400
+#, fuzzy
+msgid "Specify time-to-live ceiling for cache."
+msgstr "Sebutkan time-to-live dalam detik untuk jawaban dari /etc/hosts."
+
+# OK
+#: option.c:401
+#, fuzzy
+msgid "Specify time-to-live floor for cache."
+msgstr "Sebutkan time-to-live dalam detik untuk jawaban dari /etc/hosts."
+
+# OK
+#: option.c:402
+#, c-format
+msgid "Change to this user after startup. (defaults to %s)."
+msgstr "Ubah ke user ini setelah mulai. (default %s)."
+
+# OK
+#: option.c:403
+#, fuzzy
+msgid "Map DHCP vendor class to tag."
+msgstr "Memetakan kelas vendor DHCP ke daftar pilihan."
+
+# OK
+#: option.c:404
+msgid "Display dnsmasq version and copyright information."
+msgstr "Menampilkan versi dan informasi hak cipta dnsmasq."
+
+# OK
+#: option.c:405
+msgid "Translate IPv4 addresses from upstream servers."
+msgstr "Terjemahkan alamat-alamat IPv4 dari server-server di atas."
+
+# OK
+#: option.c:406
+msgid "Specify a SRV record."
+msgstr "Sebutkan rekord SRV."
+
+#: option.c:407
+msgid "Display this message. Use --help dhcp or --help dhcp6 for known DHCP options."
+msgstr ""
+
+# OK
+#: option.c:408
+#, fuzzy, c-format
+msgid "Specify path of PID file (defaults to %s)."
+msgstr "Sebutkan path file PID. (default %s)."
+
+# OK
+#: option.c:409
+#, c-format
+msgid "Specify maximum number of DHCP leases (defaults to %s)."
+msgstr "Sebutkan jumlah maksimum lease DHCP (default %s)."
+
+# OK
+#: option.c:410
+msgid "Answer DNS queries based on the interface a query was sent to."
+msgstr "Jawab permintaan DNS berdasarkan antarmuka dimana permintaan dikirimkan."
+
+# OK
+#: option.c:411
+msgid "Specify TXT DNS record."
+msgstr "Sebutkan rekord TXT DNS."
+
+# OK
+#: option.c:412
+#, fuzzy
+msgid "Specify PTR DNS record."
+msgstr "Sebutkan rekord TXT DNS."
+
+#: option.c:413
+msgid "Give DNS name to IPv4 address of interface."
+msgstr ""
+
+# OK
+#: option.c:414
+msgid "Bind only to interfaces in use."
+msgstr "Hanya kaitkan ke antarmuka yang sedang digunakan saja."
+
+# OK
+#: option.c:415
+#, c-format
+msgid "Read DHCP static host information from %s."
+msgstr "Baca informasi statik host DHCP dari %s."
+
+# OK
+#: option.c:416
+msgid "Enable the DBus interface for setting upstream servers, etc."
+msgstr "Mungkinkan antar muka DBus untuk menyetel server-server di atas, dsb."
+
+# OK
+#: option.c:417
+msgid "Do not provide DHCP on this interface, only provide DNS."
+msgstr "JANGAN menyediakan DHCP pada antarmuka ini, hanya menyediakan DNS."
+
+# OK
+#: option.c:418
+msgid "Enable dynamic address allocation for bootp."
+msgstr "Mungkinkan alokasi alamat dinamis untuk bootp."
+
+# OK
+#: option.c:419
+#, fuzzy
+msgid "Map MAC address (with wildcards) to option set."
+msgstr "Memetakan kelas vendor DHCP ke daftar pilihan."
+
+#: option.c:420
+msgid "Treat DHCP requests on aliases as arriving from interface."
+msgstr ""
+
+#: option.c:421
+msgid "Disable ICMP echo address checking in the DHCP server."
+msgstr ""
+
+#: option.c:422
+msgid "Shell script to run on DHCP lease creation and destruction."
+msgstr ""
+
+#: option.c:423
+msgid "Lua script to run on DHCP lease creation and destruction."
+msgstr ""
+
+#: option.c:424
+msgid "Run lease-change scripts as this user."
+msgstr ""
+
+#: option.c:425
+msgid "Call dhcp-script with changes to local ARP table."
+msgstr ""
+
+#: option.c:426
+msgid "Read configuration from all the files in this directory."
+msgstr ""
+
+# OK
+#: option.c:427
+#, fuzzy
+msgid "Log to this syslog facility or file. (defaults to DAEMON)"
+msgstr "Ubah ke user ini setelah mulai. (default %s)."
+
+#: option.c:428
+msgid "Do not use leasefile."
+msgstr ""
+
+# OK
+#: option.c:429
+#, fuzzy, c-format
+msgid "Maximum number of concurrent DNS queries. (defaults to %s)"
+msgstr "Sebutkan jumlah maksimum lease DHCP (default %s)."
+
+#: option.c:430
+#, c-format
+msgid "Clear DNS cache when reloading %s."
+msgstr ""
+
+#: option.c:431
+msgid "Ignore hostnames provided by DHCP clients."
+msgstr ""
+
+#: option.c:432
+msgid "Do NOT reuse filename and server fields for extra DHCP options."
+msgstr ""
+
+#: option.c:433
+msgid "Enable integrated read-only TFTP server."
+msgstr ""
+
+#: option.c:434
+msgid "Export files by TFTP only from the specified subtree."
+msgstr ""
+
+#: option.c:435
+msgid "Add client IP or hardware address to tftp-root."
+msgstr ""
+
+#: option.c:436
+msgid "Allow access only to files owned by the user running dnsmasq."
+msgstr ""
+
+#: option.c:437
+msgid "Do not terminate the service if TFTP directories are inaccessible."
+msgstr ""
+
+# OK
+#: option.c:438
+#, fuzzy, c-format
+msgid "Maximum number of concurrent TFTP transfers (defaults to %s)."
+msgstr "Sebutkan jumlah maksimum lease DHCP (default %s)."
+
+# OK
+#: option.c:439
+#, fuzzy
+msgid "Maximum MTU to use for TFTP transfers."
+msgstr "Sebutkan jumlah maksimum lease DHCP (default %s)."
+
+#: option.c:440
+msgid "Disable the TFTP blocksize extension."
+msgstr ""
+
+#: option.c:441
+msgid "Convert TFTP filenames to lowercase"
+msgstr ""
+
+#: option.c:442
+msgid "Ephemeral port range for use by TFTP transfers."
+msgstr ""
+
+#: option.c:443
+msgid "Extra logging for DHCP."
+msgstr ""
+
+#: option.c:444
+msgid "Enable async. logging; optionally set queue length."
+msgstr ""
+
+#: option.c:445
+msgid "Stop DNS rebinding. Filter private IP ranges when resolving."
+msgstr ""
+
+#: option.c:446
+msgid "Allow rebinding of 127.0.0.0/8, for RBL servers."
+msgstr ""
+
+#: option.c:447
+msgid "Inhibit DNS-rebind protection on this domain."
+msgstr ""
+
+#: option.c:448
+msgid "Always perform DNS queries to all servers."
+msgstr ""
+
+#: option.c:449
+msgid "Set tag if client includes matching option in request."
+msgstr ""
+
+#: option.c:450
+msgid "Use alternative ports for DHCP."
+msgstr ""
+
+# OK
+#: option.c:451
+#, fuzzy
+msgid "Specify NAPTR DNS record."
+msgstr "Sebutkan rekord TXT DNS."
+
+#: option.c:452
+msgid "Specify lowest port available for DNS query transmission."
+msgstr ""
+
+#: option.c:453
+msgid "Specify highest port available for DNS query transmission."
+msgstr ""
+
+#: option.c:454
+msgid "Use only fully qualified domain names for DHCP clients."
+msgstr ""
+
+#: option.c:455
+msgid "Generate hostnames based on MAC address for nameless clients."
+msgstr ""
+
+#: option.c:456
+msgid "Use these DHCP relays as full proxies."
+msgstr ""
+
+#: option.c:457
+msgid "Relay DHCP requests to a remote server"
+msgstr ""
+
+#: option.c:458
+msgid "Specify alias name for LOCAL DNS name."
+msgstr ""
+
+# OK
+#: option.c:459
+#, fuzzy
+msgid "Prompt to send to PXE clients."
+msgstr "Setel pilihan-pilihan tambahan yang akan disetel untuk klien-klien DHCP."
+
+#: option.c:460
+msgid "Boot service for PXE menu."
+msgstr ""
+
+#: option.c:461
+msgid "Check configuration syntax."
+msgstr ""
+
+#: option.c:462
+msgid "Add requestor's MAC address to forwarded DNS queries."
+msgstr ""
+
+#: option.c:463
+msgid "Add specified IP subnet to forwarded DNS queries."
+msgstr ""
+
+# OK
+#: option.c:464
+#, fuzzy
+msgid "Add client identification to forwarded DNS queries."
+msgstr "Paksa port asal untuk permintaan ke atas."
+
+# OK
+#: option.c:465
+#, fuzzy
+msgid "Proxy DNSSEC validation results from upstream nameservers."
+msgstr "Terjemahkan alamat-alamat IPv4 dari server-server di atas."
+
+#: option.c:466
+msgid "Attempt to allocate sequential IP addresses to DHCP clients."
+msgstr ""
+
+#: option.c:467
+msgid "Copy connection-track mark from queries to upstream connections."
+msgstr ""
+
+#: option.c:468
+msgid "Allow DHCP clients to do their own DDNS updates."
+msgstr ""
+
+#: option.c:469
+msgid "Send router-advertisements for interfaces doing DHCPv6"
+msgstr ""
+
+#: option.c:470
+msgid "Specify DUID_EN-type DHCPv6 server DUID"
+msgstr ""
+
+# OK
+#: option.c:471
+#, fuzzy
+msgid "Specify host (A/AAAA and PTR) records"
+msgstr "Sebutkan sebuah rekord MX."
+
+# OK
+#: option.c:472
+#, fuzzy
+msgid "Specify arbitrary DNS resource record"
+msgstr "Sebutkan rekord TXT DNS."
+
+# OK
+#: option.c:473
+#, fuzzy
+msgid "Bind to interfaces in use - check for new interfaces"
+msgstr "antarmuka tidak dikenal %s"
+
+#: option.c:474
+msgid "Export local names to global DNS"
+msgstr ""
+
+#: option.c:475
+msgid "Domain to export to global DNS"
+msgstr ""
+
+#: option.c:476
+msgid "Set TTL for authoritative replies"
+msgstr ""
+
+#: option.c:477
+msgid "Set authoritative zone information"
+msgstr ""
+
+#: option.c:478
+msgid "Secondary authoritative nameservers for forward domains"
+msgstr ""
+
+#: option.c:479
+msgid "Peers which are allowed to do zone transfer"
+msgstr ""
+
+#: option.c:480
+msgid "Specify ipsets to which matching domains should be added"
+msgstr ""
+
+#: option.c:481
+msgid "Specify a domain and address range for synthesised names"
+msgstr ""
+
+#: option.c:482
+msgid "Activate DNSSEC validation"
+msgstr ""
+
+#: option.c:483
+msgid "Specify trust anchor key digest."
+msgstr ""
+
+#: option.c:484
+msgid "Disable upstream checking for DNSSEC debugging."
+msgstr ""
+
+#: option.c:485
+msgid "Ensure answers without DNSSEC are in unsigned zones."
+msgstr ""
+
+#: option.c:486
+msgid "Don't check DNSSEC signature timestamps until first cache-reload"
+msgstr ""
+
+#: option.c:487
+msgid "Timestamp file to verify system clock for DNSSEC"
+msgstr ""
+
+#: option.c:489
+msgid "Specify DHCPv6 prefix class"
+msgstr ""
+
+#: option.c:491
+msgid "Set MTU, priority, resend-interval and router-lifetime"
+msgstr ""
+
+#: option.c:492
+msgid "Do not log routine DHCP."
+msgstr ""
+
+#: option.c:493
+msgid "Do not log routine DHCPv6."
+msgstr ""
+
+#: option.c:494
+msgid "Do not log RA."
+msgstr ""
+
+#: option.c:495
+msgid "Accept queries only from directly-connected networks."
+msgstr ""
+
+#: option.c:496
+msgid "Detect and remove DNS forwarding loops."
+msgstr ""
+
+#: option.c:497
+msgid "Ignore DNS responses containing ipaddr."
+msgstr ""
+
+#: option.c:498
+msgid "Set TTL in DNS responses with DHCP-derived addresses."
+msgstr ""
+
+#: option.c:499
+msgid "Delay DHCP replies for at least number of seconds."
+msgstr ""
+
+# OK
+#: option.c:703
+#, c-format
+msgid ""
+"Usage: dnsmasq [options]\n"
+"\n"
+msgstr ""
+"Penggunaan: dnsmasq [pilihan]\n"
+"\n"
+
+# OK
+#: option.c:705
+#, c-format
+msgid "Use short options only on the command line.\n"
+msgstr "Gunakan pilihan pendek saja pada perintah baris.\n"
+
+# OK
+#: option.c:707
+#, fuzzy, c-format
+msgid "Valid options are:\n"
+msgstr "Pilihan yang boleh adalah:\n"
+
+# OK
+#: option.c:754 option.c:868
+#, fuzzy
+msgid "bad address"
+msgstr "membaca %s - %d alamat"
+
+# OK
+#: option.c:779 option.c:783
+msgid "bad port"
+msgstr "port salah"
+
+#: option.c:797 option.c:826 option.c:861
+msgid "interface binding not supported"
+msgstr ""
+
+#: option.c:821 option.c:856
+msgid "interface can only be specified once"
+msgstr ""
+
+# OK
+#: option.c:835 option.c:3800
+#, fuzzy
+msgid "bad interface name"
+msgstr "nama MX salah"
+
+#: option.c:1062
+msgid "unsupported encapsulation for IPv6 option"
+msgstr ""
+
+# OK
+#: option.c:1076
+msgid "bad dhcp-option"
+msgstr "dhcp-option salah"
+
+# OK
+#: option.c:1144
+#, fuzzy
+msgid "bad IP address"
+msgstr "membaca %s - %d alamat"
+
+# OK
+#: option.c:1147 option.c:1286 option.c:3070
+#, fuzzy
+msgid "bad IPv6 address"
+msgstr "membaca %s - %d alamat"
+
+# OK
+#: option.c:1240
+#, fuzzy
+msgid "bad IPv4 address"
+msgstr "membaca %s - %d alamat"
+
+# OK
+#: option.c:1313 option.c:1407
+msgid "bad domain in dhcp-option"
+msgstr "domain dalam dhcp-option salah"
+
+# OK
+#: option.c:1445
+msgid "dhcp-option too long"
+msgstr "dhcp-option terlalu panjang"
+
+#: option.c:1452
+msgid "illegal dhcp-match"
+msgstr ""
+
+#: option.c:1514
+msgid "illegal repeated flag"
+msgstr ""
+
+#: option.c:1522
+msgid "illegal repeated keyword"
+msgstr ""
+
+# OK
+#: option.c:1593 option.c:4434
+#, fuzzy, c-format
+msgid "cannot access directory %s: %s"
+msgstr "tidak bisa membaca %s: %s"
+
+# OK
+#: option.c:1639 tftp.c:537
+#, fuzzy, c-format
+msgid "cannot access %s: %s"
+msgstr "tidak bisa membaca %s: %s"
+
+#: option.c:1727
+msgid "setting log facility is not possible under Android"
+msgstr ""
+
+#: option.c:1736
+msgid "bad log facility"
+msgstr ""
+
+# OK
+#: option.c:1789
+msgid "bad MX preference"
+msgstr "kesukaan MX salah"
+
+# OK
+#: option.c:1794
+msgid "bad MX name"
+msgstr "nama MX salah"
+
+# OK
+#: option.c:1808
+msgid "bad MX target"
+msgstr "target MX salah"
+
+#: option.c:1820
+msgid "cannot run scripts under uClinux"
+msgstr ""
+
+#: option.c:1822
+msgid "recompile with HAVE_SCRIPT defined to enable lease-change scripts"
+msgstr ""
+
+#: option.c:1826
+msgid "recompile with HAVE_LUASCRIPT defined to enable Lua scripts"
+msgstr ""
+
+# OK
+#: option.c:2095 option.c:2106 option.c:2143 option.c:2199 option.c:2482
+#, fuzzy
+msgid "bad prefix"
+msgstr "port salah"
+
+#: option.c:2504
+msgid "recompile with HAVE_IPSET defined to enable ipset directives"
+msgstr ""
+
+# OK
+#: option.c:2713
+#, fuzzy
+msgid "bad port range"
+msgstr "port salah"
+
+#: option.c:2738
+msgid "bad bridge-interface"
+msgstr ""
+
+#: option.c:2798
+msgid "only one tag allowed"
+msgstr ""
+
+# OK
+#: option.c:2818 option.c:2830 option.c:2939 option.c:2944 option.c:2983
+msgid "bad dhcp-range"
+msgstr "dhcp-range salah"
+
+# OK
+#: option.c:2845
+msgid "inconsistent DHCP range"
+msgstr "jangkauan DHCP tidak konsisten"
+
+#: option.c:2907
+msgid "prefix length must be exactly 64 for RA subnets"
+msgstr ""
+
+#: option.c:2909
+msgid "prefix length must be exactly 64 for subnet constructors"
+msgstr ""
+
+#: option.c:2913
+msgid "prefix length must be at least 64"
+msgstr ""
+
+# OK
+#: option.c:2916
+#, fuzzy
+msgid "inconsistent DHCPv6 range"
+msgstr "jangkauan DHCP tidak konsisten"
+
+#: option.c:2927
+msgid "prefix must be zero with \"constructor:\" argument"
+msgstr ""
+
+# OK
+#: option.c:3040 option.c:3088
+#, fuzzy
+msgid "bad hex constant"
+msgstr "dhcp-host salah"
+
+#: option.c:3062
+msgid "cannot match tags in --dhcp-host"
+msgstr ""
+
+# OK
+#: option.c:3110
+#, fuzzy, c-format
+msgid "duplicate dhcp-host IP address %s"
+msgstr "alamat IP kembar %s dalam direktif dhcp-config"
+
+# OK
+#: option.c:3168
+#, fuzzy
+msgid "bad DHCP host name"
+msgstr "nama MX salah"
+
+# OK
+#: option.c:3250
+#, fuzzy
+msgid "bad tag-if"
+msgstr "target MX salah"
+
+# OK
+#: option.c:3607 option.c:4030
+msgid "invalid port number"
+msgstr "nomor port tidak benar"
+
+# OK
+#: option.c:3669
+#, fuzzy
+msgid "bad dhcp-proxy address"
+msgstr "membaca %s - %d alamat"
+
+# OK
+#: option.c:3695
+#, fuzzy
+msgid "Bad dhcp-relay"
+msgstr "dhcp-range salah"
+
+#: option.c:3736
+msgid "bad RA-params"
+msgstr ""
+
+#: option.c:3745
+msgid "bad DUID"
+msgstr ""
+
+# OK
+#: option.c:3787
+#, fuzzy
+msgid "invalid alias range"
+msgstr "weight tidak benar"
+
+#: option.c:3841 option.c:3853
+msgid "bad CNAME"
+msgstr ""
+
+#: option.c:3857
+msgid "duplicate CNAME"
+msgstr ""
+
+# OK
+#: option.c:3880
+#, fuzzy
+msgid "bad PTR record"
+msgstr "rekord SRV salah"
+
+# OK
+#: option.c:3911
+#, fuzzy
+msgid "bad NAPTR record"
+msgstr "rekord SRV salah"
+
+# OK
+#: option.c:3945
+#, fuzzy
+msgid "bad RR record"
+msgstr "rekord SRV salah"
+
+# OK
+#: option.c:3975
+msgid "bad TXT record"
+msgstr "rekord TXT salah"
+
+# OK
+#: option.c:4016
+msgid "bad SRV record"
+msgstr "rekord SRV salah"
+
+# OK
+#: option.c:4023
+msgid "bad SRV target"
+msgstr "target SRV salah"
+
+# OK
+#: option.c:4037
+msgid "invalid priority"
+msgstr "prioritas tidak benar"
+
+# OK
+#: option.c:4040
+msgid "invalid weight"
+msgstr "weight tidak benar"
+
+# OK
+#: option.c:4064
+#, fuzzy
+msgid "Bad host-record"
+msgstr "rekord SRV salah"
+
+# OK
+#: option.c:4088
+#, fuzzy
+msgid "Bad name in host-record"
+msgstr "kesalahan nama di %s"
+
+# OK
+#: option.c:4153
+#, fuzzy
+msgid "bad trust anchor"
+msgstr "port salah"
+
+#: option.c:4167
+msgid "bad HEX in trust anchor"
+msgstr ""
+
+#: option.c:4177
+msgid "unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"
+msgstr ""
+
+# OK
+#: option.c:4237
+msgid "missing \""
+msgstr "kurang \""
+
+# OK
+#: option.c:4294
+msgid "bad option"
+msgstr "pilihan salah"
+
+# OK
+#: option.c:4296
+msgid "extraneous parameter"
+msgstr "parameter berlebihan"
+
+# OK
+#: option.c:4298
+msgid "missing parameter"
+msgstr "parameter kurang"
+
+# OK
+#: option.c:4300
+#, fuzzy
+msgid "illegal option"
+msgstr "pilihan salah"
+
+# OK
+#: option.c:4307
+msgid "error"
+msgstr "kesalahan"
+
+# OK
+#: option.c:4309
+#, fuzzy, c-format
+msgid " at line %d of %s"
+msgstr "%s pada baris %d dari %%s"
+
+# OK
+#: option.c:4324 option.c:4571 option.c:4607
+#, fuzzy, c-format
+msgid "read %s"
+msgstr "membaca %s"
+
+# OK
+#: option.c:4387 option.c:4510 tftp.c:715
+#, c-format
+msgid "cannot read %s: %s"
+msgstr "tidak bisa membaca %s: %s"
+
+#: option.c:4676
+msgid "junk found in command line"
+msgstr ""
+
+# OK
+#: option.c:4711
+#, c-format
+msgid "Dnsmasq version %s  %s\n"
+msgstr "Dnsmasq versi %s  %s\n"
+
+# OK
+#: option.c:4712
+#, fuzzy, c-format
+msgid ""
+"Compile time options: %s\n"
+"\n"
+msgstr ""
+"Pilihan-pilihan saat kompilasi %s\n"
+"\n"
+
+# OK
+#: option.c:4713
+#, c-format
+msgid "This software comes with ABSOLUTELY NO WARRANTY.\n"
+msgstr "Perangkat lunak ini tersedia TANPA JAMINAN SEDIKITPUN.\n"
+
+# OK
+#: option.c:4714
+#, c-format
+msgid "Dnsmasq is free software, and you are welcome to redistribute it\n"
+msgstr "Dnsdmasq adalah perangkat lunak bebas, dan Anda dipersilahkan untuk membagikannya\n"
+
+# OK
+#: option.c:4715
+#, fuzzy, c-format
+msgid "under the terms of the GNU General Public License, version 2 or 3.\n"
+msgstr "dengan aturan GNU General Public License, versi 2.\n"
+
+#: option.c:4726
+msgid "try --help"
+msgstr ""
+
+#: option.c:4728
+msgid "try -w"
+msgstr ""
+
+# OK
+#: option.c:4730
+#, fuzzy, c-format
+msgid "bad command line options: %s"
+msgstr "pilihan baris perintah salah: %s."
+
+#: option.c:4798
+#, c-format
+msgid "CNAME loop involving %s"
+msgstr ""
+
+# OK
+#: option.c:4834
+#, c-format
+msgid "cannot get host-name: %s"
+msgstr "tidak bisa mendapatkan host-name: %s"
+
+# OK
+#: option.c:4862
+msgid "only one resolv.conf file allowed in no-poll mode."
+msgstr "hanya satu file resolv.conf yang diperbolehkan dalam modus no-poll."
+
+# OK
+#: option.c:4872
+msgid "must have exactly one resolv.conf to read domain from."
+msgstr "harus mempunyai tepat satu resolv.conf untuk mendapatkan nama domain."
+
+# OK
+#: option.c:4875 network.c:1612 dhcp.c:816
+#, fuzzy, c-format
+msgid "failed to read %s: %s"
+msgstr "gagal membaca %s: %s"
+
+# OK
+#: option.c:4892
+#, c-format
+msgid "no search directive found in %s"
+msgstr "tidak ditemukan direktif search di %s"
+
+#: option.c:4913
+msgid "there must be a default domain when --dhcp-fqdn is set"
+msgstr ""
+
+#: option.c:4922
+msgid "syntax check OK"
+msgstr ""
+
+# OK
+#: forward.c:102
+#, fuzzy, c-format
+msgid "failed to send packet: %s"
+msgstr "gagal mendengarkan di socket: %s"
+
+#: forward.c:597
+msgid "discarding DNS reply: subnet option mismatch"
+msgstr ""
+
+# OK
+#: forward.c:651
+#, c-format
+msgid "nameserver %s refused to do a recursive query"
+msgstr "nameserver %s menolak melakukan resolusi rekursif"
+
+#: forward.c:683
+#, c-format
+msgid "possible DNS-rebind attack detected: %s"
+msgstr ""
+
+#: forward.c:1244 forward.c:1681
+msgid "Ignoring query from non-local network"
+msgstr ""
+
+# OK
+#: forward.c:2166
+#, fuzzy, c-format
+msgid "Maximum number of concurrent DNS queries reached (max: %d)"
+msgstr "Sebutkan jumlah maksimum lease DHCP (default %s)."
+
+# OK
+#: network.c:720
+#, fuzzy, c-format
+msgid "failed to create listening socket for %s: %s"
+msgstr "gagal membuat socket: %s "
+
+#: network.c:1031
+#, c-format
+msgid "LOUD WARNING: listening on %s may accept requests via interfaces other than %s"
+msgstr ""
+
+#: network.c:1038
+msgid "LOUD WARNING: use --bind-dynamic rather than --bind-interfaces to avoid DNS amplification attacks via these interface(s)"
+msgstr ""
+
+# OK
+#: network.c:1047
+#, fuzzy, c-format
+msgid "warning: using interface %s instead"
+msgstr "peringatan: antarmuka %s tidak ada"
+
+# OK
+#: network.c:1056
+#, fuzzy, c-format
+msgid "warning: no addresses found for interface %s"
+msgstr "menggunakan alamat lokal saja untuk %s %s"
+
+# OK
+#: network.c:1114
+#, fuzzy, c-format
+msgid "interface %s failed to join DHCPv6 multicast group: %s"
+msgstr "gagal mem-bind socket server DHCP: %s"
+
+#: network.c:1119
+msgid "try increasing /proc/sys/net/core/optmem_max"
+msgstr ""
+
+#: network.c:1322
+#, fuzzy, c-format
+msgid "failed to bind server socket for %s: %s"
+msgstr "gagal mem-bind socket untuk mendengarkan %s: %s"
+
+# OK
+#: network.c:1517
+#, c-format
+msgid "ignoring nameserver %s - local interface"
+msgstr "mengabaikan nameserver %s - antarmuka lokal"
+
+# OK
+#: network.c:1528
+#, fuzzy, c-format
+msgid "ignoring nameserver %s - cannot make/bind socket: %s"
+msgstr "mengabaikan nameserver %s - tak dapat membuat/mem-bind socket: %s"
+
+#: network.c:1548
+msgid "(no DNSSEC)"
+msgstr ""
+
+# OK
+#: network.c:1551
+msgid "unqualified"
+msgstr "tidak memenuhi syarat"
+
+#: network.c:1551
+msgid "names"
+msgstr ""
+
+#: network.c:1553
+msgid "default"
+msgstr ""
+
+# OK
+#: network.c:1555
+msgid "domain"
+msgstr "domain"
+
+# OK
+#: network.c:1561
+#, c-format
+msgid "using local addresses only for %s %s"
+msgstr "menggunakan alamat lokal saja untuk %s %s"
+
+# OK
+#: network.c:1564
+#, fuzzy, c-format
+msgid "using standard nameservers for %s %s"
+msgstr "menggunakan nameserver %s#%d untuk %s %s"
+
+# OK
+#: network.c:1566
+#, fuzzy, c-format
+msgid "using nameserver %s#%d for %s %s %s"
+msgstr "menggunakan nameserver %s#%d untuk %s %s"
+
+# OK
+#: network.c:1570
+#, fuzzy, c-format
+msgid "NOT using nameserver %s#%d - query loop detected"
+msgstr "menggunakan nameserver %s#%d untuk %s %s"
+
+# OK
+#: network.c:1573
+#, fuzzy, c-format
+msgid "using nameserver %s#%d(via %s)"
+msgstr "menggunakan nameserver %s#%d"
+
+# OK
+#: network.c:1575
+#, c-format
+msgid "using nameserver %s#%d"
+msgstr "menggunakan nameserver %s#%d"
+
+# OK
+#: network.c:1580
+#, fuzzy, c-format
+msgid "using %d more local addresses"
+msgstr "menggunakan nameserver %s#%d"
+
+# OK
+#: network.c:1582
+#, fuzzy, c-format
+msgid "using %d more nameservers"
+msgstr "menggunakan nameserver %s#%d"
+
+#: dnsmasq.c:166
+msgid "dhcp-hostsdir, dhcp-optsdir and hostsdir are not supported on this platform"
+msgstr ""
+
+#: dnsmasq.c:181
+msgid "no root trust anchor provided for DNSSEC"
+msgstr ""
+
+#: dnsmasq.c:184
+msgid "cannot reduce cache size from default when DNSSEC enabled"
+msgstr ""
+
+# OK
+#: dnsmasq.c:186
+#, fuzzy
+msgid "DNSSEC not available: set HAVE_DNSSEC in src/config.h"
+msgstr "DBus tidak tersedia: setel HAVE_DBUS dalam src/config.h"
+
+# OK
+#: dnsmasq.c:192
+#, fuzzy
+msgid "TFTP server not available: set HAVE_TFTP in src/config.h"
+msgstr "DBus tidak tersedia: setel HAVE_DBUS dalam src/config.h"
+
+#: dnsmasq.c:197
+msgid "cannot use --conntrack AND --query-port"
+msgstr ""
+
+# OK
+#: dnsmasq.c:200
+#, fuzzy
+msgid "conntrack support not available: set HAVE_CONNTRACK in src/config.h"
+msgstr "DBus tidak tersedia: setel HAVE_DBUS dalam src/config.h"
+
+#: dnsmasq.c:205
+msgid "asynchronous logging is not available under Solaris"
+msgstr ""
+
+#: dnsmasq.c:210
+msgid "asynchronous logging is not available under Android"
+msgstr ""
+
+# OK
+#: dnsmasq.c:215
+#, fuzzy
+msgid "authoritative DNS not available: set HAVE_AUTH in src/config.h"
+msgstr "DBus tidak tersedia: setel HAVE_DBUS dalam src/config.h"
+
+# OK
+#: dnsmasq.c:220
+#, fuzzy
+msgid "loop detection not available: set HAVE_LOOP in src/config.h"
+msgstr "DBus tidak tersedia: setel HAVE_DBUS dalam src/config.h"
+
+#: dnsmasq.c:227
+msgid "max_port cannot be smaller than min_port"
+msgstr ""
+
+#: dnsmasq.c:234
+msgid "zone serial must be configured in --auth-soa"
+msgstr ""
+
+#: dnsmasq.c:252
+msgid "dhcp-range constructor not available on this platform"
+msgstr ""
+
+#: dnsmasq.c:298
+msgid "cannot set --bind-interfaces and --bind-dynamic"
+msgstr ""
+
+# OK
+#: dnsmasq.c:301
+#, c-format
+msgid "failed to find list of interfaces: %s"
+msgstr "gagal mendapatkan daftar antarmuka: %s"
+
+# OK
+#: dnsmasq.c:310
+#, c-format
+msgid "unknown interface %s"
+msgstr "antarmuka tidak dikenal %s"
+
+# OK
+#: dnsmasq.c:374 dnsmasq.c:1037
+#, c-format
+msgid "DBus error: %s"
+msgstr "DBus error: %s"
+
+# OK
+#: dnsmasq.c:377
+msgid "DBus not available: set HAVE_DBUS in src/config.h"
+msgstr "DBus tidak tersedia: setel HAVE_DBUS dalam src/config.h"
+
+#: dnsmasq.c:405
+#, c-format
+msgid "unknown user or group: %s"
+msgstr ""
+
+#: dnsmasq.c:460
+#, c-format
+msgid "cannot chdir to filesystem root: %s"
+msgstr ""
+
+# OK
+#: dnsmasq.c:716
+#, fuzzy, c-format
+msgid "started, version %s DNS disabled"
+msgstr "dimulai, cache versi %s di disable"
+
+# OK
+#: dnsmasq.c:720
+#, c-format
+msgid "started, version %s cachesize %d"
+msgstr "dimulai, versi %s ukuran cache %d"
+
+# OK
+#: dnsmasq.c:722
+#, c-format
+msgid "started, version %s cache disabled"
+msgstr "dimulai, cache versi %s di disable"
+
+#: dnsmasq.c:725
+msgid "DNS service limited to local subnets"
+msgstr ""
+
+# OK
+#: dnsmasq.c:728
+#, c-format
+msgid "compile time options: %s"
+msgstr "pilihan-pilihan saat kompilasi: %s"
+
+# OK
+#: dnsmasq.c:734
+msgid "DBus support enabled: connected to system bus"
+msgstr "dukungan DBus dimungkinkan: terkoneksi pada bus sistem"
+
+# OK
+#: dnsmasq.c:736
+msgid "DBus support enabled: bus connection pending"
+msgstr "dukungan DBus dimungkinkan: koneksi bus ditunda"
+
+#: dnsmasq.c:754
+msgid "DNSSEC validation enabled"
+msgstr ""
+
+#: dnsmasq.c:758
+msgid "DNSSEC signature timestamps not checked until first cache reload"
+msgstr ""
+
+#: dnsmasq.c:761
+msgid "DNSSEC signature timestamps not checked until system time valid"
+msgstr ""
+
+# OK
+#: dnsmasq.c:766
+#, fuzzy, c-format
+msgid "warning: failed to change owner of %s: %s"
+msgstr "gagal memuat nama-nama dari %s: %s"
+
+# OK
+#: dnsmasq.c:770
+msgid "setting --bind-interfaces option because of OS limitations"
+msgstr "setelan opsi --bind-interfaces disebabkan keterbatasan OS"
+
+# OK
+#: dnsmasq.c:782
+#, c-format
+msgid "warning: interface %s does not currently exist"
+msgstr "peringatan: antarmuka %s tidak ada"
+
+#: dnsmasq.c:787
+msgid "warning: ignoring resolv-file flag because no-resolv is set"
+msgstr ""
+
+# OK
+#: dnsmasq.c:790
+#, fuzzy
+msgid "warning: no upstream servers configured"
+msgstr "menyetel server-server di atas dengan DBus"
+
+#: dnsmasq.c:794
+#, c-format
+msgid "asynchronous logging enabled, queue limit is %d messages"
+msgstr ""
+
+#: dnsmasq.c:815
+msgid "IPv6 router advertisement enabled"
+msgstr ""
+
+#: dnsmasq.c:820
+#, c-format
+msgid "DHCP, sockets bound exclusively to interface %s"
+msgstr ""
+
+#: dnsmasq.c:834
+msgid "root is "
+msgstr ""
+
+# OK
+#: dnsmasq.c:834
+#, fuzzy
+msgid "enabled"
+msgstr "di disable"
+
+#: dnsmasq.c:836
+msgid "secure mode"
+msgstr ""
+
+#: dnsmasq.c:839
+#, c-format
+msgid "warning: %s inaccessible"
+msgstr ""
+
+#: dnsmasq.c:843
+#, c-format
+msgid "warning: TFTP directory %s inaccessible"
+msgstr ""
+
+#: dnsmasq.c:869
+#, c-format
+msgid "restricting maximum simultaneous TFTP transfers to %d"
+msgstr ""
+
+# OK
+#: dnsmasq.c:1039
+msgid "connected to system DBus"
+msgstr "terhubung ke sistem DBus"
+
+#: dnsmasq.c:1189
+#, c-format
+msgid "cannot fork into background: %s"
+msgstr ""
+
+# OK
+#: dnsmasq.c:1192
+#, fuzzy, c-format
+msgid "failed to create helper: %s"
+msgstr "gagal membaca %s: %s"
+
+#: dnsmasq.c:1195
+#, c-format
+msgid "setting capabilities failed: %s"
+msgstr ""
+
+# OK
+#: dnsmasq.c:1198
+#, fuzzy, c-format
+msgid "failed to change user-id to %s: %s"
+msgstr "gagal memuat nama-nama dari %s: %s"
+
+# OK
+#: dnsmasq.c:1201
+#, fuzzy, c-format
+msgid "failed to change group-id to %s: %s"
+msgstr "gagal memuat nama-nama dari %s: %s"
+
+# OK
+#: dnsmasq.c:1204
+#, fuzzy, c-format
+msgid "failed to open pidfile %s: %s"
+msgstr "gagal membaca %s: %s"
+
+# OK
+#: dnsmasq.c:1207
+#, fuzzy, c-format
+msgid "cannot open log %s: %s"
+msgstr "tidak bisa membuka %s:%s"
+
+# OK
+#: dnsmasq.c:1210
+#, fuzzy, c-format
+msgid "failed to load Lua script: %s"
+msgstr "gagal memuat %S: %s"
+
+#: dnsmasq.c:1213
+#, c-format
+msgid "TFTP directory %s inaccessible: %s"
+msgstr ""
+
+# OK
+#: dnsmasq.c:1216
+#, fuzzy, c-format
+msgid "cannot create timestamp file %s: %s"
+msgstr "tidak dapat membuka atau membuat file lease: %s"
+
+#: dnsmasq.c:1239
+msgid "now checking DNSSEC signature timestamps"
+msgstr ""
+
+#: dnsmasq.c:1307
+#, c-format
+msgid "script process killed by signal %d"
+msgstr ""
+
+#: dnsmasq.c:1311
+#, c-format
+msgid "script process exited with status %d"
+msgstr ""
+
+# OK
+#: dnsmasq.c:1315
+#, fuzzy, c-format
+msgid "failed to execute %s: %s"
+msgstr "gagal mengakses %s: %s"
+
+# OK
+#: dnsmasq.c:1379 dnssec.c:479 dnssec.c:525
+#, fuzzy, c-format
+msgid "failed to update mtime on %s: %s"
+msgstr "gagal membaca %s: %s"
+
+#: dnsmasq.c:1386
+msgid "exiting on receipt of SIGTERM"
+msgstr "keluar karena menerima SIGTERM"
+
+# OK
+#: dnsmasq.c:1414
+#, fuzzy, c-format
+msgid "failed to access %s: %s"
+msgstr "gagal mengakses %s: %s"
+
+# OK
+#: dnsmasq.c:1444
+#, c-format
+msgid "reading %s"
+msgstr "membaca %s"
+
+# OK
+#: dnsmasq.c:1455
+#, fuzzy, c-format
+msgid "no servers found in %s, will retry"
+msgstr "tidak ditemukan direktif search di %s"
+
+# OK
+#: dhcp.c:53
+#, c-format
+msgid "cannot create DHCP socket: %s"
+msgstr "tidak bisa membuat socket DHCP: %s"
+
+# OK
+#: dhcp.c:68
+#, c-format
+msgid "failed to set options on DHCP socket: %s"
+msgstr "gagal menyetel opsi pada socket DHCP: %s"
+
+# OK
+#: dhcp.c:89
+#, fuzzy, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"
+msgstr "gagal menyetel SO_REUSEADDR pada socket DHCP: %s"
+
+# OK
+#: dhcp.c:101
+#, c-format
+msgid "failed to bind DHCP server socket: %s"
+msgstr "gagal mem-bind socket server DHCP: %s"
+
+# OK
+#: dhcp.c:127
+#, c-format
+msgid "cannot create ICMP raw socket: %s."
+msgstr "tidak dapat membuat socket ICMP raw: %s"
+
+# OK
+#: dhcp.c:252 dhcp6.c:173
+#, fuzzy, c-format
+msgid "unknown interface %s in bridge-interface"
+msgstr "antarmuka tidak dikenal %s"
+
+#: dhcp.c:293
+#, c-format
+msgid "DHCP packet received on %s which has no address"
+msgstr ""
+
+#: dhcp.c:427
+#, c-format
+msgid "ARP-cache injection failed: %s"
+msgstr ""
+
+#: dhcp.c:470
+#, c-format
+msgid "Error sending DHCP packet to %s: %s"
+msgstr ""
+
+# OK
+#: dhcp.c:531
+#, c-format
+msgid "DHCP range %s -- %s is not consistent with netmask %s"
+msgstr "jangkauan DHCP %s -- %s tidak konsisten dengan netmask %s"
+
+# OK
+#: dhcp.c:854
+#, fuzzy, c-format
+msgid "bad line at %s line %d"
+msgstr "kesalahan nama pada %s baris %d"
+
+#: dhcp.c:897
+#, c-format
+msgid "ignoring %s line %d, duplicate name or IP address"
+msgstr ""
+
+#: dhcp.c:1041 rfc3315.c:2149
+#, c-format
+msgid "DHCP relay %s -> %s"
+msgstr ""
+
+# OK
+#: lease.c:98
+msgid "too many stored leases"
+msgstr "terlalu banyak lease yang disimpan"
+
+# OK
+#: lease.c:166
+#, fuzzy, c-format
+msgid "cannot open or create lease file %s: %s"
+msgstr "tidak dapat membuka atau membuat file lease: %s"
+
+#: lease.c:175
+#, c-format
+msgid "failed to parse lease database, invalid line: %s %s %s %s ..."
+msgstr ""
+
+# OK
+#: lease.c:180
+#, fuzzy, c-format
+msgid "failed to read lease file %s: %s"
+msgstr "gagal membaca %s: %s"
+
+# OK
+#: lease.c:196
+#, fuzzy, c-format
+msgid "cannot run lease-init script %s: %s"
+msgstr "tidak bisa membaca %s: %s"
+
+#: lease.c:202
+#, c-format
+msgid "lease-init script returned exit code %s"
+msgstr ""
+
+# OK
+#: lease.c:373
+#, fuzzy, c-format
+msgid "failed to write %s: %s (retry in %us)"
+msgstr "gagal membaca %s: %s"
+
+#: lease.c:937
+#, c-format
+msgid "Ignoring domain %s for DHCP host name %s"
+msgstr ""
+
+# OK
+#: rfc2131.c:347
+#, c-format
+msgid "no address range available for DHCP request %s %s"
+msgstr "tidak ada alamat yang bisa dipakai untuk permintaan DHCP %s %s"
+
+# OK
+#: rfc2131.c:348
+msgid "with subnet selector"
+msgstr "dengan pemilih subnet"
+
+# OK
+#: rfc2131.c:348
+msgid "via"
+msgstr "lewat"
+
+# OK
+#: rfc2131.c:360
+#, fuzzy, c-format
+msgid "%u available DHCP subnet: %s/%s"
+msgstr "tidak ada alamat yang bisa dipakai untuk permintaan DHCP %s %s"
+
+#: rfc2131.c:363 rfc3315.c:306
+#, c-format
+msgid "%u available DHCP range: %s -- %s"
+msgstr ""
+
+# OK
+#: rfc2131.c:474
+#, fuzzy, c-format
+msgid "%u vendor class: %s"
+msgstr "DBus error: %s"
+
+# OK
+#: rfc2131.c:476
+#, fuzzy, c-format
+msgid "%u user class: %s"
+msgstr "DBus error: %s"
+
+# OK
+#: rfc2131.c:510
+msgid "disabled"
+msgstr "di disable"
+
+# OK
+#: rfc2131.c:551 rfc2131.c:1006 rfc2131.c:1430 rfc3315.c:616 rfc3315.c:869
+#: rfc3315.c:1148
+msgid "ignored"
+msgstr "diabaikan"
+
+# OK
+#: rfc2131.c:566 rfc2131.c:1239 rfc3315.c:919
+msgid "address in use"
+msgstr "alamat telah digunakan"
+
+# OK
+#: rfc2131.c:580 rfc2131.c:1060
+msgid "no address available"
+msgstr "tak ada alamat yang tersedia"
+
+# OK
+#: rfc2131.c:587 rfc2131.c:1202
+msgid "wrong network"
+msgstr "jaringan yang salah"
+
+# OK
+#: rfc2131.c:602
+msgid "no address configured"
+msgstr "tak ada alamat yang disetel"
+
+# OK
+#: rfc2131.c:608 rfc2131.c:1252
+msgid "no leases left"
+msgstr "tak ada lease yang tersisa"
+
+#: rfc2131.c:703 rfc3315.c:482
+#, c-format
+msgid "%u client provides name: %s"
+msgstr ""
+
+#: rfc2131.c:808
+msgid "PXE BIS not supported"
+msgstr ""
+
+# OK
+#: rfc2131.c:974 rfc3315.c:1242
+#, fuzzy, c-format
+msgid "disabling DHCP static address %s for %s"
+msgstr "men-disable alamat statik DHCP %s"
+
+# OK
+#: rfc2131.c:995
+msgid "unknown lease"
+msgstr "lease tidak diketahui"
+
+#: rfc2131.c:1029
+#, c-format
+msgid "not using configured address %s because it is leased to %s"
+msgstr ""
+
+#: rfc2131.c:1039
+#, c-format
+msgid "not using configured address %s because it is in use by the server or relay"
+msgstr ""
+
+#: rfc2131.c:1042
+#, c-format
+msgid "not using configured address %s because it was previously declined"
+msgstr ""
+
+#: rfc2131.c:1058 rfc2131.c:1245
+msgid "no unique-id"
+msgstr ""
+
+#: rfc2131.c:1140
+msgid "wrong server-ID"
+msgstr ""
+
+# OK
+#: rfc2131.c:1159
+msgid "wrong address"
+msgstr "alamat salah"
+
+# OK
+#: rfc2131.c:1177 rfc3315.c:1015
+msgid "lease not found"
+msgstr "lease tak ditemukan"
+
+# OK
+#: rfc2131.c:1210
+msgid "address not available"
+msgstr "alamat tak tersedia"
+
+# OK
+#: rfc2131.c:1221
+msgid "static lease available"
+msgstr "lease statik tak tersedia"
+
+# OK
+#: rfc2131.c:1225
+msgid "address reserved"
+msgstr "alamat telah dipesan"
+
+#: rfc2131.c:1233
+#, c-format
+msgid "abandoning lease to %s of %s"
+msgstr ""
+
+#: rfc2131.c:1757
+#, c-format
+msgid "%u bootfile name: %s"
+msgstr ""
+
+# OK
+#: rfc2131.c:1766
+#, fuzzy, c-format
+msgid "%u server name: %s"
+msgstr "DBus error: %s"
+
+# OK
+#: rfc2131.c:1774
+#, fuzzy, c-format
+msgid "%u next server: %s"
+msgstr "DBus error: %s"
+
+#: rfc2131.c:1777
+#, c-format
+msgid "%u broadcast response"
+msgstr ""
+
+#: rfc2131.c:1840
+#, c-format
+msgid "cannot send DHCP/BOOTP option %d: no space left in packet"
+msgstr ""
+
+#: rfc2131.c:2131
+msgid "PXE menu too large"
+msgstr ""
+
+# OK
+#: rfc2131.c:2270 rfc3315.c:1515
+#, fuzzy, c-format
+msgid "%u requested options: %s"
+msgstr "pilihan-pilihan saat kompilasi: %s"
+
+#: rfc2131.c:2587
+#, c-format
+msgid "cannot send RFC3925 option: too many options for enterprise number %d"
+msgstr ""
+
+#: rfc2131.c:2650
+#, c-format
+msgid "%u reply delay: %d"
+msgstr ""
+
+# OK
+#: netlink.c:77
+#, fuzzy, c-format
+msgid "cannot create netlink socket: %s"
+msgstr "tidak bisa mem-bind netlink socket: %s"
+
+# OK
+#: netlink.c:355
+#, fuzzy, c-format
+msgid "netlink returns error: %s"
+msgstr "DBus error: %s"
+
+# OK
+#: dbus.c:186
+msgid "attempt to set an IPv6 server address via DBus - no IPv6 support"
+msgstr "mencoba menyetel sebuah alamat IPv6 server lewat DBus - tidak ada dukungan untuk IPv6"
+
+#: dbus.c:439
+#, c-format
+msgid "Enabling --%s option from D-Bus"
+msgstr ""
+
+#: dbus.c:444
+#, c-format
+msgid "Disabling --%s option from D-Bus"
+msgstr ""
+
+# OK
+#: dbus.c:690
+msgid "setting upstream servers from DBus"
+msgstr "menyetel server-server di atas dengan DBus"
+
+# OK
+#: dbus.c:737
+msgid "could not register a DBus message handler"
+msgstr "tidak bisa mendaftar sebuah DBus message handler"
+
+# OK
+#: bpf.c:265
+#, c-format
+msgid "cannot create DHCP BPF socket: %s"
+msgstr "tidak dapat membuat socket DHCP BPF: %s"
+
+# OK
+#: bpf.c:293
+#, fuzzy, c-format
+msgid "DHCP request for unsupported hardware type (%d) received on %s"
+msgstr "permintaan DHCP untuk tipe hardware yang tidak didukung (%d) diterima pada %s"
+
+# OK
+#: bpf.c:378
+#, fuzzy, c-format
+msgid "cannot create PF_ROUTE socket: %s"
+msgstr "tidak bisa membuat socket DHCP: %s"
+
+#: bpf.c:399
+msgid "Unknown protocol version from route socket"
+msgstr ""
+
+#: helper.c:153
+msgid "lease() function missing in Lua script"
+msgstr ""
+
+#: tftp.c:319
+msgid "unable to get free port for TFTP"
+msgstr ""
+
+#: tftp.c:335
+#, c-format
+msgid "unsupported request from %s"
+msgstr ""
+
+# OK
+#: tftp.c:483
+#, fuzzy, c-format
+msgid "file %s not found"
+msgstr "lease tak ditemukan"
+
+#: tftp.c:592
+#, c-format
+msgid "error %d %s received from %s"
+msgstr ""
+
+# OK
+#: tftp.c:634
+#, fuzzy, c-format
+msgid "failed sending %s to %s"
+msgstr "gagal membaca %s: %s"
+
+#: tftp.c:634
+#, c-format
+msgid "sent %s to %s"
+msgstr ""
+
+#: log.c:190
+#, c-format
+msgid "overflow: %d log entries lost"
+msgstr ""
+
+#: log.c:268
+#, c-format
+msgid "log failed: %s"
+msgstr ""
+
+# OK
+#: log.c:471
+msgid "FAILED to start up"
+msgstr "GAGAL untuk memulai"
+
+#: conntrack.c:65
+#, c-format
+msgid "Conntrack connection mark retrieval failed: %s"
+msgstr ""
+
+# OK
+#: dhcp6.c:52
+#, fuzzy, c-format
+msgid "cannot create DHCPv6 socket: %s"
+msgstr "tidak bisa membuat socket DHCP: %s"
+
+# OK
+#: dhcp6.c:73
+#, fuzzy, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"
+msgstr "gagal menyetel SO_REUSEADDR pada socket DHCP: %s"
+
+# OK
+#: dhcp6.c:85
+#, fuzzy, c-format
+msgid "failed to bind DHCPv6 server socket: %s"
+msgstr "gagal mem-bind socket server DHCP: %s"
+
+# OK
+#: rfc3315.c:157
+#, fuzzy, c-format
+msgid "no address range available for DHCPv6 request from relay at %s"
+msgstr "tidak ada alamat yang bisa dipakai untuk permintaan DHCP %s %s"
+
+# OK
+#: rfc3315.c:166
+#, fuzzy, c-format
+msgid "no address range available for DHCPv6 request via %s"
+msgstr "tidak ada alamat yang bisa dipakai untuk permintaan DHCP %s %s"
+
+# OK
+#: rfc3315.c:303
+#, fuzzy, c-format
+msgid "%u available DHCPv6 subnet: %s/%d"
+msgstr "tidak ada alamat yang bisa dipakai untuk permintaan DHCP %s %s"
+
+# OK
+#: rfc3315.c:386
+#, fuzzy, c-format
+msgid "%u vendor class: %u"
+msgstr "DBus error: %s"
+
+# OK
+#: rfc3315.c:434
+#, fuzzy, c-format
+msgid "%u client MAC address: %s"
+msgstr "tidak ada antarmuka dengan alamat %s"
+
+# OK
+#: rfc3315.c:673
+#, fuzzy, c-format
+msgid "unknown prefix-class %d"
+msgstr "lease tidak diketahui"
+
+# OK
+#: rfc3315.c:816 rfc3315.c:911
+#, fuzzy
+msgid "address unavailable"
+msgstr "alamat tak tersedia"
+
+#: rfc3315.c:828 rfc3315.c:959 rfc3315.c:1292
+msgid "success"
+msgstr ""
+
+# OK
+#: rfc3315.c:843 rfc3315.c:852 rfc3315.c:967 rfc3315.c:969
+#, fuzzy
+msgid "no addresses available"
+msgstr "tak ada alamat yang tersedia"
+
+#: rfc3315.c:946
+msgid "not on link"
+msgstr ""
+
+#: rfc3315.c:1019 rfc3315.c:1204 rfc3315.c:1281
+msgid "no binding found"
+msgstr ""
+
+#: rfc3315.c:1057
+msgid "deprecated"
+msgstr ""
+
+# OK
+#: rfc3315.c:1062
+#, fuzzy
+msgid "address invalid"
+msgstr "alamat telah digunakan"
+
+#: rfc3315.c:1109
+msgid "confirm failed"
+msgstr ""
+
+# OK
+#: rfc3315.c:1125
+#, fuzzy
+msgid "all addresses still on link"
+msgstr "kesalahan nama pada %s baris %d"
+
+#: rfc3315.c:1213
+msgid "release received"
+msgstr ""
+
+#: rfc3315.c:2140
+msgid "Cannot multicast to DHCPv6 server without correct interface"
+msgstr ""
+
+#: dhcp-common.c:145
+#, c-format
+msgid "Ignoring duplicate dhcp-option %d"
+msgstr ""
+
+#: dhcp-common.c:222
+#, c-format
+msgid "%u tags: %s"
+msgstr ""
+
+#: dhcp-common.c:407
+#, c-format
+msgid "%s has more than one address in hostsfile, using %s for DHCP"
+msgstr ""
+
+# OK
+#: dhcp-common.c:430
+#, c-format
+msgid "duplicate IP address %s (%s) in dhcp-config directive"
+msgstr "alamat IP kembar %s (%s) dalam direktif dhcp-config"
+
+# OK
+#: dhcp-common.c:494
+#, fuzzy, c-format
+msgid "failed to set SO_BINDTODEVICE on DHCP socket: %s"
+msgstr "gagal menyetel SO_REUSEADDR pada socket DHCP: %s"
+
+#: dhcp-common.c:615
+#, c-format
+msgid "Known DHCP options:\n"
+msgstr ""
+
+#: dhcp-common.c:626
+#, c-format
+msgid "Known DHCPv6 options:\n"
+msgstr ""
+
+#: dhcp-common.c:823
+msgid ", prefix deprecated"
+msgstr ""
+
+#: dhcp-common.c:826
+#, c-format
+msgid ", lease time "
+msgstr ""
+
+#: dhcp-common.c:868
+#, c-format
+msgid "%s stateless on %s%.0s%.0s%s"
+msgstr ""
+
+# OK
+#: dhcp-common.c:870
+#, fuzzy, c-format
+msgid "%s, static leases only on %.0s%s%s%.0s"
+msgstr "DHCP, lease static pada %.0s%s, waktu lease %s"
+
+#: dhcp-common.c:872
+#, c-format
+msgid "%s, proxy on subnet %.0s%s%.0s%.0s"
+msgstr ""
+
+# OK
+#: dhcp-common.c:873
+#, fuzzy, c-format
+msgid "%s, IP range %s -- %s%s%.0s"
+msgstr "DHCP, jangkaun IP %s -- %s, waktu lease %s"
+
+#: dhcp-common.c:886
+#, c-format
+msgid "DHCPv4-derived IPv6 names on %s%s"
+msgstr ""
+
+# OK
+#: dhcp-common.c:889
+#, fuzzy, c-format
+msgid "router advertisement on %s%s"
+msgstr "DHCP, lease static pada %.0s%s, waktu lease %s"
+
+#: dhcp-common.c:900
+#, c-format
+msgid "DHCP relay from %s to %s via %s"
+msgstr ""
+
+#: dhcp-common.c:902
+#, c-format
+msgid "DHCP relay from %s to %s"
+msgstr ""
+
+# OK
+#: radv.c:110
+#, fuzzy, c-format
+msgid "cannot create ICMPv6 socket: %s"
+msgstr "tidak bisa membuat socket DHCP: %s"
+
+#: auth.c:449
+#, c-format
+msgid "ignoring zone transfer request from %s"
+msgstr ""
+
+# OK
+#: ipset.c:95
+#, fuzzy, c-format
+msgid "failed to find kernel version: %s"
+msgstr "gagal mem-bind socket server DHCP: %s"
+
+# OK
+#: ipset.c:114
+#, fuzzy, c-format
+msgid "failed to create IPset control socket: %s"
+msgstr "gagal membuat socket: %s "
+
+# OK
+#: ipset.c:233
+#, fuzzy, c-format
+msgid "failed to update ipset %s: %s"
+msgstr "gagal membaca %s: %s"
+
+#: dnssec.c:527
+msgid "system time considered valid, now checking DNSSEC signature timestamps."
+msgstr ""
+
+#: blockdata.c:58
+#, c-format
+msgid "DNSSEC memory in use %u, max %u, allocated %u"
+msgstr ""
+
+# OK
+#: tables.c:61
+#, fuzzy, c-format
+msgid "failed to access pf devices: %s"
+msgstr "gagal mengakses %s: %s"
+
+# OK
+#: tables.c:74
+#, fuzzy, c-format
+msgid "warning: no opened pf devices %s"
+msgstr "menggunakan alamat lokal saja untuk %s %s"
+
+# OK
+#: tables.c:82
+#, fuzzy, c-format
+msgid "error: cannot use table name %s"
+msgstr "tidak bisa mendapatkan host-name: %s"
+
+#: tables.c:90
+#, c-format
+msgid "error: cannot strlcpy table name %s"
+msgstr ""
+
+# OK
+#: tables.c:101
+#, fuzzy, c-format
+msgid "IPset: error:%s"
+msgstr "DBus error: %s"
+
+#: tables.c:108
+msgid "info: table created"
+msgstr ""
+
+#: tables.c:134
+#, c-format
+msgid "warning: DIOCR%sADDRS: %s"
+msgstr ""
+
+# OK
+#: tables.c:138
+#, fuzzy, c-format
+msgid "%d addresses %s"
+msgstr "membaca %s - %d alamat"
+
+# OK
+#: inotify.c:62
+#, fuzzy, c-format
+msgid "cannot access path %s: %s"
+msgstr "tidak bisa membaca %s: %s"
+
+# OK
+#: inotify.c:95
+#, fuzzy, c-format
+msgid "failed to create inotify: %s"
+msgstr "gagal membaca %s: %s"
+
+#: inotify.c:111
+#, c-format
+msgid "too many symlinks following %s"
+msgstr ""
+
+#: inotify.c:127
+#, c-format
+msgid "directory %s for resolv-file is missing, cannot poll"
+msgstr ""
+
+# OK
+#: inotify.c:131 inotify.c:168
+#, fuzzy, c-format
+msgid "failed to create inotify for %s: %s"
+msgstr "gagal membuat socket: %s "
+
+# OK
+#: inotify.c:153
+#, fuzzy, c-format
+msgid "bad dynamic directory %s: %s"
+msgstr "tidak bisa membaca %s: %s"
+
+#: inotify.c:255
+#, c-format
+msgid "inotify, new or changed file %s"
+msgstr ""
+
+# OK
+#, fuzzy
+#~ msgid "cannot cannonicalise resolv-file %s: %s"
+#~ msgstr "tidak dapat membuka atau membuat file lease: %s"
+
+# OK
+#~ msgid "duplicate IP address %s in dhcp-config directive."
+#~ msgstr "alamat IP kembar %s dalam direktif dhcp-config"
+
+# OK
+#, fuzzy
+#~ msgid "Specify path to Lua script (no default)."
+#~ msgstr "Sebutkan path file PID. (default %s)."
+
+# OK
+#~ msgid "TXT record string too long"
+#~ msgstr "string rekord TXT terlalu panjang"
+
+# OK
+#~ msgid "failed to set IPV6 options on listening socket: %s"
+#~ msgstr "gagal menyetel IPV6 pada socket: %s"
+
+#~ msgid "failed to bind listening socket for %s: %s"
+#~ msgstr "gagal mem-bind socket untuk mendengarkan %s: %s"
+
+# OK
+#~ msgid "must set exactly one interface on broken systems without IP_RECVIF"
+#~ msgstr "harus menyetel satu antarmuka saja pada sistem yang tidak benar dengan IP_RECVIF"
+
+# OK
+#~ msgid "Ignoring DHCP lease for %s because it has an illegal domain part"
+#~ msgstr "Mengabaikan lease DHCP untuk %s sebab terdapat bagian domain yang tidak sah"
+
+# OK
+#~ msgid "ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h"
+#~ msgstr "Integrasi dengan dhcpd ISC tidak tersedia: atur HAVE_ISC_READER dalam src/config.h"
+
+# OK
+#, fuzzy
+#~ msgid "illegal domain %s in dhcp-config directive."
+#~ msgstr "alamat IP kembar %s dalam direktif dhcp-config"
+
+# OK
+#~ msgid "running as root"
+#~ msgstr "berjalan menggunakan root"
+
+# OK
+#, fuzzy
+#~ msgid "read %s - %d hosts"
+#~ msgstr "membaca %s - %d alamat"
+
+# OK
+#~ msgid "domains"
+#~ msgstr "domain-domain"
+
+# OK
+#~ msgid "Ignoring DHCP host name %s because it has an illegal domain part"
+#~ msgstr "Mengabaikan nama host DHCP %s sebab memiliki bagian domain yang tidak sah"
+
+# OK
+#~ msgid "Display this message."
+#~ msgstr "Menampilkan pesan ini."
+
+# OK
+#~ msgid "failed to read %s: %m"
+#~ msgstr "gagal membaca %s: %m"
+
+# OK
+#~ msgid "failed to read %s:%m"
+#~ msgstr "gagal membaca %s:%m"
+
+# OK
+#~ msgid "More than one vendor class matches, using %s"
+#~ msgstr "Lebih dari satu kelas vendor yang sesuai, menggunakan %s"
+
+# OK
+#~ msgid "forwarding table overflow: check for server loops."
+#~ msgstr "meneruskan tabel overflow: memeriksa apakah terjadi loop server."
+
+# OK
+#~ msgid "nested includes not allowed"
+#~ msgstr "includes bersarang tidak diijinkan"
+
+# OK
+#~ msgid "DHCP, %s will be written every %s"
+#~ msgstr "DHCP, %s akan ditulis setiap %s"
+
+# OK
+#~ msgid "cannot create DHCP packet socket: %s. Is CONFIG_PACKET enabled in your kernel?"
+#~ msgstr "tidak dapat membuat socket packet DHCP: %s. Apakah CONFIG_PACKET dimungkinkan pada kernel?"
diff --git a/po/it.po b/po/it.po
new file mode 100755
index 0000000..5bb0c57
--- /dev/null
+++ b/po/it.po
@@ -0,0 +1,2226 @@
+# Italian translations for dnsmasq package.
+# This file is put in the public domain.
+# Simon Kelley <simon@thekelleys.org.uk>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: dnsmasq 2.32\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-06-18 12:24+0100\n"
+"PO-Revision-Date: 2017-07-17 18:30+0100\n"
+"Last-Translator: Simon Kelley <simon@thekelleys.org.uk>\n"
+"Language-Team: Italian <tp@lists.linux.it>\n"
+"Language: it\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ASCII\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: cache.c:513
+msgid "Internal error in cache."
+msgstr ""
+
+#: cache.c:923
+#, c-format
+msgid "failed to load names from %s: %s"
+msgstr ""
+
+#: cache.c:949 dhcp.c:867
+#, c-format
+msgid "bad address at %s line %d"
+msgstr ""
+
+#: cache.c:1002 dhcp.c:883
+#, c-format
+msgid "bad name at %s line %d"
+msgstr ""
+
+#: cache.c:1011 dhcp.c:958
+#, c-format
+msgid "read %s - %d addresses"
+msgstr ""
+
+#: cache.c:1124
+msgid "cleared cache"
+msgstr ""
+
+#: cache.c:1153
+#, c-format
+msgid "No IPv4 address found for %s"
+msgstr ""
+
+#: cache.c:1232
+#, c-format
+msgid "%s is a CNAME, not giving it to the DHCP lease of %s"
+msgstr ""
+
+#: cache.c:1256
+#, c-format
+msgid "not giving name %s to the DHCP lease of %s because the name exists in %s with address %s"
+msgstr ""
+
+#: cache.c:1413
+#, c-format
+msgid "time %lu"
+msgstr ""
+
+#: cache.c:1414
+#, c-format
+msgid "cache size %d, %d/%d cache insertions re-used unexpired cache entries."
+msgstr ""
+
+#: cache.c:1416
+#, c-format
+msgid "queries forwarded %u, queries answered locally %u"
+msgstr ""
+
+#: cache.c:1419
+#, c-format
+msgid "queries for authoritative zones %u"
+msgstr ""
+
+#: cache.c:1445
+#, c-format
+msgid "server %s#%d: queries sent %u, retried or failed %u"
+msgstr ""
+
+#: util.c:47
+#, c-format
+msgid "failed to seed the random number generator: %s"
+msgstr ""
+
+#: util.c:224
+msgid "failed to allocate memory"
+msgstr ""
+
+#: util.c:277 option.c:619
+msgid "could not get memory"
+msgstr ""
+
+#: util.c:287
+#, c-format
+msgid "cannot create pipe: %s"
+msgstr ""
+
+#: util.c:295
+#, c-format
+msgid "failed to allocate %d bytes"
+msgstr ""
+
+#: util.c:464
+#, c-format
+msgid "infinite"
+msgstr ""
+
+#: option.c:344
+msgid "Specify local address(es) to listen on."
+msgstr ""
+
+#: option.c:345
+msgid "Return ipaddr for all hosts in specified domains."
+msgstr ""
+
+#: option.c:346
+msgid "Fake reverse lookups for RFC1918 private address ranges."
+msgstr ""
+
+#: option.c:347
+msgid "Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."
+msgstr ""
+
+#: option.c:348
+#, c-format
+msgid "Specify the size of the cache in entries (defaults to %s)."
+msgstr ""
+
+#: option.c:349
+#, c-format
+msgid "Specify configuration file (defaults to %s)."
+msgstr ""
+
+#: option.c:350
+msgid "Do NOT fork into the background: run in debug mode."
+msgstr ""
+
+#: option.c:351
+msgid "Do NOT forward queries with no domain part."
+msgstr ""
+
+#: option.c:352
+msgid "Return self-pointing MX records for local hosts."
+msgstr ""
+
+#: option.c:353
+msgid "Expand simple names in /etc/hosts with domain-suffix."
+msgstr ""
+
+#: option.c:354
+msgid "Don't forward spurious DNS requests from Windows hosts."
+msgstr ""
+
+#: option.c:355
+msgid "Enable DHCP in the range given with lease duration."
+msgstr ""
+
+#: option.c:356
+#, c-format
+msgid "Change to this group after startup (defaults to %s)."
+msgstr ""
+
+#: option.c:357
+msgid "Set address or hostname for a specified machine."
+msgstr ""
+
+#: option.c:358
+msgid "Read DHCP host specs from file."
+msgstr ""
+
+#: option.c:359
+msgid "Read DHCP option specs from file."
+msgstr ""
+
+#: option.c:360
+msgid "Read DHCP host specs from a directory."
+msgstr ""
+
+#: option.c:361
+msgid "Read DHCP options from a directory."
+msgstr ""
+
+#: option.c:362
+msgid "Evaluate conditional tag expression."
+msgstr ""
+
+#: option.c:363
+#, c-format
+msgid "Do NOT load %s file."
+msgstr ""
+
+#: option.c:364
+#, c-format
+msgid "Specify a hosts file to be read in addition to %s."
+msgstr ""
+
+#: option.c:365
+msgid "Read hosts files from a directory."
+msgstr ""
+
+#: option.c:366
+msgid "Specify interface(s) to listen on."
+msgstr ""
+
+#: option.c:367
+msgid "Specify interface(s) NOT to listen on."
+msgstr ""
+
+#: option.c:368
+msgid "Map DHCP user class to tag."
+msgstr ""
+
+#: option.c:369
+msgid "Map RFC3046 circuit-id to tag."
+msgstr ""
+
+#: option.c:370
+msgid "Map RFC3046 remote-id to tag."
+msgstr ""
+
+#: option.c:371
+msgid "Map RFC3993 subscriber-id to tag."
+msgstr ""
+
+#: option.c:372
+msgid "Don't do DHCP for hosts with tag set."
+msgstr ""
+
+#: option.c:373
+msgid "Force broadcast replies for hosts with tag set."
+msgstr ""
+
+#: option.c:374
+msgid "Do NOT fork into the background, do NOT run in debug mode."
+msgstr ""
+
+#: option.c:375
+msgid "Assume we are the only DHCP server on the local network."
+msgstr ""
+
+#: option.c:376
+#, c-format
+msgid "Specify where to store DHCP leases (defaults to %s)."
+msgstr ""
+
+#: option.c:377
+msgid "Return MX records for local hosts."
+msgstr ""
+
+#: option.c:378
+msgid "Specify an MX record."
+msgstr ""
+
+#: option.c:379
+msgid "Specify BOOTP options to DHCP server."
+msgstr ""
+
+#: option.c:380
+#, c-format
+msgid "Do NOT poll %s file, reload only on SIGHUP."
+msgstr ""
+
+#: option.c:381
+msgid "Do NOT cache failed search results."
+msgstr ""
+
+#: option.c:382
+#, c-format
+msgid "Use nameservers strictly in the order given in %s."
+msgstr ""
+
+#: option.c:383
+msgid "Specify options to be sent to DHCP clients."
+msgstr ""
+
+#: option.c:384
+msgid "DHCP option sent even if the client does not request it."
+msgstr ""
+
+#: option.c:385
+msgid "Specify port to listen for DNS requests on (defaults to 53)."
+msgstr ""
+
+#: option.c:386
+#, c-format
+msgid "Maximum supported UDP packet size for EDNS.0 (defaults to %s)."
+msgstr ""
+
+#: option.c:387
+msgid "Log DNS queries."
+msgstr ""
+
+#: option.c:388
+msgid "Force the originating port for upstream DNS queries."
+msgstr ""
+
+#: option.c:389
+msgid "Do NOT read resolv.conf."
+msgstr ""
+
+#: option.c:390
+#, c-format
+msgid "Specify path to resolv.conf (defaults to %s)."
+msgstr ""
+
+#: option.c:391
+msgid "Specify path to file with server= options"
+msgstr ""
+
+#: option.c:392
+msgid "Specify address(es) of upstream servers with optional domains."
+msgstr ""
+
+#: option.c:393
+msgid "Specify address of upstream servers for reverse address queries"
+msgstr ""
+
+#: option.c:394
+msgid "Never forward queries to specified domains."
+msgstr ""
+
+#: option.c:395
+msgid "Specify the domain to be assigned in DHCP leases."
+msgstr ""
+
+#: option.c:396
+msgid "Specify default target in an MX record."
+msgstr ""
+
+#: option.c:397
+msgid "Specify time-to-live in seconds for replies from /etc/hosts."
+msgstr ""
+
+#: option.c:398
+msgid "Specify time-to-live in seconds for negative caching."
+msgstr ""
+
+#: option.c:399
+msgid "Specify time-to-live in seconds for maximum TTL to send to clients."
+msgstr ""
+
+#: option.c:400
+msgid "Specify time-to-live ceiling for cache."
+msgstr ""
+
+#: option.c:401
+msgid "Specify time-to-live floor for cache."
+msgstr ""
+
+#: option.c:402
+#, c-format
+msgid "Change to this user after startup. (defaults to %s)."
+msgstr ""
+
+#: option.c:403
+msgid "Map DHCP vendor class to tag."
+msgstr ""
+
+#: option.c:404
+msgid "Display dnsmasq version and copyright information."
+msgstr ""
+
+#: option.c:405
+msgid "Translate IPv4 addresses from upstream servers."
+msgstr ""
+
+#: option.c:406
+msgid "Specify a SRV record."
+msgstr ""
+
+#: option.c:407
+msgid "Display this message. Use --help dhcp or --help dhcp6 for known DHCP options."
+msgstr ""
+
+#: option.c:408
+#, c-format
+msgid "Specify path of PID file (defaults to %s)."
+msgstr ""
+
+#: option.c:409
+#, c-format
+msgid "Specify maximum number of DHCP leases (defaults to %s)."
+msgstr ""
+
+#: option.c:410
+msgid "Answer DNS queries based on the interface a query was sent to."
+msgstr ""
+
+#: option.c:411
+msgid "Specify TXT DNS record."
+msgstr ""
+
+#: option.c:412
+msgid "Specify PTR DNS record."
+msgstr ""
+
+#: option.c:413
+msgid "Give DNS name to IPv4 address of interface."
+msgstr ""
+
+#: option.c:414
+msgid "Bind only to interfaces in use."
+msgstr ""
+
+#: option.c:415
+#, c-format
+msgid "Read DHCP static host information from %s."
+msgstr ""
+
+#: option.c:416
+msgid "Enable the DBus interface for setting upstream servers, etc."
+msgstr ""
+
+#: option.c:417
+msgid "Do not provide DHCP on this interface, only provide DNS."
+msgstr ""
+
+#: option.c:418
+msgid "Enable dynamic address allocation for bootp."
+msgstr ""
+
+#: option.c:419
+msgid "Map MAC address (with wildcards) to option set."
+msgstr ""
+
+#: option.c:420
+msgid "Treat DHCP requests on aliases as arriving from interface."
+msgstr ""
+
+#: option.c:421
+msgid "Disable ICMP echo address checking in the DHCP server."
+msgstr ""
+
+#: option.c:422
+msgid "Shell script to run on DHCP lease creation and destruction."
+msgstr ""
+
+#: option.c:423
+msgid "Lua script to run on DHCP lease creation and destruction."
+msgstr ""
+
+#: option.c:424
+msgid "Run lease-change scripts as this user."
+msgstr ""
+
+#: option.c:425
+msgid "Call dhcp-script with changes to local ARP table."
+msgstr ""
+
+#: option.c:426
+msgid "Read configuration from all the files in this directory."
+msgstr ""
+
+#: option.c:427
+msgid "Log to this syslog facility or file. (defaults to DAEMON)"
+msgstr ""
+
+#: option.c:428
+msgid "Do not use leasefile."
+msgstr ""
+
+#: option.c:429
+#, c-format
+msgid "Maximum number of concurrent DNS queries. (defaults to %s)"
+msgstr ""
+
+#: option.c:430
+#, c-format
+msgid "Clear DNS cache when reloading %s."
+msgstr ""
+
+#: option.c:431
+msgid "Ignore hostnames provided by DHCP clients."
+msgstr ""
+
+#: option.c:432
+msgid "Do NOT reuse filename and server fields for extra DHCP options."
+msgstr ""
+
+#: option.c:433
+msgid "Enable integrated read-only TFTP server."
+msgstr ""
+
+#: option.c:434
+msgid "Export files by TFTP only from the specified subtree."
+msgstr ""
+
+#: option.c:435
+msgid "Add client IP or hardware address to tftp-root."
+msgstr ""
+
+#: option.c:436
+msgid "Allow access only to files owned by the user running dnsmasq."
+msgstr ""
+
+#: option.c:437
+msgid "Do not terminate the service if TFTP directories are inaccessible."
+msgstr ""
+
+#: option.c:438
+#, c-format
+msgid "Maximum number of concurrent TFTP transfers (defaults to %s)."
+msgstr ""
+
+#: option.c:439
+msgid "Maximum MTU to use for TFTP transfers."
+msgstr ""
+
+#: option.c:440
+msgid "Disable the TFTP blocksize extension."
+msgstr ""
+
+#: option.c:441
+msgid "Convert TFTP filenames to lowercase"
+msgstr ""
+
+#: option.c:442
+msgid "Ephemeral port range for use by TFTP transfers."
+msgstr ""
+
+#: option.c:443
+msgid "Extra logging for DHCP."
+msgstr ""
+
+#: option.c:444
+msgid "Enable async. logging; optionally set queue length."
+msgstr ""
+
+#: option.c:445
+msgid "Stop DNS rebinding. Filter private IP ranges when resolving."
+msgstr ""
+
+#: option.c:446
+msgid "Allow rebinding of 127.0.0.0/8, for RBL servers."
+msgstr ""
+
+#: option.c:447
+msgid "Inhibit DNS-rebind protection on this domain."
+msgstr ""
+
+#: option.c:448
+msgid "Always perform DNS queries to all servers."
+msgstr ""
+
+#: option.c:449
+msgid "Set tag if client includes matching option in request."
+msgstr ""
+
+#: option.c:450
+msgid "Use alternative ports for DHCP."
+msgstr ""
+
+#: option.c:451
+msgid "Specify NAPTR DNS record."
+msgstr ""
+
+#: option.c:452
+msgid "Specify lowest port available for DNS query transmission."
+msgstr ""
+
+#: option.c:453
+msgid "Specify highest port available for DNS query transmission."
+msgstr ""
+
+#: option.c:454
+msgid "Use only fully qualified domain names for DHCP clients."
+msgstr ""
+
+#: option.c:455
+msgid "Generate hostnames based on MAC address for nameless clients."
+msgstr ""
+
+#: option.c:456
+msgid "Use these DHCP relays as full proxies."
+msgstr ""
+
+#: option.c:457
+msgid "Relay DHCP requests to a remote server"
+msgstr ""
+
+#: option.c:458
+msgid "Specify alias name for LOCAL DNS name."
+msgstr ""
+
+#: option.c:459
+msgid "Prompt to send to PXE clients."
+msgstr ""
+
+#: option.c:460
+msgid "Boot service for PXE menu."
+msgstr ""
+
+#: option.c:461
+msgid "Check configuration syntax."
+msgstr ""
+
+#: option.c:462
+msgid "Add requestor's MAC address to forwarded DNS queries."
+msgstr ""
+
+#: option.c:463
+msgid "Add specified IP subnet to forwarded DNS queries."
+msgstr ""
+
+#: option.c:464
+msgid "Add client identification to forwarded DNS queries."
+msgstr ""
+
+#: option.c:465
+msgid "Proxy DNSSEC validation results from upstream nameservers."
+msgstr ""
+
+#: option.c:466
+msgid "Attempt to allocate sequential IP addresses to DHCP clients."
+msgstr ""
+
+#: option.c:467
+msgid "Copy connection-track mark from queries to upstream connections."
+msgstr ""
+
+#: option.c:468
+msgid "Allow DHCP clients to do their own DDNS updates."
+msgstr ""
+
+#: option.c:469
+msgid "Send router-advertisements for interfaces doing DHCPv6"
+msgstr ""
+
+#: option.c:470
+msgid "Specify DUID_EN-type DHCPv6 server DUID"
+msgstr ""
+
+#: option.c:471
+msgid "Specify host (A/AAAA and PTR) records"
+msgstr ""
+
+#: option.c:472
+msgid "Specify arbitrary DNS resource record"
+msgstr ""
+
+#: option.c:473
+msgid "Bind to interfaces in use - check for new interfaces"
+msgstr ""
+
+#: option.c:474
+msgid "Export local names to global DNS"
+msgstr ""
+
+#: option.c:475
+msgid "Domain to export to global DNS"
+msgstr ""
+
+#: option.c:476
+msgid "Set TTL for authoritative replies"
+msgstr ""
+
+#: option.c:477
+msgid "Set authoritative zone information"
+msgstr ""
+
+#: option.c:478
+msgid "Secondary authoritative nameservers for forward domains"
+msgstr ""
+
+#: option.c:479
+msgid "Peers which are allowed to do zone transfer"
+msgstr ""
+
+#: option.c:480
+msgid "Specify ipsets to which matching domains should be added"
+msgstr ""
+
+#: option.c:481
+msgid "Specify a domain and address range for synthesised names"
+msgstr ""
+
+#: option.c:482
+msgid "Activate DNSSEC validation"
+msgstr ""
+
+#: option.c:483
+msgid "Specify trust anchor key digest."
+msgstr ""
+
+#: option.c:484
+msgid "Disable upstream checking for DNSSEC debugging."
+msgstr ""
+
+#: option.c:485
+msgid "Ensure answers without DNSSEC are in unsigned zones."
+msgstr ""
+
+#: option.c:486
+msgid "Don't check DNSSEC signature timestamps until first cache-reload"
+msgstr ""
+
+#: option.c:487
+msgid "Timestamp file to verify system clock for DNSSEC"
+msgstr ""
+
+#: option.c:489
+msgid "Specify DHCPv6 prefix class"
+msgstr ""
+
+#: option.c:491
+msgid "Set MTU, priority, resend-interval and router-lifetime"
+msgstr ""
+
+#: option.c:492
+msgid "Do not log routine DHCP."
+msgstr ""
+
+#: option.c:493
+msgid "Do not log routine DHCPv6."
+msgstr ""
+
+#: option.c:494
+msgid "Do not log RA."
+msgstr ""
+
+#: option.c:495
+msgid "Accept queries only from directly-connected networks."
+msgstr ""
+
+#: option.c:496
+msgid "Detect and remove DNS forwarding loops."
+msgstr ""
+
+#: option.c:497
+msgid "Ignore DNS responses containing ipaddr."
+msgstr ""
+
+#: option.c:498
+msgid "Set TTL in DNS responses with DHCP-derived addresses."
+msgstr ""
+
+#: option.c:499
+msgid "Delay DHCP replies for at least number of seconds."
+msgstr ""
+
+#: option.c:703
+#, c-format
+msgid ""
+"Usage: dnsmasq [options]\n"
+"\n"
+msgstr ""
+
+#: option.c:705
+#, c-format
+msgid "Use short options only on the command line.\n"
+msgstr ""
+
+#: option.c:707
+#, c-format
+msgid "Valid options are:\n"
+msgstr ""
+
+#: option.c:754 option.c:868
+msgid "bad address"
+msgstr ""
+
+#: option.c:779 option.c:783
+msgid "bad port"
+msgstr ""
+
+#: option.c:797 option.c:826 option.c:861
+msgid "interface binding not supported"
+msgstr ""
+
+#: option.c:821 option.c:856
+msgid "interface can only be specified once"
+msgstr ""
+
+#: option.c:835 option.c:3800
+msgid "bad interface name"
+msgstr ""
+
+#: option.c:1062
+msgid "unsupported encapsulation for IPv6 option"
+msgstr ""
+
+#: option.c:1076
+msgid "bad dhcp-option"
+msgstr ""
+
+#: option.c:1144
+msgid "bad IP address"
+msgstr ""
+
+#: option.c:1147 option.c:1286 option.c:3070
+msgid "bad IPv6 address"
+msgstr ""
+
+#: option.c:1240
+msgid "bad IPv4 address"
+msgstr ""
+
+#: option.c:1313 option.c:1407
+msgid "bad domain in dhcp-option"
+msgstr ""
+
+#: option.c:1445
+msgid "dhcp-option too long"
+msgstr ""
+
+#: option.c:1452
+msgid "illegal dhcp-match"
+msgstr ""
+
+#: option.c:1514
+msgid "illegal repeated flag"
+msgstr ""
+
+#: option.c:1522
+msgid "illegal repeated keyword"
+msgstr ""
+
+#: option.c:1593 option.c:4434
+#, c-format
+msgid "cannot access directory %s: %s"
+msgstr ""
+
+#: option.c:1639 tftp.c:537
+#, c-format
+msgid "cannot access %s: %s"
+msgstr ""
+
+#: option.c:1727
+msgid "setting log facility is not possible under Android"
+msgstr ""
+
+#: option.c:1736
+msgid "bad log facility"
+msgstr ""
+
+#: option.c:1789
+msgid "bad MX preference"
+msgstr ""
+
+#: option.c:1794
+msgid "bad MX name"
+msgstr ""
+
+#: option.c:1808
+msgid "bad MX target"
+msgstr ""
+
+#: option.c:1820
+msgid "cannot run scripts under uClinux"
+msgstr ""
+
+#: option.c:1822
+msgid "recompile with HAVE_SCRIPT defined to enable lease-change scripts"
+msgstr ""
+
+#: option.c:1826
+msgid "recompile with HAVE_LUASCRIPT defined to enable Lua scripts"
+msgstr ""
+
+#: option.c:2095 option.c:2106 option.c:2143 option.c:2199 option.c:2482
+msgid "bad prefix"
+msgstr ""
+
+#: option.c:2504
+msgid "recompile with HAVE_IPSET defined to enable ipset directives"
+msgstr ""
+
+#: option.c:2713
+msgid "bad port range"
+msgstr ""
+
+#: option.c:2738
+msgid "bad bridge-interface"
+msgstr ""
+
+#: option.c:2798
+msgid "only one tag allowed"
+msgstr ""
+
+#: option.c:2818 option.c:2830 option.c:2939 option.c:2944 option.c:2983
+msgid "bad dhcp-range"
+msgstr ""
+
+#: option.c:2845
+msgid "inconsistent DHCP range"
+msgstr ""
+
+#: option.c:2907
+msgid "prefix length must be exactly 64 for RA subnets"
+msgstr ""
+
+#: option.c:2909
+msgid "prefix length must be exactly 64 for subnet constructors"
+msgstr ""
+
+#: option.c:2913
+msgid "prefix length must be at least 64"
+msgstr ""
+
+#: option.c:2916
+msgid "inconsistent DHCPv6 range"
+msgstr ""
+
+#: option.c:2927
+msgid "prefix must be zero with \"constructor:\" argument"
+msgstr ""
+
+#: option.c:3040 option.c:3088
+msgid "bad hex constant"
+msgstr ""
+
+#: option.c:3062
+msgid "cannot match tags in --dhcp-host"
+msgstr ""
+
+#: option.c:3110
+#, c-format
+msgid "duplicate dhcp-host IP address %s"
+msgstr ""
+
+#: option.c:3168
+msgid "bad DHCP host name"
+msgstr ""
+
+#: option.c:3250
+msgid "bad tag-if"
+msgstr ""
+
+#: option.c:3607 option.c:4030
+msgid "invalid port number"
+msgstr ""
+
+#: option.c:3669
+msgid "bad dhcp-proxy address"
+msgstr ""
+
+#: option.c:3695
+msgid "Bad dhcp-relay"
+msgstr ""
+
+#: option.c:3736
+msgid "bad RA-params"
+msgstr ""
+
+#: option.c:3745
+msgid "bad DUID"
+msgstr ""
+
+#: option.c:3787
+msgid "invalid alias range"
+msgstr ""
+
+#: option.c:3841 option.c:3853
+msgid "bad CNAME"
+msgstr ""
+
+#: option.c:3857
+msgid "duplicate CNAME"
+msgstr ""
+
+#: option.c:3880
+msgid "bad PTR record"
+msgstr ""
+
+#: option.c:3911
+msgid "bad NAPTR record"
+msgstr ""
+
+#: option.c:3945
+msgid "bad RR record"
+msgstr ""
+
+#: option.c:3975
+msgid "bad TXT record"
+msgstr ""
+
+#: option.c:4016
+msgid "bad SRV record"
+msgstr ""
+
+#: option.c:4023
+msgid "bad SRV target"
+msgstr ""
+
+#: option.c:4037
+msgid "invalid priority"
+msgstr ""
+
+#: option.c:4040
+msgid "invalid weight"
+msgstr ""
+
+#: option.c:4064
+msgid "Bad host-record"
+msgstr ""
+
+#: option.c:4088
+msgid "Bad name in host-record"
+msgstr ""
+
+#: option.c:4153
+msgid "bad trust anchor"
+msgstr ""
+
+#: option.c:4167
+msgid "bad HEX in trust anchor"
+msgstr ""
+
+#: option.c:4177
+msgid "unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"
+msgstr ""
+
+#: option.c:4237
+msgid "missing \""
+msgstr ""
+
+#: option.c:4294
+msgid "bad option"
+msgstr ""
+
+#: option.c:4296
+msgid "extraneous parameter"
+msgstr ""
+
+#: option.c:4298
+msgid "missing parameter"
+msgstr ""
+
+#: option.c:4300
+msgid "illegal option"
+msgstr ""
+
+#: option.c:4307
+msgid "error"
+msgstr ""
+
+#: option.c:4309
+#, c-format
+msgid " at line %d of %s"
+msgstr ""
+
+#: option.c:4324 option.c:4571 option.c:4607
+#, c-format
+msgid "read %s"
+msgstr ""
+
+#: option.c:4387 option.c:4510 tftp.c:715
+#, c-format
+msgid "cannot read %s: %s"
+msgstr ""
+
+#: option.c:4676
+msgid "junk found in command line"
+msgstr ""
+
+#: option.c:4711
+#, c-format
+msgid "Dnsmasq version %s  %s\n"
+msgstr ""
+
+#: option.c:4712
+#, c-format
+msgid ""
+"Compile time options: %s\n"
+"\n"
+msgstr ""
+
+#: option.c:4713
+#, c-format
+msgid "This software comes with ABSOLUTELY NO WARRANTY.\n"
+msgstr ""
+
+#: option.c:4714
+#, c-format
+msgid "Dnsmasq is free software, and you are welcome to redistribute it\n"
+msgstr ""
+
+#: option.c:4715
+#, c-format
+msgid "under the terms of the GNU General Public License, version 2 or 3.\n"
+msgstr ""
+
+#: option.c:4726
+msgid "try --help"
+msgstr ""
+
+#: option.c:4728
+msgid "try -w"
+msgstr ""
+
+#: option.c:4730
+#, c-format
+msgid "bad command line options: %s"
+msgstr ""
+
+#: option.c:4798
+#, c-format
+msgid "CNAME loop involving %s"
+msgstr ""
+
+#: option.c:4834
+#, c-format
+msgid "cannot get host-name: %s"
+msgstr ""
+
+#: option.c:4862
+msgid "only one resolv.conf file allowed in no-poll mode."
+msgstr ""
+
+#: option.c:4872
+msgid "must have exactly one resolv.conf to read domain from."
+msgstr ""
+
+#: option.c:4875 network.c:1612 dhcp.c:816
+#, c-format
+msgid "failed to read %s: %s"
+msgstr ""
+
+#: option.c:4892
+#, c-format
+msgid "no search directive found in %s"
+msgstr ""
+
+#: option.c:4913
+msgid "there must be a default domain when --dhcp-fqdn is set"
+msgstr ""
+
+#: option.c:4922
+msgid "syntax check OK"
+msgstr ""
+
+#: forward.c:102
+#, c-format
+msgid "failed to send packet: %s"
+msgstr ""
+
+#: forward.c:597
+msgid "discarding DNS reply: subnet option mismatch"
+msgstr ""
+
+#: forward.c:651
+#, c-format
+msgid "nameserver %s refused to do a recursive query"
+msgstr ""
+
+#: forward.c:683
+#, c-format
+msgid "possible DNS-rebind attack detected: %s"
+msgstr ""
+
+#: forward.c:1244 forward.c:1681
+msgid "Ignoring query from non-local network"
+msgstr ""
+
+#: forward.c:2166
+#, c-format
+msgid "Maximum number of concurrent DNS queries reached (max: %d)"
+msgstr ""
+
+#: network.c:720
+#, c-format
+msgid "failed to create listening socket for %s: %s"
+msgstr ""
+
+#: network.c:1031
+#, c-format
+msgid "LOUD WARNING: listening on %s may accept requests via interfaces other than %s"
+msgstr ""
+
+#: network.c:1038
+msgid "LOUD WARNING: use --bind-dynamic rather than --bind-interfaces to avoid DNS amplification attacks via these interface(s)"
+msgstr ""
+
+#: network.c:1047
+#, c-format
+msgid "warning: using interface %s instead"
+msgstr ""
+
+#: network.c:1056
+#, c-format
+msgid "warning: no addresses found for interface %s"
+msgstr ""
+
+#: network.c:1114
+#, c-format
+msgid "interface %s failed to join DHCPv6 multicast group: %s"
+msgstr ""
+
+#: network.c:1119
+msgid "try increasing /proc/sys/net/core/optmem_max"
+msgstr ""
+
+#: network.c:1322
+#, c-format
+msgid "failed to bind server socket for %s: %s"
+msgstr ""
+
+#: network.c:1517
+#, c-format
+msgid "ignoring nameserver %s - local interface"
+msgstr ""
+
+#: network.c:1528
+#, c-format
+msgid "ignoring nameserver %s - cannot make/bind socket: %s"
+msgstr ""
+
+#: network.c:1548
+msgid "(no DNSSEC)"
+msgstr ""
+
+#: network.c:1551
+msgid "unqualified"
+msgstr ""
+
+#: network.c:1551
+msgid "names"
+msgstr ""
+
+#: network.c:1553
+msgid "default"
+msgstr ""
+
+#: network.c:1555
+msgid "domain"
+msgstr ""
+
+#: network.c:1561
+#, c-format
+msgid "using local addresses only for %s %s"
+msgstr ""
+
+#: network.c:1564
+#, c-format
+msgid "using standard nameservers for %s %s"
+msgstr ""
+
+#: network.c:1566
+#, c-format
+msgid "using nameserver %s#%d for %s %s %s"
+msgstr ""
+
+#: network.c:1570
+#, c-format
+msgid "NOT using nameserver %s#%d - query loop detected"
+msgstr ""
+
+#: network.c:1573
+#, c-format
+msgid "using nameserver %s#%d(via %s)"
+msgstr ""
+
+#: network.c:1575
+#, c-format
+msgid "using nameserver %s#%d"
+msgstr ""
+
+#: network.c:1580
+#, c-format
+msgid "using %d more local addresses"
+msgstr ""
+
+#: network.c:1582
+#, c-format
+msgid "using %d more nameservers"
+msgstr ""
+
+#: dnsmasq.c:166
+msgid "dhcp-hostsdir, dhcp-optsdir and hostsdir are not supported on this platform"
+msgstr ""
+
+#: dnsmasq.c:181
+msgid "no root trust anchor provided for DNSSEC"
+msgstr ""
+
+#: dnsmasq.c:184
+msgid "cannot reduce cache size from default when DNSSEC enabled"
+msgstr ""
+
+#: dnsmasq.c:186
+msgid "DNSSEC not available: set HAVE_DNSSEC in src/config.h"
+msgstr ""
+
+#: dnsmasq.c:192
+msgid "TFTP server not available: set HAVE_TFTP in src/config.h"
+msgstr ""
+
+#: dnsmasq.c:197
+msgid "cannot use --conntrack AND --query-port"
+msgstr ""
+
+#: dnsmasq.c:200
+msgid "conntrack support not available: set HAVE_CONNTRACK in src/config.h"
+msgstr ""
+
+#: dnsmasq.c:205
+msgid "asynchronous logging is not available under Solaris"
+msgstr ""
+
+#: dnsmasq.c:210
+msgid "asynchronous logging is not available under Android"
+msgstr ""
+
+#: dnsmasq.c:215
+msgid "authoritative DNS not available: set HAVE_AUTH in src/config.h"
+msgstr ""
+
+#: dnsmasq.c:220
+msgid "loop detection not available: set HAVE_LOOP in src/config.h"
+msgstr ""
+
+#: dnsmasq.c:227
+msgid "max_port cannot be smaller than min_port"
+msgstr ""
+
+#: dnsmasq.c:234
+msgid "zone serial must be configured in --auth-soa"
+msgstr ""
+
+#: dnsmasq.c:252
+msgid "dhcp-range constructor not available on this platform"
+msgstr ""
+
+#: dnsmasq.c:298
+msgid "cannot set --bind-interfaces and --bind-dynamic"
+msgstr ""
+
+#: dnsmasq.c:301
+#, c-format
+msgid "failed to find list of interfaces: %s"
+msgstr ""
+
+#: dnsmasq.c:310
+#, c-format
+msgid "unknown interface %s"
+msgstr ""
+
+#: dnsmasq.c:374 dnsmasq.c:1037
+#, c-format
+msgid "DBus error: %s"
+msgstr ""
+
+#: dnsmasq.c:377
+msgid "DBus not available: set HAVE_DBUS in src/config.h"
+msgstr ""
+
+#: dnsmasq.c:405
+#, c-format
+msgid "unknown user or group: %s"
+msgstr ""
+
+#: dnsmasq.c:460
+#, c-format
+msgid "cannot chdir to filesystem root: %s"
+msgstr ""
+
+#: dnsmasq.c:716
+#, c-format
+msgid "started, version %s DNS disabled"
+msgstr ""
+
+#: dnsmasq.c:720
+#, c-format
+msgid "started, version %s cachesize %d"
+msgstr ""
+
+#: dnsmasq.c:722
+#, c-format
+msgid "started, version %s cache disabled"
+msgstr ""
+
+#: dnsmasq.c:725
+msgid "DNS service limited to local subnets"
+msgstr ""
+
+#: dnsmasq.c:728
+#, c-format
+msgid "compile time options: %s"
+msgstr ""
+
+#: dnsmasq.c:734
+msgid "DBus support enabled: connected to system bus"
+msgstr ""
+
+#: dnsmasq.c:736
+msgid "DBus support enabled: bus connection pending"
+msgstr ""
+
+#: dnsmasq.c:754
+msgid "DNSSEC validation enabled"
+msgstr ""
+
+#: dnsmasq.c:758
+msgid "DNSSEC signature timestamps not checked until first cache reload"
+msgstr ""
+
+#: dnsmasq.c:761
+msgid "DNSSEC signature timestamps not checked until system time valid"
+msgstr ""
+
+#: dnsmasq.c:766
+#, c-format
+msgid "warning: failed to change owner of %s: %s"
+msgstr ""
+
+#: dnsmasq.c:770
+msgid "setting --bind-interfaces option because of OS limitations"
+msgstr ""
+
+#: dnsmasq.c:782
+#, c-format
+msgid "warning: interface %s does not currently exist"
+msgstr ""
+
+#: dnsmasq.c:787
+msgid "warning: ignoring resolv-file flag because no-resolv is set"
+msgstr ""
+
+#: dnsmasq.c:790
+msgid "warning: no upstream servers configured"
+msgstr ""
+
+#: dnsmasq.c:794
+#, c-format
+msgid "asynchronous logging enabled, queue limit is %d messages"
+msgstr ""
+
+#: dnsmasq.c:815
+msgid "IPv6 router advertisement enabled"
+msgstr ""
+
+#: dnsmasq.c:820
+#, c-format
+msgid "DHCP, sockets bound exclusively to interface %s"
+msgstr ""
+
+#: dnsmasq.c:834
+msgid "root is "
+msgstr ""
+
+#: dnsmasq.c:834
+msgid "enabled"
+msgstr ""
+
+#: dnsmasq.c:836
+msgid "secure mode"
+msgstr ""
+
+#: dnsmasq.c:839
+#, c-format
+msgid "warning: %s inaccessible"
+msgstr ""
+
+#: dnsmasq.c:843
+#, c-format
+msgid "warning: TFTP directory %s inaccessible"
+msgstr ""
+
+#: dnsmasq.c:869
+#, c-format
+msgid "restricting maximum simultaneous TFTP transfers to %d"
+msgstr ""
+
+#: dnsmasq.c:1039
+msgid "connected to system DBus"
+msgstr ""
+
+#: dnsmasq.c:1189
+#, c-format
+msgid "cannot fork into background: %s"
+msgstr ""
+
+#: dnsmasq.c:1192
+#, c-format
+msgid "failed to create helper: %s"
+msgstr ""
+
+#: dnsmasq.c:1195
+#, c-format
+msgid "setting capabilities failed: %s"
+msgstr ""
+
+#: dnsmasq.c:1198
+#, c-format
+msgid "failed to change user-id to %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1201
+#, c-format
+msgid "failed to change group-id to %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1204
+#, c-format
+msgid "failed to open pidfile %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1207
+#, c-format
+msgid "cannot open log %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1210
+#, c-format
+msgid "failed to load Lua script: %s"
+msgstr ""
+
+#: dnsmasq.c:1213
+#, c-format
+msgid "TFTP directory %s inaccessible: %s"
+msgstr ""
+
+#: dnsmasq.c:1216
+#, c-format
+msgid "cannot create timestamp file %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1239
+msgid "now checking DNSSEC signature timestamps"
+msgstr ""
+
+#: dnsmasq.c:1307
+#, c-format
+msgid "script process killed by signal %d"
+msgstr ""
+
+#: dnsmasq.c:1311
+#, c-format
+msgid "script process exited with status %d"
+msgstr ""
+
+#: dnsmasq.c:1315
+#, c-format
+msgid "failed to execute %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1379 dnssec.c:479 dnssec.c:525
+#, c-format
+msgid "failed to update mtime on %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1386
+msgid "exiting on receipt of SIGTERM"
+msgstr ""
+
+#: dnsmasq.c:1414
+#, c-format
+msgid "failed to access %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1444
+#, c-format
+msgid "reading %s"
+msgstr ""
+
+#: dnsmasq.c:1455
+#, c-format
+msgid "no servers found in %s, will retry"
+msgstr ""
+
+#: dhcp.c:53
+#, c-format
+msgid "cannot create DHCP socket: %s"
+msgstr ""
+
+#: dhcp.c:68
+#, c-format
+msgid "failed to set options on DHCP socket: %s"
+msgstr ""
+
+#: dhcp.c:89
+#, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"
+msgstr ""
+
+#: dhcp.c:101
+#, c-format
+msgid "failed to bind DHCP server socket: %s"
+msgstr ""
+
+#: dhcp.c:127
+#, c-format
+msgid "cannot create ICMP raw socket: %s."
+msgstr ""
+
+#: dhcp.c:252 dhcp6.c:173
+#, c-format
+msgid "unknown interface %s in bridge-interface"
+msgstr ""
+
+#: dhcp.c:293
+#, c-format
+msgid "DHCP packet received on %s which has no address"
+msgstr ""
+
+#: dhcp.c:427
+#, c-format
+msgid "ARP-cache injection failed: %s"
+msgstr ""
+
+#: dhcp.c:470
+#, c-format
+msgid "Error sending DHCP packet to %s: %s"
+msgstr ""
+
+#: dhcp.c:531
+#, c-format
+msgid "DHCP range %s -- %s is not consistent with netmask %s"
+msgstr ""
+
+#: dhcp.c:854
+#, c-format
+msgid "bad line at %s line %d"
+msgstr ""
+
+#: dhcp.c:897
+#, c-format
+msgid "ignoring %s line %d, duplicate name or IP address"
+msgstr ""
+
+#: dhcp.c:1041 rfc3315.c:2149
+#, c-format
+msgid "DHCP relay %s -> %s"
+msgstr ""
+
+#: lease.c:98
+msgid "too many stored leases"
+msgstr ""
+
+#: lease.c:166
+#, c-format
+msgid "cannot open or create lease file %s: %s"
+msgstr ""
+
+#: lease.c:175
+#, c-format
+msgid "failed to parse lease database, invalid line: %s %s %s %s ..."
+msgstr ""
+
+#: lease.c:180
+#, c-format
+msgid "failed to read lease file %s: %s"
+msgstr ""
+
+#: lease.c:196
+#, c-format
+msgid "cannot run lease-init script %s: %s"
+msgstr ""
+
+#: lease.c:202
+#, c-format
+msgid "lease-init script returned exit code %s"
+msgstr ""
+
+#: lease.c:373
+#, c-format
+msgid "failed to write %s: %s (retry in %us)"
+msgstr ""
+
+#: lease.c:937
+#, c-format
+msgid "Ignoring domain %s for DHCP host name %s"
+msgstr ""
+
+#: rfc2131.c:347
+#, c-format
+msgid "no address range available for DHCP request %s %s"
+msgstr ""
+
+#: rfc2131.c:348
+msgid "with subnet selector"
+msgstr ""
+
+#: rfc2131.c:348
+msgid "via"
+msgstr ""
+
+#: rfc2131.c:360
+#, c-format
+msgid "%u available DHCP subnet: %s/%s"
+msgstr ""
+
+#: rfc2131.c:363 rfc3315.c:306
+#, c-format
+msgid "%u available DHCP range: %s -- %s"
+msgstr ""
+
+#: rfc2131.c:474
+#, c-format
+msgid "%u vendor class: %s"
+msgstr ""
+
+#: rfc2131.c:476
+#, c-format
+msgid "%u user class: %s"
+msgstr ""
+
+#: rfc2131.c:510
+msgid "disabled"
+msgstr ""
+
+#: rfc2131.c:551 rfc2131.c:1006 rfc2131.c:1430 rfc3315.c:616 rfc3315.c:869
+#: rfc3315.c:1148
+msgid "ignored"
+msgstr ""
+
+#: rfc2131.c:566 rfc2131.c:1239 rfc3315.c:919
+msgid "address in use"
+msgstr ""
+
+#: rfc2131.c:580 rfc2131.c:1060
+msgid "no address available"
+msgstr ""
+
+#: rfc2131.c:587 rfc2131.c:1202
+msgid "wrong network"
+msgstr ""
+
+#: rfc2131.c:602
+msgid "no address configured"
+msgstr ""
+
+#: rfc2131.c:608 rfc2131.c:1252
+msgid "no leases left"
+msgstr ""
+
+#: rfc2131.c:703 rfc3315.c:482
+#, c-format
+msgid "%u client provides name: %s"
+msgstr ""
+
+#: rfc2131.c:808
+msgid "PXE BIS not supported"
+msgstr ""
+
+#: rfc2131.c:974 rfc3315.c:1242
+#, c-format
+msgid "disabling DHCP static address %s for %s"
+msgstr ""
+
+#: rfc2131.c:995
+msgid "unknown lease"
+msgstr ""
+
+#: rfc2131.c:1029
+#, c-format
+msgid "not using configured address %s because it is leased to %s"
+msgstr ""
+
+#: rfc2131.c:1039
+#, c-format
+msgid "not using configured address %s because it is in use by the server or relay"
+msgstr ""
+
+#: rfc2131.c:1042
+#, c-format
+msgid "not using configured address %s because it was previously declined"
+msgstr ""
+
+#: rfc2131.c:1058 rfc2131.c:1245
+msgid "no unique-id"
+msgstr ""
+
+#: rfc2131.c:1140
+msgid "wrong server-ID"
+msgstr ""
+
+#: rfc2131.c:1159
+msgid "wrong address"
+msgstr ""
+
+#: rfc2131.c:1177 rfc3315.c:1015
+msgid "lease not found"
+msgstr ""
+
+#: rfc2131.c:1210
+msgid "address not available"
+msgstr ""
+
+#: rfc2131.c:1221
+msgid "static lease available"
+msgstr ""
+
+#: rfc2131.c:1225
+msgid "address reserved"
+msgstr ""
+
+#: rfc2131.c:1233
+#, c-format
+msgid "abandoning lease to %s of %s"
+msgstr ""
+
+#: rfc2131.c:1757
+#, c-format
+msgid "%u bootfile name: %s"
+msgstr ""
+
+#: rfc2131.c:1766
+#, c-format
+msgid "%u server name: %s"
+msgstr ""
+
+#: rfc2131.c:1774
+#, c-format
+msgid "%u next server: %s"
+msgstr ""
+
+#: rfc2131.c:1777
+#, c-format
+msgid "%u broadcast response"
+msgstr ""
+
+#: rfc2131.c:1840
+#, c-format
+msgid "cannot send DHCP/BOOTP option %d: no space left in packet"
+msgstr ""
+
+#: rfc2131.c:2131
+msgid "PXE menu too large"
+msgstr ""
+
+#: rfc2131.c:2270 rfc3315.c:1515
+#, c-format
+msgid "%u requested options: %s"
+msgstr ""
+
+#: rfc2131.c:2587
+#, c-format
+msgid "cannot send RFC3925 option: too many options for enterprise number %d"
+msgstr ""
+
+#: rfc2131.c:2650
+#, c-format
+msgid "%u reply delay: %d"
+msgstr ""
+
+#: netlink.c:77
+#, c-format
+msgid "cannot create netlink socket: %s"
+msgstr ""
+
+#: netlink.c:355
+#, c-format
+msgid "netlink returns error: %s"
+msgstr ""
+
+#: dbus.c:186
+msgid "attempt to set an IPv6 server address via DBus - no IPv6 support"
+msgstr ""
+
+#: dbus.c:439
+#, c-format
+msgid "Enabling --%s option from D-Bus"
+msgstr ""
+
+#: dbus.c:444
+#, c-format
+msgid "Disabling --%s option from D-Bus"
+msgstr ""
+
+#: dbus.c:690
+msgid "setting upstream servers from DBus"
+msgstr ""
+
+#: dbus.c:737
+msgid "could not register a DBus message handler"
+msgstr ""
+
+#: bpf.c:265
+#, c-format
+msgid "cannot create DHCP BPF socket: %s"
+msgstr ""
+
+#: bpf.c:293
+#, c-format
+msgid "DHCP request for unsupported hardware type (%d) received on %s"
+msgstr ""
+
+#: bpf.c:378
+#, c-format
+msgid "cannot create PF_ROUTE socket: %s"
+msgstr ""
+
+#: bpf.c:399
+msgid "Unknown protocol version from route socket"
+msgstr ""
+
+#: helper.c:153
+msgid "lease() function missing in Lua script"
+msgstr ""
+
+#: tftp.c:319
+msgid "unable to get free port for TFTP"
+msgstr ""
+
+#: tftp.c:335
+#, c-format
+msgid "unsupported request from %s"
+msgstr ""
+
+#: tftp.c:483
+#, c-format
+msgid "file %s not found"
+msgstr ""
+
+#: tftp.c:592
+#, c-format
+msgid "error %d %s received from %s"
+msgstr ""
+
+#: tftp.c:634
+#, c-format
+msgid "failed sending %s to %s"
+msgstr ""
+
+#: tftp.c:634
+#, c-format
+msgid "sent %s to %s"
+msgstr ""
+
+#: log.c:190
+#, c-format
+msgid "overflow: %d log entries lost"
+msgstr ""
+
+#: log.c:268
+#, c-format
+msgid "log failed: %s"
+msgstr ""
+
+#: log.c:471
+msgid "FAILED to start up"
+msgstr ""
+
+#: conntrack.c:65
+#, c-format
+msgid "Conntrack connection mark retrieval failed: %s"
+msgstr ""
+
+#: dhcp6.c:52
+#, c-format
+msgid "cannot create DHCPv6 socket: %s"
+msgstr ""
+
+#: dhcp6.c:73
+#, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"
+msgstr ""
+
+#: dhcp6.c:85
+#, c-format
+msgid "failed to bind DHCPv6 server socket: %s"
+msgstr ""
+
+#: rfc3315.c:157
+#, c-format
+msgid "no address range available for DHCPv6 request from relay at %s"
+msgstr ""
+
+#: rfc3315.c:166
+#, c-format
+msgid "no address range available for DHCPv6 request via %s"
+msgstr ""
+
+#: rfc3315.c:303
+#, c-format
+msgid "%u available DHCPv6 subnet: %s/%d"
+msgstr ""
+
+#: rfc3315.c:386
+#, c-format
+msgid "%u vendor class: %u"
+msgstr ""
+
+#: rfc3315.c:434
+#, c-format
+msgid "%u client MAC address: %s"
+msgstr ""
+
+#: rfc3315.c:673
+#, c-format
+msgid "unknown prefix-class %d"
+msgstr ""
+
+#: rfc3315.c:816 rfc3315.c:911
+msgid "address unavailable"
+msgstr ""
+
+#: rfc3315.c:828 rfc3315.c:959 rfc3315.c:1292
+msgid "success"
+msgstr ""
+
+#: rfc3315.c:843 rfc3315.c:852 rfc3315.c:967 rfc3315.c:969
+msgid "no addresses available"
+msgstr ""
+
+#: rfc3315.c:946
+msgid "not on link"
+msgstr ""
+
+#: rfc3315.c:1019 rfc3315.c:1204 rfc3315.c:1281
+msgid "no binding found"
+msgstr ""
+
+#: rfc3315.c:1057
+msgid "deprecated"
+msgstr ""
+
+#: rfc3315.c:1062
+msgid "address invalid"
+msgstr ""
+
+#: rfc3315.c:1109
+msgid "confirm failed"
+msgstr ""
+
+#: rfc3315.c:1125
+msgid "all addresses still on link"
+msgstr ""
+
+#: rfc3315.c:1213
+msgid "release received"
+msgstr ""
+
+#: rfc3315.c:2140
+msgid "Cannot multicast to DHCPv6 server without correct interface"
+msgstr ""
+
+#: dhcp-common.c:145
+#, c-format
+msgid "Ignoring duplicate dhcp-option %d"
+msgstr ""
+
+#: dhcp-common.c:222
+#, c-format
+msgid "%u tags: %s"
+msgstr ""
+
+#: dhcp-common.c:407
+#, c-format
+msgid "%s has more than one address in hostsfile, using %s for DHCP"
+msgstr ""
+
+#: dhcp-common.c:430
+#, c-format
+msgid "duplicate IP address %s (%s) in dhcp-config directive"
+msgstr ""
+
+#: dhcp-common.c:494
+#, c-format
+msgid "failed to set SO_BINDTODEVICE on DHCP socket: %s"
+msgstr ""
+
+#: dhcp-common.c:615
+#, c-format
+msgid "Known DHCP options:\n"
+msgstr ""
+
+#: dhcp-common.c:626
+#, c-format
+msgid "Known DHCPv6 options:\n"
+msgstr ""
+
+#: dhcp-common.c:823
+msgid ", prefix deprecated"
+msgstr ""
+
+#: dhcp-common.c:826
+#, c-format
+msgid ", lease time "
+msgstr ""
+
+#: dhcp-common.c:868
+#, c-format
+msgid "%s stateless on %s%.0s%.0s%s"
+msgstr ""
+
+#: dhcp-common.c:870
+#, c-format
+msgid "%s, static leases only on %.0s%s%s%.0s"
+msgstr ""
+
+#: dhcp-common.c:872
+#, c-format
+msgid "%s, proxy on subnet %.0s%s%.0s%.0s"
+msgstr ""
+
+#: dhcp-common.c:873
+#, c-format
+msgid "%s, IP range %s -- %s%s%.0s"
+msgstr ""
+
+#: dhcp-common.c:886
+#, c-format
+msgid "DHCPv4-derived IPv6 names on %s%s"
+msgstr ""
+
+#: dhcp-common.c:889
+#, c-format
+msgid "router advertisement on %s%s"
+msgstr ""
+
+#: dhcp-common.c:900
+#, c-format
+msgid "DHCP relay from %s to %s via %s"
+msgstr ""
+
+#: dhcp-common.c:902
+#, c-format
+msgid "DHCP relay from %s to %s"
+msgstr ""
+
+#: radv.c:110
+#, c-format
+msgid "cannot create ICMPv6 socket: %s"
+msgstr ""
+
+#: auth.c:449
+#, c-format
+msgid "ignoring zone transfer request from %s"
+msgstr ""
+
+#: ipset.c:95
+#, c-format
+msgid "failed to find kernel version: %s"
+msgstr ""
+
+#: ipset.c:114
+#, c-format
+msgid "failed to create IPset control socket: %s"
+msgstr ""
+
+#: ipset.c:233
+#, c-format
+msgid "failed to update ipset %s: %s"
+msgstr ""
+
+#: dnssec.c:527
+msgid "system time considered valid, now checking DNSSEC signature timestamps."
+msgstr ""
+
+#: blockdata.c:58
+#, c-format
+msgid "DNSSEC memory in use %u, max %u, allocated %u"
+msgstr ""
+
+#: tables.c:61
+#, c-format
+msgid "failed to access pf devices: %s"
+msgstr ""
+
+#: tables.c:74
+#, c-format
+msgid "warning: no opened pf devices %s"
+msgstr ""
+
+#: tables.c:82
+#, c-format
+msgid "error: cannot use table name %s"
+msgstr ""
+
+#: tables.c:90
+#, c-format
+msgid "error: cannot strlcpy table name %s"
+msgstr ""
+
+#: tables.c:101
+#, c-format
+msgid "IPset: error:%s"
+msgstr ""
+
+#: tables.c:108
+msgid "info: table created"
+msgstr ""
+
+#: tables.c:134
+#, c-format
+msgid "warning: DIOCR%sADDRS: %s"
+msgstr ""
+
+#: tables.c:138
+#, c-format
+msgid "%d addresses %s"
+msgstr ""
+
+#: inotify.c:62
+#, c-format
+msgid "cannot access path %s: %s"
+msgstr ""
+
+#: inotify.c:95
+#, c-format
+msgid "failed to create inotify: %s"
+msgstr ""
+
+#: inotify.c:111
+#, c-format
+msgid "too many symlinks following %s"
+msgstr ""
+
+#: inotify.c:127
+#, c-format
+msgid "directory %s for resolv-file is missing, cannot poll"
+msgstr ""
+
+#: inotify.c:131 inotify.c:168
+#, c-format
+msgid "failed to create inotify for %s: %s"
+msgstr ""
+
+#: inotify.c:153
+#, c-format
+msgid "bad dynamic directory %s: %s"
+msgstr ""
+
+#: inotify.c:255
+#, c-format
+msgid "inotify, new or changed file %s"
+msgstr ""
diff --git a/po/no.po b/po/no.po
new file mode 100755
index 0000000..bf952d0
--- /dev/null
+++ b/po/no.po
@@ -0,0 +1,2370 @@
+# Norwegian translations for dnsmasq package.
+# This file is put in the public domain.
+# Simon Kelley <simon@thekelleys.org.uk>, 2006.
+#
+# Current translator: Jan Erik Askildt <jeaskildt@gmail.com>, 2006
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: dnsmasq 2.25\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-06-18 12:24+0100\n"
+"PO-Revision-Date: 2017-07-17 18:30+0100\n"
+"Last-Translator: Jan Erik Askildt <jeaskildt@gmail.com>\n"
+"Language-Team: Norwegian <i18n-nb@lister.ping.uio.no>\n"
+"Language: no\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: cache.c:513
+msgid "Internal error in cache."
+msgstr ""
+
+#: cache.c:923
+#, fuzzy, c-format
+msgid "failed to load names from %s: %s"
+msgstr "feilet å laste navn fra %s: %s"
+
+#: cache.c:949 dhcp.c:867
+#, c-format
+msgid "bad address at %s line %d"
+msgstr "dårlig adresse ved %s linje %d"
+
+#: cache.c:1002 dhcp.c:883
+#, c-format
+msgid "bad name at %s line %d"
+msgstr "dårlig navn ved %s linje %d"
+
+#: cache.c:1011 dhcp.c:958
+#, c-format
+msgid "read %s - %d addresses"
+msgstr "les %s - %d adresser"
+
+#: cache.c:1124
+msgid "cleared cache"
+msgstr "mellomlager tømt"
+
+#: cache.c:1153
+#, c-format
+msgid "No IPv4 address found for %s"
+msgstr ""
+
+#: cache.c:1232
+#, c-format
+msgid "%s is a CNAME, not giving it to the DHCP lease of %s"
+msgstr ""
+
+#: cache.c:1256
+#, c-format
+msgid "not giving name %s to the DHCP lease of %s because the name exists in %s with address %s"
+msgstr "gir ikke navnet %s til DHCP leien for %s fordi navnet eksisterer i %s med adressen %s"
+
+#: cache.c:1413
+#, c-format
+msgid "time %lu"
+msgstr ""
+
+#: cache.c:1414
+#, fuzzy, c-format
+msgid "cache size %d, %d/%d cache insertions re-used unexpired cache entries."
+msgstr "mellomlager størrelse %d, %d/%d mellomlager innsettinger re-bruker mellomlager plasser som ikke er utløpt"
+
+#: cache.c:1416
+#, c-format
+msgid "queries forwarded %u, queries answered locally %u"
+msgstr ""
+
+#: cache.c:1419
+#, c-format
+msgid "queries for authoritative zones %u"
+msgstr ""
+
+#: cache.c:1445
+#, c-format
+msgid "server %s#%d: queries sent %u, retried or failed %u"
+msgstr ""
+
+#: util.c:47
+#, fuzzy, c-format
+msgid "failed to seed the random number generator: %s"
+msgstr "feilet å lytte på socket: %s"
+
+#: util.c:224
+#, fuzzy
+msgid "failed to allocate memory"
+msgstr "feilet å laste %d bytes"
+
+#: util.c:277 option.c:619
+msgid "could not get memory"
+msgstr "kunne ikke få minne"
+
+#: util.c:287
+#, fuzzy, c-format
+msgid "cannot create pipe: %s"
+msgstr "kan ikke lese %s: %s"
+
+#: util.c:295
+#, fuzzy, c-format
+msgid "failed to allocate %d bytes"
+msgstr "feilet å laste %d bytes"
+
+#: util.c:464
+#, c-format
+msgid "infinite"
+msgstr "uendelig"
+
+#: option.c:344
+msgid "Specify local address(es) to listen on."
+msgstr "Spesifiser lokal(e) adresse(r) å lytte på."
+
+#: option.c:345
+msgid "Return ipaddr for all hosts in specified domains."
+msgstr "Returner ipaddr for alle verter i det spesifiserte domenet."
+
+#: option.c:346
+msgid "Fake reverse lookups for RFC1918 private address ranges."
+msgstr "Forfalsk revers oppslag for RFC1918 private adresse områder."
+
+#: option.c:347
+msgid "Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."
+msgstr "Behandle ipaddr som NXDOMAIN (omgår Verisign wildcard)."
+
+#: option.c:348
+#, c-format
+msgid "Specify the size of the cache in entries (defaults to %s)."
+msgstr "Spesifiser størrelsen på mellomlager plassene (standard er %s)."
+
+#: option.c:349
+#, c-format
+msgid "Specify configuration file (defaults to %s)."
+msgstr "Spesifiser konfigurasjonsfil (standard er %s)."
+
+#: option.c:350
+msgid "Do NOT fork into the background: run in debug mode."
+msgstr "IKKE legg (fork) som bakgrunnsprosess: kjør i debug modus."
+
+#: option.c:351
+msgid "Do NOT forward queries with no domain part."
+msgstr "IKKE videresend oppslag som mangler domene del."
+
+#: option.c:352
+msgid "Return self-pointing MX records for local hosts."
+msgstr "Returner selv-pekende MX post for lokale verter."
+
+#: option.c:353
+msgid "Expand simple names in /etc/hosts with domain-suffix."
+msgstr "Utvid enkle navn i /etc/hosts med domene-suffiks."
+
+#: option.c:354
+msgid "Don't forward spurious DNS requests from Windows hosts."
+msgstr "Ikke videresend falske/uekte DNS forespørsler fra Windows verter."
+
+#: option.c:355
+msgid "Enable DHCP in the range given with lease duration."
+msgstr "Aktiver DHCP i det gitte området med leie varighet"
+
+#: option.c:356
+#, c-format
+msgid "Change to this group after startup (defaults to %s)."
+msgstr "Skift til denne gruppen etter oppstart (standard er %s)."
+
+#: option.c:357
+msgid "Set address or hostname for a specified machine."
+msgstr "Sett adresse eller vertsnavn for en spesifikk maskin."
+
+#: option.c:358
+#, fuzzy
+msgid "Read DHCP host specs from file."
+msgstr "dårlig MX navn"
+
+#: option.c:359
+msgid "Read DHCP option specs from file."
+msgstr ""
+
+#: option.c:360
+#, fuzzy
+msgid "Read DHCP host specs from a directory."
+msgstr "dårlig MX navn"
+
+#: option.c:361
+#, fuzzy
+msgid "Read DHCP options from a directory."
+msgstr "dårlig MX navn"
+
+#: option.c:362
+msgid "Evaluate conditional tag expression."
+msgstr ""
+
+#: option.c:363
+#, c-format
+msgid "Do NOT load %s file."
+msgstr "IKKE last %s filen."
+
+#: option.c:364
+#, c-format
+msgid "Specify a hosts file to be read in addition to %s."
+msgstr "Spesifiser en verts (hosts) fil som skal leses i tilleg til %s."
+
+#: option.c:365
+#, fuzzy
+msgid "Read hosts files from a directory."
+msgstr "dårlig MX navn"
+
+#: option.c:366
+msgid "Specify interface(s) to listen on."
+msgstr "Spesifiser nettverkskort det skal lyttes på."
+
+#: option.c:367
+msgid "Specify interface(s) NOT to listen on."
+msgstr "Spesifiser nettverkskort det IKKE skal lyttes på."
+
+#: option.c:368
+#, fuzzy
+msgid "Map DHCP user class to tag."
+msgstr "Map DHCP bruker klasse til opsjon sett."
+
+#: option.c:369
+msgid "Map RFC3046 circuit-id to tag."
+msgstr ""
+
+#: option.c:370
+msgid "Map RFC3046 remote-id to tag."
+msgstr ""
+
+#: option.c:371
+msgid "Map RFC3993 subscriber-id to tag."
+msgstr ""
+
+#: option.c:372
+#, fuzzy
+msgid "Don't do DHCP for hosts with tag set."
+msgstr "Ikke utfør DHCP for klienter i opsjon sett."
+
+#: option.c:373
+#, fuzzy
+msgid "Force broadcast replies for hosts with tag set."
+msgstr "Ikke utfør DHCP for klienter i opsjon sett."
+
+#: option.c:374
+msgid "Do NOT fork into the background, do NOT run in debug mode."
+msgstr "IKKE last (fork) som bakgrunnsprosess, IKKE kjør i debug modus."
+
+#: option.c:375
+msgid "Assume we are the only DHCP server on the local network."
+msgstr "Anta at vi er den eneste DHCP tjeneren på det lokale nettverket."
+
+#: option.c:376
+#, c-format
+msgid "Specify where to store DHCP leases (defaults to %s)."
+msgstr "Spesifiser hvor DHCP leiene skal lagres (standard er %s)."
+
+#: option.c:377
+msgid "Return MX records for local hosts."
+msgstr "Returner MX records for lokale verter."
+
+#: option.c:378
+msgid "Specify an MX record."
+msgstr "Spesifiser en MX post."
+
+#: option.c:379
+msgid "Specify BOOTP options to DHCP server."
+msgstr "Spesifiser BOOTP opsjoner til DHCP tjener."
+
+#: option.c:380
+#, c-format
+msgid "Do NOT poll %s file, reload only on SIGHUP."
+msgstr "IKKE spør (poll) %s fil, les på nytt kun ved SIGHUP"
+
+#: option.c:381
+msgid "Do NOT cache failed search results."
+msgstr "IKKE mellomlagre søkeresultater som feiler."
+
+#: option.c:382
+#, c-format
+msgid "Use nameservers strictly in the order given in %s."
+msgstr "Bruk navnetjenere kun som bestemt i rekkefølgen gitt i %s."
+
+#: option.c:383
+#, fuzzy
+msgid "Specify options to be sent to DHCP clients."
+msgstr "Sett ekstra opsjoner som skal fordeles til DHCP klientene."
+
+#: option.c:384
+msgid "DHCP option sent even if the client does not request it."
+msgstr ""
+
+#: option.c:385
+msgid "Specify port to listen for DNS requests on (defaults to 53)."
+msgstr "Spesifiser lytteport for DNS oppslag (standard er 53)."
+
+#: option.c:386
+#, c-format
+msgid "Maximum supported UDP packet size for EDNS.0 (defaults to %s)."
+msgstr "Maksimal støttet UDP pakkestørrelse for EDNS.0 (standard er %s)."
+
+#: option.c:387
+#, fuzzy
+msgid "Log DNS queries."
+msgstr "Logg oppslag."
+
+#: option.c:388
+#, fuzzy
+msgid "Force the originating port for upstream DNS queries."
+msgstr "Tving bruk av opprinnelig port for oppstrøms oppslag."
+
+#: option.c:389
+msgid "Do NOT read resolv.conf."
+msgstr "IKKE les resolv.conf."
+
+#: option.c:390
+#, c-format
+msgid "Specify path to resolv.conf (defaults to %s)."
+msgstr "Spesifiser stien til resolv.conf (standard er %s)."
+
+#: option.c:391
+#, fuzzy
+msgid "Specify path to file with server= options"
+msgstr "Spesifiser stien til PID fil. (standard er %s)."
+
+#: option.c:392
+msgid "Specify address(es) of upstream servers with optional domains."
+msgstr "Spesifiser adressen(e) til oppstrøms tjenere med valgfrie domener."
+
+#: option.c:393
+#, fuzzy
+msgid "Specify address of upstream servers for reverse address queries"
+msgstr "Spesifiser adressen(e) til oppstrøms tjenere med valgfrie domener."
+
+#: option.c:394
+msgid "Never forward queries to specified domains."
+msgstr "Aldri videresend oppslag til spesifiserte domener."
+
+#: option.c:395
+msgid "Specify the domain to be assigned in DHCP leases."
+msgstr "Spesifiser domenet som skal tildeles i DHCP leien."
+
+#: option.c:396
+msgid "Specify default target in an MX record."
+msgstr "Spesifiser default mål i en MX post."
+
+#: option.c:397
+msgid "Specify time-to-live in seconds for replies from /etc/hosts."
+msgstr "Spesifiser time-to-live i sekunder for svar fra /etc/hosts."
+
+#: option.c:398
+#, fuzzy
+msgid "Specify time-to-live in seconds for negative caching."
+msgstr "Spesifiser time-to-live i sekunder for svar fra /etc/hosts."
+
+#: option.c:399
+#, fuzzy
+msgid "Specify time-to-live in seconds for maximum TTL to send to clients."
+msgstr "Spesifiser time-to-live i sekunder for svar fra /etc/hosts."
+
+#: option.c:400
+#, fuzzy
+msgid "Specify time-to-live ceiling for cache."
+msgstr "Spesifiser time-to-live i sekunder for svar fra /etc/hosts."
+
+#: option.c:401
+#, fuzzy
+msgid "Specify time-to-live floor for cache."
+msgstr "Spesifiser time-to-live i sekunder for svar fra /etc/hosts."
+
+#: option.c:402
+#, c-format
+msgid "Change to this user after startup. (defaults to %s)."
+msgstr "Skift til denne bruker etter oppstart (standard er %s)."
+
+#: option.c:403
+#, fuzzy
+msgid "Map DHCP vendor class to tag."
+msgstr "Map DHCP produsent klasse til opsjon sett."
+
+#: option.c:404
+msgid "Display dnsmasq version and copyright information."
+msgstr "Vis dnsmasq versjon og copyright informasjon."
+
+#: option.c:405
+msgid "Translate IPv4 addresses from upstream servers."
+msgstr "Oversett IPv4 adresser fra oppstrøms tjenere."
+
+#: option.c:406
+msgid "Specify a SRV record."
+msgstr "Spesifiser en SRV post."
+
+#: option.c:407
+msgid "Display this message. Use --help dhcp or --help dhcp6 for known DHCP options."
+msgstr ""
+
+#: option.c:408
+#, fuzzy, c-format
+msgid "Specify path of PID file (defaults to %s)."
+msgstr "Spesifiser stien til PID fil. (standard er %s)."
+
+#: option.c:409
+#, c-format
+msgid "Specify maximum number of DHCP leases (defaults to %s)."
+msgstr "Spesifiser maksimum antall DHCP leier (standard er %s)"
+
+#: option.c:410
+msgid "Answer DNS queries based on the interface a query was sent to."
+msgstr "Svar DNS oppslag basert på nettverkskortet oppslaget ble sendt til."
+
+#: option.c:411
+msgid "Specify TXT DNS record."
+msgstr "Spesifiser TXT DNS post."
+
+#: option.c:412
+#, fuzzy
+msgid "Specify PTR DNS record."
+msgstr "Spesifiser TXT DNS post."
+
+#: option.c:413
+msgid "Give DNS name to IPv4 address of interface."
+msgstr ""
+
+#: option.c:414
+msgid "Bind only to interfaces in use."
+msgstr "Bind kun til nettverkskort som er i bruk."
+
+#: option.c:415
+#, c-format
+msgid "Read DHCP static host information from %s."
+msgstr "Les DHCP statisk vert informasjon fra %s."
+
+#: option.c:416
+msgid "Enable the DBus interface for setting upstream servers, etc."
+msgstr "Aktiver DBus interface for å sette oppstrøms tjenere, osv."
+
+#: option.c:417
+msgid "Do not provide DHCP on this interface, only provide DNS."
+msgstr "Ikke lever DHCP på dette nettverkskortet, kun lever DNS."
+
+#: option.c:418
+msgid "Enable dynamic address allocation for bootp."
+msgstr "Aktiver dynamisk adresse allokering for bootp."
+
+#: option.c:419
+#, fuzzy
+msgid "Map MAC address (with wildcards) to option set."
+msgstr "Map DHCP produsent klasse til opsjon sett."
+
+#: option.c:420
+msgid "Treat DHCP requests on aliases as arriving from interface."
+msgstr ""
+
+#: option.c:421
+msgid "Disable ICMP echo address checking in the DHCP server."
+msgstr ""
+
+#: option.c:422
+msgid "Shell script to run on DHCP lease creation and destruction."
+msgstr ""
+
+#: option.c:423
+msgid "Lua script to run on DHCP lease creation and destruction."
+msgstr ""
+
+#: option.c:424
+msgid "Run lease-change scripts as this user."
+msgstr ""
+
+#: option.c:425
+msgid "Call dhcp-script with changes to local ARP table."
+msgstr ""
+
+#: option.c:426
+msgid "Read configuration from all the files in this directory."
+msgstr ""
+
+#: option.c:427
+#, fuzzy
+msgid "Log to this syslog facility or file. (defaults to DAEMON)"
+msgstr "Skift til denne bruker etter oppstart (standard er %s)."
+
+#: option.c:428
+msgid "Do not use leasefile."
+msgstr ""
+
+#: option.c:429
+#, fuzzy, c-format
+msgid "Maximum number of concurrent DNS queries. (defaults to %s)"
+msgstr "Spesifiser maksimum antall DHCP leier (standard er %s)"
+
+#: option.c:430
+#, c-format
+msgid "Clear DNS cache when reloading %s."
+msgstr ""
+
+#: option.c:431
+msgid "Ignore hostnames provided by DHCP clients."
+msgstr ""
+
+#: option.c:432
+msgid "Do NOT reuse filename and server fields for extra DHCP options."
+msgstr ""
+
+#: option.c:433
+msgid "Enable integrated read-only TFTP server."
+msgstr ""
+
+#: option.c:434
+msgid "Export files by TFTP only from the specified subtree."
+msgstr ""
+
+#: option.c:435
+msgid "Add client IP or hardware address to tftp-root."
+msgstr ""
+
+#: option.c:436
+msgid "Allow access only to files owned by the user running dnsmasq."
+msgstr ""
+
+#: option.c:437
+msgid "Do not terminate the service if TFTP directories are inaccessible."
+msgstr ""
+
+#: option.c:438
+#, fuzzy, c-format
+msgid "Maximum number of concurrent TFTP transfers (defaults to %s)."
+msgstr "Spesifiser maksimum antall DHCP leier (standard er %s)"
+
+#: option.c:439
+#, fuzzy
+msgid "Maximum MTU to use for TFTP transfers."
+msgstr "Spesifiser maksimum antall DHCP leier (standard er %s)"
+
+#: option.c:440
+msgid "Disable the TFTP blocksize extension."
+msgstr ""
+
+#: option.c:441
+msgid "Convert TFTP filenames to lowercase"
+msgstr ""
+
+#: option.c:442
+msgid "Ephemeral port range for use by TFTP transfers."
+msgstr ""
+
+#: option.c:443
+msgid "Extra logging for DHCP."
+msgstr ""
+
+#: option.c:444
+msgid "Enable async. logging; optionally set queue length."
+msgstr ""
+
+#: option.c:445
+msgid "Stop DNS rebinding. Filter private IP ranges when resolving."
+msgstr ""
+
+#: option.c:446
+msgid "Allow rebinding of 127.0.0.0/8, for RBL servers."
+msgstr ""
+
+#: option.c:447
+msgid "Inhibit DNS-rebind protection on this domain."
+msgstr ""
+
+#: option.c:448
+msgid "Always perform DNS queries to all servers."
+msgstr ""
+
+#: option.c:449
+msgid "Set tag if client includes matching option in request."
+msgstr ""
+
+#: option.c:450
+msgid "Use alternative ports for DHCP."
+msgstr ""
+
+#: option.c:451
+#, fuzzy
+msgid "Specify NAPTR DNS record."
+msgstr "Spesifiser TXT DNS post."
+
+#: option.c:452
+msgid "Specify lowest port available for DNS query transmission."
+msgstr ""
+
+#: option.c:453
+msgid "Specify highest port available for DNS query transmission."
+msgstr ""
+
+#: option.c:454
+msgid "Use only fully qualified domain names for DHCP clients."
+msgstr ""
+
+#: option.c:455
+msgid "Generate hostnames based on MAC address for nameless clients."
+msgstr ""
+
+#: option.c:456
+msgid "Use these DHCP relays as full proxies."
+msgstr ""
+
+#: option.c:457
+msgid "Relay DHCP requests to a remote server"
+msgstr ""
+
+#: option.c:458
+msgid "Specify alias name for LOCAL DNS name."
+msgstr ""
+
+#: option.c:459
+#, fuzzy
+msgid "Prompt to send to PXE clients."
+msgstr "Sett ekstra opsjoner som skal fordeles til DHCP klientene."
+
+#: option.c:460
+msgid "Boot service for PXE menu."
+msgstr ""
+
+#: option.c:461
+msgid "Check configuration syntax."
+msgstr ""
+
+#: option.c:462
+msgid "Add requestor's MAC address to forwarded DNS queries."
+msgstr ""
+
+#: option.c:463
+msgid "Add specified IP subnet to forwarded DNS queries."
+msgstr ""
+
+#: option.c:464
+#, fuzzy
+msgid "Add client identification to forwarded DNS queries."
+msgstr "Tving bruk av opprinnelig port for oppstrøms oppslag."
+
+#: option.c:465
+#, fuzzy
+msgid "Proxy DNSSEC validation results from upstream nameservers."
+msgstr "Oversett IPv4 adresser fra oppstrøms tjenere."
+
+#: option.c:466
+msgid "Attempt to allocate sequential IP addresses to DHCP clients."
+msgstr ""
+
+#: option.c:467
+msgid "Copy connection-track mark from queries to upstream connections."
+msgstr ""
+
+#: option.c:468
+msgid "Allow DHCP clients to do their own DDNS updates."
+msgstr ""
+
+#: option.c:469
+msgid "Send router-advertisements for interfaces doing DHCPv6"
+msgstr ""
+
+#: option.c:470
+msgid "Specify DUID_EN-type DHCPv6 server DUID"
+msgstr ""
+
+#: option.c:471
+#, fuzzy
+msgid "Specify host (A/AAAA and PTR) records"
+msgstr "Spesifiser en MX post."
+
+#: option.c:472
+#, fuzzy
+msgid "Specify arbitrary DNS resource record"
+msgstr "Spesifiser TXT DNS post."
+
+#: option.c:473
+#, fuzzy
+msgid "Bind to interfaces in use - check for new interfaces"
+msgstr "ukjent tilknytning (interface) %s"
+
+#: option.c:474
+msgid "Export local names to global DNS"
+msgstr ""
+
+#: option.c:475
+msgid "Domain to export to global DNS"
+msgstr ""
+
+#: option.c:476
+msgid "Set TTL for authoritative replies"
+msgstr ""
+
+#: option.c:477
+msgid "Set authoritative zone information"
+msgstr ""
+
+#: option.c:478
+msgid "Secondary authoritative nameservers for forward domains"
+msgstr ""
+
+#: option.c:479
+msgid "Peers which are allowed to do zone transfer"
+msgstr ""
+
+#: option.c:480
+msgid "Specify ipsets to which matching domains should be added"
+msgstr ""
+
+#: option.c:481
+msgid "Specify a domain and address range for synthesised names"
+msgstr ""
+
+#: option.c:482
+msgid "Activate DNSSEC validation"
+msgstr ""
+
+#: option.c:483
+msgid "Specify trust anchor key digest."
+msgstr ""
+
+#: option.c:484
+msgid "Disable upstream checking for DNSSEC debugging."
+msgstr ""
+
+#: option.c:485
+msgid "Ensure answers without DNSSEC are in unsigned zones."
+msgstr ""
+
+#: option.c:486
+msgid "Don't check DNSSEC signature timestamps until first cache-reload"
+msgstr ""
+
+#: option.c:487
+msgid "Timestamp file to verify system clock for DNSSEC"
+msgstr ""
+
+#: option.c:489
+msgid "Specify DHCPv6 prefix class"
+msgstr ""
+
+#: option.c:491
+msgid "Set MTU, priority, resend-interval and router-lifetime"
+msgstr ""
+
+#: option.c:492
+msgid "Do not log routine DHCP."
+msgstr ""
+
+#: option.c:493
+msgid "Do not log routine DHCPv6."
+msgstr ""
+
+#: option.c:494
+msgid "Do not log RA."
+msgstr ""
+
+#: option.c:495
+msgid "Accept queries only from directly-connected networks."
+msgstr ""
+
+#: option.c:496
+msgid "Detect and remove DNS forwarding loops."
+msgstr ""
+
+#: option.c:497
+msgid "Ignore DNS responses containing ipaddr."
+msgstr ""
+
+#: option.c:498
+msgid "Set TTL in DNS responses with DHCP-derived addresses."
+msgstr ""
+
+#: option.c:499
+msgid "Delay DHCP replies for at least number of seconds."
+msgstr ""
+
+#: option.c:703
+#, c-format
+msgid ""
+"Usage: dnsmasq [options]\n"
+"\n"
+msgstr ""
+"Bruk: dnsmasq [opsjoner]\n"
+"\n"
+
+#: option.c:705
+#, c-format
+msgid "Use short options only on the command line.\n"
+msgstr "Bruk korte opsjoner kun på kommandolinjen.\n"
+
+#: option.c:707
+#, fuzzy, c-format
+msgid "Valid options are:\n"
+msgstr "Gyldige opsjoner er :\n"
+
+#: option.c:754 option.c:868
+#, fuzzy
+msgid "bad address"
+msgstr "les %s - %d adresser"
+
+#: option.c:779 option.c:783
+msgid "bad port"
+msgstr "dårlig port"
+
+#: option.c:797 option.c:826 option.c:861
+msgid "interface binding not supported"
+msgstr ""
+
+#: option.c:821 option.c:856
+msgid "interface can only be specified once"
+msgstr ""
+
+#: option.c:835 option.c:3800
+#, fuzzy
+msgid "bad interface name"
+msgstr "dårlig MX navn"
+
+#: option.c:1062
+msgid "unsupported encapsulation for IPv6 option"
+msgstr ""
+
+#: option.c:1076
+msgid "bad dhcp-option"
+msgstr "dårlig dhcp-opsjon"
+
+#: option.c:1144
+#, fuzzy
+msgid "bad IP address"
+msgstr "les %s - %d adresser"
+
+#: option.c:1147 option.c:1286 option.c:3070
+#, fuzzy
+msgid "bad IPv6 address"
+msgstr "les %s - %d adresser"
+
+#: option.c:1240
+#, fuzzy
+msgid "bad IPv4 address"
+msgstr "les %s - %d adresser"
+
+#: option.c:1313 option.c:1407
+msgid "bad domain in dhcp-option"
+msgstr "dårlig domene i dhcp-opsjon"
+
+#: option.c:1445
+msgid "dhcp-option too long"
+msgstr "dhcp-opsjon for lang"
+
+#: option.c:1452
+msgid "illegal dhcp-match"
+msgstr ""
+
+#: option.c:1514
+msgid "illegal repeated flag"
+msgstr ""
+
+#: option.c:1522
+msgid "illegal repeated keyword"
+msgstr ""
+
+#: option.c:1593 option.c:4434
+#, fuzzy, c-format
+msgid "cannot access directory %s: %s"
+msgstr "kan ikke lese %s: %s"
+
+#: option.c:1639 tftp.c:537
+#, fuzzy, c-format
+msgid "cannot access %s: %s"
+msgstr "kan ikke lese %s: %s"
+
+#: option.c:1727
+msgid "setting log facility is not possible under Android"
+msgstr ""
+
+#: option.c:1736
+msgid "bad log facility"
+msgstr ""
+
+#: option.c:1789
+msgid "bad MX preference"
+msgstr "dårlig MX preferanse"
+
+#: option.c:1794
+msgid "bad MX name"
+msgstr "dårlig MX navn"
+
+#: option.c:1808
+msgid "bad MX target"
+msgstr "dårlig MX mål"
+
+#: option.c:1820
+msgid "cannot run scripts under uClinux"
+msgstr ""
+
+#: option.c:1822
+msgid "recompile with HAVE_SCRIPT defined to enable lease-change scripts"
+msgstr ""
+
+#: option.c:1826
+msgid "recompile with HAVE_LUASCRIPT defined to enable Lua scripts"
+msgstr ""
+
+#: option.c:2095 option.c:2106 option.c:2143 option.c:2199 option.c:2482
+#, fuzzy
+msgid "bad prefix"
+msgstr "dårlig port"
+
+#: option.c:2504
+msgid "recompile with HAVE_IPSET defined to enable ipset directives"
+msgstr ""
+
+#: option.c:2713
+#, fuzzy
+msgid "bad port range"
+msgstr "dårlig port"
+
+#: option.c:2738
+msgid "bad bridge-interface"
+msgstr ""
+
+#: option.c:2798
+msgid "only one tag allowed"
+msgstr ""
+
+#: option.c:2818 option.c:2830 option.c:2939 option.c:2944 option.c:2983
+msgid "bad dhcp-range"
+msgstr "dårlig dhcp-område"
+
+#: option.c:2845
+msgid "inconsistent DHCP range"
+msgstr "ikke konsistent DHCP område"
+
+#: option.c:2907
+msgid "prefix length must be exactly 64 for RA subnets"
+msgstr ""
+
+#: option.c:2909
+msgid "prefix length must be exactly 64 for subnet constructors"
+msgstr ""
+
+#: option.c:2913
+msgid "prefix length must be at least 64"
+msgstr ""
+
+#: option.c:2916
+#, fuzzy
+msgid "inconsistent DHCPv6 range"
+msgstr "ikke konsistent DHCP område"
+
+#: option.c:2927
+msgid "prefix must be zero with \"constructor:\" argument"
+msgstr ""
+
+#: option.c:3040 option.c:3088
+#, fuzzy
+msgid "bad hex constant"
+msgstr "dårlig dhcp-vert"
+
+#: option.c:3062
+msgid "cannot match tags in --dhcp-host"
+msgstr ""
+
+#: option.c:3110
+#, fuzzy, c-format
+msgid "duplicate dhcp-host IP address %s"
+msgstr "dubliserte IP adresser i %s dhcp-config direktiv."
+
+#: option.c:3168
+#, fuzzy
+msgid "bad DHCP host name"
+msgstr "dårlig MX navn"
+
+#: option.c:3250
+#, fuzzy
+msgid "bad tag-if"
+msgstr "dårlig MX mål"
+
+#: option.c:3607 option.c:4030
+msgid "invalid port number"
+msgstr "ugyldig portnummer"
+
+#: option.c:3669
+#, fuzzy
+msgid "bad dhcp-proxy address"
+msgstr "les %s - %d adresser"
+
+#: option.c:3695
+#, fuzzy
+msgid "Bad dhcp-relay"
+msgstr "dårlig dhcp-område"
+
+#: option.c:3736
+msgid "bad RA-params"
+msgstr ""
+
+#: option.c:3745
+msgid "bad DUID"
+msgstr ""
+
+#: option.c:3787
+#, fuzzy
+msgid "invalid alias range"
+msgstr "ugyldig vekt"
+
+#: option.c:3841 option.c:3853
+msgid "bad CNAME"
+msgstr ""
+
+#: option.c:3857
+msgid "duplicate CNAME"
+msgstr ""
+
+#: option.c:3880
+#, fuzzy
+msgid "bad PTR record"
+msgstr "dårlig SRV post"
+
+#: option.c:3911
+#, fuzzy
+msgid "bad NAPTR record"
+msgstr "dårlig SRV post"
+
+#: option.c:3945
+#, fuzzy
+msgid "bad RR record"
+msgstr "dårlig SRV post"
+
+#: option.c:3975
+msgid "bad TXT record"
+msgstr "dårlig TXT post"
+
+#: option.c:4016
+msgid "bad SRV record"
+msgstr "dårlig SRV post"
+
+#: option.c:4023
+msgid "bad SRV target"
+msgstr "dårlig SRV mål"
+
+#: option.c:4037
+msgid "invalid priority"
+msgstr "ugyldig prioritet"
+
+#: option.c:4040
+msgid "invalid weight"
+msgstr "ugyldig vekt"
+
+#: option.c:4064
+#, fuzzy
+msgid "Bad host-record"
+msgstr "dårlig SRV post"
+
+#: option.c:4088
+#, fuzzy
+msgid "Bad name in host-record"
+msgstr "dårlig navn i %s"
+
+#: option.c:4153
+#, fuzzy
+msgid "bad trust anchor"
+msgstr "dårlig port"
+
+#: option.c:4167
+msgid "bad HEX in trust anchor"
+msgstr ""
+
+#: option.c:4177
+msgid "unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"
+msgstr ""
+
+#: option.c:4237
+msgid "missing \""
+msgstr "mangler \""
+
+#: option.c:4294
+msgid "bad option"
+msgstr "dårlig opsjon"
+
+#: option.c:4296
+msgid "extraneous parameter"
+msgstr "overflødig parameter"
+
+#: option.c:4298
+msgid "missing parameter"
+msgstr "mangler parameter"
+
+#: option.c:4300
+#, fuzzy
+msgid "illegal option"
+msgstr "dårlig opsjon"
+
+#: option.c:4307
+msgid "error"
+msgstr "feil"
+
+#: option.c:4309
+#, fuzzy, c-format
+msgid " at line %d of %s"
+msgstr "%s på linje %d av %%s"
+
+#: option.c:4324 option.c:4571 option.c:4607
+#, fuzzy, c-format
+msgid "read %s"
+msgstr "leser %s"
+
+#: option.c:4387 option.c:4510 tftp.c:715
+#, c-format
+msgid "cannot read %s: %s"
+msgstr "kan ikke lese %s: %s"
+
+#: option.c:4676
+msgid "junk found in command line"
+msgstr ""
+
+#: option.c:4711
+#, c-format
+msgid "Dnsmasq version %s  %s\n"
+msgstr "Dnsmasq versjon %s %s\n"
+
+#: option.c:4712
+#, fuzzy, c-format
+msgid ""
+"Compile time options: %s\n"
+"\n"
+msgstr ""
+"Kompileringsopsjoner %s\n"
+"\n"
+
+#: option.c:4713
+#, c-format
+msgid "This software comes with ABSOLUTELY NO WARRANTY.\n"
+msgstr "Denne programvaren kommer med ABSOLUTT INGEN GARANTI.\n"
+
+#: option.c:4714
+#, c-format
+msgid "Dnsmasq is free software, and you are welcome to redistribute it\n"
+msgstr "DNsmasq er fri programvare, du er velkommen til å redistribuere den\n"
+
+#: option.c:4715
+#, fuzzy, c-format
+msgid "under the terms of the GNU General Public License, version 2 or 3.\n"
+msgstr "under vilkårene gitt i GNU General Public License, versjon 2.\n"
+
+#: option.c:4726
+msgid "try --help"
+msgstr ""
+
+#: option.c:4728
+msgid "try -w"
+msgstr ""
+
+#: option.c:4730
+#, fuzzy, c-format
+msgid "bad command line options: %s"
+msgstr "dårlige kommandlinje opsjoner: %s."
+
+#: option.c:4798
+#, c-format
+msgid "CNAME loop involving %s"
+msgstr ""
+
+#: option.c:4834
+#, c-format
+msgid "cannot get host-name: %s"
+msgstr "klarer ikke å få vertsnavn: %s"
+
+#: option.c:4862
+msgid "only one resolv.conf file allowed in no-poll mode."
+msgstr "kun en resolv.conf fil tillat i no-poll modus."
+
+#: option.c:4872
+msgid "must have exactly one resolv.conf to read domain from."
+msgstr "må ha nøyaktig en resolv.conf å lese domene fra."
+
+#: option.c:4875 network.c:1612 dhcp.c:816
+#, fuzzy, c-format
+msgid "failed to read %s: %s"
+msgstr "feilet å lese %s: %s"
+
+#: option.c:4892
+#, c-format
+msgid "no search directive found in %s"
+msgstr "intet søke direktiv funnet i %s"
+
+#: option.c:4913
+msgid "there must be a default domain when --dhcp-fqdn is set"
+msgstr ""
+
+#: option.c:4922
+msgid "syntax check OK"
+msgstr ""
+
+#: forward.c:102
+#, fuzzy, c-format
+msgid "failed to send packet: %s"
+msgstr "feilet å lytte på socket: %s"
+
+#: forward.c:597
+msgid "discarding DNS reply: subnet option mismatch"
+msgstr ""
+
+#: forward.c:651
+#, c-format
+msgid "nameserver %s refused to do a recursive query"
+msgstr "navnetjener %s nektet å gjøre et rekursivt oppslag"
+
+#: forward.c:683
+#, c-format
+msgid "possible DNS-rebind attack detected: %s"
+msgstr ""
+
+#: forward.c:1244 forward.c:1681
+msgid "Ignoring query from non-local network"
+msgstr ""
+
+#: forward.c:2166
+#, fuzzy, c-format
+msgid "Maximum number of concurrent DNS queries reached (max: %d)"
+msgstr "Spesifiser maksimum antall DHCP leier (standard er %s)"
+
+#: network.c:720
+#, fuzzy, c-format
+msgid "failed to create listening socket for %s: %s"
+msgstr "feilet å lage lytte socket: %s"
+
+#: network.c:1031
+#, c-format
+msgid "LOUD WARNING: listening on %s may accept requests via interfaces other than %s"
+msgstr ""
+
+#: network.c:1038
+msgid "LOUD WARNING: use --bind-dynamic rather than --bind-interfaces to avoid DNS amplification attacks via these interface(s)"
+msgstr ""
+
+#: network.c:1047
+#, fuzzy, c-format
+msgid "warning: using interface %s instead"
+msgstr "advarsel: nettverkskort %s eksisterer ikke for tiden"
+
+#: network.c:1056
+#, fuzzy, c-format
+msgid "warning: no addresses found for interface %s"
+msgstr "benytter lokale adresser kun for %s %s"
+
+#: network.c:1114
+#, fuzzy, c-format
+msgid "interface %s failed to join DHCPv6 multicast group: %s"
+msgstr "feilet å binde DHCP tjener socket: %s"
+
+#: network.c:1119
+msgid "try increasing /proc/sys/net/core/optmem_max"
+msgstr ""
+
+#: network.c:1322
+#, fuzzy, c-format
+msgid "failed to bind server socket for %s: %s"
+msgstr "feilet å binde lytte socket for %s: %s"
+
+#: network.c:1517
+#, c-format
+msgid "ignoring nameserver %s - local interface"
+msgstr "ignorerer navnetjener %s - lokal tilknytning"
+
+#: network.c:1528
+#, fuzzy, c-format
+msgid "ignoring nameserver %s - cannot make/bind socket: %s"
+msgstr "ignorerer navnetjener %s - kan ikke lage/dinde socket: %s"
+
+#: network.c:1548
+msgid "(no DNSSEC)"
+msgstr ""
+
+#: network.c:1551
+msgid "unqualified"
+msgstr "ikke kvalifisert"
+
+#: network.c:1551
+msgid "names"
+msgstr ""
+
+#: network.c:1553
+msgid "default"
+msgstr ""
+
+#: network.c:1555
+msgid "domain"
+msgstr "domene"
+
+#: network.c:1561
+#, c-format
+msgid "using local addresses only for %s %s"
+msgstr "benytter lokale adresser kun for %s %s"
+
+#: network.c:1564
+#, fuzzy, c-format
+msgid "using standard nameservers for %s %s"
+msgstr "benytter navnetjener %s#%d for %s %s"
+
+#: network.c:1566
+#, fuzzy, c-format
+msgid "using nameserver %s#%d for %s %s %s"
+msgstr "benytter navnetjener %s#%d for %s %s"
+
+#: network.c:1570
+#, fuzzy, c-format
+msgid "NOT using nameserver %s#%d - query loop detected"
+msgstr "benytter navnetjener %s#%d for %s %s"
+
+#: network.c:1573
+#, fuzzy, c-format
+msgid "using nameserver %s#%d(via %s)"
+msgstr "benytter navnetjener %s#%d"
+
+#: network.c:1575
+#, c-format
+msgid "using nameserver %s#%d"
+msgstr "benytter navnetjener %s#%d"
+
+#: network.c:1580
+#, fuzzy, c-format
+msgid "using %d more local addresses"
+msgstr "benytter navnetjener %s#%d"
+
+#: network.c:1582
+#, fuzzy, c-format
+msgid "using %d more nameservers"
+msgstr "benytter navnetjener %s#%d"
+
+#: dnsmasq.c:166
+msgid "dhcp-hostsdir, dhcp-optsdir and hostsdir are not supported on this platform"
+msgstr ""
+
+#: dnsmasq.c:181
+msgid "no root trust anchor provided for DNSSEC"
+msgstr ""
+
+#: dnsmasq.c:184
+msgid "cannot reduce cache size from default when DNSSEC enabled"
+msgstr ""
+
+#: dnsmasq.c:186
+#, fuzzy
+msgid "DNSSEC not available: set HAVE_DNSSEC in src/config.h"
+msgstr "DBus ikke tilgjengelig: sett HAVE_DBUS i src/config.h"
+
+#: dnsmasq.c:192
+#, fuzzy
+msgid "TFTP server not available: set HAVE_TFTP in src/config.h"
+msgstr "DBus ikke tilgjengelig: sett HAVE_DBUS i src/config.h"
+
+#: dnsmasq.c:197
+msgid "cannot use --conntrack AND --query-port"
+msgstr ""
+
+#: dnsmasq.c:200
+#, fuzzy
+msgid "conntrack support not available: set HAVE_CONNTRACK in src/config.h"
+msgstr "DBus ikke tilgjengelig: sett HAVE_DBUS i src/config.h"
+
+#: dnsmasq.c:205
+msgid "asynchronous logging is not available under Solaris"
+msgstr ""
+
+#: dnsmasq.c:210
+msgid "asynchronous logging is not available under Android"
+msgstr ""
+
+#: dnsmasq.c:215
+#, fuzzy
+msgid "authoritative DNS not available: set HAVE_AUTH in src/config.h"
+msgstr "DBus ikke tilgjengelig: sett HAVE_DBUS i src/config.h"
+
+#: dnsmasq.c:220
+#, fuzzy
+msgid "loop detection not available: set HAVE_LOOP in src/config.h"
+msgstr "DBus ikke tilgjengelig: sett HAVE_DBUS i src/config.h"
+
+#: dnsmasq.c:227
+msgid "max_port cannot be smaller than min_port"
+msgstr ""
+
+#: dnsmasq.c:234
+msgid "zone serial must be configured in --auth-soa"
+msgstr ""
+
+#: dnsmasq.c:252
+msgid "dhcp-range constructor not available on this platform"
+msgstr ""
+
+#: dnsmasq.c:298
+msgid "cannot set --bind-interfaces and --bind-dynamic"
+msgstr ""
+
+#: dnsmasq.c:301
+#, c-format
+msgid "failed to find list of interfaces: %s"
+msgstr "feilet å finne liste av tilknytninger (interfaces): %s"
+
+#: dnsmasq.c:310
+#, c-format
+msgid "unknown interface %s"
+msgstr "ukjent tilknytning (interface) %s"
+
+#: dnsmasq.c:374 dnsmasq.c:1037
+#, c-format
+msgid "DBus error: %s"
+msgstr "DBus feil: %s"
+
+#: dnsmasq.c:377
+msgid "DBus not available: set HAVE_DBUS in src/config.h"
+msgstr "DBus ikke tilgjengelig: sett HAVE_DBUS i src/config.h"
+
+#: dnsmasq.c:405
+#, c-format
+msgid "unknown user or group: %s"
+msgstr ""
+
+#: dnsmasq.c:460
+#, c-format
+msgid "cannot chdir to filesystem root: %s"
+msgstr ""
+
+#: dnsmasq.c:716
+#, fuzzy, c-format
+msgid "started, version %s DNS disabled"
+msgstr "startet, versjon %s mellomlager deaktivert"
+
+#: dnsmasq.c:720
+#, c-format
+msgid "started, version %s cachesize %d"
+msgstr "startet, versjon %s mellomlager størrelse %d"
+
+#: dnsmasq.c:722
+#, c-format
+msgid "started, version %s cache disabled"
+msgstr "startet, versjon %s mellomlager deaktivert"
+
+#: dnsmasq.c:725
+msgid "DNS service limited to local subnets"
+msgstr ""
+
+#: dnsmasq.c:728
+#, c-format
+msgid "compile time options: %s"
+msgstr "kompilerings opsjoner: %s"
+
+#: dnsmasq.c:734
+msgid "DBus support enabled: connected to system bus"
+msgstr "DBus støtte aktivert: koblet til system buss"
+
+#: dnsmasq.c:736
+msgid "DBus support enabled: bus connection pending"
+msgstr "DBus støtte aktivert: avventer buss tilkobling"
+
+#: dnsmasq.c:754
+msgid "DNSSEC validation enabled"
+msgstr ""
+
+#: dnsmasq.c:758
+msgid "DNSSEC signature timestamps not checked until first cache reload"
+msgstr ""
+
+#: dnsmasq.c:761
+msgid "DNSSEC signature timestamps not checked until system time valid"
+msgstr ""
+
+#: dnsmasq.c:766
+#, fuzzy, c-format
+msgid "warning: failed to change owner of %s: %s"
+msgstr "feilet å laste navn fra %s: %s"
+
+#: dnsmasq.c:770
+msgid "setting --bind-interfaces option because of OS limitations"
+msgstr "setter --bind-interfaces opsjon på grunn av OS begrensninger"
+
+#: dnsmasq.c:782
+#, c-format
+msgid "warning: interface %s does not currently exist"
+msgstr "advarsel: nettverkskort %s eksisterer ikke for tiden"
+
+#: dnsmasq.c:787
+msgid "warning: ignoring resolv-file flag because no-resolv is set"
+msgstr ""
+
+#: dnsmasq.c:790
+#, fuzzy
+msgid "warning: no upstream servers configured"
+msgstr "setter oppstrøms tjener fra DBus"
+
+#: dnsmasq.c:794
+#, c-format
+msgid "asynchronous logging enabled, queue limit is %d messages"
+msgstr ""
+
+#: dnsmasq.c:815
+msgid "IPv6 router advertisement enabled"
+msgstr ""
+
+#: dnsmasq.c:820
+#, c-format
+msgid "DHCP, sockets bound exclusively to interface %s"
+msgstr ""
+
+#: dnsmasq.c:834
+msgid "root is "
+msgstr ""
+
+#: dnsmasq.c:834
+#, fuzzy
+msgid "enabled"
+msgstr "deaktivert"
+
+#: dnsmasq.c:836
+msgid "secure mode"
+msgstr ""
+
+#: dnsmasq.c:839
+#, c-format
+msgid "warning: %s inaccessible"
+msgstr ""
+
+#: dnsmasq.c:843
+#, c-format
+msgid "warning: TFTP directory %s inaccessible"
+msgstr ""
+
+#: dnsmasq.c:869
+#, c-format
+msgid "restricting maximum simultaneous TFTP transfers to %d"
+msgstr ""
+
+#: dnsmasq.c:1039
+msgid "connected to system DBus"
+msgstr "tilkoblet til system DBus"
+
+#: dnsmasq.c:1189
+#, c-format
+msgid "cannot fork into background: %s"
+msgstr ""
+
+#: dnsmasq.c:1192
+#, fuzzy, c-format
+msgid "failed to create helper: %s"
+msgstr "feilet å lese %s: %s"
+
+#: dnsmasq.c:1195
+#, c-format
+msgid "setting capabilities failed: %s"
+msgstr ""
+
+#: dnsmasq.c:1198
+#, fuzzy, c-format
+msgid "failed to change user-id to %s: %s"
+msgstr "feilet å laste navn fra %s: %s"
+
+#: dnsmasq.c:1201
+#, fuzzy, c-format
+msgid "failed to change group-id to %s: %s"
+msgstr "feilet å laste navn fra %s: %s"
+
+#: dnsmasq.c:1204
+#, fuzzy, c-format
+msgid "failed to open pidfile %s: %s"
+msgstr "feilet å lese %s: %s"
+
+#: dnsmasq.c:1207
+#, fuzzy, c-format
+msgid "cannot open log %s: %s"
+msgstr "kan ikke åpne %s:%s"
+
+#: dnsmasq.c:1210
+#, fuzzy, c-format
+msgid "failed to load Lua script: %s"
+msgstr "feilet å laste %s: %s"
+
+#: dnsmasq.c:1213
+#, c-format
+msgid "TFTP directory %s inaccessible: %s"
+msgstr ""
+
+#: dnsmasq.c:1216
+#, fuzzy, c-format
+msgid "cannot create timestamp file %s: %s"
+msgstr "kan ikke åpne eller lage leie fil: %s"
+
+#: dnsmasq.c:1239
+msgid "now checking DNSSEC signature timestamps"
+msgstr ""
+
+#: dnsmasq.c:1307
+#, c-format
+msgid "script process killed by signal %d"
+msgstr ""
+
+#: dnsmasq.c:1311
+#, c-format
+msgid "script process exited with status %d"
+msgstr ""
+
+#: dnsmasq.c:1315
+#, fuzzy, c-format
+msgid "failed to execute %s: %s"
+msgstr "feilet å få tilgang til %s: %s"
+
+#: dnsmasq.c:1379 dnssec.c:479 dnssec.c:525
+#, fuzzy, c-format
+msgid "failed to update mtime on %s: %s"
+msgstr "feilet å lese %s: %s"
+
+#: dnsmasq.c:1386
+msgid "exiting on receipt of SIGTERM"
+msgstr "avslutter etter mottak av SIGTERM"
+
+#: dnsmasq.c:1414
+#, fuzzy, c-format
+msgid "failed to access %s: %s"
+msgstr "feilet å få tilgang til %s: %s"
+
+#: dnsmasq.c:1444
+#, c-format
+msgid "reading %s"
+msgstr "leser %s"
+
+#: dnsmasq.c:1455
+#, fuzzy, c-format
+msgid "no servers found in %s, will retry"
+msgstr "intet søke direktiv funnet i %s"
+
+#: dhcp.c:53
+#, c-format
+msgid "cannot create DHCP socket: %s"
+msgstr "kan ikke lage DHCP socket: %s"
+
+#: dhcp.c:68
+#, c-format
+msgid "failed to set options on DHCP socket: %s"
+msgstr "feilet å sette opsjoner på DHCP socket: %s"
+
+#: dhcp.c:89
+#, fuzzy, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"
+msgstr "feilet å sette SO_REUSEADDR på DHCP socket: %s"
+
+#: dhcp.c:101
+#, c-format
+msgid "failed to bind DHCP server socket: %s"
+msgstr "feilet å binde DHCP tjener socket: %s"
+
+#: dhcp.c:127
+#, c-format
+msgid "cannot create ICMP raw socket: %s."
+msgstr "kan ikke lage ICMP raw socket: %s"
+
+#: dhcp.c:252 dhcp6.c:173
+#, fuzzy, c-format
+msgid "unknown interface %s in bridge-interface"
+msgstr "ukjent tilknytning (interface) %s"
+
+#: dhcp.c:293
+#, c-format
+msgid "DHCP packet received on %s which has no address"
+msgstr ""
+
+#: dhcp.c:427
+#, c-format
+msgid "ARP-cache injection failed: %s"
+msgstr ""
+
+#: dhcp.c:470
+#, c-format
+msgid "Error sending DHCP packet to %s: %s"
+msgstr ""
+
+#: dhcp.c:531
+#, c-format
+msgid "DHCP range %s -- %s is not consistent with netmask %s"
+msgstr "DHCP område %s -- %s er ikke konsistent med nettmaske %s"
+
+#: dhcp.c:854
+#, c-format
+msgid "bad line at %s line %d"
+msgstr "dårlig linje ved %s linje %d"
+
+#: dhcp.c:897
+#, c-format
+msgid "ignoring %s line %d, duplicate name or IP address"
+msgstr ""
+
+#: dhcp.c:1041 rfc3315.c:2149
+#, c-format
+msgid "DHCP relay %s -> %s"
+msgstr ""
+
+#: lease.c:98
+msgid "too many stored leases"
+msgstr "for mange lagrede leier"
+
+#: lease.c:166
+#, fuzzy, c-format
+msgid "cannot open or create lease file %s: %s"
+msgstr "kan ikke åpne eller lage leie fil: %s"
+
+#: lease.c:175
+#, c-format
+msgid "failed to parse lease database, invalid line: %s %s %s %s ..."
+msgstr ""
+
+#: lease.c:180
+#, fuzzy, c-format
+msgid "failed to read lease file %s: %s"
+msgstr "feilet å lese %s: %s"
+
+#: lease.c:196
+#, fuzzy, c-format
+msgid "cannot run lease-init script %s: %s"
+msgstr "kan ikke lese %s: %s"
+
+#: lease.c:202
+#, c-format
+msgid "lease-init script returned exit code %s"
+msgstr ""
+
+#: lease.c:373
+#, fuzzy, c-format
+msgid "failed to write %s: %s (retry in %us)"
+msgstr "feilet å lese %s: %s"
+
+#: lease.c:937
+#, c-format
+msgid "Ignoring domain %s for DHCP host name %s"
+msgstr ""
+
+#: rfc2131.c:347
+#, c-format
+msgid "no address range available for DHCP request %s %s"
+msgstr "ingen adresse område tilgjengelig for DHCP krav %s %s"
+
+#: rfc2131.c:348
+msgid "with subnet selector"
+msgstr "med subnet velger"
+
+#: rfc2131.c:348
+msgid "via"
+msgstr "via"
+
+#: rfc2131.c:360
+#, fuzzy, c-format
+msgid "%u available DHCP subnet: %s/%s"
+msgstr "ingen adresse område tilgjengelig for DHCP krav %s %s"
+
+#: rfc2131.c:363 rfc3315.c:306
+#, c-format
+msgid "%u available DHCP range: %s -- %s"
+msgstr ""
+
+#: rfc2131.c:474
+#, fuzzy, c-format
+msgid "%u vendor class: %s"
+msgstr "DBus feil: %s"
+
+#: rfc2131.c:476
+#, fuzzy, c-format
+msgid "%u user class: %s"
+msgstr "DBus feil: %s"
+
+#: rfc2131.c:510
+msgid "disabled"
+msgstr "deaktivert"
+
+#: rfc2131.c:551 rfc2131.c:1006 rfc2131.c:1430 rfc3315.c:616 rfc3315.c:869
+#: rfc3315.c:1148
+msgid "ignored"
+msgstr "oversett"
+
+#: rfc2131.c:566 rfc2131.c:1239 rfc3315.c:919
+msgid "address in use"
+msgstr "adresse i bruk"
+
+#: rfc2131.c:580 rfc2131.c:1060
+msgid "no address available"
+msgstr "ingen adresse tilgjengelig"
+
+#: rfc2131.c:587 rfc2131.c:1202
+msgid "wrong network"
+msgstr "galt nettverk"
+
+#: rfc2131.c:602
+msgid "no address configured"
+msgstr "ingen adresse konfigurert"
+
+#: rfc2131.c:608 rfc2131.c:1252
+msgid "no leases left"
+msgstr "ingen leier igjen"
+
+#: rfc2131.c:703 rfc3315.c:482
+#, c-format
+msgid "%u client provides name: %s"
+msgstr ""
+
+#: rfc2131.c:808
+msgid "PXE BIS not supported"
+msgstr ""
+
+#: rfc2131.c:974 rfc3315.c:1242
+#, fuzzy, c-format
+msgid "disabling DHCP static address %s for %s"
+msgstr "deaktiverer DHCP statisk adresse %s"
+
+#: rfc2131.c:995
+msgid "unknown lease"
+msgstr "ukjent leie"
+
+#: rfc2131.c:1029
+#, c-format
+msgid "not using configured address %s because it is leased to %s"
+msgstr ""
+
+#: rfc2131.c:1039
+#, c-format
+msgid "not using configured address %s because it is in use by the server or relay"
+msgstr ""
+
+#: rfc2131.c:1042
+#, c-format
+msgid "not using configured address %s because it was previously declined"
+msgstr ""
+
+#: rfc2131.c:1058 rfc2131.c:1245
+msgid "no unique-id"
+msgstr ""
+
+#: rfc2131.c:1140
+msgid "wrong server-ID"
+msgstr ""
+
+#: rfc2131.c:1159
+msgid "wrong address"
+msgstr "gal adresse"
+
+#: rfc2131.c:1177 rfc3315.c:1015
+msgid "lease not found"
+msgstr "leie ikke funnet"
+
+#: rfc2131.c:1210
+msgid "address not available"
+msgstr "adresse ikke tilgjengelig"
+
+#: rfc2131.c:1221
+msgid "static lease available"
+msgstr "statisk leie tilgjengelig"
+
+#: rfc2131.c:1225
+msgid "address reserved"
+msgstr "adresse reservert"
+
+#: rfc2131.c:1233
+#, c-format
+msgid "abandoning lease to %s of %s"
+msgstr ""
+
+#: rfc2131.c:1757
+#, c-format
+msgid "%u bootfile name: %s"
+msgstr ""
+
+#: rfc2131.c:1766
+#, fuzzy, c-format
+msgid "%u server name: %s"
+msgstr "DBus feil: %s"
+
+#: rfc2131.c:1774
+#, fuzzy, c-format
+msgid "%u next server: %s"
+msgstr "DBus feil: %s"
+
+#: rfc2131.c:1777
+#, c-format
+msgid "%u broadcast response"
+msgstr ""
+
+#: rfc2131.c:1840
+#, fuzzy, c-format
+msgid "cannot send DHCP/BOOTP option %d: no space left in packet"
+msgstr "kan ikke sende DHCP opsjon %d: ikke mer plass i pakken"
+
+#: rfc2131.c:2131
+msgid "PXE menu too large"
+msgstr ""
+
+#: rfc2131.c:2270 rfc3315.c:1515
+#, fuzzy, c-format
+msgid "%u requested options: %s"
+msgstr "kompilerings opsjoner: %s"
+
+#: rfc2131.c:2587
+#, c-format
+msgid "cannot send RFC3925 option: too many options for enterprise number %d"
+msgstr ""
+
+#: rfc2131.c:2650
+#, c-format
+msgid "%u reply delay: %d"
+msgstr ""
+
+#: netlink.c:77
+#, fuzzy, c-format
+msgid "cannot create netlink socket: %s"
+msgstr "kan ikke binde netlink socket: %s"
+
+#: netlink.c:355
+#, fuzzy, c-format
+msgid "netlink returns error: %s"
+msgstr "DBus feil: %s"
+
+#: dbus.c:186
+msgid "attempt to set an IPv6 server address via DBus - no IPv6 support"
+msgstr "forsøk på å sette en IPv6 tjener adresse via DBus - ingen IPv6 støtte"
+
+#: dbus.c:439
+#, c-format
+msgid "Enabling --%s option from D-Bus"
+msgstr ""
+
+#: dbus.c:444
+#, c-format
+msgid "Disabling --%s option from D-Bus"
+msgstr ""
+
+#: dbus.c:690
+msgid "setting upstream servers from DBus"
+msgstr "setter oppstrøms tjener fra DBus"
+
+#: dbus.c:737
+msgid "could not register a DBus message handler"
+msgstr "kunne ikke registrere en DBus meldingshåndterer"
+
+#: bpf.c:265
+#, c-format
+msgid "cannot create DHCP BPF socket: %s"
+msgstr "kan ikke lage DHCP BPF socket: %s"
+
+#: bpf.c:293
+#, fuzzy, c-format
+msgid "DHCP request for unsupported hardware type (%d) received on %s"
+msgstr "DHCP krav for ikke støttet maskinvare type (%d) mottatt på %s"
+
+#: bpf.c:378
+#, fuzzy, c-format
+msgid "cannot create PF_ROUTE socket: %s"
+msgstr "kan ikke lage DHCP socket: %s"
+
+#: bpf.c:399
+msgid "Unknown protocol version from route socket"
+msgstr ""
+
+#: helper.c:153
+msgid "lease() function missing in Lua script"
+msgstr ""
+
+#: tftp.c:319
+msgid "unable to get free port for TFTP"
+msgstr ""
+
+#: tftp.c:335
+#, c-format
+msgid "unsupported request from %s"
+msgstr ""
+
+#: tftp.c:483
+#, fuzzy, c-format
+msgid "file %s not found"
+msgstr "leie ikke funnet"
+
+#: tftp.c:592
+#, c-format
+msgid "error %d %s received from %s"
+msgstr ""
+
+#: tftp.c:634
+#, fuzzy, c-format
+msgid "failed sending %s to %s"
+msgstr "feilet å lese %s: %s"
+
+#: tftp.c:634
+#, c-format
+msgid "sent %s to %s"
+msgstr ""
+
+#: log.c:190
+#, c-format
+msgid "overflow: %d log entries lost"
+msgstr ""
+
+#: log.c:268
+#, c-format
+msgid "log failed: %s"
+msgstr ""
+
+#: log.c:471
+msgid "FAILED to start up"
+msgstr "FEILET å starte opp"
+
+#: conntrack.c:65
+#, c-format
+msgid "Conntrack connection mark retrieval failed: %s"
+msgstr ""
+
+#: dhcp6.c:52
+#, fuzzy, c-format
+msgid "cannot create DHCPv6 socket: %s"
+msgstr "kan ikke lage DHCP socket: %s"
+
+#: dhcp6.c:73
+#, fuzzy, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"
+msgstr "feilet å sette SO_REUSEADDR på DHCP socket: %s"
+
+#: dhcp6.c:85
+#, fuzzy, c-format
+msgid "failed to bind DHCPv6 server socket: %s"
+msgstr "feilet å binde DHCP tjener socket: %s"
+
+#: rfc3315.c:157
+#, fuzzy, c-format
+msgid "no address range available for DHCPv6 request from relay at %s"
+msgstr "ingen adresse område tilgjengelig for DHCP krav %s %s"
+
+#: rfc3315.c:166
+#, fuzzy, c-format
+msgid "no address range available for DHCPv6 request via %s"
+msgstr "ingen adresse område tilgjengelig for DHCP krav %s %s"
+
+#: rfc3315.c:303
+#, fuzzy, c-format
+msgid "%u available DHCPv6 subnet: %s/%d"
+msgstr "ingen adresse område tilgjengelig for DHCP krav %s %s"
+
+#: rfc3315.c:386
+#, fuzzy, c-format
+msgid "%u vendor class: %u"
+msgstr "DBus feil: %s"
+
+#: rfc3315.c:434
+#, fuzzy, c-format
+msgid "%u client MAC address: %s"
+msgstr "ingen tilknytning (interface) med adresse %s"
+
+#: rfc3315.c:673
+#, fuzzy, c-format
+msgid "unknown prefix-class %d"
+msgstr "ukjent leie"
+
+#: rfc3315.c:816 rfc3315.c:911
+#, fuzzy
+msgid "address unavailable"
+msgstr "adresse ikke tilgjengelig"
+
+#: rfc3315.c:828 rfc3315.c:959 rfc3315.c:1292
+msgid "success"
+msgstr ""
+
+#: rfc3315.c:843 rfc3315.c:852 rfc3315.c:967 rfc3315.c:969
+#, fuzzy
+msgid "no addresses available"
+msgstr "ingen adresse tilgjengelig"
+
+#: rfc3315.c:946
+msgid "not on link"
+msgstr ""
+
+#: rfc3315.c:1019 rfc3315.c:1204 rfc3315.c:1281
+msgid "no binding found"
+msgstr ""
+
+#: rfc3315.c:1057
+msgid "deprecated"
+msgstr ""
+
+#: rfc3315.c:1062
+#, fuzzy
+msgid "address invalid"
+msgstr "adresse i bruk"
+
+#: rfc3315.c:1109
+msgid "confirm failed"
+msgstr ""
+
+#: rfc3315.c:1125
+#, fuzzy
+msgid "all addresses still on link"
+msgstr "dårlig adresse ved %s linje %d"
+
+#: rfc3315.c:1213
+msgid "release received"
+msgstr ""
+
+#: rfc3315.c:2140
+msgid "Cannot multicast to DHCPv6 server without correct interface"
+msgstr ""
+
+#: dhcp-common.c:145
+#, c-format
+msgid "Ignoring duplicate dhcp-option %d"
+msgstr ""
+
+#: dhcp-common.c:222
+#, c-format
+msgid "%u tags: %s"
+msgstr ""
+
+#: dhcp-common.c:407
+#, c-format
+msgid "%s has more than one address in hostsfile, using %s for DHCP"
+msgstr ""
+
+#: dhcp-common.c:430
+#, c-format
+msgid "duplicate IP address %s (%s) in dhcp-config directive"
+msgstr "dubliserte IP adresser i %s (%s) i dhcp-config direktiv"
+
+#: dhcp-common.c:494
+#, fuzzy, c-format
+msgid "failed to set SO_BINDTODEVICE on DHCP socket: %s"
+msgstr "feilet å sette SO_REUSEADDR på DHCP socket: %s"
+
+#: dhcp-common.c:615
+#, c-format
+msgid "Known DHCP options:\n"
+msgstr ""
+
+#: dhcp-common.c:626
+#, c-format
+msgid "Known DHCPv6 options:\n"
+msgstr ""
+
+#: dhcp-common.c:823
+msgid ", prefix deprecated"
+msgstr ""
+
+#: dhcp-common.c:826
+#, c-format
+msgid ", lease time "
+msgstr ""
+
+#: dhcp-common.c:868
+#, c-format
+msgid "%s stateless on %s%.0s%.0s%s"
+msgstr ""
+
+#: dhcp-common.c:870
+#, fuzzy, c-format
+msgid "%s, static leases only on %.0s%s%s%.0s"
+msgstr "DHCP, statisk leie kun på %.0s%s, leie tid %s"
+
+#: dhcp-common.c:872
+#, c-format
+msgid "%s, proxy on subnet %.0s%s%.0s%.0s"
+msgstr ""
+
+#: dhcp-common.c:873
+#, fuzzy, c-format
+msgid "%s, IP range %s -- %s%s%.0s"
+msgstr "DHCP, IP område %s -- %s, leie tid %s"
+
+#: dhcp-common.c:886
+#, c-format
+msgid "DHCPv4-derived IPv6 names on %s%s"
+msgstr ""
+
+#: dhcp-common.c:889
+#, fuzzy, c-format
+msgid "router advertisement on %s%s"
+msgstr "DHCP, statisk leie kun på %.0s%s, leie tid %s"
+
+#: dhcp-common.c:900
+#, c-format
+msgid "DHCP relay from %s to %s via %s"
+msgstr ""
+
+#: dhcp-common.c:902
+#, c-format
+msgid "DHCP relay from %s to %s"
+msgstr ""
+
+#: radv.c:110
+#, fuzzy, c-format
+msgid "cannot create ICMPv6 socket: %s"
+msgstr "kan ikke lage DHCP socket: %s"
+
+#: auth.c:449
+#, c-format
+msgid "ignoring zone transfer request from %s"
+msgstr ""
+
+#: ipset.c:95
+#, fuzzy, c-format
+msgid "failed to find kernel version: %s"
+msgstr "feilet å binde DHCP tjener socket: %s"
+
+#: ipset.c:114
+#, fuzzy, c-format
+msgid "failed to create IPset control socket: %s"
+msgstr "feilet å lage lytte socket: %s"
+
+#: ipset.c:233
+#, fuzzy, c-format
+msgid "failed to update ipset %s: %s"
+msgstr "feilet å lese %s: %s"
+
+#: dnssec.c:527
+msgid "system time considered valid, now checking DNSSEC signature timestamps."
+msgstr ""
+
+#: blockdata.c:58
+#, c-format
+msgid "DNSSEC memory in use %u, max %u, allocated %u"
+msgstr ""
+
+#: tables.c:61
+#, fuzzy, c-format
+msgid "failed to access pf devices: %s"
+msgstr "feilet å få tilgang til %s: %s"
+
+#: tables.c:74
+#, fuzzy, c-format
+msgid "warning: no opened pf devices %s"
+msgstr "benytter lokale adresser kun for %s %s"
+
+#: tables.c:82
+#, fuzzy, c-format
+msgid "error: cannot use table name %s"
+msgstr "klarer ikke å få vertsnavn: %s"
+
+#: tables.c:90
+#, c-format
+msgid "error: cannot strlcpy table name %s"
+msgstr ""
+
+#: tables.c:101
+#, fuzzy, c-format
+msgid "IPset: error:%s"
+msgstr "DBus feil: %s"
+
+#: tables.c:108
+msgid "info: table created"
+msgstr ""
+
+#: tables.c:134
+#, c-format
+msgid "warning: DIOCR%sADDRS: %s"
+msgstr ""
+
+#: tables.c:138
+#, fuzzy, c-format
+msgid "%d addresses %s"
+msgstr "les %s - %d adresser"
+
+#: inotify.c:62
+#, fuzzy, c-format
+msgid "cannot access path %s: %s"
+msgstr "kan ikke lese %s: %s"
+
+#: inotify.c:95
+#, fuzzy, c-format
+msgid "failed to create inotify: %s"
+msgstr "feilet å lese %s: %s"
+
+#: inotify.c:111
+#, c-format
+msgid "too many symlinks following %s"
+msgstr ""
+
+#: inotify.c:127
+#, c-format
+msgid "directory %s for resolv-file is missing, cannot poll"
+msgstr ""
+
+#: inotify.c:131 inotify.c:168
+#, fuzzy, c-format
+msgid "failed to create inotify for %s: %s"
+msgstr "feilet å lage lytte socket: %s"
+
+#: inotify.c:153
+#, fuzzy, c-format
+msgid "bad dynamic directory %s: %s"
+msgstr "kan ikke lese %s: %s"
+
+#: inotify.c:255
+#, c-format
+msgid "inotify, new or changed file %s"
+msgstr ""
+
+#, fuzzy
+#~ msgid "cannot cannonicalise resolv-file %s: %s"
+#~ msgstr "kan ikke åpne eller lage leie fil: %s"
+
+#~ msgid "duplicate IP address %s in dhcp-config directive."
+#~ msgstr "dubliserte IP adresser i %s dhcp-config direktiv."
+
+#, fuzzy
+#~ msgid "Specify path to Lua script (no default)."
+#~ msgstr "Spesifiser stien til PID fil. (standard er %s)."
+
+#~ msgid "TXT record string too long"
+#~ msgstr "TXT post streng for lang"
+
+#~ msgid "failed to set IPV6 options on listening socket: %s"
+#~ msgstr "feilet å sette IPv6 opsjoner på lytte socket: %s"
+
+#~ msgid "failed to bind listening socket for %s: %s"
+#~ msgstr "feilet å binde lytte socket for %s: %s"
+
+#~ msgid "must set exactly one interface on broken systems without IP_RECVIF"
+#~ msgstr "må sette nøyaktig et interface på ødelagte systemer uten IP_RECVIF"
+
+#~ msgid "Ignoring DHCP lease for %s because it has an illegal domain part"
+#~ msgstr "Ignorerer DHCP leie for %s siden den har en ulovlig domene del"
+
+#~ msgid "ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h"
+#~ msgstr "ISC dhcpf integrasjon ikke tilgjengelig: sett HAVE_ISC_READER i src/config.h"
+
+#, fuzzy
+#~ msgid "illegal domain %s in dhcp-config directive."
+#~ msgstr "dubliserte IP adresser i %s dhcp-config direktiv."
+
+#~ msgid "running as root"
+#~ msgstr "kjører som rot (root)"
+
+#, fuzzy
+#~ msgid "read %s - %d hosts"
+#~ msgstr "les %s - %d adresser"
+
+#~ msgid "domains"
+#~ msgstr "domener"
+
+#~ msgid "Ignoring DHCP host name %s because it has an illegal domain part"
+#~ msgstr "Ignorerer DHCP verts navn %s på grunn av ulovlig domene del"
+
+#~ msgid "Display this message."
+#~ msgstr "Vis denne meldingen."
+
+#~ msgid "failed to read %s: %m"
+#~ msgstr "feilet å lese %s: %m"
+
+#~ msgid "failed to read %s:%m"
+#~ msgstr "feilet å lese %s:%m"
+
+#, fuzzy
+#~ msgid "cannot send encapsulated option %d: no space left in wrapper"
+#~ msgstr "kan ikke sende DHCP opsjon %d: ikke mer plass i pakken"
+
+#~ msgid "More than one vendor class matches, using %s"
+#~ msgstr "Mer enn en produsent klasse som passer, bruker %s"
+
+#~ msgid "forwarding table overflow: check for server loops."
+#~ msgstr "fremsendelse (forwarding) tabell overflyt: sjekk etter tjener løkker."
+
+#~ msgid "nested includes not allowed"
+#~ msgstr "nøstede inkluderinger er ikke tillatt"
+
+#~ msgid "DHCP, %s will be written every %s"
+#~ msgstr "DHCP, %s vil bli skrevet hver %s"
+
+#~ msgid "cannot create DHCP packet socket: %s. Is CONFIG_PACKET enabled in your kernel?"
+#~ msgstr "kan ikke lage DHCP pakke socket: %s. Er CONFIG_PACKET aktivert i din kjerne?"
+
+#~ msgid "Cannot use RTnetlink socket, falling back to ioctl API"
+#~ msgstr "Kan ikke benytte RTnetlink socket, faller tilbake til ioctl API"
diff --git a/po/pl.po b/po/pl.po
new file mode 100755
index 0000000..0bf4173
--- /dev/null
+++ b/po/pl.po
@@ -0,0 +1,2283 @@
+# translation of pl.po to polski
+# Polish translations for dnsmasq package.
+# This file is put in the public domain.
+#
+# Tomasz Sochański <nerdhero@gmail.com>, 2005.
+# Jan Psota <jasiupsota@gmail.com>, 2008-2015.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: pl\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-06-10 20:57+0100\n"
+"PO-Revision-Date: 2017-07-17 18:30+0100\n"
+"Last-Translator: Jan Psota <jasiupsota@gmail.com>\n"
+"Language-Team: polski <>\n"
+"Language: pl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n!=1);\n"
+"X-Generator: Poedit 1.8.7\n"
+"X-Language: pl_PL\n"
+
+#: cache.c:513
+msgid "Internal error in cache."
+msgstr "Wewnętrzny błąd w pamięci podręcznej."
+
+#: cache.c:923
+#, c-format
+msgid "failed to load names from %s: %s"
+msgstr "nie potrafię wczytać nazw z %s: %s"
+
+#: cache.c:949 dhcp.c:867
+#, c-format
+msgid "bad address at %s line %d"
+msgstr "błędny adres w pliku %s, w linii %d"
+
+#: cache.c:1002 dhcp.c:883
+#, c-format
+msgid "bad name at %s line %d"
+msgstr "błędna nazwa w pliku %s, w linii %d"
+
+#: cache.c:1011 dhcp.c:958
+#, c-format
+msgid "read %s - %d addresses"
+msgstr "wczytałem %s - %d adresów"
+
+#: cache.c:1124
+msgid "cleared cache"
+msgstr "wyczyszczono pamięć podręczną"
+
+#: cache.c:1153
+#, c-format
+msgid "No IPv4 address found for %s"
+msgstr "Nie znalazłem adresu IPv4 komputera %s"
+
+#: cache.c:1232
+#, c-format
+msgid "%s is a CNAME, not giving it to the DHCP lease of %s"
+msgstr "%s to nazwa CNAME, nie przypisuję jej dzierżawie DHCP %s"
+
+#: cache.c:1256
+#, c-format
+msgid "not giving name %s to the DHCP lease of %s because the name exists in %s with address %s"
+msgstr "nazwa %s nie została nadana dzierżawie DHCP %s, ponieważ nazwa istnieje w %s i ma już adres %s"
+
+#: cache.c:1413
+#, c-format
+msgid "time %lu"
+msgstr "czas %lu"
+
+#: cache.c:1414
+#, c-format
+msgid "cache size %d, %d/%d cache insertions re-used unexpired cache entries."
+msgstr "wielkość pamięci podręcznej: %d; %d z %d miejsc aktualnych wpisów użyto ponownie."
+
+#: cache.c:1416
+#, c-format
+msgid "queries forwarded %u, queries answered locally %u"
+msgstr "%u zapytań przesłanych dalej, %u odpowiedzi udzielonych samodzielnie"
+
+#: cache.c:1419
+#, c-format
+msgid "queries for authoritative zones %u"
+msgstr "zapytań do stref autorytatywnych %u"
+
+#: cache.c:1445
+#, c-format
+msgid "server %s#%d: queries sent %u, retried or failed %u"
+msgstr "serwer %s#%d: %u zapytań wysłanych, %u ponowionych lub nieudanych"
+
+#: util.c:47
+#, c-format
+msgid "failed to seed the random number generator: %s"
+msgstr "brak możliwości użycia generatora liczb losowych: %s"
+
+#: util.c:224
+msgid "failed to allocate memory"
+msgstr "nie udało się przydzielić pamięci"
+
+#: util.c:277 option.c:619
+msgid "could not get memory"
+msgstr "nie można dostać pamięci"
+
+#: util.c:287
+#, c-format
+msgid "cannot create pipe: %s"
+msgstr "błąd podczas próby utworzenia potoku: %s"
+
+#: util.c:295
+#, c-format
+msgid "failed to allocate %d bytes"
+msgstr "niemożliwość przydzielenia %d bajtów pamięci"
+
+#: util.c:464
+#, c-format
+msgid "infinite"
+msgstr "nieskończona"
+
+#: option.c:344
+msgid "Specify local address(es) to listen on."
+msgstr "Wskazanie adresów, na których należy nasłuchiwać."
+
+#: option.c:345
+msgid "Return ipaddr for all hosts in specified domains."
+msgstr "Zwracanie adresu IP dla wszystkich hostów we wskazanych domenach."
+
+#: option.c:346
+msgid "Fake reverse lookups for RFC1918 private address ranges."
+msgstr "Wyłączenie przekazywania zapytań odwrotnych dla prywatnych zakresów IP."
+
+#: option.c:347
+msgid "Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."
+msgstr "Traktowanie adresu IP jako NXDOMAIN (unieważnia ,,Verisign wildcard'')."
+
+#: option.c:348
+#, c-format
+msgid "Specify the size of the cache in entries (defaults to %s)."
+msgstr "Wskazanie wielkości pamięci podręcznej (domyślnie: %s miejsc)."
+
+#: option.c:349
+#, c-format
+msgid "Specify configuration file (defaults to %s)."
+msgstr "Wskazanie pliku konfiguracyjnego (domyślnie: %s)."
+
+#: option.c:350
+msgid "Do NOT fork into the background: run in debug mode."
+msgstr "NIE twórz procesu potomnego w tle: działanie w trybie debugowania."
+
+#: option.c:351
+msgid "Do NOT forward queries with no domain part."
+msgstr "Wyłączenie przekazywania zapytań bez podanej części domenowej."
+
+#: option.c:352
+msgid "Return self-pointing MX records for local hosts."
+msgstr "Zwracanie samowskazującego rekordu MX dla lokalnych hostów."
+
+#: option.c:353
+msgid "Expand simple names in /etc/hosts with domain-suffix."
+msgstr "Rozwijanie prostych nazw z /etc/hosts przyrostkiem domenowym."
+
+#: option.c:354
+msgid "Don't forward spurious DNS requests from Windows hosts."
+msgstr "Wyłączenie przekazywania pozornych zapytań DNS z komputerów działających pod Windows."
+
+#: option.c:355
+msgid "Enable DHCP in the range given with lease duration."
+msgstr "Włączenie serwera DHCP dla wskazanego zakresu adresów."
+
+#: option.c:356
+#, c-format
+msgid "Change to this group after startup (defaults to %s)."
+msgstr "Po uruchomieniu zmiana grupy procesu na podaną (domyślnie: %s)."
+
+#: option.c:357
+msgid "Set address or hostname for a specified machine."
+msgstr "Ustawienie adresu lub nazwy dla wskazanego komputera."
+
+#: option.c:358
+msgid "Read DHCP host specs from file."
+msgstr "Wskazanie pliku z wartościami 'dhcp-host='."
+
+#: option.c:359
+msgid "Read DHCP option specs from file."
+msgstr "Wskazanie pliku z wartościami 'dhcp-option='."
+
+#: option.c:360
+msgid "Read DHCP host specs from a directory."
+msgstr "Odczyt specyfikacji hostów dla DHCP z katalogu."
+
+#: option.c:361
+msgid "Read DHCP options from a directory."
+msgstr "Odczyt opcji DHCP z katalogu."
+
+#: option.c:362
+msgid "Evaluate conditional tag expression."
+msgstr "Warunkowe ustawianie znaczników."
+
+#: option.c:363
+#, c-format
+msgid "Do NOT load %s file."
+msgstr "NIE wczytywanie pliku %s."
+
+#: option.c:364
+#, c-format
+msgid "Specify a hosts file to be read in addition to %s."
+msgstr "Wskazanie dodatkowego pliku 'hosts' oprócz %s."
+
+#: option.c:365
+msgid "Read hosts files from a directory."
+msgstr "Odczyt pliku hostów z katalogu."
+
+#: option.c:366
+msgid "Specify interface(s) to listen on."
+msgstr "Interfejsy, na których nasłuchiwać."
+
+#: option.c:367
+msgid "Specify interface(s) NOT to listen on."
+msgstr "Interfejsy, na których NIE nasłuchiwać."
+
+#: option.c:368
+msgid "Map DHCP user class to tag."
+msgstr "Przyporządkowanie znacznika w zależności od klasy użytkownika DHCP."
+
+#: option.c:369
+msgid "Map RFC3046 circuit-id to tag."
+msgstr "Przyporządkowanie znacznika w zależności od numeru obwodu (w rozumieniu RFC3046)."
+
+#: option.c:370
+msgid "Map RFC3046 remote-id to tag."
+msgstr "Przyporządkowanie znacznika w zależności od numeru agenta (w rozumieniu RFC3046)."
+
+#: option.c:371
+msgid "Map RFC3993 subscriber-id to tag."
+msgstr "Przyporządkowanie znacznika w zależności od numeru subskrybenta (w rozumieniu RFC3993)."
+
+#: option.c:372
+msgid "Don't do DHCP for hosts with tag set."
+msgstr "Wyłączenie DHCP dla hostów z określonym znacznikiem."
+
+#: option.c:373
+msgid "Force broadcast replies for hosts with tag set."
+msgstr "Wymuszenie odpowiedzi w trybie rozgłoszeniowym dla hostów z określonym znacznikiem."
+
+#: option.c:374
+msgid "Do NOT fork into the background, do NOT run in debug mode."
+msgstr "NIE twórz procesu potomnego w tle i NIE włączaj trybu debugowania."
+
+#: option.c:375
+msgid "Assume we are the only DHCP server on the local network."
+msgstr "Zakładanie, że jesteśmy jedynym serwerem DHCP w sieci lokalnej."
+
+#: option.c:376
+#, c-format
+msgid "Specify where to store DHCP leases (defaults to %s)."
+msgstr "Ścieżka przechowywania pliku dzierżaw DHCP (domyślnie: %s)."
+
+#: option.c:377
+msgid "Return MX records for local hosts."
+msgstr "Włączenie zwracania rekordu MX dla hostów lokalnych."
+
+#: option.c:378
+msgid "Specify an MX record."
+msgstr "Specyfikacja rekordu MX."
+
+#: option.c:379
+msgid "Specify BOOTP options to DHCP server."
+msgstr "Określenie opcji BOOTP serwera DHCP."
+
+#: option.c:380
+#, c-format
+msgid "Do NOT poll %s file, reload only on SIGHUP."
+msgstr "Wyłączenie obserwowania pliku %s; ponowne odczytywanie tylko po odebraniu sygnału SIGHUP."
+
+#: option.c:381
+msgid "Do NOT cache failed search results."
+msgstr "Wyłączenie przechowywania w pamięci podręcznej wyników nieudanych wyszukiwań."
+
+#: option.c:382
+#, c-format
+msgid "Use nameservers strictly in the order given in %s."
+msgstr "Odpytywanie serwerów nazw w kolejności ich wystąpienia w %s."
+
+#: option.c:383
+msgid "Specify options to be sent to DHCP clients."
+msgstr "Specyfikacja opcji wysyłanej do klientów DHCP."
+
+#: option.c:384
+msgid "DHCP option sent even if the client does not request it."
+msgstr "Opcja DHCP wysyłana nawet jeżeli klient o nią nie prosi."
+
+#: option.c:385
+msgid "Specify port to listen for DNS requests on (defaults to 53)."
+msgstr "Wskazanie portu do nasłuchiwania zapytań DNS (domyślnie: 53)."
+
+#: option.c:386
+#, c-format
+msgid "Maximum supported UDP packet size for EDNS.0 (defaults to %s)."
+msgstr "Maksymalna obsługiwana wielkość pakietu EDNS.0 (domyślnie: %s)."
+
+#: option.c:387
+msgid "Log DNS queries."
+msgstr "Włączenie spisywania zapytań DNS do logu."
+
+#: option.c:388
+msgid "Force the originating port for upstream DNS queries."
+msgstr "Wymuszenie użycia wskazanego portu UDP do odpytywania nadrzędnych serwerów DNS i odbierania od nich odpowiedzi."
+
+#: option.c:389
+msgid "Do NOT read resolv.conf."
+msgstr "Wyłączenie czytania pliku resolv.conf."
+
+#: option.c:390
+#, c-format
+msgid "Specify path to resolv.conf (defaults to %s)."
+msgstr "Wskazanie położenia pliku resolv.conf (domyślnie: %s)."
+
+#: option.c:391
+msgid "Specify path to file with server= options"
+msgstr "Wskazanie położenia pliku z opcjami server="
+
+#: option.c:392
+msgid "Specify address(es) of upstream servers with optional domains."
+msgstr "Wskazywanie adresów serwerów nazw, opcjonalnie z przypisaniem do domeny."
+
+#: option.c:393
+msgid "Specify address of upstream servers for reverse address queries"
+msgstr "Wskazanie serwerów nazw do odwrotnej translacji adresów."
+
+#: option.c:394
+msgid "Never forward queries to specified domains."
+msgstr "Wyłączenie przekazywania zapytań do wskazanych domen."
+
+#: option.c:395
+msgid "Specify the domain to be assigned in DHCP leases."
+msgstr "Wskazanie domeny dla serwera DHCP."
+
+#: option.c:396
+msgid "Specify default target in an MX record."
+msgstr "Określenie domyślnego celu w rekordzie MX."
+
+#: option.c:397
+msgid "Specify time-to-live in seconds for replies from /etc/hosts."
+msgstr "Określenie (w sekundach) czasu ważności odpowiedzi udzielonych na podstawie /etc/hosts (domyślnie 0)."
+
+#: option.c:398
+msgid "Specify time-to-live in seconds for negative caching."
+msgstr "Określenie (w sekundach) czasu ważności negatywnych odpowiedzi."
+
+#: option.c:399
+msgid "Specify time-to-live in seconds for maximum TTL to send to clients."
+msgstr "Ograniczenie maksymalnego czasu ważności odpowiedzi (TTL) podawanego klientom [w sekundach]."
+
+#: option.c:400
+msgid "Specify time-to-live ceiling for cache."
+msgstr "Określenie górnej granicy czasu ważności dla wpisów w pamięci podręcznej."
+
+#: option.c:401
+msgid "Specify time-to-live floor for cache."
+msgstr "Określenie dolnej granicy czasu ważności dla wpisów w pamięci podręcznej."
+
+#: option.c:402
+#, c-format
+msgid "Change to this user after startup. (defaults to %s)."
+msgstr "Zmiana użytkownika procesu na wskazanego (po uruchomieniu, domyślnie: %s)."
+
+#: option.c:403
+msgid "Map DHCP vendor class to tag."
+msgstr "Przyporządkowanie znacznika w zależności od typu klienta DHCP."
+
+#: option.c:404
+msgid "Display dnsmasq version and copyright information."
+msgstr "Wydrukowanie informacji o programie i ochronie praw autorskich."
+
+#: option.c:405
+msgid "Translate IPv4 addresses from upstream servers."
+msgstr "Tłumaczenie adresów IPv4 z serwerów nadrzędnych."
+
+#: option.c:406
+msgid "Specify a SRV record."
+msgstr "Określenie rekordu SRV."
+
+#: option.c:407
+msgid "Display this message. Use --help dhcp or --help dhcp6 for known DHCP options."
+msgstr "Wyświetla ten komunikat. Chcąc przejrzeć listę dostępnych opcji DHCP użyj '--help dhcp' lub '--help dhcp6' ."
+
+#: option.c:408
+#, c-format
+msgid "Specify path of PID file (defaults to %s)."
+msgstr "Określenie ścieżki do pliku PID (domyślnie: %s)."
+
+#: option.c:409
+#, c-format
+msgid "Specify maximum number of DHCP leases (defaults to %s)."
+msgstr "Maksymalna liczba dzierżaw DHCP (domyślnie: %s)."
+
+#: option.c:410
+msgid "Answer DNS queries based on the interface a query was sent to."
+msgstr "Uzależnienie odpowiedzi DNS od interfejsu, na którym odebrano zapytanie (wygodne dla serwerów kilku podsieci z różnymi adresami w /etc/hosts)."
+
+#: option.c:411
+msgid "Specify TXT DNS record."
+msgstr "Specyfikacja rekordu DNS TXT."
+
+#: option.c:412
+msgid "Specify PTR DNS record."
+msgstr "Specyfikacja rekordu DNS PTR."
+
+#: option.c:413
+msgid "Give DNS name to IPv4 address of interface."
+msgstr "Zwraca nazwę domenową powiązaną z adresem interfejsu sieciowego."
+
+#: option.c:414
+msgid "Bind only to interfaces in use."
+msgstr "Nasłuchiwanie tylko na wykorzystywanych interfejsach (umożliwia uruchomienie osobnych serwerów dla różnych kart)."
+
+#: option.c:415
+#, c-format
+msgid "Read DHCP static host information from %s."
+msgstr "Wczytanie przyporządkowań adresów z %s."
+
+#: option.c:416
+msgid "Enable the DBus interface for setting upstream servers, etc."
+msgstr "Włączenie używania interfejsu DBus do informowania o zmianach konfiguracji."
+
+#: option.c:417
+msgid "Do not provide DHCP on this interface, only provide DNS."
+msgstr "Uruchomienie na wskazanym interfejsie tylko DNS-a, bez usług DHCP i TFTP."
+
+#: option.c:418
+msgid "Enable dynamic address allocation for bootp."
+msgstr "Włączenie dynamicznego przydzielania adresów dla klientów BOOTP."
+
+#: option.c:419
+msgid "Map MAC address (with wildcards) to option set."
+msgstr "Przyporządkowanie znacznika w zależności od adresu MAC (można używać uogólnień: *)."
+
+#: option.c:420
+msgid "Treat DHCP requests on aliases as arriving from interface."
+msgstr "Traktowanie żądań DHCP odebranych na interfejsach alias, ..., jako odebranych na iface."
+
+#: option.c:421
+msgid "Disable ICMP echo address checking in the DHCP server."
+msgstr "Pominięcie sprawdzania za pomocą ICMP niezajętości adresu przed jego wydzierżawieniem."
+
+#: option.c:422
+msgid "Shell script to run on DHCP lease creation and destruction."
+msgstr "Skrypt powłoki uruchamiany po przyznaniu lub zwolnieniu adresu."
+
+#: option.c:423
+msgid "Lua script to run on DHCP lease creation and destruction."
+msgstr "Skrypt Lua uruchamiany po przyznaniu lub zwolnieniu adresu."
+
+#: option.c:424
+msgid "Run lease-change scripts as this user."
+msgstr "Wskazanie użytkownika z którego uprawnieniami będą uruchamiane skrypty."
+
+#: option.c:425
+msgid "Call dhcp-script with changes to local ARP table."
+msgstr "Wywoływanie dhcp-script w reakcji na zmiany w tablicy ARP."
+
+#: option.c:426
+msgid "Read configuration from all the files in this directory."
+msgstr "Wczytanie wszystkich plików ze wskazanego katalogu jako konfiguracyjnych."
+
+#: option.c:427
+msgid "Log to this syslog facility or file. (defaults to DAEMON)"
+msgstr "Wskazanie kanału syslog-a do którego mają trafiać komunikaty (domyślnie: DAEMON)"
+
+#: option.c:428
+msgid "Do not use leasefile."
+msgstr "Nieużywanie bazy dzierżaw."
+
+#: option.c:429
+#, c-format
+msgid "Maximum number of concurrent DNS queries. (defaults to %s)"
+msgstr "Maksymalna liczba jednocześnie obsługiwanych zapytań DNS (domyślnie: %s)"
+
+#: option.c:430
+#, c-format
+msgid "Clear DNS cache when reloading %s."
+msgstr "Czyszczenie pamięci podręcznej serwera nazw w przypadku ponownego odczytu %s."
+
+#: option.c:431
+msgid "Ignore hostnames provided by DHCP clients."
+msgstr "Nie zwracanie uwagi na nazwę podawaną przez klienta w przypadku dopasowania wszystkich wymienionych znaczników."
+
+#: option.c:432
+msgid "Do NOT reuse filename and server fields for extra DHCP options."
+msgstr "Wyłączenie oszczędzania miejsca w pakiecie DHCP przez przesuwanie pól servername i filename do opcji DHCP. Wymusza prostszy tryb budowy pakietu rozwiązując problemy z nieprzystosowanymi klientami DHCP."
+
+#: option.c:433
+msgid "Enable integrated read-only TFTP server."
+msgstr "Włączenie wbudowanego serwera TFTP (tylko do wysyłania)."
+
+#: option.c:434
+msgid "Export files by TFTP only from the specified subtree."
+msgstr "Ograniczenie działania serwera TFTP do wskazanego katalogu i podkatalogów. Nazwy z .. są odrzucane, / odnosi się do wskazanego katalogu."
+
+#: option.c:435
+#, fuzzy
+msgid "Add client IP or hardware address to tftp-root."
+msgstr "Doklejanie adresu IP klienta do głównego katalogu TFTP. Jeżeli wynikowy katalog nie istnieje, nadal wykorzystuje się tftp-root."
+
+#: option.c:436
+msgid "Allow access only to files owned by the user running dnsmasq."
+msgstr "Ograniczenie dostępu do plików przez TFTP do tych, których właścicielem jest użytkownik uruchamiający dnsmasq-a."
+
+#: option.c:437
+msgid "Do not terminate the service if TFTP directories are inaccessible."
+msgstr "Nieprzerywanie działania serwisu mimo braku dostępu do katalogów TFTP."
+
+#: option.c:438
+#, fuzzy, c-format
+msgid "Maximum number of concurrent TFTP transfers (defaults to %s)."
+msgstr "Maksymalna liczba jednocześnie obsługiwanych połączeń TFTP (domyślnie %s)."
+
+#: option.c:439
+msgid "Maximum MTU to use for TFTP transfers."
+msgstr "Ograniczenie MTU w komunikacji TFTP."
+
+#: option.c:440
+msgid "Disable the TFTP blocksize extension."
+msgstr "Wyłączenie możliwości negocjowania wielkości bloku dla przesyłów przez TFTP."
+
+#: option.c:441
+msgid "Convert TFTP filenames to lowercase"
+msgstr "Konwertowanie nazw plików żądanych przez TFTP do małych liter"
+
+#: option.c:442
+msgid "Ephemeral port range for use by TFTP transfers."
+msgstr "Wskazanie zakresu portów do użytku TFTP."
+
+#: option.c:443
+msgid "Extra logging for DHCP."
+msgstr "Włączenie spisywania w logu operacji DHCP."
+
+#: option.c:444
+msgid "Enable async. logging; optionally set queue length."
+msgstr "Włączenie asynchronicznego zapisywania do logu z ewentualnym wskazaniem długości kolejki."
+
+#: option.c:445
+msgid "Stop DNS rebinding. Filter private IP ranges when resolving."
+msgstr "Odfiltrowywanie adresów wskazujących na komputery w sieciach wewnętrznych spośród odpowiedzi od zewnętrznych serwerów DNS."
+
+#: option.c:446
+msgid "Allow rebinding of 127.0.0.0/8, for RBL servers."
+msgstr "Zezwolenie na przekazywanie odpowiedzi w klasie 127.0.0.0/8. Dla serwerów RBL."
+
+#: option.c:447
+msgid "Inhibit DNS-rebind protection on this domain."
+msgstr "Dezaktywacja zabezpieczenia przed atakami DNS-rebind dla wskazanych domen."
+
+#: option.c:448
+msgid "Always perform DNS queries to all servers."
+msgstr "Jednoczesne odpytywanie wszystkich serwerów nadrzędnych; klientowi przekazywana jest pierwsza odpowiedź."
+
+#: option.c:449
+msgid "Set tag if client includes matching option in request."
+msgstr "Ustawienie znacznika jeżeli w żądaniu DHCP pojawi się wskazana opcja, ewentualnie o konkretnej wartości."
+
+#: option.c:450
+msgid "Use alternative ports for DHCP."
+msgstr "Użycie alternatywnych portów dla usługi DHCP."
+
+#: option.c:451
+msgid "Specify NAPTR DNS record."
+msgstr "Specyfikacja rekordu DNS NAPTR."
+
+#: option.c:452
+msgid "Specify lowest port available for DNS query transmission."
+msgstr "Ustawienie dolnej granicy numerów portów do przesyłania zapytań DNS."
+
+#: option.c:453
+msgid "Specify highest port available for DNS query transmission."
+msgstr "Ograniczenie najwyższego numeru portu dla transmisji zapytań DNS."
+
+#: option.c:454
+msgid "Use only fully qualified domain names for DHCP clients."
+msgstr "Przechowywanie w serwerze DNS dnsmasq-a tylko w pełni kwalifikowanych nazw zgłaszanych przez klientów DHCP."
+
+#: option.c:455
+msgid "Generate hostnames based on MAC address for nameless clients."
+msgstr "Generowanie nazw na podstawie MAC-adresów dla klientów bez nazwy."
+
+#: option.c:456
+msgid "Use these DHCP relays as full proxies."
+msgstr "Traktowanie wskazanych serwerów pośredniczących DHCP jako działających w trybie \"pełnomocnika\" (full-proxy)."
+
+#: option.c:457
+msgid "Relay DHCP requests to a remote server"
+msgstr "Przekazywanie żądań DHCP do zdalnego serwera"
+
+#: option.c:458
+msgid "Specify alias name for LOCAL DNS name."
+msgstr "Wskazanie synonimu nazwy komputera lokalnego - znanego z /etc/hosts albo z DHCP."
+
+#: option.c:459
+msgid "Prompt to send to PXE clients."
+msgstr "Zgłoszenie wysyłane klientom PXE."
+
+#: option.c:460
+msgid "Boot service for PXE menu."
+msgstr "Składnik menu PXE (--> man)."
+
+#: option.c:461
+msgid "Check configuration syntax."
+msgstr "Sprawdzenie składni."
+
+#: option.c:462
+msgid "Add requestor's MAC address to forwarded DNS queries."
+msgstr "Przekazywanie MAC-adresu komputera pytającego w ruchu wychodzącym DNS."
+
+#: option.c:463
+msgid "Add specified IP subnet to forwarded DNS queries."
+msgstr "Zamieszczanie wskazanego adresu podsieci w przekazywanych zapytaniach DNS."
+
+#: option.c:464
+msgid "Add client identification to forwarded DNS queries."
+msgstr "Zamieszczanie identyfikacji pytającego w przekazywanych zapytaniach DNS."
+
+#: option.c:465
+msgid "Proxy DNSSEC validation results from upstream nameservers."
+msgstr "Przekazywanie wyników weryfikacji DNSSEC z serwerów nadrzędnych."
+
+#: option.c:466
+msgid "Attempt to allocate sequential IP addresses to DHCP clients."
+msgstr "Zmiana sposobu przydzielania adresów IP na sekwencyjny."
+
+#: option.c:467
+msgid "Copy connection-track mark from queries to upstream connections."
+msgstr "Zachowanie znacznika połączenia z odebranego zapytania DNS w ruchu zewnętrznym."
+
+#: option.c:468
+msgid "Allow DHCP clients to do their own DDNS updates."
+msgstr "Zezwolenie klientom DHCP na uaktualnianie DDNS-ów."
+
+#: option.c:469
+msgid "Send router-advertisements for interfaces doing DHCPv6"
+msgstr "Załączenie anonsowania (RA) na interfejsach serwujących DHCPv6"
+
+#: option.c:470
+msgid "Specify DUID_EN-type DHCPv6 server DUID"
+msgstr "Określenie DHCPv6 DUID"
+
+#: option.c:471
+msgid "Specify host (A/AAAA and PTR) records"
+msgstr "Określenie rekordów A/AAAA i PTR"
+
+#: option.c:472
+msgid "Specify arbitrary DNS resource record"
+msgstr "Określenie rekordu TXT"
+
+#: option.c:473
+msgid "Bind to interfaces in use - check for new interfaces"
+msgstr "Dynamiczne podpinanie do interfejsów sieciowych"
+
+#: option.c:474
+msgid "Export local names to global DNS"
+msgstr "Eksportowanie lokalnych nazw hostów do globalnego DNS-a"
+
+#: option.c:475
+msgid "Domain to export to global DNS"
+msgstr "Domena pod którą będą eksportowane lokalne nazwy"
+
+#: option.c:476
+msgid "Set TTL for authoritative replies"
+msgstr "Określenie TTL dla odpowiedzi autorytatywnych"
+
+#: option.c:477
+#, fuzzy
+msgid "Set authoritative zone information"
+msgstr "Określenie danych strefy autorytatywnej (SOA)"
+
+#: option.c:478
+msgid "Secondary authoritative nameservers for forward domains"
+msgstr "Pomocnicze serwery autorytatywne dla forwardowanych domen"
+
+#: option.c:479
+msgid "Peers which are allowed to do zone transfer"
+msgstr "Wskazanie serwerów uprawnionych do transferu stref"
+
+#: option.c:480
+msgid "Specify ipsets to which matching domains should be added"
+msgstr "Wyszczególnienie ipset-ów, do których będą dopisywane adresy IP leżące we wskazanych domenach"
+
+#: option.c:481
+msgid "Specify a domain and address range for synthesised names"
+msgstr "Wskazanie domeny i zakresu adresów dla generowanych nazw"
+
+#: option.c:482
+msgid "Activate DNSSEC validation"
+msgstr "Uaktywnienie walidacji DNSSEC"
+
+#: option.c:483
+msgid "Specify trust anchor key digest."
+msgstr "Wskazanie punktu zaufania dla uwierzytelniania DNSSEC."
+
+#: option.c:484
+msgid "Disable upstream checking for DNSSEC debugging."
+msgstr "Akceptowanie nieuwiarygodnionych odpowiedzi DNSSEC (ustawienie bitu CD w zapytaniach)."
+
+#: option.c:485
+msgid "Ensure answers without DNSSEC are in unsigned zones."
+msgstr "Upewnianie się, że odpowiedzi bez DNSSEC pochodzą ze stref niepodpisanych."
+
+#: option.c:486
+msgid "Don't check DNSSEC signature timestamps until first cache-reload"
+msgstr "Wyłączenie sprawdzania sygnatur czasowych DNSSEC do pierwszego przeładowania pamięci podręcznej."
+
+#: option.c:487
+msgid "Timestamp file to verify system clock for DNSSEC"
+msgstr "Plik znacznika czasu do weryfikacji zegara systemowego dla potrzeb DNSSEC."
+
+#: option.c:489
+msgid "Specify DHCPv6 prefix class"
+msgstr "Określenie prefiksu klasy DHCPv6"
+
+#: option.c:491
+#, fuzzy
+msgid "Set MTU, priority, resend-interval and router-lifetime"
+msgstr "Ustawianie priorytetu, okresu rozsyłania oraz czasu życia rutera (RA)."
+
+#: option.c:492
+msgid "Do not log routine DHCP."
+msgstr "Wyłączenie logowania zwyczajnego DHCP."
+
+#: option.c:493
+msgid "Do not log routine DHCPv6."
+msgstr "Wyłączenie logowania zwyczajnego DHCPv6."
+
+#: option.c:494
+msgid "Do not log RA."
+msgstr "Wyłączenie logowania RA."
+
+#: option.c:495
+msgid "Accept queries only from directly-connected networks."
+msgstr "Akceptowanie zapytań wyłącznie z sieci podpiętych bezpośrednio."
+
+#: option.c:496
+msgid "Detect and remove DNS forwarding loops."
+msgstr "Wykrywanie i usuwanie pętli zapytań DNS."
+
+#: option.c:497
+msgid "Ignore DNS responses containing ipaddr."
+msgstr "Ignorowanie odpowiedzi DNS zawierających ipaddr."
+
+#: option.c:498
+msgid "Set TTL in DNS responses with DHCP-derived addresses."
+msgstr "Ustawienie TTL w odpowiedziach DNS dla adresów przydzielonych przez DHCP."
+
+#: option.c:499
+msgid "Delay DHCP replies for at least number of seconds."
+msgstr ""
+
+#: option.c:703
+#, c-format
+msgid ""
+"Usage: dnsmasq [options]\n"
+"\n"
+msgstr ""
+"Użycie: dnsmasq [opcje]\n"
+"\n"
+
+#: option.c:705
+#, c-format
+msgid "Use short options only on the command line.\n"
+msgstr "W tym systemie w linii poleceń można używać wyłącznie jednoliterowych opcji.\n"
+
+#: option.c:707
+#, c-format
+msgid "Valid options are:\n"
+msgstr "Dostępne opcje:\n"
+
+#: option.c:754 option.c:868
+msgid "bad address"
+msgstr "zły adres"
+
+#: option.c:779 option.c:783
+msgid "bad port"
+msgstr "nieprawidłowy numer portu"
+
+#: option.c:797 option.c:826 option.c:861
+msgid "interface binding not supported"
+msgstr "nie ma możliwości dowiązywania do interfejsu"
+
+#: option.c:821 option.c:856
+msgid "interface can only be specified once"
+msgstr ""
+
+#: option.c:835 option.c:3800
+msgid "bad interface name"
+msgstr "nieprawidłowa nazwa interfejsu"
+
+#: option.c:1062
+msgid "unsupported encapsulation for IPv6 option"
+msgstr "nieobsługiwany rodzaj enkapsulacji opcji IPv6"
+
+#: option.c:1076
+msgid "bad dhcp-option"
+msgstr "błąd w dhcp-option"
+
+#: option.c:1144
+msgid "bad IP address"
+msgstr "zły adres IP"
+
+#: option.c:1147 option.c:1286 option.c:3070
+msgid "bad IPv6 address"
+msgstr "zły adres IPv6"
+
+#: option.c:1240
+msgid "bad IPv4 address"
+msgstr "nieprawidłowy adres IPv4"
+
+#: option.c:1313 option.c:1407
+msgid "bad domain in dhcp-option"
+msgstr "nieprawidłowa nazwa domeny w dhcp-option"
+
+#: option.c:1445
+msgid "dhcp-option too long"
+msgstr "zbyt długa dhcp-option (>255 znaków)"
+
+#: option.c:1452
+msgid "illegal dhcp-match"
+msgstr "niedopuszczalne dhcp-match"
+
+#: option.c:1514
+msgid "illegal repeated flag"
+msgstr "wielokrotne użycie opcji niedozwolone (pojawiła się wcześniej w linii poleceń)"
+
+#: option.c:1522
+msgid "illegal repeated keyword"
+msgstr "wielokrotne użycie opcji niedozwolone (pojawiła się wsześniej w pliku konfiguracyjnym)"
+
+#: option.c:1593 option.c:4434
+#, c-format
+msgid "cannot access directory %s: %s"
+msgstr "brak dostępu do katalogu %s: %s"
+
+#: option.c:1639 tftp.c:537
+#, c-format
+msgid "cannot access %s: %s"
+msgstr "brak dostępu do %s: %s"
+
+#: option.c:1727
+msgid "setting log facility is not possible under Android"
+msgstr "zmiana log-facility w systemie Android nie jest możliwa"
+
+#: option.c:1736
+msgid "bad log facility"
+msgstr "nierozpoznany znacznik logów"
+
+#: option.c:1789
+msgid "bad MX preference"
+msgstr "nieprawidłowa wartość preferencji MX"
+
+#: option.c:1794
+msgid "bad MX name"
+msgstr "nieprawidłowa nazwa MX"
+
+#: option.c:1808
+msgid "bad MX target"
+msgstr "nieprawidłowa wartość celu MX"
+
+#: option.c:1820
+msgid "cannot run scripts under uClinux"
+msgstr "w uClinuksie nie ma możliwości uruchamiania skryptów"
+
+#: option.c:1822
+msgid "recompile with HAVE_SCRIPT defined to enable lease-change scripts"
+msgstr "żeby mieć możliwość używania skryptów wywoływanych przy zmianie dzierżawy, przekompiluj dnsmasq-a z włączoną flagą HAVE_SCRIPT"
+
+#: option.c:1826
+msgid "recompile with HAVE_LUASCRIPT defined to enable Lua scripts"
+msgstr "używanie skryptów Lua, wymaga skompilowania dnsmasq-a z flagą HAVE_LUASCRIPT"
+
+#: option.c:2095 option.c:2106 option.c:2143 option.c:2199 option.c:2482
+msgid "bad prefix"
+msgstr "zła maska"
+
+#: option.c:2504
+msgid "recompile with HAVE_IPSET defined to enable ipset directives"
+msgstr "chcąc korzystać z ipsets przekompiluj dnsmasq-a z HAVE_IPSET"
+
+#: option.c:2713
+msgid "bad port range"
+msgstr "nieprawidłowy zakres numerów portów"
+
+#: option.c:2738
+msgid "bad bridge-interface"
+msgstr "nieprawidłowa nazwa urządzenia w bridge-interface"
+
+#: option.c:2798
+msgid "only one tag allowed"
+msgstr "można wskazać tylko jeden znacznik sieci"
+
+#: option.c:2818 option.c:2830 option.c:2939 option.c:2944 option.c:2983
+msgid "bad dhcp-range"
+msgstr "nieprawidłowy zakres dhcp-range"
+
+#: option.c:2845
+msgid "inconsistent DHCP range"
+msgstr "niespójny zakres adresów DHCP"
+
+#: option.c:2907
+msgid "prefix length must be exactly 64 for RA subnets"
+msgstr "długość prefiksu musi wynosić dokładnie 64 dla podsieci RA"
+
+#: option.c:2909
+msgid "prefix length must be exactly 64 for subnet constructors"
+msgstr "długość prefiksu musi wynosić dokładnie 64 dla konstruktorów podsieci"
+
+#: option.c:2913
+msgid "prefix length must be at least 64"
+msgstr "długość prefiksu musi wynosić co najmniej 64"
+
+#: option.c:2916
+msgid "inconsistent DHCPv6 range"
+msgstr "niespójny zakres adresów DHCPv6"
+
+#: option.c:2927
+msgid "prefix must be zero with \"constructor:\" argument"
+msgstr "prefiks musi wynosić zero z argumentem \"constructor:\""
+
+#: option.c:3040 option.c:3088
+msgid "bad hex constant"
+msgstr "zapis niezgodny z formatem szesnastkowym"
+
+#: option.c:3062
+msgid "cannot match tags in --dhcp-host"
+msgstr "--dhcp-host nie dopuszcza dopasowywania na podstawie znaczników"
+
+#: option.c:3110
+#, c-format
+msgid "duplicate dhcp-host IP address %s"
+msgstr "powtórzony adres IP %s w specyfikacji dhcp-host"
+
+#: option.c:3168
+msgid "bad DHCP host name"
+msgstr "niedopuszczalna nazwa komputera w dhcp-host"
+
+#: option.c:3250
+msgid "bad tag-if"
+msgstr "nieprawidłowa składnia 'tag-if'"
+
+#: option.c:3607 option.c:4030
+msgid "invalid port number"
+msgstr "nieprawidłowy numer portu"
+
+#: option.c:3669
+msgid "bad dhcp-proxy address"
+msgstr "zły adres dhcp-proxy"
+
+#: option.c:3695
+msgid "Bad dhcp-relay"
+msgstr "zły dhcp-relay"
+
+#: option.c:3736
+msgid "bad RA-params"
+msgstr "nieprawidłowe argumenty RA"
+
+#: option.c:3745
+msgid "bad DUID"
+msgstr "zły DUID"
+
+#: option.c:3787
+msgid "invalid alias range"
+msgstr "nieprawidłowy zakres adresów w --alias"
+
+#: option.c:3841 option.c:3853
+msgid "bad CNAME"
+msgstr "zła CNAME"
+
+#: option.c:3857
+msgid "duplicate CNAME"
+msgstr "powtórzona CNAME"
+
+#: option.c:3880
+msgid "bad PTR record"
+msgstr "nieprawidłowy zapis rekordu PTR"
+
+#: option.c:3911
+msgid "bad NAPTR record"
+msgstr "nieprawidłowy zapis rekordu NAPTR"
+
+#: option.c:3945
+msgid "bad RR record"
+msgstr "nieprawidłowy zapis rekordu RR"
+
+#: option.c:3975
+msgid "bad TXT record"
+msgstr "nieprawidłowy zapis rekordu TXT"
+
+#: option.c:4016
+msgid "bad SRV record"
+msgstr "nieprawidłowy zapis rekordu SRV"
+
+#: option.c:4023
+msgid "bad SRV target"
+msgstr "nieprawidłowa wartość celu SRV"
+
+#: option.c:4037
+msgid "invalid priority"
+msgstr "nieprawidłowy priorytet"
+
+#: option.c:4040
+msgid "invalid weight"
+msgstr "nieprawidłowa waga"
+
+#: option.c:4064
+msgid "Bad host-record"
+msgstr "nieprawidłowy zapis host-record"
+
+#: option.c:4088
+msgid "Bad name in host-record"
+msgstr "niedopuszczalna nazwa w host-record"
+
+#: option.c:4153
+msgid "bad trust anchor"
+msgstr "nieprawidłowa specyfikacja punktu zaufania"
+
+#: option.c:4167
+msgid "bad HEX in trust anchor"
+msgstr "zły zapis szesnastkowy"
+
+#: option.c:4177
+msgid "unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"
+msgstr "nieobsługiwana opcja (sprawdź, czy obsługa DHCP/TFTP/DNSSEC/DBus została wkompilowana)"
+
+#: option.c:4237
+msgid "missing \""
+msgstr "brakuje \""
+
+#: option.c:4294
+msgid "bad option"
+msgstr "nieprawidłowa opcja"
+
+#: option.c:4296
+msgid "extraneous parameter"
+msgstr "nadwyżkowy parametr"
+
+#: option.c:4298
+msgid "missing parameter"
+msgstr "brak parametru"
+
+#: option.c:4300
+msgid "illegal option"
+msgstr "niedopuszczalna opcja"
+
+#: option.c:4307
+msgid "error"
+msgstr "błąd"
+
+#: option.c:4309
+#, c-format
+msgid " at line %d of %s"
+msgstr " w linii %d pliku %s"
+
+#: option.c:4324 option.c:4571 option.c:4607
+#, c-format
+msgid "read %s"
+msgstr "przeczytałem %s"
+
+#: option.c:4387 option.c:4510 tftp.c:715
+#, c-format
+msgid "cannot read %s: %s"
+msgstr "błąd odczytu z pliku %s: %s"
+
+#: option.c:4676
+msgid "junk found in command line"
+msgstr "jakieś śmieci w linii poleceń"
+
+#: option.c:4711
+#, c-format
+msgid "Dnsmasq version %s  %s\n"
+msgstr "Dnsmasq, wersja %s  %s\n"
+
+#: option.c:4712
+#, c-format
+msgid ""
+"Compile time options: %s\n"
+"\n"
+msgstr ""
+"Wkompilowane opcje %s\n"
+"\n"
+
+#: option.c:4713
+#, c-format
+msgid "This software comes with ABSOLUTELY NO WARRANTY.\n"
+msgstr "Autor nie daje ŻADNYCH GWARANCJI egzekwowalnych prawnie.\n"
+
+#: option.c:4714
+#, c-format
+msgid "Dnsmasq is free software, and you are welcome to redistribute it\n"
+msgstr "Dnsmasq jest wolnym oprogramowaniem, możesz go rozprowadzać\n"
+
+#: option.c:4715
+#, c-format
+msgid "under the terms of the GNU General Public License, version 2 or 3.\n"
+msgstr "na warunkach określonych w GNU General Public Licence, w wersji 2 lub 3.\n"
+
+#: option.c:4726
+msgid "try --help"
+msgstr "spróbuj: --help"
+
+#: option.c:4728
+msgid "try -w"
+msgstr "spróbuj: -w"
+
+#: option.c:4730
+#, c-format
+msgid "bad command line options: %s"
+msgstr "nieprawidłowa opcja w linii poleceń %s"
+
+#: option.c:4798
+#, c-format
+msgid "CNAME loop involving %s"
+msgstr ""
+
+#: option.c:4834
+#, c-format
+msgid "cannot get host-name: %s"
+msgstr "nie można pobrać nazwy hosta: %s"
+
+#: option.c:4862
+msgid "only one resolv.conf file allowed in no-poll mode."
+msgstr "w trybie no-poll można wskazać najwyżej jeden plik resolv.conf."
+
+#: option.c:4872
+msgid "must have exactly one resolv.conf to read domain from."
+msgstr "musisz mieć dokładnie jeden plik resolv.conf do odczytu domen."
+
+#: option.c:4875 network.c:1612 dhcp.c:816
+#, c-format
+msgid "failed to read %s: %s"
+msgstr "nie udało się odczytać %s: %s"
+
+#: option.c:4892
+#, c-format
+msgid "no search directive found in %s"
+msgstr "brak wytycznych wyszukiwania w %s"
+
+#: option.c:4913
+msgid "there must be a default domain when --dhcp-fqdn is set"
+msgstr "w przypadku używania --dhcp-fqdn trzeba wskazać domyślną domenę"
+
+#: option.c:4922
+msgid "syntax check OK"
+msgstr "składnia sprawdzona, jest prawidłowa"
+
+#: forward.c:102
+#, c-format
+msgid "failed to send packet: %s"
+msgstr "wysyłanie pakietu nie powiodło się: %s"
+
+#: forward.c:597
+msgid "discarding DNS reply: subnet option mismatch"
+msgstr "odrzucam odpowiedź DNS: nie zgadza się specyfikacja podsieci"
+
+#: forward.c:651
+#, c-format
+msgid "nameserver %s refused to do a recursive query"
+msgstr "serwer nazw %s odmawia wykonania zapytania rekurencyjnego"
+
+#: forward.c:683
+#, c-format
+msgid "possible DNS-rebind attack detected: %s"
+msgstr "prawdopodobnie wykryto atak DNS-rebind: %s"
+
+#: forward.c:1244 forward.c:1681
+msgid "Ignoring query from non-local network"
+msgstr "Ignorowanie zapytań z sieci pozalokalnych."
+
+#: forward.c:2166
+#, c-format
+msgid "Maximum number of concurrent DNS queries reached (max: %d)"
+msgstr "Osiągnięto graniczną ilość jednocześnie obsługiwanych zapytań DNS (maks: %d)"
+
+#: network.c:720
+#, c-format
+msgid "failed to create listening socket for %s: %s"
+msgstr "nie udało się otworzyć gniazda %s: %s"
+
+#: network.c:1031
+#, c-format
+msgid "LOUD WARNING: listening on %s may accept requests via interfaces other than %s"
+msgstr "UWAGA: nasłuchiwanie na %s może przyjmować żądania przychodzące przez interfejsy inne niż %s"
+
+#: network.c:1038
+msgid "LOUD WARNING: use --bind-dynamic rather than --bind-interfaces to avoid DNS amplification attacks via these interface(s)"
+msgstr "UWAGA: zastosowanie --bind-dynamic zamiast --bind-interfaces daje ochronę przed atakami wzmocnienia DNS"
+
+#: network.c:1047
+#, fuzzy, c-format
+msgid "warning: using interface %s instead"
+msgstr "uwaga: %s niedostępny"
+
+#: network.c:1056
+#, c-format
+msgid "warning: no addresses found for interface %s"
+msgstr "uwaga: nie znaleziono adresu interfejsu %s"
+
+#: network.c:1114
+#, c-format
+msgid "interface %s failed to join DHCPv6 multicast group: %s"
+msgstr "interfejs %s nie pozwolił się przyłączyć do grupy rozgłoszeniowej DHCPv6: %s"
+
+#: network.c:1119
+msgid "try increasing /proc/sys/net/core/optmem_max"
+msgstr "spróbuj podwyższyć /proc/sys/net/core/optmem_max"
+
+#: network.c:1322
+#, c-format
+msgid "failed to bind server socket for %s: %s"
+msgstr "błąd przy przyznawaniu nazwy gniazdu serwera %s: %s"
+
+#: network.c:1517
+#, c-format
+msgid "ignoring nameserver %s - local interface"
+msgstr "ignorowanie serwera nazw %s - interfejs lokalny"
+
+#: network.c:1528
+#, c-format
+msgid "ignoring nameserver %s - cannot make/bind socket: %s"
+msgstr "ignorowanie serwera nazw %s - nie można utworzyć/dowiązać gniazda: %s"
+
+#: network.c:1548
+msgid "(no DNSSEC)"
+msgstr "(brak obsługi DNSSEC)"
+
+#: network.c:1551
+msgid "unqualified"
+msgstr "niekwalifikowane(-a)"
+
+#: network.c:1551
+msgid "names"
+msgstr "nazwy"
+
+#: network.c:1553
+msgid "default"
+msgstr "domyślne"
+
+#: network.c:1555
+msgid "domain"
+msgstr "domeny"
+
+#: network.c:1561
+#, c-format
+msgid "using local addresses only for %s %s"
+msgstr "używam adresów lokalnych tylko dla %s %s"
+
+#: network.c:1564
+#, c-format
+msgid "using standard nameservers for %s %s"
+msgstr "używam standardowych serwerów nazw dla %s %s"
+
+#: network.c:1566
+#, c-format
+msgid "using nameserver %s#%d for %s %s %s"
+msgstr "używam serwera nazw %s#%d dla %s %s %s"
+
+#: network.c:1570
+#, c-format
+msgid "NOT using nameserver %s#%d - query loop detected"
+msgstr "NIE używam serwera nazw %s#%d - wykryto pętlę zapytań"
+
+#: network.c:1573
+#, c-format
+msgid "using nameserver %s#%d(via %s)"
+msgstr "używam serwera nazw %s#%d (przez %s)"
+
+#: network.c:1575
+#, c-format
+msgid "using nameserver %s#%d"
+msgstr "używam serwera nazw %s#%d"
+
+#: network.c:1580
+#, fuzzy, c-format
+msgid "using %d more local addresses"
+msgstr "używam o %d serwerów nazw więcej"
+
+#: network.c:1582
+#, c-format
+msgid "using %d more nameservers"
+msgstr "używam o %d serwerów nazw więcej"
+
+#: dnsmasq.c:166
+msgid "dhcp-hostsdir, dhcp-optsdir and hostsdir are not supported on this platform"
+msgstr "dhcp-hostsdir, dhcp-optsdir i hostsdir nie znajdują zastosowania na tej platformie"
+
+#: dnsmasq.c:181
+msgid "no root trust anchor provided for DNSSEC"
+msgstr "nie wskazano punktów zaufania dla DNSSEC"
+
+#: dnsmasq.c:184
+msgid "cannot reduce cache size from default when DNSSEC enabled"
+msgstr "brak możliwości zmniejszenia pamięci podręcznej poniżej wielkości domyślnej w przypadku używania DNSSEC"
+
+#: dnsmasq.c:186
+msgid "DNSSEC not available: set HAVE_DNSSEC in src/config.h"
+msgstr "obsługa DNSSEC niedostępna - ustaw HAVE_DNSSEC w src/config.h"
+
+#: dnsmasq.c:192
+msgid "TFTP server not available: set HAVE_TFTP in src/config.h"
+msgstr "Serwer TFTP nie został wkompilowany -- ustaw HAVE_TFTP w src/config.h"
+
+#: dnsmasq.c:197
+msgid "cannot use --conntrack AND --query-port"
+msgstr "--conntrack i --query-port wzajemnie się wykluczają"
+
+#: dnsmasq.c:200
+msgid "conntrack support not available: set HAVE_CONNTRACK in src/config.h"
+msgstr "wsparcie przekazywania znaczników połączeń (conntrack) nie zostało wkompilowane - ustaw HAVE_CONNTRACK w src/config.h"
+
+#: dnsmasq.c:205
+msgid "asynchronous logging is not available under Solaris"
+msgstr "zapis do logów w trybie asynchronicznym nie jest dostępny w Solarisie"
+
+#: dnsmasq.c:210
+msgid "asynchronous logging is not available under Android"
+msgstr "zapis do logów w trybie asynchronicznym nie jest dostępny w Androidzie"
+
+#: dnsmasq.c:215
+msgid "authoritative DNS not available: set HAVE_AUTH in src/config.h"
+msgstr "tryb autorytatywny DNS-a niedostępny - ustaw HAVE_AUTH w src/config.h"
+
+#: dnsmasq.c:220
+msgid "loop detection not available: set HAVE_LOOP in src/config.h"
+msgstr "wykrywanie pętli zapytań nie zostało wkompilowane - ustaw HAVE_LOOP w src/config.h"
+
+#: dnsmasq.c:227
+msgid "max_port cannot be smaller than min_port"
+msgstr "max_port nie może być niższy niż min_port"
+
+#: dnsmasq.c:234
+msgid "zone serial must be configured in --auth-soa"
+msgstr "za pomocą --auth-soa musi zostać ustawiony numer seryjny strefy"
+
+#: dnsmasq.c:252
+msgid "dhcp-range constructor not available on this platform"
+msgstr "konstrukcja dhcp-range nie jest dostępna w tym systemie"
+
+#: dnsmasq.c:298
+msgid "cannot set --bind-interfaces and --bind-dynamic"
+msgstr "--bind-interfaces i --bind-dynamic wzajemnie się wykluczają"
+
+#: dnsmasq.c:301
+#, c-format
+msgid "failed to find list of interfaces: %s"
+msgstr "błąd podczas tworzenia listy interfejsów sieciowych: %s"
+
+#: dnsmasq.c:310
+#, c-format
+msgid "unknown interface %s"
+msgstr "nieznany interfejs %s"
+
+#: dnsmasq.c:374 dnsmasq.c:1037
+#, c-format
+msgid "DBus error: %s"
+msgstr "błąd DBus: %s"
+
+#: dnsmasq.c:377
+msgid "DBus not available: set HAVE_DBUS in src/config.h"
+msgstr "Obsługa DBus nie została wkompilowana -- ustaw HAVE_DBUS w src/config.h"
+
+#: dnsmasq.c:405
+#, c-format
+msgid "unknown user or group: %s"
+msgstr "nieznany użytkownik lub grupa: %s"
+
+#: dnsmasq.c:460
+#, c-format
+msgid "cannot chdir to filesystem root: %s"
+msgstr "nie potrafię wejść do głównego katalogu: %s"
+
+#: dnsmasq.c:716
+#, c-format
+msgid "started, version %s DNS disabled"
+msgstr "uruchomiony, wersja %s, DNS wyłączony"
+
+#: dnsmasq.c:720
+#, c-format
+msgid "started, version %s cachesize %d"
+msgstr "uruchomiony, wersja %s, %d miejsc w pamięci podręcznej"
+
+#: dnsmasq.c:722
+#, c-format
+msgid "started, version %s cache disabled"
+msgstr "uruchomiony, wersja %s, pamięć podręczna wyłączona"
+
+#: dnsmasq.c:725
+msgid "DNS service limited to local subnets"
+msgstr "usługa DNS ograniczona do lokalnych podsieci"
+
+#: dnsmasq.c:728
+#, c-format
+msgid "compile time options: %s"
+msgstr "opcje kompilacji: %s"
+
+#: dnsmasq.c:734
+msgid "DBus support enabled: connected to system bus"
+msgstr "obsługa DBus włączona, podłączono do serwera DBus"
+
+#: dnsmasq.c:736
+msgid "DBus support enabled: bus connection pending"
+msgstr "obsługa DBus włączona, trwa podłączanie do serwera DBus"
+
+#: dnsmasq.c:754
+msgid "DNSSEC validation enabled"
+msgstr "walidacja DNSSEC włączona"
+
+#: dnsmasq.c:758
+msgid "DNSSEC signature timestamps not checked until first cache reload"
+msgstr "sprawdzanie sygnatur czasowych DNSSEC wyłączone do czasu przeładowania pamięci podręcznej"
+
+#: dnsmasq.c:761
+msgid "DNSSEC signature timestamps not checked until system time valid"
+msgstr "sprawdzanie sygnatur czasowych DNSSEC wyłączone do czasu zsynchronizowania się zegara systemowego"
+
+#: dnsmasq.c:766
+#, c-format
+msgid "warning: failed to change owner of %s: %s"
+msgstr "uwaga: nie udało się zmienić użytkownika pliku %s: %s"
+
+#: dnsmasq.c:770
+msgid "setting --bind-interfaces option because of OS limitations"
+msgstr "ustawiam --bind-interfaces z powodu ograniczeń systemu operacyjnego"
+
+#: dnsmasq.c:782
+#, c-format
+msgid "warning: interface %s does not currently exist"
+msgstr "uwaga: interfejs %s nie jest włączony"
+
+#: dnsmasq.c:787
+msgid "warning: ignoring resolv-file flag because no-resolv is set"
+msgstr "uwaga: ignoruję opcję resolv-file, ponieważ wybrano tryb no-resolv"
+
+#: dnsmasq.c:790
+msgid "warning: no upstream servers configured"
+msgstr "uwaga: nie wskazano nadrzędnych serwerów DNS"
+
+#: dnsmasq.c:794
+#, c-format
+msgid "asynchronous logging enabled, queue limit is %d messages"
+msgstr "włączono asynchroniczny tryb zapisu do logów z kolejką na %d komunikatów"
+
+#: dnsmasq.c:815
+msgid "IPv6 router advertisement enabled"
+msgstr "anonsowanie rutera IPv6 włączone"
+
+#: dnsmasq.c:820
+#, c-format
+msgid "DHCP, sockets bound exclusively to interface %s"
+msgstr "DHCP, gniazda dowiązane na wyłączność interfejsowi %s"
+
+#: dnsmasq.c:834
+msgid "root is "
+msgstr "z głównym katalogiem w "
+
+#: dnsmasq.c:834
+msgid "enabled"
+msgstr "włączony"
+
+#: dnsmasq.c:836
+msgid "secure mode"
+msgstr "w trybie bezpiecznym"
+
+#: dnsmasq.c:839
+#, c-format
+msgid "warning: %s inaccessible"
+msgstr "uwaga: %s niedostępny"
+
+#: dnsmasq.c:843
+#, c-format
+msgid "warning: TFTP directory %s inaccessible"
+msgstr "uwaga: katalog TFTP %s nie jest dostępny"
+
+#: dnsmasq.c:869
+#, c-format
+msgid "restricting maximum simultaneous TFTP transfers to %d"
+msgstr "ograniczam ilość jednoczesnych przesłań TFTP do %d"
+
+#: dnsmasq.c:1039
+msgid "connected to system DBus"
+msgstr "podłączono do DBus-a"
+
+#: dnsmasq.c:1189
+#, c-format
+msgid "cannot fork into background: %s"
+msgstr "nie potrafię przełączyć się do pracy w tle: %s"
+
+#: dnsmasq.c:1192
+#, c-format
+msgid "failed to create helper: %s"
+msgstr "nie udało się utworzyć procesu pomocniczego: %s"
+
+#: dnsmasq.c:1195
+#, c-format
+msgid "setting capabilities failed: %s"
+msgstr "nie powiodło się ustawianie ograniczeń (capabilities): %s"
+
+#: dnsmasq.c:1198
+#, c-format
+msgid "failed to change user-id to %s: %s"
+msgstr "nie udało się zmienić użytkownika procesu na %s: %s"
+
+#: dnsmasq.c:1201
+#, c-format
+msgid "failed to change group-id to %s: %s"
+msgstr "nie udało się zmienić grupy procesu na %s: %s"
+
+#: dnsmasq.c:1204
+#, c-format
+msgid "failed to open pidfile %s: %s"
+msgstr "nie udało się otworzyć pliku z PID-em %s: %s"
+
+#: dnsmasq.c:1207
+#, c-format
+msgid "cannot open log %s: %s"
+msgstr "nie udało się otworzyć logu %s: %s"
+
+#: dnsmasq.c:1210
+#, c-format
+msgid "failed to load Lua script: %s"
+msgstr "nie udało się wczytać skryptu Lua: %s"
+
+#: dnsmasq.c:1213
+#, c-format
+msgid "TFTP directory %s inaccessible: %s"
+msgstr "katalog TFTP %s nie jest dostępny: %s"
+
+#: dnsmasq.c:1216
+#, c-format
+msgid "cannot create timestamp file %s: %s"
+msgstr "nie potrafię utworzyć pliku znacznika czasu %s: %s"
+
+#: dnsmasq.c:1239
+msgid "now checking DNSSEC signature timestamps"
+msgstr "trwa sprawdzanie sygnatur czasowych podpisów DNSSEC"
+
+#: dnsmasq.c:1307
+#, c-format
+msgid "script process killed by signal %d"
+msgstr "skrypt został zabity sygnałem %d"
+
+#: dnsmasq.c:1311
+#, c-format
+msgid "script process exited with status %d"
+msgstr "skrypt zakończył się z kodem powrotu %d"
+
+#: dnsmasq.c:1315
+#, c-format
+msgid "failed to execute %s: %s"
+msgstr "nie udało się uruchomić %s: %s"
+
+#: dnsmasq.c:1379 dnssec.c:479 dnssec.c:525
+#, c-format
+msgid "failed to update mtime on %s: %s"
+msgstr "nie udało się uaktualnić znacznika czasu pliku %s: %s"
+
+#: dnsmasq.c:1386
+msgid "exiting on receipt of SIGTERM"
+msgstr "zakończyłem działanie z powodu odebrania SIGTERM"
+
+#: dnsmasq.c:1414
+#, c-format
+msgid "failed to access %s: %s"
+msgstr "brak dostępu do %s: %s"
+
+#: dnsmasq.c:1444
+#, c-format
+msgid "reading %s"
+msgstr "czytanie %s"
+
+#: dnsmasq.c:1455
+#, c-format
+msgid "no servers found in %s, will retry"
+msgstr "w %s nie znalazłem serwerów, spróbuję ponownie później"
+
+#: dhcp.c:53
+#, c-format
+msgid "cannot create DHCP socket: %s"
+msgstr "nie udało się utworzyć gniazda dla DHCP: %s"
+
+#: dhcp.c:68
+#, c-format
+msgid "failed to set options on DHCP socket: %s"
+msgstr "błąd podczas ustawiania opcji gniazda DHCP: %s"
+
+#: dhcp.c:89
+#, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"
+msgstr "nie udało się ustawić SO_REUSE{ADDR|PORT} gniazda DHCP: %s"
+
+#: dhcp.c:101
+#, c-format
+msgid "failed to bind DHCP server socket: %s"
+msgstr "błąd przy przyznawaniu nazwy gniazdu serwera DHCP: %s"
+
+#: dhcp.c:127
+#, c-format
+msgid "cannot create ICMP raw socket: %s."
+msgstr "nie udało się utworzyć surowego gniazda ICMP: %s."
+
+#: dhcp.c:252 dhcp6.c:173
+#, c-format
+msgid "unknown interface %s in bridge-interface"
+msgstr "nieznany interfejs %s w bridge-u"
+
+#: dhcp.c:293
+#, c-format
+msgid "DHCP packet received on %s which has no address"
+msgstr "żądanie DHCP odebrano na interfejsie %s, który nie ma adresu"
+
+#: dhcp.c:427
+#, c-format
+msgid "ARP-cache injection failed: %s"
+msgstr "uzupełnienie pamięci podręcznej ARP nie powiodło się: %s"
+
+#: dhcp.c:470
+#, c-format
+msgid "Error sending DHCP packet to %s: %s"
+msgstr "Błąd wysyłania pakietu DHCP do %s: %s"
+
+#: dhcp.c:531
+#, c-format
+msgid "DHCP range %s -- %s is not consistent with netmask %s"
+msgstr "zakres adresów DHCP %s -- %s jest niespójny z maską sieci %s"
+
+#: dhcp.c:854
+#, c-format
+msgid "bad line at %s line %d"
+msgstr "zła zawartość pliku %s, w linii %d"
+
+#: dhcp.c:897
+#, c-format
+msgid "ignoring %s line %d, duplicate name or IP address"
+msgstr "w %s pomijam linię %d -- powtórzona nazwa lub adres IP"
+
+#: dhcp.c:1041 rfc3315.c:2149
+#, c-format
+msgid "DHCP relay %s -> %s"
+msgstr "przekazywanie DHCP %s -> %s"
+
+#: lease.c:98
+msgid "too many stored leases"
+msgstr "zbyt duża ilość zapisanych dzierżaw"
+
+#: lease.c:166
+#, c-format
+msgid "cannot open or create lease file %s: %s"
+msgstr "nie potrafię otworzyć albo utworzyć pliku dzierżaw %s: %s"
+
+#: lease.c:175
+#, c-format
+msgid "failed to parse lease database, invalid line: %s %s %s %s ..."
+msgstr ""
+
+#: lease.c:180
+#, fuzzy, c-format
+msgid "failed to read lease file %s: %s"
+msgstr "nie udało się odczytać %s: %s"
+
+#: lease.c:196
+#, c-format
+msgid "cannot run lease-init script %s: %s"
+msgstr "nie potrafię uruchomić skryptu %s: %s"
+
+#: lease.c:202
+#, c-format
+msgid "lease-init script returned exit code %s"
+msgstr "skrypt zakończył się z kodem powrotu %s"
+
+#: lease.c:373
+#, c-format
+msgid "failed to write %s: %s (retry in %us)"
+msgstr "błąd zapisu do %s: %s (spróbuję ponownie za %us)"
+
+#: lease.c:937
+#, c-format
+msgid "Ignoring domain %s for DHCP host name %s"
+msgstr "Nie uwzględniam części domenowej (%s) dla komputera %s"
+
+#: rfc2131.c:347
+#, c-format
+msgid "no address range available for DHCP request %s %s"
+msgstr "nie zdefiniowano zakresu adresów odpowiedniego dla żądania %s %s"
+
+#: rfc2131.c:348
+msgid "with subnet selector"
+msgstr "z wyborem podsieci"
+
+#: rfc2131.c:348
+msgid "via"
+msgstr "przez"
+
+#: rfc2131.c:360
+#, c-format
+msgid "%u available DHCP subnet: %s/%s"
+msgstr "%u dostępna podsieć DHCP: %s/%s"
+
+#: rfc2131.c:363 rfc3315.c:306
+#, c-format
+msgid "%u available DHCP range: %s -- %s"
+msgstr "%u dostępny zakres adresów DHCP: %s -- %s"
+
+#: rfc2131.c:474
+#, c-format
+msgid "%u vendor class: %s"
+msgstr "%u klasa dostawcy: %s"
+
+#: rfc2131.c:476
+#, c-format
+msgid "%u user class: %s"
+msgstr "%u klasa użytkownika: %s"
+
+#: rfc2131.c:510
+msgid "disabled"
+msgstr "wyłączony(a)"
+
+#: rfc2131.c:551 rfc2131.c:1006 rfc2131.c:1430 rfc3315.c:616 rfc3315.c:869
+#: rfc3315.c:1148
+msgid "ignored"
+msgstr "ignoruję"
+
+#: rfc2131.c:566 rfc2131.c:1239 rfc3315.c:919
+msgid "address in use"
+msgstr "adres jest w użyciu"
+
+#: rfc2131.c:580 rfc2131.c:1060
+msgid "no address available"
+msgstr "brak dostępnego adresu"
+
+#: rfc2131.c:587 rfc2131.c:1202
+msgid "wrong network"
+msgstr "nieprawidłowa sieć"
+
+#: rfc2131.c:602
+msgid "no address configured"
+msgstr "brak skonfigurowanego adresu"
+
+#: rfc2131.c:608 rfc2131.c:1252
+msgid "no leases left"
+msgstr "brak wolnych dzierżaw"
+
+#: rfc2131.c:703 rfc3315.c:482
+#, c-format
+msgid "%u client provides name: %s"
+msgstr "klient %u przedstawia się jako %s"
+
+#: rfc2131.c:808
+msgid "PXE BIS not supported"
+msgstr "PXE BIS nie jest obsługiwane"
+
+#: rfc2131.c:974 rfc3315.c:1242
+#, c-format
+msgid "disabling DHCP static address %s for %s"
+msgstr "wyłączam statyczne przypisanie adresu %s dla %s"
+
+#: rfc2131.c:995
+msgid "unknown lease"
+msgstr "nieznana dzierżawa"
+
+#: rfc2131.c:1029
+#, c-format
+msgid "not using configured address %s because it is leased to %s"
+msgstr "nie proponuję zakładanego w konfiguracji adresu %s, bo jest on już wydzierżawiony komputerowi %s"
+
+#: rfc2131.c:1039
+#, c-format
+msgid "not using configured address %s because it is in use by the server or relay"
+msgstr "nie proponuję zakładanego w konfiguracji adresu %s, bo używa go któryś z serwerów"
+
+#: rfc2131.c:1042
+#, c-format
+msgid "not using configured address %s because it was previously declined"
+msgstr "nie proponuję zakładanego w konfiguracji adresu %s, bo już poprzednio został odrzucony"
+
+#: rfc2131.c:1058 rfc2131.c:1245
+msgid "no unique-id"
+msgstr "brak unikalnego id"
+
+#: rfc2131.c:1140
+msgid "wrong server-ID"
+msgstr "nieprawidłowy identyfikator serwera (server-ID)"
+
+#: rfc2131.c:1159
+msgid "wrong address"
+msgstr "błędny adres"
+
+#: rfc2131.c:1177 rfc3315.c:1015
+msgid "lease not found"
+msgstr "dzierżawa nieznaleziona"
+
+#: rfc2131.c:1210
+msgid "address not available"
+msgstr "adres niedostępny"
+
+#: rfc2131.c:1221
+msgid "static lease available"
+msgstr "dostępna statyczna dzierżawa"
+
+#: rfc2131.c:1225
+msgid "address reserved"
+msgstr "adres zarezerwowany"
+
+#: rfc2131.c:1233
+#, c-format
+msgid "abandoning lease to %s of %s"
+msgstr "porzucam przypisanie do %s nazwy %s"
+
+#: rfc2131.c:1757
+#, c-format
+msgid "%u bootfile name: %s"
+msgstr "%u nazwa pliku bootowania: %s"
+
+#: rfc2131.c:1766
+#, c-format
+msgid "%u server name: %s"
+msgstr "%u nazwa serwera: %s"
+
+#: rfc2131.c:1774
+#, c-format
+msgid "%u next server: %s"
+msgstr "%u następny serwer: %s"
+
+#: rfc2131.c:1777
+#, c-format
+msgid "%u broadcast response"
+msgstr "%u odpowiedź rozgłoszeniowa"
+
+#: rfc2131.c:1840
+#, c-format
+msgid "cannot send DHCP/BOOTP option %d: no space left in packet"
+msgstr "nie mam możliwości wysłania opcji %d DHCP/BOOTP: niedostateczna ilość miejsca w pakiecie"
+
+#: rfc2131.c:2131
+msgid "PXE menu too large"
+msgstr "menu PXE zbyt duże"
+
+#: rfc2131.c:2270 rfc3315.c:1515
+#, c-format
+msgid "%u requested options: %s"
+msgstr "%u zażądano: %s"
+
+#: rfc2131.c:2587
+#, c-format
+msgid "cannot send RFC3925 option: too many options for enterprise number %d"
+msgstr "nie mogę wysłać opcji RFC3925: za długi łańcuch opcji przy numerze %d"
+
+#: rfc2131.c:2650
+#, c-format
+msgid "%u reply delay: %d"
+msgstr ""
+
+#: netlink.c:77
+#, c-format
+msgid "cannot create netlink socket: %s"
+msgstr "nie potrafię utworzyć połączenia netlink %s"
+
+#: netlink.c:355
+#, c-format
+msgid "netlink returns error: %s"
+msgstr "wystąpił błąd w połączeniu netlink %s"
+
+#: dbus.c:186
+msgid "attempt to set an IPv6 server address via DBus - no IPv6 support"
+msgstr "próba ustawienia adresu IPv6 serwera przez DBus, ale brak obsługi IPv6"
+
+#: dbus.c:439
+#, c-format
+msgid "Enabling --%s option from D-Bus"
+msgstr "opcja --%s została właśnie aktywowana za pomocą D-Bus"
+
+#: dbus.c:444
+#, c-format
+msgid "Disabling --%s option from D-Bus"
+msgstr "opcja --%s została właśnie dezaktywowana za pomocą D-Bus"
+
+#: dbus.c:690
+msgid "setting upstream servers from DBus"
+msgstr "ustawiam adresy serwerów nadrzędnych na podstawie informacji odebranych z DBus"
+
+#: dbus.c:737
+msgid "could not register a DBus message handler"
+msgstr "nie można zarejestrować uchwytu DBus"
+
+#: bpf.c:265
+#, c-format
+msgid "cannot create DHCP BPF socket: %s"
+msgstr "nie potrafię utworzyć gniazda DHCP BPF: %s"
+
+#: bpf.c:293
+#, c-format
+msgid "DHCP request for unsupported hardware type (%d) received on %s"
+msgstr "żądanie DHCP od urządzenia nieobsługiwanego typu (%d) odebrano na %s"
+
+#: bpf.c:378
+#, c-format
+msgid "cannot create PF_ROUTE socket: %s"
+msgstr "nie udało się utworzyć gniazda PF_ROUTE: %s"
+
+#: bpf.c:399
+msgid "Unknown protocol version from route socket"
+msgstr "Nieznana wersja protokołu."
+
+#: helper.c:153
+msgid "lease() function missing in Lua script"
+msgstr "w skrypcie Lua brak funkcji lease()"
+
+#: tftp.c:319
+msgid "unable to get free port for TFTP"
+msgstr "brak wolnego portu dla usługi TFTP"
+
+#: tftp.c:335
+#, c-format
+msgid "unsupported request from %s"
+msgstr "nieobsługiwane żądanie od komputera %s"
+
+#: tftp.c:483
+#, c-format
+msgid "file %s not found"
+msgstr "plik %s nie został znaleziony"
+
+#: tftp.c:592
+#, c-format
+msgid "error %d %s received from %s"
+msgstr "błąd %d %s odebrano od %s"
+
+#: tftp.c:634
+#, c-format
+msgid "failed sending %s to %s"
+msgstr "błąd wysyłania pliku %s do komputera %s"
+
+#: tftp.c:634
+#, c-format
+msgid "sent %s to %s"
+msgstr "plik %s przesłano do %s"
+
+#: log.c:190
+#, c-format
+msgid "overflow: %d log entries lost"
+msgstr "przepełnienie: stracono %d wpisów do logów"
+
+#: log.c:268
+#, c-format
+msgid "log failed: %s"
+msgstr "nie udało się zapisać komunikatów do %s"
+
+#: log.c:471
+msgid "FAILED to start up"
+msgstr "BŁĄD: nie udało się uruchomić dnsmasq-a"
+
+#: conntrack.c:65
+#, c-format
+msgid "Conntrack connection mark retrieval failed: %s"
+msgstr "Nie udało się odcztać znacznika połączenia (conntrack): %s"
+
+#: dhcp6.c:52
+#, c-format
+msgid "cannot create DHCPv6 socket: %s"
+msgstr "nie udało się utworzyć gniazda dla DHCPv6: %s"
+
+#: dhcp6.c:73
+#, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"
+msgstr "nie udało się ustawić SO_REUSE{ADDR|PORT} gniazda DHCPv6: %s"
+
+#: dhcp6.c:85
+#, c-format
+msgid "failed to bind DHCPv6 server socket: %s"
+msgstr "dowiązywanie gniazda serwera DHCPv6 zakończone niepowodzeniem: %s"
+
+#: rfc3315.c:157
+#, c-format
+msgid "no address range available for DHCPv6 request from relay at %s"
+msgstr "nie zdefiniowano zakresu adresów odpowiedniego dla żądania DHCPv6 przekazanego przez %s"
+
+#: rfc3315.c:166
+#, c-format
+msgid "no address range available for DHCPv6 request via %s"
+msgstr "nie zdefiniowano zakresu adresów odpowiedniego dla żądania DHCPv6 od %s"
+
+#: rfc3315.c:303
+#, c-format
+msgid "%u available DHCPv6 subnet: %s/%d"
+msgstr "%u dostępna podsieć DHCPv6: %s/%d"
+
+#: rfc3315.c:386
+#, c-format
+msgid "%u vendor class: %u"
+msgstr "%u klasa dostawcy: %u"
+
+#: rfc3315.c:434
+#, c-format
+msgid "%u client MAC address: %s"
+msgstr "adres MAC klienta %u: %s"
+
+#: rfc3315.c:673
+#, c-format
+msgid "unknown prefix-class %d"
+msgstr "nieznana klasa sieci %d"
+
+#: rfc3315.c:816 rfc3315.c:911
+msgid "address unavailable"
+msgstr "adres niedostępny"
+
+#: rfc3315.c:828 rfc3315.c:959 rfc3315.c:1292
+msgid "success"
+msgstr "udane"
+
+#: rfc3315.c:843 rfc3315.c:852 rfc3315.c:967 rfc3315.c:969
+msgid "no addresses available"
+msgstr "brak wolnych adresów"
+
+#: rfc3315.c:946
+msgid "not on link"
+msgstr "poza zasięgiem"
+
+#: rfc3315.c:1019 rfc3315.c:1204 rfc3315.c:1281
+msgid "no binding found"
+msgstr "brak powiązania"
+
+#: rfc3315.c:1057
+msgid "deprecated"
+msgstr "przestarzały"
+
+#: rfc3315.c:1062
+msgid "address invalid"
+msgstr "niepoprawny adres"
+
+#: rfc3315.c:1109
+msgid "confirm failed"
+msgstr "brak potwierdzenia"
+
+#: rfc3315.c:1125
+msgid "all addresses still on link"
+msgstr "wszystkie adresy ciągle w użyciu"
+
+#: rfc3315.c:1213
+msgid "release received"
+msgstr "adres został zwolniony"
+
+#: rfc3315.c:2140
+msgid "Cannot multicast to DHCPv6 server without correct interface"
+msgstr "Nie mogę rozesłać do serwerów DHCPv6 nie mając prawidłowego interfejsu"
+
+#: dhcp-common.c:145
+#, c-format
+msgid "Ignoring duplicate dhcp-option %d"
+msgstr "Pomijam powtórzoną dhcp-option %d"
+
+#: dhcp-common.c:222
+#, c-format
+msgid "%u tags: %s"
+msgstr "%u cechy: %s"
+
+#: dhcp-common.c:407
+#, c-format
+msgid "%s has more than one address in hostsfile, using %s for DHCP"
+msgstr "do komputera o nazwie %s pasuje więcej niż jeden adres, w odpowiedzi DHCP wysyłam %s"
+
+#: dhcp-common.c:430
+#, c-format
+msgid "duplicate IP address %s (%s) in dhcp-config directive"
+msgstr "powtórzenie adresu IP %s (%s) w opcji dhcp-config"
+
+#: dhcp-common.c:494
+#, c-format
+msgid "failed to set SO_BINDTODEVICE on DHCP socket: %s"
+msgstr "nie udało się ustawić SO_BINDTODEVICE gniazda DHCP: %s"
+
+#: dhcp-common.c:615
+#, c-format
+msgid "Known DHCP options:\n"
+msgstr "Znane opcje DHCP:\n"
+
+#: dhcp-common.c:626
+#, c-format
+msgid "Known DHCPv6 options:\n"
+msgstr "Rozpoznawane opcje DHCPv6:\n"
+
+#: dhcp-common.c:823
+msgid ", prefix deprecated"
+msgstr ", przestarzały prefiks"
+
+#: dhcp-common.c:826
+#, c-format
+msgid ", lease time "
+msgstr ", czas dzierżawy "
+
+#: dhcp-common.c:868
+#, c-format
+msgid "%s stateless on %s%.0s%.0s%s"
+msgstr "%s bezstanowy na %s%.0s%.0s%s"
+
+#: dhcp-common.c:870
+#, c-format
+msgid "%s, static leases only on %.0s%s%s%.0s"
+msgstr "%s, wyłącznie statyczne dzierżawy na %.0s%s%s%.0s"
+
+#: dhcp-common.c:872
+#, c-format
+msgid "%s, proxy on subnet %.0s%s%.0s%.0s"
+msgstr "%s, wykryto pośrednika na podsieci %.0s%s%.0s%.0s"
+
+#: dhcp-common.c:873
+#, c-format
+msgid "%s, IP range %s -- %s%s%.0s"
+msgstr "%s, zakres IP %s -- %s%s%.0s"
+
+#: dhcp-common.c:886
+#, c-format
+msgid "DHCPv4-derived IPv6 names on %s%s"
+msgstr "pochodzące z DHCPv4 nazwy IPv6 na %s%s"
+
+#: dhcp-common.c:889
+#, c-format
+msgid "router advertisement on %s%s"
+msgstr "anonsowanie rutera na %s%s"
+
+#: dhcp-common.c:900
+#, c-format
+msgid "DHCP relay from %s to %s via %s"
+msgstr "przekazywanie DHCP z %s do %s za pomocą %s"
+
+#: dhcp-common.c:902
+#, c-format
+msgid "DHCP relay from %s to %s"
+msgstr "przekazywanie DHCP z %s do %s"
+
+#: radv.c:110
+#, c-format
+msgid "cannot create ICMPv6 socket: %s"
+msgstr "nie udało się utworzyć gniazda dla ICMPv6: %s"
+
+#: auth.c:449
+#, c-format
+msgid "ignoring zone transfer request from %s"
+msgstr "ignoruję żądanie transferu strefy od %s"
+
+#: ipset.c:95
+#, c-format
+msgid "failed to find kernel version: %s"
+msgstr "niezgodna wersja jądra: %s"
+
+#: ipset.c:114
+#, c-format
+msgid "failed to create IPset control socket: %s"
+msgstr "nie powiodło się otwieranie gniazda sterującego IPset: %s"
+
+#: ipset.c:233
+#, fuzzy, c-format
+msgid "failed to update ipset %s: %s"
+msgstr "nie udało się uaktualnić znacznika czasu pliku %s: %s"
+
+#: dnssec.c:527
+#, fuzzy
+msgid "system time considered valid, now checking DNSSEC signature timestamps."
+msgstr "trwa sprawdzanie sygnatur czasowych podpisów DNSSEC"
+
+#: blockdata.c:58
+#, c-format
+msgid "DNSSEC memory in use %u, max %u, allocated %u"
+msgstr "DNSSEC: zużycie pamięci %u, maks. %u, przydzielona %u"
+
+#: tables.c:61
+#, c-format
+msgid "failed to access pf devices: %s"
+msgstr "brak dostępu do /dev/pf (filtra pakietów): %s"
+
+#: tables.c:74
+#, c-format
+msgid "warning: no opened pf devices %s"
+msgstr "uwaga: brak otwartych filtrów pakietów %s"
+
+#: tables.c:82
+#, c-format
+msgid "error: cannot use table name %s"
+msgstr "błąd: nie potrafię użyć nazwy tablicy %s"
+
+#: tables.c:90
+#, c-format
+msgid "error: cannot strlcpy table name %s"
+msgstr "błąd: nie potrafię strlcpy nazwy tablicy %s"
+
+#: tables.c:101
+#, fuzzy, c-format
+msgid "IPset: error:%s"
+msgstr "błąd DBus: %s"
+
+#: tables.c:108
+msgid "info: table created"
+msgstr "info: tablica utworzona"
+
+#: tables.c:134
+#, c-format
+msgid "warning: DIOCR%sADDRS: %s"
+msgstr "uwaga: DIOCR%sADDRS: %s"
+
+#: tables.c:138
+#, c-format
+msgid "%d addresses %s"
+msgstr "%d adresów %s"
+
+#: inotify.c:62
+#, c-format
+msgid "cannot access path %s: %s"
+msgstr "brak dostępu do katalogu %s: %s"
+
+#: inotify.c:95
+#, c-format
+msgid "failed to create inotify: %s"
+msgstr "nie udało się uruchomić powiadamiania inotify: %s"
+
+#: inotify.c:111
+#, c-format
+msgid "too many symlinks following %s"
+msgstr "zbyt wiele odniesień począwszy od %s"
+
+#: inotify.c:127
+#, c-format
+msgid "directory %s for resolv-file is missing, cannot poll"
+msgstr "katalog %s z resolv-file nie istnieje - nie ma czego odpytywać"
+
+#: inotify.c:131 inotify.c:168
+#, c-format
+msgid "failed to create inotify for %s: %s"
+msgstr "nie udało się utworzyć powiadamiania dla %s: %s"
+
+#: inotify.c:153
+#, c-format
+msgid "bad dynamic directory %s: %s"
+msgstr "zły katalog dynamiczny %s: %s"
+
+#: inotify.c:255
+#, c-format
+msgid "inotify, new or changed file %s"
+msgstr "inotify: pojawił się lub uległ zmianie plik %s"
+
+#~ msgid "bad TTL"
+#~ msgstr "zły TTL"
+
+#~ msgid "error: fill_addr missused"
+#~ msgstr "błąd: niepoprawnie użyty fill_addr"
+
+#~ msgid "warning: pfr_add_tables: %s(%d)"
+#~ msgstr "uwaga: pfr_add_tables: %s(%d)"
+
+#, fuzzy
+#~ msgid "cannot cannonicalise resolv-file %s: %s"
+#~ msgstr "nie potrafię otworzyć albo utworzyć pliku dzierżaw %s: %s"
+
+#~ msgid "Always send frequent router-advertisements"
+#~ msgstr "Rozsyłanie wielokrotne anonsów rutera (RA)"
+
+#~ msgid "no interface with address %s"
+#~ msgstr "brak interfejsu z adresem %s"
+
+#~ msgid "duplicate IP address %s in dhcp-config directive."
+#~ msgstr "powtórzony adres IP (%s) w parametrze dhcp-config"
+
+#, fuzzy
+#~ msgid "Specify path to Lua script (no default)."
+#~ msgstr "Określenie ścieżki do pliku PID (domyślnie: %s)."
+
+#~ msgid "only one dhcp-hostsfile allowed"
+#~ msgstr "można wskazać tylko jeden plik dhcp-hostsfile"
+
+#~ msgid "only one dhcp-optsfile allowed"
+#~ msgstr "można wskazać tylko jeden plik dhcp-optsfile"
+
+#~ msgid "files nested too deep in %s"
+#~ msgstr "zbyt duże zagłębienie plików w %s"
+
+#~ msgid "TXT record string too long"
+#~ msgstr "zbyt długi rekord TXT"
+
+#~ msgid "failed to set IPV6 options on listening socket: %s"
+#~ msgstr "błąd ustawiania opcji IPV6 na nasłuchującym gnieździe: %s"
+
+#~ msgid "failed to bind listening socket for %s: %s"
+#~ msgstr "błąd przy przyznawaniu nazwy gniazdu %s: %s"
diff --git a/po/pt_BR.po b/po/pt_BR.po
new file mode 100755
index 0000000..c985a9b
--- /dev/null
+++ b/po/pt_BR.po
@@ -0,0 +1,2226 @@
+# Portuguese translations for dnsmasq package.
+# This file is put in the public domain.
+# Simon Kelley <simon@thekelleys.org.uk>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: dnsmasq 2.26\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-06-18 12:24+0100\n"
+"PO-Revision-Date: 2017-07-17 18:30+0100\n"
+"Last-Translator: Simon Kelley <simon@thekelleys.org.uk>\n"
+"Language-Team: Portuguese <ldp-br@bazar.conectiva.com.br>\n"
+"Language: pt\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ASCII\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: cache.c:513
+msgid "Internal error in cache."
+msgstr ""
+
+#: cache.c:923
+#, c-format
+msgid "failed to load names from %s: %s"
+msgstr ""
+
+#: cache.c:949 dhcp.c:867
+#, c-format
+msgid "bad address at %s line %d"
+msgstr ""
+
+#: cache.c:1002 dhcp.c:883
+#, c-format
+msgid "bad name at %s line %d"
+msgstr ""
+
+#: cache.c:1011 dhcp.c:958
+#, c-format
+msgid "read %s - %d addresses"
+msgstr ""
+
+#: cache.c:1124
+msgid "cleared cache"
+msgstr ""
+
+#: cache.c:1153
+#, c-format
+msgid "No IPv4 address found for %s"
+msgstr ""
+
+#: cache.c:1232
+#, c-format
+msgid "%s is a CNAME, not giving it to the DHCP lease of %s"
+msgstr ""
+
+#: cache.c:1256
+#, c-format
+msgid "not giving name %s to the DHCP lease of %s because the name exists in %s with address %s"
+msgstr ""
+
+#: cache.c:1413
+#, c-format
+msgid "time %lu"
+msgstr ""
+
+#: cache.c:1414
+#, c-format
+msgid "cache size %d, %d/%d cache insertions re-used unexpired cache entries."
+msgstr ""
+
+#: cache.c:1416
+#, c-format
+msgid "queries forwarded %u, queries answered locally %u"
+msgstr ""
+
+#: cache.c:1419
+#, c-format
+msgid "queries for authoritative zones %u"
+msgstr ""
+
+#: cache.c:1445
+#, c-format
+msgid "server %s#%d: queries sent %u, retried or failed %u"
+msgstr ""
+
+#: util.c:47
+#, c-format
+msgid "failed to seed the random number generator: %s"
+msgstr ""
+
+#: util.c:224
+msgid "failed to allocate memory"
+msgstr ""
+
+#: util.c:277 option.c:619
+msgid "could not get memory"
+msgstr ""
+
+#: util.c:287
+#, c-format
+msgid "cannot create pipe: %s"
+msgstr ""
+
+#: util.c:295
+#, c-format
+msgid "failed to allocate %d bytes"
+msgstr ""
+
+#: util.c:464
+#, c-format
+msgid "infinite"
+msgstr ""
+
+#: option.c:344
+msgid "Specify local address(es) to listen on."
+msgstr ""
+
+#: option.c:345
+msgid "Return ipaddr for all hosts in specified domains."
+msgstr ""
+
+#: option.c:346
+msgid "Fake reverse lookups for RFC1918 private address ranges."
+msgstr ""
+
+#: option.c:347
+msgid "Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."
+msgstr ""
+
+#: option.c:348
+#, c-format
+msgid "Specify the size of the cache in entries (defaults to %s)."
+msgstr ""
+
+#: option.c:349
+#, c-format
+msgid "Specify configuration file (defaults to %s)."
+msgstr ""
+
+#: option.c:350
+msgid "Do NOT fork into the background: run in debug mode."
+msgstr ""
+
+#: option.c:351
+msgid "Do NOT forward queries with no domain part."
+msgstr ""
+
+#: option.c:352
+msgid "Return self-pointing MX records for local hosts."
+msgstr ""
+
+#: option.c:353
+msgid "Expand simple names in /etc/hosts with domain-suffix."
+msgstr ""
+
+#: option.c:354
+msgid "Don't forward spurious DNS requests from Windows hosts."
+msgstr ""
+
+#: option.c:355
+msgid "Enable DHCP in the range given with lease duration."
+msgstr ""
+
+#: option.c:356
+#, c-format
+msgid "Change to this group after startup (defaults to %s)."
+msgstr ""
+
+#: option.c:357
+msgid "Set address or hostname for a specified machine."
+msgstr ""
+
+#: option.c:358
+msgid "Read DHCP host specs from file."
+msgstr ""
+
+#: option.c:359
+msgid "Read DHCP option specs from file."
+msgstr ""
+
+#: option.c:360
+msgid "Read DHCP host specs from a directory."
+msgstr ""
+
+#: option.c:361
+msgid "Read DHCP options from a directory."
+msgstr ""
+
+#: option.c:362
+msgid "Evaluate conditional tag expression."
+msgstr ""
+
+#: option.c:363
+#, c-format
+msgid "Do NOT load %s file."
+msgstr ""
+
+#: option.c:364
+#, c-format
+msgid "Specify a hosts file to be read in addition to %s."
+msgstr ""
+
+#: option.c:365
+msgid "Read hosts files from a directory."
+msgstr ""
+
+#: option.c:366
+msgid "Specify interface(s) to listen on."
+msgstr ""
+
+#: option.c:367
+msgid "Specify interface(s) NOT to listen on."
+msgstr ""
+
+#: option.c:368
+msgid "Map DHCP user class to tag."
+msgstr ""
+
+#: option.c:369
+msgid "Map RFC3046 circuit-id to tag."
+msgstr ""
+
+#: option.c:370
+msgid "Map RFC3046 remote-id to tag."
+msgstr ""
+
+#: option.c:371
+msgid "Map RFC3993 subscriber-id to tag."
+msgstr ""
+
+#: option.c:372
+msgid "Don't do DHCP for hosts with tag set."
+msgstr ""
+
+#: option.c:373
+msgid "Force broadcast replies for hosts with tag set."
+msgstr ""
+
+#: option.c:374
+msgid "Do NOT fork into the background, do NOT run in debug mode."
+msgstr ""
+
+#: option.c:375
+msgid "Assume we are the only DHCP server on the local network."
+msgstr ""
+
+#: option.c:376
+#, c-format
+msgid "Specify where to store DHCP leases (defaults to %s)."
+msgstr ""
+
+#: option.c:377
+msgid "Return MX records for local hosts."
+msgstr ""
+
+#: option.c:378
+msgid "Specify an MX record."
+msgstr ""
+
+#: option.c:379
+msgid "Specify BOOTP options to DHCP server."
+msgstr ""
+
+#: option.c:380
+#, c-format
+msgid "Do NOT poll %s file, reload only on SIGHUP."
+msgstr ""
+
+#: option.c:381
+msgid "Do NOT cache failed search results."
+msgstr ""
+
+#: option.c:382
+#, c-format
+msgid "Use nameservers strictly in the order given in %s."
+msgstr ""
+
+#: option.c:383
+msgid "Specify options to be sent to DHCP clients."
+msgstr ""
+
+#: option.c:384
+msgid "DHCP option sent even if the client does not request it."
+msgstr ""
+
+#: option.c:385
+msgid "Specify port to listen for DNS requests on (defaults to 53)."
+msgstr ""
+
+#: option.c:386
+#, c-format
+msgid "Maximum supported UDP packet size for EDNS.0 (defaults to %s)."
+msgstr ""
+
+#: option.c:387
+msgid "Log DNS queries."
+msgstr ""
+
+#: option.c:388
+msgid "Force the originating port for upstream DNS queries."
+msgstr ""
+
+#: option.c:389
+msgid "Do NOT read resolv.conf."
+msgstr ""
+
+#: option.c:390
+#, c-format
+msgid "Specify path to resolv.conf (defaults to %s)."
+msgstr ""
+
+#: option.c:391
+msgid "Specify path to file with server= options"
+msgstr ""
+
+#: option.c:392
+msgid "Specify address(es) of upstream servers with optional domains."
+msgstr ""
+
+#: option.c:393
+msgid "Specify address of upstream servers for reverse address queries"
+msgstr ""
+
+#: option.c:394
+msgid "Never forward queries to specified domains."
+msgstr ""
+
+#: option.c:395
+msgid "Specify the domain to be assigned in DHCP leases."
+msgstr ""
+
+#: option.c:396
+msgid "Specify default target in an MX record."
+msgstr ""
+
+#: option.c:397
+msgid "Specify time-to-live in seconds for replies from /etc/hosts."
+msgstr ""
+
+#: option.c:398
+msgid "Specify time-to-live in seconds for negative caching."
+msgstr ""
+
+#: option.c:399
+msgid "Specify time-to-live in seconds for maximum TTL to send to clients."
+msgstr ""
+
+#: option.c:400
+msgid "Specify time-to-live ceiling for cache."
+msgstr ""
+
+#: option.c:401
+msgid "Specify time-to-live floor for cache."
+msgstr ""
+
+#: option.c:402
+#, c-format
+msgid "Change to this user after startup. (defaults to %s)."
+msgstr ""
+
+#: option.c:403
+msgid "Map DHCP vendor class to tag."
+msgstr ""
+
+#: option.c:404
+msgid "Display dnsmasq version and copyright information."
+msgstr ""
+
+#: option.c:405
+msgid "Translate IPv4 addresses from upstream servers."
+msgstr ""
+
+#: option.c:406
+msgid "Specify a SRV record."
+msgstr ""
+
+#: option.c:407
+msgid "Display this message. Use --help dhcp or --help dhcp6 for known DHCP options."
+msgstr ""
+
+#: option.c:408
+#, c-format
+msgid "Specify path of PID file (defaults to %s)."
+msgstr ""
+
+#: option.c:409
+#, c-format
+msgid "Specify maximum number of DHCP leases (defaults to %s)."
+msgstr ""
+
+#: option.c:410
+msgid "Answer DNS queries based on the interface a query was sent to."
+msgstr ""
+
+#: option.c:411
+msgid "Specify TXT DNS record."
+msgstr ""
+
+#: option.c:412
+msgid "Specify PTR DNS record."
+msgstr ""
+
+#: option.c:413
+msgid "Give DNS name to IPv4 address of interface."
+msgstr ""
+
+#: option.c:414
+msgid "Bind only to interfaces in use."
+msgstr ""
+
+#: option.c:415
+#, c-format
+msgid "Read DHCP static host information from %s."
+msgstr ""
+
+#: option.c:416
+msgid "Enable the DBus interface for setting upstream servers, etc."
+msgstr ""
+
+#: option.c:417
+msgid "Do not provide DHCP on this interface, only provide DNS."
+msgstr ""
+
+#: option.c:418
+msgid "Enable dynamic address allocation for bootp."
+msgstr ""
+
+#: option.c:419
+msgid "Map MAC address (with wildcards) to option set."
+msgstr ""
+
+#: option.c:420
+msgid "Treat DHCP requests on aliases as arriving from interface."
+msgstr ""
+
+#: option.c:421
+msgid "Disable ICMP echo address checking in the DHCP server."
+msgstr ""
+
+#: option.c:422
+msgid "Shell script to run on DHCP lease creation and destruction."
+msgstr ""
+
+#: option.c:423
+msgid "Lua script to run on DHCP lease creation and destruction."
+msgstr ""
+
+#: option.c:424
+msgid "Run lease-change scripts as this user."
+msgstr ""
+
+#: option.c:425
+msgid "Call dhcp-script with changes to local ARP table."
+msgstr ""
+
+#: option.c:426
+msgid "Read configuration from all the files in this directory."
+msgstr ""
+
+#: option.c:427
+msgid "Log to this syslog facility or file. (defaults to DAEMON)"
+msgstr ""
+
+#: option.c:428
+msgid "Do not use leasefile."
+msgstr ""
+
+#: option.c:429
+#, c-format
+msgid "Maximum number of concurrent DNS queries. (defaults to %s)"
+msgstr ""
+
+#: option.c:430
+#, c-format
+msgid "Clear DNS cache when reloading %s."
+msgstr ""
+
+#: option.c:431
+msgid "Ignore hostnames provided by DHCP clients."
+msgstr ""
+
+#: option.c:432
+msgid "Do NOT reuse filename and server fields for extra DHCP options."
+msgstr ""
+
+#: option.c:433
+msgid "Enable integrated read-only TFTP server."
+msgstr ""
+
+#: option.c:434
+msgid "Export files by TFTP only from the specified subtree."
+msgstr ""
+
+#: option.c:435
+msgid "Add client IP or hardware address to tftp-root."
+msgstr ""
+
+#: option.c:436
+msgid "Allow access only to files owned by the user running dnsmasq."
+msgstr ""
+
+#: option.c:437
+msgid "Do not terminate the service if TFTP directories are inaccessible."
+msgstr ""
+
+#: option.c:438
+#, c-format
+msgid "Maximum number of concurrent TFTP transfers (defaults to %s)."
+msgstr ""
+
+#: option.c:439
+msgid "Maximum MTU to use for TFTP transfers."
+msgstr ""
+
+#: option.c:440
+msgid "Disable the TFTP blocksize extension."
+msgstr ""
+
+#: option.c:441
+msgid "Convert TFTP filenames to lowercase"
+msgstr ""
+
+#: option.c:442
+msgid "Ephemeral port range for use by TFTP transfers."
+msgstr ""
+
+#: option.c:443
+msgid "Extra logging for DHCP."
+msgstr ""
+
+#: option.c:444
+msgid "Enable async. logging; optionally set queue length."
+msgstr ""
+
+#: option.c:445
+msgid "Stop DNS rebinding. Filter private IP ranges when resolving."
+msgstr ""
+
+#: option.c:446
+msgid "Allow rebinding of 127.0.0.0/8, for RBL servers."
+msgstr ""
+
+#: option.c:447
+msgid "Inhibit DNS-rebind protection on this domain."
+msgstr ""
+
+#: option.c:448
+msgid "Always perform DNS queries to all servers."
+msgstr ""
+
+#: option.c:449
+msgid "Set tag if client includes matching option in request."
+msgstr ""
+
+#: option.c:450
+msgid "Use alternative ports for DHCP."
+msgstr ""
+
+#: option.c:451
+msgid "Specify NAPTR DNS record."
+msgstr ""
+
+#: option.c:452
+msgid "Specify lowest port available for DNS query transmission."
+msgstr ""
+
+#: option.c:453
+msgid "Specify highest port available for DNS query transmission."
+msgstr ""
+
+#: option.c:454
+msgid "Use only fully qualified domain names for DHCP clients."
+msgstr ""
+
+#: option.c:455
+msgid "Generate hostnames based on MAC address for nameless clients."
+msgstr ""
+
+#: option.c:456
+msgid "Use these DHCP relays as full proxies."
+msgstr ""
+
+#: option.c:457
+msgid "Relay DHCP requests to a remote server"
+msgstr ""
+
+#: option.c:458
+msgid "Specify alias name for LOCAL DNS name."
+msgstr ""
+
+#: option.c:459
+msgid "Prompt to send to PXE clients."
+msgstr ""
+
+#: option.c:460
+msgid "Boot service for PXE menu."
+msgstr ""
+
+#: option.c:461
+msgid "Check configuration syntax."
+msgstr ""
+
+#: option.c:462
+msgid "Add requestor's MAC address to forwarded DNS queries."
+msgstr ""
+
+#: option.c:463
+msgid "Add specified IP subnet to forwarded DNS queries."
+msgstr ""
+
+#: option.c:464
+msgid "Add client identification to forwarded DNS queries."
+msgstr ""
+
+#: option.c:465
+msgid "Proxy DNSSEC validation results from upstream nameservers."
+msgstr ""
+
+#: option.c:466
+msgid "Attempt to allocate sequential IP addresses to DHCP clients."
+msgstr ""
+
+#: option.c:467
+msgid "Copy connection-track mark from queries to upstream connections."
+msgstr ""
+
+#: option.c:468
+msgid "Allow DHCP clients to do their own DDNS updates."
+msgstr ""
+
+#: option.c:469
+msgid "Send router-advertisements for interfaces doing DHCPv6"
+msgstr ""
+
+#: option.c:470
+msgid "Specify DUID_EN-type DHCPv6 server DUID"
+msgstr ""
+
+#: option.c:471
+msgid "Specify host (A/AAAA and PTR) records"
+msgstr ""
+
+#: option.c:472
+msgid "Specify arbitrary DNS resource record"
+msgstr ""
+
+#: option.c:473
+msgid "Bind to interfaces in use - check for new interfaces"
+msgstr ""
+
+#: option.c:474
+msgid "Export local names to global DNS"
+msgstr ""
+
+#: option.c:475
+msgid "Domain to export to global DNS"
+msgstr ""
+
+#: option.c:476
+msgid "Set TTL for authoritative replies"
+msgstr ""
+
+#: option.c:477
+msgid "Set authoritative zone information"
+msgstr ""
+
+#: option.c:478
+msgid "Secondary authoritative nameservers for forward domains"
+msgstr ""
+
+#: option.c:479
+msgid "Peers which are allowed to do zone transfer"
+msgstr ""
+
+#: option.c:480
+msgid "Specify ipsets to which matching domains should be added"
+msgstr ""
+
+#: option.c:481
+msgid "Specify a domain and address range for synthesised names"
+msgstr ""
+
+#: option.c:482
+msgid "Activate DNSSEC validation"
+msgstr ""
+
+#: option.c:483
+msgid "Specify trust anchor key digest."
+msgstr ""
+
+#: option.c:484
+msgid "Disable upstream checking for DNSSEC debugging."
+msgstr ""
+
+#: option.c:485
+msgid "Ensure answers without DNSSEC are in unsigned zones."
+msgstr ""
+
+#: option.c:486
+msgid "Don't check DNSSEC signature timestamps until first cache-reload"
+msgstr ""
+
+#: option.c:487
+msgid "Timestamp file to verify system clock for DNSSEC"
+msgstr ""
+
+#: option.c:489
+msgid "Specify DHCPv6 prefix class"
+msgstr ""
+
+#: option.c:491
+msgid "Set MTU, priority, resend-interval and router-lifetime"
+msgstr ""
+
+#: option.c:492
+msgid "Do not log routine DHCP."
+msgstr ""
+
+#: option.c:493
+msgid "Do not log routine DHCPv6."
+msgstr ""
+
+#: option.c:494
+msgid "Do not log RA."
+msgstr ""
+
+#: option.c:495
+msgid "Accept queries only from directly-connected networks."
+msgstr ""
+
+#: option.c:496
+msgid "Detect and remove DNS forwarding loops."
+msgstr ""
+
+#: option.c:497
+msgid "Ignore DNS responses containing ipaddr."
+msgstr ""
+
+#: option.c:498
+msgid "Set TTL in DNS responses with DHCP-derived addresses."
+msgstr ""
+
+#: option.c:499
+msgid "Delay DHCP replies for at least number of seconds."
+msgstr ""
+
+#: option.c:703
+#, c-format
+msgid ""
+"Usage: dnsmasq [options]\n"
+"\n"
+msgstr ""
+
+#: option.c:705
+#, c-format
+msgid "Use short options only on the command line.\n"
+msgstr ""
+
+#: option.c:707
+#, c-format
+msgid "Valid options are:\n"
+msgstr ""
+
+#: option.c:754 option.c:868
+msgid "bad address"
+msgstr ""
+
+#: option.c:779 option.c:783
+msgid "bad port"
+msgstr ""
+
+#: option.c:797 option.c:826 option.c:861
+msgid "interface binding not supported"
+msgstr ""
+
+#: option.c:821 option.c:856
+msgid "interface can only be specified once"
+msgstr ""
+
+#: option.c:835 option.c:3800
+msgid "bad interface name"
+msgstr ""
+
+#: option.c:1062
+msgid "unsupported encapsulation for IPv6 option"
+msgstr ""
+
+#: option.c:1076
+msgid "bad dhcp-option"
+msgstr ""
+
+#: option.c:1144
+msgid "bad IP address"
+msgstr ""
+
+#: option.c:1147 option.c:1286 option.c:3070
+msgid "bad IPv6 address"
+msgstr ""
+
+#: option.c:1240
+msgid "bad IPv4 address"
+msgstr ""
+
+#: option.c:1313 option.c:1407
+msgid "bad domain in dhcp-option"
+msgstr ""
+
+#: option.c:1445
+msgid "dhcp-option too long"
+msgstr ""
+
+#: option.c:1452
+msgid "illegal dhcp-match"
+msgstr ""
+
+#: option.c:1514
+msgid "illegal repeated flag"
+msgstr ""
+
+#: option.c:1522
+msgid "illegal repeated keyword"
+msgstr ""
+
+#: option.c:1593 option.c:4434
+#, c-format
+msgid "cannot access directory %s: %s"
+msgstr ""
+
+#: option.c:1639 tftp.c:537
+#, c-format
+msgid "cannot access %s: %s"
+msgstr ""
+
+#: option.c:1727
+msgid "setting log facility is not possible under Android"
+msgstr ""
+
+#: option.c:1736
+msgid "bad log facility"
+msgstr ""
+
+#: option.c:1789
+msgid "bad MX preference"
+msgstr ""
+
+#: option.c:1794
+msgid "bad MX name"
+msgstr ""
+
+#: option.c:1808
+msgid "bad MX target"
+msgstr ""
+
+#: option.c:1820
+msgid "cannot run scripts under uClinux"
+msgstr ""
+
+#: option.c:1822
+msgid "recompile with HAVE_SCRIPT defined to enable lease-change scripts"
+msgstr ""
+
+#: option.c:1826
+msgid "recompile with HAVE_LUASCRIPT defined to enable Lua scripts"
+msgstr ""
+
+#: option.c:2095 option.c:2106 option.c:2143 option.c:2199 option.c:2482
+msgid "bad prefix"
+msgstr ""
+
+#: option.c:2504
+msgid "recompile with HAVE_IPSET defined to enable ipset directives"
+msgstr ""
+
+#: option.c:2713
+msgid "bad port range"
+msgstr ""
+
+#: option.c:2738
+msgid "bad bridge-interface"
+msgstr ""
+
+#: option.c:2798
+msgid "only one tag allowed"
+msgstr ""
+
+#: option.c:2818 option.c:2830 option.c:2939 option.c:2944 option.c:2983
+msgid "bad dhcp-range"
+msgstr ""
+
+#: option.c:2845
+msgid "inconsistent DHCP range"
+msgstr ""
+
+#: option.c:2907
+msgid "prefix length must be exactly 64 for RA subnets"
+msgstr ""
+
+#: option.c:2909
+msgid "prefix length must be exactly 64 for subnet constructors"
+msgstr ""
+
+#: option.c:2913
+msgid "prefix length must be at least 64"
+msgstr ""
+
+#: option.c:2916
+msgid "inconsistent DHCPv6 range"
+msgstr ""
+
+#: option.c:2927
+msgid "prefix must be zero with \"constructor:\" argument"
+msgstr ""
+
+#: option.c:3040 option.c:3088
+msgid "bad hex constant"
+msgstr ""
+
+#: option.c:3062
+msgid "cannot match tags in --dhcp-host"
+msgstr ""
+
+#: option.c:3110
+#, c-format
+msgid "duplicate dhcp-host IP address %s"
+msgstr ""
+
+#: option.c:3168
+msgid "bad DHCP host name"
+msgstr ""
+
+#: option.c:3250
+msgid "bad tag-if"
+msgstr ""
+
+#: option.c:3607 option.c:4030
+msgid "invalid port number"
+msgstr ""
+
+#: option.c:3669
+msgid "bad dhcp-proxy address"
+msgstr ""
+
+#: option.c:3695
+msgid "Bad dhcp-relay"
+msgstr ""
+
+#: option.c:3736
+msgid "bad RA-params"
+msgstr ""
+
+#: option.c:3745
+msgid "bad DUID"
+msgstr ""
+
+#: option.c:3787
+msgid "invalid alias range"
+msgstr ""
+
+#: option.c:3841 option.c:3853
+msgid "bad CNAME"
+msgstr ""
+
+#: option.c:3857
+msgid "duplicate CNAME"
+msgstr ""
+
+#: option.c:3880
+msgid "bad PTR record"
+msgstr ""
+
+#: option.c:3911
+msgid "bad NAPTR record"
+msgstr ""
+
+#: option.c:3945
+msgid "bad RR record"
+msgstr ""
+
+#: option.c:3975
+msgid "bad TXT record"
+msgstr ""
+
+#: option.c:4016
+msgid "bad SRV record"
+msgstr ""
+
+#: option.c:4023
+msgid "bad SRV target"
+msgstr ""
+
+#: option.c:4037
+msgid "invalid priority"
+msgstr ""
+
+#: option.c:4040
+msgid "invalid weight"
+msgstr ""
+
+#: option.c:4064
+msgid "Bad host-record"
+msgstr ""
+
+#: option.c:4088
+msgid "Bad name in host-record"
+msgstr ""
+
+#: option.c:4153
+msgid "bad trust anchor"
+msgstr ""
+
+#: option.c:4167
+msgid "bad HEX in trust anchor"
+msgstr ""
+
+#: option.c:4177
+msgid "unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"
+msgstr ""
+
+#: option.c:4237
+msgid "missing \""
+msgstr ""
+
+#: option.c:4294
+msgid "bad option"
+msgstr ""
+
+#: option.c:4296
+msgid "extraneous parameter"
+msgstr ""
+
+#: option.c:4298
+msgid "missing parameter"
+msgstr ""
+
+#: option.c:4300
+msgid "illegal option"
+msgstr ""
+
+#: option.c:4307
+msgid "error"
+msgstr ""
+
+#: option.c:4309
+#, c-format
+msgid " at line %d of %s"
+msgstr ""
+
+#: option.c:4324 option.c:4571 option.c:4607
+#, c-format
+msgid "read %s"
+msgstr ""
+
+#: option.c:4387 option.c:4510 tftp.c:715
+#, c-format
+msgid "cannot read %s: %s"
+msgstr ""
+
+#: option.c:4676
+msgid "junk found in command line"
+msgstr ""
+
+#: option.c:4711
+#, c-format
+msgid "Dnsmasq version %s  %s\n"
+msgstr ""
+
+#: option.c:4712
+#, c-format
+msgid ""
+"Compile time options: %s\n"
+"\n"
+msgstr ""
+
+#: option.c:4713
+#, c-format
+msgid "This software comes with ABSOLUTELY NO WARRANTY.\n"
+msgstr ""
+
+#: option.c:4714
+#, c-format
+msgid "Dnsmasq is free software, and you are welcome to redistribute it\n"
+msgstr ""
+
+#: option.c:4715
+#, c-format
+msgid "under the terms of the GNU General Public License, version 2 or 3.\n"
+msgstr ""
+
+#: option.c:4726
+msgid "try --help"
+msgstr ""
+
+#: option.c:4728
+msgid "try -w"
+msgstr ""
+
+#: option.c:4730
+#, c-format
+msgid "bad command line options: %s"
+msgstr ""
+
+#: option.c:4798
+#, c-format
+msgid "CNAME loop involving %s"
+msgstr ""
+
+#: option.c:4834
+#, c-format
+msgid "cannot get host-name: %s"
+msgstr ""
+
+#: option.c:4862
+msgid "only one resolv.conf file allowed in no-poll mode."
+msgstr ""
+
+#: option.c:4872
+msgid "must have exactly one resolv.conf to read domain from."
+msgstr ""
+
+#: option.c:4875 network.c:1612 dhcp.c:816
+#, c-format
+msgid "failed to read %s: %s"
+msgstr ""
+
+#: option.c:4892
+#, c-format
+msgid "no search directive found in %s"
+msgstr ""
+
+#: option.c:4913
+msgid "there must be a default domain when --dhcp-fqdn is set"
+msgstr ""
+
+#: option.c:4922
+msgid "syntax check OK"
+msgstr ""
+
+#: forward.c:102
+#, c-format
+msgid "failed to send packet: %s"
+msgstr ""
+
+#: forward.c:597
+msgid "discarding DNS reply: subnet option mismatch"
+msgstr ""
+
+#: forward.c:651
+#, c-format
+msgid "nameserver %s refused to do a recursive query"
+msgstr ""
+
+#: forward.c:683
+#, c-format
+msgid "possible DNS-rebind attack detected: %s"
+msgstr ""
+
+#: forward.c:1244 forward.c:1681
+msgid "Ignoring query from non-local network"
+msgstr ""
+
+#: forward.c:2166
+#, c-format
+msgid "Maximum number of concurrent DNS queries reached (max: %d)"
+msgstr ""
+
+#: network.c:720
+#, c-format
+msgid "failed to create listening socket for %s: %s"
+msgstr ""
+
+#: network.c:1031
+#, c-format
+msgid "LOUD WARNING: listening on %s may accept requests via interfaces other than %s"
+msgstr ""
+
+#: network.c:1038
+msgid "LOUD WARNING: use --bind-dynamic rather than --bind-interfaces to avoid DNS amplification attacks via these interface(s)"
+msgstr ""
+
+#: network.c:1047
+#, c-format
+msgid "warning: using interface %s instead"
+msgstr ""
+
+#: network.c:1056
+#, c-format
+msgid "warning: no addresses found for interface %s"
+msgstr ""
+
+#: network.c:1114
+#, c-format
+msgid "interface %s failed to join DHCPv6 multicast group: %s"
+msgstr ""
+
+#: network.c:1119
+msgid "try increasing /proc/sys/net/core/optmem_max"
+msgstr ""
+
+#: network.c:1322
+#, c-format
+msgid "failed to bind server socket for %s: %s"
+msgstr ""
+
+#: network.c:1517
+#, c-format
+msgid "ignoring nameserver %s - local interface"
+msgstr ""
+
+#: network.c:1528
+#, c-format
+msgid "ignoring nameserver %s - cannot make/bind socket: %s"
+msgstr ""
+
+#: network.c:1548
+msgid "(no DNSSEC)"
+msgstr ""
+
+#: network.c:1551
+msgid "unqualified"
+msgstr ""
+
+#: network.c:1551
+msgid "names"
+msgstr ""
+
+#: network.c:1553
+msgid "default"
+msgstr ""
+
+#: network.c:1555
+msgid "domain"
+msgstr ""
+
+#: network.c:1561
+#, c-format
+msgid "using local addresses only for %s %s"
+msgstr ""
+
+#: network.c:1564
+#, c-format
+msgid "using standard nameservers for %s %s"
+msgstr ""
+
+#: network.c:1566
+#, c-format
+msgid "using nameserver %s#%d for %s %s %s"
+msgstr ""
+
+#: network.c:1570
+#, c-format
+msgid "NOT using nameserver %s#%d - query loop detected"
+msgstr ""
+
+#: network.c:1573
+#, c-format
+msgid "using nameserver %s#%d(via %s)"
+msgstr ""
+
+#: network.c:1575
+#, c-format
+msgid "using nameserver %s#%d"
+msgstr ""
+
+#: network.c:1580
+#, c-format
+msgid "using %d more local addresses"
+msgstr ""
+
+#: network.c:1582
+#, c-format
+msgid "using %d more nameservers"
+msgstr ""
+
+#: dnsmasq.c:166
+msgid "dhcp-hostsdir, dhcp-optsdir and hostsdir are not supported on this platform"
+msgstr ""
+
+#: dnsmasq.c:181
+msgid "no root trust anchor provided for DNSSEC"
+msgstr ""
+
+#: dnsmasq.c:184
+msgid "cannot reduce cache size from default when DNSSEC enabled"
+msgstr ""
+
+#: dnsmasq.c:186
+msgid "DNSSEC not available: set HAVE_DNSSEC in src/config.h"
+msgstr ""
+
+#: dnsmasq.c:192
+msgid "TFTP server not available: set HAVE_TFTP in src/config.h"
+msgstr ""
+
+#: dnsmasq.c:197
+msgid "cannot use --conntrack AND --query-port"
+msgstr ""
+
+#: dnsmasq.c:200
+msgid "conntrack support not available: set HAVE_CONNTRACK in src/config.h"
+msgstr ""
+
+#: dnsmasq.c:205
+msgid "asynchronous logging is not available under Solaris"
+msgstr ""
+
+#: dnsmasq.c:210
+msgid "asynchronous logging is not available under Android"
+msgstr ""
+
+#: dnsmasq.c:215
+msgid "authoritative DNS not available: set HAVE_AUTH in src/config.h"
+msgstr ""
+
+#: dnsmasq.c:220
+msgid "loop detection not available: set HAVE_LOOP in src/config.h"
+msgstr ""
+
+#: dnsmasq.c:227
+msgid "max_port cannot be smaller than min_port"
+msgstr ""
+
+#: dnsmasq.c:234
+msgid "zone serial must be configured in --auth-soa"
+msgstr ""
+
+#: dnsmasq.c:252
+msgid "dhcp-range constructor not available on this platform"
+msgstr ""
+
+#: dnsmasq.c:298
+msgid "cannot set --bind-interfaces and --bind-dynamic"
+msgstr ""
+
+#: dnsmasq.c:301
+#, c-format
+msgid "failed to find list of interfaces: %s"
+msgstr ""
+
+#: dnsmasq.c:310
+#, c-format
+msgid "unknown interface %s"
+msgstr ""
+
+#: dnsmasq.c:374 dnsmasq.c:1037
+#, c-format
+msgid "DBus error: %s"
+msgstr ""
+
+#: dnsmasq.c:377
+msgid "DBus not available: set HAVE_DBUS in src/config.h"
+msgstr ""
+
+#: dnsmasq.c:405
+#, c-format
+msgid "unknown user or group: %s"
+msgstr ""
+
+#: dnsmasq.c:460
+#, c-format
+msgid "cannot chdir to filesystem root: %s"
+msgstr ""
+
+#: dnsmasq.c:716
+#, c-format
+msgid "started, version %s DNS disabled"
+msgstr ""
+
+#: dnsmasq.c:720
+#, c-format
+msgid "started, version %s cachesize %d"
+msgstr ""
+
+#: dnsmasq.c:722
+#, c-format
+msgid "started, version %s cache disabled"
+msgstr ""
+
+#: dnsmasq.c:725
+msgid "DNS service limited to local subnets"
+msgstr ""
+
+#: dnsmasq.c:728
+#, c-format
+msgid "compile time options: %s"
+msgstr ""
+
+#: dnsmasq.c:734
+msgid "DBus support enabled: connected to system bus"
+msgstr ""
+
+#: dnsmasq.c:736
+msgid "DBus support enabled: bus connection pending"
+msgstr ""
+
+#: dnsmasq.c:754
+msgid "DNSSEC validation enabled"
+msgstr ""
+
+#: dnsmasq.c:758
+msgid "DNSSEC signature timestamps not checked until first cache reload"
+msgstr ""
+
+#: dnsmasq.c:761
+msgid "DNSSEC signature timestamps not checked until system time valid"
+msgstr ""
+
+#: dnsmasq.c:766
+#, c-format
+msgid "warning: failed to change owner of %s: %s"
+msgstr ""
+
+#: dnsmasq.c:770
+msgid "setting --bind-interfaces option because of OS limitations"
+msgstr ""
+
+#: dnsmasq.c:782
+#, c-format
+msgid "warning: interface %s does not currently exist"
+msgstr ""
+
+#: dnsmasq.c:787
+msgid "warning: ignoring resolv-file flag because no-resolv is set"
+msgstr ""
+
+#: dnsmasq.c:790
+msgid "warning: no upstream servers configured"
+msgstr ""
+
+#: dnsmasq.c:794
+#, c-format
+msgid "asynchronous logging enabled, queue limit is %d messages"
+msgstr ""
+
+#: dnsmasq.c:815
+msgid "IPv6 router advertisement enabled"
+msgstr ""
+
+#: dnsmasq.c:820
+#, c-format
+msgid "DHCP, sockets bound exclusively to interface %s"
+msgstr ""
+
+#: dnsmasq.c:834
+msgid "root is "
+msgstr ""
+
+#: dnsmasq.c:834
+msgid "enabled"
+msgstr ""
+
+#: dnsmasq.c:836
+msgid "secure mode"
+msgstr ""
+
+#: dnsmasq.c:839
+#, c-format
+msgid "warning: %s inaccessible"
+msgstr ""
+
+#: dnsmasq.c:843
+#, c-format
+msgid "warning: TFTP directory %s inaccessible"
+msgstr ""
+
+#: dnsmasq.c:869
+#, c-format
+msgid "restricting maximum simultaneous TFTP transfers to %d"
+msgstr ""
+
+#: dnsmasq.c:1039
+msgid "connected to system DBus"
+msgstr ""
+
+#: dnsmasq.c:1189
+#, c-format
+msgid "cannot fork into background: %s"
+msgstr ""
+
+#: dnsmasq.c:1192
+#, c-format
+msgid "failed to create helper: %s"
+msgstr ""
+
+#: dnsmasq.c:1195
+#, c-format
+msgid "setting capabilities failed: %s"
+msgstr ""
+
+#: dnsmasq.c:1198
+#, c-format
+msgid "failed to change user-id to %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1201
+#, c-format
+msgid "failed to change group-id to %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1204
+#, c-format
+msgid "failed to open pidfile %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1207
+#, c-format
+msgid "cannot open log %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1210
+#, c-format
+msgid "failed to load Lua script: %s"
+msgstr ""
+
+#: dnsmasq.c:1213
+#, c-format
+msgid "TFTP directory %s inaccessible: %s"
+msgstr ""
+
+#: dnsmasq.c:1216
+#, c-format
+msgid "cannot create timestamp file %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1239
+msgid "now checking DNSSEC signature timestamps"
+msgstr ""
+
+#: dnsmasq.c:1307
+#, c-format
+msgid "script process killed by signal %d"
+msgstr ""
+
+#: dnsmasq.c:1311
+#, c-format
+msgid "script process exited with status %d"
+msgstr ""
+
+#: dnsmasq.c:1315
+#, c-format
+msgid "failed to execute %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1379 dnssec.c:479 dnssec.c:525
+#, c-format
+msgid "failed to update mtime on %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1386
+msgid "exiting on receipt of SIGTERM"
+msgstr ""
+
+#: dnsmasq.c:1414
+#, c-format
+msgid "failed to access %s: %s"
+msgstr ""
+
+#: dnsmasq.c:1444
+#, c-format
+msgid "reading %s"
+msgstr ""
+
+#: dnsmasq.c:1455
+#, c-format
+msgid "no servers found in %s, will retry"
+msgstr ""
+
+#: dhcp.c:53
+#, c-format
+msgid "cannot create DHCP socket: %s"
+msgstr ""
+
+#: dhcp.c:68
+#, c-format
+msgid "failed to set options on DHCP socket: %s"
+msgstr ""
+
+#: dhcp.c:89
+#, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"
+msgstr ""
+
+#: dhcp.c:101
+#, c-format
+msgid "failed to bind DHCP server socket: %s"
+msgstr ""
+
+#: dhcp.c:127
+#, c-format
+msgid "cannot create ICMP raw socket: %s."
+msgstr ""
+
+#: dhcp.c:252 dhcp6.c:173
+#, c-format
+msgid "unknown interface %s in bridge-interface"
+msgstr ""
+
+#: dhcp.c:293
+#, c-format
+msgid "DHCP packet received on %s which has no address"
+msgstr ""
+
+#: dhcp.c:427
+#, c-format
+msgid "ARP-cache injection failed: %s"
+msgstr ""
+
+#: dhcp.c:470
+#, c-format
+msgid "Error sending DHCP packet to %s: %s"
+msgstr ""
+
+#: dhcp.c:531
+#, c-format
+msgid "DHCP range %s -- %s is not consistent with netmask %s"
+msgstr ""
+
+#: dhcp.c:854
+#, c-format
+msgid "bad line at %s line %d"
+msgstr ""
+
+#: dhcp.c:897
+#, c-format
+msgid "ignoring %s line %d, duplicate name or IP address"
+msgstr ""
+
+#: dhcp.c:1041 rfc3315.c:2149
+#, c-format
+msgid "DHCP relay %s -> %s"
+msgstr ""
+
+#: lease.c:98
+msgid "too many stored leases"
+msgstr ""
+
+#: lease.c:166
+#, c-format
+msgid "cannot open or create lease file %s: %s"
+msgstr ""
+
+#: lease.c:175
+#, c-format
+msgid "failed to parse lease database, invalid line: %s %s %s %s ..."
+msgstr ""
+
+#: lease.c:180
+#, c-format
+msgid "failed to read lease file %s: %s"
+msgstr ""
+
+#: lease.c:196
+#, c-format
+msgid "cannot run lease-init script %s: %s"
+msgstr ""
+
+#: lease.c:202
+#, c-format
+msgid "lease-init script returned exit code %s"
+msgstr ""
+
+#: lease.c:373
+#, c-format
+msgid "failed to write %s: %s (retry in %us)"
+msgstr ""
+
+#: lease.c:937
+#, c-format
+msgid "Ignoring domain %s for DHCP host name %s"
+msgstr ""
+
+#: rfc2131.c:347
+#, c-format
+msgid "no address range available for DHCP request %s %s"
+msgstr ""
+
+#: rfc2131.c:348
+msgid "with subnet selector"
+msgstr ""
+
+#: rfc2131.c:348
+msgid "via"
+msgstr ""
+
+#: rfc2131.c:360
+#, c-format
+msgid "%u available DHCP subnet: %s/%s"
+msgstr ""
+
+#: rfc2131.c:363 rfc3315.c:306
+#, c-format
+msgid "%u available DHCP range: %s -- %s"
+msgstr ""
+
+#: rfc2131.c:474
+#, c-format
+msgid "%u vendor class: %s"
+msgstr ""
+
+#: rfc2131.c:476
+#, c-format
+msgid "%u user class: %s"
+msgstr ""
+
+#: rfc2131.c:510
+msgid "disabled"
+msgstr ""
+
+#: rfc2131.c:551 rfc2131.c:1006 rfc2131.c:1430 rfc3315.c:616 rfc3315.c:869
+#: rfc3315.c:1148
+msgid "ignored"
+msgstr ""
+
+#: rfc2131.c:566 rfc2131.c:1239 rfc3315.c:919
+msgid "address in use"
+msgstr ""
+
+#: rfc2131.c:580 rfc2131.c:1060
+msgid "no address available"
+msgstr ""
+
+#: rfc2131.c:587 rfc2131.c:1202
+msgid "wrong network"
+msgstr ""
+
+#: rfc2131.c:602
+msgid "no address configured"
+msgstr ""
+
+#: rfc2131.c:608 rfc2131.c:1252
+msgid "no leases left"
+msgstr ""
+
+#: rfc2131.c:703 rfc3315.c:482
+#, c-format
+msgid "%u client provides name: %s"
+msgstr ""
+
+#: rfc2131.c:808
+msgid "PXE BIS not supported"
+msgstr ""
+
+#: rfc2131.c:974 rfc3315.c:1242
+#, c-format
+msgid "disabling DHCP static address %s for %s"
+msgstr ""
+
+#: rfc2131.c:995
+msgid "unknown lease"
+msgstr ""
+
+#: rfc2131.c:1029
+#, c-format
+msgid "not using configured address %s because it is leased to %s"
+msgstr ""
+
+#: rfc2131.c:1039
+#, c-format
+msgid "not using configured address %s because it is in use by the server or relay"
+msgstr ""
+
+#: rfc2131.c:1042
+#, c-format
+msgid "not using configured address %s because it was previously declined"
+msgstr ""
+
+#: rfc2131.c:1058 rfc2131.c:1245
+msgid "no unique-id"
+msgstr ""
+
+#: rfc2131.c:1140
+msgid "wrong server-ID"
+msgstr ""
+
+#: rfc2131.c:1159
+msgid "wrong address"
+msgstr ""
+
+#: rfc2131.c:1177 rfc3315.c:1015
+msgid "lease not found"
+msgstr ""
+
+#: rfc2131.c:1210
+msgid "address not available"
+msgstr ""
+
+#: rfc2131.c:1221
+msgid "static lease available"
+msgstr ""
+
+#: rfc2131.c:1225
+msgid "address reserved"
+msgstr ""
+
+#: rfc2131.c:1233
+#, c-format
+msgid "abandoning lease to %s of %s"
+msgstr ""
+
+#: rfc2131.c:1757
+#, c-format
+msgid "%u bootfile name: %s"
+msgstr ""
+
+#: rfc2131.c:1766
+#, c-format
+msgid "%u server name: %s"
+msgstr ""
+
+#: rfc2131.c:1774
+#, c-format
+msgid "%u next server: %s"
+msgstr ""
+
+#: rfc2131.c:1777
+#, c-format
+msgid "%u broadcast response"
+msgstr ""
+
+#: rfc2131.c:1840
+#, c-format
+msgid "cannot send DHCP/BOOTP option %d: no space left in packet"
+msgstr ""
+
+#: rfc2131.c:2131
+msgid "PXE menu too large"
+msgstr ""
+
+#: rfc2131.c:2270 rfc3315.c:1515
+#, c-format
+msgid "%u requested options: %s"
+msgstr ""
+
+#: rfc2131.c:2587
+#, c-format
+msgid "cannot send RFC3925 option: too many options for enterprise number %d"
+msgstr ""
+
+#: rfc2131.c:2650
+#, c-format
+msgid "%u reply delay: %d"
+msgstr ""
+
+#: netlink.c:77
+#, c-format
+msgid "cannot create netlink socket: %s"
+msgstr ""
+
+#: netlink.c:355
+#, c-format
+msgid "netlink returns error: %s"
+msgstr ""
+
+#: dbus.c:186
+msgid "attempt to set an IPv6 server address via DBus - no IPv6 support"
+msgstr ""
+
+#: dbus.c:439
+#, c-format
+msgid "Enabling --%s option from D-Bus"
+msgstr ""
+
+#: dbus.c:444
+#, c-format
+msgid "Disabling --%s option from D-Bus"
+msgstr ""
+
+#: dbus.c:690
+msgid "setting upstream servers from DBus"
+msgstr ""
+
+#: dbus.c:737
+msgid "could not register a DBus message handler"
+msgstr ""
+
+#: bpf.c:265
+#, c-format
+msgid "cannot create DHCP BPF socket: %s"
+msgstr ""
+
+#: bpf.c:293
+#, c-format
+msgid "DHCP request for unsupported hardware type (%d) received on %s"
+msgstr ""
+
+#: bpf.c:378
+#, c-format
+msgid "cannot create PF_ROUTE socket: %s"
+msgstr ""
+
+#: bpf.c:399
+msgid "Unknown protocol version from route socket"
+msgstr ""
+
+#: helper.c:153
+msgid "lease() function missing in Lua script"
+msgstr ""
+
+#: tftp.c:319
+msgid "unable to get free port for TFTP"
+msgstr ""
+
+#: tftp.c:335
+#, c-format
+msgid "unsupported request from %s"
+msgstr ""
+
+#: tftp.c:483
+#, c-format
+msgid "file %s not found"
+msgstr ""
+
+#: tftp.c:592
+#, c-format
+msgid "error %d %s received from %s"
+msgstr ""
+
+#: tftp.c:634
+#, c-format
+msgid "failed sending %s to %s"
+msgstr ""
+
+#: tftp.c:634
+#, c-format
+msgid "sent %s to %s"
+msgstr ""
+
+#: log.c:190
+#, c-format
+msgid "overflow: %d log entries lost"
+msgstr ""
+
+#: log.c:268
+#, c-format
+msgid "log failed: %s"
+msgstr ""
+
+#: log.c:471
+msgid "FAILED to start up"
+msgstr ""
+
+#: conntrack.c:65
+#, c-format
+msgid "Conntrack connection mark retrieval failed: %s"
+msgstr ""
+
+#: dhcp6.c:52
+#, c-format
+msgid "cannot create DHCPv6 socket: %s"
+msgstr ""
+
+#: dhcp6.c:73
+#, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"
+msgstr ""
+
+#: dhcp6.c:85
+#, c-format
+msgid "failed to bind DHCPv6 server socket: %s"
+msgstr ""
+
+#: rfc3315.c:157
+#, c-format
+msgid "no address range available for DHCPv6 request from relay at %s"
+msgstr ""
+
+#: rfc3315.c:166
+#, c-format
+msgid "no address range available for DHCPv6 request via %s"
+msgstr ""
+
+#: rfc3315.c:303
+#, c-format
+msgid "%u available DHCPv6 subnet: %s/%d"
+msgstr ""
+
+#: rfc3315.c:386
+#, c-format
+msgid "%u vendor class: %u"
+msgstr ""
+
+#: rfc3315.c:434
+#, c-format
+msgid "%u client MAC address: %s"
+msgstr ""
+
+#: rfc3315.c:673
+#, c-format
+msgid "unknown prefix-class %d"
+msgstr ""
+
+#: rfc3315.c:816 rfc3315.c:911
+msgid "address unavailable"
+msgstr ""
+
+#: rfc3315.c:828 rfc3315.c:959 rfc3315.c:1292
+msgid "success"
+msgstr ""
+
+#: rfc3315.c:843 rfc3315.c:852 rfc3315.c:967 rfc3315.c:969
+msgid "no addresses available"
+msgstr ""
+
+#: rfc3315.c:946
+msgid "not on link"
+msgstr ""
+
+#: rfc3315.c:1019 rfc3315.c:1204 rfc3315.c:1281
+msgid "no binding found"
+msgstr ""
+
+#: rfc3315.c:1057
+msgid "deprecated"
+msgstr ""
+
+#: rfc3315.c:1062
+msgid "address invalid"
+msgstr ""
+
+#: rfc3315.c:1109
+msgid "confirm failed"
+msgstr ""
+
+#: rfc3315.c:1125
+msgid "all addresses still on link"
+msgstr ""
+
+#: rfc3315.c:1213
+msgid "release received"
+msgstr ""
+
+#: rfc3315.c:2140
+msgid "Cannot multicast to DHCPv6 server without correct interface"
+msgstr ""
+
+#: dhcp-common.c:145
+#, c-format
+msgid "Ignoring duplicate dhcp-option %d"
+msgstr ""
+
+#: dhcp-common.c:222
+#, c-format
+msgid "%u tags: %s"
+msgstr ""
+
+#: dhcp-common.c:407
+#, c-format
+msgid "%s has more than one address in hostsfile, using %s for DHCP"
+msgstr ""
+
+#: dhcp-common.c:430
+#, c-format
+msgid "duplicate IP address %s (%s) in dhcp-config directive"
+msgstr ""
+
+#: dhcp-common.c:494
+#, c-format
+msgid "failed to set SO_BINDTODEVICE on DHCP socket: %s"
+msgstr ""
+
+#: dhcp-common.c:615
+#, c-format
+msgid "Known DHCP options:\n"
+msgstr ""
+
+#: dhcp-common.c:626
+#, c-format
+msgid "Known DHCPv6 options:\n"
+msgstr ""
+
+#: dhcp-common.c:823
+msgid ", prefix deprecated"
+msgstr ""
+
+#: dhcp-common.c:826
+#, c-format
+msgid ", lease time "
+msgstr ""
+
+#: dhcp-common.c:868
+#, c-format
+msgid "%s stateless on %s%.0s%.0s%s"
+msgstr ""
+
+#: dhcp-common.c:870
+#, c-format
+msgid "%s, static leases only on %.0s%s%s%.0s"
+msgstr ""
+
+#: dhcp-common.c:872
+#, c-format
+msgid "%s, proxy on subnet %.0s%s%.0s%.0s"
+msgstr ""
+
+#: dhcp-common.c:873
+#, c-format
+msgid "%s, IP range %s -- %s%s%.0s"
+msgstr ""
+
+#: dhcp-common.c:886
+#, c-format
+msgid "DHCPv4-derived IPv6 names on %s%s"
+msgstr ""
+
+#: dhcp-common.c:889
+#, c-format
+msgid "router advertisement on %s%s"
+msgstr ""
+
+#: dhcp-common.c:900
+#, c-format
+msgid "DHCP relay from %s to %s via %s"
+msgstr ""
+
+#: dhcp-common.c:902
+#, c-format
+msgid "DHCP relay from %s to %s"
+msgstr ""
+
+#: radv.c:110
+#, c-format
+msgid "cannot create ICMPv6 socket: %s"
+msgstr ""
+
+#: auth.c:449
+#, c-format
+msgid "ignoring zone transfer request from %s"
+msgstr ""
+
+#: ipset.c:95
+#, c-format
+msgid "failed to find kernel version: %s"
+msgstr ""
+
+#: ipset.c:114
+#, c-format
+msgid "failed to create IPset control socket: %s"
+msgstr ""
+
+#: ipset.c:233
+#, c-format
+msgid "failed to update ipset %s: %s"
+msgstr ""
+
+#: dnssec.c:527
+msgid "system time considered valid, now checking DNSSEC signature timestamps."
+msgstr ""
+
+#: blockdata.c:58
+#, c-format
+msgid "DNSSEC memory in use %u, max %u, allocated %u"
+msgstr ""
+
+#: tables.c:61
+#, c-format
+msgid "failed to access pf devices: %s"
+msgstr ""
+
+#: tables.c:74
+#, c-format
+msgid "warning: no opened pf devices %s"
+msgstr ""
+
+#: tables.c:82
+#, c-format
+msgid "error: cannot use table name %s"
+msgstr ""
+
+#: tables.c:90
+#, c-format
+msgid "error: cannot strlcpy table name %s"
+msgstr ""
+
+#: tables.c:101
+#, c-format
+msgid "IPset: error:%s"
+msgstr ""
+
+#: tables.c:108
+msgid "info: table created"
+msgstr ""
+
+#: tables.c:134
+#, c-format
+msgid "warning: DIOCR%sADDRS: %s"
+msgstr ""
+
+#: tables.c:138
+#, c-format
+msgid "%d addresses %s"
+msgstr ""
+
+#: inotify.c:62
+#, c-format
+msgid "cannot access path %s: %s"
+msgstr ""
+
+#: inotify.c:95
+#, c-format
+msgid "failed to create inotify: %s"
+msgstr ""
+
+#: inotify.c:111
+#, c-format
+msgid "too many symlinks following %s"
+msgstr ""
+
+#: inotify.c:127
+#, c-format
+msgid "directory %s for resolv-file is missing, cannot poll"
+msgstr ""
+
+#: inotify.c:131 inotify.c:168
+#, c-format
+msgid "failed to create inotify for %s: %s"
+msgstr ""
+
+#: inotify.c:153
+#, c-format
+msgid "bad dynamic directory %s: %s"
+msgstr ""
+
+#: inotify.c:255
+#, c-format
+msgid "inotify, new or changed file %s"
+msgstr ""
diff --git a/po/ro.po b/po/ro.po
new file mode 100755
index 0000000..fa29557
--- /dev/null
+++ b/po/ro.po
@@ -0,0 +1,2365 @@
+# Romanian translations for dnsmasq package.
+# This file is put in the public domain.
+# Simon Kelley <simon@thekelleys.org.uk>, 2005.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: dnsmasq 2.24\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-06-18 12:24+0100\n"
+"PO-Revision-Date: 2017-07-17 18:30+0100\n"
+"Last-Translator: Simon Kelley <simon@thekelleys.org.uk>\n"
+"Language-Team: Romanian <translation-team-ro@lists.sourceforge.net>\n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: cache.c:513
+msgid "Internal error in cache."
+msgstr ""
+
+# for compatibility purposes the letters â, ă, ş, ţ and î can be written as their look-alike correspondent.
+#: cache.c:923
+#, fuzzy, c-format
+msgid "failed to load names from %s: %s"
+msgstr "încărcarea numelor din %s: %s a eşuat"
+
+#: cache.c:949 dhcp.c:867
+#, c-format
+msgid "bad address at %s line %d"
+msgstr "adresă greşită în %s, linia %d"
+
+#: cache.c:1002 dhcp.c:883
+#, c-format
+msgid "bad name at %s line %d"
+msgstr "nume greşit în %s linia %d"
+
+#: cache.c:1011 dhcp.c:958
+#, c-format
+msgid "read %s - %d addresses"
+msgstr "citesc %s - %d adrese"
+
+#: cache.c:1124
+msgid "cleared cache"
+msgstr "memoria temporară a fost ştearsă"
+
+#: cache.c:1153
+#, c-format
+msgid "No IPv4 address found for %s"
+msgstr ""
+
+#: cache.c:1232
+#, c-format
+msgid "%s is a CNAME, not giving it to the DHCP lease of %s"
+msgstr ""
+
+#: cache.c:1256
+#, c-format
+msgid "not giving name %s to the DHCP lease of %s because the name exists in %s with address %s"
+msgstr "nu pot da numele %s împrumutului de adresă DHCP a lui %s deoarece numeleexistă în %s cu adresa %s"
+
+#: cache.c:1413
+#, c-format
+msgid "time %lu"
+msgstr ""
+
+#: cache.c:1414
+#, fuzzy, c-format
+msgid "cache size %d, %d/%d cache insertions re-used unexpired cache entries."
+msgstr "cantitate de memorie temporară %d, %d/%d stocări temporare aureutilizat locaţii neexpirate."
+
+#: cache.c:1416
+#, c-format
+msgid "queries forwarded %u, queries answered locally %u"
+msgstr ""
+
+#: cache.c:1419
+#, c-format
+msgid "queries for authoritative zones %u"
+msgstr ""
+
+#: cache.c:1445
+#, c-format
+msgid "server %s#%d: queries sent %u, retried or failed %u"
+msgstr ""
+
+#: util.c:47
+#, fuzzy, c-format
+msgid "failed to seed the random number generator: %s"
+msgstr "ascultarea pe socket a eşuat: %s"
+
+#: util.c:224
+#, fuzzy
+msgid "failed to allocate memory"
+msgstr "nu pot încărca %d bytes"
+
+#: util.c:277 option.c:619
+msgid "could not get memory"
+msgstr "nu am putut aloca memorie"
+
+#: util.c:287
+#, fuzzy, c-format
+msgid "cannot create pipe: %s"
+msgstr "nu pot citi %s: %s"
+
+#: util.c:295
+#, fuzzy, c-format
+msgid "failed to allocate %d bytes"
+msgstr "nu pot încărca %d bytes"
+
+#: util.c:464
+#, c-format
+msgid "infinite"
+msgstr "infinit"
+
+#: option.c:344
+msgid "Specify local address(es) to listen on."
+msgstr "Specificaţi adresele locale deservite."
+
+#: option.c:345
+msgid "Return ipaddr for all hosts in specified domains."
+msgstr "Afişează adresele IP ale maşinilor în domeniul dat."
+
+#: option.c:346
+msgid "Fake reverse lookups for RFC1918 private address ranges."
+msgstr "Simulează căutări după adresă pentru domenii de adresă private (RFC1918)."
+
+#: option.c:347
+msgid "Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."
+msgstr "Interpretează adresa IP ca NXDOMAIN (împotriva manipulărilor Verisign)"
+
+#: option.c:348
+#, c-format
+msgid "Specify the size of the cache in entries (defaults to %s)."
+msgstr "Specifică mărimea înregistrărilor temporare (implicit e %s)."
+
+#: option.c:349
+#, c-format
+msgid "Specify configuration file (defaults to %s)."
+msgstr "Specifică fişier de configurare (implicit e %s)."
+
+#: option.c:350
+msgid "Do NOT fork into the background: run in debug mode."
+msgstr "NU porneşte în fundal: rulează în modul depanare."
+
+#: option.c:351
+msgid "Do NOT forward queries with no domain part."
+msgstr "NU înainta cererile ce nu conţin domeniu DNS."
+
+#: option.c:352
+msgid "Return self-pointing MX records for local hosts."
+msgstr "Răspunde cu înregistrări MX spre el însuşi pentru maşini locale."
+
+#: option.c:353
+msgid "Expand simple names in /etc/hosts with domain-suffix."
+msgstr "Adaugă numelor simple din /etc/hosts numele domeniului ca sufix."
+
+#: option.c:354
+msgid "Don't forward spurious DNS requests from Windows hosts."
+msgstr "Nu inainta cereri DNS defecte provenite de la maşini Windows."
+
+#: option.c:355
+msgid "Enable DHCP in the range given with lease duration."
+msgstr "Activează DHCP în domeniul dat cu durată limitată de împrumut."
+
+#: option.c:356
+#, c-format
+msgid "Change to this group after startup (defaults to %s)."
+msgstr "Rulează sub acest grup după pornire (implicit e %s)."
+
+#: option.c:357
+msgid "Set address or hostname for a specified machine."
+msgstr "Schimbă adresa sau numele maşinii specificate."
+
+#: option.c:358
+#, fuzzy
+msgid "Read DHCP host specs from file."
+msgstr "nume MX invalid"
+
+#: option.c:359
+msgid "Read DHCP option specs from file."
+msgstr ""
+
+#: option.c:360
+#, fuzzy
+msgid "Read DHCP host specs from a directory."
+msgstr "nume MX invalid"
+
+#: option.c:361
+#, fuzzy
+msgid "Read DHCP options from a directory."
+msgstr "nume MX invalid"
+
+#: option.c:362
+msgid "Evaluate conditional tag expression."
+msgstr ""
+
+#: option.c:363
+#, c-format
+msgid "Do NOT load %s file."
+msgstr "Nu încarcă fişierul %s."
+
+#: option.c:364
+#, c-format
+msgid "Specify a hosts file to be read in addition to %s."
+msgstr "Specifică spre citire un fişier hosts adiţional la %s."
+
+#: option.c:365
+#, fuzzy
+msgid "Read hosts files from a directory."
+msgstr "nume MX invalid"
+
+#: option.c:366
+msgid "Specify interface(s) to listen on."
+msgstr "Specifică interfeţele deservite."
+
+#: option.c:367
+msgid "Specify interface(s) NOT to listen on."
+msgstr "Specifică interfeţele NE-deservite."
+
+#: option.c:368
+#, fuzzy
+msgid "Map DHCP user class to tag."
+msgstr "Leagă clasa de utilizator DHCP cu grup de opţiuni."
+
+#: option.c:369
+msgid "Map RFC3046 circuit-id to tag."
+msgstr ""
+
+#: option.c:370
+msgid "Map RFC3046 remote-id to tag."
+msgstr ""
+
+#: option.c:371
+msgid "Map RFC3993 subscriber-id to tag."
+msgstr ""
+
+#: option.c:372
+#, fuzzy
+msgid "Don't do DHCP for hosts with tag set."
+msgstr "Nu furniza DHCP maşinilor din grupul de opţiuni."
+
+#: option.c:373
+#, fuzzy
+msgid "Force broadcast replies for hosts with tag set."
+msgstr "Nu furniza DHCP maşinilor din grupul de opţiuni."
+
+#: option.c:374
+msgid "Do NOT fork into the background, do NOT run in debug mode."
+msgstr "NU porneşte în fundal, NU rulează în modul depanare."
+
+#: option.c:375
+msgid "Assume we are the only DHCP server on the local network."
+msgstr "Presupune că suntem singurul server DHCP din reţeaua locală."
+
+#: option.c:376
+#, c-format
+msgid "Specify where to store DHCP leases (defaults to %s)."
+msgstr "Specifică fişierul de stocare a împrumuturilor DHCP (implicit e %s)."
+
+#: option.c:377
+msgid "Return MX records for local hosts."
+msgstr "Răspunde cu întregistrări MX pentru maşini locale."
+
+#: option.c:378
+msgid "Specify an MX record."
+msgstr "Specifică o înregistrare MX."
+
+#: option.c:379
+msgid "Specify BOOTP options to DHCP server."
+msgstr "Specifică opţiuni BOOTP serverului DHCP."
+
+#: option.c:380
+#, c-format
+msgid "Do NOT poll %s file, reload only on SIGHUP."
+msgstr "Nu încărca fişierul %s, citeşte-l doar la SIGHUP."
+
+#: option.c:381
+msgid "Do NOT cache failed search results."
+msgstr "NU memora rezultatele de căutare DNS eşuatată."
+
+#: option.c:382
+#, c-format
+msgid "Use nameservers strictly in the order given in %s."
+msgstr "Foloseşte servere DNS strict în ordinea dată în %s."
+
+#: option.c:383
+#, fuzzy
+msgid "Specify options to be sent to DHCP clients."
+msgstr "Configurează opţiuni în plusce trebuie trimise clienţilor DHCP."
+
+#: option.c:384
+msgid "DHCP option sent even if the client does not request it."
+msgstr ""
+
+#: option.c:385
+msgid "Specify port to listen for DNS requests on (defaults to 53)."
+msgstr "Specifică numărul portului pentru cereri DNS (implicit e 53)."
+
+#: option.c:386
+#, c-format
+msgid "Maximum supported UDP packet size for EDNS.0 (defaults to %s)."
+msgstr "Marimea maximă a pachetului UDP pentru EDNS.0 (implicit e %s)."
+
+#: option.c:387
+#, fuzzy
+msgid "Log DNS queries."
+msgstr "Înregistrează tranzacţiile."
+
+#: option.c:388
+#, fuzzy
+msgid "Force the originating port for upstream DNS queries."
+msgstr "Forţează acest port pentru datele ce pleacă."
+
+#: option.c:389
+msgid "Do NOT read resolv.conf."
+msgstr "NU citi fişierul resolv.conf"
+
+#: option.c:390
+#, c-format
+msgid "Specify path to resolv.conf (defaults to %s)."
+msgstr "Specifică calea către resolv.conf (implicit e %s)."
+
+#: option.c:391
+#, fuzzy
+msgid "Specify path to file with server= options"
+msgstr "Specifică o cale pentru fişierul PID. (implicit %s)."
+
+#: option.c:392
+msgid "Specify address(es) of upstream servers with optional domains."
+msgstr "Specifică adresele server(elor) superioare cu domenii opţionale."
+
+#: option.c:393
+#, fuzzy
+msgid "Specify address of upstream servers for reverse address queries"
+msgstr "Specifică adresele server(elor) superioare cu domenii opţionale."
+
+#: option.c:394
+msgid "Never forward queries to specified domains."
+msgstr "Nu înaintează cererile spre domeniile specificate."
+
+#: option.c:395
+msgid "Specify the domain to be assigned in DHCP leases."
+msgstr "Specifică domeniul de transmis prin DHCP."
+
+#: option.c:396
+msgid "Specify default target in an MX record."
+msgstr "Specifică o ţintă într-o înregistrare MX."
+
+#: option.c:397
+msgid "Specify time-to-live in seconds for replies from /etc/hosts."
+msgstr "Specifică TTL în secunde pentru răspunsurile din /etc/hosts."
+
+#: option.c:398
+#, fuzzy
+msgid "Specify time-to-live in seconds for negative caching."
+msgstr "Specifică TTL în secunde pentru răspunsurile din /etc/hosts."
+
+#: option.c:399
+#, fuzzy
+msgid "Specify time-to-live in seconds for maximum TTL to send to clients."
+msgstr "Specifică TTL în secunde pentru răspunsurile din /etc/hosts."
+
+#: option.c:400
+#, fuzzy
+msgid "Specify time-to-live ceiling for cache."
+msgstr "Specifică TTL în secunde pentru răspunsurile din /etc/hosts."
+
+#: option.c:401
+#, fuzzy
+msgid "Specify time-to-live floor for cache."
+msgstr "Specifică TTL în secunde pentru răspunsurile din /etc/hosts."
+
+#: option.c:402
+#, c-format
+msgid "Change to this user after startup. (defaults to %s)."
+msgstr "Rulează sub acest utilizator după pornire. (implicit e %s)."
+
+#: option.c:403
+#, fuzzy
+msgid "Map DHCP vendor class to tag."
+msgstr "Trimite opţiuni DHCP în funcţie de marca plăcii de reţea."
+
+#: option.c:404
+msgid "Display dnsmasq version and copyright information."
+msgstr "Afişează versiunea dnsmasq şi drepturile de autor."
+
+#: option.c:405
+msgid "Translate IPv4 addresses from upstream servers."
+msgstr "Traduce adresele IPv4 de la serverele DNS superioare."
+
+#: option.c:406
+msgid "Specify a SRV record."
+msgstr "Specifică o înregistrare SRV."
+
+#: option.c:407
+msgid "Display this message. Use --help dhcp or --help dhcp6 for known DHCP options."
+msgstr ""
+
+#: option.c:408
+#, fuzzy, c-format
+msgid "Specify path of PID file (defaults to %s)."
+msgstr "Specifică o cale pentru fişierul PID. (implicit %s)."
+
+#: option.c:409
+#, c-format
+msgid "Specify maximum number of DHCP leases (defaults to %s)."
+msgstr "Specifică numărul maxim de împrumuturi DHCP (implicit %s)."
+
+#: option.c:410
+msgid "Answer DNS queries based on the interface a query was sent to."
+msgstr "Răspunde cererilor DNS în funcţie de interfaţa pe care a venit cererea."
+
+#: option.c:411
+msgid "Specify TXT DNS record."
+msgstr "Specifică o înregistrare TXT."
+
+#: option.c:412
+#, fuzzy
+msgid "Specify PTR DNS record."
+msgstr "Specifică o înregistrare TXT."
+
+#: option.c:413
+msgid "Give DNS name to IPv4 address of interface."
+msgstr ""
+
+#: option.c:414
+msgid "Bind only to interfaces in use."
+msgstr "Ascultă doar pe interfeţele active."
+
+#: option.c:415
+#, c-format
+msgid "Read DHCP static host information from %s."
+msgstr "Citeşte informaţii DHCP statice despre maşină din %s."
+
+#: option.c:416
+msgid "Enable the DBus interface for setting upstream servers, etc."
+msgstr "Activeaza interfaţa DBus pentru configurarea serverelor superioare."
+
+#: option.c:417
+msgid "Do not provide DHCP on this interface, only provide DNS."
+msgstr "Nu activează DHCP ci doar DNS pe această interfaţă."
+
+#: option.c:418
+msgid "Enable dynamic address allocation for bootp."
+msgstr "Activează alocarea dinamică a adreselor pentru BOOTP."
+
+#: option.c:419
+#, fuzzy
+msgid "Map MAC address (with wildcards) to option set."
+msgstr "Trimite opţiuni DHCP în funcţie de marca plăcii de reţea."
+
+#: option.c:420
+msgid "Treat DHCP requests on aliases as arriving from interface."
+msgstr ""
+
+#: option.c:421
+msgid "Disable ICMP echo address checking in the DHCP server."
+msgstr ""
+
+#: option.c:422
+msgid "Shell script to run on DHCP lease creation and destruction."
+msgstr ""
+
+#: option.c:423
+msgid "Lua script to run on DHCP lease creation and destruction."
+msgstr ""
+
+#: option.c:424
+msgid "Run lease-change scripts as this user."
+msgstr ""
+
+#: option.c:425
+msgid "Call dhcp-script with changes to local ARP table."
+msgstr ""
+
+#: option.c:426
+msgid "Read configuration from all the files in this directory."
+msgstr ""
+
+#: option.c:427
+#, fuzzy
+msgid "Log to this syslog facility or file. (defaults to DAEMON)"
+msgstr "Rulează sub acest utilizator după pornire. (implicit e %s)."
+
+#: option.c:428
+msgid "Do not use leasefile."
+msgstr ""
+
+#: option.c:429
+#, fuzzy, c-format
+msgid "Maximum number of concurrent DNS queries. (defaults to %s)"
+msgstr "Specifică numărul maxim de împrumuturi DHCP (implicit %s)."
+
+#: option.c:430
+#, c-format
+msgid "Clear DNS cache when reloading %s."
+msgstr ""
+
+#: option.c:431
+msgid "Ignore hostnames provided by DHCP clients."
+msgstr ""
+
+#: option.c:432
+msgid "Do NOT reuse filename and server fields for extra DHCP options."
+msgstr ""
+
+#: option.c:433
+msgid "Enable integrated read-only TFTP server."
+msgstr ""
+
+#: option.c:434
+msgid "Export files by TFTP only from the specified subtree."
+msgstr ""
+
+#: option.c:435
+msgid "Add client IP or hardware address to tftp-root."
+msgstr ""
+
+#: option.c:436
+msgid "Allow access only to files owned by the user running dnsmasq."
+msgstr ""
+
+#: option.c:437
+msgid "Do not terminate the service if TFTP directories are inaccessible."
+msgstr ""
+
+#: option.c:438
+#, fuzzy, c-format
+msgid "Maximum number of concurrent TFTP transfers (defaults to %s)."
+msgstr "Specifică numărul maxim de împrumuturi DHCP (implicit %s)."
+
+#: option.c:439
+#, fuzzy
+msgid "Maximum MTU to use for TFTP transfers."
+msgstr "Specifică numărul maxim de împrumuturi DHCP (implicit %s)."
+
+#: option.c:440
+msgid "Disable the TFTP blocksize extension."
+msgstr ""
+
+#: option.c:441
+msgid "Convert TFTP filenames to lowercase"
+msgstr ""
+
+#: option.c:442
+msgid "Ephemeral port range for use by TFTP transfers."
+msgstr ""
+
+#: option.c:443
+msgid "Extra logging for DHCP."
+msgstr ""
+
+#: option.c:444
+msgid "Enable async. logging; optionally set queue length."
+msgstr ""
+
+#: option.c:445
+msgid "Stop DNS rebinding. Filter private IP ranges when resolving."
+msgstr ""
+
+#: option.c:446
+msgid "Allow rebinding of 127.0.0.0/8, for RBL servers."
+msgstr ""
+
+#: option.c:447
+msgid "Inhibit DNS-rebind protection on this domain."
+msgstr ""
+
+#: option.c:448
+msgid "Always perform DNS queries to all servers."
+msgstr ""
+
+#: option.c:449
+msgid "Set tag if client includes matching option in request."
+msgstr ""
+
+#: option.c:450
+msgid "Use alternative ports for DHCP."
+msgstr ""
+
+#: option.c:451
+#, fuzzy
+msgid "Specify NAPTR DNS record."
+msgstr "Specifică o înregistrare TXT."
+
+#: option.c:452
+msgid "Specify lowest port available for DNS query transmission."
+msgstr ""
+
+#: option.c:453
+msgid "Specify highest port available for DNS query transmission."
+msgstr ""
+
+#: option.c:454
+msgid "Use only fully qualified domain names for DHCP clients."
+msgstr ""
+
+#: option.c:455
+msgid "Generate hostnames based on MAC address for nameless clients."
+msgstr ""
+
+#: option.c:456
+msgid "Use these DHCP relays as full proxies."
+msgstr ""
+
+#: option.c:457
+msgid "Relay DHCP requests to a remote server"
+msgstr ""
+
+#: option.c:458
+msgid "Specify alias name for LOCAL DNS name."
+msgstr ""
+
+#: option.c:459
+#, fuzzy
+msgid "Prompt to send to PXE clients."
+msgstr "Configurează opţiuni în plusce trebuie trimise clienţilor DHCP."
+
+#: option.c:460
+msgid "Boot service for PXE menu."
+msgstr ""
+
+#: option.c:461
+msgid "Check configuration syntax."
+msgstr ""
+
+#: option.c:462
+msgid "Add requestor's MAC address to forwarded DNS queries."
+msgstr ""
+
+#: option.c:463
+msgid "Add specified IP subnet to forwarded DNS queries."
+msgstr ""
+
+#: option.c:464
+#, fuzzy
+msgid "Add client identification to forwarded DNS queries."
+msgstr "Forţează acest port pentru datele ce pleacă."
+
+#: option.c:465
+#, fuzzy
+msgid "Proxy DNSSEC validation results from upstream nameservers."
+msgstr "Traduce adresele IPv4 de la serverele DNS superioare."
+
+#: option.c:466
+msgid "Attempt to allocate sequential IP addresses to DHCP clients."
+msgstr ""
+
+#: option.c:467
+msgid "Copy connection-track mark from queries to upstream connections."
+msgstr ""
+
+#: option.c:468
+msgid "Allow DHCP clients to do their own DDNS updates."
+msgstr ""
+
+#: option.c:469
+msgid "Send router-advertisements for interfaces doing DHCPv6"
+msgstr ""
+
+#: option.c:470
+msgid "Specify DUID_EN-type DHCPv6 server DUID"
+msgstr ""
+
+#: option.c:471
+#, fuzzy
+msgid "Specify host (A/AAAA and PTR) records"
+msgstr "Specifică o înregistrare MX."
+
+#: option.c:472
+#, fuzzy
+msgid "Specify arbitrary DNS resource record"
+msgstr "Specifică o înregistrare TXT."
+
+#: option.c:473
+#, fuzzy
+msgid "Bind to interfaces in use - check for new interfaces"
+msgstr "interfaţă necunoscută %s"
+
+#: option.c:474
+msgid "Export local names to global DNS"
+msgstr ""
+
+#: option.c:475
+msgid "Domain to export to global DNS"
+msgstr ""
+
+#: option.c:476
+msgid "Set TTL for authoritative replies"
+msgstr ""
+
+#: option.c:477
+msgid "Set authoritative zone information"
+msgstr ""
+
+#: option.c:478
+msgid "Secondary authoritative nameservers for forward domains"
+msgstr ""
+
+#: option.c:479
+msgid "Peers which are allowed to do zone transfer"
+msgstr ""
+
+#: option.c:480
+msgid "Specify ipsets to which matching domains should be added"
+msgstr ""
+
+#: option.c:481
+msgid "Specify a domain and address range for synthesised names"
+msgstr ""
+
+#: option.c:482
+msgid "Activate DNSSEC validation"
+msgstr ""
+
+#: option.c:483
+msgid "Specify trust anchor key digest."
+msgstr ""
+
+#: option.c:484
+msgid "Disable upstream checking for DNSSEC debugging."
+msgstr ""
+
+#: option.c:485
+msgid "Ensure answers without DNSSEC are in unsigned zones."
+msgstr ""
+
+#: option.c:486
+msgid "Don't check DNSSEC signature timestamps until first cache-reload"
+msgstr ""
+
+#: option.c:487
+msgid "Timestamp file to verify system clock for DNSSEC"
+msgstr ""
+
+#: option.c:489
+msgid "Specify DHCPv6 prefix class"
+msgstr ""
+
+#: option.c:491
+msgid "Set MTU, priority, resend-interval and router-lifetime"
+msgstr ""
+
+#: option.c:492
+msgid "Do not log routine DHCP."
+msgstr ""
+
+#: option.c:493
+msgid "Do not log routine DHCPv6."
+msgstr ""
+
+#: option.c:494
+msgid "Do not log RA."
+msgstr ""
+
+#: option.c:495
+msgid "Accept queries only from directly-connected networks."
+msgstr ""
+
+#: option.c:496
+msgid "Detect and remove DNS forwarding loops."
+msgstr ""
+
+#: option.c:497
+msgid "Ignore DNS responses containing ipaddr."
+msgstr ""
+
+#: option.c:498
+msgid "Set TTL in DNS responses with DHCP-derived addresses."
+msgstr ""
+
+#: option.c:499
+msgid "Delay DHCP replies for at least number of seconds."
+msgstr ""
+
+#: option.c:703
+#, c-format
+msgid ""
+"Usage: dnsmasq [options]\n"
+"\n"
+msgstr ""
+"Utilizare: dnsmasq [opţiuni]\n"
+"\n"
+
+#: option.c:705
+#, c-format
+msgid "Use short options only on the command line.\n"
+msgstr "Folosiţi opţiunile prescurtate doar în linie de comandă.\n"
+
+#: option.c:707
+#, fuzzy, c-format
+msgid "Valid options are:\n"
+msgstr "Opţiunile valide sunt:\n"
+
+#: option.c:754 option.c:868
+#, fuzzy
+msgid "bad address"
+msgstr "citesc %s - %d adrese"
+
+#: option.c:779 option.c:783
+msgid "bad port"
+msgstr "port invalid"
+
+#: option.c:797 option.c:826 option.c:861
+msgid "interface binding not supported"
+msgstr ""
+
+#: option.c:821 option.c:856
+msgid "interface can only be specified once"
+msgstr ""
+
+#: option.c:835 option.c:3800
+#, fuzzy
+msgid "bad interface name"
+msgstr "nume MX invalid"
+
+#: option.c:1062
+msgid "unsupported encapsulation for IPv6 option"
+msgstr ""
+
+#: option.c:1076
+msgid "bad dhcp-option"
+msgstr "dhcp-option invalid"
+
+#: option.c:1144
+#, fuzzy
+msgid "bad IP address"
+msgstr "citesc %s - %d adrese"
+
+#: option.c:1147 option.c:1286 option.c:3070
+#, fuzzy
+msgid "bad IPv6 address"
+msgstr "citesc %s - %d adrese"
+
+#: option.c:1240
+#, fuzzy
+msgid "bad IPv4 address"
+msgstr "citesc %s - %d adrese"
+
+#: option.c:1313 option.c:1407
+msgid "bad domain in dhcp-option"
+msgstr "domeniu DNS invalid în declaraţia dhcp-option"
+
+#: option.c:1445
+msgid "dhcp-option too long"
+msgstr "declararea dhcp-option este prea lungă"
+
+#: option.c:1452
+msgid "illegal dhcp-match"
+msgstr ""
+
+#: option.c:1514
+msgid "illegal repeated flag"
+msgstr ""
+
+#: option.c:1522
+msgid "illegal repeated keyword"
+msgstr ""
+
+#: option.c:1593 option.c:4434
+#, fuzzy, c-format
+msgid "cannot access directory %s: %s"
+msgstr "nu pot citi %s: %s"
+
+#: option.c:1639 tftp.c:537
+#, fuzzy, c-format
+msgid "cannot access %s: %s"
+msgstr "nu pot citi %s: %s"
+
+#: option.c:1727
+msgid "setting log facility is not possible under Android"
+msgstr ""
+
+#: option.c:1736
+msgid "bad log facility"
+msgstr ""
+
+#: option.c:1789
+msgid "bad MX preference"
+msgstr "preferinţă MX invalidă"
+
+#: option.c:1794
+msgid "bad MX name"
+msgstr "nume MX invalid"
+
+#: option.c:1808
+msgid "bad MX target"
+msgstr "ţintă MX invalidă"
+
+#: option.c:1820
+msgid "cannot run scripts under uClinux"
+msgstr ""
+
+#: option.c:1822
+msgid "recompile with HAVE_SCRIPT defined to enable lease-change scripts"
+msgstr ""
+
+#: option.c:1826
+msgid "recompile with HAVE_LUASCRIPT defined to enable Lua scripts"
+msgstr ""
+
+#: option.c:2095 option.c:2106 option.c:2143 option.c:2199 option.c:2482
+#, fuzzy
+msgid "bad prefix"
+msgstr "port invalid"
+
+#: option.c:2504
+msgid "recompile with HAVE_IPSET defined to enable ipset directives"
+msgstr ""
+
+#: option.c:2713
+#, fuzzy
+msgid "bad port range"
+msgstr "port invalid"
+
+#: option.c:2738
+msgid "bad bridge-interface"
+msgstr ""
+
+#: option.c:2798
+msgid "only one tag allowed"
+msgstr ""
+
+#: option.c:2818 option.c:2830 option.c:2939 option.c:2944 option.c:2983
+msgid "bad dhcp-range"
+msgstr "dhcp-range invalid"
+
+#: option.c:2845
+msgid "inconsistent DHCP range"
+msgstr "domeniu DHCP inconsistent"
+
+#: option.c:2907
+msgid "prefix length must be exactly 64 for RA subnets"
+msgstr ""
+
+#: option.c:2909
+msgid "prefix length must be exactly 64 for subnet constructors"
+msgstr ""
+
+#: option.c:2913
+msgid "prefix length must be at least 64"
+msgstr ""
+
+#: option.c:2916
+#, fuzzy
+msgid "inconsistent DHCPv6 range"
+msgstr "domeniu DHCP inconsistent"
+
+#: option.c:2927
+msgid "prefix must be zero with \"constructor:\" argument"
+msgstr ""
+
+#: option.c:3040 option.c:3088
+#, fuzzy
+msgid "bad hex constant"
+msgstr "dhcp-host invalid"
+
+#: option.c:3062
+msgid "cannot match tags in --dhcp-host"
+msgstr ""
+
+#: option.c:3110
+#, fuzzy, c-format
+msgid "duplicate dhcp-host IP address %s"
+msgstr "adresă IP duplicat %s în declaraţia dhcp-config."
+
+#: option.c:3168
+#, fuzzy
+msgid "bad DHCP host name"
+msgstr "nume MX invalid"
+
+#: option.c:3250
+#, fuzzy
+msgid "bad tag-if"
+msgstr "ţintă MX invalidă"
+
+#: option.c:3607 option.c:4030
+msgid "invalid port number"
+msgstr "număr de port invalid"
+
+#: option.c:3669
+#, fuzzy
+msgid "bad dhcp-proxy address"
+msgstr "citesc %s - %d adrese"
+
+#: option.c:3695
+#, fuzzy
+msgid "Bad dhcp-relay"
+msgstr "dhcp-range invalid"
+
+#: option.c:3736
+msgid "bad RA-params"
+msgstr ""
+
+#: option.c:3745
+msgid "bad DUID"
+msgstr ""
+
+#: option.c:3787
+#, fuzzy
+msgid "invalid alias range"
+msgstr "pondere invalidă"
+
+#: option.c:3841 option.c:3853
+msgid "bad CNAME"
+msgstr ""
+
+#: option.c:3857
+msgid "duplicate CNAME"
+msgstr ""
+
+#: option.c:3880
+#, fuzzy
+msgid "bad PTR record"
+msgstr "înregistrare SRV invalidă"
+
+#: option.c:3911
+#, fuzzy
+msgid "bad NAPTR record"
+msgstr "înregistrare SRV invalidă"
+
+#: option.c:3945
+#, fuzzy
+msgid "bad RR record"
+msgstr "înregistrare SRV invalidă"
+
+#: option.c:3975
+msgid "bad TXT record"
+msgstr "înregistrare TXT invalidă"
+
+#: option.c:4016
+msgid "bad SRV record"
+msgstr "înregistrare SRV invalidă"
+
+#: option.c:4023
+msgid "bad SRV target"
+msgstr "ţintă SRV invalidă"
+
+#: option.c:4037
+msgid "invalid priority"
+msgstr "prioritate invalidă"
+
+#: option.c:4040
+msgid "invalid weight"
+msgstr "pondere invalidă"
+
+#: option.c:4064
+#, fuzzy
+msgid "Bad host-record"
+msgstr "înregistrare SRV invalidă"
+
+#: option.c:4088
+#, fuzzy
+msgid "Bad name in host-record"
+msgstr "nume invalid în %s"
+
+#: option.c:4153
+#, fuzzy
+msgid "bad trust anchor"
+msgstr "port invalid"
+
+#: option.c:4167
+msgid "bad HEX in trust anchor"
+msgstr ""
+
+#: option.c:4177
+msgid "unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"
+msgstr ""
+
+#: option.c:4237
+msgid "missing \""
+msgstr "lipseşte \""
+
+#: option.c:4294
+msgid "bad option"
+msgstr "opţiune invalidă"
+
+#: option.c:4296
+msgid "extraneous parameter"
+msgstr "parametru nerecunoscut"
+
+#: option.c:4298
+msgid "missing parameter"
+msgstr "parametru lipsa"
+
+#: option.c:4300
+#, fuzzy
+msgid "illegal option"
+msgstr "opţiune invalidă"
+
+#: option.c:4307
+msgid "error"
+msgstr "eroare"
+
+#: option.c:4309
+#, fuzzy, c-format
+msgid " at line %d of %s"
+msgstr "%s la linia %d din %%s"
+
+#: option.c:4324 option.c:4571 option.c:4607
+#, fuzzy, c-format
+msgid "read %s"
+msgstr "citesc %s"
+
+#: option.c:4387 option.c:4510 tftp.c:715
+#, c-format
+msgid "cannot read %s: %s"
+msgstr "nu pot citi %s: %s"
+
+#: option.c:4676
+msgid "junk found in command line"
+msgstr ""
+
+#: option.c:4711
+#, c-format
+msgid "Dnsmasq version %s  %s\n"
+msgstr "dnsmasq versiunea %s  %s\n"
+
+#: option.c:4712
+#, fuzzy, c-format
+msgid ""
+"Compile time options: %s\n"
+"\n"
+msgstr ""
+"Opţiuni cu care a fost compilat %s\n"
+"\n"
+
+#: option.c:4713
+#, c-format
+msgid "This software comes with ABSOLUTELY NO WARRANTY.\n"
+msgstr "Acest program vine FĂRĂ NICI O GARANŢIE.\n"
+
+#: option.c:4714
+#, c-format
+msgid "Dnsmasq is free software, and you are welcome to redistribute it\n"
+msgstr "Dnsmasq este un program gratuit, sunteţi invitaţi să-l redistribuiţi\n"
+
+#: option.c:4715
+#, fuzzy, c-format
+msgid "under the terms of the GNU General Public License, version 2 or 3.\n"
+msgstr "în termenii Licenţei publice generale GNU, versiunea 2.\n"
+
+#: option.c:4726
+msgid "try --help"
+msgstr ""
+
+#: option.c:4728
+msgid "try -w"
+msgstr ""
+
+#: option.c:4730
+#, fuzzy, c-format
+msgid "bad command line options: %s"
+msgstr "opţiuni în linie de comandă invalide: %s."
+
+#: option.c:4798
+#, c-format
+msgid "CNAME loop involving %s"
+msgstr ""
+
+#: option.c:4834
+#, c-format
+msgid "cannot get host-name: %s"
+msgstr "nu pot citi numele maşinii: %s"
+
+#: option.c:4862
+msgid "only one resolv.conf file allowed in no-poll mode."
+msgstr "se permite un singur fişier resolv.conf în modul no-poll"
+
+#: option.c:4872
+msgid "must have exactly one resolv.conf to read domain from."
+msgstr "am nevoie de un singur resolv.conf din care să citesc numele domeniului."
+
+#: option.c:4875 network.c:1612 dhcp.c:816
+#, fuzzy, c-format
+msgid "failed to read %s: %s"
+msgstr "nu pot citi %s: %s"
+
+#: option.c:4892
+#, c-format
+msgid "no search directive found in %s"
+msgstr "nu s-a găsit nici un criteriu de căutare în %s"
+
+#: option.c:4913
+msgid "there must be a default domain when --dhcp-fqdn is set"
+msgstr ""
+
+#: option.c:4922
+msgid "syntax check OK"
+msgstr ""
+
+#: forward.c:102
+#, fuzzy, c-format
+msgid "failed to send packet: %s"
+msgstr "ascultarea pe socket a eşuat: %s"
+
+#: forward.c:597
+msgid "discarding DNS reply: subnet option mismatch"
+msgstr ""
+
+#: forward.c:651
+#, c-format
+msgid "nameserver %s refused to do a recursive query"
+msgstr "serverul DNS %s refuză interogările recursive"
+
+#: forward.c:683
+#, c-format
+msgid "possible DNS-rebind attack detected: %s"
+msgstr ""
+
+#: forward.c:1244 forward.c:1681
+msgid "Ignoring query from non-local network"
+msgstr ""
+
+#: forward.c:2166
+#, fuzzy, c-format
+msgid "Maximum number of concurrent DNS queries reached (max: %d)"
+msgstr "Specifică numărul maxim de împrumuturi DHCP (implicit %s)."
+
+#: network.c:720
+#, fuzzy, c-format
+msgid "failed to create listening socket for %s: %s"
+msgstr "creearea socket-ului de ascultare a eşuat: %s"
+
+#: network.c:1031
+#, c-format
+msgid "LOUD WARNING: listening on %s may accept requests via interfaces other than %s"
+msgstr ""
+
+#: network.c:1038
+msgid "LOUD WARNING: use --bind-dynamic rather than --bind-interfaces to avoid DNS amplification attacks via these interface(s)"
+msgstr ""
+
+#: network.c:1047
+#, fuzzy, c-format
+msgid "warning: using interface %s instead"
+msgstr "atenţie: interfaţa %s nu există momentan"
+
+#: network.c:1056
+#, fuzzy, c-format
+msgid "warning: no addresses found for interface %s"
+msgstr "folosim adresele locale doar pentru %S %s"
+
+#: network.c:1114
+#, fuzzy, c-format
+msgid "interface %s failed to join DHCPv6 multicast group: %s"
+msgstr "activarea socket-ului server-ului DHCP a eşuat: %s"
+
+#: network.c:1119
+msgid "try increasing /proc/sys/net/core/optmem_max"
+msgstr ""
+
+#: network.c:1322
+#, fuzzy, c-format
+msgid "failed to bind server socket for %s: %s"
+msgstr "activarea socket-ului de ascultare pentru %s a eşuat: %s"
+
+#: network.c:1517
+#, c-format
+msgid "ignoring nameserver %s - local interface"
+msgstr "ignorăm serverul DNS %s - interfaţă locală"
+
+#: network.c:1528
+#, fuzzy, c-format
+msgid "ignoring nameserver %s - cannot make/bind socket: %s"
+msgstr "ignorăm serverul DNS %s - nu pot creea/activa socket-ul: %s"
+
+#: network.c:1548
+msgid "(no DNSSEC)"
+msgstr ""
+
+#: network.c:1551
+msgid "unqualified"
+msgstr "invalid"
+
+#: network.c:1551
+msgid "names"
+msgstr ""
+
+#: network.c:1553
+msgid "default"
+msgstr ""
+
+#: network.c:1555
+msgid "domain"
+msgstr "domeniu"
+
+#: network.c:1561
+#, c-format
+msgid "using local addresses only for %s %s"
+msgstr "folosim adresele locale doar pentru %S %s"
+
+#: network.c:1564
+#, fuzzy, c-format
+msgid "using standard nameservers for %s %s"
+msgstr "folosim serverul DNS %s#%d pentru %s %s"
+
+#: network.c:1566
+#, fuzzy, c-format
+msgid "using nameserver %s#%d for %s %s %s"
+msgstr "folosim serverul DNS %s#%d pentru %s %s"
+
+#: network.c:1570
+#, fuzzy, c-format
+msgid "NOT using nameserver %s#%d - query loop detected"
+msgstr "folosim serverul DNS %s#%d pentru %s %s"
+
+#: network.c:1573
+#, fuzzy, c-format
+msgid "using nameserver %s#%d(via %s)"
+msgstr "folosim serverul DNS %s#%d"
+
+#: network.c:1575
+#, c-format
+msgid "using nameserver %s#%d"
+msgstr "folosim serverul DNS %s#%d"
+
+#: network.c:1580
+#, fuzzy, c-format
+msgid "using %d more local addresses"
+msgstr "folosim serverul DNS %s#%d"
+
+#: network.c:1582
+#, fuzzy, c-format
+msgid "using %d more nameservers"
+msgstr "folosim serverul DNS %s#%d"
+
+#: dnsmasq.c:166
+msgid "dhcp-hostsdir, dhcp-optsdir and hostsdir are not supported on this platform"
+msgstr ""
+
+#: dnsmasq.c:181
+msgid "no root trust anchor provided for DNSSEC"
+msgstr ""
+
+#: dnsmasq.c:184
+msgid "cannot reduce cache size from default when DNSSEC enabled"
+msgstr ""
+
+#: dnsmasq.c:186
+#, fuzzy
+msgid "DNSSEC not available: set HAVE_DNSSEC in src/config.h"
+msgstr "DBus nu este disponibil: puneţi HAVE_DBUS in src/config.h"
+
+#: dnsmasq.c:192
+#, fuzzy
+msgid "TFTP server not available: set HAVE_TFTP in src/config.h"
+msgstr "DBus nu este disponibil: puneţi HAVE_DBUS in src/config.h"
+
+#: dnsmasq.c:197
+msgid "cannot use --conntrack AND --query-port"
+msgstr ""
+
+#: dnsmasq.c:200
+#, fuzzy
+msgid "conntrack support not available: set HAVE_CONNTRACK in src/config.h"
+msgstr "DBus nu este disponibil: puneţi HAVE_DBUS in src/config.h"
+
+#: dnsmasq.c:205
+msgid "asynchronous logging is not available under Solaris"
+msgstr ""
+
+#: dnsmasq.c:210
+msgid "asynchronous logging is not available under Android"
+msgstr ""
+
+#: dnsmasq.c:215
+#, fuzzy
+msgid "authoritative DNS not available: set HAVE_AUTH in src/config.h"
+msgstr "DBus nu este disponibil: puneţi HAVE_DBUS in src/config.h"
+
+#: dnsmasq.c:220
+#, fuzzy
+msgid "loop detection not available: set HAVE_LOOP in src/config.h"
+msgstr "DBus nu este disponibil: puneţi HAVE_DBUS in src/config.h"
+
+#: dnsmasq.c:227
+msgid "max_port cannot be smaller than min_port"
+msgstr ""
+
+#: dnsmasq.c:234
+msgid "zone serial must be configured in --auth-soa"
+msgstr ""
+
+#: dnsmasq.c:252
+msgid "dhcp-range constructor not available on this platform"
+msgstr ""
+
+#: dnsmasq.c:298
+msgid "cannot set --bind-interfaces and --bind-dynamic"
+msgstr ""
+
+#: dnsmasq.c:301
+#, c-format
+msgid "failed to find list of interfaces: %s"
+msgstr "enumerarea interfeţelor a eşuat: %s"
+
+#: dnsmasq.c:310
+#, c-format
+msgid "unknown interface %s"
+msgstr "interfaţă necunoscută %s"
+
+#: dnsmasq.c:374 dnsmasq.c:1037
+#, c-format
+msgid "DBus error: %s"
+msgstr "eroare DBus: %s"
+
+#: dnsmasq.c:377
+msgid "DBus not available: set HAVE_DBUS in src/config.h"
+msgstr "DBus nu este disponibil: puneţi HAVE_DBUS in src/config.h"
+
+#: dnsmasq.c:405
+#, c-format
+msgid "unknown user or group: %s"
+msgstr ""
+
+#: dnsmasq.c:460
+#, c-format
+msgid "cannot chdir to filesystem root: %s"
+msgstr ""
+
+#: dnsmasq.c:716
+#, fuzzy, c-format
+msgid "started, version %s DNS disabled"
+msgstr "am pornit, versiunea %s memorie temporară dezactivată"
+
+#: dnsmasq.c:720
+#, c-format
+msgid "started, version %s cachesize %d"
+msgstr "am ponit, versiunea %s memorie temporară %d"
+
+#: dnsmasq.c:722
+#, c-format
+msgid "started, version %s cache disabled"
+msgstr "am pornit, versiunea %s memorie temporară dezactivată"
+
+#: dnsmasq.c:725
+msgid "DNS service limited to local subnets"
+msgstr ""
+
+#: dnsmasq.c:728
+#, c-format
+msgid "compile time options: %s"
+msgstr "compilat cu opţiunile: %s"
+
+#: dnsmasq.c:734
+msgid "DBus support enabled: connected to system bus"
+msgstr "suportul DBus activ: sunt conectat la magistrala sistem"
+
+#: dnsmasq.c:736
+msgid "DBus support enabled: bus connection pending"
+msgstr "suportul DBus activ: aştept conexiunea la magistrală"
+
+#: dnsmasq.c:754
+msgid "DNSSEC validation enabled"
+msgstr ""
+
+#: dnsmasq.c:758
+msgid "DNSSEC signature timestamps not checked until first cache reload"
+msgstr ""
+
+#: dnsmasq.c:761
+msgid "DNSSEC signature timestamps not checked until system time valid"
+msgstr ""
+
+# for compatibility purposes the letters â, ă, ş, ţ and î can be written as their look-alike correspondent.
+#: dnsmasq.c:766
+#, fuzzy, c-format
+msgid "warning: failed to change owner of %s: %s"
+msgstr "încărcarea numelor din %s: %s a eşuat"
+
+#: dnsmasq.c:770
+msgid "setting --bind-interfaces option because of OS limitations"
+msgstr "specific opţiunea --bind-interfaces din cauza limitărilor SO"
+
+#: dnsmasq.c:782
+#, c-format
+msgid "warning: interface %s does not currently exist"
+msgstr "atenţie: interfaţa %s nu există momentan"
+
+#: dnsmasq.c:787
+msgid "warning: ignoring resolv-file flag because no-resolv is set"
+msgstr ""
+
+#: dnsmasq.c:790
+#, fuzzy
+msgid "warning: no upstream servers configured"
+msgstr "configurăm serverele superioare prin Dbus"
+
+#: dnsmasq.c:794
+#, c-format
+msgid "asynchronous logging enabled, queue limit is %d messages"
+msgstr ""
+
+#: dnsmasq.c:815
+msgid "IPv6 router advertisement enabled"
+msgstr ""
+
+#: dnsmasq.c:820
+#, c-format
+msgid "DHCP, sockets bound exclusively to interface %s"
+msgstr ""
+
+#: dnsmasq.c:834
+msgid "root is "
+msgstr ""
+
+#: dnsmasq.c:834
+#, fuzzy
+msgid "enabled"
+msgstr "dezactivat"
+
+#: dnsmasq.c:836
+msgid "secure mode"
+msgstr ""
+
+#: dnsmasq.c:839
+#, c-format
+msgid "warning: %s inaccessible"
+msgstr ""
+
+#: dnsmasq.c:843
+#, c-format
+msgid "warning: TFTP directory %s inaccessible"
+msgstr ""
+
+#: dnsmasq.c:869
+#, c-format
+msgid "restricting maximum simultaneous TFTP transfers to %d"
+msgstr ""
+
+#: dnsmasq.c:1039
+msgid "connected to system DBus"
+msgstr "magistrala sistem Dbus conectată"
+
+#: dnsmasq.c:1189
+#, c-format
+msgid "cannot fork into background: %s"
+msgstr ""
+
+#: dnsmasq.c:1192
+#, fuzzy, c-format
+msgid "failed to create helper: %s"
+msgstr "nu pot citi %s: %s"
+
+#: dnsmasq.c:1195
+#, c-format
+msgid "setting capabilities failed: %s"
+msgstr ""
+
+# for compatibility purposes the letters â, ă, ş, ţ and î can be written as their look-alike correspondent.
+#: dnsmasq.c:1198
+#, fuzzy, c-format
+msgid "failed to change user-id to %s: %s"
+msgstr "încărcarea numelor din %s: %s a eşuat"
+
+# for compatibility purposes the letters â, ă, ş, ţ and î can be written as their look-alike correspondent.
+#: dnsmasq.c:1201
+#, fuzzy, c-format
+msgid "failed to change group-id to %s: %s"
+msgstr "încărcarea numelor din %s: %s a eşuat"
+
+#: dnsmasq.c:1204
+#, fuzzy, c-format
+msgid "failed to open pidfile %s: %s"
+msgstr "nu pot citi %s: %s"
+
+#: dnsmasq.c:1207
+#, fuzzy, c-format
+msgid "cannot open log %s: %s"
+msgstr "nu pot deschide %s:%s"
+
+#: dnsmasq.c:1210
+#, fuzzy, c-format
+msgid "failed to load Lua script: %s"
+msgstr "nu pot încărca %s: %s"
+
+#: dnsmasq.c:1213
+#, c-format
+msgid "TFTP directory %s inaccessible: %s"
+msgstr ""
+
+#: dnsmasq.c:1216
+#, fuzzy, c-format
+msgid "cannot create timestamp file %s: %s"
+msgstr "nu pot creea sau deschide fişierul cu împrumuturi: %s"
+
+#: dnsmasq.c:1239
+msgid "now checking DNSSEC signature timestamps"
+msgstr ""
+
+#: dnsmasq.c:1307
+#, c-format
+msgid "script process killed by signal %d"
+msgstr ""
+
+#: dnsmasq.c:1311
+#, c-format
+msgid "script process exited with status %d"
+msgstr ""
+
+#: dnsmasq.c:1315
+#, fuzzy, c-format
+msgid "failed to execute %s: %s"
+msgstr "accesarea serverului %s a eşuat: %s"
+
+#: dnsmasq.c:1379 dnssec.c:479 dnssec.c:525
+#, fuzzy, c-format
+msgid "failed to update mtime on %s: %s"
+msgstr "nu pot citi %s: %s"
+
+#: dnsmasq.c:1386
+msgid "exiting on receipt of SIGTERM"
+msgstr "am primit SIGTERM, am terminat"
+
+#: dnsmasq.c:1414
+#, fuzzy, c-format
+msgid "failed to access %s: %s"
+msgstr "accesarea serverului %s a eşuat: %s"
+
+#: dnsmasq.c:1444
+#, c-format
+msgid "reading %s"
+msgstr "citesc %s"
+
+#: dnsmasq.c:1455
+#, fuzzy, c-format
+msgid "no servers found in %s, will retry"
+msgstr "nu s-a găsit nici un criteriu de căutare în %s"
+
+#: dhcp.c:53
+#, c-format
+msgid "cannot create DHCP socket: %s"
+msgstr "nu pot creea socket DHCP: %s"
+
+#: dhcp.c:68
+#, c-format
+msgid "failed to set options on DHCP socket: %s"
+msgstr "configurarea opţiunilor socketului DHCP a eşuat: %s"
+
+#: dhcp.c:89
+#, fuzzy, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"
+msgstr "configurarea SO_REUSEADDR pe socket-ul DHCP a eşuat: %s"
+
+#: dhcp.c:101
+#, c-format
+msgid "failed to bind DHCP server socket: %s"
+msgstr "activarea socket-ului server-ului DHCP a eşuat: %s"
+
+#: dhcp.c:127
+#, c-format
+msgid "cannot create ICMP raw socket: %s."
+msgstr "nu pot creea socket ICMP raw: %s."
+
+#: dhcp.c:252 dhcp6.c:173
+#, fuzzy, c-format
+msgid "unknown interface %s in bridge-interface"
+msgstr "interfaţă necunoscută %s"
+
+#: dhcp.c:293
+#, c-format
+msgid "DHCP packet received on %s which has no address"
+msgstr ""
+
+#: dhcp.c:427
+#, c-format
+msgid "ARP-cache injection failed: %s"
+msgstr ""
+
+#: dhcp.c:470
+#, c-format
+msgid "Error sending DHCP packet to %s: %s"
+msgstr ""
+
+#: dhcp.c:531
+#, c-format
+msgid "DHCP range %s -- %s is not consistent with netmask %s"
+msgstr "domeniu DHCP %s -- %s nu este consistent cu masca de reţea %s"
+
+#: dhcp.c:854
+#, c-format
+msgid "bad line at %s line %d"
+msgstr "linie invalidă în %s rândul %d"
+
+#: dhcp.c:897
+#, c-format
+msgid "ignoring %s line %d, duplicate name or IP address"
+msgstr ""
+
+#: dhcp.c:1041 rfc3315.c:2149
+#, c-format
+msgid "DHCP relay %s -> %s"
+msgstr ""
+
+#: lease.c:98
+msgid "too many stored leases"
+msgstr "prea multe împrumuturi stocate"
+
+#: lease.c:166
+#, fuzzy, c-format
+msgid "cannot open or create lease file %s: %s"
+msgstr "nu pot creea sau deschide fişierul cu împrumuturi: %s"
+
+#: lease.c:175
+#, c-format
+msgid "failed to parse lease database, invalid line: %s %s %s %s ..."
+msgstr ""
+
+#: lease.c:180
+#, fuzzy, c-format
+msgid "failed to read lease file %s: %s"
+msgstr "nu pot citi %s: %s"
+
+#: lease.c:196
+#, fuzzy, c-format
+msgid "cannot run lease-init script %s: %s"
+msgstr "nu pot citi %s: %s"
+
+#: lease.c:202
+#, c-format
+msgid "lease-init script returned exit code %s"
+msgstr ""
+
+#: lease.c:373
+#, fuzzy, c-format
+msgid "failed to write %s: %s (retry in %us)"
+msgstr "nu pot citi %s: %s"
+
+#: lease.c:937
+#, c-format
+msgid "Ignoring domain %s for DHCP host name %s"
+msgstr ""
+
+#: rfc2131.c:347
+#, c-format
+msgid "no address range available for DHCP request %s %s"
+msgstr "nici un domeniu de adrese disponibil pentru cererea DHCP %s %s"
+
+#: rfc2131.c:348
+msgid "with subnet selector"
+msgstr "cu selectorul de subreţea"
+
+#: rfc2131.c:348
+msgid "via"
+msgstr "prin"
+
+#: rfc2131.c:360
+#, fuzzy, c-format
+msgid "%u available DHCP subnet: %s/%s"
+msgstr "nici un domeniu de adrese disponibil pentru cererea DHCP %s %s"
+
+#: rfc2131.c:363 rfc3315.c:306
+#, c-format
+msgid "%u available DHCP range: %s -- %s"
+msgstr ""
+
+#: rfc2131.c:474
+#, fuzzy, c-format
+msgid "%u vendor class: %s"
+msgstr "eroare DBus: %s"
+
+#: rfc2131.c:476
+#, fuzzy, c-format
+msgid "%u user class: %s"
+msgstr "eroare DBus: %s"
+
+#: rfc2131.c:510
+msgid "disabled"
+msgstr "dezactivat"
+
+#: rfc2131.c:551 rfc2131.c:1006 rfc2131.c:1430 rfc3315.c:616 rfc3315.c:869
+#: rfc3315.c:1148
+msgid "ignored"
+msgstr "ignorat"
+
+#: rfc2131.c:566 rfc2131.c:1239 rfc3315.c:919
+msgid "address in use"
+msgstr "adresa este folosită"
+
+#: rfc2131.c:580 rfc2131.c:1060
+msgid "no address available"
+msgstr "nici o adresă disponibilă"
+
+#: rfc2131.c:587 rfc2131.c:1202
+msgid "wrong network"
+msgstr "reţea greşită"
+
+#: rfc2131.c:602
+msgid "no address configured"
+msgstr "adresă lipsă"
+
+#: rfc2131.c:608 rfc2131.c:1252
+msgid "no leases left"
+msgstr "nu mai am de unde să împrumut"
+
+#: rfc2131.c:703 rfc3315.c:482
+#, c-format
+msgid "%u client provides name: %s"
+msgstr ""
+
+#: rfc2131.c:808
+msgid "PXE BIS not supported"
+msgstr ""
+
+#: rfc2131.c:974 rfc3315.c:1242
+#, fuzzy, c-format
+msgid "disabling DHCP static address %s for %s"
+msgstr "dezactivăm adresele DHCP statice %s"
+
+#: rfc2131.c:995
+msgid "unknown lease"
+msgstr "împrumut necunoscut"
+
+#: rfc2131.c:1029
+#, c-format
+msgid "not using configured address %s because it is leased to %s"
+msgstr ""
+
+#: rfc2131.c:1039
+#, c-format
+msgid "not using configured address %s because it is in use by the server or relay"
+msgstr ""
+
+#: rfc2131.c:1042
+#, c-format
+msgid "not using configured address %s because it was previously declined"
+msgstr ""
+
+#: rfc2131.c:1058 rfc2131.c:1245
+msgid "no unique-id"
+msgstr ""
+
+#: rfc2131.c:1140
+msgid "wrong server-ID"
+msgstr ""
+
+#: rfc2131.c:1159
+msgid "wrong address"
+msgstr "adresă greşită"
+
+#: rfc2131.c:1177 rfc3315.c:1015
+msgid "lease not found"
+msgstr "împrumutul nu a fost găsit"
+
+#: rfc2131.c:1210
+msgid "address not available"
+msgstr "adresă indisponibilă"
+
+#: rfc2131.c:1221
+msgid "static lease available"
+msgstr "împrumut static este disponibil"
+
+#: rfc2131.c:1225
+msgid "address reserved"
+msgstr "adresă rezervată"
+
+#: rfc2131.c:1233
+#, c-format
+msgid "abandoning lease to %s of %s"
+msgstr ""
+
+#: rfc2131.c:1757
+#, c-format
+msgid "%u bootfile name: %s"
+msgstr ""
+
+#: rfc2131.c:1766
+#, fuzzy, c-format
+msgid "%u server name: %s"
+msgstr "eroare DBus: %s"
+
+#: rfc2131.c:1774
+#, fuzzy, c-format
+msgid "%u next server: %s"
+msgstr "eroare DBus: %s"
+
+#: rfc2131.c:1777
+#, c-format
+msgid "%u broadcast response"
+msgstr ""
+
+#: rfc2131.c:1840
+#, fuzzy, c-format
+msgid "cannot send DHCP/BOOTP option %d: no space left in packet"
+msgstr "nu pot trimite opţiunea DHCP %d: nu mai este loc în pachet"
+
+#: rfc2131.c:2131
+msgid "PXE menu too large"
+msgstr ""
+
+#: rfc2131.c:2270 rfc3315.c:1515
+#, fuzzy, c-format
+msgid "%u requested options: %s"
+msgstr "compilat cu opţiunile: %s"
+
+#: rfc2131.c:2587
+#, c-format
+msgid "cannot send RFC3925 option: too many options for enterprise number %d"
+msgstr ""
+
+#: rfc2131.c:2650
+#, c-format
+msgid "%u reply delay: %d"
+msgstr ""
+
+#: netlink.c:77
+#, fuzzy, c-format
+msgid "cannot create netlink socket: %s"
+msgstr "nu pot să activez socket-ul netlink: %s"
+
+#: netlink.c:355
+#, fuzzy, c-format
+msgid "netlink returns error: %s"
+msgstr "eroare DBus: %s"
+
+#: dbus.c:186
+msgid "attempt to set an IPv6 server address via DBus - no IPv6 support"
+msgstr "incerc să configurez un server IPv6 prin Dbus - nu este suport IPv6"
+
+#: dbus.c:439
+#, c-format
+msgid "Enabling --%s option from D-Bus"
+msgstr ""
+
+#: dbus.c:444
+#, c-format
+msgid "Disabling --%s option from D-Bus"
+msgstr ""
+
+#: dbus.c:690
+msgid "setting upstream servers from DBus"
+msgstr "configurăm serverele superioare prin Dbus"
+
+#: dbus.c:737
+msgid "could not register a DBus message handler"
+msgstr "nu pot activa o interfaţă de mesaje DBus"
+
+#: bpf.c:265
+#, c-format
+msgid "cannot create DHCP BPF socket: %s"
+msgstr "nu pot creea socket DHCP BPF: %s"
+
+#: bpf.c:293
+#, fuzzy, c-format
+msgid "DHCP request for unsupported hardware type (%d) received on %s"
+msgstr "cerere DHCP pentru dispozitiv nesuportat (%d) recepţionată prin %s"
+
+#: bpf.c:378
+#, fuzzy, c-format
+msgid "cannot create PF_ROUTE socket: %s"
+msgstr "nu pot creea socket DHCP: %s"
+
+#: bpf.c:399
+msgid "Unknown protocol version from route socket"
+msgstr ""
+
+#: helper.c:153
+msgid "lease() function missing in Lua script"
+msgstr ""
+
+#: tftp.c:319
+msgid "unable to get free port for TFTP"
+msgstr ""
+
+#: tftp.c:335
+#, c-format
+msgid "unsupported request from %s"
+msgstr ""
+
+#: tftp.c:483
+#, fuzzy, c-format
+msgid "file %s not found"
+msgstr "împrumutul nu a fost găsit"
+
+#: tftp.c:592
+#, c-format
+msgid "error %d %s received from %s"
+msgstr ""
+
+#: tftp.c:634
+#, fuzzy, c-format
+msgid "failed sending %s to %s"
+msgstr "nu pot citi %s: %s"
+
+#: tftp.c:634
+#, c-format
+msgid "sent %s to %s"
+msgstr ""
+
+#: log.c:190
+#, c-format
+msgid "overflow: %d log entries lost"
+msgstr ""
+
+#: log.c:268
+#, c-format
+msgid "log failed: %s"
+msgstr ""
+
+#: log.c:471
+msgid "FAILED to start up"
+msgstr "pornirea A EŞUAT"
+
+#: conntrack.c:65
+#, c-format
+msgid "Conntrack connection mark retrieval failed: %s"
+msgstr ""
+
+#: dhcp6.c:52
+#, fuzzy, c-format
+msgid "cannot create DHCPv6 socket: %s"
+msgstr "nu pot creea socket DHCP: %s"
+
+#: dhcp6.c:73
+#, fuzzy, c-format
+msgid "failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"
+msgstr "configurarea SO_REUSEADDR pe socket-ul DHCP a eşuat: %s"
+
+#: dhcp6.c:85
+#, fuzzy, c-format
+msgid "failed to bind DHCPv6 server socket: %s"
+msgstr "activarea socket-ului server-ului DHCP a eşuat: %s"
+
+#: rfc3315.c:157
+#, fuzzy, c-format
+msgid "no address range available for DHCPv6 request from relay at %s"
+msgstr "nici un domeniu de adrese disponibil pentru cererea DHCP %s %s"
+
+#: rfc3315.c:166
+#, fuzzy, c-format
+msgid "no address range available for DHCPv6 request via %s"
+msgstr "nici un domeniu de adrese disponibil pentru cererea DHCP %s %s"
+
+#: rfc3315.c:303
+#, fuzzy, c-format
+msgid "%u available DHCPv6 subnet: %s/%d"
+msgstr "nici un domeniu de adrese disponibil pentru cererea DHCP %s %s"
+
+#: rfc3315.c:386
+#, fuzzy, c-format
+msgid "%u vendor class: %u"
+msgstr "eroare DBus: %s"
+
+#: rfc3315.c:434
+#, fuzzy, c-format
+msgid "%u client MAC address: %s"
+msgstr "nu exista interfaţă pentru adresa %s"
+
+#: rfc3315.c:673
+#, fuzzy, c-format
+msgid "unknown prefix-class %d"
+msgstr "împrumut necunoscut"
+
+#: rfc3315.c:816 rfc3315.c:911
+#, fuzzy
+msgid "address unavailable"
+msgstr "adresă indisponibilă"
+
+#: rfc3315.c:828 rfc3315.c:959 rfc3315.c:1292
+msgid "success"
+msgstr ""
+
+#: rfc3315.c:843 rfc3315.c:852 rfc3315.c:967 rfc3315.c:969
+#, fuzzy
+msgid "no addresses available"
+msgstr "nici o adresă disponibilă"
+
+#: rfc3315.c:946
+msgid "not on link"
+msgstr ""
+
+#: rfc3315.c:1019 rfc3315.c:1204 rfc3315.c:1281
+msgid "no binding found"
+msgstr ""
+
+#: rfc3315.c:1057
+msgid "deprecated"
+msgstr ""
+
+#: rfc3315.c:1062
+#, fuzzy
+msgid "address invalid"
+msgstr "adresa este folosită"
+
+#: rfc3315.c:1109
+msgid "confirm failed"
+msgstr ""
+
+#: rfc3315.c:1125
+#, fuzzy
+msgid "all addresses still on link"
+msgstr "adresă greşită în %s, linia %d"
+
+#: rfc3315.c:1213
+msgid "release received"
+msgstr ""
+
+#: rfc3315.c:2140
+msgid "Cannot multicast to DHCPv6 server without correct interface"
+msgstr ""
+
+#: dhcp-common.c:145
+#, c-format
+msgid "Ignoring duplicate dhcp-option %d"
+msgstr ""
+
+#: dhcp-common.c:222
+#, c-format
+msgid "%u tags: %s"
+msgstr ""
+
+#: dhcp-common.c:407
+#, c-format
+msgid "%s has more than one address in hostsfile, using %s for DHCP"
+msgstr ""
+
+#: dhcp-common.c:430
+#, c-format
+msgid "duplicate IP address %s (%s) in dhcp-config directive"
+msgstr "adresă IP duplicat %s (%s) în declaraţia dhcp-config."
+
+#: dhcp-common.c:494
+#, fuzzy, c-format
+msgid "failed to set SO_BINDTODEVICE on DHCP socket: %s"
+msgstr "configurarea SO_REUSEADDR pe socket-ul DHCP a eşuat: %s"
+
+#: dhcp-common.c:615
+#, c-format
+msgid "Known DHCP options:\n"
+msgstr ""
+
+#: dhcp-common.c:626
+#, c-format
+msgid "Known DHCPv6 options:\n"
+msgstr ""
+
+#: dhcp-common.c:823
+msgid ", prefix deprecated"
+msgstr ""
+
+#: dhcp-common.c:826
+#, c-format
+msgid ", lease time "
+msgstr ""
+
+#: dhcp-common.c:868
+#, c-format
+msgid "%s stateless on %s%.0s%.0s%s"
+msgstr ""
+
+#: dhcp-common.c:870
+#, fuzzy, c-format
+msgid "%s, static leases only on %.0s%s%s%.0s"
+msgstr "DHCP, împrumuturi statice doar către  %.0s%s, timpul reînoirii %s"
+
+#: dhcp-common.c:872
+#, c-format
+msgid "%s, proxy on subnet %.0s%s%.0s%.0s"
+msgstr ""
+
+#: dhcp-common.c:873
+#, fuzzy, c-format
+msgid "%s, IP range %s -- %s%s%.0s"
+msgstr "DHCP, domeniu IP %s -- %s, timpul reînoirii %s"
+
+#: dhcp-common.c:886
+#, c-format
+msgid "DHCPv4-derived IPv6 names on %s%s"
+msgstr ""
+
+#: dhcp-common.c:889
+#, fuzzy, c-format
+msgid "router advertisement on %s%s"
+msgstr "DHCP, împrumuturi statice doar către  %.0s%s, timpul reînoirii %s"
+
+#: dhcp-common.c:900
+#, c-format
+msgid "DHCP relay from %s to %s via %s"
+msgstr ""
+
+#: dhcp-common.c:902
+#, c-format
+msgid "DHCP relay from %s to %s"
+msgstr ""
+
+#: radv.c:110
+#, fuzzy, c-format
+msgid "cannot create ICMPv6 socket: %s"
+msgstr "nu pot creea socket DHCP: %s"
+
+#: auth.c:449
+#, c-format
+msgid "ignoring zone transfer request from %s"
+msgstr ""
+
+#: ipset.c:95
+#, fuzzy, c-format
+msgid "failed to find kernel version: %s"
+msgstr "activarea socket-ului server-ului DHCP a eşuat: %s"
+
+#: ipset.c:114
+#, fuzzy, c-format
+msgid "failed to create IPset control socket: %s"
+msgstr "creearea socket-ului de ascultare a eşuat: %s"
+
+#: ipset.c:233
+#, fuzzy, c-format
+msgid "failed to update ipset %s: %s"
+msgstr "nu pot citi %s: %s"
+
+#: dnssec.c:527
+msgid "system time considered valid, now checking DNSSEC signature timestamps."
+msgstr ""
+
+#: blockdata.c:58
+#, c-format
+msgid "DNSSEC memory in use %u, max %u, allocated %u"
+msgstr ""
+
+#: tables.c:61
+#, fuzzy, c-format
+msgid "failed to access pf devices: %s"
+msgstr "accesarea serverului %s a eşuat: %s"
+
+#: tables.c:74
+#, fuzzy, c-format
+msgid "warning: no opened pf devices %s"
+msgstr "folosim adresele locale doar pentru %S %s"
+
+#: tables.c:82
+#, fuzzy, c-format
+msgid "error: cannot use table name %s"
+msgstr "nu pot citi numele maşinii: %s"
+
+#: tables.c:90
+#, c-format
+msgid "error: cannot strlcpy table name %s"
+msgstr ""
+
+#: tables.c:101
+#, fuzzy, c-format
+msgid "IPset: error:%s"
+msgstr "eroare DBus: %s"
+
+#: tables.c:108
+msgid "info: table created"
+msgstr ""
+
+#: tables.c:134
+#, c-format
+msgid "warning: DIOCR%sADDRS: %s"
+msgstr ""
+
+#: tables.c:138
+#, fuzzy, c-format
+msgid "%d addresses %s"
+msgstr "citesc %s - %d adrese"
+
+#: inotify.c:62
+#, fuzzy, c-format
+msgid "cannot access path %s: %s"
+msgstr "nu pot citi %s: %s"
+
+#: inotify.c:95
+#, fuzzy, c-format
+msgid "failed to create inotify: %s"
+msgstr "nu pot citi %s: %s"
+
+#: inotify.c:111
+#, c-format
+msgid "too many symlinks following %s"
+msgstr ""
+
+#: inotify.c:127
+#, c-format
+msgid "directory %s for resolv-file is missing, cannot poll"
+msgstr ""
+
+#: inotify.c:131 inotify.c:168
+#, fuzzy, c-format
+msgid "failed to create inotify for %s: %s"
+msgstr "creearea socket-ului de ascultare a eşuat: %s"
+
+#: inotify.c:153
+#, fuzzy, c-format
+msgid "bad dynamic directory %s: %s"
+msgstr "nu pot citi %s: %s"
+
+#: inotify.c:255
+#, c-format
+msgid "inotify, new or changed file %s"
+msgstr ""
+
+#, fuzzy
+#~ msgid "cannot cannonicalise resolv-file %s: %s"
+#~ msgstr "nu pot creea sau deschide fişierul cu împrumuturi: %s"
+
+#~ msgid "duplicate IP address %s in dhcp-config directive."
+#~ msgstr "adresă IP duplicat %s în declaraţia dhcp-config."
+
+#, fuzzy
+#~ msgid "Specify path to Lua script (no default)."
+#~ msgstr "Specifică o cale pentru fişierul PID. (implicit %s)."
+
+#~ msgid "TXT record string too long"
+#~ msgstr "şirul de caractere pentru înregistrarea TXT este prea lung"
+
+#~ msgid "failed to set IPV6 options on listening socket: %s"
+#~ msgstr "configurarea opţiunilor IPv6 a eşuat pe socket-ul de ascultare: %s"
+
+#~ msgid "failed to bind listening socket for %s: %s"
+#~ msgstr "activarea socket-ului de ascultare pentru %s a eşuat: %s"
+
+#~ msgid "must set exactly one interface on broken systems without IP_RECVIF"
+#~ msgstr "trebuie specificată exact o singură interfaţă pe sistemele defectece nu au IP_RECVIF"
+
+#~ msgid "Ignoring DHCP lease for %s because it has an illegal domain part"
+#~ msgstr "Împrumutul DHCP pentru %s va fi ignorat deoarece are domeniu invalid"
+
+#~ msgid "ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h"
+#~ msgstr "Integrarea cu ISC dhcpd nu este disponibilă:puneţi HAVE_ISC_HEADER în src/config.h"
+
+#, fuzzy
+#~ msgid "illegal domain %s in dhcp-config directive."
+#~ msgstr "adresă IP duplicat %s în declaraţia dhcp-config."
+
+#~ msgid "running as root"
+#~ msgstr "rulez ca root"
+
+#, fuzzy
+#~ msgid "read %s - %d hosts"
+#~ msgstr "citesc %s - %d adrese"
+
+#~ msgid "domains"
+#~ msgstr "domenii"
+
+#~ msgid "Ignoring DHCP host name %s because it has an illegal domain part"
+#~ msgstr "Ignor numele DHCP al maşinii %s deoarece are domeniu DNS ilegal"
+
+#~ msgid "Display this message."
+#~ msgstr "Afişează acest mesaj."
+
+#~ msgid "failed to read %s:%m"
+#~ msgstr "citirea %s:%n a eşuat"
+
+#, fuzzy
+#~ msgid "cannot send encapsulated option %d: no space left in wrapper"
+#~ msgstr "nu pot trimite opţiunea DHCP %d: nu mai este loc în pachet"
+
+#~ msgid "More than one vendor class matches, using %s"
+#~ msgstr "Se potrivesc mai multe clase de mărci de interfeţe, folosim %s"
+
+#~ msgid "forwarding table overflow: check for server loops."
+#~ msgstr "depăşire de memorie în tabela cu înaintări DNS: verificaţi de bucle."
+
+#~ msgid "nested includes not allowed"
+#~ msgstr "incluziunile locale nu sunt permise"
+
+#~ msgid "DHCP, %s will be written every %s"
+#~ msgstr "DHCP, %s va fi rescris odată la fiecare %s"
+
+#~ msgid "cannot create DHCP packet socket: %s. Is CONFIG_PACKET enabled in your kernel?"
+#~ msgstr "nu pot creea socket DHCP packet: %s. Aveţi activată în nucleulsistemului opţiunea CONFIG_PACKET ?"
diff --git a/setup.html b/setup.html
new file mode 100755
index 0000000..fe831f6
--- /dev/null
+++ b/setup.html
@@ -0,0 +1,231 @@
+<HTML>
+<HEAD>
+<TITLE> Configuring Dnsmasq.</TITLE>
+</HEAD>
+<BODY BGCOLOR="WHITE"> 
+<H1 ALIGN=center>Dnsmasq setup</H1> 
+<H2>Installation.</H2>
+To compile and install dnsmasq, the following command (as root) is enough.
+
+<PRE>
+make install
+</PRE>
+
+You might want to edit config.h. Dnsmasq has
+been run on (at least) Linux, uCLinux, AIX 4.1.5, FreeBSD 4.4 OpenBSD and Tru64 4.x 
+
+Dnsmasq is normally  run on a firewall machine (the machine with the
+modem or other connection to your ISP.) but it can run on any machine
+with access to the ISPs nameservers.
+
+Put the binary in <TT>/usr/local/sbin/dnsmasq</TT> (running <TT>make install</TT>  will do this) and arrange for it
+to be started at boot time.
+
+Note that dnsmasq needs to run as root, since it binds privileged ports. It will drop root privileges after start-up. Dnsmasq
+logs problems using the syslog facility as a daemon. It logs debugging
+information to local0
+<P>
+<H2>Configuration.</H2>
+Configuration for dnsmasq is pretty simple in almost all cases. The
+program has collected a fair few options as it has developed but most of them
+are not needed most of the time. A machine which already has a DNS
+configuration (ie one or more external nameservers in <TT>/etc/resolv.conf</TT>
+and any local hosts in <TT>/etc/hosts</TT>) can be turned into a nameserver
+simply by running dnsmasq, with no options or configuration at
+all. Set the IP address of the machine running dnsmasq as the DNS
+server in all the other machines on your network, and you're done.
+<P>
+With a few option flags, it is possible to make dnsmasq do more clever
+tricks. Options for dnsmasq can be set either on the command line
+when starting dnsmasq, or in its configuration file, <TT>/etc/dnsmasq.conf</TT>.
+
+<h2>Making the nameserver machine use dnsmasq.</h2>
+In the simple configuration described above, processes local to the
+machine will not use dnsmasq, since they get their information about
+which nameservers to use from /etc/resolv.conf, which is set to the
+upstream nameservers. To fix this, simply replace the nameserver in
+<TT>/etc/resolv.conf</TT> with the local address 127.0.0.1 and give the
+address(es) of the upstream nameserver(s) to dnsmasq directly. You can
+do this using either the <TT>server</TT> option, or by putting them into
+another file, and telling  dnsmasq about its location with 
+the <TT>resolv-file</TT> option. 
+
+<h2>Automatic nameserver configuration.</h2>
+The two protocols most used for automatic IP network configuration
+(PPP and DHCP) can determine the IP addresses for nameservers automatically.
+The daemons can be made to write out a file in the resolv.conf format with the
+nameservers in which is perfect for dnsmasq to use. When the
+nameservers change, for instance on dialling into a new ISP using PPP,
+dnsmasq will automatically re-read this file and begin using the new
+nameserver(s) completely transparently.
+
+<h3>Automatic DNS server configuration with PPP.</h3>
+Later versions of pppd have an option "usepeerdns" which instructs it to write a file containing
+the address(es) of the DNS severs in <TT>/etc/ppp/resolv.conf</TT>. Configure dnsmasq
+as above with "nameserver 127.0.0.1" in <TT>/etc/resolv.conf</TT> and run dnsmasq 
+with to option <TT>resolv-file=/etc/ppp/resolv.conf</TT>.
+<P>
+On Redhat (at least versions 7.1, 7.2 and 7.3) you can set pppd
+options by adding "PPPOPTIONS=usepeerdns" to
+<TT>/etc/sysconfig/network-scripts/ifcfg-ippp0</TT>.  In the same file, make sure
+that "PEERDNS=no" to stop RedHat's network initscripts from copying
+<TT>/etc/ppp/resolv.conf</TT> into <TT>/etc/resolv.conf</TT>.<BR>
+
+On SuSE (at least version 8.1, and 8.2) you should use YaST to activate
+<TT>[x] Modify DNS when connected</TT> then stop SuSEs network initscripts 
+from copying <TT>/etc/ppp/resolv.conf</TT> into <TT>/etc/resolv.conf</TT> 
+by modifying MODIFY_RESOLV_CONF_DYNAMICALLY="no" in <TT>/etc/sysconfig/network/config</TT>.
+ 
+
+<h3>Automatic DNS server configuration with DHCP.</h3>
+You need to get your DHCP client to write the address(es) of the DNS
+servers to a file other than <TT>/etc/resolv.conf</TT>. For dhcpcd, the
+<TT>dhcpcd.exe</TT> script gets run with the addresses of the nameserver(s) in
+the shell variable <TT>$DNS</TT>. The following bit of shell script
+uses that to write a file suitable for dnsmasq. 
+<PRE>
+
+echo -n >|/etc/dhcpc/resolv.conf
+dnsservers=${DNS//,/ }
+for serv in $dnsservers; do
+    echo "nameserver $serv" >>/etc/dhcpc/resolv.conf
+done
+
+</PRE>
+ 
+Remember to give dhcpcd the <TT>-R</TT> flag to stop it overwriting 
+<TT>/etc/resolv.conf</TT>.
+
+<P>
+For other DHCP clients it should be possible to achieve the same effect.
+
+<h3> DHCP and PPP.</h3>
+On a laptop which may potentially connect via a modem and PPP or
+ethernet and DHCP it is possible to combine both of the above
+configurations. Running dnsmasq with the flags
+<TT>resolv-file=/etc/ppp/resolv.conf resolv-file=/etc/dhcpc/resolv.conf</TT>  
+makes it poll <B>both</B> files and use whichever was updated
+last. The result is automatic switching between DNS servers.
+</H3>
+
+<H2> Integration with DHCP.</H2>
+Dnsmasq reads <TT>/etc/hosts</TT> so that the names of local machines are
+available in DNS. This is fine when you give all your local machines
+static IP addresses which can go in <TT>/etc/hosts</TT>, but it doesn't work 
+when local machines are configured via DHCP, since the IP address
+allocated to machine is not fixed. Dnsmasq comes with an integrated
+DHCP daemon to solve this problem.
+<P>
+The dnsmasq DHCP daemon allocates addresses to hosts on the network and tries
+to determine their names. If it succeeds it add the name and address
+pair to the DNS. There are basically two ways to associate a name with
+a DHCP-configured machine; either the machine knows its name which it
+gets a DHCP lease, or dnsmasq gives it a name, based on the MAC
+address of its ethernet card. For the former to work, a machine needs to know its name when it
+requests a DHCP lease. For dhcpcd, the -h option specifies this. The
+names may be anything as far as DHCP is concerned, but dnsmasq adds
+some limitations. By default the names must no have a domain part, ie
+they must just be a alphanumeric name, without any dots.  This is a
+security feature to stop a machine on your network telling DHCP that
+its name is "www.microsoft.com" and thereby grabbing traffic which
+shouldn't go to it. A domain part is only allowed by dnsmasq in DHCP machine names
+if the <TT>domain-suffix</TT> option is set, the domain part must match the
+suffix.
+<P>
+As an aside, make sure not to tell DHCP to set the hostname when it
+obtains a lease (in dhcpcd that's the -H flag.)
+This is not reliable since the DHCP server gets the
+hostname from DNS which in this case is dnsmasq. There is a race
+condition because the host's name in the DNS may change as a
+result of it getting a DHCP lease, but this does not propagate before
+the name is looked up. The net effect may be that the host believes it
+is called something different to its name in the DNS. To be safe, set
+the hostname on a machine locally, and pass the same name to DHCP when
+requesting a lease.
+<P>
+<H2>Setting up a mailhub.</H2>
+If you generate mail on the machines attached to your private network, you may
+ be interested in the MX record feature of dnsmasq. This allows you to have all
+ the machines on your network use your firewall or another machine as a "smarthost" and 
+deliver mail to it. The details of how to set this up are highly dependent on
+your mailer, system and distribution. The only thing that's relevant to dnsmasq is that the mailer 
+needs to be able to interrogate the DNS and find an MX record for your mailhub.
+<P>
+By giving dnsmasq the <TT>mx-host</TT> option
+you instruct dnsmasq to serve an MX record for the specified address. 
+By default the MX record 
+points to the machine on which dnsmasq is running, so mail delivered to that
+name will get sent to the mailer on your firewall machine. You can
+have the MX record point to another machine by using the <TT>mx-target</TT>
+option.
+<P>
+In some cases it's useful for all local machines to see an MX record
+pointing at themselves: this allows mailers which insist on an MX record and
+don't fall back to A records to deliver mail within the
+machine. These MX records are enabled using the <TT>selfmx</TT> option.
+
+<H2>Using special servers.</H2>
+Dnsmasq has the ability to direct DNS queries for certain domains to
+specific upstream nameservers. This feature was added for use with
+VPNs but it is fully general. The scenario is this: you have a
+standard internet connection via an ISP, and dnsmasq is configured to
+forward queries to the ISP's nameservers, then you make a VPN
+connection into your companies network, giving access to hosts inside
+the company firewall. You have access, but since many of the internal hosts
+aren't visible on the public internet, your company doesn't publish 
+them to the public DNS and you can't get their IP address from the ISP
+nameservers. The solution is to use the companies nameserver for
+private domains within the company, and dnsmasq allows this. Assuming
+that internal company machines are all in the domain internal.myco.com
+and the companies nameserver is at 192.168.10.1 then the option
+<TT>server=/internal.myco.com/192.168.10.1</TT> will direct all
+queries in the internal domain to the correct nameserver. You can
+specify more than one domain in each server option. If there is
+more than one nameserver just include as many
+<TT>server</TT> options as is needed to specify them all.  
+
+<H2>Local domains.</H2>
+Sometimes people have local domains which they do not want forwarded
+to upstream servers. This is accommodated by using server options
+without the server IP address. To make things clearer <TT>local</TT>
+is a synonym for <TT>server</TT>. For example the option
+<TT>local=/localnet/</TT> ensures that any domain name query which ends in
+<TT>.localnet</TT> will be answered if possible from
+<TT>/etc/hosts</TT> or DHCP, but never sent to an upstream server.
+
+<H2>Defeating wildcards in top level domains.</H2>
+In September 2003 Verisign installed a wildcard record in the .com and
+.net top level domains. The effect of this is that queries for
+unregistered .com and .net names now return the address of Verisign's
+sitefinder service, rather than a "no such domain" response. To
+restore the correct behaviour, you can tell dnsmasq the address of the
+sitefinder host and have it substitute an NXDOMAIN reply when it sees
+that address. The sitefinder address is currently  64.94.110.11, so
+giving the option <TT>bogus-nxdomain=64.94.110.11</TT> will enable
+this facility for Verisign. If other TLDs do that same thing you can
+add the correct addresses for them too. See the dnsmasq FAQ for more
+details on the <TT>bogus-nxdomain</TT> option.
+ 
+<H2>Other configuration details.</H2>
+By default dnsmasq offers DNS service on all the configured interfaces
+of a host. It's likely that you don't (for instance) want to offer a
+DNS service to the world via an interface connected to ADSL or
+cable-modem so dnsmasq allows you to specify which interfaces it will
+listen on. Use either the <TT>interface</TT> or <TT>address</TT> options to do this.
+<P>
+The <TT>filterwin2k</TT> option makes dnsmasq ignore certain DNS requests which
+are made by Windows boxen every few minutes. The requests generally
+don't get sensible answers in the global DNS and cause trouble by
+triggering dial-on-demand internet links.
+<P>
+Sending SIGHUP to the dnsmasq process will cause it to empty its cache and 
+then re-load <TT>/etc/hosts</TT> and <TT>/etc/resolv.conf</TT>.
+<P> Sending SIGUSR1 (killall -10 dnsmasq) to the dnsmasq process will
+cause to write cache usage statisticss to the log, typically
+<TT>/var/log/syslog</TT> or <TT>/var/log/messages</TT>.
+<P> The <TT>log-queries</TT> option tells dnsmasq to verbosely log the queries
+it is handling and causes SIGUSR1 to trigger a complete dump of the
+contents of the cache to the syslog.
+
+<P>For a complete listing of options please take a look at the manpage
+dnsmasq(8).
diff --git a/src/Android.mk b/src/Android.mk
new file mode 100644
index 0000000..b9f4e41
--- /dev/null
+++ b/src/Android.mk
@@ -0,0 +1,54 @@
+LOCAL_PATH := $(call my-dir)
+
+DNSMASQ_USE_DBUS ?= no
+DNSMASQ_USE_IPV6 ?= no
+DNSMASQ_USE_INOTIFY ?= no
+#########################
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES :=  bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
+                    forward.c helper.c lease.c log.c \
+                    netlink.c network.c option.c rfc1035.c \
+		    rfc2131.c tftp.c util.c conntrack.c \
+		    dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
+		    radv.c slaac.c auth.c ipset.c domain.c \
+	            dnssec.c blockdata.c tables.c \
+		    loop.c inotify.c poll.c rrfilter.c edns0.c arp.c
+
+LOCAL_MODULE := dnsmasq
+
+LOCAL_C_INCLUDES := external/dnsmasq/src
+
+LOCAL_CFLAGS := -O2 -g -W -Wall -Wno-pointer-arith -Wno-sign-compare -Wno-shift-count-overflow -Wno-shift-count-negative
+
+# version string flag
+DNSMASQ_VERSION := $(shell $(LOCAL_PATH)/../bld/get-version $(shell pwd)/$(LOCAL_PATH)/..)
+LOCAL_CFLAGS += -DVERSION='"$(DNSMASQ_VERSION)"'
+
+# config flags
+LOCAL_CFLAGS += -D__ANDROID__ -DNO_TFTP -DNO_AUTH -DNO_SCRIPT
+
+ifneq ($(BUILD_EUREKA),)
+LOCAL_CFLAGS += -DEUREKA
+endif
+
+# HAVE_DBUS is not defined by default
+ifeq ($(DNSMASQ_USE_DBUS), yes)
+LOCAL_CFLAGS += -DHAVE_DBUS
+LOCAL_SHARED_LIBRARIES += libdbus
+LOCAL_C_INCLUDES += external/dbus
+endif
+
+# HAVE_IPV6 is defined by default
+ifeq ($(DNSMASQ_USE_IPV6), no)
+LOCAL_CFLAGS += -DNO_IPV6
+endif
+
+# HAVE_INOTIFY is defined by default
+ifeq ($(DNSMASQ_USE_INOTIFY), no)
+LOCAL_CFLAGS += -DNO_INOTIFY
+endif
+
+LOCAL_SYSTEM_SHARED_LIBRARIES := liblog
+
+include $(BUILD_EXECUTABLE)
diff --git a/src/NOTICE b/src/NOTICE
new file mode 100755
index 0000000..60549be
--- /dev/null
+++ b/src/NOTICE
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    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; either version 2 of the License, or
+    (at your option) any later version.
+
+    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.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/src/arp.c b/src/arp.c
new file mode 100644
index 0000000..97490bd
--- /dev/null
+++ b/src/arp.c
@@ -0,0 +1,247 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+/* Time between forced re-loads from kernel. */
+#define INTERVAL 90
+
+#define ARP_MARK  0
+#define ARP_FOUND 1  /* Confirmed */
+#define ARP_NEW   2  /* Newly created */
+#define ARP_EMPTY 3  /* No MAC addr */
+
+struct arp_record {
+  unsigned short hwlen, status;
+  int family;
+  unsigned char hwaddr[DHCP_CHADDR_MAX]; 
+  struct all_addr addr;
+  struct arp_record *next;
+};
+
+static struct arp_record *arps = NULL, *old = NULL, *freelist = NULL;
+static time_t last = 0;
+
+static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
+{
+  struct arp_record *arp;
+
+  (void)parmv;
+
+  if (maclen > DHCP_CHADDR_MAX)
+    return 1;
+
+#ifndef HAVE_IPV6
+  if (family != AF_INET)
+    return 1;
+#endif
+
+  /* Look for existing entry */
+  for (arp = arps; arp; arp = arp->next)
+    {
+      if (family != arp->family || arp->status == ARP_NEW)
+	continue;
+      
+      if (family == AF_INET)
+	{
+	  if (arp->addr.addr.addr4.s_addr != ((struct in_addr *)addrp)->s_addr)
+	    continue;
+	}
+#ifdef HAVE_IPV6
+      else
+	{
+	  if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, (struct in6_addr *)addrp))
+	    continue;
+	}
+#endif
+
+      if (arp->status == ARP_EMPTY)
+	{
+	  /* existing address, was negative. */
+	  arp->status = ARP_NEW;
+	  arp->hwlen = maclen;
+	  memcpy(arp->hwaddr, mac, maclen);
+	}
+      else if (arp->hwlen == maclen && memcmp(arp->hwaddr, mac, maclen) == 0)
+	/* Existing entry matches - confirm. */
+	arp->status = ARP_FOUND;
+      else
+	continue;
+      
+      break;
+    }
+
+  if (!arp)
+    {
+      /* New entry */
+      if (freelist)
+	{
+	  arp = freelist;
+	  freelist = freelist->next;
+	}
+      else if (!(arp = whine_malloc(sizeof(struct arp_record))))
+	return 1;
+      
+      arp->next = arps;
+      arps = arp;
+      arp->status = ARP_NEW;
+      arp->hwlen = maclen;
+      arp->family = family;
+      memcpy(arp->hwaddr, mac, maclen);
+      if (family == AF_INET)
+	arp->addr.addr.addr4.s_addr = ((struct in_addr *)addrp)->s_addr;
+#ifdef HAVE_IPV6
+      else
+	memcpy(&arp->addr.addr.addr6, addrp, IN6ADDRSZ);
+#endif
+    }
+  
+  return 1;
+}
+
+/* If in lazy mode, we cache absence of ARP entries. */
+int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now)
+{
+  struct arp_record *arp, *tmp, **up;
+  int updated = 0;
+
+ again:
+  
+  /* If the database is less then INTERVAL old, look in there */
+  if (difftime(now, last) < INTERVAL)
+    {
+      /* addr == NULL -> just make cache up-to-date */
+      if (!addr)
+	return 0;
+
+      for (arp = arps; arp; arp = arp->next)
+	{
+	  if (addr->sa.sa_family != arp->family)
+	    continue;
+	    
+	  if (arp->family == AF_INET &&
+	      arp->addr.addr.addr4.s_addr != addr->in.sin_addr.s_addr)
+	    continue;
+	    
+#ifdef HAVE_IPV6
+	  if (arp->family == AF_INET6 && 
+	      !IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, &addr->in6.sin6_addr))
+	    continue;
+#endif
+	  
+	  /* Only accept positive entries unless in lazy mode. */
+	  if (arp->status != ARP_EMPTY || lazy || updated)
+	    {
+	      if (mac && arp->hwlen != 0)
+		memcpy(mac, arp->hwaddr, arp->hwlen);
+	      return arp->hwlen;
+	    }
+	}
+    }
+
+  /* Not found, try the kernel */
+  if (!updated)
+     {
+       updated = 1;
+       last = now;
+
+       /* Mark all non-negative entries */
+       for (arp = arps; arp; arp = arp->next)
+	 if (arp->status != ARP_EMPTY)
+	   arp->status = ARP_MARK;
+       
+       iface_enumerate(AF_UNSPEC, NULL, filter_mac);
+       
+       /* Remove all unconfirmed entries to old list. */
+       for (arp = arps, up = &arps; arp; arp = tmp)
+	 {
+	   tmp = arp->next;
+	   
+	   if (arp->status == ARP_MARK)
+	     {
+	       *up = arp->next;
+	       arp->next = old;
+	       old = arp;
+	     }
+	   else
+	     up = &arp->next;
+	 }
+
+       goto again;
+     }
+
+  /* record failure, so we don't consult the kernel each time
+     we're asked for this address */
+  if (freelist)
+    {
+      arp = freelist;
+      freelist = freelist->next;
+    }
+  else
+    arp = whine_malloc(sizeof(struct arp_record));
+  
+  if (arp)
+    {      
+      arp->next = arps;
+      arps = arp;
+      arp->status = ARP_EMPTY;
+      arp->family = addr->sa.sa_family;
+      arp->hwlen = 0;
+
+      if (addr->sa.sa_family == AF_INET)
+	arp->addr.addr.addr4.s_addr = addr->in.sin_addr.s_addr;
+#ifdef HAVE_IPV6
+      else
+	memcpy(&arp->addr.addr.addr6, &addr->in6.sin6_addr, IN6ADDRSZ);
+#endif
+    }
+	  
+   return 0;
+}
+
+int do_arp_script_run(void)
+{
+  struct arp_record *arp;
+  
+  /* Notify any which went, then move to free list */
+  if (old)
+    {
+#ifdef HAVE_SCRIPT
+      if (option_bool(OPT_SCRIPT_ARP))
+	queue_arp(ACTION_ARP_DEL, old->hwaddr, old->hwlen, old->family, &old->addr);
+#endif
+      arp = old;
+      old = arp->next;
+      arp->next = freelist;
+      freelist = arp;
+      return 1;
+    }
+
+  for (arp = arps; arp; arp = arp->next)
+    if (arp->status == ARP_NEW)
+      {
+#ifdef HAVE_SCRIPT
+	if (option_bool(OPT_SCRIPT_ARP))
+	  queue_arp(ACTION_ARP, arp->hwaddr, arp->hwlen, arp->family, &arp->addr);
+#endif
+	arp->status = ARP_FOUND;
+	return 1;
+      }
+
+  return 0;
+}
+
+
diff --git a/src/auth.c b/src/auth.c
new file mode 100644
index 0000000..7f95f98
--- /dev/null
+++ b/src/auth.c
@@ -0,0 +1,889 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_AUTH
+
+static struct addrlist *find_addrlist(struct addrlist *list, int flag, struct all_addr *addr_u)
+{
+  do {
+    if (!(list->flags & ADDRLIST_IPV6))
+      {
+	struct in_addr netmask, addr = addr_u->addr.addr4;
+	
+	if (!(flag & F_IPV4))
+	  continue;
+	
+	netmask.s_addr = htonl(~(in_addr_t)0 << (32 - list->prefixlen));
+	
+	if  (is_same_net(addr, list->addr.addr.addr4, netmask))
+	  return list;
+      }
+#ifdef HAVE_IPV6
+    else if (is_same_net6(&(addr_u->addr.addr6), &list->addr.addr.addr6, list->prefixlen))
+      return list;
+#endif
+    
+  } while ((list = list->next));
+  
+  return NULL;
+}
+
+static struct addrlist *find_subnet(struct auth_zone *zone, int flag, struct all_addr *addr_u)
+{
+  if (!zone->subnet)
+    return NULL;
+  
+  return find_addrlist(zone->subnet, flag, addr_u);
+}
+
+static struct addrlist *find_exclude(struct auth_zone *zone, int flag, struct all_addr *addr_u)
+{
+  if (!zone->exclude)
+    return NULL;
+  
+  return find_addrlist(zone->exclude, flag, addr_u);
+}
+
+static int filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u)
+{
+  if (find_exclude(zone, flag, addr_u))
+    return 0;
+
+  /* No subnets specified, no filter */
+  if (!zone->subnet)
+    return 1;
+  
+  return find_subnet(zone, flag, addr_u) != NULL;
+}
+
+int in_zone(struct auth_zone *zone, char *name, char **cut)
+{
+  size_t namelen = strlen(name);
+  size_t domainlen = strlen(zone->domain);
+
+  if (cut)
+    *cut = NULL;
+  
+  if (namelen >= domainlen && 
+      hostname_isequal(zone->domain, &name[namelen - domainlen]))
+    {
+      
+      if (namelen == domainlen)
+	return 1;
+      
+      if (name[namelen - domainlen - 1] == '.')
+	{
+	  if (cut)
+	    *cut = &name[namelen - domainlen - 1]; 
+	  return 1;
+	}
+    }
+
+  return 0;
+}
+
+
+size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, 
+		   int local_query, int do_bit, int have_pseudoheader) 
+{
+  char *name = daemon->namebuff;
+  unsigned char *p, *ansp;
+  int qtype, qclass;
+  int nameoffset, axfroffset = 0;
+  int q, anscount = 0, authcount = 0;
+  struct crec *crecp;
+  int  auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0;
+  struct auth_zone *zone = NULL;
+  struct addrlist *subnet = NULL;
+  char *cut;
+  struct mx_srv_record *rec, *move, **up;
+  struct txt_record *txt;
+  struct interface_name *intr;
+  struct naptr *na;
+  struct all_addr addr;
+  struct cname *a, *candidate;
+  unsigned int wclen;
+  
+  if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
+    return 0;
+
+  /* determine end of question section (we put answers there) */
+  if (!(ansp = skip_questions(header, qlen)))
+    return 0; /* bad packet */
+  
+  /* now process each question, answers go in RRs after the question */
+  p = (unsigned char *)(header+1);
+
+  for (q = ntohs(header->qdcount); q != 0; q--)
+    {
+      unsigned short flag = 0;
+      int found = 0;
+      int cname_wildcard = 0;
+  
+      /* save pointer to name for copying into answers */
+      nameoffset = p - (unsigned char *)header;
+
+      /* now extract name as .-concatenated string into name */
+      if (!extract_name(header, qlen, &p, name, 1, 4))
+	return 0; /* bad packet */
+ 
+      GETSHORT(qtype, p); 
+      GETSHORT(qclass, p);
+      
+      if (qclass != C_IN)
+	{
+	  auth = 0;
+	  continue;
+	}
+
+      if ((qtype == T_PTR || qtype == T_SOA || qtype == T_NS) &&
+	  (flag = in_arpa_name_2_addr(name, &addr)) &&
+	  !local_query)
+	{
+	  for (zone = daemon->auth_zones; zone; zone = zone->next)
+	    if ((subnet = find_subnet(zone, flag, &addr)))
+	      break;
+	  
+	  if (!zone)
+	    {
+	      auth = 0;
+	      continue;
+	    }
+	  else if (qtype == T_SOA)
+	    soa = 1, found = 1;
+	  else if (qtype == T_NS)
+	    ns = 1, found = 1;
+	}
+
+      if (qtype == T_PTR && flag)
+	{
+	  intr = NULL;
+
+	  if (flag == F_IPV4)
+	    for (intr = daemon->int_names; intr; intr = intr->next)
+	      {
+		struct addrlist *addrlist;
+		
+		for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
+		  if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
+		    break;
+		
+		if (addrlist)
+		  break;
+		else
+		  while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
+		    intr = intr->next;
+	      }
+#ifdef HAVE_IPV6
+	  else if (flag == F_IPV6)
+	    for (intr = daemon->int_names; intr; intr = intr->next)
+	      {
+		struct addrlist *addrlist;
+		
+		for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
+		  if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
+		    break;
+		
+		if (addrlist)
+		  break;
+		else
+		  while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
+		    intr = intr->next;
+	      }
+#endif
+	  
+	  if (intr)
+	    {
+	      if (local_query || in_zone(zone, intr->name, NULL))
+		{	
+		  found = 1;
+		  log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
+		  if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+					  daemon->auth_ttl, NULL,
+					  T_PTR, C_IN, "d", intr->name))
+		    anscount++;
+		}
+	    }
+	  
+	  if ((crecp = cache_find_by_addr(NULL, &addr, now, flag)))
+	    do { 
+	      strcpy(name, cache_get_name(crecp));
+	      
+	      if (crecp->flags & F_DHCP && !option_bool(OPT_DHCP_FQDN))
+		{
+		  char *p = strchr(name, '.');
+		  if (p)
+		    *p = 0; /* must be bare name */
+		  
+		  /* add  external domain */
+		  if (zone)
+		    {
+		      strcat(name, ".");
+		      strcat(name, zone->domain);
+		    }
+		  log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));
+		  found = 1;
+		  if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+					  daemon->auth_ttl, NULL,
+					  T_PTR, C_IN, "d", name))
+		    anscount++;
+		}
+	      else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL)))
+		{
+		  log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
+		  found = 1;
+		  if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+					  daemon->auth_ttl, NULL,
+					  T_PTR, C_IN, "d", name))
+		    anscount++;
+		}
+	      else
+		continue;
+		    
+	    } while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
+
+	  if (found)
+	    nxdomain = 0;
+	  else
+	    log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL);
+
+	  continue;
+	}
+      
+    cname_restart:
+      if (found)
+	/* NS and SOA .arpa requests have set found above. */
+	cut = NULL;
+      else
+	{
+	  for (zone = daemon->auth_zones; zone; zone = zone->next)
+	    if (in_zone(zone, name, &cut))
+	      break;
+	  
+	  if (!zone)
+	    {
+	      auth = 0;
+	      continue;
+	    }
+	}
+
+      for (rec = daemon->mxnames; rec; rec = rec->next)
+	if (!rec->issrv && hostname_isequal(name, rec->name))
+	  {
+	    nxdomain = 0;
+	         
+	    if (qtype == T_MX)
+	      {
+		found = 1;
+		log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>"); 
+		if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
+					NULL, T_MX, C_IN, "sd", rec->weight, rec->target))
+		  anscount++;
+	      }
+	  }
+      
+      for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next)
+	if (rec->issrv && hostname_isequal(name, rec->name))
+	  {
+	    nxdomain = 0;
+	    
+	    if (qtype == T_SRV)
+	      {
+		found = 1;
+		log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>"); 
+		if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
+					NULL, T_SRV, C_IN, "sssd", 
+					rec->priority, rec->weight, rec->srvport, rec->target))
+
+		  anscount++;
+	      } 
+	    
+	    /* unlink first SRV record found */
+	    if (!move)
+	      {
+		move = rec;
+		*up = rec->next;
+	      }
+	    else
+	      up = &rec->next;      
+	  }
+	else
+	  up = &rec->next;
+	  
+      /* put first SRV record back at the end. */
+      if (move)
+	{
+	  *up = move;
+	  move->next = NULL;
+	}
+
+      for (txt = daemon->rr; txt; txt = txt->next)
+	if (hostname_isequal(name, txt->name))
+	  {
+	    nxdomain = 0;
+	    if (txt->class == qtype)
+	      {
+		found = 1;
+		log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>"); 
+		if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
+					NULL, txt->class, C_IN, "t", txt->len, txt->txt))
+		  anscount++;
+	      }
+	  }
+      
+      for (txt = daemon->txt; txt; txt = txt->next)
+	if (txt->class == C_IN && hostname_isequal(name, txt->name))
+	  {
+	    nxdomain = 0;
+	    if (qtype == T_TXT)
+	      {
+		found = 1;
+		log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>"); 
+		if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
+					NULL, T_TXT, C_IN, "t", txt->len, txt->txt))
+		  anscount++;
+	      }
+	  }
+
+       for (na = daemon->naptr; na; na = na->next)
+	 if (hostname_isequal(name, na->name))
+	   {
+	     nxdomain = 0;
+	     if (qtype == T_NAPTR)
+	       {
+		 found = 1;
+		 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
+		 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, 
+					 NULL, T_NAPTR, C_IN, "sszzzd", 
+					 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
+			  anscount++;
+	       }
+	   }
+    
+       if (qtype == T_A)
+	 flag = F_IPV4;
+       
+#ifdef HAVE_IPV6
+       if (qtype == T_AAAA)
+	 flag = F_IPV6;
+#endif
+       
+       for (intr = daemon->int_names; intr; intr = intr->next)
+	 if (hostname_isequal(name, intr->name))
+	   {
+	     struct addrlist *addrlist;
+	     
+	     nxdomain = 0;
+	     
+	     if (flag)
+	       for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)  
+		 if (((addrlist->flags & ADDRLIST_IPV6)  ? T_AAAA : T_A) == qtype &&
+		     (local_query || filter_zone(zone, flag, &addrlist->addr)))
+		   {
+#ifdef HAVE_IPV6
+		     if (addrlist->flags & ADDRLIST_REVONLY)
+		       continue;
+#endif
+		     found = 1;
+		     log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
+		     if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+					     daemon->auth_ttl, NULL, qtype, C_IN, 
+					     qtype == T_A ? "4" : "6", &addrlist->addr))
+		       anscount++;
+		   }
+	     }
+       
+      if (!cut)
+	{
+	  nxdomain = 0;
+	  
+	  if (qtype == T_SOA)
+	    {
+	      auth = soa = 1; /* inhibits auth section */
+	      found = 1;
+	      log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
+	    }
+      	  else if (qtype == T_AXFR)
+	    {
+	      struct iname *peers;
+	      
+	      if (peer_addr->sa.sa_family == AF_INET)
+		peer_addr->in.sin_port = 0;
+#ifdef HAVE_IPV6
+	      else
+		{
+		  peer_addr->in6.sin6_port = 0; 
+		  peer_addr->in6.sin6_scope_id = 0;
+		}
+#endif
+	      
+	      for (peers = daemon->auth_peers; peers; peers = peers->next)
+		if (sockaddr_isequal(peer_addr, &peers->addr))
+		  break;
+	      
+	      /* Refuse all AXFR unless --auth-sec-servers is set */
+	      if ((!peers && daemon->auth_peers) || !daemon->secondary_forward_server)
+		{
+		  if (peer_addr->sa.sa_family == AF_INET)
+		    inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
+#ifdef HAVE_IPV6
+		  else
+		    inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN); 
+#endif
+		  
+		  my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff);
+		  return 0;
+		}
+	       	      
+	      auth = 1;
+	      soa = 1; /* inhibits auth section */
+	      ns = 1; /* ensure we include NS records! */
+	      axfr = 1;
+	      found = 1;
+	      axfroffset = nameoffset;
+	      log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>");
+	    }
+      	  else if (qtype == T_NS)
+	    {
+	      auth = 1;
+	      ns = 1; /* inhibits auth section */
+	      found = 1;
+	      log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>"); 
+	    }
+	}
+      
+      if (!option_bool(OPT_DHCP_FQDN) && cut)
+	{	  
+	  *cut = 0; /* remove domain part */
+	  
+	  if (!strchr(name, '.') && (crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
+	    {
+	      if (crecp->flags & F_DHCP)
+		do
+		  { 
+		    nxdomain = 0;
+		    if ((crecp->flags & flag) && 
+			(local_query || filter_zone(zone, flag, &(crecp->addr.addr))))
+		      {
+			*cut = '.'; /* restore domain part */
+			log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
+			*cut  = 0; /* remove domain part */
+			found = 1;
+			if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+						daemon->auth_ttl, NULL, qtype, C_IN, 
+						qtype == T_A ? "4" : "6", &crecp->addr))
+			  anscount++;
+		      }
+		  } while ((crecp = cache_find_by_name(crecp, name, now,  F_IPV4 | F_IPV6)));
+	    }
+       	  
+	  *cut = '.'; /* restore domain part */	    
+	}
+      
+      if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
+	{
+	  if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
+	    do
+	      { 
+		 nxdomain = 0;
+		 if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr.addr))))
+		   {
+		     log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
+		     found = 1;
+		     if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+					     daemon->auth_ttl, NULL, qtype, C_IN, 
+					     qtype == T_A ? "4" : "6", &crecp->addr))
+		       anscount++;
+		   }
+	      } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
+	}
+      
+      /* Only supply CNAME if no record for any type is known. */
+      if (nxdomain)
+	{
+	  /* Check for possible wildcard match against *.domain 
+	     return length of match, to get longest.
+	     Note that if return length of wildcard section, so
+	     we match b.simon to _both_ *.simon and b.simon
+	     but return a longer (better) match to b.simon.
+	  */  
+	  for (wclen = 0, candidate = NULL, a = daemon->cnames; a; a = a->next)
+	    if (a->alias[0] == '*')
+	      {
+		char *test = name;
+		
+		while ((test = strchr(test+1, '.')))
+		  {
+		    if (hostname_isequal(test, &(a->alias[1])))
+		      {
+			if (strlen(test) > wclen && !cname_wildcard)
+			  {
+			    wclen = strlen(test);
+			    candidate = a;
+			    cname_wildcard = 1;
+			  }
+			break;
+		      }
+		  }
+		
+	      }
+	    else if (hostname_isequal(a->alias, name) && strlen(a->alias) > wclen)
+	      {
+		/* Simple case, no wildcard */
+		wclen = strlen(a->alias);
+		candidate = a;
+	      }
+	  
+	  if (candidate)
+	    {
+	      log_query(F_CONFIG | F_CNAME, name, NULL, NULL);
+	      strcpy(name, candidate->target);
+	      if (!strchr(name, '.'))
+		{
+		  strcat(name, ".");
+		  strcat(name, zone->domain);
+		}
+	      found = 1;
+	      if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+				      daemon->auth_ttl, &nameoffset,
+				      T_CNAME, C_IN, "d", name))
+		anscount++;
+	      
+	      goto cname_restart;
+	    }
+
+	  log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);
+	}
+      
+    }
+  
+  /* Add auth section */
+  if (auth && zone)
+    {
+      char *authname;
+      int newoffset, offset = 0;
+
+      if (!subnet)
+	authname = zone->domain;
+      else
+	{
+	  /* handle NS and SOA for PTR records */
+	  
+	  authname = name;
+
+	  if (!(subnet->flags & ADDRLIST_IPV6))
+	    {
+	      in_addr_t a = ntohl(subnet->addr.addr.addr4.s_addr) >> 8;
+	      char *p = name;
+	      
+	      if (subnet->prefixlen >= 24)
+		p += sprintf(p, "%u.", a & 0xff);
+	      a = a >> 8;
+	      if (subnet->prefixlen >= 16 )
+		p += sprintf(p, "%u.", a & 0xff);
+	      a = a >> 8;
+	      p += sprintf(p, "%u.in-addr.arpa", a & 0xff);
+	      
+	    }
+#ifdef HAVE_IPV6
+	  else
+	    {
+	      char *p = name;
+	      int i;
+	      
+	      for (i = subnet->prefixlen-1; i >= 0; i -= 4)
+		{ 
+		  int dig = ((unsigned char *)&subnet->addr.addr.addr6)[i>>3];
+		  p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
+		}
+	      p += sprintf(p, "ip6.arpa");
+	      
+	    }
+#endif
+	}
+      
+      /* handle NS and SOA in auth section or for explicit queries */
+       newoffset = ansp - (unsigned char *)header;
+       if (((anscount == 0 && !ns) || soa) &&
+	  add_resource_record(header, limit, &trunc, 0, &ansp, 
+			      daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
+			      authname, daemon->authserver,  daemon->hostmaster,
+			      daemon->soa_sn, daemon->soa_refresh, 
+			      daemon->soa_retry, daemon->soa_expiry, 
+			      daemon->auth_ttl))
+	{
+	  offset = newoffset;
+	  if (soa)
+	    anscount++;
+	  else
+	    authcount++;
+	}
+      
+      if (anscount != 0 || ns)
+	{
+	  struct name_list *secondary;
+	  
+	  newoffset = ansp - (unsigned char *)header;
+	  if (add_resource_record(header, limit, &trunc, -offset, &ansp, 
+				  daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
+	    {
+	      if (offset == 0) 
+		offset = newoffset;
+	      if (ns) 
+		anscount++;
+	      else
+		authcount++;
+	    }
+
+	  if (!subnet)
+	    for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next)
+	      if (add_resource_record(header, limit, &trunc, offset, &ansp, 
+				      daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name))
+		{
+		  if (ns) 
+		    anscount++;
+		  else
+		    authcount++;
+		}
+	}
+      
+      if (axfr)
+	{
+	  for (rec = daemon->mxnames; rec; rec = rec->next)
+	    if (in_zone(zone, rec->name, &cut))
+	      {
+		if (cut)
+		   *cut = 0;
+
+		if (rec->issrv)
+		  {
+		    if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
+					    NULL, T_SRV, C_IN, "sssd", cut ? rec->name : NULL,
+					    rec->priority, rec->weight, rec->srvport, rec->target))
+		      
+		      anscount++;
+		  }
+		else
+		  {
+		    if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
+					    NULL, T_MX, C_IN, "sd", cut ? rec->name : NULL, rec->weight, rec->target))
+		      anscount++;
+		  }
+		
+		/* restore config data */
+		if (cut)
+		  *cut = '.';
+	      }
+	      
+	  for (txt = daemon->rr; txt; txt = txt->next)
+	    if (in_zone(zone, txt->name, &cut))
+	      {
+		if (cut)
+		  *cut = 0;
+		
+		if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
+					NULL, txt->class, C_IN, "t",  cut ? txt->name : NULL, txt->len, txt->txt))
+		  anscount++;
+		
+		/* restore config data */
+		if (cut)
+		  *cut = '.';
+	      }
+	  
+	  for (txt = daemon->txt; txt; txt = txt->next)
+	    if (txt->class == C_IN && in_zone(zone, txt->name, &cut))
+	      {
+		if (cut)
+		  *cut = 0;
+		
+		if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
+					NULL, T_TXT, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
+		  anscount++;
+		
+		/* restore config data */
+		if (cut)
+		  *cut = '.';
+	      }
+	  
+	  for (na = daemon->naptr; na; na = na->next)
+	    if (in_zone(zone, na->name, &cut))
+	      {
+		if (cut)
+		  *cut = 0;
+		
+		if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl, 
+					NULL, T_NAPTR, C_IN, "sszzzd", cut ? na->name : NULL,
+					na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
+		  anscount++;
+		
+		/* restore config data */
+		if (cut)
+		  *cut = '.'; 
+	      }
+	  
+	  for (intr = daemon->int_names; intr; intr = intr->next)
+	    if (in_zone(zone, intr->name, &cut))
+	      {
+		struct addrlist *addrlist;
+		
+		if (cut)
+		  *cut = 0;
+		
+		for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) 
+		  if (!(addrlist->flags & ADDRLIST_IPV6) &&
+		      (local_query || filter_zone(zone, F_IPV4, &addrlist->addr)) && 
+		      add_resource_record(header, limit, &trunc, -axfroffset, &ansp, 
+					  daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr))
+		    anscount++;
+		
+#ifdef HAVE_IPV6
+		for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) 
+		  if ((addrlist->flags & ADDRLIST_IPV6) && 
+		      (local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) &&
+		      add_resource_record(header, limit, &trunc, -axfroffset, &ansp, 
+					  daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr))
+		    anscount++;
+#endif		    
+		
+		/* restore config data */
+		if (cut)
+		  *cut = '.'; 
+	      }
+             
+	  for (a = daemon->cnames; a; a = a->next)
+	    if (in_zone(zone, a->alias, &cut))
+	      {
+		strcpy(name, a->target);
+		if (!strchr(name, '.'))
+		  {
+		    strcat(name, ".");
+		    strcat(name, zone->domain);
+		  }
+		
+		if (cut)
+		  *cut = 0;
+		
+		if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, 
+					daemon->auth_ttl, NULL,
+					T_CNAME, C_IN, "d",  cut ? a->alias : NULL, name))
+		  anscount++;
+	      }
+	
+	  cache_enumerate(1);
+	  while ((crecp = cache_enumerate(0)))
+	    {
+	      if ((crecp->flags & (F_IPV4 | F_IPV6)) &&
+		  !(crecp->flags & (F_NEG | F_NXDOMAIN)) &&
+		  (crecp->flags & F_FORWARD))
+		{
+		  if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN))
+		    {
+		      char *cache_name = cache_get_name(crecp);
+		      if (!strchr(cache_name, '.') && 
+			  (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr))))
+			{
+			  qtype = T_A;
+#ifdef HAVE_IPV6
+			  if (crecp->flags & F_IPV6)
+			    qtype = T_AAAA;
+#endif
+			  if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, 
+						  daemon->auth_ttl, NULL, qtype, C_IN, 
+						  (crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr))
+			    anscount++;
+			}
+		    }
+		  
+		  if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
+		    {
+		      strcpy(name, cache_get_name(crecp));
+		      if (in_zone(zone, name, &cut) && 
+			  (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr))))
+			{
+			  qtype = T_A;
+#ifdef HAVE_IPV6
+			  if (crecp->flags & F_IPV6)
+			    qtype = T_AAAA;
+#endif
+			   if (cut)
+			     *cut = 0;
+
+			   if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, 
+						   daemon->auth_ttl, NULL, qtype, C_IN, 
+						   (crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr))
+			     anscount++;
+			}
+		    }
+		}
+	    }
+	   
+	  /* repeat SOA as last record */
+	  if (add_resource_record(header, limit, &trunc, axfroffset, &ansp, 
+				  daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
+				  daemon->authserver,  daemon->hostmaster,
+				  daemon->soa_sn, daemon->soa_refresh, 
+				  daemon->soa_retry, daemon->soa_expiry, 
+				  daemon->auth_ttl))
+	    anscount++;
+	  
+	}
+      
+    }
+  
+  /* done all questions, set up header and return length of result */
+  /* clear authoritative and truncated flags, set QR flag */
+  header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
+
+  if (local_query)
+    {
+      /* set RA flag */
+      header->hb4 |= HB4_RA;
+    }
+  else
+    {
+      /* clear RA flag */
+      header->hb4 &= ~HB4_RA;
+    }
+
+  /* authoritative */
+  if (auth)
+    header->hb3 |= HB3_AA;
+  
+  /* truncation */
+  if (trunc)
+    header->hb3 |= HB3_TC;
+  
+  if ((auth || local_query) && nxdomain)
+    SET_RCODE(header, NXDOMAIN);
+  else
+    SET_RCODE(header, NOERROR); /* no error */
+  header->ancount = htons(anscount);
+  header->nscount = htons(authcount);
+  header->arcount = htons(0);
+
+  /* Advertise our packet size limit in our reply */
+  if (have_pseudoheader)
+    return add_pseudoheader(header,  ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
+
+  return ansp - (unsigned char *)header;
+}
+  
+#endif  
+  
+
+
diff --git a/src/blockdata.c b/src/blockdata.c
new file mode 100644
index 0000000..8683b9b
--- /dev/null
+++ b/src/blockdata.c
@@ -0,0 +1,151 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_DNSSEC
+
+static struct blockdata *keyblock_free;
+static unsigned int blockdata_count, blockdata_hwm, blockdata_alloced;
+
+static void blockdata_expand(int n)
+{
+  struct blockdata *new = whine_malloc(n * sizeof(struct blockdata));
+  
+  if (n > 0 && new)
+    {
+      int i;
+      
+      new[n-1].next = keyblock_free;
+      keyblock_free = new;
+
+      for (i = 0; i < n - 1; i++)
+	new[i].next = &new[i+1];
+
+      blockdata_alloced += n;
+    }
+}
+
+/* Preallocate some blocks, proportional to cachesize, to reduce heap fragmentation. */
+void blockdata_init(void)
+{
+  keyblock_free = NULL;
+  blockdata_alloced = 0;
+  blockdata_count = 0;
+  blockdata_hwm = 0;
+
+  /* Note that daemon->cachesize is enforced to have non-zero size if OPT_DNSSEC_VALID is set */  
+  if (option_bool(OPT_DNSSEC_VALID))
+    blockdata_expand((daemon->cachesize * 100) / sizeof(struct blockdata));
+}
+
+void blockdata_report(void)
+{
+  if (option_bool(OPT_DNSSEC_VALID))
+    my_syslog(LOG_INFO, _("DNSSEC memory in use %u, max %u, allocated %u"), 
+	      blockdata_count * sizeof(struct blockdata),  
+	      blockdata_hwm * sizeof(struct blockdata),  
+	      blockdata_alloced * sizeof(struct blockdata));
+} 
+
+struct blockdata *blockdata_alloc(char *data, size_t len)
+{
+  struct blockdata *block, *ret = NULL;
+  struct blockdata **prev = &ret;
+  size_t blen;
+
+  while (len > 0)
+    {
+      if (!keyblock_free)
+	blockdata_expand(50);
+      
+      if (keyblock_free)
+	{
+	  block = keyblock_free;
+	  keyblock_free = block->next;
+	  blockdata_count++; 
+	}
+      else
+	{
+	  /* failed to alloc, free partial chain */
+	  blockdata_free(ret);
+	  return NULL;
+	}
+       
+      if (blockdata_hwm < blockdata_count)
+	blockdata_hwm = blockdata_count; 
+      
+      blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
+      memcpy(block->key, data, blen);
+      data += blen;
+      len -= blen;
+      *prev = block;
+      prev = &block->next;
+      block->next = NULL;
+    }
+  
+  return ret;
+}
+
+void blockdata_free(struct blockdata *blocks)
+{
+  struct blockdata *tmp;
+  
+  if (blocks)
+    {
+      for (tmp = blocks; tmp->next; tmp = tmp->next)
+	blockdata_count--;
+      tmp->next = keyblock_free;
+      keyblock_free = blocks; 
+      blockdata_count--;
+    }
+}
+
+/* if data == NULL, return pointer to static block of sufficient size */
+void *blockdata_retrieve(struct blockdata *block, size_t len, void *data)
+{
+  size_t blen;
+  struct  blockdata *b;
+  void *new, *d;
+  
+  static unsigned int buff_len = 0;
+  static unsigned char *buff = NULL;
+   
+  if (!data)
+    {
+      if (len > buff_len)
+	{
+	  if (!(new = whine_malloc(len)))
+	    return NULL;
+	  if (buff)
+	    free(buff);
+	  buff = new;
+	}
+      data = buff;
+    }
+  
+  for (d = data, b = block; len > 0 && b;  b = b->next)
+    {
+      blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
+      memcpy(d, b->key, blen);
+      d += blen;
+      len -= blen;
+    }
+
+  return data;
+}
+ 
+#endif
diff --git a/src/bpf.c b/src/bpf.c
new file mode 100755
index 0000000..3f9ef5a
--- /dev/null
+++ b/src/bpf.c
@@ -0,0 +1,450 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
+#include <ifaddrs.h>
+
+#include <sys/param.h>
+#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
+#include <sys/sysctl.h>
+#endif
+#include <net/if.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <netinet/if_ether.h>
+#if defined(__FreeBSD__)
+#  include <net/if_var.h> 
+#endif
+#include <netinet/in_var.h>
+#ifdef HAVE_IPV6
+#  include <netinet6/in6_var.h>
+#endif
+
+#ifndef SA_SIZE
+#define SA_SIZE(sa)                                             \
+    (  (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ?      \
+        sizeof(long)            :                               \
+        1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
+#endif
+
+#ifdef HAVE_BSD_NETWORK
+static int del_family = 0;
+static struct all_addr del_addr;
+#endif
+
+#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
+
+int arp_enumerate(void *parm, int (*callback)())
+{
+  int mib[6];
+  size_t needed;
+  char *next;
+  struct rt_msghdr *rtm;
+  struct sockaddr_inarp *sin2;
+  struct sockaddr_dl *sdl;
+  struct iovec buff;
+  int rc;
+
+  buff.iov_base = NULL;
+  buff.iov_len = 0;
+
+  mib[0] = CTL_NET;
+  mib[1] = PF_ROUTE;
+  mib[2] = 0;
+  mib[3] = AF_INET;
+  mib[4] = NET_RT_FLAGS;
+#ifdef RTF_LLINFO
+  mib[5] = RTF_LLINFO;
+#else
+  mib[5] = 0;
+#endif	
+  if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1 || needed == 0)
+    return 0;
+
+  while (1) 
+    {
+      if (!expand_buf(&buff, needed))
+	return 0;
+      if ((rc = sysctl(mib, 6, buff.iov_base, &needed, NULL, 0)) == 0 ||
+	  errno != ENOMEM)
+	break;
+      needed += needed / 8;
+    }
+  if (rc == -1)
+    return 0;
+  
+  for (next = buff.iov_base ; next < (char *)buff.iov_base + needed; next += rtm->rtm_msglen)
+    {
+      rtm = (struct rt_msghdr *)next;
+      sin2 = (struct sockaddr_inarp *)(rtm + 1);
+      sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2));
+      if (!(*callback)(AF_INET, &sin2->sin_addr, LLADDR(sdl), sdl->sdl_alen, parm))
+	return 0;
+    }
+
+  return 1;
+}
+#endif /* defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) */
+
+
+int iface_enumerate(int family, void *parm, int (*callback)())
+{
+  struct ifaddrs *head, *addrs;
+  int errsave, fd = -1, ret = 0;
+
+  if (family == AF_UNSPEC)
+#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
+    return  arp_enumerate(parm, callback);
+#else
+  return 0; /* need code for Solaris and MacOS*/
+#endif
+
+  /* AF_LINK doesn't exist in Linux, so we can't use it in our API */
+  if (family == AF_LOCAL)
+    family = AF_LINK;
+
+  if (getifaddrs(&head) == -1)
+    return 0;
+
+#if defined(HAVE_BSD_NETWORK) && defined(HAVE_IPV6)
+  if (family == AF_INET6)
+    fd = socket(PF_INET6, SOCK_DGRAM, 0);
+#endif
+  
+  for (addrs = head; addrs; addrs = addrs->ifa_next)
+    {
+      if (addrs->ifa_addr->sa_family == family)
+	{
+	  int iface_index = if_nametoindex(addrs->ifa_name);
+
+	  if (iface_index == 0 || !addrs->ifa_addr || 
+	      (!addrs->ifa_netmask && family != AF_LINK))
+	    continue;
+
+	  if (family == AF_INET)
+	    {
+	      struct in_addr addr, netmask, broadcast;
+	      addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
+#ifdef HAVE_BSD_NETWORK
+	      if (del_family == AF_INET && del_addr.addr.addr4.s_addr == addr.s_addr)
+		continue;
+#endif
+	      netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
+	      if (addrs->ifa_broadaddr)
+		broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr; 
+	      else 
+		broadcast.s_addr = 0;	      
+	      if (!((*callback)(addr, iface_index, NULL, netmask, broadcast, parm)))
+		goto err;
+	    }
+#ifdef HAVE_IPV6
+	  else if (family == AF_INET6)
+	    {
+	      struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr;
+	      unsigned char *netmask = (unsigned char *) &((struct sockaddr_in6 *) addrs->ifa_netmask)->sin6_addr;
+	      int scope_id = ((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id;
+	      int i, j, prefix = 0;
+	      u32 valid = 0xffffffff, preferred = 0xffffffff;
+	      int flags = 0;
+#ifdef HAVE_BSD_NETWORK
+	      if (del_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&del_addr.addr.addr6, addr))
+		continue;
+#endif
+#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
+	      struct in6_ifreq ifr6;
+
+	      memset(&ifr6, 0, sizeof(ifr6));
+	      strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
+	      
+	      ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
+	      if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
+		{
+		  if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
+		    flags |= IFACE_TENTATIVE;
+		  
+		  if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
+		    flags |= IFACE_DEPRECATED;
+
+#ifdef IN6_IFF_TEMPORARY
+		  if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY)))
+		    flags |= IFACE_PERMANENT;
+#endif
+
+#ifdef IN6_IFF_PRIVACY
+		  if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_PRIVACY)))
+		    flags |= IFACE_PERMANENT;
+#endif
+		}
+	      
+	      ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
+	      if (fd != -1 && ioctl(fd, SIOCGIFALIFETIME_IN6, &ifr6) != -1)
+		{
+		  valid = ifr6.ifr_ifru.ifru_lifetime.ia6t_vltime;
+		  preferred = ifr6.ifr_ifru.ifru_lifetime.ia6t_pltime;
+		}
+#endif
+	      	      
+	      for (i = 0; i < IN6ADDRSZ; i++, prefix += 8) 
+                if (netmask[i] != 0xff)
+		  break;
+	      
+	      if (i != IN6ADDRSZ && netmask[i]) 
+                for (j = 7; j > 0; j--, prefix++) 
+		  if ((netmask[i] & (1 << j)) == 0)
+		    break;
+	      
+	      /* voodoo to clear interface field in address */
+	      if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
+		{
+		  addr->s6_addr[2] = 0;
+		  addr->s6_addr[3] = 0;
+		} 
+	     
+	      if (!((*callback)(addr, prefix, scope_id, iface_index, flags,
+				(int) preferred, (int)valid, parm)))
+		goto err;	      
+	    }
+#endif /* HAVE_IPV6 */
+
+#ifdef HAVE_DHCP6      
+	  else if (family == AF_LINK)
+	    { 
+	      /* Assume ethernet again here */
+	      struct sockaddr_dl *sdl = (struct sockaddr_dl *) addrs->ifa_addr;
+	      if (sdl->sdl_alen != 0 && 
+		  !((*callback)(iface_index, ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm)))
+		goto err;
+	    }
+#endif 
+	}
+    }
+  
+  ret = 1;
+
+ err:
+  errsave = errno;
+  freeifaddrs(head); 
+  if (fd != -1)
+    close(fd);
+  errno = errsave;
+
+  return ret;
+}
+#endif /* defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) */
+
+
+#if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP)
+#include <net/bpf.h>
+
+void init_bpf(void)
+{
+  int i = 0;
+
+  while (1) 
+    {
+      sprintf(daemon->dhcp_buff, "/dev/bpf%d", i++);
+      if ((daemon->dhcp_raw_fd = open(daemon->dhcp_buff, O_RDWR, 0)) != -1)
+	return;
+
+      if (errno != EBUSY)
+	die(_("cannot create DHCP BPF socket: %s"), NULL, EC_BADNET);
+    }	     
+}
+
+void send_via_bpf(struct dhcp_packet *mess, size_t len,
+		  struct in_addr iface_addr, struct ifreq *ifr)
+{
+   /* Hairy stuff, packet either has to go to the
+      net broadcast or the destination can't reply to ARP yet,
+      but we do know the physical address. 
+      Build the packet by steam, and send directly, bypassing
+      the kernel IP stack */
+  
+  struct ether_header ether; 
+  struct ip ip;
+  struct udphdr {
+    u16 uh_sport;               /* source port */
+    u16 uh_dport;               /* destination port */
+    u16 uh_ulen;                /* udp length */
+    u16 uh_sum;                 /* udp checksum */
+  } udp;
+  
+  u32 i, sum;
+  struct iovec iov[4];
+
+  /* Only know how to do ethernet on *BSD */
+  if (mess->htype != ARPHRD_ETHER || mess->hlen != ETHER_ADDR_LEN)
+    {
+      my_syslog(MS_DHCP | LOG_WARNING, _("DHCP request for unsupported hardware type (%d) received on %s"), 
+		mess->htype, ifr->ifr_name);
+      return;
+    }
+   
+  ifr->ifr_addr.sa_family = AF_LINK;
+  if (ioctl(daemon->dhcpfd, SIOCGIFADDR, ifr) < 0)
+    return;
+  
+  memcpy(ether.ether_shost, LLADDR((struct sockaddr_dl *)&ifr->ifr_addr), ETHER_ADDR_LEN);
+  ether.ether_type = htons(ETHERTYPE_IP);
+  
+  if (ntohs(mess->flags) & 0x8000)
+    {
+      memset(ether.ether_dhost, 255,  ETHER_ADDR_LEN);
+      ip.ip_dst.s_addr = INADDR_BROADCAST;
+    }
+  else
+    {
+      memcpy(ether.ether_dhost, mess->chaddr, ETHER_ADDR_LEN); 
+      ip.ip_dst.s_addr = mess->yiaddr.s_addr;
+    }
+  
+  ip.ip_p = IPPROTO_UDP;
+  ip.ip_src.s_addr = iface_addr.s_addr;
+  ip.ip_len = htons(sizeof(struct ip) + 
+		    sizeof(struct udphdr) +
+		    len) ;
+  ip.ip_hl = sizeof(struct ip) / 4;
+  ip.ip_v = IPVERSION;
+  ip.ip_tos = 0;
+  ip.ip_id = htons(0);
+  ip.ip_off = htons(0x4000); /* don't fragment */
+  ip.ip_ttl = IPDEFTTL;
+  ip.ip_sum = 0;
+  for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
+    sum += ((u16 *)&ip)[i];
+  while (sum>>16)
+    sum = (sum & 0xffff) + (sum >> 16);  
+  ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
+  
+  udp.uh_sport = htons(daemon->dhcp_server_port);
+  udp.uh_dport = htons(daemon->dhcp_client_port);
+  if (len & 1)
+    ((char *)mess)[len] = 0; /* for checksum, in case length is odd. */
+  udp.uh_sum = 0;
+  udp.uh_ulen = sum = htons(sizeof(struct udphdr) + len);
+  sum += htons(IPPROTO_UDP);
+  sum += ip.ip_src.s_addr & 0xffff;
+  sum += (ip.ip_src.s_addr >> 16) & 0xffff;
+  sum += ip.ip_dst.s_addr & 0xffff;
+  sum += (ip.ip_dst.s_addr >> 16) & 0xffff;
+  for (i = 0; i < sizeof(struct udphdr)/2; i++)
+    sum += ((u16 *)&udp)[i];
+  for (i = 0; i < (len + 1) / 2; i++)
+    sum += ((u16 *)mess)[i];
+  while (sum>>16)
+    sum = (sum & 0xffff) + (sum >> 16);
+  udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
+  
+  ioctl(daemon->dhcp_raw_fd, BIOCSETIF, ifr);
+  
+  iov[0].iov_base = &ether;
+  iov[0].iov_len = sizeof(ether);
+  iov[1].iov_base = &ip;
+  iov[1].iov_len = sizeof(ip);
+  iov[2].iov_base = &udp;
+  iov[2].iov_len = sizeof(udp);
+  iov[3].iov_base = mess;
+  iov[3].iov_len = len;
+
+  while (retry_send(writev(daemon->dhcp_raw_fd, iov, 4)));
+}
+
+#endif /* defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP) */
+ 
+
+#ifdef HAVE_BSD_NETWORK
+
+void route_init(void)
+{
+  /* AF_UNSPEC: all addr families */
+  daemon->routefd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
+  
+  if (daemon->routefd == -1 || !fix_fd(daemon->routefd))
+    die(_("cannot create PF_ROUTE socket: %s"), NULL, EC_BADNET);
+}
+
+void route_sock(void)
+{
+  struct if_msghdr *msg;
+  int rc = recv(daemon->routefd, daemon->packet, daemon->packet_buff_sz, 0);
+
+  if (rc < 4)
+    return;
+
+  msg = (struct if_msghdr *)daemon->packet;
+  
+  if (rc < msg->ifm_msglen)
+    return;
+
+   if (msg->ifm_version != RTM_VERSION)
+     {
+       static int warned = 0;
+       if (!warned)
+	 {
+	   my_syslog(LOG_WARNING, _("Unknown protocol version from route socket"));
+	   warned = 1;
+	 }
+     }
+   else if (msg->ifm_type == RTM_NEWADDR)
+     {
+       del_family = 0;
+       queue_event(EVENT_NEWADDR);
+     }
+   else if (msg->ifm_type == RTM_DELADDR)
+     {
+       /* There's a race in the kernel, such that if we run iface_enumerate() immediately
+	  we get a DELADDR event, the deleted address still appears. Here we store the deleted address
+	  in a static variable, and omit it from the set returned by iface_enumerate() */
+       int mask = ((struct ifa_msghdr *)msg)->ifam_addrs;
+       int maskvec[] = { RTA_DST, RTA_GATEWAY, RTA_NETMASK, RTA_GENMASK,
+			 RTA_IFP, RTA_IFA, RTA_AUTHOR, RTA_BRD };
+       int of;
+       unsigned int i;
+       
+       for (i = 0,  of = sizeof(struct ifa_msghdr); of < rc && i < sizeof(maskvec)/sizeof(maskvec[0]); i++) 
+	 if (mask & maskvec[i]) 
+	   {
+	     struct sockaddr *sa = (struct sockaddr *)((char *)msg + of);
+	     size_t diff = (sa->sa_len != 0) ? sa->sa_len : sizeof(long);
+	     
+	     if (maskvec[i] == RTA_IFA)
+	       {
+		 del_family = sa->sa_family;
+		 if (del_family == AF_INET)
+		   del_addr.addr.addr4 = ((struct sockaddr_in *)sa)->sin_addr;
+#ifdef HAVE_IPV6
+		 else if (del_family == AF_INET6)
+		   del_addr.addr.addr6 = ((struct sockaddr_in6 *)sa)->sin6_addr;
+#endif
+		 else
+		   del_family = 0;
+	       }
+	     
+	     of += diff;
+	     /* round up as needed */
+	     if (diff & (sizeof(long) - 1)) 
+	       of += sizeof(long) - (diff & (sizeof(long) - 1));
+	   }
+       
+       queue_event(EVENT_NEWADDR);
+     }
+}
+
+#endif /* HAVE_BSD_NETWORK */
+
+
diff --git a/src/cache.c b/src/cache.c
new file mode 100755
index 0000000..a719d95
--- /dev/null
+++ b/src/cache.c
@@ -0,0 +1,1686 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL;
+#ifdef HAVE_DHCP
+static struct crec *dhcp_spare = NULL;
+#endif
+static struct crec *new_chain = NULL;
+static int cache_inserted = 0, cache_live_freed = 0, insert_error;
+static union bigname *big_free = NULL;
+static int bignames_left, hash_size;
+
+/* type->string mapping: this is also used by the name-hash function as a mixing table. */
+static const struct {
+  unsigned int type;
+  const char * const name;
+} typestr[] = {
+  { 1,   "A" },
+  { 2,   "NS" },
+  { 5,   "CNAME" },
+  { 6,   "SOA" },
+  { 10,  "NULL" },
+  { 11,  "WKS" },
+  { 12,  "PTR" },
+  { 13,  "HINFO" },	
+  { 15,  "MX" },
+  { 16,  "TXT" },
+  { 22,  "NSAP" },
+  { 23,  "NSAP_PTR" },
+  { 24,  "SIG" },
+  { 25,  "KEY" },
+  { 28,  "AAAA" },
+  { 33,  "SRV" },
+  { 35,  "NAPTR" },
+  { 36,  "KX" },
+  { 37,  "CERT" },
+  { 38,  "A6" },
+  { 39,  "DNAME" },
+  { 41,  "OPT" },
+  { 43,  "DS" },
+  { 46,  "RRSIG" },
+  { 47,  "NSEC" },
+  { 48,  "DNSKEY" },
+  { 50,  "NSEC3" },
+  { 249, "TKEY" },
+  { 250, "TSIG" },
+  { 251, "IXFR" },
+  { 252, "AXFR" },
+  { 253, "MAILB" },
+  { 254, "MAILA" },
+  { 255, "ANY" }
+};
+
+static void cache_free(struct crec *crecp);
+static void cache_unlink(struct crec *crecp);
+static void cache_link(struct crec *crecp);
+static void rehash(int size);
+static void cache_hash(struct crec *crecp);
+
+static unsigned int next_uid(void)
+{
+  static unsigned int uid = 0;
+
+  uid++;
+  
+  /* uid == 0 used to indicate CNAME to interface name. */
+  if (uid == SRC_INTERFACE)
+    uid++;
+  
+  return uid;
+}
+
+void cache_init(void)
+{
+  struct crec *crecp;
+  int i;
+ 
+  bignames_left = daemon->cachesize/10;
+  
+  if (daemon->cachesize > 0)
+    {
+      crecp = safe_malloc(daemon->cachesize*sizeof(struct crec));
+      
+      for (i=0; i < daemon->cachesize; i++, crecp++)
+	{
+	  cache_link(crecp);
+	  crecp->flags = 0;
+	  crecp->uid = next_uid();
+	}
+    }
+  
+  /* create initial hash table*/
+  rehash(daemon->cachesize);
+}
+
+/* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
+   but if the hosts file(s) are big (some people have 50000 ad-block entries), the table
+   will be much too small, so the hosts reading code calls rehash every 1000 addresses, to
+   expand the table. */
+static void rehash(int size)
+{
+  struct crec **new, **old, *p, *tmp;
+  int i, new_size, old_size;
+
+  /* hash_size is a power of two. */
+  for (new_size = 64; new_size < size/10; new_size = new_size << 1);
+  
+  /* must succeed in getting first instance, failure later is non-fatal */
+  if (!hash_table)
+    new = safe_malloc(new_size * sizeof(struct crec *));
+  else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *))))
+    return;
+
+  for(i = 0; i < new_size; i++)
+    new[i] = NULL;
+
+  old = hash_table;
+  old_size = hash_size;
+  hash_table = new;
+  hash_size = new_size;
+  
+  if (old)
+    {
+      for (i = 0; i < old_size; i++)
+	for (p = old[i]; p ; p = tmp)
+	  {
+	    tmp = p->hash_next;
+	    cache_hash(p);
+	  }
+      free(old);
+    }
+}
+  
+static struct crec **hash_bucket(char *name)
+{
+  unsigned int c, val = 017465; /* Barker code - minimum self-correlation in cyclic shift */
+  const unsigned char *mix_tab = (const unsigned char*)typestr; 
+
+  while((c = (unsigned char) *name++))
+    {
+      /* don't use tolower and friends here - they may be messed up by LOCALE */
+      if (c >= 'A' && c <= 'Z')
+	c += 'a' - 'A';
+      val = ((val << 7) | (val >> (32 - 7))) + (mix_tab[(val + c) & 0x3F] ^ c);
+    } 
+  
+  /* hash_size is a power of two */
+  return hash_table + ((val ^ (val >> 16)) & (hash_size - 1));
+}
+
+static void cache_hash(struct crec *crecp)
+{
+  /* maintain an invariant that all entries with F_REVERSE set
+     are at the start of the hash-chain  and all non-reverse
+     immortal entries are at the end of the hash-chain.
+     This allows reverse searches and garbage collection to be optimised */
+
+  struct crec **up = hash_bucket(cache_get_name(crecp));
+
+  if (!(crecp->flags & F_REVERSE))
+    {
+      while (*up && ((*up)->flags & F_REVERSE))
+	up = &((*up)->hash_next); 
+      
+      if (crecp->flags & F_IMMORTAL)
+	while (*up && !((*up)->flags & F_IMMORTAL))
+	  up = &((*up)->hash_next);
+    }
+  crecp->hash_next = *up;
+  *up = crecp;
+}
+
+#ifdef HAVE_DNSSEC
+static void cache_blockdata_free(struct crec *crecp)
+{
+  if (crecp->flags & F_DNSKEY)
+    blockdata_free(crecp->addr.key.keydata);
+  else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
+    blockdata_free(crecp->addr.ds.keydata);
+}
+#endif
+
+static void cache_free(struct crec *crecp)
+{
+  crecp->flags &= ~F_FORWARD;
+  crecp->flags &= ~F_REVERSE;
+  crecp->uid = next_uid(); /* invalidate CNAMES pointing to this. */
+
+  if (cache_tail)
+    cache_tail->next = crecp;
+  else
+    cache_head = crecp;
+  crecp->prev = cache_tail;
+  crecp->next = NULL;
+  cache_tail = crecp;
+  
+  /* retrieve big name for further use. */
+  if (crecp->flags & F_BIGNAME)
+    {
+      crecp->name.bname->next = big_free;
+      big_free = crecp->name.bname;
+      crecp->flags &= ~F_BIGNAME;
+    }
+
+#ifdef HAVE_DNSSEC
+  cache_blockdata_free(crecp);
+#endif
+}    
+
+/* insert a new cache entry at the head of the list (youngest entry) */
+static void cache_link(struct crec *crecp)
+{
+  if (cache_head) /* check needed for init code */
+    cache_head->prev = crecp;
+  crecp->next = cache_head;
+  crecp->prev = NULL;
+  cache_head = crecp;
+  if (!cache_tail)
+    cache_tail = crecp;
+}
+
+/* remove an arbitrary cache entry for promotion */ 
+static void cache_unlink (struct crec *crecp)
+{
+  if (crecp->prev)
+    crecp->prev->next = crecp->next;
+  else
+    cache_head = crecp->next;
+
+  if (crecp->next)
+    crecp->next->prev = crecp->prev;
+  else
+    cache_tail = crecp->prev;
+}
+
+char *cache_get_name(struct crec *crecp)
+{
+  if (crecp->flags & F_BIGNAME)
+    return crecp->name.bname->name;
+  else if (crecp->flags & F_NAMEP) 
+    return crecp->name.namep;
+  
+  return crecp->name.sname;
+}
+
+char *cache_get_cname_target(struct crec *crecp)
+{
+  if (crecp->addr.cname.uid != SRC_INTERFACE)
+    return cache_get_name(crecp->addr.cname.target.cache);
+
+  return crecp->addr.cname.target.int_name->name;
+}
+
+
+
+struct crec *cache_enumerate(int init)
+{
+  static int bucket;
+  static struct crec *cache;
+
+  if (init)
+    {
+      bucket = 0;
+      cache = NULL;
+    }
+  else if (cache && cache->hash_next)
+    cache = cache->hash_next;
+  else
+    {
+       cache = NULL; 
+       while (bucket < hash_size)
+	 if ((cache = hash_table[bucket++]))
+	   break;
+    }
+  
+  return cache;
+}
+
+static int is_outdated_cname_pointer(struct crec *crecp)
+{
+  if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == SRC_INTERFACE)
+    return 0;
+  
+  /* NB. record may be reused as DS or DNSKEY, where uid is 
+     overloaded for something completely different */
+  if (crecp->addr.cname.target.cache && 
+      (crecp->addr.cname.target.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&
+      crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid)
+    return 0;
+  
+  return 1;
+}
+
+static int is_expired(time_t now, struct crec *crecp)
+{
+  if (crecp->flags & F_IMMORTAL)
+    return 0;
+
+  if (difftime(now, crecp->ttd) < 0)
+    return 0;
+  
+  return 1;
+}
+
+static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
+{
+  /* Scan and remove old entries.
+     If (flags & F_FORWARD) then remove any forward entries for name and any expired
+     entries but only in the same hash bucket as name.
+     If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
+     entries in the whole cache.
+     If (flags == 0) remove any expired entries in the whole cache. 
+
+     In the flags & F_FORWARD case, the return code is valid, and returns a non-NULL pointer
+     to a cache entry if the name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
+
+     We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
+     so that when we hit an entry which isn't reverse and is immortal, we're done. */
+ 
+  struct crec *crecp, **up;
+  
+  if (flags & F_FORWARD)
+    {
+      for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
+	{
+	  if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
+	    { 
+	      *up = crecp->hash_next;
+	      if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
+		{
+		  cache_unlink(crecp);
+		  cache_free(crecp);
+		}
+	      continue;
+	    } 
+	
+	  if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
+	    {
+	      /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
+	      if ((flags & crecp->flags & (F_IPV4 | F_IPV6)) || 
+		  (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
+		{
+		  if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
+		    return crecp;
+		  *up = crecp->hash_next;
+		  cache_unlink(crecp);
+		  cache_free(crecp);
+		  continue;
+		}
+	      
+#ifdef HAVE_DNSSEC
+	      /* Deletion has to be class-sensitive for DS and DNSKEY */
+	      if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == addr->addr.dnssec.class)
+		{
+		  if (crecp->flags & F_CONFIG)
+		    return crecp;
+		  *up = crecp->hash_next;
+		  cache_unlink(crecp);
+		  cache_free(crecp);
+		  continue;
+		}
+#endif
+	    }
+	  up = &crecp->hash_next;
+	}
+    }
+  else
+    {
+      int i;
+#ifdef HAVE_IPV6
+      int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
+#else
+      int addrlen = INADDRSZ;
+#endif 
+      for (i = 0; i < hash_size; i++)
+	for (crecp = hash_table[i], up = &hash_table[i]; 
+	     crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
+	     crecp = crecp->hash_next)
+	  if (is_expired(now, crecp))
+	    {
+	      *up = crecp->hash_next;
+	      if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
+		{ 
+		  cache_unlink(crecp);
+		  cache_free(crecp);
+		}
+	    }
+	  else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
+		   (flags & crecp->flags & F_REVERSE) && 
+		   (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
+		   memcmp(&crecp->addr.addr, addr, addrlen) == 0)
+	    {
+	      *up = crecp->hash_next;
+	      cache_unlink(crecp);
+	      cache_free(crecp);
+	    }
+	  else
+	    up = &crecp->hash_next;
+    }
+  
+  return NULL;
+}
+
+/* Note: The normal calling sequence is
+   cache_start_insert
+   cache_insert * n
+   cache_end_insert
+
+   but an abort can cause the cache_end_insert to be missed 
+   in which can the next cache_start_insert cleans things up. */
+
+void cache_start_insert(void)
+{
+  /* Free any entries which didn't get committed during the last
+     insert due to error.
+  */
+  while (new_chain)
+    {
+      struct crec *tmp = new_chain->next;
+      cache_free(new_chain);
+      new_chain = tmp;
+    }
+  new_chain = NULL;
+  insert_error = 0;
+}
+ 
+struct crec *cache_insert(char *name, struct all_addr *addr, 
+			  time_t now,  unsigned long ttl, unsigned short flags)
+{
+  struct crec *new;
+  union bigname *big_name = NULL;
+  int freed_all = flags & F_REVERSE;
+  int free_avail = 0;
+
+  /* Don't log DNSSEC records here, done elsewhere */
+  if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
+    {
+      log_query(flags | F_UPSTREAM, name, addr, NULL);
+      /* Don't mess with TTL for DNSSEC records. */
+      if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
+	ttl = daemon->max_cache_ttl;
+      if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
+	ttl = daemon->min_cache_ttl;
+    }
+
+  /* if previous insertion failed give up now. */
+  if (insert_error)
+    return NULL;
+  
+  /* First remove any expired entries and entries for the name/address we
+     are currently inserting. */
+  if ((new = cache_scan_free(name, addr, now, flags)))
+    {
+      /* We're trying to insert a record over one from 
+	 /etc/hosts or DHCP, or other config. If the 
+	 existing record is for an A or AAAA and
+	 the record we're trying to insert is the same, 
+	 just drop the insert, but don't error the whole process. */
+      if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD) && addr)
+	{
+	  if ((flags & F_IPV4) && (new->flags & F_IPV4) &&
+	      new->addr.addr.addr.addr4.s_addr == addr->addr.addr4.s_addr)
+	    return new;
+#ifdef HAVE_IPV6
+	  else if ((flags & F_IPV6) && (new->flags & F_IPV6) &&
+		   IN6_ARE_ADDR_EQUAL(&new->addr.addr.addr.addr6, &addr->addr.addr6))
+	    return new;
+#endif
+	}
+      
+      insert_error = 1;
+      return NULL;
+    }
+  
+  /* Now get a cache entry from the end of the LRU list */
+  while (1) {
+    if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
+      {
+	insert_error = 1;
+	return NULL;
+      }
+    
+    /* End of LRU list is still in use: if we didn't scan all the hash
+       chains for expired entries do that now. If we already tried that
+       then it's time to start spilling things. */
+    
+    if (new->flags & (F_FORWARD | F_REVERSE))
+      { 
+	/* If free_avail set, we believe that an entry has been freed.
+	   Bugs have been known to make this not true, resulting in
+	   a tight loop here. If that happens, abandon the
+	   insert. Once in this state, all inserts will probably fail. */
+	if (free_avail)
+	  {
+	    static int warned = 0;
+	    if (!warned)
+	      {
+		my_syslog(LOG_ERR, _("Internal error in cache."));
+		warned = 1;
+	      }
+	    insert_error = 1;
+	    return NULL;
+	  }
+		
+	if (freed_all)
+	  {
+	    struct all_addr free_addr = new->addr.addr;;
+
+#ifdef HAVE_DNSSEC
+	    /* For DNSSEC records, addr holds class. */
+	    if (new->flags & (F_DS | F_DNSKEY))
+	      free_addr.addr.dnssec.class = new->uid;
+#endif
+	    
+	    free_avail = 1; /* Must be free space now. */
+	    cache_scan_free(cache_get_name(new), &free_addr, now, new->flags);
+	    cache_live_freed++;
+	  }
+	else
+	  {
+	    cache_scan_free(NULL, NULL, now, 0);
+	    freed_all = 1;
+	  }
+	continue;
+      }
+ 
+    /* Check if we need to and can allocate extra memory for a long name.
+       If that fails, give up now, always succeed for DNSSEC records. */
+    if (name && (strlen(name) > SMALLDNAME-1))
+      {
+	if (big_free)
+	  { 
+	    big_name = big_free;
+	    big_free = big_free->next;
+	  }
+	else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) ||
+		 !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
+	  {
+	    insert_error = 1;
+	    return NULL;
+	  }
+	else if (bignames_left != 0)
+	  bignames_left--;
+	
+      }
+
+    /* Got the rest: finally grab entry. */
+    cache_unlink(new);
+    break;
+  }
+  
+  new->flags = flags;
+  if (big_name)
+    {
+      new->name.bname = big_name;
+      new->flags |= F_BIGNAME;
+    }
+
+  if (name)
+    strcpy(cache_get_name(new), name);
+  else
+    *cache_get_name(new) = 0;
+
+  if (addr)
+    {
+#ifdef HAVE_DNSSEC
+      if (flags & (F_DS | F_DNSKEY))
+	new->uid = addr->addr.dnssec.class;
+      else
+#endif
+	new->addr.addr = *addr;	
+    }
+
+  new->ttd = now + (time_t)ttl;
+  new->next = new_chain;
+  new_chain = new;
+
+  return new;
+}
+
+/* after end of insertion, commit the new entries */
+void cache_end_insert(void)
+{
+  if (insert_error)
+    return;
+  
+  while (new_chain)
+    { 
+      struct crec *tmp = new_chain->next;
+      /* drop CNAMEs which didn't find a target. */
+      if (is_outdated_cname_pointer(new_chain))
+	cache_free(new_chain);
+      else
+	{
+	  cache_hash(new_chain);
+	  cache_link(new_chain);
+	  cache_inserted++;
+	}
+      new_chain = tmp;
+    }
+  new_chain = NULL;
+}
+
+struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
+{
+  struct crec *ans;
+  int no_rr = prot & F_NO_RR;
+
+  prot &= ~F_NO_RR;
+  
+  if (crecp) /* iterating */
+    ans = crecp->next;
+  else
+    {
+      /* first search, look for relevant entries and push to top of list
+	 also free anything which has expired */
+      struct crec *next, **up, **insert = NULL, **chainp = &ans;
+      unsigned short ins_flags = 0;
+      
+      for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
+	{
+	  next = crecp->hash_next;
+	  
+	  if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
+	    {
+	      if ((crecp->flags & F_FORWARD) && 
+		  (crecp->flags & prot) &&
+		  hostname_isequal(cache_get_name(crecp), name))
+		{
+		  if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
+		    {
+		      *chainp = crecp;
+		      chainp = &crecp->next;
+		    }
+		  else
+		    {
+		      cache_unlink(crecp);
+		      cache_link(crecp);
+		    }
+	      	      
+		  /* Move all but the first entry up the hash chain
+		     this implements round-robin. 
+		     Make sure that re-ordering doesn't break the hash-chain
+		     order invariants. 
+		  */
+		  if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
+		    {
+		      *up = crecp->hash_next;
+		      crecp->hash_next = *insert;
+		      *insert = crecp;
+		      insert = &crecp->hash_next;
+		    }
+		  else
+		    {
+		      if (!insert && !no_rr)
+			{
+			  insert = up;
+			  ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
+			}
+		      up = &crecp->hash_next; 
+		    }
+		}
+	      else
+		/* case : not expired, incorrect entry. */
+		up = &crecp->hash_next; 
+	    }
+	  else
+	    {
+	      /* expired entry, free it */
+	      *up = crecp->hash_next;
+	      if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
+		{ 
+		  cache_unlink(crecp);
+		  cache_free(crecp);
+		}
+	    }
+	}
+	  
+      *chainp = cache_head;
+    }
+
+  if (ans && 
+      (ans->flags & F_FORWARD) &&
+      (ans->flags & prot) &&     
+      hostname_isequal(cache_get_name(ans), name))
+    return ans;
+  
+  return NULL;
+}
+
+struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr, 
+				time_t now, unsigned int prot)
+{
+  struct crec *ans;
+#ifdef HAVE_IPV6
+  int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
+#else
+  int addrlen = INADDRSZ;
+#endif
+  
+  if (crecp) /* iterating */
+    ans = crecp->next;
+  else
+    {  
+      /* first search, look for relevant entries and push to top of list
+	 also free anything which has expired. All the reverse entries are at the
+	 start of the hash chain, so we can give up when we find the first 
+	 non-REVERSE one.  */
+       int i;
+       struct crec **up, **chainp = &ans;
+       
+       for (i=0; i<hash_size; i++)
+	 for (crecp = hash_table[i], up = &hash_table[i]; 
+	      crecp && (crecp->flags & F_REVERSE);
+	      crecp = crecp->hash_next)
+	   if (!is_expired(now, crecp))
+	     {      
+	       if ((crecp->flags & prot) &&
+		   memcmp(&crecp->addr.addr, addr, addrlen) == 0)
+		 {	    
+		   if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
+		     {
+		       *chainp = crecp;
+		       chainp = &crecp->next;
+		     }
+		   else
+		     {
+		       cache_unlink(crecp);
+		       cache_link(crecp);
+		     }
+		 }
+	       up = &crecp->hash_next;
+	     }
+	   else
+	     {
+	       *up = crecp->hash_next;
+	       if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
+		 {
+		   cache_unlink(crecp);
+		   cache_free(crecp);
+		 }
+	     }
+       
+       *chainp = cache_head;
+    }
+  
+  if (ans && 
+      (ans->flags & F_REVERSE) &&
+      (ans->flags & prot) &&
+      memcmp(&ans->addr.addr, addr, addrlen) == 0)
+    return ans;
+  
+  return NULL;
+}
+
+static void add_hosts_cname(struct crec *target)
+{
+  struct crec *crec;
+  struct cname *a;
+  
+  for (a = daemon->cnames; a; a = a->next)
+    if (a->alias[1] != '*' &&
+	hostname_isequal(cache_get_name(target), a->target) &&
+	(crec = whine_malloc(sizeof(struct crec))))
+      {
+	crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
+	crec->ttd = a->ttl;
+	crec->name.namep = a->alias;
+	crec->addr.cname.target.cache = target;
+	crec->addr.cname.uid = target->uid;
+	crec->uid = next_uid();
+	cache_hash(crec);
+	add_hosts_cname(crec); /* handle chains */
+      }
+}
+  
+static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen, 
+			    unsigned int index, struct crec **rhash, int hashsz)
+{
+  struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
+  int i, nameexists = 0;
+  unsigned int j; 
+
+  /* Remove duplicates in hosts files. */
+  if (lookup && (lookup->flags & F_HOSTS))
+    {
+      nameexists = 1;
+      if (memcmp(&lookup->addr.addr, addr, addrlen) == 0)
+	{
+	  free(cache);
+	  return;
+	}
+    }
+  
+  /* Ensure there is only one address -> name mapping (first one trumps) 
+     We do this by steam here, The entries are kept in hash chains, linked
+     by ->next (which is unused at this point) held in hash buckets in
+     the array rhash, hashed on address. Note that rhash and the values
+     in ->next are only valid  whilst reading hosts files: the buckets are
+     then freed, and the ->next pointer used for other things. 
+
+     Only insert each unique address once into this hashing structure.
+
+     This complexity avoids O(n^2) divergent CPU use whilst reading
+     large (10000 entry) hosts files. 
+
+     Note that we only do this process when bulk-reading hosts files, 
+     for incremental reads, rhash is NULL, and we use cache lookups
+     instead.
+  */
+  
+  if (rhash)
+    {
+      /* hash address */
+      for (j = 0, i = 0; i < addrlen; i++)
+	j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
+      
+      for (lookup = rhash[j]; lookup; lookup = lookup->next)
+	if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
+	    memcmp(&lookup->addr.addr, addr, addrlen) == 0)
+	  {
+	    cache->flags &= ~F_REVERSE;
+	    break;
+	  }
+      
+      /* maintain address hash chain, insert new unique address */
+      if (!lookup)
+	{
+	  cache->next = rhash[j];
+	  rhash[j] = cache;
+	}
+    }
+  else
+    {
+      /* incremental read, lookup in cache */
+      lookup = cache_find_by_addr(NULL, addr, 0, cache->flags & (F_IPV4 | F_IPV6));
+      if (lookup && lookup->flags & F_HOSTS)
+	cache->flags &= ~F_REVERSE;
+    }
+
+  cache->uid = index;
+  memcpy(&cache->addr.addr, addr, addrlen);  
+  cache_hash(cache);
+  
+  /* don't need to do alias stuff for second and subsequent addresses. */
+  if (!nameexists)
+    add_hosts_cname(cache);
+}
+
+static int eatspace(FILE *f)
+{
+  int c, nl = 0;
+
+  while (1)
+    {
+      if ((c = getc(f)) == '#')
+	while (c != '\n' && c != EOF)
+	  c = getc(f);
+      
+      if (c == EOF)
+	return 1;
+
+      if (!isspace(c))
+	{
+	  ungetc(c, f);
+	  return nl;
+	}
+
+      if (c == '\n')
+	nl = 1;
+    }
+}
+	 
+static int gettok(FILE *f, char *token)
+{
+  int c, count = 0;
+ 
+  while (1)
+    {
+      if ((c = getc(f)) == EOF)
+	return (count == 0) ? EOF : 1;
+
+      if (isspace(c) || c == '#')
+	{
+	  ungetc(c, f);
+	  return eatspace(f);
+	}
+      
+      if (count < (MAXDNAME - 1))
+	{
+	  token[count++] = c;
+	  token[count] = 0;
+	}
+    }
+}
+
+int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
+{  
+  FILE *f = fopen(filename, "r");
+  char *token = daemon->namebuff, *domain_suffix = NULL;
+  int addr_count = 0, name_count = cache_size, lineno = 0;
+  unsigned short flags = 0;
+  struct all_addr addr;
+  int atnl, addrlen = 0;
+
+  if (!f)
+    {
+      my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
+      return cache_size;
+    }
+  
+  eatspace(f);
+  
+  while ((atnl = gettok(f, token)) != EOF)
+    {
+      lineno++;
+      
+      if (inet_pton(AF_INET, token, &addr) > 0)
+	{
+	  flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
+	  addrlen = INADDRSZ;
+	  domain_suffix = get_domain(addr.addr.addr4);
+	}
+#ifdef HAVE_IPV6
+      else if (inet_pton(AF_INET6, token, &addr) > 0)
+	{
+	  flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
+	  addrlen = IN6ADDRSZ;
+	  domain_suffix = get_domain6(&addr.addr.addr6);
+	}
+#endif
+      else
+	{
+	  my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno); 
+	  while (atnl == 0)
+	    atnl = gettok(f, token);
+	  continue;
+	}
+      
+      addr_count++;
+      
+      /* rehash every 1000 names. */
+      if (rhash && ((name_count - cache_size) > 1000))
+	{
+	  rehash(name_count);
+	  cache_size = name_count;
+	} 
+      
+      while (atnl == 0)
+	{
+	  struct crec *cache;
+	  int fqdn, nomem;
+	  char *canon;
+	  
+	  if ((atnl = gettok(f, token)) == EOF)
+	    break;
+
+	  fqdn = !!strchr(token, '.');
+
+	  if ((canon = canonicalise(token, &nomem)))
+	    {
+	      /* If set, add a version of the name with a default domain appended */
+	      if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn && 
+		  (cache = whine_malloc(sizeof(struct crec) + 
+					strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
+		{
+		  strcpy(cache->name.sname, canon);
+		  strcat(cache->name.sname, ".");
+		  strcat(cache->name.sname, domain_suffix);
+		  cache->flags = flags;
+		  cache->ttd = daemon->local_ttl;
+		  add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
+		  name_count++;
+		}
+	      if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
+		{
+		  strcpy(cache->name.sname, canon);
+		  cache->flags = flags;
+		  cache->ttd = daemon->local_ttl;
+		  add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
+		  name_count++;
+		}
+	      free(canon);
+	      
+	    }
+	  else if (!nomem)
+	    my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno); 
+	}
+    } 
+
+  fclose(f);
+  
+  if (rhash)
+    rehash(name_count); 
+  
+  my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
+  
+  return name_count;
+}
+	    
+void cache_reload(void)
+{
+  struct crec *cache, **up, *tmp;
+  int revhashsz, i, total_size = daemon->cachesize;
+  struct hostsfile *ah;
+  struct host_record *hr;
+  struct name_list *nl;
+  struct cname *a;
+  struct interface_name *intr;
+#ifdef HAVE_DNSSEC
+  struct ds_config *ds;
+#endif
+
+  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)
+      {
+#ifdef HAVE_DNSSEC
+	cache_blockdata_free(cache);
+#endif
+	tmp = cache->hash_next;
+	if (cache->flags & (F_HOSTS | F_CONFIG))
+	  {
+	    *up = cache->hash_next;
+	    free(cache);
+	  }
+	else if (!(cache->flags & F_DHCP))
+	  {
+	    *up = cache->hash_next;
+	    if (cache->flags & F_BIGNAME)
+	      {
+		cache->name.bname->next = big_free;
+		big_free = cache->name.bname;
+	      }
+	    cache->flags = 0;
+	  }
+	else
+	  up = &cache->hash_next;
+      }
+  
+  /* Add CNAMEs to interface_names to the cache */
+  for (a = daemon->cnames; a; a = a->next)
+    for (intr = daemon->int_names; intr; intr = intr->next)
+      if (a->alias[1] != '*' &&
+	  hostname_isequal(a->target, intr->name) &&
+	  ((cache = whine_malloc(sizeof(struct crec)))))
+	{
+	  cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
+	  cache->ttd = a->ttl;
+	  cache->name.namep = a->alias;
+	  cache->addr.cname.target.int_name = intr;
+	  cache->addr.cname.uid = SRC_INTERFACE;
+	  cache->uid = next_uid();
+	  cache_hash(cache);
+	  add_hosts_cname(cache); /* handle chains */
+	}
+
+#ifdef HAVE_DNSSEC
+  for (ds = daemon->ds; ds; ds = ds->next)
+    if ((cache = whine_malloc(sizeof(struct crec))) &&
+	(cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
+      {
+	cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
+	cache->ttd = daemon->local_ttl;
+	cache->name.namep = ds->name;
+	cache->addr.ds.keylen = ds->digestlen;
+	cache->addr.ds.algo = ds->algo;
+	cache->addr.ds.keytag = ds->keytag;
+	cache->addr.ds.digest = ds->digest_type;
+	cache->uid = ds->class;
+	cache_hash(cache);
+      }
+#endif
+  
+  /* borrow the packet buffer for a temporary by-address hash */
+  memset(daemon->packet, 0, daemon->packet_buff_sz);
+  revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
+  /* we overwrote the buffer... */
+  daemon->srv_save = NULL;
+
+  /* Do host_records in config. */
+  for (hr = daemon->host_records; hr; hr = hr->next)
+    for (nl = hr->names; nl; nl = nl->next)
+      {
+	if (hr->addr.s_addr != 0 &&
+	    (cache = whine_malloc(sizeof(struct crec))))
+	  {
+	    cache->name.namep = nl->name;
+	    cache->ttd = hr->ttl;
+	    cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
+	    add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
+	  }
+#ifdef HAVE_IPV6
+	if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
+	    (cache = whine_malloc(sizeof(struct crec))))
+	  {
+	    cache->name.namep = nl->name;
+	    cache->ttd = hr->ttl;
+	    cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
+	    add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
+	  }
+#endif
+      }
+	
+  if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
+    {
+      if (daemon->cachesize > 0)
+	my_syslog(LOG_INFO, _("cleared cache"));
+    }
+  else
+    {
+      if (!option_bool(OPT_NO_HOSTS))
+	total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
+      
+      daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
+      for (ah = daemon->addn_hosts; ah; ah = ah->next)
+	if (!(ah->flags & AH_INACTIVE))
+	  total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
+    }
+
+#ifdef HAVE_INOTIFY
+  set_dynamic_inotify(AH_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
+#endif
+  
+} 
+
+#ifdef HAVE_DHCP
+struct in_addr a_record_from_hosts(char *name, time_t now)
+{
+  struct crec *crecp = NULL;
+  struct in_addr ret;
+  
+  while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
+    if (crecp->flags & F_HOSTS)
+      return *(struct in_addr *)&crecp->addr;
+
+  my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
+  
+  ret.s_addr = 0;
+  return ret;
+}
+
+void cache_unhash_dhcp(void)
+{
+  struct crec *cache, **up;
+  int i;
+
+  for (i=0; i<hash_size; i++)
+    for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
+      if (cache->flags & F_DHCP)
+	{
+	  *up = cache->hash_next;
+	  cache->next = dhcp_spare;
+	  dhcp_spare = cache;
+	}
+      else
+	up = &cache->hash_next;
+}
+
+static void add_dhcp_cname(struct crec *target, time_t ttd)
+{
+  struct crec *aliasc;
+  struct cname *a;
+  
+  for (a = daemon->cnames; a; a = a->next)
+    if (a->alias[1] != '*' &&
+	hostname_isequal(cache_get_name(target), a->target))
+      {
+	if ((aliasc = dhcp_spare))
+	  dhcp_spare = dhcp_spare->next;
+	else /* need new one */
+	  aliasc = whine_malloc(sizeof(struct crec));
+	
+	if (aliasc)
+	  {
+	    aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME | F_CONFIG;
+	    if (ttd == 0)
+	      aliasc->flags |= F_IMMORTAL;
+	    else
+	      aliasc->ttd = ttd;
+	    aliasc->name.namep = a->alias;
+	    aliasc->addr.cname.target.cache = target;
+	    aliasc->addr.cname.uid = target->uid;
+	    aliasc->uid = next_uid();
+	    cache_hash(aliasc);
+	    add_dhcp_cname(aliasc, ttd);
+	  }
+      }
+}
+
+void cache_add_dhcp_entry(char *host_name, int prot,
+			  struct all_addr *host_address, time_t ttd) 
+{
+  struct crec *crec = NULL, *fail_crec = NULL;
+  unsigned short flags = F_IPV4;
+  int in_hosts = 0;
+  size_t addrlen = sizeof(struct in_addr);
+
+#ifdef HAVE_IPV6
+  if (prot == AF_INET6)
+    {
+      flags = F_IPV6;
+      addrlen = sizeof(struct in6_addr);
+    }
+#endif
+  
+  inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
+  
+  while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
+    {
+      /* check all addresses associated with name */
+      if (crec->flags & (F_HOSTS | F_CONFIG))
+	{
+	  if (crec->flags & F_CNAME)
+	    my_syslog(MS_DHCP | LOG_WARNING, 
+		      _("%s is a CNAME, not giving it to the DHCP lease of %s"),
+		      host_name, daemon->addrbuff);
+	  else if (memcmp(&crec->addr.addr, host_address, addrlen) == 0)
+	    in_hosts = 1;
+	  else
+	    fail_crec = crec;
+	}
+      else if (!(crec->flags & F_DHCP))
+	{
+	  cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD));
+	  /* scan_free deletes all addresses associated with name */
+	  break;
+	}
+    }
+  
+  /* if in hosts, don't need DHCP record */
+  if (in_hosts)
+    return;
+  
+  /* Name in hosts, address doesn't match */
+  if (fail_crec)
+    {
+      inet_ntop(prot, &fail_crec->addr.addr, daemon->namebuff, MAXDNAME);
+      my_syslog(MS_DHCP | LOG_WARNING, 
+		_("not giving name %s to the DHCP lease of %s because "
+		  "the name exists in %s with address %s"), 
+		host_name, daemon->addrbuff,
+		record_source(fail_crec->uid), daemon->namebuff);
+      return;
+    }	  
+  
+  if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
+    {
+      if (crec->flags & F_NEG)
+	{
+	  flags |= F_REVERSE;
+	  cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
+	}
+    }
+  else
+    flags |= F_REVERSE;
+  
+  if ((crec = dhcp_spare))
+    dhcp_spare = dhcp_spare->next;
+  else /* need new one */
+    crec = whine_malloc(sizeof(struct crec));
+  
+  if (crec) /* malloc may fail */
+    {
+      crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
+      if (ttd == 0)
+	crec->flags |= F_IMMORTAL;
+      else
+	crec->ttd = ttd;
+      crec->addr.addr = *host_address;
+      crec->name.namep = host_name;
+      crec->uid = next_uid();
+      cache_hash(crec);
+
+      add_dhcp_cname(crec, ttd);
+    }
+}
+#endif
+
+#ifndef NO_ID
+int cache_make_stat(struct txt_record *t)
+{ 
+  static char *buff = NULL;
+  static int bufflen = 60;
+  int len;
+  struct server *serv, *serv1;
+  char *p;
+
+  if (!buff && !(buff = whine_malloc(60)))
+    return 0;
+
+  p = buff;
+  
+  switch (t->stat)
+    {
+    case TXT_STAT_CACHESIZE:
+      sprintf(buff+1, "%d", daemon->cachesize);
+      break;
+
+    case TXT_STAT_INSERTS:
+      sprintf(buff+1, "%d", cache_inserted);
+      break;
+
+    case TXT_STAT_EVICTIONS:
+      sprintf(buff+1, "%d", cache_live_freed);
+      break;
+
+    case TXT_STAT_MISSES:
+      sprintf(buff+1, "%u", daemon->queries_forwarded);
+      break;
+
+    case TXT_STAT_HITS:
+      sprintf(buff+1, "%u", daemon->local_answer);
+      break;
+
+#ifdef HAVE_AUTH
+    case TXT_STAT_AUTH:
+      sprintf(buff+1, "%u", daemon->auth_answer);
+      break;
+#endif
+
+    case TXT_STAT_SERVERS:
+      /* sum counts from different records for same server */
+      for (serv = daemon->servers; serv; serv = serv->next)
+	serv->flags &= ~SERV_COUNTED;
+      
+      for (serv = daemon->servers; serv; serv = serv->next)
+	if (!(serv->flags & 
+	      (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
+	  {
+	    char *new, *lenp;
+	    int port, newlen, bytes_avail, bytes_needed;
+	    unsigned int queries = 0, failed_queries = 0;
+	    for (serv1 = serv; serv1; serv1 = serv1->next)
+	      if (!(serv1->flags & 
+		    (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) && 
+		  sockaddr_isequal(&serv->addr, &serv1->addr))
+		{
+		  serv1->flags |= SERV_COUNTED;
+		  queries += serv1->queries;
+		  failed_queries += serv1->failed_queries;
+		}
+	    port = prettyprint_addr(&serv->addr, daemon->addrbuff);
+	    lenp = p++; /* length */
+	    bytes_avail = bufflen - (p - buff );
+	    bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
+	    if (bytes_needed >= bytes_avail)
+	      {
+		/* expand buffer if necessary */
+		newlen = bytes_needed + 1 + bufflen - bytes_avail;
+		if (!(new = whine_malloc(newlen)))
+		  return 0;
+		memcpy(new, buff, bufflen);
+		free(buff);
+		p = new + (p - buff);
+		lenp = p - 1;
+		buff = new;
+		bufflen = newlen;
+		bytes_avail =  bufflen - (p - buff );
+		bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
+	      }
+	    *lenp = bytes_needed;
+	    p += bytes_needed;
+	  }
+      t->txt = (unsigned char *)buff;
+      t->len = p - buff;
+      return 1;
+    }
+  
+  len = strlen(buff+1);
+  t->txt = (unsigned char *)buff;
+  t->len = len + 1;
+  *buff = len;
+  return 1;
+}
+#endif
+
+/* There can be names in the cache containing control chars, don't 
+   mess up logging or open security holes. */
+static char *sanitise(char *name)
+{
+  unsigned char *r;
+  if (name)
+    for (r = (unsigned char *)name; *r; r++)
+      if (!isprint((int)*r))
+	return "<name unprintable>";
+
+  return name;
+}
+
+
+void dump_cache(time_t now)
+{
+  struct server *serv, *serv1;
+  char *t = "";
+
+  my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
+  my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."), 
+	    daemon->cachesize, cache_live_freed, cache_inserted);
+  my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"), 
+	    daemon->queries_forwarded, daemon->local_answer);
+#ifdef HAVE_AUTH
+  my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->auth_answer);
+#endif
+#ifdef HAVE_DNSSEC
+  blockdata_report();
+#endif
+
+  /* sum counts from different records for same server */
+  for (serv = daemon->servers; serv; serv = serv->next)
+    serv->flags &= ~SERV_COUNTED;
+  
+  for (serv = daemon->servers; serv; serv = serv->next)
+    if (!(serv->flags & 
+	  (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
+      {
+	int port;
+	unsigned int queries = 0, failed_queries = 0;
+	for (serv1 = serv; serv1; serv1 = serv1->next)
+	  if (!(serv1->flags & 
+		(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) && 
+	      sockaddr_isequal(&serv->addr, &serv1->addr))
+	    {
+	      serv1->flags |= SERV_COUNTED;
+	      queries += serv1->queries;
+	      failed_queries += serv1->failed_queries;
+	    }
+	port = prettyprint_addr(&serv->addr, daemon->addrbuff);
+	my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), daemon->addrbuff, port, queries, failed_queries);
+      }
+  
+  if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
+    {
+      struct crec *cache ;
+      int i;
+      my_syslog(LOG_INFO, "Host                                     Address                        Flags      Expires");
+    
+      for (i=0; i<hash_size; i++)
+	for (cache = hash_table[i]; cache; cache = cache->hash_next)
+	  {
+	    char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
+	    *a = 0;
+	    if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
+	      n = "<Root>";
+	    p += sprintf(p, "%-30.30s ", sanitise(n));
+	    if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
+	      a = sanitise(cache_get_cname_target(cache));
+#ifdef HAVE_DNSSEC
+	    else if (cache->flags & F_DS)
+	      {
+		if (!(cache->flags & F_NEG))
+		  sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
+			  cache->addr.ds.algo, cache->addr.ds.digest);
+	      }
+	    else if (cache->flags & F_DNSKEY)
+	      sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
+		      cache->addr.key.algo, cache->addr.key.flags);
+#endif
+	    else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
+	      { 
+		a = daemon->addrbuff;
+		if (cache->flags & F_IPV4)
+		  inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN);
+#ifdef HAVE_IPV6
+		else if (cache->flags & F_IPV6)
+		  inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN);
+#endif
+	      }
+
+	    if (cache->flags & F_IPV4)
+	      t = "4";
+	    else if (cache->flags & F_IPV6)
+	      t = "6";
+	    else if (cache->flags & F_CNAME)
+	      t = "C";
+#ifdef HAVE_DNSSEC
+	    else if (cache->flags & F_DS)
+	      t = "S";
+	    else if (cache->flags & F_DNSKEY)
+	      t = "K";
+#endif
+	    p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s  ", a, t,
+			 cache->flags & F_FORWARD ? "F" : " ",
+			 cache->flags & F_REVERSE ? "R" : " ",
+			 cache->flags & F_IMMORTAL ? "I" : " ",
+			 cache->flags & F_DHCP ? "D" : " ",
+			 cache->flags & F_NEG ? "N" : " ",
+			 cache->flags & F_NXDOMAIN ? "X" : " ",
+			 cache->flags & F_HOSTS ? "H" : " ",
+			 cache->flags & F_DNSSECOK ? "V" : " ");
+#ifdef HAVE_BROKEN_RTC
+	    p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
+#else
+	    p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
+	    /* ctime includes trailing \n - eat it */
+	    *(p-1) = 0;
+#endif
+	    my_syslog(LOG_INFO, "%s", daemon->namebuff);
+	  }
+    }
+}
+
+char *record_source(unsigned int index)
+{
+  struct hostsfile *ah;
+
+  if (index == SRC_CONFIG)
+    return "config";
+  else if (index == SRC_HOSTS)
+    return HOSTSFILE;
+
+  for (ah = daemon->addn_hosts; ah; ah = ah->next)
+    if (ah->index == index)
+      return ah->fname;
+
+#ifdef HAVE_INOTIFY
+  for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
+     if (ah->index == index)
+       return ah->fname;
+#endif
+
+  return "<unknown>";
+}
+
+char *querystr(char *desc, unsigned short type)
+{
+  unsigned int i;
+  int len = 10; /* strlen("type=xxxxx") */
+  const char *types = NULL;
+  static char *buff = NULL;
+  static int bufflen = 0;
+
+  for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
+    if (typestr[i].type == type)
+      {
+	types = typestr[i].name;
+	len = strlen(types);
+	break;
+      }
+
+  len += 3; /* braces, terminator */
+  len += strlen(desc);
+
+  if (!buff || bufflen < len)
+    {
+      if (buff)
+	free(buff);
+      else if (len < 20)
+	len = 20;
+      
+      buff = whine_malloc(len);
+      bufflen = len;
+    }
+
+  if (buff)
+    {
+      if (types)
+	sprintf(buff, "%s[%s]", desc, types);
+      else
+	sprintf(buff, "%s[type=%d]", desc, type);
+    }
+
+  return buff ? buff : "";
+}
+
+void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
+{
+  char *source, *dest = daemon->addrbuff;
+  char *verb = "is";
+  
+  if (!option_bool(OPT_LOG))
+    return;
+
+  name = sanitise(name);
+
+  if (addr)
+    {
+      if (flags & F_KEYTAG)
+	sprintf(daemon->addrbuff, arg, addr->addr.log.keytag, addr->addr.log.algo, addr->addr.log.digest);
+      else
+	{
+#ifdef HAVE_IPV6
+	  inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
+		    addr, daemon->addrbuff, ADDRSTRLEN);
+#else
+	  strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);  
+#endif
+	}
+    }
+  else
+    dest = arg;
+
+  if (flags & F_REVERSE)
+    {
+      dest = name;
+      name = daemon->addrbuff;
+    }
+  
+  if (flags & F_NEG)
+    {
+      if (flags & F_NXDOMAIN)
+	dest = "NXDOMAIN";
+      else
+	{      
+	  if (flags & F_IPV4)
+	    dest = "NODATA-IPv4";
+	  else if (flags & F_IPV6)
+	    dest = "NODATA-IPv6";
+	  else
+	    dest = "NODATA";
+	}
+    }
+  else if (flags & F_CNAME)
+    dest = "<CNAME>";
+  else if (flags & F_RRNAME)
+    dest = arg;
+    
+  if (flags & F_CONFIG)
+    source = "config";
+  else if (flags & F_DHCP)
+    source = "DHCP";
+  else if (flags & F_HOSTS)
+    source = arg;
+  else if (flags & F_UPSTREAM)
+    source = "reply";
+  else if (flags & F_SECSTAT)
+    source = "validation";
+  else if (flags & F_AUTH)
+    source = "auth";
+  else if (flags & F_SERVER)
+    {
+      source = "forwarded";
+      verb = "to";
+    }
+  else if (flags & F_QUERY)
+    {
+      source = arg;
+      verb = "from";
+    }
+  else if (flags & F_DNSSEC)
+    {
+      source = arg;
+      verb = "to";
+    }
+  else if (flags & F_IPSET)
+    {
+      source = "ipset add";
+      dest = name;
+      name = arg;
+      verb = daemon->addrbuff;
+    }
+  else
+    source = "cached";
+  
+  if (strlen(name) == 0)
+    name = ".";
+
+  if (option_bool(OPT_EXTRALOG))
+    {
+      int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
+      if (flags & F_NOEXTRA)
+	my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
+      else
+	my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest);
+    }
+  else
+    my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
+}
+
+ 
diff --git a/src/config.h b/src/config.h
new file mode 100755
index 0000000..5b225f8
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,470 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define FTABSIZ 150 /* max number of outstanding requests (default) */
+#define MAX_PROCS 20 /* max no children for TCP requests */
+#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
+#define TCP_MAX_QUERIES 100 /* Maximum number of queries per incoming TCP connection */
+#define TCP_BACKLOG 32  /* kernel backlog limit for TCP connections */
+#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
+#define SAFE_PKTSZ 1280 /* "go anywhere" UDP packet size */
+#define KEYBLOCK_LEN 40 /* choose to minimise fragmentation when storing DNSSEC keys */
+#define DNSSEC_WORK 50 /* Max number of queries to validate one question */
+#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
+#define FORWARD_TEST 50 /* try all servers every 50 queries */
+#define FORWARD_TIME 20 /* or 20 seconds */
+#define SERVERS_LOGGED 30 /* Only log this many servers when logging state */
+#define LOCALS_LOGGED 8 /* Only log this many local addresses when logging state */
+#define RANDOM_SOCKS 64 /* max simultaneous random ports */
+#define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
+#define CACHESIZ 150 /* default cache size */
+#define TTL_FLOOR_LIMIT 3600 /* don't allow --min-cache-ttl to raise TTL above this under any circumstances */
+#define MAXLEASES 1000 /* maximum number of DHCP leases */
+#define PING_WAIT 3 /* wait for ping address-in-use test */
+#define PING_CACHE_TIME 30 /* Ping test assumed to be valid this long. */
+#define DECLINE_BACKOFF 600 /* disable DECLINEd static addresses for this long */
+#define DHCP_PACKET_MAX 16384 /* hard limit on DHCP packet size */
+#define SMALLDNAME 50 /* most domain names are smaller than this */
+#define CNAME_CHAIN 10 /* chains longer than this atr dropped for loop protection */
+#define HOSTSFILE "/etc/hosts"
+#define ETHERSFILE "/etc/ethers"
+#define DEFLEASE 3600 /* default lease time, 1 hour */
+#define CHUSER "nobody"
+#define CHGRP "dip"
+#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
+#define LOG_MAX 5 /* log-queue length */
+#define RANDFILE "/dev/urandom"
+#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* Default - may be overridden by config */
+#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
+#define AUTH_TTL 600 /* default TTL for auth DNS */
+#define SOA_REFRESH 1200 /* SOA refresh default */
+#define SOA_RETRY 180 /* SOA retry default */
+#define SOA_EXPIRY 1209600 /* SOA expiry default */
+#define LOOP_TEST_DOMAIN "test" /* domain for loop testing, "test" is reserved by RFC 2606 and won't therefore clash */
+#define LOOP_TEST_TYPE T_TXT
+ 
+/* compile-time options: uncomment below to enable or do eg.
+   make COPTS=-DHAVE_BROKEN_RTC
+
+HAVE_BROKEN_RTC
+   define this on embedded systems which don't have an RTC
+   which keeps time over reboots. Causes dnsmasq to use uptime
+   for timing, and keep lease lengths rather than expiry times
+   in its leases file. This also make dnsmasq "flash disk friendly".
+   Normally, dnsmasq tries very hard to keep the on-disk leases file
+   up-to-date: rewriting it after every renewal.  When HAVE_BROKEN_RTC 
+   is in effect, the lease file is only written when a new lease is 
+   created, or an old one destroyed. (Because those are the only times 
+   it changes.) This vastly reduces the number of file writes, and makes
+   it viable to keep the lease file on a flash filesystem.
+   NOTE: when enabling or disabling this, be sure to delete any old
+   leases file, otherwise dnsmasq may get very confused.
+
+HAVE_TFTP
+   define this to get dnsmasq's built-in TFTP server.
+
+HAVE_DHCP
+   define this to get dnsmasq's DHCPv4 server.
+
+HAVE_DHCP6
+   define this to get dnsmasq's DHCPv6 server. (implies HAVE_DHCP).
+
+HAVE_SCRIPT
+   define this to get the ability to call scripts on lease-change.
+
+HAVE_LUASCRIPT
+   define this to get the ability to call Lua script on lease-change. (implies HAVE_SCRIPT) 
+
+HAVE_DBUS
+   define this if you want to link against libdbus, and have dnsmasq
+   support some methods to allow (re)configuration of the upstream DNS 
+   servers via DBus.
+
+HAVE_IDN
+   define this if you want international domain name 2003 support.
+   
+HAVE_LIBIDN2
+   define this if you want international domain name 2008 support.
+
+HAVE_CONNTRACK
+   define this to include code which propagates conntrack marks from
+   incoming DNS queries to the corresponding upstream queries. This adds
+   a build-dependency on libnetfilter_conntrack, but the resulting binary will
+   still run happily on a kernel without conntrack support.
+
+HAVE_IPSET
+    define this to include the ability to selectively add resolved ip addresses
+    to given ipsets.
+
+HAVE_AUTH
+   define this to include the facility to act as an authoritative DNS
+   server for one or more zones.
+
+HAVE_DNSSEC
+   include DNSSEC validator.
+
+HAVE_LOOP
+   include functionality to probe for and remove DNS forwarding loops.
+
+HAVE_INOTIFY
+   use the Linux inotify facility to efficiently re-read configuration files.
+
+NO_ID
+   Don't report *.bind CHAOS info to clients, forward such requests upstream instead.
+NO_IPV6
+NO_TFTP
+NO_DHCP
+NO_DHCP6
+NO_SCRIPT
+NO_LARGEFILE
+NO_AUTH
+NO_INOTIFY
+   these are available to explicitly disable compile time options which would 
+   otherwise be enabled automatically (HAVE_IPV6, >2Gb file sizes) or 
+   which are enabled  by default in the distributed source tree. Building dnsmasq
+   with something like "make COPTS=-DNO_SCRIPT" will do the trick.
+
+NO_NETTLE_ECC
+   Don't include the ECDSA cypher in DNSSEC validation. Needed for older Nettle versions.
+NO_GMP
+   Don't use and link against libgmp, Useful if nettle is built with --enable-mini-gmp.
+
+LEASEFILE
+CONFFILE
+RESOLVFILE
+   the default locations of these files are determined below, but may be overridden 
+   in a build command line using COPTS.
+
+*/
+
+/* Defining this builds a binary which handles time differently and works better on a system without a 
+   stable RTC (it uses uptime, not epoch time) and writes the DHCP leases file less often to avoid flash wear. 
+*/
+
+/* #define HAVE_BROKEN_RTC */
+
+/* The default set of options to build. Built with these options, dnsmasq
+   has no library dependencies other than libc */
+
+#define HAVE_DHCP
+#define HAVE_DHCP6 
+#define HAVE_TFTP
+#define HAVE_SCRIPT
+#define HAVE_AUTH
+#define HAVE_IPSET 
+#define HAVE_LOOP
+
+/* Build options which require external libraries.
+   
+   Defining HAVE_<opt>_STATIC as _well_ as HAVE_<opt> will link the library statically.
+
+   You can use "make COPTS=-DHAVE_<opt>" instead of editing these.
+*/
+
+/* #define HAVE_LUASCRIPT */
+/* #define HAVE_DBUS */
+/* #define HAVE_IDN */
+/* #define HAVE_LIBIDN2 */
+/* #define HAVE_CONNTRACK */
+/* #define HAVE_DNSSEC */
+
+
+/* Default locations for important system files. */
+
+#ifndef LEASEFILE
+#   if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
+#      define LEASEFILE "/var/db/dnsmasq.leases"
+#   elif defined(__sun__) || defined (__sun)
+#      define LEASEFILE "/var/cache/dnsmasq.leases"
+#   elif defined(__ANDROID__)
+#      define LEASEFILE "/data/misc/dhcp/dnsmasq.leases"
+#   else
+#      define LEASEFILE "/var/lib/misc/dnsmasq.leases"
+#   endif
+#endif
+
+#ifndef CONFFILE
+#   if defined(__FreeBSD__)
+#      define CONFFILE "/usr/local/etc/dnsmasq.conf"
+#   else
+#      define CONFFILE "/etc/dnsmasq.conf"
+#   endif
+#endif
+
+#ifndef RESOLVFILE
+#   if defined(__uClinux__)
+#      define RESOLVFILE "/etc/config/resolv.conf"
+#   else
+#      define RESOLVFILE "/etc/resolv.conf"
+#   endif
+#endif
+
+#ifndef RUNFILE
+#   if defined(__ANDROID__)
+#      define RUNFILE "/data/dnsmasq.pid"
+#    else
+#      define RUNFILE "/var/run/dnsmasq.pid"
+#    endif
+#endif
+
+/* platform dependent options: these are determined automatically below
+
+HAVE_LINUX_NETWORK
+HAVE_BSD_NETWORK
+HAVE_SOLARIS_NETWORK
+   define exactly one of these to alter interaction with kernel networking.
+
+HAVE_GETOPT_LONG
+   defined when GNU-style getopt_long available. 
+
+HAVE_SOCKADDR_SA_LEN
+   defined if struct sockaddr has sa_len field (*BSD) 
+*/
+
+/* Must precede __linux__ since uClinux defines __linux__ too. */
+#if defined(__uClinux__)
+#define HAVE_LINUX_NETWORK
+#define HAVE_GETOPT_LONG
+#undef HAVE_SOCKADDR_SA_LEN
+/* 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 and disables the call-a-script on leasechange
+   system. It's intended for use on MMU-less kernels. */
+#define NO_FORK
+
+#elif defined(__UCLIBC__)
+#define HAVE_LINUX_NETWORK
+#if defined(__UCLIBC_HAS_GNU_GETOPT__) || \
+   ((__UCLIBC_MAJOR__==0) && (__UCLIBC_MINOR__==9) && (__UCLIBC_SUBLEVEL__<21))
+#    define HAVE_GETOPT_LONG
+#endif
+#undef HAVE_SOCKADDR_SA_LEN
+#if !defined(__ARCH_HAS_MMU__) && !defined(__UCLIBC_HAS_MMU__)
+#  define NO_FORK
+#endif
+#if defined(__UCLIBC_HAS_IPV6__)
+#  ifndef IPV6_V6ONLY
+#    define IPV6_V6ONLY 26
+#  endif
+#endif
+
+/* This is for glibc 2.x */
+#elif defined(__linux__)
+#define HAVE_LINUX_NETWORK
+#define HAVE_GETOPT_LONG
+#undef HAVE_SOCKADDR_SA_LEN
+
+#elif defined(__FreeBSD__) || \
+      defined(__OpenBSD__) || \
+      defined(__DragonFly__) || \
+      defined(__FreeBSD_kernel__)
+#define HAVE_BSD_NETWORK
+/* Later versions of FreeBSD have getopt_long() */
+#if defined(optional_argument) && defined(required_argument)
+#   define HAVE_GETOPT_LONG
+#endif
+#define HAVE_SOCKADDR_SA_LEN
+
+#elif defined(__APPLE__)
+#define HAVE_BSD_NETWORK
+#define HAVE_GETOPT_LONG
+#define HAVE_SOCKADDR_SA_LEN
+/* Define before sys/socket.h is included so we get socklen_t */
+#define _BSD_SOCKLEN_T_
+/* Select the RFC_3542 version of the IPv6 socket API. 
+   Define before netinet6/in6.h is included. */
+#define __APPLE_USE_RFC_3542 
+#define NO_IPSET
+
+#elif defined(__NetBSD__)
+#define HAVE_BSD_NETWORK
+#define HAVE_GETOPT_LONG
+#define HAVE_SOCKADDR_SA_LEN
+
+#elif defined(__sun) || defined(__sun__)
+#define HAVE_SOLARIS_NETWORK
+#define HAVE_GETOPT_LONG
+#undef HAVE_SOCKADDR_SA_LEN
+#define ETHER_ADDR_LEN 6 
+ 
+#endif
+
+/* Decide if we're going to support IPv6 */
+/* We assume that systems which don't have IPv6
+   headers don't have ntop and pton either */
+
+#if defined(INET6_ADDRSTRLEN) && defined(IPV6_V6ONLY)
+#ifndef HAVE_IPV6
+#  define HAVE_IPV6
+#endif
+#  define ADDRSTRLEN INET6_ADDRSTRLEN
+#else
+#  if !defined(INET_ADDRSTRLEN)
+#      define INET_ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
+#  endif
+#  undef HAVE_IPV6
+#  define ADDRSTRLEN INET_ADDRSTRLEN
+#endif
+
+
+/* rules to implement compile-time option dependencies and 
+   the NO_XXX flags */
+
+#ifdef NO_IPV6
+#undef HAVE_IPV6
+#endif
+
+#ifdef NO_TFTP
+#undef HAVE_TFTP
+#endif
+
+#ifdef NO_DHCP
+#undef HAVE_DHCP
+#undef HAVE_DHCP6
+#endif
+
+#if defined(NO_DHCP6) || !defined(HAVE_IPV6)
+#undef HAVE_DHCP6
+#endif
+
+/* DHCP6 needs DHCP too */
+#ifdef HAVE_DHCP6
+#define HAVE_DHCP
+#endif
+
+#if defined(NO_SCRIPT) || defined(NO_FORK)
+#undef HAVE_SCRIPT
+#undef HAVE_LUASCRIPT
+#endif
+
+/* Must HAVE_SCRIPT to HAVE_LUASCRIPT */
+#ifdef HAVE_LUASCRIPT
+#define HAVE_SCRIPT
+#endif
+
+#ifdef NO_AUTH
+#undef HAVE_AUTH
+#endif
+
+#if defined(NO_IPSET)
+#undef HAVE_IPSET
+#endif
+
+#ifdef NO_LOOP
+#undef HAVE_LOOP
+#endif
+
+#if defined (HAVE_LINUX_NETWORK)
+#ifdef NO_INOTIFY
+#undef HAVE_INOTIFY
+#else
+#ifndef HAVE_INOTIFY
+#define HAVE_INOTIFY
+#endif
+#endif
+#endif
+
+/* Define a string indicating which options are in use.
+   DNSMASQ_COMPILE_OPTS is only defined in dnsmasq.c */
+
+#ifdef DNSMASQ_COMPILE_OPTS
+
+static char *compile_opts = 
+#ifndef HAVE_IPV6
+"no-"
+#endif
+"IPv6 "
+#ifndef HAVE_GETOPT_LONG
+"no-"
+#endif
+"GNU-getopt "
+#ifdef HAVE_BROKEN_RTC
+"no-RTC "
+#endif
+#ifdef NO_FORK
+"no-MMU "
+#endif
+#ifndef HAVE_DBUS
+"no-"
+#endif
+"DBus "
+#ifndef LOCALEDIR
+"no-"
+#endif
+"i18n "
+#if defined(HAVE_LIBIDN2)
+"IDN2 "
+#else
+ #if !defined(HAVE_IDN)
+"no-"
+ #endif 
+"IDN " 
+#endif
+#ifndef HAVE_DHCP
+"no-"
+#endif
+"DHCP "
+#if defined(HAVE_DHCP)
+#  if !defined (HAVE_DHCP6)
+     "no-"
+#  endif  
+     "DHCPv6 "
+#endif
+#if !defined(HAVE_SCRIPT)
+     "no-scripts "
+#else
+#  if !defined(HAVE_LUASCRIPT)
+     "no-"
+#  endif
+     "Lua "
+#endif
+#ifndef HAVE_TFTP
+"no-"
+#endif
+"TFTP "
+#ifndef HAVE_CONNTRACK
+"no-"
+#endif
+"conntrack "
+#ifndef HAVE_IPSET
+"no-"
+#endif
+"ipset "
+#ifndef HAVE_AUTH
+"no-"
+#endif
+"auth "
+#ifndef HAVE_DNSSEC
+"no-"
+#endif
+"DNSSEC "
+#ifdef NO_ID
+"no-ID "
+#endif
+#ifndef HAVE_LOOP
+"no-"
+#endif
+"loop-detect "
+#ifndef HAVE_INOTIFY
+"no-"
+#endif
+"inotify";
+
+
+#endif
+
+
+
diff --git a/src/conntrack.c b/src/conntrack.c
new file mode 100644
index 0000000..1aa4e28
--- /dev/null
+++ b/src/conntrack.c
@@ -0,0 +1,90 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_CONNTRACK
+
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+static int gotit = 0; /* yuck */
+
+static int callback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data);
+
+int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr, int istcp, unsigned int *markp)
+{
+  struct nf_conntrack *ct;
+  struct nfct_handle *h;
+  
+  gotit = 0;
+  
+  if ((ct = nfct_new())) 
+    {
+      nfct_set_attr_u8(ct, ATTR_L4PROTO, istcp ? IPPROTO_TCP : IPPROTO_UDP);
+      nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(daemon->port));
+      
+#ifdef HAVE_IPV6
+      if (peer_addr->sa.sa_family == AF_INET6)
+	{
+	  nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET6);
+	  nfct_set_attr(ct, ATTR_IPV6_SRC, peer_addr->in6.sin6_addr.s6_addr);
+	  nfct_set_attr_u16(ct, ATTR_PORT_SRC, peer_addr->in6.sin6_port);
+	  nfct_set_attr(ct, ATTR_IPV6_DST, local_addr->addr.addr6.s6_addr);
+	}
+      else
+#endif
+	{
+	  nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET);
+	  nfct_set_attr_u32(ct, ATTR_IPV4_SRC, peer_addr->in.sin_addr.s_addr);
+	  nfct_set_attr_u16(ct, ATTR_PORT_SRC, peer_addr->in.sin_port);
+	  nfct_set_attr_u32(ct, ATTR_IPV4_DST, local_addr->addr.addr4.s_addr);
+	}
+      
+      
+      if ((h = nfct_open(CONNTRACK, 0))) 
+	{
+	  nfct_callback_register(h, NFCT_T_ALL, callback, (void *)markp);  
+	  if (nfct_query(h, NFCT_Q_GET, ct) == -1)
+	    {
+	      static int warned = 0;
+	      if (!warned)
+		{
+		  my_syslog(LOG_ERR, _("Conntrack connection mark retrieval failed: %s"), strerror(errno));
+		  warned = 1;
+		}
+	    }
+	  nfct_close(h);  
+	}
+      nfct_destroy(ct);
+    }
+
+  return gotit;
+}
+
+static int callback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data)
+{
+  unsigned int *ret = (unsigned int *)data;
+  *ret = nfct_get_attr_u32(ct, ATTR_MARK);
+  (void)type; /* eliminate warning */
+  gotit = 1;
+
+  return NFCT_CB_CONTINUE;
+}
+
+#endif
+  
+
+
diff --git a/src/dbus.c b/src/dbus.c
new file mode 100755
index 0000000..9bd68ad
--- /dev/null
+++ b/src/dbus.c
@@ -0,0 +1,857 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_DBUS
+
+#include <dbus/dbus.h>
+
+const char* introspection_xml_template =
+"<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
+"\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
+"<node name=\"" DNSMASQ_PATH "\">\n"
+"  <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
+"    <method name=\"Introspect\">\n"
+"      <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
+"    </method>\n"
+"  </interface>\n"
+"  <interface name=\"%s\">\n"
+"    <method name=\"ClearCache\">\n"
+"    </method>\n"
+"    <method name=\"GetVersion\">\n"
+"      <arg name=\"version\" direction=\"out\" type=\"s\"/>\n"
+"    </method>\n"
+#ifdef HAVE_LOOP
+"    <method name=\"GetLoopServers\">\n"
+"      <arg name=\"server\" direction=\"out\" type=\"as\"/>\n"
+"    </method>\n"
+#endif
+"    <method name=\"SetServers\">\n"
+"      <arg name=\"servers\" direction=\"in\" type=\"av\"/>\n"
+"    </method>\n"
+"    <method name=\"SetDomainServers\">\n"
+"      <arg name=\"servers\" direction=\"in\" type=\"as\"/>\n"
+"    </method>\n"
+"    <method name=\"SetServersEx\">\n"
+"      <arg name=\"servers\" direction=\"in\" type=\"aas\"/>\n"
+"    </method>\n"
+"    <method name=\"SetFilterWin2KOption\">\n"
+"      <arg name=\"filterwin2k\" direction=\"in\" type=\"b\"/>\n"
+"    </method>\n"
+"    <method name=\"SetBogusPrivOption\">\n"
+"      <arg name=\"boguspriv\" direction=\"in\" type=\"b\"/>\n"
+"    </method>\n"
+"    <signal name=\"DhcpLeaseAdded\">\n"
+"      <arg name=\"ipaddr\" type=\"s\"/>\n"
+"      <arg name=\"hwaddr\" type=\"s\"/>\n"
+"      <arg name=\"hostname\" type=\"s\"/>\n"
+"    </signal>\n"
+"    <signal name=\"DhcpLeaseDeleted\">\n"
+"      <arg name=\"ipaddr\" type=\"s\"/>\n"
+"      <arg name=\"hwaddr\" type=\"s\"/>\n"
+"      <arg name=\"hostname\" type=\"s\"/>\n"
+"    </signal>\n"
+"    <signal name=\"DhcpLeaseUpdated\">\n"
+"      <arg name=\"ipaddr\" type=\"s\"/>\n"
+"      <arg name=\"hwaddr\" type=\"s\"/>\n"
+"      <arg name=\"hostname\" type=\"s\"/>\n"
+"    </signal>\n"
+#ifdef HAVE_DHCP
+"    <method name=\"AddDhcpLease\">\n"
+"       <arg name=\"ipaddr\" type=\"s\"/>\n"
+"       <arg name=\"hwaddr\" type=\"s\"/>\n"
+"       <arg name=\"hostname\" type=\"ay\"/>\n"
+"       <arg name=\"clid\" type=\"ay\"/>\n"
+"       <arg name=\"lease_duration\" type=\"u\"/>\n"
+"       <arg name=\"ia_id\" type=\"u\"/>\n"
+"       <arg name=\"is_temporary\" type=\"b\"/>\n"
+"    </method>\n"
+"    <method name=\"DeleteDhcpLease\">\n"
+"       <arg name=\"ipaddr\" type=\"s\"/>\n"
+"       <arg name=\"success\" type=\"b\" direction=\"out\"/>\n"
+"    </method>\n"
+#endif
+"  </interface>\n"
+"</node>\n";
+
+static char *introspection_xml = NULL;
+
+struct watch {
+  DBusWatch *watch;      
+  struct watch *next;
+};
+
+
+static dbus_bool_t add_watch(DBusWatch *watch, void *data)
+{
+  struct watch *w;
+
+  for (w = daemon->watches; w; w = w->next)
+    if (w->watch == watch)
+      return TRUE;
+
+  if (!(w = whine_malloc(sizeof(struct watch))))
+    return FALSE;
+
+  w->watch = watch;
+  w->next = daemon->watches;
+  daemon->watches = w;
+
+  w = data; /* no warning */
+  return TRUE;
+}
+
+static void remove_watch(DBusWatch *watch, void *data)
+{
+  struct watch **up, *w, *tmp;  
+  
+  for (up = &(daemon->watches), w = daemon->watches; w; w = tmp)
+    {
+      tmp = w->next;
+      if (w->watch == watch)
+	{
+	  *up = tmp;
+	  free(w);
+	}
+      else
+	up = &(w->next);
+    }
+
+  w = data; /* no warning */
+}
+
+static void dbus_read_servers(DBusMessage *message)
+{
+  DBusMessageIter iter;
+  union  mysockaddr addr, source_addr;
+  char *domain;
+  
+  dbus_message_iter_init(message, &iter);
+
+  mark_servers(SERV_FROM_DBUS);
+  
+  while (1)
+    {
+      int skip = 0;
+
+      if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT32)
+	{
+	  u32 a;
+	  
+	  dbus_message_iter_get_basic(&iter, &a);
+	  dbus_message_iter_next (&iter);
+	  
+#ifdef HAVE_SOCKADDR_SA_LEN
+	  source_addr.in.sin_len = addr.in.sin_len = sizeof(struct sockaddr_in);
+#endif
+	  addr.in.sin_addr.s_addr = ntohl(a);
+	  source_addr.in.sin_family = addr.in.sin_family = AF_INET;
+	  addr.in.sin_port = htons(NAMESERVER_PORT);
+	  source_addr.in.sin_addr.s_addr = INADDR_ANY;
+	  source_addr.in.sin_port = htons(daemon->query_port);
+	}
+      else if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_BYTE)
+	{
+	  unsigned char p[sizeof(struct in6_addr)];
+	  unsigned int i;
+
+	  skip = 1;
+
+	  for(i = 0; i < sizeof(struct in6_addr); i++)
+	    {
+	      dbus_message_iter_get_basic(&iter, &p[i]);
+	      dbus_message_iter_next (&iter);
+	      if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BYTE)
+		{
+		  i++;
+		  break;
+		}
+	    }
+
+#ifndef HAVE_IPV6
+	  my_syslog(LOG_WARNING, _("attempt to set an IPv6 server address via DBus - no IPv6 support"));
+#else
+	  if (i == sizeof(struct in6_addr))
+	    {
+	      memcpy(&addr.in6.sin6_addr, p, sizeof(struct in6_addr));
+#ifdef HAVE_SOCKADDR_SA_LEN
+              source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+              source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
+              addr.in6.sin6_port = htons(NAMESERVER_PORT);
+              source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = 0;
+	      source_addr.in6.sin6_scope_id = addr.in6.sin6_scope_id = 0;
+              source_addr.in6.sin6_addr = in6addr_any;
+              source_addr.in6.sin6_port = htons(daemon->query_port);
+	      skip = 0;
+	    }
+#endif
+	}
+      else
+	/* At the end */
+	break;
+      
+      /* process each domain */
+      do {
+	if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING)
+	  {
+	    dbus_message_iter_get_basic(&iter, &domain);
+	    dbus_message_iter_next (&iter);
+	  }
+	else
+	  domain = NULL;
+	
+	if (!skip)
+	  add_update_server(SERV_FROM_DBUS, &addr, &source_addr, NULL, domain);
+     
+      } while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING); 
+    }
+   
+  /* unlink and free anything still marked. */
+  cleanup_servers();
+}
+
+#ifdef HAVE_LOOP
+static DBusMessage *dbus_reply_server_loop(DBusMessage *message)
+{
+  DBusMessageIter args, args_iter;
+  struct server *serv;
+  DBusMessage *reply = dbus_message_new_method_return(message);
+   
+  dbus_message_iter_init_append (reply, &args);
+  dbus_message_iter_open_container (&args, DBUS_TYPE_ARRAY,DBUS_TYPE_STRING_AS_STRING, &args_iter);
+
+  for (serv = daemon->servers; serv; serv = serv->next)
+    if (serv->flags & SERV_LOOP)
+      {
+	prettyprint_addr(&serv->addr, daemon->addrbuff);
+	dbus_message_iter_append_basic (&args_iter, DBUS_TYPE_STRING, &daemon->addrbuff);
+      }
+  
+  dbus_message_iter_close_container (&args, &args_iter);
+
+  return reply;
+}
+#endif
+
+static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
+{
+  DBusMessageIter iter, array_iter, string_iter;
+  DBusMessage *error = NULL;
+  const char *addr_err;
+  char *dup = NULL;
+  
+  if (!dbus_message_iter_init(message, &iter))
+    {
+      return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                    "Failed to initialize dbus message iter");
+    }
+
+  /* check that the message contains an array of arrays */
+  if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
+      (dbus_message_iter_get_element_type(&iter) != (strings ? DBUS_TYPE_STRING : DBUS_TYPE_ARRAY)))
+    {
+      return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                    strings ? "Expected array of string" : "Expected array of string arrays");
+     }
+ 
+  mark_servers(SERV_FROM_DBUS);
+
+  /* array_iter points to each "as" element in the outer array */
+  dbus_message_iter_recurse(&iter, &array_iter);
+  while (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID)
+    {
+      const char *str = NULL;
+      union  mysockaddr addr, source_addr;
+      int flags = 0;
+      char interface[IF_NAMESIZE];
+      char *str_addr, *str_domain = NULL;
+
+      if (strings)
+	{
+	  dbus_message_iter_get_basic(&array_iter, &str);
+	  if (!str || !strlen (str))
+	    {
+	      error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+					     "Empty string");
+	      break;
+	    }
+	  
+	  /* dup the string because it gets modified during parsing */
+	  if (dup)
+	    free(dup);
+	  if (!(dup = str_domain = whine_malloc(strlen(str)+1)))
+	    break;
+	  
+	  strcpy(str_domain, str);
+
+	  /* point to address part of old string for error message */
+	  if ((str_addr = strrchr(str, '/')))
+	    str = str_addr+1;
+	  
+	  if ((str_addr = strrchr(str_domain, '/')))
+	    {
+	      if (*str_domain != '/' || str_addr == str_domain)
+		{
+		  error = dbus_message_new_error_printf(message,
+							DBUS_ERROR_INVALID_ARGS,
+							"No domain terminator '%s'",
+							str);
+		  break;
+		}
+	      *str_addr++ = 0;
+	      str_domain++;
+	    }
+	  else
+	    {
+	      str_addr = str_domain;
+	      str_domain = NULL;
+	    }
+
+	  
+	}
+      else
+	{
+	  /* check the types of the struct and its elements */
+	  if ((dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY) ||
+	      (dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_STRING))
+	    {
+	      error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+					     "Expected inner array of strings");
+	      break;
+	    }
+	  
+	  /* string_iter points to each "s" element in the inner array */
+	  dbus_message_iter_recurse(&array_iter, &string_iter);
+	  if (dbus_message_iter_get_arg_type(&string_iter) != DBUS_TYPE_STRING)
+	    {
+	      /* no IP address given */
+	      error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+					     "Expected IP address");
+	      break;
+	    }
+	  
+	  dbus_message_iter_get_basic(&string_iter, &str);
+	  if (!str || !strlen (str))
+	    {
+	      error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+					     "Empty IP address");
+	      break;
+	    }
+	  
+	  /* dup the string because it gets modified during parsing */
+	  if (dup)
+	    free(dup);
+	  if (!(dup = str_addr = whine_malloc(strlen(str)+1)))
+	    break;
+	  
+	  strcpy(str_addr, str);
+	}
+
+      memset(&addr, 0, sizeof(addr));
+      memset(&source_addr, 0, sizeof(source_addr));
+      memset(&interface, 0, sizeof(interface));
+
+      /* parse the IP address */
+      if ((addr_err = parse_server(str_addr, &addr, &source_addr, (char *) &interface, &flags)))
+	{
+          error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
+                                                "Invalid IP address '%s': %s",
+                                                str, addr_err);
+          break;
+        }
+      
+      /* 0.0.0.0 for server address == NULL, for Dbus */
+      if (addr.in.sin_family == AF_INET &&
+          addr.in.sin_addr.s_addr == 0)
+        flags |= SERV_NO_ADDR;
+      
+      if (strings)
+	{
+	  char *p;
+	  
+	  do {
+	    if (str_domain)
+	      {
+		if ((p = strchr(str_domain, '/')))
+		  *p++ = 0;
+	      }
+	    else 
+	      p = NULL;
+	    
+	    add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain);
+	  } while ((str_domain = p));
+	}
+      else
+	{
+	  /* jump past the address to the domain list (if any) */
+	  dbus_message_iter_next (&string_iter);
+	  
+	  /* parse domains and add each server/domain pair to the list */
+	  do {
+	    str = NULL;
+	    if (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING)
+	      dbus_message_iter_get_basic(&string_iter, &str);
+	    dbus_message_iter_next (&string_iter);
+	    
+	    add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str);
+	  } while (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING);
+	}
+	 
+      /* jump to next element in outer array */
+      dbus_message_iter_next(&array_iter);
+    }
+
+  cleanup_servers();
+
+  if (dup)
+    free(dup);
+
+  return error;
+}
+
+static DBusMessage *dbus_set_bool(DBusMessage *message, int flag, char *name)
+{
+  DBusMessageIter iter;
+  dbus_bool_t enabled;
+
+  if (!dbus_message_iter_init(message, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
+    return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, "Expected boolean argument");
+  
+  dbus_message_iter_get_basic(&iter, &enabled);
+
+  if (enabled)
+    { 
+      my_syslog(LOG_INFO, _("Enabling --%s option from D-Bus"), name);
+      set_option_bool(flag);
+    }
+  else
+    {
+      my_syslog(LOG_INFO, _("Disabling --%s option from D-Bus"), name);
+      reset_option_bool(flag);
+    }
+
+  return NULL;
+}
+
+#ifdef HAVE_DHCP
+static DBusMessage *dbus_add_lease(DBusMessage* message)
+{
+  struct dhcp_lease *lease;
+  const char *ipaddr, *hwaddr, *hostname, *tmp;
+  const unsigned char* clid;
+  int clid_len, hostname_len, hw_len, hw_type;
+  dbus_uint32_t expires, ia_id;
+  dbus_bool_t is_temporary;
+  struct all_addr addr;
+  time_t now = dnsmasq_time();
+  unsigned char dhcp_chaddr[DHCP_CHADDR_MAX];
+
+  DBusMessageIter iter, array_iter;
+  if (!dbus_message_iter_init(message, &iter))
+    return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+				  "Failed to initialize dbus message iter");
+
+  if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+    return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+				  "Expected string as first argument");
+
+  dbus_message_iter_get_basic(&iter, &ipaddr);
+  dbus_message_iter_next(&iter);
+
+  if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+    return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+				  "Expected string as second argument");
+    
+  dbus_message_iter_get_basic(&iter, &hwaddr);
+  dbus_message_iter_next(&iter);
+
+  if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
+      (dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE))
+    return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+				  "Expected byte array as third argument");
+    
+  dbus_message_iter_recurse(&iter, &array_iter);
+  dbus_message_iter_get_fixed_array(&array_iter, &hostname, &hostname_len);
+  tmp = memchr(hostname, '\0', hostname_len);
+  if (tmp)
+    {
+      if (tmp == &hostname[hostname_len - 1])
+	hostname_len--;
+      else
+	return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+				      "Hostname contains an embedded NUL character");
+    }
+  dbus_message_iter_next(&iter);
+
+  if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
+      (dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE))
+    return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+				  "Expected byte array as fourth argument");
+
+  dbus_message_iter_recurse(&iter, &array_iter);
+  dbus_message_iter_get_fixed_array(&array_iter, &clid, &clid_len);
+  dbus_message_iter_next(&iter);
+
+  if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
+    return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+				  "Expected uint32 as fifth argument");
+    
+  dbus_message_iter_get_basic(&iter, &expires);
+  dbus_message_iter_next(&iter);
+
+  if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
+    return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                    "Expected uint32 as sixth argument");
+  
+  dbus_message_iter_get_basic(&iter, &ia_id);
+  dbus_message_iter_next(&iter);
+
+  if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
+    return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+				  "Expected uint32 as sixth argument");
+
+  dbus_message_iter_get_basic(&iter, &is_temporary);
+
+  if (inet_pton(AF_INET, ipaddr, &addr.addr.addr4))
+    {
+      if (ia_id != 0 || is_temporary)
+	return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+				      "ia_id and is_temporary must be zero for IPv4 lease");
+      
+      if (!(lease = lease_find_by_addr(addr.addr.addr4)))
+    	lease = lease4_allocate(addr.addr.addr4);
+    }
+#ifdef HAVE_DHCP6
+  else if (inet_pton(AF_INET6, ipaddr, &addr.addr.addr6))
+    {
+      if (!(lease = lease6_find_by_addr(&addr.addr.addr6, 128, 0)))
+	lease = lease6_allocate(&addr.addr.addr6,
+				is_temporary ? LEASE_TA : LEASE_NA);
+      lease_set_iaid(lease, ia_id);
+    }
+#endif
+  else
+    return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
+					 "Invalid IP address '%s'", ipaddr);
+   
+  hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL, &hw_type);
+  if (hw_type == 0 && hw_len != 0)
+    hw_type = ARPHRD_ETHER;
+  
+  lease_set_hwaddr(lease, dhcp_chaddr, clid, hw_len, hw_type,
+                   clid_len, now, 0);
+  lease_set_expires(lease, expires, now);
+  if (hostname_len != 0)
+    lease_set_hostname(lease, hostname, 0, get_domain(lease->addr), NULL);
+  
+  lease_update_file(now);
+  lease_update_dns(0);
+
+  return NULL;
+}
+
+static DBusMessage *dbus_del_lease(DBusMessage* message)
+{
+  struct dhcp_lease *lease;
+  DBusMessageIter iter;
+  const char *ipaddr;
+  DBusMessage *reply;
+  struct all_addr addr;
+  dbus_bool_t ret = 1;
+  time_t now = dnsmasq_time();
+
+  if (!dbus_message_iter_init(message, &iter))
+    return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+				  "Failed to initialize dbus message iter");
+   
+  if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+    return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+				  "Expected string as first argument");
+   
+  dbus_message_iter_get_basic(&iter, &ipaddr);
+
+  if (inet_pton(AF_INET, ipaddr, &addr.addr.addr4))
+    lease = lease_find_by_addr(addr.addr.addr4);
+#ifdef HAVE_DHCP6
+  else if (inet_pton(AF_INET6, ipaddr, &addr.addr.addr6))
+    lease = lease6_find_by_addr(&addr.addr.addr6, 128, 0);
+#endif
+  else
+    return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
+					 "Invalid IP address '%s'", ipaddr);
+    
+  if (lease)
+    {
+      lease_prune(lease, now);
+      lease_update_file(now);
+      lease_update_dns(0);
+    }
+  else
+    ret = 0;
+  
+  if ((reply = dbus_message_new_method_return(message)))
+    dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &ret,
+			     DBUS_TYPE_INVALID);
+  
+    
+  return reply;
+}
+#endif
+
+DBusHandlerResult message_handler(DBusConnection *connection, 
+				  DBusMessage *message, 
+				  void *user_data)
+{
+  char *method = (char *)dbus_message_get_member(message);
+  DBusMessage *reply = NULL;
+  int clear_cache = 0, new_servers = 0;
+    
+  if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
+    {
+      /* string length: "%s" provides space for termination zero */
+      if (!introspection_xml && 
+	  (introspection_xml = whine_malloc(strlen(introspection_xml_template) + strlen(daemon->dbus_name))))
+	sprintf(introspection_xml, introspection_xml_template, daemon->dbus_name);
+    
+      if (introspection_xml)
+	{
+	  reply = dbus_message_new_method_return(message);
+	  dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection_xml, DBUS_TYPE_INVALID);
+	}
+    }
+  else if (strcmp(method, "GetVersion") == 0)
+    {
+      char *v = VERSION;
+      reply = dbus_message_new_method_return(message);
+      
+      dbus_message_append_args(reply, DBUS_TYPE_STRING, &v, DBUS_TYPE_INVALID);
+    }
+#ifdef HAVE_LOOP
+  else if (strcmp(method, "GetLoopServers") == 0)
+    {
+      reply = dbus_reply_server_loop(message);
+    }
+#endif
+  else if (strcmp(method, "SetServers") == 0)
+    {
+      dbus_read_servers(message);
+      new_servers = 1;
+    }
+  else if (strcmp(method, "SetServersEx") == 0)
+    {
+      reply = dbus_read_servers_ex(message, 0);
+      new_servers = 1;
+    }
+  else if (strcmp(method, "SetDomainServers") == 0)
+    {
+      reply = dbus_read_servers_ex(message, 1);
+      new_servers = 1;
+    }
+  else if (strcmp(method, "SetFilterWin2KOption") == 0)
+    {
+      reply = dbus_set_bool(message, OPT_FILTER, "filterwin2k");
+    }
+  else if (strcmp(method, "SetBogusPrivOption") == 0)
+    {
+      reply = dbus_set_bool(message, OPT_BOGUSPRIV, "bogus-priv");
+    }
+#ifdef HAVE_DHCP
+  else if (strcmp(method, "AddDhcpLease") == 0)
+    {
+      reply = dbus_add_lease(message);
+    }
+  else if (strcmp(method, "DeleteDhcpLease") == 0)
+    {
+      reply = dbus_del_lease(message);
+    }
+#endif
+  else if (strcmp(method, "ClearCache") == 0)
+    clear_cache = 1;
+  else
+    return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+   
+  if (new_servers)
+    {
+      my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
+      check_servers();
+      if (option_bool(OPT_RELOAD))
+	clear_cache = 1;
+    }
+
+  if (clear_cache)
+    clear_cache_and_reload(dnsmasq_time());
+  
+  method = user_data; /* no warning */
+
+  /* If no reply or no error, return nothing */
+  if (!reply)
+    reply = dbus_message_new_method_return(message);
+
+  if (reply)
+    {
+      dbus_connection_send (connection, reply, NULL);
+      dbus_message_unref (reply);
+    }
+
+  return (DBUS_HANDLER_RESULT_HANDLED);
+}
+ 
+
+/* returns NULL or error message, may fail silently if dbus daemon not yet up. */
+char *dbus_init(void)
+{
+  DBusConnection *connection = NULL;
+  DBusObjectPathVTable dnsmasq_vtable = {NULL, &message_handler, NULL, NULL, NULL, NULL };
+  DBusError dbus_error;
+  DBusMessage *message;
+
+  dbus_error_init (&dbus_error);
+  if (!(connection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error)))
+    return NULL;
+    
+  dbus_connection_set_exit_on_disconnect(connection, FALSE);
+  dbus_connection_set_watch_functions(connection, add_watch, remove_watch, 
+				      NULL, NULL, NULL);
+  dbus_error_init (&dbus_error);
+  dbus_bus_request_name (connection, daemon->dbus_name, 0, &dbus_error);
+  if (dbus_error_is_set (&dbus_error))
+    return (char *)dbus_error.message;
+  
+  if (!dbus_connection_register_object_path(connection,  DNSMASQ_PATH, 
+					    &dnsmasq_vtable, NULL))
+    return _("could not register a DBus message handler");
+  
+  daemon->dbus = connection; 
+  
+  if ((message = dbus_message_new_signal(DNSMASQ_PATH, daemon->dbus_name, "Up")))
+    {
+      dbus_connection_send(connection, message, NULL);
+      dbus_message_unref(message);
+    }
+
+  return NULL;
+}
+ 
+
+void set_dbus_listeners(void)
+{
+  struct watch *w;
+  
+  for (w = daemon->watches; w; w = w->next)
+    if (dbus_watch_get_enabled(w->watch))
+      {
+	unsigned int flags = dbus_watch_get_flags(w->watch);
+	int fd = dbus_watch_get_unix_fd(w->watch);
+	
+	if (flags & DBUS_WATCH_READABLE)
+	  poll_listen(fd, POLLIN);
+	
+	if (flags & DBUS_WATCH_WRITABLE)
+	  poll_listen(fd, POLLOUT);
+	
+	poll_listen(fd, POLLERR);
+      }
+}
+
+void check_dbus_listeners()
+{
+  DBusConnection *connection = (DBusConnection *)daemon->dbus;
+  struct watch *w;
+
+  for (w = daemon->watches; w; w = w->next)
+    if (dbus_watch_get_enabled(w->watch))
+      {
+	unsigned int flags = 0;
+	int fd = dbus_watch_get_unix_fd(w->watch);
+	
+	if (poll_check(fd, POLLIN))
+	  flags |= DBUS_WATCH_READABLE;
+	
+	if (poll_check(fd, POLLOUT))
+	  flags |= DBUS_WATCH_WRITABLE;
+	
+	if (poll_check(fd, POLLERR))
+	  flags |= DBUS_WATCH_ERROR;
+
+	if (flags != 0)
+	  dbus_watch_handle(w->watch, flags);
+      }
+
+  if (connection)
+    {
+      dbus_connection_ref (connection);
+      while (dbus_connection_dispatch (connection) == DBUS_DISPATCH_DATA_REMAINS);
+      dbus_connection_unref (connection);
+    }
+}
+
+#ifdef HAVE_DHCP
+void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
+{
+  DBusConnection *connection = (DBusConnection *)daemon->dbus;
+  DBusMessage* message = NULL;
+  DBusMessageIter args;
+  char *action_str, *mac = daemon->namebuff;
+  unsigned char *p;
+  int i;
+
+  if (!connection)
+    return;
+  
+  if (!hostname)
+    hostname = "";
+  
+#ifdef HAVE_DHCP6
+   if (lease->flags & (LEASE_TA | LEASE_NA))
+     {
+       print_mac(mac, lease->clid, lease->clid_len);
+       inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN);
+     }
+   else
+#endif
+     {
+       p = extended_hwaddr(lease->hwaddr_type, lease->hwaddr_len,
+			   lease->hwaddr, lease->clid_len, lease->clid, &i);
+       print_mac(mac, p, i);
+       inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN);
+     }
+
+  if (action == ACTION_DEL)
+    action_str = "DhcpLeaseDeleted";
+  else if (action == ACTION_ADD)
+    action_str = "DhcpLeaseAdded";
+  else if (action == ACTION_OLD)
+    action_str = "DhcpLeaseUpdated";
+  else
+    return;
+
+  if (!(message = dbus_message_new_signal(DNSMASQ_PATH, daemon->dbus_name, action_str)))
+    return;
+  
+  dbus_message_iter_init_append(message, &args);
+  
+  if (dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &daemon->addrbuff) &&
+      dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &mac) &&
+      dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &hostname))
+    dbus_connection_send(connection, message, NULL);
+  
+  dbus_message_unref(message);
+}
+#endif
+
+#endif
diff --git a/src/dhcp-common.c b/src/dhcp-common.c
new file mode 100644
index 0000000..eae9ae3
--- /dev/null
+++ b/src/dhcp-common.c
@@ -0,0 +1,905 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_DHCP
+
+void dhcp_common_init(void)
+{
+  /* These each hold a DHCP option max size 255
+     and get a terminating zero added */
+  daemon->dhcp_buff = safe_malloc(DHCP_BUFF_SZ);
+  daemon->dhcp_buff2 = safe_malloc(DHCP_BUFF_SZ); 
+  daemon->dhcp_buff3 = safe_malloc(DHCP_BUFF_SZ);
+  
+  /* dhcp_packet is used by v4 and v6, outpacket only by v6 
+     sizeof(struct dhcp_packet) is as good an initial size as any,
+     even for v6 */
+  expand_buf(&daemon->dhcp_packet, sizeof(struct dhcp_packet));
+#ifdef HAVE_DHCP6
+  if (daemon->dhcp6)
+    expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
+#endif
+}
+
+ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
+{  
+  ssize_t sz;
+ 
+  while (1)
+    {
+      msg->msg_flags = 0;
+      while ((sz = recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
+      
+      if (sz == -1)
+	return -1;
+      
+      if (!(msg->msg_flags & MSG_TRUNC))
+	break;
+
+      /* Very new Linux kernels return the actual size needed, 
+	 older ones always return truncated size */
+      if ((size_t)sz == msg->msg_iov->iov_len)
+	{
+	  if (!expand_buf(msg->msg_iov, sz + 100))
+	    return -1;
+	}
+      else
+	{
+	  expand_buf(msg->msg_iov, sz);
+	  break;
+	}
+    }
+  
+  while ((sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
+  
+  return (msg->msg_flags & MSG_TRUNC) ? -1 : sz;
+}
+
+struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
+{
+  struct tag_if *exprs;
+  struct dhcp_netid_list *list;
+
+  for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
+    if (match_netid(exprs->tag, tags, 1))
+      for (list = exprs->set; list; list = list->next)
+	{
+	  list->list->next = tags;
+	  tags = list->list;
+	}
+
+  return tags;
+}
+
+
+struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *context_tags, struct dhcp_opt *opts)
+{
+  struct dhcp_netid *tagif = run_tag_if(tags);
+  struct dhcp_opt *opt;
+  struct dhcp_opt *tmp;  
+
+  /* flag options which are valid with the current tag set (sans context tags) */
+  for (opt = opts; opt; opt = opt->next)
+    {
+      opt->flags &= ~DHOPT_TAGOK;
+      if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
+	  match_netid(opt->netid, tagif, 0))
+	opt->flags |= DHOPT_TAGOK;
+    }
+
+  /* now flag options which are valid, including the context tags,
+     otherwise valid options are inhibited if we found a higher priority one above */
+  if (context_tags)
+    {
+      struct dhcp_netid *last_tag;
+
+      for (last_tag = context_tags; last_tag->next; last_tag = last_tag->next);
+      last_tag->next = tags;
+      tagif = run_tag_if(context_tags);
+      
+      /* reset stuff with tag:!<tag> which now matches. */
+      for (opt = opts; opt; opt = opt->next)
+	if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
+	    (opt->flags & DHOPT_TAGOK) &&
+	    !match_netid(opt->netid, tagif, 0))
+	  opt->flags &= ~DHOPT_TAGOK;
+
+      for (opt = opts; opt; opt = opt->next)
+	if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) &&
+	    match_netid(opt->netid, tagif, 0))
+	  {
+	    struct dhcp_opt *tmp;  
+	    for (tmp = opts; tmp; tmp = tmp->next) 
+	      if (tmp->opt == opt->opt && opt->netid && (tmp->flags & DHOPT_TAGOK))
+		break;
+	    if (!tmp)
+	      opt->flags |= DHOPT_TAGOK;
+	  }      
+    }
+  
+  /* now flag untagged options which are not overridden by tagged ones */
+  for (opt = opts; opt; opt = opt->next)
+    if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
+      {
+	for (tmp = opts; tmp; tmp = tmp->next) 
+	  if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
+	    break;
+	if (!tmp)
+	  opt->flags |= DHOPT_TAGOK;
+	else if (!tmp->netid)
+	  my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt); 
+      }
+
+  /* Finally, eliminate duplicate options later in the chain, and therefore earlier in the config file. */
+  for (opt = opts; opt; opt = opt->next)
+    if (opt->flags & DHOPT_TAGOK)
+      for (tmp = opt->next; tmp; tmp = tmp->next) 
+	if (tmp->opt == opt->opt)
+	  tmp->flags &= ~DHOPT_TAGOK;
+  
+  return tagif;
+}
+	
+/* Is every member of check matched by a member of pool? 
+   If tagnotneeded, untagged is OK */
+int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded)
+{
+  struct dhcp_netid *tmp1;
+  
+  if (!check && !tagnotneeded)
+    return 0;
+
+  for (; check; check = check->next)
+    {
+      /* '#' for not is for backwards compat. */
+      if (check->net[0] != '!' && check->net[0] != '#')
+	{
+	  for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
+	    if (strcmp(check->net, tmp1->net) == 0)
+	      break;
+	  if (!tmp1)
+	    return 0;
+	}
+      else
+	for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
+	  if (strcmp((check->net)+1, tmp1->net) == 0)
+	    return 0;
+    }
+  return 1;
+}
+
+/* return domain or NULL if none. */
+char *strip_hostname(char *hostname)
+{
+  char *dot = strchr(hostname, '.');
+ 
+  if (!dot)
+    return NULL;
+  
+  *dot = 0; /* truncate */
+  if (strlen(dot+1) != 0)
+    return dot+1;
+  
+  return NULL;
+}
+
+void log_tags(struct dhcp_netid *netid, u32 xid)
+{
+  if (netid && option_bool(OPT_LOG_OPTS))
+    {
+      char *s = daemon->namebuff;
+      for (*s = 0; netid; netid = netid->next)
+	{
+	  /* kill dupes. */
+	  struct dhcp_netid *n;
+	  
+	  for (n = netid->next; n; n = n->next)
+	    if (strcmp(netid->net, n->net) == 0)
+	      break;
+	  
+	  if (!n)
+	    {
+	      strncat (s, netid->net, (MAXDNAME-1) - strlen(s));
+	      if (netid->next)
+		strncat (s, ", ", (MAXDNAME-1) - strlen(s));
+	    }
+	}
+      my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), xid, s);
+    } 
+}   
+  
+int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
+{
+  int i;
+  
+  if (o->len > len)
+    return 0;
+  
+  if (o->len == 0)
+    return 1;
+     
+  if (o->flags & DHOPT_HEX)
+    { 
+      if (memcmp_masked(o->val, p, o->len, o->u.wildcard_mask))
+	return 1;
+    }
+  else 
+    for (i = 0; i <= (len - o->len); ) 
+      {
+	if (memcmp(o->val, p + i, o->len) == 0)
+	  return 1;
+	    
+	if (o->flags & DHOPT_STRING)
+	  i++;
+	else
+	  i += o->len;
+      }
+  
+  return 0;
+}
+
+int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
+{
+  struct hwaddr_config *conf_addr;
+  
+  for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
+    if (conf_addr->wildcard_mask == 0 &&
+	conf_addr->hwaddr_len == len &&
+	(conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
+	memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
+      return 1;
+  
+  return 0;
+}
+
+static int is_config_in_context(struct dhcp_context *context, struct dhcp_config *config)
+{
+  if (!context) /* called via find_config() from lease_update_from_configs() */
+    return 1; 
+
+  if (!(config->flags & (CONFIG_ADDR | CONFIG_ADDR6)))
+    return 1;
+  
+#ifdef HAVE_DHCP6
+  if ((context->flags & CONTEXT_V6) && (config->flags & CONFIG_WILDCARD))
+    return 1;
+#endif
+
+  for (; context; context = context->current)
+#ifdef HAVE_DHCP6
+    if (context->flags & CONTEXT_V6) 
+      {
+	if ((config->flags & CONFIG_ADDR6) && is_same_net6(&config->addr6, &context->start6, context->prefix))
+	  return 1;
+      }
+    else 
+#endif
+      if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask))
+	return 1;
+
+  return 0;
+}
+
+struct dhcp_config *find_config(struct dhcp_config *configs,
+				struct dhcp_context *context,
+				unsigned char *clid, int clid_len,
+				unsigned char *hwaddr, int hw_len, 
+				int hw_type, char *hostname)
+{
+  int count, new;
+  struct dhcp_config *config, *candidate; 
+  struct hwaddr_config *conf_addr;
+
+  if (clid)
+    for (config = configs; config; config = config->next)
+      if (config->flags & CONFIG_CLID)
+	{
+	  if (config->clid_len == clid_len && 
+	      memcmp(config->clid, clid, clid_len) == 0 &&
+	      is_config_in_context(context, config))
+	    return config;
+	  
+	  /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
+	     cope with that here. This is IPv4 only. context==NULL implies IPv4, 
+	     see lease_update_from_configs() */
+	  if ((!context || !(context->flags & CONTEXT_V6)) && *clid == 0 && config->clid_len == clid_len-1  &&
+	      memcmp(config->clid, clid+1, clid_len-1) == 0 &&
+	      is_config_in_context(context, config))
+	    return config;
+	}
+  
+
+  if (hwaddr)
+    for (config = configs; config; config = config->next)
+      if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
+	  is_config_in_context(context, config))
+	return config;
+  
+  if (hostname && context)
+    for (config = configs; config; config = config->next)
+      if ((config->flags & CONFIG_NAME) && 
+	  hostname_isequal(config->hostname, hostname) &&
+	  is_config_in_context(context, config))
+	return config;
+
+  
+  if (!hwaddr)
+    return NULL;
+
+  /* use match with fewest wildcard octets */
+  for (candidate = NULL, count = 0, config = configs; config; config = config->next)
+    if (is_config_in_context(context, config))
+      for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
+	if (conf_addr->wildcard_mask != 0 &&
+	    conf_addr->hwaddr_len == hw_len &&	
+	    (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
+	    (new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
+	  {
+	      count = new;
+	      candidate = config;
+	  }
+  
+  return candidate;
+}
+
+void dhcp_update_configs(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. 
+     We take care to maintain the invariant that any IP address can appear
+     in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP, 
+     restore the status-quo ante first. */
+  
+  struct dhcp_config *config, *conf_tmp;
+  struct crec *crec;
+  int prot = AF_INET;
+
+  for (config = configs; config; config = config->next)
+    if (config->flags & CONFIG_ADDR_HOSTS)
+      config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR6 | CONFIG_ADDR_HOSTS);
+
+#ifdef HAVE_DHCP6 
+ again:  
+#endif
+
+  if (daemon->port != 0)
+    for (config = configs; config; config = config->next)
+      {
+	int conflags = CONFIG_ADDR;
+	int cacheflags = F_IPV4;
+
+#ifdef HAVE_DHCP6
+	if (prot == AF_INET6)
+	  {
+	    conflags = CONFIG_ADDR6;
+	    cacheflags = F_IPV6;
+	  }
+#endif
+	if (!(config->flags & conflags) &&
+	    (config->flags & CONFIG_NAME) && 
+	    (crec = cache_find_by_name(NULL, config->hostname, 0, cacheflags)) &&
+	    (crec->flags & F_HOSTS))
+	  {
+	    if (cache_find_by_name(crec, config->hostname, 0, cacheflags))
+	      {
+		/* use primary (first) address */
+		while (crec && !(crec->flags & F_REVERSE))
+		  crec = cache_find_by_name(crec, config->hostname, 0, cacheflags);
+		if (!crec)
+		  continue; /* should be never */
+		inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
+		my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"), 
+			  config->hostname, daemon->addrbuff);
+	      }
+	    
+	    if (prot == AF_INET && 
+		(!(conf_tmp = config_find_by_address(configs, crec->addr.addr.addr.addr4)) || conf_tmp == config))
+	      {
+		config->addr = crec->addr.addr.addr.addr4;
+		config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
+		continue;
+	      }
+
+#ifdef HAVE_DHCP6
+	    if (prot == AF_INET6 && 
+		(!(conf_tmp = config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0)) || conf_tmp == config))
+	      {
+		memcpy(&config->addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ);
+		config->flags |= CONFIG_ADDR6 | CONFIG_ADDR_HOSTS;
+		continue;
+	      }
+#endif
+
+	    inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
+	    my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"), 
+		      daemon->addrbuff, config->hostname);
+	    
+	    
+	  }
+      }
+
+#ifdef HAVE_DHCP6
+  if (prot == AF_INET)
+    {
+      prot = AF_INET6;
+      goto again;
+    }
+#endif
+
+}
+
+#ifdef HAVE_LINUX_NETWORK 
+char *whichdevice(void)
+{
+  /* If we are doing DHCP on exactly one interface, and running linux, do SO_BINDTODEVICE
+     to that device. This is for the use case of  (eg) OpenStack, which runs a new
+     dnsmasq instance for each VLAN interface it creates. Without the BINDTODEVICE, 
+     individual processes don't always see the packets they should.
+     SO_BINDTODEVICE is only available Linux. 
+
+     Note that if wildcards are used in --interface, or --interface is not used at all,
+     or a configured interface doesn't yet exist, then more interfaces may arrive later, 
+     so we can't safely assert there is only one interface and proceed.
+*/
+  
+  struct irec *iface, *found;
+  struct iname *if_tmp;
+  
+  if (!daemon->if_names)
+    return NULL;
+  
+  for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
+    if (if_tmp->name && (!if_tmp->used || strchr(if_tmp->name, '*')))
+      return NULL;
+
+  for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
+    if (iface->dhcp_ok)
+      {
+	if (!found)
+	  found = iface;
+	else if (strcmp(found->name, iface->name) != 0) 
+	  return NULL; /* more than one. */
+      }
+
+  if (found)
+    return found->name;
+
+  return NULL;
+}
+ 
+void  bindtodevice(char *device, int fd)
+{
+  struct ifreq ifr;
+  
+  strcpy(ifr.ifr_name, device);
+  /* only allowed by root. */
+  if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 &&
+      errno != EPERM)
+    die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
+}
+#endif
+
+static const struct opttab_t {
+  char *name;
+  u16 val, size;
+} opttab[] = {
+  { "netmask", 1, OT_ADDR_LIST },
+  { "time-offset", 2, 4 },
+  { "router", 3, OT_ADDR_LIST  },
+  { "dns-server", 6, OT_ADDR_LIST },
+  { "log-server", 7, OT_ADDR_LIST },
+  { "lpr-server", 9, OT_ADDR_LIST },
+  { "hostname", 12, OT_INTERNAL | OT_NAME },
+  { "boot-file-size", 13, 2 | OT_DEC },
+  { "domain-name", 15, OT_NAME },
+  { "swap-server", 16, OT_ADDR_LIST },
+  { "root-path", 17, OT_NAME },
+  { "extension-path", 18, OT_NAME },
+  { "ip-forward-enable", 19, 1 },
+  { "non-local-source-routing", 20, 1 },
+  { "policy-filter", 21, OT_ADDR_LIST },
+  { "max-datagram-reassembly", 22, 2 | OT_DEC },
+  { "default-ttl", 23, 1 | OT_DEC },
+  { "mtu", 26, 2 | OT_DEC },
+  { "all-subnets-local", 27, 1 },
+  { "broadcast", 28, OT_INTERNAL | OT_ADDR_LIST },
+  { "router-discovery", 31, 1 },
+  { "router-solicitation", 32, OT_ADDR_LIST },
+  { "static-route", 33, OT_ADDR_LIST },
+  { "trailer-encapsulation", 34, 1 },
+  { "arp-timeout", 35, 4 | OT_DEC },
+  { "ethernet-encap", 36, 1 },
+  { "tcp-ttl", 37, 1 },
+  { "tcp-keepalive", 38, 4 | OT_DEC },
+  { "nis-domain", 40, OT_NAME },
+  { "nis-server", 41, OT_ADDR_LIST },
+  { "ntp-server", 42, OT_ADDR_LIST },
+  { "vendor-encap", 43, OT_INTERNAL },
+  { "netbios-ns", 44, OT_ADDR_LIST },
+  { "netbios-dd", 45, OT_ADDR_LIST },
+  { "netbios-nodetype", 46, 1 },
+  { "netbios-scope", 47, 0 },
+  { "x-windows-fs", 48, OT_ADDR_LIST },
+  { "x-windows-dm", 49, OT_ADDR_LIST },
+  { "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
+  { "lease-time", 51, OT_INTERNAL | OT_TIME },
+  { "option-overload", 52, OT_INTERNAL },
+  { "message-type", 53, OT_INTERNAL | OT_DEC },
+  { "server-identifier", 54, OT_INTERNAL | OT_ADDR_LIST },
+  { "parameter-request", 55, OT_INTERNAL },
+  { "message", 56, OT_INTERNAL },
+  { "max-message-size", 57, OT_INTERNAL },
+  { "T1", 58, OT_TIME},
+  { "T2", 59, OT_TIME},
+  { "vendor-class", 60, 0 },
+  { "client-id", 61, OT_INTERNAL },
+  { "nis+-domain", 64, OT_NAME },
+  { "nis+-server", 65, OT_ADDR_LIST },
+  { "tftp-server", 66, OT_NAME },
+  { "bootfile-name", 67, OT_NAME },
+  { "mobile-ip-home", 68, OT_ADDR_LIST }, 
+  { "smtp-server", 69, OT_ADDR_LIST }, 
+  { "pop3-server", 70, OT_ADDR_LIST }, 
+  { "nntp-server", 71, OT_ADDR_LIST }, 
+  { "irc-server", 74, OT_ADDR_LIST }, 
+  { "user-class", 77, 0 },
+  { "FQDN", 81, OT_INTERNAL },
+  { "agent-id", 82, OT_INTERNAL },
+  { "client-arch", 93, 2 | OT_DEC },
+  { "client-interface-id", 94, 0 },
+  { "client-machine-id", 97, 0 },
+  { "subnet-select", 118, OT_INTERNAL },
+  { "domain-search", 119, OT_RFC1035_NAME },
+  { "sip-server", 120, 0 },
+  { "classless-static-route", 121, 0 },
+  { "vendor-id-encap", 125, 0 },
+  { "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
+  { NULL, 0, 0 }
+};
+
+#ifdef HAVE_DHCP6
+static const struct opttab_t opttab6[] = {
+  { "client-id", 1, OT_INTERNAL },
+  { "server-id", 2, OT_INTERNAL },
+  { "ia-na", 3, OT_INTERNAL },
+  { "ia-ta", 4, OT_INTERNAL },
+  { "iaaddr", 5, OT_INTERNAL },
+  { "oro", 6, OT_INTERNAL },
+  { "preference", 7, OT_INTERNAL | OT_DEC },
+  { "unicast", 12, OT_INTERNAL },
+  { "status", 13, OT_INTERNAL },
+  { "rapid-commit", 14, OT_INTERNAL },
+  { "user-class", 15, OT_INTERNAL | OT_CSTRING },
+  { "vendor-class", 16, OT_INTERNAL | OT_CSTRING },
+  { "vendor-opts", 17, OT_INTERNAL },
+  { "sip-server-domain", 21,  OT_RFC1035_NAME },
+  { "sip-server", 22, OT_ADDR_LIST },
+  { "dns-server", 23, OT_ADDR_LIST },
+  { "domain-search", 24, OT_RFC1035_NAME },
+  { "nis-server", 27, OT_ADDR_LIST },
+  { "nis+-server", 28, OT_ADDR_LIST },
+  { "nis-domain", 29,  OT_RFC1035_NAME },
+  { "nis+-domain", 30, OT_RFC1035_NAME },
+  { "sntp-server", 31,  OT_ADDR_LIST },
+  { "information-refresh-time", 32, OT_TIME },
+  { "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
+  { "ntp-server", 56,  0 },
+  { "bootfile-url", 59, OT_NAME },
+  { "bootfile-param", 60, OT_CSTRING },
+  { NULL, 0, 0 }
+};
+#endif
+
+
+
+void display_opts(void)
+{
+  int i;
+  
+  printf(_("Known DHCP options:\n"));
+  
+  for (i = 0; opttab[i].name; i++)
+    if (!(opttab[i].size & OT_INTERNAL))
+      printf("%3d %s\n", opttab[i].val, opttab[i].name);
+}
+
+#ifdef HAVE_DHCP6
+void display_opts6(void)
+{
+  int i;
+  printf(_("Known DHCPv6 options:\n"));
+  
+  for (i = 0; opttab6[i].name; i++)
+    if (!(opttab6[i].size & OT_INTERNAL))
+      printf("%3d %s\n", opttab6[i].val, opttab6[i].name);
+}
+#endif
+
+int lookup_dhcp_opt(int prot, char *name)
+{
+  const struct opttab_t *t;
+  int i;
+
+  (void)prot;
+
+#ifdef HAVE_DHCP6
+  if (prot == AF_INET6)
+    t = opttab6;
+  else
+#endif
+    t = opttab;
+
+  for (i = 0; t[i].name; i++)
+    if (strcasecmp(t[i].name, name) == 0)
+      return t[i].val;
+  
+  return -1;
+}
+
+int lookup_dhcp_len(int prot, int val)
+{
+  const struct opttab_t *t;
+  int i;
+
+  (void)prot;
+
+#ifdef HAVE_DHCP6
+  if (prot == AF_INET6)
+    t = opttab6;
+  else
+#endif
+    t = opttab;
+
+  for (i = 0; t[i].name; i++)
+    if (val == t[i].val)
+      return t[i].size & ~OT_DEC;
+
+   return 0;
+}
+
+char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
+{
+  int o, i, j, nodecode = 0;
+  const struct opttab_t *ot = opttab;
+
+#ifdef HAVE_DHCP6
+  if (prot == AF_INET6)
+    ot = opttab6;
+#endif
+
+  for (o = 0; ot[o].name; o++)
+    if (ot[o].val == opt)
+      {
+	if (buf)
+	  {
+	    memset(buf, 0, buf_len);
+	    
+	    if (ot[o].size & OT_ADDR_LIST) 
+	      {
+		struct all_addr addr;
+		int addr_len = INADDRSZ;
+
+#ifdef HAVE_DHCP6
+		if (prot == AF_INET6)
+		  addr_len = IN6ADDRSZ;
+#endif
+		for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len) 
+		  {
+		    if (i != 0)
+		      strncat(buf, ", ", buf_len - strlen(buf));
+		    /* align */
+		    memcpy(&addr, &val[i], addr_len); 
+		    inet_ntop(prot, &val[i], daemon->addrbuff, ADDRSTRLEN);
+		    strncat(buf, daemon->addrbuff, buf_len - strlen(buf));
+		  }
+	      }
+	    else if (ot[o].size & OT_NAME)
+		for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
+		  {
+		    char c = val[i];
+		    if (isprint((int)c))
+		      buf[j++] = c;
+		  }
+#ifdef HAVE_DHCP6
+	    /* We don't handle compressed rfc1035 names, so no good in IPv4 land */
+	    else if ((ot[o].size & OT_RFC1035_NAME) && prot == AF_INET6)
+	      {
+		i = 0, j = 0;
+		while (i < opt_len && val[i] != 0)
+		  {
+		    int k, l = i + val[i] + 1;
+		    for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++)
+		     {
+		       char c = val[k];
+		       if (isprint((int)c))
+			 buf[j++] = c;
+		     }
+		    i = l;
+		    if (val[i] != 0 && j < buf_len)
+		      buf[j++] = '.';
+		  }
+	      }
+	    else if ((ot[o].size & OT_CSTRING))
+	      {
+		int k, len;
+		unsigned char *p;
+
+		i = 0, j = 0;
+		while (1)
+		  {
+		    p = &val[i];
+		    GETSHORT(len, p);
+		    for (k = 0; k < len && j < buf_len; k++)
+		      {
+		       char c = *p++;
+		       if (isprint((int)c))
+			 buf[j++] = c;
+		     }
+		    i += len +2;
+		    if (i >= opt_len)
+		      break;
+
+		    if (j < buf_len)
+		      buf[j++] = ',';
+		  }
+	      }	      
+#endif
+	    else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
+	      {
+		unsigned int dec = 0;
+		
+		for (i = 0; i < opt_len; i++)
+		  dec = (dec << 8) | val[i]; 
+
+		if (ot[o].size & OT_TIME)
+		  prettyprint_time(buf, dec);
+		else
+		  sprintf(buf, "%u", dec);
+	      }
+	    else
+	      nodecode = 1;
+	  }
+	break;
+      }
+
+  if (opt_len != 0 && buf && (!ot[o].name || nodecode))
+    {
+      int trunc  = 0;
+      if (opt_len > 14)
+	{
+	  trunc = 1;
+	  opt_len = 14;
+	}
+      print_mac(buf, val, opt_len);
+      if (trunc)
+	strncat(buf, "...", buf_len - strlen(buf));
+    
+
+    }
+
+  return ot[o].name ? ot[o].name : "";
+
+}
+
+void log_context(int family, struct dhcp_context *context)
+{
+  /* Cannot use dhcp_buff* for RA contexts */
+
+  void *start = &context->start;
+  void *end = &context->end;
+  char *template = "", *p = daemon->namebuff;
+  
+  *p = 0;
+    
+#ifdef HAVE_DHCP6
+  if (family == AF_INET6)
+    {
+      struct in6_addr subnet = context->start6;
+      if (!(context->flags & CONTEXT_TEMPLATE))
+	setaddr6part(&subnet, 0);
+      inet_ntop(AF_INET6, &subnet, daemon->addrbuff, ADDRSTRLEN); 
+      start = &context->start6;
+      end = &context->end6;
+    }
+#endif
+
+  if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
+    strcpy(daemon->namebuff, _(", prefix deprecated"));
+  else
+    {
+      p += sprintf(p, _(", lease time "));
+      prettyprint_time(p, context->lease_time);
+      p += strlen(p);
+    }	
+
+#ifdef HAVE_DHCP6
+  if (context->flags & CONTEXT_CONSTRUCTED)
+    {
+      char ifrn_name[IFNAMSIZ];
+      
+      template = p;
+      p += sprintf(p, ", ");
+      
+      if (indextoname(daemon->icmp6fd, context->if_index, ifrn_name))
+	sprintf(p, "%s for %s", (context->flags & CONTEXT_OLD) ? "old prefix" : "constructed", ifrn_name);
+    }
+  else if (context->flags & CONTEXT_TEMPLATE && !(context->flags & CONTEXT_RA_STATELESS))
+    {
+      template = p;
+      p += sprintf(p, ", ");
+      
+      sprintf(p, "template for %s", context->template_interface);  
+    }
+#endif
+     
+  if (!(context->flags & CONTEXT_OLD) &&
+      ((context->flags & CONTEXT_DHCP) || family == AF_INET)) 
+    {
+#ifdef HAVE_DHCP6
+      if (context->flags & CONTEXT_RA_STATELESS)
+	{
+	  if (context->flags & CONTEXT_TEMPLATE)
+	    strncpy(daemon->dhcp_buff, context->template_interface, DHCP_BUFF_SZ);
+	  else
+	    strcpy(daemon->dhcp_buff, daemon->addrbuff);
+	}
+      else 
+#endif
+	inet_ntop(family, start, daemon->dhcp_buff, DHCP_BUFF_SZ);
+      inet_ntop(family, end, daemon->dhcp_buff3, DHCP_BUFF_SZ);
+      my_syslog(MS_DHCP | LOG_INFO, 
+		(context->flags & CONTEXT_RA_STATELESS) ? 
+		_("%s stateless on %s%.0s%.0s%s") :
+		(context->flags & CONTEXT_STATIC) ? 
+		_("%s, static leases only on %.0s%s%s%.0s") :
+		(context->flags & CONTEXT_PROXY) ?
+		_("%s, proxy on subnet %.0s%s%.0s%.0s") :
+		_("%s, IP range %s -- %s%s%.0s"),
+		(family != AF_INET) ? "DHCPv6" : "DHCP",
+		daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
+    }
+  
+#ifdef HAVE_DHCP6
+  if (context->flags & CONTEXT_TEMPLATE)
+    {
+      strcpy(daemon->addrbuff, context->template_interface);
+      template = "";
+    }
+
+  if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
+    my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
+  
+  if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6)) 
+    my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
+#endif
+
+}
+
+void log_relay(int family, struct dhcp_relay *relay)
+{
+  inet_ntop(family, &relay->local, daemon->addrbuff, ADDRSTRLEN);
+  inet_ntop(family, &relay->server, daemon->namebuff, ADDRSTRLEN); 
+
+  if (relay->interface)
+    my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
+  else
+    my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s"), daemon->addrbuff, daemon->namebuff);
+}
+   
+#endif
diff --git a/src/dhcp-protocol.h b/src/dhcp-protocol.h
new file mode 100644
index 0000000..0786f87
--- /dev/null
+++ b/src/dhcp-protocol.h
@@ -0,0 +1,100 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#define DHCP_SERVER_PORT 67
+#define DHCP_CLIENT_PORT 68
+#define DHCP_SERVER_ALTPORT 1067
+#define DHCP_CLIENT_ALTPORT 1068
+#define PXE_PORT 4011
+
+/* These each hold a DHCP option max size 255
+   and get a terminating zero added */
+#define DHCP_BUFF_SZ 256
+
+#define BOOTREQUEST              1
+#define BOOTREPLY                2
+#define DHCP_COOKIE              0x63825363
+
+/* The Linux in-kernel DHCP client silently ignores any packet 
+   smaller than this. Sigh...........   */
+#define MIN_PACKETSZ             300
+
+#define OPTION_PAD               0
+#define OPTION_NETMASK           1
+#define OPTION_ROUTER            3
+#define OPTION_DNSSERVER         6
+#define OPTION_HOSTNAME          12
+#define OPTION_DOMAINNAME        15
+#define OPTION_BROADCAST         28
+#define OPTION_VENDOR_CLASS_OPT  43
+#define OPTION_REQUESTED_IP      50 
+#define OPTION_LEASE_TIME        51
+#define OPTION_OVERLOAD          52
+#define OPTION_MESSAGE_TYPE      53
+#define OPTION_SERVER_IDENTIFIER 54
+#define OPTION_REQUESTED_OPTIONS 55
+#define OPTION_MESSAGE           56
+#define OPTION_MAXMESSAGE        57
+#define OPTION_T1                58
+#define OPTION_T2                59
+#define OPTION_VENDOR_ID         60
+#define OPTION_CLIENT_ID         61
+#define OPTION_SNAME             66
+#define OPTION_FILENAME          67
+#define OPTION_USER_CLASS        77
+#define OPTION_CLIENT_FQDN       81
+#define OPTION_AGENT_ID          82
+#define OPTION_ARCH              93
+#define OPTION_PXE_UUID          97
+#define OPTION_SUBNET_SELECT     118
+#define OPTION_DOMAIN_SEARCH     119
+#define OPTION_SIP_SERVER        120
+#define OPTION_VENDOR_IDENT      124
+#define OPTION_VENDOR_IDENT_OPT  125
+#define OPTION_END               255
+
+#define SUBOPT_CIRCUIT_ID        1
+#define SUBOPT_REMOTE_ID         2
+#define SUBOPT_SUBNET_SELECT     5     /* RFC 3527 */
+#define SUBOPT_SUBSCR_ID         6     /* RFC 3393 */
+#define SUBOPT_SERVER_OR         11    /* RFC 5107 */
+
+#define SUBOPT_PXE_BOOT_ITEM     71    /* PXE standard */
+#define SUBOPT_PXE_DISCOVERY     6
+#define SUBOPT_PXE_SERVERS       8
+#define SUBOPT_PXE_MENU          9
+#define SUBOPT_PXE_MENU_PROMPT   10
+
+#define DHCPDISCOVER             1
+#define DHCPOFFER                2
+#define DHCPREQUEST              3
+#define DHCPDECLINE              4
+#define DHCPACK                  5
+#define DHCPNAK                  6
+#define DHCPRELEASE              7
+#define DHCPINFORM               8
+
+#define BRDBAND_FORUM_IANA       3561 /* Broadband forum IANA enterprise */
+
+#define DHCP_CHADDR_MAX 16
+
+struct dhcp_packet {
+  u8 op, htype, hlen, hops;
+  u32 xid;
+  u16 secs, flags;
+  struct in_addr ciaddr, yiaddr, siaddr, giaddr;
+  u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
+  u8 options[312];
+};
diff --git a/src/dhcp.c b/src/dhcp.c
new file mode 100755
index 0000000..9f50c59
--- /dev/null
+++ b/src/dhcp.c
@@ -0,0 +1,1080 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_DHCP
+
+struct iface_param {
+  struct dhcp_context *current;
+  struct dhcp_relay *relay;
+  struct in_addr relay_local;
+  int ind;
+};
+
+struct match_param {
+  int ind, matched;
+  struct in_addr netmask, broadcast, addr;
+};
+
+static int complete_context(struct in_addr local, int if_index, char *label,
+			    struct in_addr netmask, struct in_addr broadcast, void *vparam);
+static int check_listen_addrs(struct in_addr local, int if_index, char *label,
+			      struct in_addr netmask, struct in_addr broadcast, void *vparam);
+static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index);
+static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface);
+
+static int make_fd(int port)
+{
+  int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+  struct sockaddr_in saddr;
+  int oneopt = 1;
+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
+  int mtu = IP_PMTUDISC_DONT;
+#endif
+#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
+  int tos = IPTOS_CLASS_CS6;
+#endif
+
+  if (fd == -1)
+    die (_("cannot create DHCP socket: %s"), NULL, EC_BADNET);
+  
+  if (!fix_fd(fd) ||
+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
+      setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
+#endif
+#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
+      setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1 ||
+#endif
+#if defined(HAVE_LINUX_NETWORK)
+      setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
+#else
+      setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
+#endif
+      setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)  
+    die(_("failed to set options on DHCP socket: %s"), NULL, EC_BADNET);
+  
+  /* When bind-interfaces is set, there might be more than one dnsmasq
+     instance binding port 67. That's OK if they serve different networks.
+     Need to set REUSEADDR|REUSEPORT to make this possible.
+     Handle the case that REUSEPORT is defined, but the kernel doesn't 
+     support it. This handles the introduction of REUSEPORT on Linux. */
+  if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
+    {
+      int rc = 0;
+
+#ifdef SO_REUSEPORT
+      if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 && 
+	  errno == ENOPROTOOPT)
+	rc = 0;
+#endif
+      
+      if (rc != -1)
+	rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
+      
+      if (rc == -1)
+	die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
+    }
+  
+  memset(&saddr, 0, sizeof(saddr));
+  saddr.sin_family = AF_INET;
+  saddr.sin_port = htons(port);
+  saddr.sin_addr.s_addr = INADDR_ANY;
+#ifdef HAVE_SOCKADDR_SA_LEN
+  saddr.sin_len = sizeof(struct sockaddr_in);
+#endif
+
+  if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)))
+    die(_("failed to bind DHCP server socket: %s"), NULL, EC_BADNET);
+
+  return fd;
+}
+
+void dhcp_init(void)
+{
+#if defined(HAVE_BSD_NETWORK)
+  int oneopt = 1;
+#endif
+
+  daemon->dhcpfd = make_fd(daemon->dhcp_server_port);
+  if (daemon->enable_pxe)
+    daemon->pxefd = make_fd(PXE_PORT);
+  else
+    daemon->pxefd = -1;
+
+#if defined(HAVE_BSD_NETWORK)
+  /* When we're not using capabilities, we need to do this here before
+     we drop root. Also, set buffer size small, to avoid wasting
+     kernel buffers */
+  
+  if (option_bool(OPT_NO_PING))
+    daemon->dhcp_icmp_fd = -1;
+  else if ((daemon->dhcp_icmp_fd = make_icmp_sock()) == -1 ||
+	   setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1 )
+    die(_("cannot create ICMP raw socket: %s."), NULL, EC_BADNET);
+  
+  /* Make BPF raw send socket */
+  init_bpf();
+#endif  
+}
+
+void dhcp_packet(time_t now, int pxe_fd)
+{
+  int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
+  struct dhcp_packet *mess;
+  struct dhcp_context *context;
+  struct dhcp_relay *relay;
+  int is_relay_reply = 0;
+  struct iname *tmp;
+  struct ifreq ifr;
+  struct msghdr msg;
+  struct sockaddr_in dest;
+  struct cmsghdr *cmptr;
+  struct iovec iov;
+  ssize_t sz; 
+  int iface_index = 0, unicast_dest = 0, is_inform = 0, loopback = 0;
+  int rcvd_iface_index;
+  struct in_addr iface_addr;
+  struct iface_param parm;
+  time_t recvtime = now;
+#ifdef HAVE_LINUX_NETWORK
+  struct arpreq arp_req;
+  struct timeval tv;
+#endif
+  
+  union {
+    struct cmsghdr align; /* this ensures alignment */
+#if defined(HAVE_LINUX_NETWORK)
+    char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
+#elif defined(HAVE_SOLARIS_NETWORK)
+    char control[CMSG_SPACE(sizeof(unsigned int))];
+#elif defined(HAVE_BSD_NETWORK) 
+    char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
+#endif
+  } control_u;
+  struct dhcp_bridge *bridge, *alias;
+
+  msg.msg_controllen = sizeof(control_u);
+  msg.msg_control = control_u.control;
+  msg.msg_name = &dest;
+  msg.msg_namelen = sizeof(dest);
+  msg.msg_iov = &daemon->dhcp_packet;
+  msg.msg_iovlen = 1;
+  
+  if ((sz = recv_dhcp_packet(fd, &msg)) == -1 || 
+      (sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))) 
+    return;
+    
+  #if defined (HAVE_LINUX_NETWORK)
+  if (ioctl(fd, SIOCGSTAMP, &tv) == 0)
+    recvtime = tv.tv_sec;
+
+  if (msg.msg_controllen >= sizeof(struct cmsghdr))
+    for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
+      if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
+	{
+	  union {
+	    unsigned char *c;
+	    struct in_pktinfo *p;
+	  } p;
+	  p.c = CMSG_DATA(cmptr);
+	  iface_index = p.p->ipi_ifindex;
+	  if (p.p->ipi_addr.s_addr != INADDR_BROADCAST)
+	    unicast_dest = 1;
+	}
+
+#elif defined(HAVE_BSD_NETWORK) 
+  if (msg.msg_controllen >= sizeof(struct cmsghdr))
+    for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
+      if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
+        {
+	  union {
+            unsigned char *c;
+            struct sockaddr_dl *s;
+          } p;
+	  p.c = CMSG_DATA(cmptr);
+	  iface_index = p.s->sdl_index;
+	}
+  
+#elif defined(HAVE_SOLARIS_NETWORK) 
+  if (msg.msg_controllen >= sizeof(struct cmsghdr))
+    for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
+      if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
+	{
+	  union {
+	    unsigned char *c;
+	    unsigned int *i;
+	  } p;
+	  p.c = CMSG_DATA(cmptr);
+	  iface_index = *(p.i);
+	}
+#endif
+	
+  if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name) ||
+      ioctl(daemon->dhcpfd, SIOCGIFFLAGS, &ifr) != 0)
+    return;
+  
+  mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
+  loopback = !mess->giaddr.s_addr && (ifr.ifr_flags & IFF_LOOPBACK);
+  
+#ifdef HAVE_LINUX_NETWORK
+  /* ARP fiddling uses original interface even if we pretend to use a different one. */
+  strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
+#endif 
+
+  /* If the interface on which the DHCP request was received is an
+     alias of some other interface (as specified by the
+     --bridge-interface option), change ifr.ifr_name so that we look
+     for DHCP contexts associated with the aliased interface instead
+     of with the aliasing one. */
+  rcvd_iface_index = iface_index;
+  for (bridge = daemon->bridges; bridge; bridge = bridge->next)
+    {
+      for (alias = bridge->alias; alias; alias = alias->next)
+	if (wildcard_matchn(alias->iface, ifr.ifr_name, IF_NAMESIZE))
+	  {
+	    if (!(iface_index = if_nametoindex(bridge->iface)))
+	      {
+		my_syslog(MS_DHCP | LOG_WARNING,
+			  _("unknown interface %s in bridge-interface"),
+			  bridge->iface);
+		return;
+	      }
+	    else 
+	      {
+		strncpy(ifr.ifr_name,  bridge->iface, IF_NAMESIZE);
+		break;
+	      }
+	  }
+      
+      if (alias)
+	break;
+    }
+
+#ifdef MSG_BCAST
+  /* OpenBSD tells us when a packet was broadcast */
+  if (!(msg.msg_flags & MSG_BCAST))
+    unicast_dest = 1;
+#endif
+  
+  if ((relay = relay_reply4((struct dhcp_packet *)daemon->dhcp_packet.iov_base, ifr.ifr_name)))
+    {
+      /* Reply from server, using us as relay. */
+      rcvd_iface_index = relay->iface_index;
+      if (!indextoname(daemon->dhcpfd, rcvd_iface_index, ifr.ifr_name))
+	return;
+      is_relay_reply = 1; 
+      iov.iov_len = sz;
+#ifdef HAVE_LINUX_NETWORK
+      strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
+#endif 
+    }
+  else
+    {
+      ifr.ifr_addr.sa_family = AF_INET;
+      if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
+	iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
+      else
+	{
+	  if (iface_check(AF_INET, NULL, ifr.ifr_name, NULL))
+	    my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
+	  return;
+	}
+      
+      for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
+	if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
+	  return;
+      
+      /* unlinked contexts/relays are marked by context->current == context */
+      for (context = daemon->dhcp; context; context = context->next)
+	context->current = context;
+      
+      for (relay = daemon->relay4; relay; relay = relay->next)
+	relay->current = relay;
+      
+      parm.current = NULL;
+      parm.relay = NULL;
+      parm.relay_local.s_addr = 0;
+      parm.ind = iface_index;
+      
+      if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name, NULL))
+	{
+	  /* If we failed to match the primary address of the interface, see if we've got a --listen-address
+	     for a secondary */
+	  struct match_param match;
+	  
+	  match.matched = 0;
+	  match.ind = iface_index;
+	  
+	  if (!daemon->if_addrs ||
+	      !iface_enumerate(AF_INET, &match, check_listen_addrs) ||
+	      !match.matched)
+	    return;
+	  
+	  iface_addr = match.addr;
+	  /* make sure secondary address gets priority in case
+	     there is more than one address on the interface in the same subnet */
+	  complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
+	}    
+      
+      if (!iface_enumerate(AF_INET, &parm, complete_context))
+	return;
+
+      /* We're relaying this request */
+      if  (parm.relay_local.s_addr != 0 &&
+	   relay_upstream4(parm.relay, mess, (size_t)sz, iface_index))
+	return;
+
+      /* May have configured relay, but not DHCP server */
+      if (!daemon->dhcp)
+	return;
+
+      lease_prune(NULL, now); /* lose any expired leases */
+      iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz, 
+			       now, unicast_dest, loopback, &is_inform, pxe_fd, iface_addr, recvtime);
+      lease_update_file(now);
+      lease_update_dns(0);
+      
+      if (iov.iov_len == 0)
+	return;
+    }
+
+  msg.msg_name = &dest;
+  msg.msg_namelen = sizeof(dest);
+  msg.msg_control = NULL;
+  msg.msg_controllen = 0;
+  msg.msg_iov = &iov;
+  iov.iov_base = daemon->dhcp_packet.iov_base;
+  
+  /* packet buffer may have moved */
+  mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
+  
+#ifdef HAVE_SOCKADDR_SA_LEN
+  dest.sin_len = sizeof(struct sockaddr_in);
+#endif
+  
+  if (pxe_fd)
+    { 
+      if (mess->ciaddr.s_addr != 0)
+	dest.sin_addr = mess->ciaddr;
+    }
+  else if (mess->giaddr.s_addr && !is_relay_reply)
+    {
+      /* Send to BOOTP relay  */
+      dest.sin_port = htons(daemon->dhcp_server_port);
+      dest.sin_addr = mess->giaddr; 
+    }
+  else if (mess->ciaddr.s_addr)
+    {
+      /* If the client's idea of its own address tallys with
+	 the source address in the request packet, we believe the
+	 source port too, and send back to that.  If we're replying 
+	 to a DHCPINFORM, trust the source address always. */
+      if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
+	  dest.sin_port == 0 || dest.sin_addr.s_addr == 0 || is_relay_reply)
+	{
+	  dest.sin_port = htons(daemon->dhcp_client_port); 
+	  dest.sin_addr = mess->ciaddr;
+	}
+    } 
+#if defined(HAVE_LINUX_NETWORK)
+  else
+    {
+      /* fill cmsg for outbound interface (both broadcast & unicast) */
+      struct in_pktinfo *pkt;
+      msg.msg_control = control_u.control;
+      msg.msg_controllen = sizeof(control_u);
+      cmptr = CMSG_FIRSTHDR(&msg);
+      pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
+      pkt->ipi_ifindex = rcvd_iface_index;
+      pkt->ipi_spec_dst.s_addr = 0;
+      msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+      cmptr->cmsg_level = IPPROTO_IP;
+      cmptr->cmsg_type = IP_PKTINFO;
+
+      if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
+         mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
+        {
+          /* broadcast to 255.255.255.255 (or mac address invalid) */
+          dest.sin_addr.s_addr = INADDR_BROADCAST;
+          dest.sin_port = htons(daemon->dhcp_client_port);
+        }
+      else
+        {
+          /* unicast to unconfigured client. Inject mac address direct into ARP cache.
+          struct sockaddr limits size to 14 bytes. */
+          dest.sin_addr = mess->yiaddr;
+          dest.sin_port = htons(daemon->dhcp_client_port);
+          memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
+          arp_req.arp_ha.sa_family = mess->htype;
+          memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
+          /* interface name already copied in */
+          arp_req.arp_flags = ATF_COM;
+          if (ioctl(daemon->dhcpfd, SIOCSARP, &arp_req) == -1)
+            my_syslog(MS_DHCP | LOG_ERR, _("ARP-cache injection failed: %s"), strerror(errno));
+        }
+    }
+#elif defined(HAVE_SOLARIS_NETWORK)
+  else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER)
+    {
+      /* broadcast to 255.255.255.255 (or mac address invalid) */
+      dest.sin_addr.s_addr = INADDR_BROADCAST;
+      dest.sin_port = htons(daemon->dhcp_client_port);
+      /* note that we don't specify the interface here: that's done by the
+	 IP_BOUND_IF sockopt lower down. */
+    }
+  else
+    {
+      /* unicast to unconfigured client. Inject mac address direct into ARP cache. 
+	 Note that this only works for ethernet on solaris, because we use SIOCSARP
+	 and not SIOCSXARP, which would be perfect, except that it returns ENXIO 
+	 mysteriously. Bah. Fall back to broadcast for other net types. */
+      struct arpreq req;
+      dest.sin_addr = mess->yiaddr;
+      dest.sin_port = htons(daemon->dhcp_client_port);
+      *((struct sockaddr_in *)&req.arp_pa) = dest;
+      req.arp_ha.sa_family = AF_UNSPEC;
+      memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
+      req.arp_flags = ATF_COM;
+      ioctl(daemon->dhcpfd, SIOCSARP, &req);
+    }
+#elif defined(HAVE_BSD_NETWORK)
+  else 
+    {
+      send_via_bpf(mess, iov.iov_len, iface_addr, &ifr);
+      return;
+    }
+#endif
+   
+#ifdef HAVE_SOLARIS_NETWORK
+  setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
+#endif
+  
+  while(retry_send(sendmsg(fd, &msg, 0)));
+
+  /* This can fail when, eg, iptables DROPS destination 255.255.255.255 */
+  if (errno != 0)
+    my_syslog(MS_DHCP | LOG_WARNING, _("Error sending DHCP packet to %s: %s"),
+	      inet_ntoa(dest.sin_addr), strerror(errno));
+}
+
+/* check against secondary interface addresses */
+static int check_listen_addrs(struct in_addr local, int if_index, char *label,
+			      struct in_addr netmask, struct in_addr broadcast, void *vparam)
+{
+  struct match_param *param = vparam;
+  struct iname *tmp;
+
+  (void) label;
+
+  if (if_index == param->ind)
+    {
+      for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
+	if ( tmp->addr.sa.sa_family == AF_INET &&
+	     tmp->addr.in.sin_addr.s_addr == local.s_addr)
+	  {
+	    param->matched = 1;
+	    param->addr = local;
+	    param->netmask = netmask;
+	    param->broadcast = broadcast;
+	    break;
+	  }
+    }
+  
+  return 1;
+}
+
+/* This is a complex routine: it gets called with each (address,netmask,broadcast) triple 
+   of each interface (and any relay address) and does the  following things:
+
+   1) Discards stuff for interfaces other than the one on which a DHCP packet just arrived.
+   2) Fills in any netmask and broadcast addresses which have not been explicitly configured.
+   3) Fills in local (this host) and router (this host or relay) addresses.
+   4) Links contexts which are valid for hosts directly connected to the arrival interface on ->current.
+
+   Note that the current chain may be superseded later for configured hosts or those coming via gateways. */
+
+static int complete_context(struct in_addr local, int if_index, char *label,
+			    struct in_addr netmask, struct in_addr broadcast, void *vparam)
+{
+  struct dhcp_context *context;
+  struct dhcp_relay *relay;
+  struct iface_param *param = vparam;
+
+  (void)label;
+  
+  for (context = daemon->dhcp; context; context = context->next)
+    {
+      if (!(context->flags & CONTEXT_NETMASK) &&
+	  (is_same_net(local, context->start, netmask) ||
+	   is_same_net(local, context->end, netmask)))
+      { 
+	if (context->netmask.s_addr != netmask.s_addr &&
+	    !(is_same_net(local, context->start, netmask) &&
+	      is_same_net(local, context->end, netmask)))
+	  {
+	    strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
+	    strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
+	    my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
+		      daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
+	  }	
+ 	context->netmask = netmask;
+      }
+      
+      if (context->netmask.s_addr != 0 &&
+	  is_same_net(local, context->start, context->netmask) &&
+	  is_same_net(local, context->end, context->netmask))
+	{
+	  /* link it onto the current chain if we've not seen it before */
+	  if (if_index == param->ind && context->current == context)
+	    {
+	      context->router = local;
+	      context->local = local;
+	      context->current = param->current;
+	      param->current = context;
+	    }
+	  
+	  if (!(context->flags & CONTEXT_BRDCAST))
+	    {
+	      if (is_same_net(broadcast, context->start, context->netmask))
+		context->broadcast = broadcast;
+	      else 
+		context->broadcast.s_addr  = context->start.s_addr | ~context->netmask.s_addr;
+	    }
+	}		
+    }
+
+  for (relay = daemon->relay4; relay; relay = relay->next)
+    if (if_index == param->ind && relay->local.addr.addr4.s_addr == local.s_addr && relay->current == relay &&
+	(param->relay_local.s_addr == 0 || param->relay_local.s_addr == local.s_addr))
+      {
+	relay->current = param->relay;
+	param->relay = relay;
+	param->relay_local = local;	
+      }
+
+  return 1;
+}
+	  
+struct dhcp_context *address_available(struct dhcp_context *context, 
+				       struct in_addr taddr,
+				       struct dhcp_netid *netids)
+{
+  /* Check is an address is OK for this network, check all
+     possible ranges. Make sure that the address isn't in use
+     by the server itself. */
+  
+  unsigned int start, end, addr = ntohl(taddr.s_addr);
+  struct dhcp_context *tmp;
+
+  for (tmp = context; tmp; tmp = tmp->current)
+    if (taddr.s_addr == context->router.s_addr)
+      return NULL;
+  
+  for (tmp = context; tmp; tmp = tmp->current)
+    {
+      start = ntohl(tmp->start.s_addr);
+      end = ntohl(tmp->end.s_addr);
+
+      if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) &&
+	  addr >= start &&
+	  addr <= end &&
+	  match_netid(tmp->filter, netids, 1))
+	return tmp;
+    }
+
+  return NULL;
+}
+
+struct dhcp_context *narrow_context(struct dhcp_context *context, 
+				    struct in_addr taddr,
+				    struct dhcp_netid *netids)
+{
+  /* We start of with a set of possible contexts, all on the current physical interface.
+     These are chained on ->current.
+     Here we have an address, and return the actual context corresponding 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 if possible, or failing that,
+     any context on the correct subnet. (If there's more than one, this is a dodgy 
+     configuration: maybe there should be a warning.) */
+  
+  struct dhcp_context *tmp;
+
+  if (!(tmp = address_available(context, taddr, netids)))
+    {
+      for (tmp = context; tmp; tmp = tmp->current)
+	if (match_netid(tmp->filter, netids, 1) &&
+	    is_same_net(taddr, tmp->start, tmp->netmask) && 
+	    (tmp->flags & CONTEXT_STATIC))
+	  break;
+      
+      if (!tmp)
+	for (tmp = context; tmp; tmp = tmp->current)
+	  if (match_netid(tmp->filter, netids, 1) &&
+	      is_same_net(taddr, tmp->start, tmp->netmask) &&
+	      !(tmp->flags & CONTEXT_PROXY))
+	    break;
+    }
+  
+  /* Only one context allowed now */
+  if (tmp)
+    tmp->current = NULL;
+  
+  return tmp;
+}
+
+struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
+{
+  struct dhcp_config *config;
+  
+  for (config = configs; config; config = config->next)
+    if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
+      return config;
+
+  return NULL;
+}
+
+/* Check if and address is in use by sending ICMP ping.
+   This wrapper handles a cache and load-limiting.
+   Return is NULL is address in use, or a pointer to a cache entry
+   recording that it isn't. */
+struct ping_result *do_icmp_ping(time_t now, struct in_addr addr, unsigned int hash, int loopback)
+{
+  static struct ping_result dummy;
+  struct ping_result *r, *victim = NULL;
+  int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
+				((float)PING_WAIT)));
+
+  /* check if we failed to ping addr sometime in the last
+     PING_CACHE_TIME seconds. If so, assume the same situation still exists.
+     This avoids problems when a stupid client bangs
+     on us repeatedly. As a final check, if we did more
+     than 60% of the possible ping checks in the last 
+     PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
+  for (count = 0, r = daemon->ping_results; r; r = r->next)
+    if (difftime(now, r->time) >  (float)PING_CACHE_TIME)
+      victim = r; /* old record */
+    else 
+      {
+	count++;
+	if (r->addr.s_addr == addr.s_addr)
+	  return r;
+      }
+  
+  /* didn't find cached entry */
+  if ((count >= max) || option_bool(OPT_NO_PING) || loopback)
+    {
+      /* overloaded, or configured not to check, loopback interface, return "not in use" */
+      dummy.hash = 0;
+      return &dummy;
+    }
+  else if (icmp_ping(addr))
+    return NULL; /* address in use. */
+  else
+    {
+      /* at this point victim may hold an expired record */
+      if (!victim)
+	{
+	  if ((victim = whine_malloc(sizeof(struct ping_result))))
+	    {
+	      victim->next = daemon->ping_results;
+	      daemon->ping_results = victim;
+	    }
+	}
+      
+      /* record that this address is OK for 30s 
+	 without more ping checks */
+      if (victim)
+	{
+	  victim->addr = addr;
+	  victim->time = now;
+	  victim->hash = hash;
+	}
+      return victim;
+    }
+}
+
+int address_allocate(struct dhcp_context *context,
+		     struct in_addr *addrp, unsigned char *hwaddr, int hw_len, 
+		     struct dhcp_netid *netids, time_t now, int loopback)   
+{
+  /* Find a free address: exclude anything in use and anything allocated to
+     a particular hwaddr/clientid/hostname in our configuration.
+     Try to return from contexts which match netids first. */
+
+  struct in_addr start, addr;
+  struct dhcp_context *c, *d;
+  int i, pass;
+  unsigned int j; 
+
+  /* hash hwaddr: use the SDBM hashing algorithm.  Seems to give good
+     dispersal even with similarly-valued "strings". */ 
+  for (j = 0, i = 0; i < hw_len; i++)
+    j = hwaddr[i] + (j << 6) + (j << 16) - j;
+
+  /* j == 0 is marker */
+  if (j == 0)
+    j = 1;
+  
+  for (pass = 0; pass <= 1; pass++)
+    for (c = context; c; c = c->current)
+      if (c->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
+	continue;
+      else if (!match_netid(c->filter, netids, pass))
+	continue;
+      else
+	{
+	  if (option_bool(OPT_CONSEC_ADDR))
+	    /* seed is largest extant lease addr in this context */
+	    start = lease_find_max_addr(c);
+	  else
+	    /* pick a seed based on hwaddr */
+	    start.s_addr = htonl(ntohl(c->start.s_addr) + 
+				 ((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
+
+	  /* iterate until we find a free address. */
+	  addr = start;
+	  
+	  do {
+	    /* eliminate addresses in use by the server. */
+	    for (d = context; d; d = d->current)
+	      if (addr.s_addr == d->router.s_addr)
+		break;
+
+	    /* Addresses which end in .255 and .0 are broken in Windows even when using 
+	       supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254.0
+	       then 192.168.0.255 is a valid IP address, but not for Windows as it's
+	       in the class C range. See  KB281579. We therefore don't allocate these 
+	       addresses to avoid hard-to-diagnose problems. Thanks Bill. */	    
+	    if (!d &&
+		!lease_find_by_addr(addr) && 
+		!config_find_by_address(daemon->dhcp_conf, addr) &&
+		(!IN_CLASSC(ntohl(addr.s_addr)) || 
+		 ((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0))))
+	      {
+		/* in consec-ip mode, skip addresses equal to
+		   the number of addresses rejected by clients. This
+		   should avoid the same client being offered the same
+		   address after it has rjected it. */
+		if (option_bool(OPT_CONSEC_ADDR) && c->addr_epoch)
+		  c->addr_epoch--;
+		else
+		  {
+		    struct ping_result *r;
+		    
+		    if ((r = do_icmp_ping(now, addr, j, loopback)))
+		      {
+			/* consec-ip mode: we offered this address for another client
+			   (different hash) recently, don't offer it to this one. */
+			if (!option_bool(OPT_CONSEC_ADDR) || r->hash == j)
+			  {
+			    *addrp = addr;
+			    return 1;
+			  }
+		      }
+		    else
+		      {
+			/* address in use: perturb address selection so that we are
+			   less likely to try this address again. */
+			if (!option_bool(OPT_CONSEC_ADDR))
+			  c->addr_epoch++;
+		      }
+		  }
+	      }
+	    
+	    addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
+	    
+	    if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1))
+	      addr = c->start;
+	    
+	  } while (addr.s_addr != start.s_addr);
+	}
+
+  return 0;
+}
+
+void dhcp_read_ethers(void)
+{
+  FILE *f = fopen(ETHERSFILE, "r");
+  unsigned int flags;
+  char *buff = daemon->namebuff;
+  char *ip, *cp;
+  struct in_addr addr;
+  unsigned char hwaddr[ETHER_ADDR_LEN];
+  struct dhcp_config **up, *tmp;
+  struct dhcp_config *config;
+  int count = 0, lineno = 0;
+
+  addr.s_addr = 0; /* eliminate warning */
+  
+  if (!f)
+    {
+      my_syslog(MS_DHCP | LOG_ERR, _("failed to read %s: %s"), ETHERSFILE, strerror(errno));
+      return;
+    }
+
+  /* This can be called again on SIGHUP, so remove entries created last time round. */
+  for (up = &daemon->dhcp_conf, config = daemon->dhcp_conf; config; config = tmp)
+    {
+      tmp = config->next;
+      if (config->flags & CONFIG_FROM_ETHERS)
+	{
+	  *up = tmp;
+	  /* cannot have a clid */
+	  if (config->flags & CONFIG_NAME)
+	    free(config->hostname);
+	  free(config->hwaddr);
+	  free(config);
+	}
+      else
+	up = &config->next;
+    }
+
+  while (fgets(buff, MAXDNAME, f))
+    {
+      char *host = NULL;
+      
+      lineno++;
+      
+      while (strlen(buff) > 0 && isspace((int)buff[strlen(buff)-1]))
+	buff[strlen(buff)-1] = 0;
+      
+      if ((*buff == '#') || (*buff == '+') || (*buff == 0))
+	continue;
+      
+      for (ip = buff; *ip && !isspace((int)*ip); ip++);
+      for(; *ip && isspace((int)*ip); ip++)
+	*ip = 0;
+      if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
+	{
+	  my_syslog(MS_DHCP | LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno); 
+	  continue;
+	}
+      
+      /* check for name or dotted-quad */
+      for (cp = ip; *cp; cp++)
+	if (!(*cp == '.' || (*cp >='0' && *cp <= '9')))
+	  break;
+      
+      if (!*cp)
+	{
+	  if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
+	    {
+	      my_syslog(MS_DHCP | LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno); 
+	      continue;
+	    }
+
+	  flags = CONFIG_ADDR;
+	  
+	  for (config = daemon->dhcp_conf; config; config = config->next)
+	    if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
+	      break;
+	}
+      else 
+	{
+	  int nomem;
+	  if (!(host = canonicalise(ip, &nomem)) || !legal_hostname(host))
+	    {
+	      if (!nomem)
+		my_syslog(MS_DHCP | LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno); 
+	      free(host);
+	      continue;
+	    }
+	      
+	  flags = CONFIG_NAME;
+
+	  for (config = daemon->dhcp_conf; config; config = config->next)
+	    if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, host))
+	      break;
+	}
+
+      if (config && (config->flags & CONFIG_FROM_ETHERS))
+	{
+	  my_syslog(MS_DHCP | LOG_ERR, _("ignoring %s line %d, duplicate name or IP address"), ETHERSFILE, lineno); 
+	  continue;
+	}
+	
+      if (!config)
+	{ 
+	  for (config = daemon->dhcp_conf; config; config = config->next)
+	    {
+	      struct hwaddr_config *conf_addr = config->hwaddr;
+	      if (conf_addr && 
+		  conf_addr->next == NULL && 
+		  conf_addr->wildcard_mask == 0 &&
+		  conf_addr->hwaddr_len == ETHER_ADDR_LEN &&
+		  (conf_addr->hwaddr_type == ARPHRD_ETHER || conf_addr->hwaddr_type == 0) &&
+		  memcmp(conf_addr->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
+		break;
+	    }
+	  
+	  if (!config)
+	    {
+	      if (!(config = whine_malloc(sizeof(struct dhcp_config))))
+		continue;
+	      config->flags = CONFIG_FROM_ETHERS;
+	      config->hwaddr = NULL;
+	      config->domain = NULL;
+	      config->netid = NULL;
+	      config->next = daemon->dhcp_conf;
+	      daemon->dhcp_conf = config;
+	    }
+	  
+	  config->flags |= flags;
+	  
+	  if (flags & CONFIG_NAME)
+	    {
+	      config->hostname = host;
+	      host = NULL;
+	    }
+	  
+	  if (flags & CONFIG_ADDR)
+	    config->addr = addr;
+	}
+      
+      config->flags |= CONFIG_NOCLID;
+      if (!config->hwaddr)
+	config->hwaddr = whine_malloc(sizeof(struct hwaddr_config));
+      if (config->hwaddr)
+	{
+	  memcpy(config->hwaddr->hwaddr, hwaddr, ETHER_ADDR_LEN);
+	  config->hwaddr->hwaddr_len = ETHER_ADDR_LEN;
+	  config->hwaddr->hwaddr_type = ARPHRD_ETHER;
+	  config->hwaddr->wildcard_mask = 0;
+	  config->hwaddr->next = NULL;
+	}
+      count++;
+      
+      free(host);
+
+    }
+  
+  fclose(f);
+
+  my_syslog(MS_DHCP | LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
+}
+
+
+/* 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. The set of legal domain names is bigger than the set of legal hostnames
+   so check here that the domain name is legal as a hostname. 
+   NOTE: we're only allowed to overwrite daemon->dhcp_buff if we succeed. */
+char *host_from_dns(struct in_addr addr)
+{
+  struct crec *lookup;
+
+  if (daemon->port == 0)
+    return NULL; /* DNS disabled. */
+  
+  lookup = cache_find_by_addr(NULL, (struct all_addr *)&addr, 0, F_IPV4);
+
+  if (lookup && (lookup->flags & F_HOSTS))
+    {
+      char *dot, *hostname = cache_get_name(lookup);
+      dot = strchr(hostname, '.');
+      
+      if (dot && strlen(dot+1) != 0)
+	{
+	  char *d2 = get_domain(addr);
+	  if (!d2 || !hostname_isequal(dot+1, d2))
+	    return NULL; /* wrong domain */
+	}
+
+      if (!legal_hostname(hostname))
+	return NULL;
+      
+      strncpy(daemon->dhcp_buff, hostname, 256);
+      daemon->dhcp_buff[255] = 0;
+      strip_hostname(daemon->dhcp_buff);
+
+      return daemon->dhcp_buff;
+    }
+  
+  return NULL;
+}
+
+static int  relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index)
+{
+  /* ->local is same value for all relays on ->current chain */
+  struct all_addr from;
+  
+  if (mess->op != BOOTREQUEST)
+    return 0;
+
+  /* source address == relay address */
+  from.addr.addr4 = relay->local.addr.addr4;
+  
+  /* already gatewayed ? */
+  if (mess->giaddr.s_addr)
+    {
+      /* if so check if by us, to stomp on loops. */
+      if (mess->giaddr.s_addr == relay->local.addr.addr4.s_addr)
+	return 1;
+    }
+  else
+    {
+      /* plug in our address */
+      mess->giaddr.s_addr = relay->local.addr.addr4.s_addr;
+    }
+
+  if ((mess->hops++) > 20)
+    return 1;
+
+  for (; relay; relay = relay->current)
+    {
+      union mysockaddr to;
+      
+      to.sa.sa_family = AF_INET;
+      to.in.sin_addr = relay->server.addr.addr4;
+      to.in.sin_port = htons(daemon->dhcp_server_port);
+      
+      send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0);
+      
+      if (option_bool(OPT_LOG_OPTS))
+	{
+	  inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN);
+	  my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, inet_ntoa(relay->server.addr.addr4));
+	}
+      
+      /* Save this for replies */
+      relay->iface_index = iface_index;
+    }
+  
+  return 1;
+}
+
+
+static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface)
+{
+  struct dhcp_relay *relay;
+
+  if (mess->giaddr.s_addr == 0 || mess->op != BOOTREPLY)
+    return NULL;
+
+  for (relay = daemon->relay4; relay; relay = relay->next)
+    {
+      if (mess->giaddr.s_addr == relay->local.addr.addr4.s_addr)
+	{
+	  if (!relay->interface || wildcard_match(relay->interface, arrival_interface))
+	    return relay->iface_index != 0 ? relay : NULL;
+	}
+    }
+  
+  return NULL;	 
+}     
+
+#endif
diff --git a/src/dhcp6-protocol.h b/src/dhcp6-protocol.h
new file mode 100644
index 0000000..f4d03dd
--- /dev/null
+++ b/src/dhcp6-protocol.h
@@ -0,0 +1,75 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define DHCPV6_SERVER_PORT 547
+#define DHCPV6_CLIENT_PORT 546
+
+#define ALL_SERVERS                  "FF05::1:3"
+#define ALL_RELAY_AGENTS_AND_SERVERS "FF02::1:2"
+
+#define DHCP6SOLICIT      1
+#define DHCP6ADVERTISE    2
+#define DHCP6REQUEST      3
+#define DHCP6CONFIRM      4
+#define DHCP6RENEW        5
+#define DHCP6REBIND       6
+#define DHCP6REPLY        7
+#define DHCP6RELEASE      8
+#define DHCP6DECLINE      9
+#define DHCP6RECONFIGURE  10
+#define DHCP6IREQ         11
+#define DHCP6RELAYFORW    12
+#define DHCP6RELAYREPL    13
+
+#define OPTION6_CLIENT_ID       1
+#define OPTION6_SERVER_ID       2
+#define OPTION6_IA_NA           3
+#define OPTION6_IA_TA           4
+#define OPTION6_IAADDR          5
+#define OPTION6_ORO             6
+#define OPTION6_PREFERENCE      7
+#define OPTION6_ELAPSED_TIME    8
+#define OPTION6_RELAY_MSG       9
+#define OPTION6_AUTH            11
+#define OPTION6_UNICAST         12
+#define OPTION6_STATUS_CODE     13
+#define OPTION6_RAPID_COMMIT    14
+#define OPTION6_USER_CLASS      15
+#define OPTION6_VENDOR_CLASS    16
+#define OPTION6_VENDOR_OPTS     17
+#define OPTION6_INTERFACE_ID    18
+#define OPTION6_RECONFIGURE_MSG 19
+#define OPTION6_RECONF_ACCEPT   20
+#define OPTION6_DNS_SERVER      23
+#define OPTION6_DOMAIN_SEARCH   24
+#define OPTION6_REFRESH_TIME    32
+#define OPTION6_REMOTE_ID       37
+#define OPTION6_SUBSCRIBER_ID   38
+#define OPTION6_FQDN            39
+#define OPTION6_CLIENT_MAC      79
+
+/* replace this with the real number when allocated.
+   defining this also enables the relevant code. */ 
+/* #define OPTION6_PREFIX_CLASS    99 */
+
+
+#define DHCP6SUCCESS     0
+#define DHCP6UNSPEC      1
+#define DHCP6NOADDRS     2
+#define DHCP6NOBINDING   3
+#define DHCP6NOTONLINK   4
+#define DHCP6USEMULTI    5
+
diff --git a/src/dhcp6.c b/src/dhcp6.c
new file mode 100644
index 0000000..f4caea3
--- /dev/null
+++ b/src/dhcp6.c
@@ -0,0 +1,790 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_DHCP6
+
+#include <netinet/icmp6.h>
+
+struct iface_param {
+  struct dhcp_context *current;
+  struct dhcp_relay *relay;
+  struct in6_addr fallback, relay_local, ll_addr, ula_addr;
+  int ind, addr_match;
+};
+
+
+static int complete_context6(struct in6_addr *local,  int prefix,
+			     int scope, int if_index, int flags, 
+			     unsigned int preferred, unsigned int valid, void *vparam);
+static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm); 
+
+void dhcp6_init(void)
+{
+  int fd;
+  struct sockaddr_in6 saddr;
+#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
+  int class = IPTOS_CLASS_CS6;
+#endif
+  int oneopt = 1;
+
+  if ((fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1 ||
+#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
+      setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
+#endif
+      setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &oneopt, sizeof(oneopt)) == -1 ||
+      !fix_fd(fd) ||
+      !set_ipv6pktinfo(fd))
+    die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
+  
+ /* When bind-interfaces is set, there might be more than one dnsmasq
+     instance binding port 547. That's OK if they serve different networks.
+     Need to set REUSEADDR|REUSEPORT to make this possible.
+     Handle the case that REUSEPORT is defined, but the kernel doesn't 
+     support it. This handles the introduction of REUSEPORT on Linux. */
+  if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
+    {
+      int rc = 0;
+
+#ifdef SO_REUSEPORT
+      if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
+	  errno == ENOPROTOOPT)
+	rc = 0;
+#endif
+      
+      if (rc != -1)
+	rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
+      
+      if (rc == -1)
+	die(_("failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"), NULL, EC_BADNET);
+    }
+  
+  memset(&saddr, 0, sizeof(saddr));
+#ifdef HAVE_SOCKADDR_SA_LEN
+  saddr.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+  saddr.sin6_family = AF_INET6;
+  saddr.sin6_addr = in6addr_any;
+  saddr.sin6_port = htons(DHCPV6_SERVER_PORT);
+  
+  if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in6)))
+    die(_("failed to bind DHCPv6 server socket: %s"), NULL, EC_BADNET);
+  
+  daemon->dhcp6fd = fd;
+}
+
+void dhcp6_packet(time_t now)
+{
+  struct dhcp_context *context;
+  struct dhcp_relay *relay;
+  struct iface_param parm;
+  struct cmsghdr *cmptr;
+  struct msghdr msg;
+  int if_index = 0;
+  union {
+    struct cmsghdr align; /* this ensures alignment */
+    char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+  } control_u;
+  struct sockaddr_in6 from;
+  ssize_t sz; 
+  struct ifreq ifr;
+  struct iname *tmp;
+  unsigned short port;
+  struct in6_addr dst_addr;
+
+  memset(&dst_addr, 0, sizeof(dst_addr));
+
+  msg.msg_control = control_u.control6;
+  msg.msg_controllen = sizeof(control_u);
+  msg.msg_flags = 0;
+  msg.msg_name = &from;
+  msg.msg_namelen = sizeof(from);
+  msg.msg_iov =  &daemon->dhcp_packet;
+  msg.msg_iovlen = 1;
+  
+  if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg)) == -1)
+    return;
+  
+  for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
+    if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
+      {
+	union {
+	  unsigned char *c;
+	  struct in6_pktinfo *p;
+	} p;
+	p.c = CMSG_DATA(cmptr);
+        
+	if_index = p.p->ipi6_ifindex;
+	dst_addr = p.p->ipi6_addr;
+      }
+
+  if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
+    return;
+
+  if ((port = relay_reply6(&from, sz, ifr.ifr_name)) == 0)
+    {
+      struct dhcp_bridge *bridge, *alias;
+
+      for (tmp = daemon->if_except; tmp; tmp = tmp->next)
+	if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
+	  return;
+      
+      for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
+	if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
+	  return;
+      
+      parm.current = NULL;
+      parm.relay = NULL;
+      memset(&parm.relay_local, 0, IN6ADDRSZ);
+      parm.ind = if_index;
+      parm.addr_match = 0;
+      memset(&parm.fallback, 0, IN6ADDRSZ);
+      memset(&parm.ll_addr, 0, IN6ADDRSZ);
+      memset(&parm.ula_addr, 0, IN6ADDRSZ);
+
+      /* If the interface on which the DHCPv6 request was received is
+         an alias of some other interface (as specified by the
+         --bridge-interface option), change parm.ind so that we look
+         for DHCPv6 contexts associated with the aliased interface
+         instead of with the aliasing one. */
+      for (bridge = daemon->bridges; bridge; bridge = bridge->next)
+	{
+	  for (alias = bridge->alias; alias; alias = alias->next)
+	    if (wildcard_matchn(alias->iface, ifr.ifr_name, IF_NAMESIZE))
+	      {
+		parm.ind = if_nametoindex(bridge->iface);
+		if (!parm.ind)
+		  {
+		    my_syslog(MS_DHCP | LOG_WARNING,
+			      _("unknown interface %s in bridge-interface"),
+			      bridge->iface);
+		    return;
+		  }
+		break;
+	      }
+	  if (alias)
+	    break;
+	}
+      
+      for (context = daemon->dhcp6; context; context = context->next)
+	if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
+	  {
+	    /* wildcard context for DHCP-stateless only */
+	    parm.current = context;
+	    context->current = NULL;
+	  }
+	else
+	  {
+	    /* unlinked contexts are marked by context->current == context */
+	    context->current = context;
+	    memset(&context->local6, 0, IN6ADDRSZ);
+	  }
+
+      for (relay = daemon->relay6; relay; relay = relay->next)
+	relay->current = relay;
+      
+      if (!iface_enumerate(AF_INET6, &parm, complete_context6))
+	return;
+
+      if (daemon->if_names || daemon->if_addrs)
+	{
+	  
+	  for (tmp = daemon->if_names; tmp; tmp = tmp->next)
+	    if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
+	      break;
+	  
+	  if (!tmp && !parm.addr_match)
+	    return;
+	}
+      
+      if (parm.relay)
+	{
+	  /* Ignore requests sent to the ALL_SERVERS multicast address for relay when
+	     we're listening there for DHCPv6 server reasons. */
+	  struct in6_addr all_servers;
+	  
+	  inet_pton(AF_INET6, ALL_SERVERS, &all_servers);
+	  
+	  if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))
+	    relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id, now);
+	  return;
+	}
+      
+      /* May have configured relay, but not DHCP server */
+      if (!daemon->doing_dhcp6)
+	return;
+
+      lease_prune(NULL, now); /* lose any expired leases */
+      
+      port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback, 
+			 &parm.ll_addr, &parm.ula_addr, sz, &from.sin6_addr, now);
+      
+      lease_update_file(now);
+      lease_update_dns(0);
+    }
+			  
+  /* The port in the source address of the original request should
+     be correct, but at least once client sends from the server port,
+     so we explicitly send to the client port to a client, and the
+     server port to a relay. */
+  if (port != 0)
+    {
+      from.sin6_port = htons(port);
+      while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, 
+			       save_counter(0), 0, (struct sockaddr *)&from, 
+			       sizeof(from))));
+    }
+}
+
+void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsigned int *maclenp, unsigned int *mactypep, time_t now)
+{
+  /* Receiving a packet from a host does not populate the neighbour
+     cache, so we send a neighbour discovery request if we can't 
+     find the sender. Repeat a few times in case of packet loss. */
+  
+  struct neigh_packet neigh;
+  union mysockaddr addr;
+  int i, maclen;
+
+  neigh.type = ND_NEIGHBOR_SOLICIT;
+  neigh.code = 0;
+  neigh.reserved = 0;
+  neigh.target = *client;
+  /* RFC4443 section-2.3: checksum has to be zero to be calculated */
+  neigh.checksum = 0;
+   
+  memset(&addr, 0, sizeof(addr));
+#ifdef HAVE_SOCKADDR_SA_LEN
+  addr.in6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+  addr.in6.sin6_family = AF_INET6;
+  addr.in6.sin6_port = htons(IPPROTO_ICMPV6);
+  addr.in6.sin6_addr = *client;
+  addr.in6.sin6_scope_id = iface;
+  
+  for (i = 0; i < 5; i++)
+    {
+      struct timespec ts;
+      
+      if ((maclen = find_mac(&addr, mac, 0, now)) != 0)
+	break;
+	  
+      sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr));
+      
+      ts.tv_sec = 0;
+      ts.tv_nsec = 100000000; /* 100ms */
+      nanosleep(&ts, NULL);
+    }
+
+  *maclenp = maclen;
+  *mactypep = ARPHRD_ETHER;
+}
+    
+static int complete_context6(struct in6_addr *local,  int prefix,
+			     int scope, int if_index, int flags, unsigned int preferred, 
+			     unsigned int valid, void *vparam)
+{
+  struct dhcp_context *context;
+  struct dhcp_relay *relay;
+  struct iface_param *param = vparam;
+  struct iname *tmp;
+ 
+  (void)scope; /* warning */
+  
+  if (if_index == param->ind)
+    {
+      if (IN6_IS_ADDR_LINKLOCAL(local))
+	param->ll_addr = *local;
+      else if (IN6_IS_ADDR_ULA(local))
+	param->ula_addr = *local;
+
+      if (!IN6_IS_ADDR_LOOPBACK(local) &&
+	  !IN6_IS_ADDR_LINKLOCAL(local) &&
+	  !IN6_IS_ADDR_MULTICAST(local))
+	{
+	  /* if we have --listen-address config, see if the 
+	     arrival interface has a matching address. */
+	  for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
+	    if (tmp->addr.sa.sa_family == AF_INET6 &&
+		IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
+	      param->addr_match = 1;
+	  
+	  /* Determine a globally address on the arrival interface, even
+	     if we have no matching dhcp-context, because we're only
+	     allocating on remote subnets via relays. This
+	     is used as a default for the DNS server option. */
+	  param->fallback = *local;
+	  
+	  for (context = daemon->dhcp6; context; context = context->next)
+	    {
+	      if ((context->flags & CONTEXT_DHCP) &&
+		  !(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
+		  prefix <= context->prefix &&
+		  is_same_net6(local, &context->start6, context->prefix) &&
+		  is_same_net6(local, &context->end6, context->prefix))
+		{
+		  
+		  
+		  /* link it onto the current chain if we've not seen it before */
+		  if (context->current == context)
+		    {
+		      struct dhcp_context *tmp, **up;
+		      
+		      /* use interface values only for constructed contexts */
+		      if (!(context->flags & CONTEXT_CONSTRUCTED))
+			preferred = valid = 0xffffffff;
+		      else if (flags & IFACE_DEPRECATED)
+			preferred = 0;
+		      
+		      if (context->flags & CONTEXT_DEPRECATE)
+			preferred = 0;
+		      
+		      /* order chain, longest preferred time first */
+		      for (up = &param->current, tmp = param->current; tmp; tmp = tmp->current)
+			if (tmp->preferred <= preferred)
+			  break;
+			else
+			  up = &tmp->current;
+		      
+		      context->current = *up;
+		      *up = context;
+		      context->local6 = *local;
+		      context->preferred = preferred;
+		      context->valid = valid;
+		    }
+		}
+	    }
+	}
+
+      for (relay = daemon->relay6; relay; relay = relay->next)
+	if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr.addr6) && relay->current == relay &&
+	    (IN6_IS_ADDR_UNSPECIFIED(&param->relay_local) || IN6_ARE_ADDR_EQUAL(local, &param->relay_local)))
+	  {
+	    relay->current = param->relay;
+	    param->relay = relay;
+	    param->relay_local = *local;
+	  }
+      
+    }          
+ 
+ return 1;
+}
+
+struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr)
+{
+  struct dhcp_config *config;
+  
+  for (config = configs; config; config = config->next)
+    if ((config->flags & CONFIG_ADDR6) &&
+	is_same_net6(&config->addr6, net, prefix) &&
+	(prefix == 128 || addr6part(&config->addr6) == addr))
+      return config;
+  
+  return NULL;
+}
+
+struct dhcp_context *address6_allocate(struct dhcp_context *context,  unsigned char *clid, int clid_len, int temp_addr,
+				       int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans)   
+{
+  /* Find a free address: exclude anything in use and anything allocated to
+     a particular hwaddr/clientid/hostname in our configuration.
+     Try to return from contexts which match netids first. 
+     
+     Note that we assume the address prefix lengths are 64 or greater, so we can
+     get by with 64 bit arithmetic.
+*/
+
+  u64 start, addr;
+  struct dhcp_context *c, *d;
+  int i, pass;
+  u64 j; 
+
+  /* hash hwaddr: use the SDBM hashing algorithm.  This works
+     for MAC addresses, let's see how it manages with client-ids! 
+     For temporary addresses, we generate a new random one each time. */
+  if (temp_addr)
+    j = rand64();
+  else
+    for (j = iaid, i = 0; i < clid_len; i++)
+      j = clid[i] + (j << 6) + (j << 16) - j;
+  
+  for (pass = 0; pass <= plain_range ? 1 : 0; pass++)
+    for (c = context; c; c = c->current)
+      if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS | CONTEXT_USED))
+	continue;
+      else if (!match_netid(c->filter, netids, pass))
+	continue;
+      else
+	{ 
+	  if (!temp_addr && option_bool(OPT_CONSEC_ADDR))
+	    {
+	      /* seed is largest extant lease addr in this context,
+		 skip addresses equal to the number of addresses rejected
+		 by clients. This should avoid the same client being offered the same
+		 address after it has rjected it. */
+	      start = lease_find_max_addr6(c) + 1 + serial + c->addr_epoch;
+	      if (c->addr_epoch)
+		c->addr_epoch--;
+	    }
+	  else
+	    {
+	      u64 range = 1 + addr6part(&c->end6) - addr6part(&c->start6);
+	      u64 offset = j + c->addr_epoch;
+
+	      /* don't divide by zero if range is whole 2^64 */
+	      if (range != 0)
+		offset = offset % range;
+
+	      start = addr6part(&c->start6) + offset;
+	    }
+
+	  /* iterate until we find a free address. */
+	  addr = start;
+	  
+	  do {
+	    /* eliminate addresses in use by the server. */
+	    for (d = context; d; d = d->current)
+	      if (addr == addr6part(&d->local6))
+		break;
+
+	    if (!d &&
+		!lease6_find_by_addr(&c->start6, c->prefix, addr) && 
+		!config_find_by_address6(daemon->dhcp_conf, &c->start6, c->prefix, addr))
+	      {
+		*ans = c->start6;
+		setaddr6part (ans, addr);
+		return c;
+	      }
+	
+	    addr++;
+	    
+	    if (addr  == addr6part(&c->end6) + 1)
+	      addr = addr6part(&c->start6);
+	    
+	  } while (addr != start);
+	}
+	   
+  return NULL;
+}
+
+/* can dynamically allocate addr */
+struct dhcp_context *address6_available(struct dhcp_context *context, 
+					struct in6_addr *taddr,
+					struct dhcp_netid *netids,
+					int plain_range)
+{
+  u64 start, end, addr = addr6part(taddr);
+  struct dhcp_context *tmp;
+ 
+  for (tmp = context; tmp; tmp = tmp->current)
+    {
+      start = addr6part(&tmp->start6);
+      end = addr6part(&tmp->end6);
+
+      if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_RA_STATELESS)) &&
+          is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
+	  is_same_net6(&tmp->end6, taddr, tmp->prefix) &&
+	  addr >= start &&
+          addr <= end &&
+          match_netid(tmp->filter, netids, plain_range))
+        return tmp;
+    }
+
+  return NULL;
+}
+
+/* address OK if configured */
+struct dhcp_context *address6_valid(struct dhcp_context *context, 
+				    struct in6_addr *taddr,
+				    struct dhcp_netid *netids,
+				    int plain_range)
+{
+  struct dhcp_context *tmp;
+ 
+  for (tmp = context; tmp; tmp = tmp->current)
+    if (is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
+	match_netid(tmp->filter, netids, plain_range))
+      return tmp;
+
+  return NULL;
+}
+
+int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr)
+{
+  if (!config || !(config->flags & CONFIG_ADDR6))
+    return 0;
+
+  if ((config->flags & CONFIG_WILDCARD) && context->prefix == 64)
+    {
+      *addr = context->start6;
+      setaddr6part(addr, addr6part(&config->addr6));
+      return 1;
+    }
+  
+  if (is_same_net6(&context->start6, &config->addr6, context->prefix))
+    {
+      *addr = config->addr6;
+      return 1;
+    }
+  
+  return 0;
+}
+
+void make_duid(time_t now)
+{
+  (void)now;
+
+  if (daemon->duid_config)
+    {
+      unsigned char *p;
+      
+      daemon->duid = p = safe_malloc(daemon->duid_config_len + 6);
+      daemon->duid_len = daemon->duid_config_len + 6;
+      PUTSHORT(2, p); /* DUID_EN */
+      PUTLONG(daemon->duid_enterprise, p);
+      memcpy(p, daemon->duid_config, daemon->duid_config_len);
+    }
+  else
+    {
+      time_t newnow = 0;
+      
+      /* If we have no persistent lease database, or a non-stable RTC, use DUID_LL (newnow == 0) */
+#ifndef HAVE_BROKEN_RTC
+      /* rebase epoch to 1/1/2000 */
+      if (!option_bool(OPT_LEASE_RO) || daemon->lease_change_command)
+	newnow = now - 946684800;
+#endif      
+      
+      iface_enumerate(AF_LOCAL, &newnow, make_duid1);
+      
+      if(!daemon->duid)
+	die("Cannot create DHCPv6 server DUID: %s", NULL, EC_MISC);
+    }
+}
+
+static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm)
+{
+  /* create DUID as specified in RFC3315. We use the MAC of the
+     first interface we find that isn't loopback or P-to-P and
+     has address-type < 256. Address types above 256 are things like 
+     tunnels which don't have usable MAC addresses. */
+  
+  unsigned char *p;
+  (void)index;
+  (void)parm;
+  time_t newnow = *((time_t *)parm);
+  
+  if (type >= 256)
+    return 1;
+
+  if (newnow == 0)
+    {
+      daemon->duid = p = safe_malloc(maclen + 4);
+      daemon->duid_len = maclen + 4;
+      PUTSHORT(3, p); /* DUID_LL */
+      PUTSHORT(type, p); /* address type */
+    }
+  else
+    {
+      daemon->duid = p = safe_malloc(maclen + 8);
+      daemon->duid_len = maclen + 8;
+      PUTSHORT(1, p); /* DUID_LLT */
+      PUTSHORT(type, p); /* address type */
+      PUTLONG(*((time_t *)parm), p); /* time */
+    }
+  
+  memcpy(p, mac, maclen);
+
+  return 0;
+}
+
+struct cparam {
+  time_t now;
+  int newone, newname;
+};
+
+static int construct_worker(struct in6_addr *local, int prefix, 
+			    int scope, int if_index, int flags, 
+			    int preferred, int valid, void *vparam)
+{
+  char ifrn_name[IFNAMSIZ];
+  struct in6_addr start6, end6;
+  struct dhcp_context *template, *context;
+
+  (void)scope;
+  (void)flags;
+  (void)valid;
+  (void)preferred;
+
+  struct cparam *param = vparam;
+
+  if (IN6_IS_ADDR_LOOPBACK(local) ||
+      IN6_IS_ADDR_LINKLOCAL(local) ||
+      IN6_IS_ADDR_MULTICAST(local))
+    return 1;
+
+  if (!(flags & IFACE_PERMANENT))
+    return 1;
+
+  if (flags & IFACE_DEPRECATED)
+    return 1;
+
+  if (!indextoname(daemon->icmp6fd, if_index, ifrn_name))
+    return 0;
+  
+  for (template = daemon->dhcp6; template; template = template->next)
+    if (!(template->flags & CONTEXT_TEMPLATE))
+      {
+	/* non-template entries, just fill in interface and local addresses */
+	if (prefix <= template->prefix &&
+	    is_same_net6(local, &template->start6, template->prefix) &&
+	    is_same_net6(local, &template->end6, template->prefix))
+	  {
+	    template->if_index = if_index;
+	    template->local6 = *local;
+	  }
+	
+      }
+    else if (wildcard_match(template->template_interface, ifrn_name) &&
+	     template->prefix >= prefix)
+      {
+	start6 = *local;
+	setaddr6part(&start6, addr6part(&template->start6));
+	end6 = *local;
+	setaddr6part(&end6, addr6part(&template->end6));
+	
+	for (context = daemon->dhcp6; context; context = context->next)
+	  if ((context->flags & CONTEXT_CONSTRUCTED) &&
+	      IN6_ARE_ADDR_EQUAL(&start6, &context->start6) &&
+	      IN6_ARE_ADDR_EQUAL(&end6, &context->end6))
+	    {
+	      int flags = context->flags;
+	      context->flags &= ~(CONTEXT_GC | CONTEXT_OLD);
+	      if (flags & CONTEXT_OLD)
+		{
+		  /* address went, now it's back */
+		  log_context(AF_INET6, context); 
+		  /* fast RAs for a while */
+		  ra_start_unsolicited(param->now, context);
+		  param->newone = 1; 
+		  /* Add address to name again */
+		  if (context->flags & CONTEXT_RA_NAME)
+		    param->newname = 1;
+		}
+	      break;
+	    }
+	
+	if (!context && (context = whine_malloc(sizeof (struct dhcp_context))))
+	  {
+	    *context = *template;
+	    context->start6 = start6;
+	    context->end6 = end6;
+	    context->flags &= ~CONTEXT_TEMPLATE;
+	    context->flags |= CONTEXT_CONSTRUCTED;
+	    context->if_index = if_index;
+	    context->local6 = *local;
+	    context->saved_valid = 0;
+	    
+	    context->next = daemon->dhcp6;
+	    daemon->dhcp6 = context;
+
+	    ra_start_unsolicited(param->now, context);
+	    /* we created a new one, need to call
+	       lease_update_file to get periodic functions called */
+	    param->newone = 1; 
+
+	    /* Will need to add new putative SLAAC addresses to existing leases */
+	    if (context->flags & CONTEXT_RA_NAME)
+	      param->newname = 1;
+	    
+	    log_context(AF_INET6, context);
+	  } 
+      }
+  
+  return 1;
+}
+
+void dhcp_construct_contexts(time_t now)
+{ 
+  struct dhcp_context *context, *tmp, **up;
+  struct cparam param;
+  param.newone = 0;
+  param.newname = 0;
+  param.now = now;
+
+  for (context = daemon->dhcp6; context; context = context->next)
+    if (context->flags & CONTEXT_CONSTRUCTED)
+      context->flags |= CONTEXT_GC;
+   
+  iface_enumerate(AF_INET6, &param, construct_worker);
+
+  for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
+    {
+      
+      tmp = context->next; 
+     
+      if (context->flags & CONTEXT_GC && !(context->flags & CONTEXT_OLD))
+	{
+	  if ((context->flags & CONTEXT_RA) || option_bool(OPT_RA))
+	    {
+	      /* previously constructed context has gone. advertise it's demise */
+	      context->flags |= CONTEXT_OLD;
+	      context->address_lost_time = now;
+	      /* Apply same ceiling of configured lease time as in radv.c */
+	      if (context->saved_valid > context->lease_time)
+		context->saved_valid = context->lease_time;
+	      /* maximum time is 2 hours, from RFC */
+	      if (context->saved_valid > 7200) /* 2 hours */
+		context->saved_valid = 7200;
+	      ra_start_unsolicited(now, context);
+	      param.newone = 1; /* include deletion */ 
+	      
+	      if (context->flags & CONTEXT_RA_NAME)
+		param.newname = 1; 
+			      
+	      log_context(AF_INET6, context);
+	      
+	      up = &context->next;
+	    }
+	  else
+	    {
+	      /* we were never doing RA for this, so free now */
+	      *up = context->next;
+	      free(context);
+	    }
+	}
+      else
+	 up = &context->next;
+    }
+  
+  if (param.newone)
+    {
+      if (daemon->dhcp || daemon->doing_dhcp6)
+	{
+	  if (param.newname)
+	    lease_update_slaac(now);
+	  lease_update_file(now);
+	}
+      else 
+	/* Not doing DHCP, so no lease system, manage alarms for ra only */
+	send_alarm(periodic_ra(now), now);
+    }
+}
+
+#endif
+
+
diff --git a/src/dns-protocol.h b/src/dns-protocol.h
new file mode 100644
index 0000000..db1abc7
--- /dev/null
+++ b/src/dns-protocol.h
@@ -0,0 +1,155 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define NAMESERVER_PORT 53
+#define TFTP_PORT       69
+#define MAX_PORT        65535u
+
+#define IN6ADDRSZ       16
+#define INADDRSZ        4
+
+#define PACKETSZ	512		/* maximum packet size */
+#define MAXDNAME	1025		/* maximum presentation domain name */
+#define RRFIXEDSZ	10		/* #/bytes of fixed data in r record */
+#define MAXLABEL        63              /* maximum length of domain label */
+
+#define NOERROR		0		/* no error */
+#define FORMERR		1		/* format error */
+#define SERVFAIL	2		/* server failure */
+#define NXDOMAIN	3		/* non existent domain */
+#define NOTIMP		4		/* not implemented */
+#define REFUSED		5		/* query refused */
+
+#define QUERY           0               /* opcode */
+
+#define C_IN            1               /* the arpa internet */
+#define C_CHAOS         3               /* for chaos net (MIT) */
+#define C_HESIOD        4               /* hesiod */
+#define C_ANY           255             /* wildcard match */
+
+#define T_A		1
+#define T_NS            2
+#define T_MD            3
+#define T_MF            4             
+#define T_CNAME		5
+#define T_SOA		6
+#define T_MB            7
+#define T_MG            8
+#define T_MR            9
+#define T_PTR		12
+#define T_MINFO         14
+#define T_MX		15
+#define T_TXT		16
+#define T_RP            17
+#define T_AFSDB         18
+#define T_RT            21
+#define T_SIG		24
+#define T_PX            26
+#define T_AAAA		28
+#define T_NXT           30
+#define T_SRV		33
+#define T_NAPTR		35
+#define T_KX            36
+#define T_DNAME         39
+#define T_OPT		41
+#define T_DS            43
+#define T_RRSIG         46
+#define T_NSEC          47
+#define T_DNSKEY        48
+#define T_NSEC3         50
+#define	T_TKEY		249		
+#define	T_TSIG		250
+#define T_AXFR          252
+#define T_MAILB		253	
+#define T_ANY		255
+
+#define EDNS0_OPTION_MAC            65001 /* dyndns.org temporary assignment */
+#define EDNS0_OPTION_CLIENT_SUBNET  8     /* IANA */
+#define EDNS0_OPTION_NOMDEVICEID    65073 /* Nominum temporary assignment */
+#define EDNS0_OPTION_NOMCPEID       65074 /* Nominum temporary assignment */
+
+struct dns_header {
+  u16 id;
+  u8  hb3,hb4;
+  u16 qdcount,ancount,nscount,arcount;
+};
+
+#define HB3_QR       0x80 /* Query */
+#define HB3_OPCODE   0x78
+#define HB3_AA       0x04 /* Authoritative Answer */
+#define HB3_TC       0x02 /* TrunCated */
+#define HB3_RD       0x01 /* Recursion Desired */
+
+#define HB4_RA       0x80 /* Recursion Available */
+#define HB4_AD       0x20 /* Authenticated Data */
+#define HB4_CD       0x10 /* Checking Disabled */
+#define HB4_RCODE    0x0f
+
+#define OPCODE(x)          (((x)->hb3 & HB3_OPCODE) >> 3)
+#define SET_OPCODE(x, code) (x)->hb3 = ((x)->hb3 & ~HB3_OPCODE) | code
+
+#define RCODE(x)           ((x)->hb4 & HB4_RCODE)
+#define SET_RCODE(x, code) (x)->hb4 = ((x)->hb4 & ~HB4_RCODE) | code
+  
+#define GETSHORT(s, cp) { \
+	unsigned char *t_cp = (unsigned char *)(cp); \
+	(s) = ((u16)t_cp[0] << 8) \
+	    | ((u16)t_cp[1]) \
+	    ; \
+	(cp) += 2; \
+}
+
+#define GETLONG(l, cp) { \
+	unsigned char *t_cp = (unsigned char *)(cp); \
+	(l) = ((u32)t_cp[0] << 24) \
+	    | ((u32)t_cp[1] << 16) \
+	    | ((u32)t_cp[2] << 8) \
+	    | ((u32)t_cp[3]) \
+	    ; \
+	(cp) += 4; \
+}
+
+#define PUTSHORT(s, cp) { \
+	u16 t_s = (u16)(s); \
+	unsigned char *t_cp = (unsigned char *)(cp); \
+	*t_cp++ = t_s >> 8; \
+	*t_cp   = t_s; \
+	(cp) += 2; \
+}
+
+#define PUTLONG(l, cp) { \
+	u32 t_l = (u32)(l); \
+	unsigned char *t_cp = (unsigned char *)(cp); \
+	*t_cp++ = t_l >> 24; \
+	*t_cp++ = t_l >> 16; \
+	*t_cp++ = t_l >> 8; \
+	*t_cp   = t_l; \
+	(cp) += 4; \
+}
+
+#define CHECK_LEN(header, pp, plen, len) \
+    ((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))
+
+#define ADD_RDLEN(header, pp, plen, len) \
+  (!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))
+
+/* Escape character in our presentation format for names.
+   Cannot be '.' or /000 and must be !isprint().
+   Note that escaped chars are stored as
+   <NAME_ESCAPE> <orig-char+1>
+   to ensure that the escaped form of /000 doesn't include /000
+*/
+#define NAME_ESCAPE 1
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
new file mode 100755
index 0000000..771bec1
--- /dev/null
+++ b/src/dnsmasq.c
@@ -0,0 +1,1888 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Declare static char *compiler_opts  in config.h */
+#define DNSMASQ_COMPILE_OPTS
+
+#include "dnsmasq.h"
+
+struct daemon *daemon;
+
+static volatile pid_t pid = 0;
+static volatile int pipewrite;
+
+static int set_dns_listeners(time_t now);
+static void check_dns_listeners(time_t now);
+static void sig_handler(int sig);
+static void async_event(int pipe, time_t now);
+static void fatal_event(struct event_desc *ev, char *msg);
+static int read_event(int fd, struct event_desc *evp, char **msg);
+static void poll_resolv(int force, int do_reload, time_t now);
+
+int main (int argc, char **argv)
+{
+  int bind_fallback = 0;
+  time_t now;
+  struct sigaction sigact;
+  struct iname *if_tmp;
+  int piperead, pipefd[2], err_pipe[2];
+  struct passwd *ent_pw = NULL;
+#if defined(HAVE_SCRIPT)
+  uid_t script_uid = 0;
+  gid_t script_gid = 0;
+#endif
+  struct group *gp = NULL;
+  long i, max_fd = sysconf(_SC_OPEN_MAX);
+  char *baduser = NULL;
+  int log_err;
+#if defined(HAVE_LINUX_NETWORK)
+  cap_user_header_t hdr = NULL;
+  cap_user_data_t data = NULL;
+  char *bound_device = NULL;
+  int did_bind = 0;
+#endif 
+#if defined(HAVE_DHCP) || defined(HAVE_DHCP6)
+  struct dhcp_context *context;
+  struct dhcp_relay *relay;
+#endif
+#ifdef HAVE_TFTP
+  int tftp_prefix_missing = 0;
+#endif
+
+#ifdef LOCALEDIR
+  setlocale(LC_ALL, "");
+  bindtextdomain("dnsmasq", LOCALEDIR); 
+  textdomain("dnsmasq");
+#endif
+
+  sigact.sa_handler = sig_handler;
+  sigact.sa_flags = 0;
+  sigemptyset(&sigact.sa_mask);
+  sigaction(SIGUSR1, &sigact, NULL);
+  sigaction(SIGUSR2, &sigact, NULL);
+  sigaction(SIGHUP, &sigact, NULL);
+  sigaction(SIGTERM, &sigact, NULL);
+  sigaction(SIGALRM, &sigact, NULL);
+  sigaction(SIGCHLD, &sigact, NULL);
+
+  /* ignore SIGPIPE */
+  sigact.sa_handler = SIG_IGN;
+  sigaction(SIGPIPE, &sigact, NULL);
+
+  umask(022); /* known umask, create leases and pid files as 0644 */
+ 
+  rand_init(); /* Must precede read_opts() */
+  
+  read_opts(argc, argv, compile_opts);
+ 
+  if (daemon->edns_pktsz < PACKETSZ)
+    daemon->edns_pktsz = PACKETSZ;
+
+  /* Min buffer size: we check after adding each record, so there must be 
+     memory for the largest packet, and the largest record so the
+     min for DNS is PACKETSZ+MAXDNAME+RRFIXEDSZ which is < 1000.
+     This might be increased is EDNS packet size if greater than the minimum. */ 
+  daemon->packet_buff_sz = daemon->edns_pktsz + MAXDNAME + RRFIXEDSZ;
+  daemon->packet = safe_malloc(daemon->packet_buff_sz);
+  
+  daemon->addrbuff = safe_malloc(ADDRSTRLEN);
+  if (option_bool(OPT_EXTRALOG))
+    daemon->addrbuff2 = safe_malloc(ADDRSTRLEN);
+  
+#ifdef HAVE_DNSSEC
+  if (option_bool(OPT_DNSSEC_VALID))
+    {
+      /* Note that both /000 and '.' are allowed within labels. These get
+	 represented in presentation format using NAME_ESCAPE as an escape
+	 character when in DNSSEC mode. 
+	 In theory, if all the characters in a name were /000 or
+	 '.' or NAME_ESCAPE then all would have to be escaped, so the 
+	 presentation format would be twice as long as the spec.
+
+	 daemon->namebuff was previously allocated by the option-reading
+	 code before we knew if we're in DNSSEC mode, so reallocate here. */
+      free(daemon->namebuff);
+      daemon->namebuff = safe_malloc(MAXDNAME * 2);
+      daemon->keyname = safe_malloc(MAXDNAME * 2);
+      daemon->workspacename = safe_malloc(MAXDNAME * 2);
+    }
+#endif
+
+#ifdef HAVE_DHCP
+  if (!daemon->lease_file)
+    {
+      if (daemon->dhcp || daemon->dhcp6)
+	daemon->lease_file = LEASEFILE;
+    }
+#endif
+  
+  /* Close any file descriptors we inherited apart from std{in|out|err} 
+     
+     Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist,
+     otherwise file descriptors we create can end up being 0, 1, or 2 
+     and then get accidentally closed later when we make 0, 1, and 2 
+     open to /dev/null. Normally we'll be started with 0, 1 and 2 open, 
+     but it's not guaranteed. By opening /dev/null three times, we 
+     ensure that we're not using those fds for real stuff. */
+  for (i = 0; i < max_fd; i++)
+    if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
+      close(i);
+    else
+      open("/dev/null", O_RDWR); 
+
+#ifndef HAVE_LINUX_NETWORK
+#  if !(defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
+  if (!option_bool(OPT_NOWILD))
+    {
+      bind_fallback = 1;
+      set_option_bool(OPT_NOWILD);
+    }
+#  endif
+  
+  /* -- bind-dynamic not supported on !Linux, fall back to --bind-interfaces */
+  if (option_bool(OPT_CLEVERBIND))
+    {
+      bind_fallback = 1;
+      set_option_bool(OPT_NOWILD);
+      reset_option_bool(OPT_CLEVERBIND);
+    }
+#endif
+
+#ifndef HAVE_INOTIFY
+  if (daemon->dynamic_dirs)
+    die(_("dhcp-hostsdir, dhcp-optsdir and hostsdir are not supported on this platform"), NULL, EC_BADCONF);
+#endif
+  
+  if (option_bool(OPT_DNSSEC_VALID))
+    {
+#ifdef HAVE_DNSSEC
+      struct ds_config *ds;
+
+      /* Must have at least a root trust anchor, or the DNSSEC code
+	 can loop forever. */
+      for (ds = daemon->ds; ds; ds = ds->next)
+	if (ds->name[0] == 0)
+	  break;
+
+      if (!ds)
+	die(_("no root trust anchor provided for DNSSEC"), NULL, EC_BADCONF);
+      
+      if (daemon->cachesize < CACHESIZ)
+	die(_("cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
+#else 
+      die(_("DNSSEC not available: set HAVE_DNSSEC in src/config.h"), NULL, EC_BADCONF);
+#endif
+    }
+
+#ifndef HAVE_TFTP
+  if (option_bool(OPT_TFTP))
+    die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
+#endif
+
+#ifdef HAVE_CONNTRACK
+  if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
+    die (_("cannot use --conntrack AND --query-port"), NULL, EC_BADCONF); 
+#else
+  if (option_bool(OPT_CONNTRACK))
+    die(_("conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
+#endif
+
+#ifdef HAVE_SOLARIS_NETWORK
+  if (daemon->max_logs != 0)
+    die(_("asynchronous logging is not available under Solaris"), NULL, EC_BADCONF);
+#endif
+  
+#ifdef __ANDROID__
+  if (daemon->max_logs != 0)
+    die(_("asynchronous logging is not available under Android"), NULL, EC_BADCONF);
+#endif
+
+#ifndef HAVE_AUTH
+  if (daemon->authserver)
+    die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
+#endif
+
+#ifndef HAVE_LOOP
+  if (option_bool(OPT_LOOP_DETECT))
+    die(_("loop detection not available: set HAVE_LOOP in src/config.h"), NULL, EC_BADCONF);
+#endif
+
+  if (daemon->max_port != MAX_PORT && daemon->min_port == 0)
+    daemon->min_port = 1024u;
+
+  if (daemon->max_port < daemon->min_port)
+    die(_("max_port cannot be smaller than min_port"), NULL, EC_BADCONF);
+
+  now = dnsmasq_time();
+
+  /* Create a serial at startup if not configured. */
+  if (daemon->authinterface && daemon->soa_sn == 0)
+#ifdef HAVE_BROKEN_RTC
+    die(_("zone serial must be configured in --auth-soa"), NULL, EC_BADCONF);
+#else
+  daemon->soa_sn = now;
+#endif
+  
+#ifdef HAVE_DHCP6
+  if (daemon->dhcp6)
+    {
+      daemon->doing_ra = option_bool(OPT_RA);
+      
+      for (context = daemon->dhcp6; context; context = context->next)
+	{
+	  if (context->flags & CONTEXT_DHCP)
+	    daemon->doing_dhcp6 = 1;
+	  if (context->flags & CONTEXT_RA)
+	    daemon->doing_ra = 1;
+#if !defined(HAVE_LINUX_NETWORK) && !defined(HAVE_BSD_NETWORK)
+	  if (context->flags & CONTEXT_TEMPLATE)
+	    die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
+#endif 
+	}
+    }
+#endif
+  
+#ifdef HAVE_DHCP
+  /* Note that order matters here, we must call lease_init before
+     creating any file descriptors which shouldn't be leaked
+     to the lease-script init process. We need to call common_init
+     before lease_init to allocate buffers it uses.
+     The script subsystem relies on DHCP buffers, hence the last two
+     conditions below. */  
+  if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || 
+      daemon->relay6 || option_bool(OPT_TFTP) || option_bool(OPT_SCRIPT_ARP))
+    {
+      dhcp_common_init();
+      if (daemon->dhcp || daemon->doing_dhcp6)
+	lease_init(now);
+    }
+  
+  if (daemon->dhcp || daemon->relay4)
+    dhcp_init();
+  
+#  ifdef HAVE_DHCP6
+  if (daemon->doing_ra || daemon->doing_dhcp6 || daemon->relay6)
+    ra_init(now);
+  
+  if (daemon->doing_dhcp6 || daemon->relay6)
+    dhcp6_init();
+#  endif
+
+#endif
+
+#ifdef HAVE_IPSET
+  if (daemon->ipsets)
+    ipset_init();
+#endif
+
+#if  defined(HAVE_LINUX_NETWORK)
+  netlink_init();
+#elif defined(HAVE_BSD_NETWORK)
+  route_init();
+#endif
+
+  if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
+    die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
+  
+  if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
+    die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
+  
+  if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND)) 
+    {
+      create_bound_listeners(1);
+      
+      if (!option_bool(OPT_CLEVERBIND))
+	for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
+	  if (if_tmp->name && !if_tmp->used)
+	    die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
+
+#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
+      /* after enumerate_interfaces()  */
+      bound_device = whichdevice();
+      
+      if (daemon->dhcp)
+	{
+	  if (!daemon->relay4 && bound_device)
+	    {
+	      bindtodevice(bound_device, daemon->dhcpfd);
+	      did_bind = 1;
+	    }
+	  if (daemon->enable_pxe && bound_device)
+	    {
+	      bindtodevice(bound_device, daemon->pxefd);
+	      did_bind = 1;
+	    }
+	}
+#endif
+
+#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
+      if (daemon->doing_dhcp6 && !daemon->relay6 && bound_device)
+	{
+	  bindtodevice(bound_device, daemon->dhcp6fd);
+	  did_bind = 1;
+	}
+#endif
+    }
+  else 
+    create_wildcard_listeners();
+ 
+#ifdef HAVE_DHCP6
+  /* after enumerate_interfaces() */
+  if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
+    join_multicast(1);
+
+  /* After netlink_init() and before create_helper() */
+  lease_make_duid(now);
+#endif
+  
+  if (daemon->port != 0)
+    {
+      cache_init();
+
+#ifdef HAVE_DNSSEC
+      blockdata_init();
+#endif
+    }
+
+#ifdef HAVE_INOTIFY
+  if (daemon->port != 0 || daemon->dhcp || daemon->doing_dhcp6)
+    inotify_dnsmasq_init();
+  else
+    daemon->inotifyfd = -1;
+#endif
+       
+  if (option_bool(OPT_DBUS))
+#ifdef HAVE_DBUS
+    {
+      char *err;
+      daemon->dbus = NULL;
+      daemon->watches = NULL;
+      if ((err = dbus_init()))
+	die(_("DBus error: %s"), err, EC_MISC);
+    }
+#else
+  die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
+#endif
+
+  if (daemon->port != 0)
+    pre_allocate_sfds();
+
+#if defined(HAVE_SCRIPT)
+  /* Note getpwnam returns static storage */
+  if ((daemon->dhcp || daemon->dhcp6) && 
+      daemon->scriptuser && 
+      (daemon->lease_change_command || daemon->luascript))
+    {
+      if ((ent_pw = getpwnam(daemon->scriptuser)))
+	{
+	  script_uid = ent_pw->pw_uid;
+	  script_gid = ent_pw->pw_gid;
+	 }
+      else
+	baduser = daemon->scriptuser;
+    }
+#endif
+  
+  if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
+    baduser = daemon->username;
+  else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
+    baduser = daemon->groupname;
+
+  if (baduser)
+    die(_("unknown user or group: %s"), baduser, EC_BADCONF);
+
+  /* implement group defaults, "dip" if available, or group associated with uid */
+  if (!daemon->group_set && !gp)
+    {
+      if (!(gp = getgrnam(CHGRP)) && ent_pw)
+	gp = getgrgid(ent_pw->pw_gid);
+      
+      /* for error message */
+      if (gp)
+	daemon->groupname = gp->gr_name; 
+    }
+
+#if defined(HAVE_LINUX_NETWORK)
+  /* determine capability API version here, while we can still
+     call safe_malloc */
+  if (ent_pw && ent_pw->pw_uid != 0)
+    {
+      int capsize = 1; /* for header version 1 */
+      hdr = safe_malloc(sizeof(*hdr));
+
+      /* find version supported by kernel */
+      memset(hdr, 0, sizeof(*hdr));
+      capget(hdr, NULL);
+      
+      if (hdr->version != LINUX_CAPABILITY_VERSION_1)
+	{
+	  /* if unknown version, use largest supported version (3) */
+	  if (hdr->version != LINUX_CAPABILITY_VERSION_2)
+	    hdr->version = LINUX_CAPABILITY_VERSION_3;
+	  capsize = 2;
+	}
+      
+      data = safe_malloc(sizeof(*data) * capsize);
+      memset(data, 0, sizeof(*data) * capsize);
+    }
+#endif
+
+  /* Use a pipe to carry signals and other events back to the event loop 
+     in a race-free manner and another to carry errors to daemon-invoking process */
+  safe_pipe(pipefd, 1);
+  
+  piperead = pipefd[0];
+  pipewrite = pipefd[1];
+  /* prime the pipe to load stuff first time. */
+  send_event(pipewrite, EVENT_INIT, 0, NULL); 
+
+  err_pipe[1] = -1;
+  
+  if (!option_bool(OPT_DEBUG))   
+    {
+      /* The following code "daemonizes" the process. 
+	 See Stevens section 12.4 */
+      
+      if (chdir("/") != 0)
+	die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC); 
+
+#ifndef NO_FORK      
+      if (!option_bool(OPT_NO_FORK))
+	{
+	  pid_t pid;
+	  
+	  /* pipe to carry errors back to original process.
+	     When startup is complete we close this and the process terminates. */
+	  safe_pipe(err_pipe, 0);
+	  
+	  if ((pid = fork()) == -1)
+	    /* fd == -1 since we've not forked, never returns. */
+	    send_event(-1, EVENT_FORK_ERR, errno, NULL);
+	   
+	  if (pid != 0)
+	    {
+	      struct event_desc ev;
+	      char *msg;
+
+	      /* close our copy of write-end */
+	      while (retry_send(close(err_pipe[1])));
+	      
+	      /* check for errors after the fork */
+	      if (read_event(err_pipe[0], &ev, &msg))
+		fatal_event(&ev, msg);
+	      
+	      _exit(EC_GOOD);
+	    } 
+	  
+	  while (retry_send(close(err_pipe[0])));
+
+	  /* NO calls to die() from here on. */
+	  
+	  setsid();
+	 
+	  if ((pid = fork()) == -1)
+	    send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
+	 
+	  if (pid != 0)
+	    _exit(0);
+	}
+#endif
+            
+      /* write pidfile _after_ forking ! */
+      if (daemon->runfile)
+	{
+	  int fd, err = 0;
+
+	  sprintf(daemon->namebuff, "%d\n", (int) getpid());
+
+	  /* Explanation: Some installations of dnsmasq (eg Debian/Ubuntu) locate the pid-file
+	     in a directory which is writable by the non-privileged user that dnsmasq runs as. This
+	     allows the daemon to delete the file as part of its shutdown. This is a security hole to the 
+	     extent that an attacker running as the unprivileged  user could replace the pidfile with a 
+	     symlink, and have the target of that symlink overwritten as root next time dnsmasq starts. 
+
+	     The following code first deletes any existing file, and then opens it with the O_EXCL flag,
+	     ensuring that the open() fails should there be any existing file (because the unlink() failed, 
+	     or an attacker exploited the race between unlink() and open()). This ensures that no symlink
+	     attack can succeed. 
+
+	     Any compromise of the non-privileged user still theoretically allows the pid-file to be
+	     replaced whilst dnsmasq is running. The worst that could allow is that the usual 
+	     "shutdown dnsmasq" shell command could be tricked into stopping any other process.
+
+	     Note that if dnsmasq is started as non-root (eg for testing) it silently ignores 
+	     failure to write the pid-file.
+	  */
+
+	  unlink(daemon->runfile); 
+	  
+	  if ((fd = open(daemon->runfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)) == -1)
+	    {
+	      /* only complain if started as root */
+	      if (getuid() == 0)
+		err = 1;
+	    }
+	  else
+	    {
+	      if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
+		err = 1;
+	      else 
+		{
+		  while (retry_send(close(fd)));
+		  if (errno != 0)
+		    err = 1;
+		}
+	    }
+
+	  if (err)
+	    {
+	      send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
+	      _exit(0);
+	    }
+	}
+    }
+  
+   log_err = log_start(ent_pw, err_pipe[1]);
+
+   if (!option_bool(OPT_DEBUG)) 
+     {       
+       /* open  stdout etc to /dev/null */
+       int nullfd = open("/dev/null", O_RDWR);
+       if (nullfd != -1)
+	 {
+	   dup2(nullfd, STDOUT_FILENO);
+	   dup2(nullfd, STDERR_FILENO);
+	   dup2(nullfd, STDIN_FILENO);
+	   close(nullfd);
+	 }
+     }
+   
+   /* if we are to run scripts, we need to fork a helper before dropping root. */
+  daemon->helperfd = -1;
+#ifdef HAVE_SCRIPT 
+  if ((daemon->dhcp || daemon->dhcp6 || option_bool(OPT_TFTP) || option_bool(OPT_SCRIPT_ARP)) && 
+      (daemon->lease_change_command || daemon->luascript))
+      daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
+#endif
+
+  if (!option_bool(OPT_DEBUG) && getuid() == 0)   
+    {
+      int bad_capabilities = 0;
+      gid_t dummy;
+      
+      /* remove all supplementary groups */
+      if (gp && 
+	  (setgroups(0, &dummy) == -1 ||
+	   setgid(gp->gr_gid) == -1))
+	{
+	  send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
+	  _exit(0);
+	}
+  
+      if (ent_pw && ent_pw->pw_uid != 0)
+	{     
+#if defined(HAVE_LINUX_NETWORK)	  
+	  /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
+	     CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind 
+	     ports because of DAD, or we're doing it dynamically,
+	     we need CAP_NET_BIND_SERVICE too. */
+	  if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
+	    data->effective = data->permitted = data->inheritable =
+	      (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | 
+	      (1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
+	  else
+	    data->effective = data->permitted = data->inheritable =
+	      (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
+	  
+	  /* Tell kernel to not clear capabilities when dropping root */
+	  if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
+	    bad_capabilities = errno;
+			  
+#elif defined(HAVE_SOLARIS_NETWORK)
+	  /* http://developers.sun.com/solaris/articles/program_privileges.html */
+	  priv_set_t *priv_set;
+	  
+	  if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
+	      priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
+	      priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
+	    bad_capabilities = errno;
+
+	  if (priv_set && bad_capabilities == 0)
+	    {
+	      priv_inverse(priv_set);
+	  
+	      if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
+		bad_capabilities = errno;
+	    }
+
+	  if (priv_set)
+	    priv_freeset(priv_set);
+
+#endif    
+
+	  if (bad_capabilities != 0)
+	    {
+	      send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
+	      _exit(0);
+	    }
+	  
+	  /* finally drop root */
+	  if (setuid(ent_pw->pw_uid) == -1)
+	    {
+	      send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
+	      _exit(0);
+	    }     
+
+#ifdef HAVE_LINUX_NETWORK
+	  if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
+	   data->effective = data->permitted =
+	     (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
+	 else
+	   data->effective = data->permitted = 
+	     (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
+	  data->inheritable = 0;
+	  
+	  /* lose the setuid and setgid capabilities */
+	  if (capset(hdr, data) == -1)
+	    {
+	      send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
+	      _exit(0);
+	    }
+#endif
+	  
+	}
+    }
+  
+#ifdef HAVE_LINUX_NETWORK
+  free(hdr);
+  free(data);
+  if (option_bool(OPT_DEBUG)) 
+    prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
+#endif
+
+#ifdef HAVE_TFTP
+  if (option_bool(OPT_TFTP))
+    {
+      DIR *dir;
+      struct tftp_prefix *p;
+      
+      if (daemon->tftp_prefix)
+	{
+	  if (!((dir = opendir(daemon->tftp_prefix))))
+	    {
+	      tftp_prefix_missing = 1;
+	      if (!option_bool(OPT_TFTP_NO_FAIL))
+	        {
+	          send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
+	          _exit(0);
+	        }
+	    }
+	  else
+	    closedir(dir);
+	}
+
+      for (p = daemon->if_prefix; p; p = p->next)
+	{
+	  p->missing = 0;
+	  if (!((dir = opendir(p->prefix))))
+	    {
+	      p->missing = 1;
+	      if (!option_bool(OPT_TFTP_NO_FAIL))
+		{
+		  send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
+		  _exit(0);
+		}
+	    }
+	  else
+	    closedir(dir);
+	}
+    }
+#endif
+
+  if (daemon->port == 0)
+    my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
+  else 
+    {
+      if (daemon->cachesize != 0)
+	my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
+      else
+	my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
+
+      if (option_bool(OPT_LOCAL_SERVICE))
+	my_syslog(LOG_INFO, _("DNS service limited to local subnets"));
+    }
+  
+  my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
+  
+#ifdef HAVE_DBUS
+  if (option_bool(OPT_DBUS))
+    {
+      if (daemon->dbus)
+	my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
+      else
+	my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
+    }
+#endif
+
+#ifdef HAVE_DNSSEC
+  if (option_bool(OPT_DNSSEC_VALID))
+    {
+      int rc;
+
+      /* Delay creating the timestamp file until here, after we've changed user, so that
+	 it has the correct owner to allow updating the mtime later. 
+	 This means we have to report fatal errors via the pipe. */
+      if ((rc = setup_timestamp()) == -1)
+	{
+	  send_event(err_pipe[1], EVENT_TIME_ERR, errno, daemon->timestamp_file);
+	  _exit(0);
+	}
+      
+      my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
+      
+      daemon->dnssec_no_time_check = option_bool(OPT_DNSSEC_TIME);
+      if (option_bool(OPT_DNSSEC_TIME) && !daemon->back_to_the_future)
+	my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
+      
+      if (rc == 1)
+	my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until system time valid"));
+    }
+#endif
+
+  if (log_err != 0)
+    my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"), 
+	      daemon->log_file, strerror(log_err));
+  
+  if (bind_fallback)
+    my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
+
+  if (option_bool(OPT_NOWILD))
+    warn_bound_listeners();
+  else if (!option_bool(OPT_CLEVERBIND))
+    warn_wild_labels();
+
+  warn_int_names();
+  
+  if (!option_bool(OPT_NOWILD)) 
+    for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
+      if (if_tmp->name && !if_tmp->used)
+	my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
+   
+  if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
+    {
+      if (daemon->resolv_files && !daemon->resolv_files->is_default)
+	my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
+      daemon->resolv_files = NULL;
+      if (!daemon->servers)
+	my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
+    } 
+
+  if (daemon->max_logs != 0)
+    my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
+  
+
+#ifdef HAVE_DHCP
+  for (context = daemon->dhcp; context; context = context->next)
+    log_context(AF_INET, context);
+
+  for (relay = daemon->relay4; relay; relay = relay->next)
+    log_relay(AF_INET, relay);
+
+#  ifdef HAVE_DHCP6
+  for (context = daemon->dhcp6; context; context = context->next)
+    log_context(AF_INET6, context);
+
+  for (relay = daemon->relay6; relay; relay = relay->next)
+    log_relay(AF_INET6, relay);
+  
+  if (daemon->doing_dhcp6 || daemon->doing_ra)
+    dhcp_construct_contexts(now);
+  
+  if (option_bool(OPT_RA))
+    my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
+#  endif
+
+#  ifdef HAVE_LINUX_NETWORK
+  if (did_bind)
+    my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device);
+#  endif
+
+  /* after dhcp_construct_contexts */
+  if (daemon->dhcp || daemon->doing_dhcp6)
+    lease_find_interfaces(now);
+#endif
+
+#ifdef HAVE_TFTP
+  if (option_bool(OPT_TFTP))
+    {
+      struct tftp_prefix *p;
+
+      my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s", 
+		daemon->tftp_prefix ? _("root is ") : _("enabled"),
+		daemon->tftp_prefix ? daemon->tftp_prefix: "",
+		option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
+
+      if (tftp_prefix_missing)
+	my_syslog(MS_TFTP | LOG_WARNING, _("warning: %s inaccessible"), daemon->tftp_prefix);
+
+      for (p = daemon->if_prefix; p; p = p->next)
+	if (p->missing)
+	   my_syslog(MS_TFTP | LOG_WARNING, _("warning: TFTP directory %s inaccessible"), p->prefix);
+
+      /* This is a guess, it assumes that for small limits, 
+	 disjoint files might be served, but for large limits, 
+	 a single file will be sent to may clients (the file only needs
+	 one fd). */
+
+      max_fd -= 30; /* use other than TFTP */
+      
+      if (max_fd < 0)
+	max_fd = 5;
+      else if (max_fd < 100)
+	max_fd = max_fd/2;
+      else
+	max_fd = max_fd - 20;
+      
+      /* if we have to use a limited range of ports, 
+	 that will limit the number of transfers */
+      if (daemon->start_tftp_port != 0 &&
+	  daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
+	max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
+
+      if (daemon->tftp_max > max_fd)
+	{
+	  daemon->tftp_max = max_fd;
+	  my_syslog(MS_TFTP | LOG_WARNING, 
+		    _("restricting maximum simultaneous TFTP transfers to %d"), 
+		    daemon->tftp_max);
+	}
+    }
+#endif
+
+  /* finished start-up - release original process */
+  if (err_pipe[1] != -1)
+    while (retry_send(close(err_pipe[1])));
+  
+  if (daemon->port != 0)
+    check_servers();
+  
+  pid = getpid();
+  
+#ifdef HAVE_INOTIFY
+  /* Using inotify, have to select a resolv file at startup */
+  poll_resolv(1, 0, now);
+#endif
+  
+  while (1)
+    {
+      int t, timeout = -1;
+      
+      poll_reset();
+      
+      /* if we are out of resources, find how long we have to wait
+	 for some to come free, we'll loop around then and restart
+	 listening for queries */
+      if ((t = set_dns_listeners(now)) != 0)
+	timeout = t * 1000;
+
+      /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
+      if (daemon->tftp_trans ||
+	  (option_bool(OPT_DBUS) && !daemon->dbus))
+	timeout = 250;
+
+      /* Wake every second whilst waiting for DAD to complete */
+      else if (is_dad_listeners())
+	timeout = 1000;
+
+#ifdef HAVE_DBUS
+      set_dbus_listeners();
+#endif	
+  
+#ifdef HAVE_DHCP
+      if (daemon->dhcp || daemon->relay4)
+	{
+	  poll_listen(daemon->dhcpfd, POLLIN);
+	  if (daemon->pxefd != -1)
+	    poll_listen(daemon->pxefd, POLLIN);
+	}
+#endif
+
+#ifdef HAVE_DHCP6
+      if (daemon->doing_dhcp6 || daemon->relay6)
+	poll_listen(daemon->dhcp6fd, POLLIN);
+	
+      if (daemon->doing_ra)
+	poll_listen(daemon->icmp6fd, POLLIN); 
+#endif
+    
+#ifdef HAVE_INOTIFY
+      if (daemon->inotifyfd != -1)
+	poll_listen(daemon->inotifyfd, POLLIN);
+#endif
+
+#if defined(HAVE_LINUX_NETWORK)
+      poll_listen(daemon->netlinkfd, POLLIN);
+#elif defined(HAVE_BSD_NETWORK)
+      poll_listen(daemon->routefd, POLLIN);
+#endif
+      
+      poll_listen(piperead, POLLIN);
+
+#ifdef HAVE_SCRIPT
+#    ifdef HAVE_DHCP
+      while (helper_buf_empty() && do_script_run(now)); 
+#    endif
+
+      /* Refresh cache */
+      if (option_bool(OPT_SCRIPT_ARP))
+	find_mac(NULL, NULL, 0, now);
+      while (helper_buf_empty() && do_arp_script_run());
+
+#    ifdef HAVE_TFTP
+      while (helper_buf_empty() && do_tftp_script_run());
+#    endif
+
+      if (!helper_buf_empty())
+	poll_listen(daemon->helperfd, POLLOUT);
+#else
+      /* need this for other side-effects */
+#    ifdef HAVE_DHCP
+      while (do_script_run(now));
+#    endif
+
+      while (do_arp_script_run());
+
+#    ifdef HAVE_TFTP 
+      while (do_tftp_script_run());
+#    endif
+
+#endif
+
+   
+      /* must do this just before select(), when we know no
+	 more calls to my_syslog() can occur */
+      set_log_writer();
+      
+      if (do_poll(timeout) < 0)
+	continue;
+      
+      now = dnsmasq_time();
+
+      check_log_writer(0);
+
+      /* prime. */
+      enumerate_interfaces(1);
+
+      /* Check the interfaces to see if any have exited DAD state
+	 and if so, bind the address. */
+      if (is_dad_listeners())
+	{
+	  enumerate_interfaces(0);
+	  /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
+	  create_bound_listeners(0);
+	  warn_bound_listeners();
+	}
+
+#if defined(HAVE_LINUX_NETWORK)
+      if (poll_check(daemon->netlinkfd, POLLIN))
+	netlink_multicast();
+#elif defined(HAVE_BSD_NETWORK)
+      if (poll_check(daemon->routefd, POLLIN))
+	route_sock();
+#endif
+
+#ifdef HAVE_INOTIFY
+      if  (daemon->inotifyfd != -1 && poll_check(daemon->inotifyfd, POLLIN) && inotify_check(now))
+	{
+	  if (daemon->port != 0 && !option_bool(OPT_NO_POLL))
+	    poll_resolv(1, 1, now);
+	} 	  
+#else
+      /* Check for changes to resolv files once per second max. */
+      /* Don't go silent for long periods if the clock goes backwards. */
+      if (daemon->last_resolv == 0 || 
+	  difftime(now, daemon->last_resolv) > 1.0 || 
+	  difftime(now, daemon->last_resolv) < -1.0)
+	{
+	  /* poll_resolv doesn't need to reload first time through, since 
+	     that's queued anyway. */
+
+	  poll_resolv(0, daemon->last_resolv != 0, now); 	  
+	  daemon->last_resolv = now;
+	}
+#endif
+
+      if (poll_check(piperead, POLLIN))
+	async_event(piperead, now);
+      
+#ifdef HAVE_DBUS
+      /* if we didn't create a DBus connection, retry now. */ 
+     if (option_bool(OPT_DBUS) && !daemon->dbus)
+	{
+	  char *err;
+	  if ((err = dbus_init()))
+	    my_syslog(LOG_WARNING, _("DBus error: %s"), err);
+	  if (daemon->dbus)
+	    my_syslog(LOG_INFO, _("connected to system DBus"));
+	}
+      check_dbus_listeners();
+#endif
+      
+      check_dns_listeners(now);
+
+#ifdef HAVE_TFTP
+      check_tftp_listeners(now);
+#endif      
+
+#ifdef HAVE_DHCP
+      if (daemon->dhcp || daemon->relay4)
+	{
+	  if (poll_check(daemon->dhcpfd, POLLIN))
+	    dhcp_packet(now, 0);
+	  if (daemon->pxefd != -1 && poll_check(daemon->pxefd, POLLIN))
+	    dhcp_packet(now, 1);
+	}
+
+#ifdef HAVE_DHCP6
+      if ((daemon->doing_dhcp6 || daemon->relay6) && poll_check(daemon->dhcp6fd, POLLIN))
+	dhcp6_packet(now);
+
+      if (daemon->doing_ra && poll_check(daemon->icmp6fd, POLLIN))
+	icmp6_packet(now);
+#endif
+
+#  ifdef HAVE_SCRIPT
+      if (daemon->helperfd != -1 && poll_check(daemon->helperfd, POLLOUT))
+	helper_write();
+#  endif
+#endif
+
+    }
+}
+
+static void sig_handler(int sig)
+{
+  if (pid == 0)
+    {
+      /* ignore anything other than TERM during startup
+	 and in helper proc. (helper ignore TERM too) */
+      if (sig == SIGTERM)
+	exit(EC_MISC);
+    }
+  else if (pid != getpid())
+    {
+      /* alarm is used to kill TCP children after a fixed time. */
+      if (sig == SIGALRM)
+	_exit(0);
+    }
+  else
+    {
+      /* master process */
+      int event, errsave = errno;
+      
+      if (sig == SIGHUP)
+	event = EVENT_RELOAD;
+      else if (sig == SIGCHLD)
+	event = EVENT_CHILD;
+      else if (sig == SIGALRM)
+	event = EVENT_ALARM;
+      else if (sig == SIGTERM)
+	event = EVENT_TERM;
+      else if (sig == SIGUSR1)
+	event = EVENT_DUMP;
+      else if (sig == SIGUSR2)
+	event = EVENT_REOPEN;
+      else
+	return;
+
+      send_event(pipewrite, event, 0, NULL); 
+      errno = errsave;
+    }
+}
+
+/* now == 0 -> queue immediate callback */
+void send_alarm(time_t event, time_t now)
+{
+  if (now == 0 || event != 0)
+    {
+      /* alarm(0) or alarm(-ve) doesn't do what we want.... */
+      if ((now == 0 || difftime(event, now) <= 0.0))
+	send_event(pipewrite, EVENT_ALARM, 0, NULL);
+      else 
+	alarm((unsigned)difftime(event, now)); 
+    }
+}
+
+void queue_event(int event)
+{
+  send_event(pipewrite, event, 0, NULL);
+}
+
+void send_event(int fd, int event, int data, char *msg)
+{
+  struct event_desc ev;
+  struct iovec iov[2];
+
+  ev.event = event;
+  ev.data = data;
+  ev.msg_sz = msg ? strlen(msg) : 0;
+  
+  iov[0].iov_base = &ev;
+  iov[0].iov_len = sizeof(ev);
+  iov[1].iov_base = msg;
+  iov[1].iov_len = ev.msg_sz;
+  
+  /* error pipe, debug mode. */
+  if (fd == -1)
+    fatal_event(&ev, msg);
+  else
+    /* pipe is non-blocking and struct event_desc is smaller than
+       PIPE_BUF, so this either fails or writes everything */
+    while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
+}
+
+/* NOTE: the memory used to return msg is leaked: use msgs in events only
+   to describe fatal errors. */
+static int read_event(int fd, struct event_desc *evp, char **msg)
+{
+  char *buf;
+
+  if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
+    return 0;
+  
+  *msg = NULL;
+  
+  if (evp->msg_sz != 0 && 
+      (buf = malloc(evp->msg_sz + 1)) &&
+      read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
+    {
+      buf[evp->msg_sz] = 0;
+      *msg = buf;
+    }
+
+  return 1;
+}
+    
+static void fatal_event(struct event_desc *ev, char *msg)
+{
+  errno = ev->data;
+  
+  switch (ev->event)
+    {
+    case EVENT_DIE:
+      exit(0);
+
+    case EVENT_FORK_ERR:
+      die(_("cannot fork into background: %s"), NULL, EC_MISC);
+  
+    case EVENT_PIPE_ERR:
+      die(_("failed to create helper: %s"), NULL, EC_MISC);
+  
+    case EVENT_CAP_ERR:
+      die(_("setting capabilities failed: %s"), NULL, EC_MISC);
+
+    case EVENT_USER_ERR:
+      die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
+
+    case EVENT_GROUP_ERR:
+      die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
+      
+    case EVENT_PIDFILE:
+      die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
+
+    case EVENT_LOG_ERR:
+      die(_("cannot open log %s: %s"), msg, EC_FILE);
+    
+    case EVENT_LUA_ERR:
+      die(_("failed to load Lua script: %s"), msg, EC_MISC);
+
+    case EVENT_TFTP_ERR:
+      die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
+    
+    case EVENT_TIME_ERR:
+      die(_("cannot create timestamp file %s: %s" ), msg, EC_BADCONF);
+    }
+}	
+      
+static void async_event(int pipe, time_t now)
+{
+  pid_t p;
+  struct event_desc ev;
+  int i, check = 0;
+  char *msg;
+  
+  /* NOTE: the memory used to return msg is leaked: use msgs in events only
+     to describe fatal errors. */
+  
+  if (read_event(pipe, &ev, &msg))
+    switch (ev.event)
+      {
+      case EVENT_RELOAD:
+	daemon->soa_sn++; /* Bump zone serial, as it may have changed. */
+
+#ifdef HAVE_DNSSEC
+	if (daemon->dnssec_no_time_check && option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
+	  {
+	    my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
+	    daemon->dnssec_no_time_check = 0;
+	  } 
+#endif
+	/* fall through */
+	
+      case EVENT_INIT:
+	clear_cache_and_reload(now);
+	
+	if (daemon->port != 0)
+	  {
+	    if (daemon->resolv_files && option_bool(OPT_NO_POLL))
+	      {
+		reload_servers(daemon->resolv_files->name);
+		check = 1;
+	      }
+
+	    if (daemon->servers_file)
+	      {
+		read_servers_file();
+		check = 1;
+	      }
+
+	    if (check)
+	      check_servers();
+	  }
+
+#ifdef HAVE_DHCP
+	rerun_scripts();
+#endif
+	break;
+	
+      case EVENT_DUMP:
+	if (daemon->port != 0)
+	  dump_cache(now);
+	break;
+	
+      case EVENT_ALARM:
+#ifdef HAVE_DHCP
+	if (daemon->dhcp || daemon->doing_dhcp6)
+	  {
+	    lease_prune(NULL, now);
+	    lease_update_file(now);
+	  }
+#ifdef HAVE_DHCP6
+	else if (daemon->doing_ra)
+	  /* Not doing DHCP, so no lease system, manage alarms for ra only */
+	    send_alarm(periodic_ra(now), now);
+#endif
+#endif
+	break;
+		
+      case EVENT_CHILD:
+	/* See Stevens 5.10 */
+	while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
+	  if (p == -1)
+	    {
+	      if (errno != EINTR)
+		break;
+	    }      
+	  else 
+	    for (i = 0 ; i < MAX_PROCS; i++)
+	      if (daemon->tcp_pids[i] == p)
+		daemon->tcp_pids[i] = 0;
+	break;
+	
+#if defined(HAVE_SCRIPT)	
+      case EVENT_KILLED:
+	my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
+	break;
+
+      case EVENT_EXITED:
+	my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
+	break;
+
+      case EVENT_EXEC_ERR:
+	my_syslog(LOG_ERR, _("failed to execute %s: %s"), 
+		  daemon->lease_change_command, strerror(ev.data));
+	break;
+
+      case EVENT_SCRIPT_LOG:
+	my_syslog(MS_SCRIPT | LOG_DEBUG, "%s", msg ? msg : "");
+        free(msg);
+	msg = NULL;
+	break;
+
+	/* necessary for fatal errors in helper */
+      case EVENT_USER_ERR:
+      case EVENT_DIE:
+      case EVENT_LUA_ERR:
+	fatal_event(&ev, msg);
+	break;
+#endif
+
+      case EVENT_REOPEN:
+	/* Note: this may leave TCP-handling processes with the old file still open.
+	   Since any such process will die in CHILD_LIFETIME or probably much sooner,
+	   we leave them logging to the old file. */
+	if (daemon->log_file != NULL)
+	  log_reopen(daemon->log_file);
+	break;
+
+      case EVENT_NEWADDR:
+	newaddress(now);
+	break;
+
+      case EVENT_NEWROUTE:
+	resend_query();
+	/* Force re-reading resolv file right now, for luck. */
+	poll_resolv(0, 1, now);
+	break;
+
+      case EVENT_TERM:
+	/* Knock all our children on the head. */
+	for (i = 0; i < MAX_PROCS; i++)
+	  if (daemon->tcp_pids[i] != 0)
+	    kill(daemon->tcp_pids[i], SIGALRM);
+	
+#if defined(HAVE_SCRIPT) && defined(HAVE_DHCP)
+	/* handle pending lease transitions */
+	if (daemon->helperfd != -1)
+	  {
+	    /* block in writes until all done */
+	    if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
+	      fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK); 
+	    do {
+	      helper_write();
+	    } while (!helper_buf_empty() || do_script_run(now));
+	    while (retry_send(close(daemon->helperfd)));
+	  }
+#endif
+	
+	if (daemon->lease_stream)
+	  fclose(daemon->lease_stream);
+
+#ifdef HAVE_DNSSEC
+	/* update timestamp file on TERM if time is considered valid */
+	if (daemon->back_to_the_future)
+	  {
+	     if (utimes(daemon->timestamp_file, NULL) == -1)
+		my_syslog(LOG_ERR, _("failed to update mtime on %s: %s"), daemon->timestamp_file, strerror(errno));
+	  }
+#endif
+
+	if (daemon->runfile)
+	  unlink(daemon->runfile);
+	
+	my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
+	flush_log();
+	exit(EC_GOOD);
+      }
+}
+
+static void poll_resolv(int force, int do_reload, time_t now)
+{
+  struct resolvc *res, *latest;
+  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. */
+
+  if (daemon->port == 0 || option_bool(OPT_NO_POLL))
+    return;
+  
+  for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
+    if (stat(res->name, &statbuf) == -1)
+      {
+	if (force)
+	  {
+	    res->mtime = 0; 
+	    continue;
+	  }
+
+	if (!res->logged)
+	  my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
+	res->logged = 1;
+	
+	if (res->mtime != 0)
+	  { 
+	    /* existing file evaporated, force selection of the latest
+	       file even if its mtime hasn't changed since we last looked */
+	    poll_resolv(1, do_reload, now);
+	    return;
+	  }
+      }
+    else
+      {
+	res->logged = 0;
+	if (force || (statbuf.st_mtime != res->mtime))
+          {
+            res->mtime = statbuf.st_mtime;
+	    if (difftime(statbuf.st_mtime, last_change) > 0.0)
+	      {
+		last_change = statbuf.st_mtime;
+		latest = res;
+	      }
+	  }
+      }
+  
+  if (latest)
+    {
+      static int warned = 0;
+      if (reload_servers(latest->name))
+	{
+	  my_syslog(LOG_INFO, _("reading %s"), latest->name);
+	  warned = 0;
+	  check_servers();
+	  if (option_bool(OPT_RELOAD) && do_reload)
+	    clear_cache_and_reload(now);
+	}
+      else 
+	{
+	  latest->mtime = 0;
+	  if (!warned)
+	    {
+	      my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
+	      warned = 1;
+	    }
+	}
+    }
+}       
+
+void clear_cache_and_reload(time_t now)
+{
+  (void)now;
+
+  if (daemon->port != 0)
+    cache_reload();
+  
+#ifdef HAVE_DHCP
+  if (daemon->dhcp || daemon->doing_dhcp6)
+    {
+      if (option_bool(OPT_ETHERS))
+	dhcp_read_ethers();
+      reread_dhcp();
+#ifdef HAVE_INOTIFY
+      set_dynamic_inotify(AH_DHCP_HST | AH_DHCP_OPT, 0, NULL, 0);
+#endif
+      dhcp_update_configs(daemon->dhcp_conf);
+      lease_update_from_configs(); 
+      lease_update_file(now); 
+      lease_update_dns(1);
+    }
+#ifdef HAVE_DHCP6
+  else if (daemon->doing_ra)
+    /* Not doing DHCP, so no lease system, manage 
+       alarms for ra only */
+    send_alarm(periodic_ra(now), now);
+#endif
+#endif
+}
+
+static int set_dns_listeners(time_t now)
+{
+  struct serverfd *serverfdp;
+  struct listener *listener;
+  int wait = 0, i;
+  
+#ifdef HAVE_TFTP
+  int  tftp = 0;
+  struct tftp_transfer *transfer;
+  for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
+    {
+      tftp++;
+      poll_listen(transfer->sockfd, POLLIN);
+    }
+#endif
+  
+  /* will we be able to get memory? */
+  if (daemon->port != 0)
+    get_new_frec(now, &wait, 0);
+  
+  for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
+    poll_listen(serverfdp->fd, POLLIN);
+    
+  if (daemon->port != 0 && !daemon->osport)
+    for (i = 0; i < RANDOM_SOCKS; i++)
+      if (daemon->randomsocks[i].refcount != 0)
+	poll_listen(daemon->randomsocks[i].fd, POLLIN);
+	  
+  for (listener = daemon->listeners; listener; listener = listener->next)
+    {
+      /* only listen for queries if we have resources */
+      if (listener->fd != -1 && wait == 0)
+	poll_listen(listener->fd, POLLIN);
+	
+      /* death of a child goes through the select loop, so
+	 we don't need to explicitly arrange to wake up here */
+      if  (listener->tcpfd != -1)
+	for (i = 0; i < MAX_PROCS; i++)
+	  if (daemon->tcp_pids[i] == 0)
+	    {
+	      poll_listen(listener->tcpfd, POLLIN);
+	      break;
+	    }
+
+#ifdef HAVE_TFTP
+      if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
+	poll_listen(listener->tftpfd, POLLIN);
+#endif
+
+    }
+  
+  return wait;
+}
+
+static void check_dns_listeners(time_t now)
+{
+  struct serverfd *serverfdp;
+  struct listener *listener;
+  int i;
+
+  for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
+    if (poll_check(serverfdp->fd, POLLIN))
+      reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
+  
+  if (daemon->port != 0 && !daemon->osport)
+    for (i = 0; i < RANDOM_SOCKS; i++)
+      if (daemon->randomsocks[i].refcount != 0 && 
+	  poll_check(daemon->randomsocks[i].fd, POLLIN))
+	reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
+  
+  for (listener = daemon->listeners; listener; listener = listener->next)
+    {
+      if (listener->fd != -1 && poll_check(listener->fd, POLLIN))
+	receive_query(listener, now); 
+      
+#ifdef HAVE_TFTP     
+      if (listener->tftpfd != -1 && poll_check(listener->tftpfd, POLLIN))
+	tftp_request(listener, now);
+#endif
+
+      if (listener->tcpfd != -1 && poll_check(listener->tcpfd, POLLIN))
+	{
+	  int confd, client_ok = 1;
+	  struct irec *iface = NULL;
+	  pid_t p;
+	  union mysockaddr tcp_addr;
+	  socklen_t tcp_len = sizeof(union mysockaddr);
+
+	  while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
+	  
+	  if (confd == -1)
+	    continue;
+	  
+	  if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
+	    {
+	      while (retry_send(close(confd)));
+	      continue;
+	    }
+	  
+	  /* Make sure that the interface list is up-to-date.
+	     
+	     We do this here as we may need the results below, and
+	     the DNS code needs them for --interface-name stuff.
+
+	     Multiple calls to enumerate_interfaces() per select loop are
+	     inhibited, so calls to it in the child process (which doesn't select())
+	     have no effect. This avoids two processes reading from the same
+	     netlink fd and screwing the pooch entirely.
+	  */
+ 
+	  enumerate_interfaces(0);
+	  
+	  if (option_bool(OPT_NOWILD))
+	    iface = listener->iface; /* May be NULL */
+	  else 
+	    {
+	      int if_index;
+	      char intr_name[IF_NAMESIZE];
+	      
+	      /* if we can find the arrival interface, check it's one that's allowed */
+	      if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
+		  indextoname(listener->tcpfd, if_index, intr_name))
+		{
+		  struct all_addr addr;
+		  addr.addr.addr4 = tcp_addr.in.sin_addr;
+#ifdef HAVE_IPV6
+		  if (tcp_addr.sa.sa_family == AF_INET6)
+		    addr.addr.addr6 = tcp_addr.in6.sin6_addr;
+#endif
+		  
+		  for (iface = daemon->interfaces; iface; iface = iface->next)
+		    if (iface->index == if_index)
+		      break;
+		  
+		  if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
+		    client_ok = 0;
+		}
+	      
+	      if (option_bool(OPT_CLEVERBIND))
+		iface = listener->iface; /* May be NULL */
+	      else
+		{
+		  /* Check for allowed interfaces when binding the wildcard address:
+		     we do this by looking for an interface with the same address as 
+		     the local address of the TCP connection, then looking to see if that's
+		     an allowed interface. As a side effect, we get the netmask of the
+		     interface too, for localisation. */
+		  
+		  for (iface = daemon->interfaces; iface; iface = iface->next)
+		    if (sockaddr_isequal(&iface->addr, &tcp_addr))
+		      break;
+		  
+		  if (!iface)
+		    client_ok = 0;
+		}
+	    }
+	  
+	  if (!client_ok)
+	    {
+	      shutdown(confd, SHUT_RDWR);
+	      while (retry_send(close(confd)));
+	    }
+#ifndef NO_FORK
+	  else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
+	    {
+	      if (p != -1)
+		{
+		  int i;
+		  for (i = 0; i < MAX_PROCS; i++)
+		    if (daemon->tcp_pids[i] == 0)
+		      {
+			daemon->tcp_pids[i] = p;
+			break;
+		      }
+		}
+	      while (retry_send(close(confd)));
+
+	      /* The child can use up to TCP_MAX_QUERIES ids, so skip that many. */
+	      daemon->log_id += TCP_MAX_QUERIES;
+	    }
+#endif
+	  else
+	    {
+	      unsigned char *buff;
+	      struct server *s; 
+	      int flags;
+	      struct in_addr netmask;
+	      int auth_dns;
+
+	      if (iface)
+		{
+		  netmask = iface->netmask;
+		  auth_dns = iface->dns_auth;
+		}
+	      else
+		{
+		  netmask.s_addr = 0;
+		  auth_dns = 0;
+		}
+
+#ifndef NO_FORK
+	      /* Arrange for SIGALRM after CHILD_LIFETIME seconds to
+		 terminate the process. */
+	      if (!option_bool(OPT_DEBUG))
+		alarm(CHILD_LIFETIME);
+#endif
+
+	      /* start with no upstream connections. */
+	      for (s = daemon->servers; s; s = s->next)
+		 s->tcpfd = -1; 
+	      
+	      /* The connected socket inherits non-blocking
+		 attribute from the listening socket. 
+		 Reset that here. */
+	      if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
+		fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
+	      
+	      buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
+	       
+	      shutdown(confd, SHUT_RDWR);
+	      while (retry_send(close(confd)));
+	      
+	      if (buff)
+		free(buff);
+	      
+	      for (s = daemon->servers; s; s = s->next)
+		if (s->tcpfd != -1)
+		  {
+		    shutdown(s->tcpfd, SHUT_RDWR);
+		    while (retry_send(close(s->tcpfd)));
+		  }
+#ifndef NO_FORK		   
+	      if (!option_bool(OPT_DEBUG))
+		{
+		  flush_log();
+		  _exit(0);
+		}
+#endif
+	    }
+	}
+    }
+}
+
+#ifdef HAVE_DHCP
+int make_icmp_sock(void)
+{
+  int fd;
+  int zeroopt = 0;
+
+  if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
+    {
+      if (!fix_fd(fd) ||
+	  setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
+	{
+	  close(fd);
+	  fd = -1;
+	}
+    }
+
+  return fd;
+}
+
+int icmp_ping(struct in_addr addr)
+{
+  /* Try and get an ICMP echo from a machine. */
+
+  int fd;
+  struct sockaddr_in saddr;
+  struct { 
+    struct ip ip;
+    struct icmp icmp;
+  } packet;
+  unsigned short id = rand16();
+  unsigned int i, j;
+  int gotreply = 0;
+
+#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
+  if ((fd = make_icmp_sock()) == -1)
+    return 0;
+#else
+  int opt = 2000;
+  fd = daemon->dhcp_icmp_fd;
+  setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
+#endif
+
+  saddr.sin_family = AF_INET;
+  saddr.sin_port = 0;
+  saddr.sin_addr = addr;
+#ifdef HAVE_SOCKADDR_SA_LEN
+  saddr.sin_len = sizeof(struct sockaddr_in);
+#endif
+  
+  memset(&packet.icmp, 0, sizeof(packet.icmp));
+  packet.icmp.icmp_type = ICMP_ECHO;
+  packet.icmp.icmp_id = id;
+  for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
+    j += ((u16 *)&packet.icmp)[i];
+  while (j>>16)
+    j = (j & 0xffff) + (j >> 16);  
+  packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
+  
+  while (retry_send(sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0, 
+			   (struct sockaddr *)&saddr, sizeof(saddr))));
+  
+  gotreply = delay_dhcp(dnsmasq_time(), PING_WAIT, fd, addr.s_addr, id);
+
+#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
+  while (retry_send(close(fd)));
+#else
+  opt = 1;
+  setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
+#endif
+
+  return gotreply;
+}
+
+int delay_dhcp(time_t start, int sec, int fd, uint32_t addr, unsigned short id)
+{
+  /* Delay processing DHCP packets for "sec" seconds counting from "start".
+     If "fd" is not -1 it will stop waiting if an ICMP echo reply is received
+     from "addr" with ICMP ID "id" and return 1 */
+
+  /* Note that whilst waiting, we check for
+     (and service) events on the DNS and TFTP  sockets, (so doing that
+     better not use any resources our caller has in use...)
+     but we remain deaf to signals or further DHCP packets. */
+
+  /* There can be a problem using dnsmasq_time() to end the loop, since
+     it's not monotonic, and can go backwards if the system clock is
+     tweaked, leading to the code getting stuck in this loop and
+     ignoring DHCP requests. To fix this, we check to see if select returned
+     as a result of a timeout rather than a socket becoming available. We
+     only allow this to happen as many times as it takes to get to the wait time
+     in quarter-second chunks. This provides a fallback way to end loop. */
+
+  int rc, timeout_count;
+  time_t now;
+
+  for (now = dnsmasq_time(), timeout_count = 0;
+       (difftime(now, start) <= (float)sec) && (timeout_count < sec * 4);)
+    {
+      poll_reset();
+      if (fd != -1)
+        poll_listen(fd, POLLIN);
+      set_dns_listeners(now);
+      set_log_writer();
+      
+#ifdef HAVE_DHCP6
+      if (daemon->doing_ra)
+	poll_listen(daemon->icmp6fd, POLLIN); 
+#endif
+      
+      rc = do_poll(250);
+      
+      if (rc < 0)
+	continue;
+      else if (rc == 0)
+	timeout_count++;
+
+      now = dnsmasq_time();
+      
+      check_log_writer(0);
+      check_dns_listeners(now);
+      
+#ifdef HAVE_DHCP6
+      if (daemon->doing_ra && poll_check(daemon->icmp6fd, POLLIN))
+	icmp6_packet(now);
+#endif
+      
+#ifdef HAVE_TFTP
+      check_tftp_listeners(now);
+#endif
+
+      if (fd != -1)
+        {
+          struct {
+            struct ip ip;
+            struct icmp icmp;
+          } packet;
+          struct sockaddr_in faddr;
+          socklen_t len = sizeof(faddr);
+	  
+          if (poll_check(fd, POLLIN) &&
+	      recvfrom(fd, &packet, sizeof(packet), 0, (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
+	      addr == faddr.sin_addr.s_addr &&
+	      packet.icmp.icmp_type == ICMP_ECHOREPLY &&
+	      packet.icmp.icmp_seq == 0 &&
+	      packet.icmp.icmp_id == id)
+	    return 1;
+	}
+    }
+
+  return 0;
+}
+#endif
+
+ 
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
new file mode 100755
index 0000000..dd16563
--- /dev/null
+++ b/src/dnsmasq.h
@@ -0,0 +1,1566 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#define COPYRIGHT "Copyright (c) 2000-2017 Simon Kelley"
+
+/* We do defines that influence behavior of stdio.h, so complain
+   if included too early. */
+#ifdef _STDIO_H
+#  error "Header file stdio.h included too early!"
+#endif 
+
+#ifndef NO_LARGEFILE
+/* Ensure we can use files >2GB (log files may grow this big) */
+#  define _LARGEFILE_SOURCE 1
+#  define _FILE_OFFSET_BITS 64
+#endif
+
+/* Get linux C library versions and define _GNU_SOURCE for kFreeBSD. */
+#if defined(__linux__) || defined(__GLIBC__)
+#  ifndef __ANDROID__
+#      define _GNU_SOURCE
+#  endif
+#  include <features.h> 
+#endif
+
+/* Need these defined early */
+#if defined(__sun) || defined(__sun__)
+#  define _XPG4_2
+#  define __EXTENSIONS__
+#endif
+
+/* get these before config.h  for IPv6 stuff... */
+#include <sys/types.h> 
+#include <sys/socket.h>
+
+#ifdef __APPLE__
+/* Define before netinet/in.h to select API. OSX Lion onwards. */
+#  define __APPLE_USE_RFC_3542
+#endif
+#include <netinet/in.h>
+
+/* Also needed before config.h. */
+#include <getopt.h>
+
+#include "config.h"
+#include "ip6addr.h"
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+typedef unsigned long long u64;
+
+#define countof(x)      (long)(sizeof(x) / sizeof(x[0]))
+#define MIN(a,b)        ((a) < (b) ? (a) : (b))
+
+#include "dns-protocol.h"
+#include "dhcp-protocol.h"
+#ifdef HAVE_DHCP6
+#include "dhcp6-protocol.h"
+#include "radv-protocol.h"
+#endif
+
+#define gettext_noop(S) (S)
+#ifndef LOCALEDIR
+#  define _(S) (S)
+#else
+#  include <libintl.h>
+#  include <locale.h>   
+#  define _(S) gettext(S)
+#endif
+
+#include <arpa/inet.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#if defined(HAVE_SOLARIS_NETWORK)
+#  include <sys/sockio.h>
+#endif
+#include <sys/poll.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <limits.h>
+#include <net/if.h>
+#if defined(HAVE_SOLARIS_NETWORK) && !defined(ifr_mtu)
+/* Some solaris net/if./h omit this. */
+#  define ifr_mtu  ifr_ifru.ifru_metric
+#endif
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <signal.h>
+#include <stddef.h>
+#include <time.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stdarg.h>
+#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__) || defined (__sun) || defined (__ANDROID__)
+#  include <netinet/if_ether.h>
+#else
+#  include <net/ethernet.h>
+#endif
+#include <net/if_arp.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <sys/uio.h>
+#include <syslog.h>
+#include <dirent.h>
+#ifndef HAVE_LINUX_NETWORK
+#  include <net/if_dl.h>
+#endif
+
+#if defined(HAVE_LINUX_NETWORK)
+#include <linux/capability.h>
+/* There doesn't seem to be a universally-available 
+   userspace header for these. */
+extern int capset(cap_user_header_t header, cap_user_data_t data);
+extern int capget(cap_user_header_t header, cap_user_data_t data);
+#define LINUX_CAPABILITY_VERSION_1  0x19980330
+#define LINUX_CAPABILITY_VERSION_2  0x20071026
+#define LINUX_CAPABILITY_VERSION_3  0x20080522
+
+#include <sys/prctl.h>
+#elif defined(HAVE_SOLARIS_NETWORK)
+#include <priv.h>
+#endif
+
+/* daemon is function in the C library.... */
+#define daemon dnsmasq_daemon
+
+/* Async event queue */
+struct event_desc {
+  int event, data, msg_sz;
+};
+
+#define EVENT_RELOAD     1
+#define EVENT_DUMP       2
+#define EVENT_ALARM      3
+#define EVENT_TERM       4
+#define EVENT_CHILD      5
+#define EVENT_REOPEN     6
+#define EVENT_EXITED     7
+#define EVENT_KILLED     8
+#define EVENT_EXEC_ERR   9
+#define EVENT_PIPE_ERR   10
+#define EVENT_USER_ERR   11
+#define EVENT_CAP_ERR    12
+#define EVENT_PIDFILE    13
+#define EVENT_HUSER_ERR  14
+#define EVENT_GROUP_ERR  15
+#define EVENT_DIE        16
+#define EVENT_LOG_ERR    17
+#define EVENT_FORK_ERR   18
+#define EVENT_LUA_ERR    19
+#define EVENT_TFTP_ERR   20
+#define EVENT_INIT       21
+#define EVENT_NEWADDR    22
+#define EVENT_NEWROUTE   23
+#define EVENT_TIME_ERR   24
+#define EVENT_SCRIPT_LOG 25
+
+/* Exit codes. */
+#define EC_GOOD        0
+#define EC_BADCONF     1
+#define EC_BADNET      2
+#define EC_FILE        3
+#define EC_NOMEM       4
+#define EC_MISC        5
+#define EC_INIT_OFFSET 10
+
+/* Trust the compiler dead-code eliminator.... */
+#define option_bool(x) (((x) < 32) ? daemon->options & (1u << (x)) : daemon->options2 & (1u << ((x) - 32)))
+
+#define OPT_BOGUSPRIV      0
+#define OPT_FILTER         1
+#define OPT_LOG            2
+#define OPT_SELFMX         3
+#define OPT_NO_HOSTS       4
+#define OPT_NO_POLL        5
+#define OPT_DEBUG          6
+#define OPT_ORDER          7
+#define OPT_NO_RESOLV      8
+#define OPT_EXPAND         9
+#define OPT_LOCALMX        10
+#define OPT_NO_NEG         11
+#define OPT_NODOTS_LOCAL   12
+#define OPT_NOWILD         13
+#define OPT_ETHERS         14
+#define OPT_RESOLV_DOMAIN  15
+#define OPT_NO_FORK        16
+#define OPT_AUTHORITATIVE  17
+#define OPT_LOCALISE       18
+#define OPT_DBUS           19
+#define OPT_DHCP_FQDN      20
+#define OPT_NO_PING        21
+#define OPT_LEASE_RO       22
+#define OPT_ALL_SERVERS    23
+#define OPT_RELOAD         24
+#define OPT_LOCAL_REBIND   25  
+#define OPT_TFTP_SECURE    26
+#define OPT_TFTP_NOBLOCK   27
+#define OPT_LOG_OPTS       28
+#define OPT_TFTP_APREF_IP  29
+#define OPT_NO_OVERRIDE    30
+#define OPT_NO_REBIND      31
+#define OPT_ADD_MAC        32
+#define OPT_DNSSEC_PROXY   33
+#define OPT_CONSEC_ADDR    34
+#define OPT_CONNTRACK      35
+#define OPT_FQDN_UPDATE    36
+#define OPT_RA             37
+#define OPT_TFTP_LC        38
+#define OPT_CLEVERBIND     39
+#define OPT_TFTP           40
+#define OPT_CLIENT_SUBNET  41
+#define OPT_QUIET_DHCP     42
+#define OPT_QUIET_DHCP6    43
+#define OPT_QUIET_RA	   44
+#define OPT_DNSSEC_VALID   45
+#define OPT_DNSSEC_TIME    46
+#define OPT_DNSSEC_DEBUG   47
+#define OPT_DNSSEC_NO_SIGN 48 
+#define OPT_LOCAL_SERVICE  49
+#define OPT_LOOP_DETECT    50
+#define OPT_EXTRALOG       51
+#define OPT_TFTP_NO_FAIL   52
+#define OPT_SCRIPT_ARP     53
+#define OPT_MAC_B64        54
+#define OPT_MAC_HEX        55
+#define OPT_TFTP_APREF_MAC 56
+#define OPT_LAST           57
+
+/* extra flags for my_syslog, we use a couple of facilities since they are known 
+   not to occupy the same bits as priorities, no matter how syslog.h is set up. */
+#define MS_TFTP   LOG_USER
+#define MS_DHCP   LOG_DAEMON
+#define MS_SCRIPT LOG_MAIL
+
+struct all_addr {
+  union {
+    struct in_addr addr4;
+#ifdef HAVE_IPV6
+    struct in6_addr addr6;
+#endif
+    /* for log_query */
+    struct {
+      unsigned short keytag, algo, digest;
+    } log; 
+    /* for cache_insert of DNSKEY, DS */
+    struct {
+      unsigned short class, type;
+    } dnssec;      
+  } addr;
+};
+
+struct bogus_addr {
+  struct in_addr addr;
+  struct bogus_addr *next;
+};
+
+/* dns doctor param */
+struct doctor {
+  struct in_addr in, end, out, mask;
+  struct doctor *next;
+};
+
+struct mx_srv_record {
+  char *name, *target;
+  int issrv, srvport, priority, weight;
+  unsigned int offset;
+  struct mx_srv_record *next;
+};
+
+struct naptr {
+  char *name, *replace, *regexp, *services, *flags;
+  unsigned int order, pref;
+  struct naptr *next;
+};
+
+#ifndef NO_ID
+#define TXT_STAT_CACHESIZE     1
+#define TXT_STAT_INSERTS       2
+#define TXT_STAT_EVICTIONS     3
+#define TXT_STAT_MISSES        4
+#define TXT_STAT_HITS          5
+#define TXT_STAT_AUTH          6
+#define TXT_STAT_SERVERS       7
+#endif
+
+struct txt_record {
+  char *name;
+  unsigned char *txt;
+  unsigned short class, len;
+  int stat;
+  struct txt_record *next;
+};
+
+struct ptr_record {
+  char *name, *ptr;
+  struct ptr_record *next;
+};
+
+struct cname {
+  int ttl, flag;
+  char *alias, *target;
+  struct cname *next, *targetp;
+}; 
+
+struct ds_config {
+  char *name, *digest;
+  int digestlen, class, algo, keytag, digest_type;
+  struct ds_config *next;
+};
+
+#define ADDRLIST_LITERAL 1
+#define ADDRLIST_IPV6    2
+#define ADDRLIST_REVONLY 4
+
+struct addrlist {
+  struct all_addr addr;
+  int flags, prefixlen; 
+  struct addrlist *next;
+};
+
+#define AUTH6     1
+#define AUTH4     2
+
+struct auth_zone {
+  char *domain;
+  struct auth_name_list {
+    char *name;
+    int flags;
+    struct auth_name_list *next;
+  } *interface_names;
+  struct addrlist *subnet;
+  struct addrlist *exclude;
+  struct auth_zone *next;
+};
+
+
+struct host_record {
+  int ttl;
+  struct name_list {
+    char *name;
+    struct name_list *next;
+  } *names;
+  struct in_addr addr;
+#ifdef HAVE_IPV6
+  struct in6_addr addr6;
+#endif
+  struct host_record *next;
+};
+
+struct interface_name {
+  char *name; /* domain name */
+  char *intr; /* interface name */
+  int family; /* AF_INET, AF_INET6 or zero for both */
+  struct addrlist *addr;
+  struct interface_name *next;
+};
+
+union bigname {
+  char name[MAXDNAME];
+  union bigname *next; /* freelist */
+};
+
+struct blockdata {
+  struct blockdata *next;
+  unsigned char key[KEYBLOCK_LEN];
+};
+
+struct crec { 
+  struct crec *next, *prev, *hash_next;
+  /* union is 16 bytes when doing IPv6, 8 bytes on 32 bit machines without IPv6 */
+  union {
+    struct all_addr addr;
+    struct {
+      union {
+	struct crec *cache;
+	struct interface_name *int_name;
+      } target;
+      unsigned int uid; /* 0 if union is interface-name */
+    } cname;
+    struct {
+      struct blockdata *keydata;
+      unsigned short keylen, flags, keytag;
+      unsigned char algo;
+    } key; 
+    struct {
+      struct blockdata *keydata;
+      unsigned short keylen, keytag;
+      unsigned char algo;
+      unsigned char digest; 
+    } ds; 
+  } addr;
+  time_t ttd; /* time to die */
+  /* used as class if DNSKEY/DS, index to source for F_HOSTS */
+  unsigned int uid; 
+  unsigned short flags;
+  union {
+    char sname[SMALLDNAME];
+    union bigname *bname;
+    char *namep;
+  } name;
+};
+
+#define F_IMMORTAL  (1u<<0)
+#define F_NAMEP     (1u<<1)
+#define F_REVERSE   (1u<<2)
+#define F_FORWARD   (1u<<3)
+#define F_DHCP      (1u<<4)
+#define F_NEG       (1u<<5)       
+#define F_HOSTS     (1u<<6)
+#define F_IPV4      (1u<<7)
+#define F_IPV6      (1u<<8)
+#define F_BIGNAME   (1u<<9)
+#define F_NXDOMAIN  (1u<<10)
+#define F_CNAME     (1u<<11)
+#define F_DNSKEY    (1u<<12)
+#define F_CONFIG    (1u<<13)
+#define F_DS        (1u<<14)
+#define F_DNSSECOK  (1u<<15)
+
+/* below here are only valid as args to log_query: cache
+   entries are limited to 16 bits */
+#define F_UPSTREAM  (1u<<16)
+#define F_RRNAME    (1u<<17)
+#define F_SERVER    (1u<<18)
+#define F_QUERY     (1u<<19)
+#define F_NOERR     (1u<<20)
+#define F_AUTH      (1u<<21)
+#define F_DNSSEC    (1u<<22)
+#define F_KEYTAG    (1u<<23)
+#define F_SECSTAT   (1u<<24)
+#define F_NO_RR     (1u<<25)
+#define F_IPSET     (1u<<26)
+#define F_NOEXTRA   (1u<<27)
+
+/* Values of uid in crecs with F_CONFIG bit set. */
+#define SRC_INTERFACE 0
+#define SRC_CONFIG    1
+#define SRC_HOSTS     2
+#define SRC_AH        3
+
+
+/* struct sockaddr is not large enough to hold any address,
+   and specifically not big enough to hold an IPv6 address.
+   Blech. Roll our own. */
+union mysockaddr {
+  struct sockaddr sa;
+  struct sockaddr_in in;
+#if defined(HAVE_IPV6)
+  struct sockaddr_in6 in6;
+#endif
+};
+
+/* bits in flag param to IPv6 callbacks from iface_enumerate() */
+#define IFACE_TENTATIVE   1
+#define IFACE_DEPRECATED  2
+#define IFACE_PERMANENT   4
+
+
+#define SERV_FROM_RESOLV       1  /* 1 for servers from resolv, 0 for command line. */
+#define SERV_NO_ADDR           2  /* no server, this domain is local only */
+#define SERV_LITERAL_ADDRESS   4  /* addr is the answer, not the server */ 
+#define SERV_HAS_DOMAIN        8  /* server for one domain only */
+#define SERV_HAS_SOURCE       16  /* source address defined */
+#define SERV_FOR_NODOTS       32  /* server for names with no domain part only */
+#define SERV_WARNED_RECURSIVE 64  /* avoid warning spam */
+#define SERV_FROM_DBUS       128  /* 1 if source is DBus */
+#define SERV_MARK            256  /* for mark-and-delete */
+#define SERV_TYPE    (SERV_HAS_DOMAIN | SERV_FOR_NODOTS)
+#define SERV_COUNTED         512  /* workspace for log code */
+#define SERV_USE_RESOLV     1024  /* forward this domain in the normal way */
+#define SERV_NO_REBIND      2048  /* inhibit dns-rebind protection */
+#define SERV_FROM_FILE      4096  /* read from --servers-file */
+#define SERV_LOOP           8192  /* server causes forwarding loop */
+#define SERV_DO_DNSSEC     16384  /* Validate DNSSEC when using this server */
+#define SERV_GOT_TCP       32768  /* Got some data from the TCP connection */
+
+struct serverfd {
+  int fd;
+  union mysockaddr source_addr;
+  char interface[IF_NAMESIZE+1];
+  unsigned int ifindex, used;
+  struct serverfd *next;
+};
+
+struct randfd {
+  int fd;
+  unsigned short refcount, family;
+};
+  
+struct server {
+  union mysockaddr addr, source_addr;
+  char interface[IF_NAMESIZE+1];
+  struct serverfd *sfd; 
+  char *domain; /* set if this server only handles a domain. */ 
+  int flags, tcpfd, edns_pktsz;
+  unsigned int queries, failed_queries;
+#ifdef HAVE_LOOP
+  u32 uid;
+#endif
+  struct server *next; 
+};
+
+struct ipsets {
+  char **sets;
+  char *domain;
+  struct ipsets *next;
+};
+
+struct irec {
+  union mysockaddr addr;
+  struct in_addr netmask; /* only valid for IPv4 */
+  int tftp_ok, dhcp_ok, mtu, done, warned, dad, dns_auth, index, multicast_done, found, label;
+  char *name; 
+  struct irec *next;
+};
+
+struct listener {
+  int fd, tcpfd, tftpfd, family;
+  struct irec *iface; /* only sometimes valid for non-wildcard */
+  struct listener *next;
+};
+
+/* interface and address parms from command line. */
+struct iname {
+  char *name;
+  union mysockaddr addr;
+  int used;
+  struct iname *next;
+};
+
+/* subnet parameters from command line */
+struct mysubnet {
+  union mysockaddr addr;
+  int addr_used;
+  int mask;
+};
+
+/* resolv-file parms from command-line */
+struct resolvc {
+  struct resolvc *next;
+  int is_default, logged;
+  time_t mtime;
+  char *name;
+#ifdef HAVE_INOTIFY
+  int wd; /* inotify watch descriptor */
+  char *file; /* pointer to file part if path */
+#endif
+};
+
+/* adn-hosts parms from command-line (also dhcp-hostsfile and dhcp-optsfile and dhcp-hostsdir*/
+#define AH_DIR      1
+#define AH_INACTIVE 2
+#define AH_WD_DONE  4
+#define AH_HOSTS    8
+#define AH_DHCP_HST 16
+#define AH_DHCP_OPT 32
+struct hostsfile {
+  struct hostsfile *next;
+  int flags;
+  char *fname;
+#ifdef HAVE_INOTIFY
+  int wd; /* inotify watch descriptor */
+#endif
+  unsigned int index; /* matches to cache entries for logging */
+};
+
+
+/* DNSSEC status values. */
+#define STAT_SECURE             1
+#define STAT_INSECURE           2
+#define STAT_BOGUS              3
+#define STAT_NEED_DS            4
+#define STAT_NEED_KEY           5
+#define STAT_TRUNCATED          6
+#define STAT_SECURE_WILDCARD    7
+#define STAT_OK                 8
+#define STAT_ABANDONED          9
+
+#define FREC_NOREBIND           1
+#define FREC_CHECKING_DISABLED  2
+#define FREC_HAS_SUBNET         4
+#define FREC_DNSKEY_QUERY       8
+#define FREC_DS_QUERY          16
+#define FREC_AD_QUESTION       32
+#define FREC_DO_QUESTION       64
+#define FREC_ADDED_PHEADER    128
+#define FREC_TEST_PKTSZ       256
+#define FREC_HAS_EXTRADATA    512        
+
+#ifdef HAVE_DNSSEC
+#define HASH_SIZE 20 /* SHA-1 digest size */
+#else
+#define HASH_SIZE sizeof(int)
+#endif
+
+struct frec {
+  union mysockaddr source;
+  struct all_addr dest;
+  struct server *sentto; /* NULL means free */
+  struct randfd *rfd4;
+#ifdef HAVE_IPV6
+  struct randfd *rfd6;
+#endif
+  unsigned int iface;
+  unsigned short orig_id, new_id;
+  int log_id, fd, forwardall, flags;
+  time_t time;
+  unsigned char *hash[HASH_SIZE];
+#ifdef HAVE_DNSSEC 
+  int class, work_counter;
+  struct blockdata *stash; /* Saved reply, whilst we validate */
+  size_t stash_len;
+  struct frec *dependent; /* Query awaiting internally-generated DNSKEY or DS query */
+  struct frec *blocking_query; /* Query which is blocking us. */
+#endif
+  struct frec *next;
+};
+
+/* flags in top of length field for DHCP-option tables */
+#define OT_ADDR_LIST    0x8000
+#define OT_RFC1035_NAME 0x4000
+#define OT_INTERNAL     0x2000
+#define OT_NAME         0x1000
+#define OT_CSTRING      0x0800
+#define OT_DEC          0x0400 
+#define OT_TIME         0x0200
+
+/* actions in the daemon->helper RPC */
+#define ACTION_DEL           1
+#define ACTION_OLD_HOSTNAME  2
+#define ACTION_OLD           3
+#define ACTION_ADD           4
+#define ACTION_TFTP          5
+#define ACTION_ARP           6
+#define ACTION_ARP_DEL       7
+
+#define LEASE_NEW            1  /* newly created */
+#define LEASE_CHANGED        2  /* modified */
+#define LEASE_AUX_CHANGED    4  /* CLID or expiry changed */
+#define LEASE_AUTH_NAME      8  /* hostname came from config, not from client */
+#define LEASE_USED          16  /* used this DHCPv6 transaction */
+#define LEASE_NA            32  /* IPv6 no-temporary lease */
+#define LEASE_TA            64  /* IPv6 temporary lease */
+#define LEASE_HAVE_HWADDR  128  /* Have set hwaddress */
+
+struct dhcp_lease {
+  int clid_len;          /* length of client identifier */
+  unsigned char *clid;   /* clientid */
+  char *hostname, *fqdn; /* name from client-hostname option or config */
+  char *old_hostname;    /* hostname before it moved to another lease */
+  int flags;
+  time_t expires;        /* lease expiry */
+#ifdef HAVE_BROKEN_RTC
+  unsigned int length;
+#endif
+  int hwaddr_len, hwaddr_type;
+  unsigned char hwaddr[DHCP_CHADDR_MAX]; 
+  struct in_addr addr, override, giaddr;
+  unsigned char *extradata;
+  unsigned int extradata_len, extradata_size;
+  int last_interface;
+  int new_interface;     /* save possible originated interface */
+  int new_prefixlen;     /* and its prefix length */
+#ifdef HAVE_DHCP6
+  struct in6_addr addr6;
+  int iaid;
+  struct slaac_address {
+    struct in6_addr addr;
+    time_t ping_time;
+    int backoff; /* zero -> confirmed */
+    struct slaac_address *next;
+  } *slaac_address;
+  int vendorclass_count;
+#endif
+  u8 req_options[256];   /* cover all possible options (0-254 + OPTION_END) */
+  struct dhcp_lease *next;
+};
+
+struct dhcp_netid {
+  char *net;
+  struct dhcp_netid *next;
+};
+
+struct dhcp_netid_list {
+  struct dhcp_netid *list;
+  struct dhcp_netid_list *next;
+};
+
+struct tag_if {
+  struct dhcp_netid_list *set;
+  struct dhcp_netid *tag;
+  struct tag_if *next;
+};
+
+struct delay_config {
+  int delay;
+  struct dhcp_netid *netid;
+  struct delay_config *next;
+};
+
+struct hwaddr_config {
+  int hwaddr_len, hwaddr_type;
+  unsigned char hwaddr[DHCP_CHADDR_MAX];
+  unsigned int wildcard_mask;
+  struct hwaddr_config *next;
+};
+
+struct dhcp_config {
+  unsigned int flags;
+  int clid_len;          /* length of client identifier */
+  unsigned char *clid;   /* clientid */
+  char *hostname, *domain;
+  struct dhcp_netid_list *netid;
+#ifdef HAVE_DHCP6
+  struct in6_addr addr6;
+#endif
+  struct in_addr addr;
+  time_t decline_time;
+  unsigned int lease_time;
+  struct hwaddr_config *hwaddr;
+  struct dhcp_config *next;
+};
+
+#define have_config(config, mask) ((config) && ((config)->flags & (mask))) 
+
+#define CONFIG_DISABLE           1
+#define CONFIG_CLID              2
+#define CONFIG_TIME              8
+#define CONFIG_NAME             16
+#define CONFIG_ADDR             32
+#define CONFIG_NOCLID          128
+#define CONFIG_FROM_ETHERS     256    /* entry created by /etc/ethers */
+#define CONFIG_ADDR_HOSTS      512    /* address added by from /etc/hosts */
+#define CONFIG_DECLINED       1024    /* address declined by client */
+#define CONFIG_BANK           2048    /* from dhcp hosts file */
+#define CONFIG_ADDR6          4096
+#define CONFIG_WILDCARD       8192
+
+struct dhcp_opt {
+  int opt, len, flags;
+  union {
+    int encap;
+    unsigned int wildcard_mask;
+    unsigned char *vendor_class;
+  } u;
+  unsigned char *val;
+  struct dhcp_netid *netid;
+  struct dhcp_opt *next;
+};
+
+#define DHOPT_ADDR               1
+#define DHOPT_STRING             2
+#define DHOPT_ENCAPSULATE        4
+#define DHOPT_ENCAP_MATCH        8
+#define DHOPT_FORCE             16
+#define DHOPT_BANK              32
+#define DHOPT_ENCAP_DONE        64
+#define DHOPT_MATCH            128
+#define DHOPT_VENDOR           256
+#define DHOPT_HEX              512
+#define DHOPT_VENDOR_MATCH    1024
+#define DHOPT_RFC3925         2048
+#define DHOPT_TAGOK           4096
+#define DHOPT_ADDR6           8192
+
+struct dhcp_boot {
+  char *file, *sname, *tftp_sname;
+  struct in_addr next_server;
+  struct dhcp_netid *netid;
+  struct dhcp_boot *next;
+};
+
+struct pxe_service {
+  unsigned short CSA, type; 
+  char *menu, *basename, *sname;
+  struct in_addr server;
+  struct dhcp_netid *netid;
+  struct pxe_service *next;
+};
+
+#define MATCH_VENDOR     1
+#define MATCH_USER       2
+#define MATCH_CIRCUIT    3
+#define MATCH_REMOTE     4
+#define MATCH_SUBSCRIBER 5
+
+/* vendorclass, userclass, remote-id or circuit-id */
+struct dhcp_vendor {
+  int len, match_type;
+  unsigned int enterprise;
+  char *data;
+  struct dhcp_netid netid;
+  struct dhcp_vendor *next;
+};
+
+struct dhcp_mac {
+  unsigned int mask;
+  int hwaddr_len, hwaddr_type;
+  unsigned char hwaddr[DHCP_CHADDR_MAX];
+  struct dhcp_netid netid;
+  struct dhcp_mac *next;
+};
+
+struct dhcp_bridge {
+  char iface[IF_NAMESIZE];
+  struct dhcp_bridge *alias, *next;
+};
+
+struct cond_domain {
+  char *domain, *prefix;
+  struct in_addr start, end;
+#ifdef HAVE_IPV6
+  struct in6_addr start6, end6;
+#endif
+  int is6;
+  struct cond_domain *next;
+}; 
+
+#ifdef OPTION6_PREFIX_CLASS 
+struct prefix_class {
+  int class;
+  struct dhcp_netid tag;
+  struct prefix_class *next;
+};
+#endif
+
+struct ra_interface {
+  char *name;
+  char *mtu_name;
+  int interval, lifetime, prio, mtu;
+  struct ra_interface *next;
+};
+
+struct dhcp_context {
+  unsigned int lease_time, addr_epoch;
+  struct in_addr netmask, broadcast;
+  struct in_addr local, router;
+  struct in_addr start, end; /* range of available addresses */
+#ifdef HAVE_DHCP6
+  struct in6_addr start6, end6; /* range of available addresses */
+  struct in6_addr local6;
+  int prefix, if_index;
+  unsigned int valid, preferred, saved_valid;
+  time_t ra_time, ra_short_period_start, address_lost_time;
+  char *template_interface;
+#endif
+  int flags;
+  struct dhcp_netid netid, *filter;
+  struct dhcp_context *next, *current;
+};
+
+#define CONTEXT_STATIC         (1u<<0)
+#define CONTEXT_NETMASK        (1u<<1)
+#define CONTEXT_BRDCAST        (1u<<2)
+#define CONTEXT_PROXY          (1u<<3)
+#define CONTEXT_RA_ROUTER      (1u<<4)
+#define CONTEXT_RA_DONE        (1u<<5)
+#define CONTEXT_RA_NAME        (1u<<6)
+#define CONTEXT_RA_STATELESS   (1u<<7)
+#define CONTEXT_DHCP           (1u<<8)
+#define CONTEXT_DEPRECATE      (1u<<9)
+#define CONTEXT_TEMPLATE       (1u<<10)    /* create contexts using addresses */
+#define CONTEXT_CONSTRUCTED    (1u<<11)
+#define CONTEXT_GC             (1u<<12)
+#define CONTEXT_RA             (1u<<13)
+#define CONTEXT_CONF_USED      (1u<<14)
+#define CONTEXT_USED           (1u<<15)
+#define CONTEXT_OLD            (1u<<16)
+#define CONTEXT_V6             (1u<<17)
+#define CONTEXT_RA_OFF_LINK    (1u<<18)
+
+struct ping_result {
+  struct in_addr addr;
+  time_t time;
+  unsigned int hash;
+  struct ping_result *next;
+};
+
+struct tftp_file {
+  int refcount, fd;
+  off_t size;
+  dev_t dev;
+  ino_t inode;
+  char filename[];
+};
+
+struct tftp_transfer {
+  int sockfd;
+  time_t timeout;
+  int backoff;
+  unsigned int block, blocksize, expansion;
+  off_t offset;
+  union mysockaddr peer;
+  char opt_blocksize, opt_transize, netascii, carrylf;
+  struct tftp_file *file;
+  struct tftp_transfer *next;
+};
+
+struct addr_list {
+  struct in_addr addr;
+  struct addr_list *next;
+};
+
+struct tftp_prefix {
+  char *interface;
+  char *prefix;
+  int missing;
+  struct tftp_prefix *next;
+};
+
+struct dhcp_relay {
+  struct all_addr local, server;
+  char *interface; /* Allowable interface for replies from server, and dest for IPv6 multicast */
+  int iface_index; /* working - interface in which requests arrived, for return */
+  struct dhcp_relay *current, *next;
+};
+
+extern struct daemon {
+  /* datastuctures representing the command-line and 
+     config file arguments. All set (including defaults)
+     in option.c */
+
+  unsigned int options, options2;
+  struct resolvc default_resolv, *resolv_files;
+  time_t last_resolv;
+  char *servers_file;
+  struct mx_srv_record *mxnames;
+  struct naptr *naptr;
+  struct txt_record *txt, *rr;
+  struct ptr_record *ptr;
+  struct host_record *host_records, *host_records_tail;
+  struct cname *cnames;
+  struct auth_zone *auth_zones;
+  struct interface_name *int_names;
+  char *mxtarget;
+  struct mysubnet *add_subnet4;
+  struct mysubnet *add_subnet6;
+  char *lease_file;
+  char *username, *groupname, *scriptuser;
+  char *luascript;
+  char *authserver, *hostmaster;
+  struct iname *authinterface;
+  struct name_list *secondary_forward_server;
+  int group_set, osport;
+  char *domain_suffix;
+  struct cond_domain *cond_domain, *synth_domains;
+  char *runfile; 
+  char *lease_change_command;
+  struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
+  struct bogus_addr *bogus_addr, *ignore_addr;
+  struct server *servers;
+  struct ipsets *ipsets;
+  int log_fac; /* log facility */
+  char *log_file; /* optional log file */
+  int max_logs;  /* queue limit */
+  int cachesize, ftabsize;
+  int port, query_port, min_port, max_port;
+  unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, max_cache_ttl, auth_ttl, dhcp_ttl, use_dhcp_ttl;
+  char *dns_client_id;
+  struct hostsfile *addn_hosts;
+  struct dhcp_context *dhcp, *dhcp6;
+  struct ra_interface *ra_interfaces;
+  struct dhcp_config *dhcp_conf;
+  struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6;
+  struct dhcp_vendor *dhcp_vendors;
+  struct dhcp_mac *dhcp_macs;
+  struct dhcp_boot *boot_config;
+  struct pxe_service *pxe_services;
+  struct tag_if *tag_if; 
+  struct addr_list *override_relays;
+  struct dhcp_relay *relay4, *relay6;
+  struct delay_config *delay_conf;
+  int override;
+  int enable_pxe;
+  int doing_ra, doing_dhcp6;
+  struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names; 
+  struct dhcp_netid_list *force_broadcast, *bootp_dynamic;
+  struct hostsfile *dhcp_hosts_file, *dhcp_opts_file, *dynamic_dirs;
+  int dhcp_max, tftp_max, tftp_mtu;
+  int dhcp_server_port, dhcp_client_port;
+  int start_tftp_port, end_tftp_port; 
+  unsigned int min_leasetime;
+  struct doctor *doctors;
+  unsigned short edns_pktsz;
+  char *tftp_prefix; 
+  struct tftp_prefix *if_prefix; /* per-interface TFTP prefixes */
+  unsigned int duid_enterprise, duid_config_len;
+  unsigned char *duid_config;
+  char *dbus_name;
+  unsigned long soa_sn, soa_refresh, soa_retry, soa_expiry;
+#ifdef OPTION6_PREFIX_CLASS 
+  struct prefix_class *prefix_classes;
+#endif
+#ifdef HAVE_DNSSEC
+  struct ds_config *ds;
+  int dnssec_no_time_check;
+  int back_to_the_future;
+  char *timestamp_file;
+#endif
+
+  /* globally used stuff for DNS */
+  char *packet; /* packet buffer */
+  int packet_buff_sz; /* size of above */
+  char *namebuff; /* MAXDNAME size buffer */
+#ifdef HAVE_DNSSEC
+  char *keyname; /* MAXDNAME size buffer */
+  char *workspacename; /* ditto */
+#endif
+  unsigned int local_answer, queries_forwarded, auth_answer;
+  struct frec *frec_list;
+  struct serverfd *sfds;
+  struct irec *interfaces;
+  struct listener *listeners;
+  struct server *last_server;
+  time_t forwardtime;
+  int forwardcount;
+  struct server *srv_save; /* Used for resend on DoD */
+  size_t packet_len;       /*      "        "        */
+  struct randfd *rfd_save; /*      "        "        */
+  pid_t tcp_pids[MAX_PROCS];
+  struct randfd randomsocks[RANDOM_SOCKS];
+  int v6pktinfo; 
+  struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */
+  int log_id, log_display_id; /* ids of transactions for logging */
+  union mysockaddr *log_source_addr;
+
+  /* DHCP state */
+  int dhcpfd, helperfd, pxefd; 
+#ifdef HAVE_INOTIFY
+  int inotifyfd;
+#endif
+#if defined(HAVE_LINUX_NETWORK)
+  int netlinkfd;
+#elif defined(HAVE_BSD_NETWORK)
+  int dhcp_raw_fd, dhcp_icmp_fd, routefd;
+#endif
+  struct iovec dhcp_packet;
+  char *dhcp_buff, *dhcp_buff2, *dhcp_buff3;
+  struct ping_result *ping_results;
+  FILE *lease_stream;
+  struct dhcp_bridge *bridges;
+#ifdef HAVE_DHCP6
+  int duid_len;
+  unsigned char *duid;
+  struct iovec outpacket;
+  int dhcp6fd, icmp6fd;
+#endif
+  /* DBus stuff */
+  /* void * here to avoid depending on dbus headers outside dbus.c */
+  void *dbus;
+#ifdef HAVE_DBUS
+  struct watch *watches;
+#endif
+
+  /* TFTP stuff */
+  struct tftp_transfer *tftp_trans, *tftp_done_trans;
+
+  /* utility string buffer, hold max sized IP address as string */
+  char *addrbuff;
+  char *addrbuff2; /* only allocated when OPT_EXTRALOG */
+
+} *daemon;
+
+/* cache.c */
+void cache_init(void);
+void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg); 
+char *record_source(unsigned int index);
+char *querystr(char *desc, unsigned short type);
+struct crec *cache_find_by_addr(struct crec *crecp,
+				struct all_addr *addr, time_t now, 
+				unsigned int prot);
+struct crec *cache_find_by_name(struct crec *crecp, 
+				char *name, time_t now, unsigned int prot);
+void cache_end_insert(void);
+void cache_start_insert(void);
+struct crec *cache_insert(char *name, struct all_addr *addr,
+			  time_t now, unsigned long ttl, unsigned short flags);
+void cache_reload(void);
+void cache_add_dhcp_entry(char *host_name, int prot, struct all_addr *host_address, time_t ttd);
+struct in_addr a_record_from_hosts(char *name, time_t now);
+void cache_unhash_dhcp(void);
+void dump_cache(time_t now);
+#ifndef NO_ID
+int cache_make_stat(struct txt_record *t);
+#endif
+char *cache_get_name(struct crec *crecp);
+char *cache_get_cname_target(struct crec *crecp);
+struct crec *cache_enumerate(int init);
+int read_hostsfile(char *filename, unsigned int index, int cache_size, 
+		   struct crec **rhash, int hashsz);
+
+/* blockdata.c */
+#ifdef HAVE_DNSSEC
+void blockdata_init(void);
+void blockdata_report(void);
+struct blockdata *blockdata_alloc(char *data, size_t len);
+void *blockdata_retrieve(struct blockdata *block, size_t len, void *data);
+void blockdata_free(struct blockdata *blocks);
+#endif
+
+/* domain.c */
+char *get_domain(struct in_addr addr);
+#ifdef HAVE_IPV6
+char *get_domain6(struct in6_addr *addr);
+#endif
+int is_name_synthetic(int flags, char *name, struct all_addr *addr);
+int is_rev_synth(int flag, struct all_addr *addr, char *name);
+
+/* rfc1035.c */
+int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, 
+                 char *name, int isExtract, int extrabytes);
+unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes);
+unsigned char *skip_questions(struct dns_header *header, size_t plen);
+unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen);
+unsigned int extract_request(struct dns_header *header, size_t qlen, 
+			       char *name, unsigned short *typep);
+size_t setup_reply(struct dns_header *header, size_t  qlen,
+		   struct all_addr *addrp, unsigned int flags,
+		   unsigned long ttl);
+int extract_addresses(struct dns_header *header, size_t qlen, char *name,
+		      time_t now, char **ipsets, int is_sign, int check_rebind,
+		      int no_cache_dnssec, int secure, int *doctored);
+size_t answer_request(struct dns_header *header, char *limit, size_t qlen,  
+		      struct in_addr local_addr, struct in_addr local_netmask, 
+		      time_t now, int ad_reqd, int do_bit, int have_pseudoheader);
+int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name, 
+			     struct bogus_addr *baddr, time_t now);
+int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
+int check_for_local_domain(char *name, time_t now);
+unsigned int questions_crc(struct dns_header *header, size_t plen, char *name);
+size_t resize_packet(struct dns_header *header, size_t plen, 
+		  unsigned char *pheader, size_t hlen);
+int add_resource_record(struct dns_header *header, char *limit, int *truncp,
+			int nameoffset, unsigned char **pp, unsigned long ttl, 
+			int *offset, unsigned short type, unsigned short class, char *format, ...);
+unsigned char *skip_questions(struct dns_header *header, size_t plen);
+int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, 
+		 char *name, int isExtract, int extrabytes);
+int in_arpa_name_2_addr(char *namein, struct all_addr *addrp);
+int private_net(struct in_addr addr, int ban_localhost);
+
+/* auth.c */
+#ifdef HAVE_AUTH
+size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, 
+		   time_t now, union mysockaddr *peer_addr, int local_query,
+		   int do_bit, int have_pseudoheader);
+int in_zone(struct auth_zone *zone, char *name, char **cut);
+#endif
+
+/* dnssec.c */
+size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class, int type, union mysockaddr *addr, int edns_pktsz);
+int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
+int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
+int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class,
+			  int check_unsigned, int *neganswer, int *nons);
+int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen);
+size_t filter_rrsigs(struct dns_header *header, size_t plen);
+unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
+int setup_timestamp(void);
+
+/* util.c */
+void rand_init(void);
+unsigned short rand16(void);
+u32 rand32(void);
+u64 rand64(void);
+int legal_hostname(char *name);
+char *canonicalise(char *in, int *nomem);
+unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit);
+void *safe_malloc(size_t size);
+void safe_pipe(int *fd, int read_noblock);
+void *whine_malloc(size_t size);
+int sa_len(union mysockaddr *addr);
+int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
+int hostname_isequal(const char *a, const char *b);
+time_t dnsmasq_time(void);
+int netmask_length(struct in_addr mask);
+int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
+#ifdef HAVE_IPV6
+int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen);
+u64 addr6part(struct in6_addr *addr);
+void setaddr6part(struct in6_addr *addr, u64 host);
+#endif
+int retry_send(ssize_t rc);
+void prettyprint_time(char *buf, unsigned int t);
+int prettyprint_addr(union mysockaddr *addr, char *buf);
+int parse_hex(char *in, unsigned char *out, int maxlen, 
+	      unsigned int *wildcard_mask, int *mac_type);
+int memcmp_masked(unsigned char *a, unsigned char *b, int len, 
+		  unsigned int mask);
+int expand_buf(struct iovec *iov, size_t size);
+char *print_mac(char *buff, unsigned char *mac, int len);
+int read_write(int fd, unsigned char *packet, int size, int rw);
+
+int wildcard_match(const char* wildcard, const char* match);
+int wildcard_matchn(const char* wildcard, const char* match, int num);
+
+/* log.c */
+void die(char *message, char *arg1, int exit_code);
+int log_start(struct passwd *ent_pw, int errfd);
+int log_reopen(char *log_file);
+
+void my_syslog(int priority, const char *format, ...);
+
+void set_log_writer(void);
+void check_log_writer(int force);
+void flush_log(void);
+
+/* option.c */
+void read_opts (int argc, char **argv, char *compile_opts);
+char *option_string(int prot, unsigned int opt, unsigned char *val, 
+		    int opt_len, char *buf, int buf_len);
+void reread_dhcp(void);
+void read_servers_file(void);
+void set_option_bool(unsigned int opt);
+void reset_option_bool(unsigned int opt);
+struct hostsfile *expand_filelist(struct hostsfile *list);
+char *parse_server(char *arg, union mysockaddr *addr, 
+		   union mysockaddr *source_addr, char *interface, int *flags);
+int option_read_dynfile(char *file, int flags);
+
+/* forward.c */
+void reply_query(int fd, int family, time_t now);
+void receive_query(struct listener *listen, time_t now);
+unsigned char *tcp_request(int confd, time_t now,
+			   union mysockaddr *local_addr, struct in_addr netmask, int auth_dns);
+void server_gone(struct server *server);
+struct frec *get_new_frec(time_t now, int *wait, int force);
+int send_from(int fd, int nowild, char *packet, size_t len, 
+	       union mysockaddr *to, struct all_addr *source,
+	       unsigned int iface);
+void resend_query(void);
+struct randfd *allocate_rfd(int family);
+void free_rfd(struct randfd *rfd);
+
+/* network.c */
+int indextoname(int fd, int index, char *name);
+int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp);
+int random_sock(int family);
+void pre_allocate_sfds(void);
+int reload_servers(char *fname);
+void mark_servers(int flag);
+void cleanup_servers(void);
+void add_update_server(int flags,
+		       union mysockaddr *addr,
+		       union mysockaddr *source_addr,
+		       const char *interface,
+		       const char *domain);
+void check_servers(void);
+int enumerate_interfaces(int reset);
+void create_wildcard_listeners(void);
+void create_bound_listeners(int dienow);
+void warn_bound_listeners(void);
+void warn_wild_labels(void);
+void warn_int_names(void);
+int is_dad_listeners(void);
+int iface_check(int family, struct all_addr *addr, char *name, int *auth);
+int loopback_exception(int fd, int family, struct all_addr *addr, char *name);
+int label_exception(int index, int family, struct all_addr *addr);
+int fix_fd(int fd);
+int tcp_interface(int fd, int af);
+#ifdef HAVE_IPV6
+int set_ipv6pktinfo(int fd);
+#endif
+#ifdef HAVE_DHCP6
+void join_multicast(int dienow);
+#endif
+#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_BSD_NETWORK)
+void newaddress(time_t now);
+#endif
+
+
+/* dhcp.c */
+#ifdef HAVE_DHCP
+void dhcp_init(void);
+void dhcp_packet(time_t now, int pxe_fd);
+struct dhcp_context *address_available(struct dhcp_context *context, 
+				       struct in_addr taddr,
+				       struct dhcp_netid *netids);
+struct dhcp_context *narrow_context(struct dhcp_context *context, 
+				    struct in_addr taddr,
+				    struct dhcp_netid *netids);
+struct ping_result *do_icmp_ping(time_t now, struct in_addr addr,
+				 unsigned int hash, int loopback);
+int address_allocate(struct dhcp_context *context,
+		     struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
+		     struct dhcp_netid *netids, time_t now, int loopback);
+void dhcp_read_ethers(void);
+struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
+char *host_from_dns(struct in_addr addr);
+#endif
+
+/* lease.c */
+#ifdef HAVE_DHCP
+void lease_update_file(time_t now);
+void lease_update_dns(int force);
+void lease_init(time_t now);
+struct dhcp_lease *lease4_allocate(struct in_addr addr);
+#ifdef HAVE_DHCP6
+struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type);
+struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len, 
+			       int lease_type, int iaid, struct in6_addr *addr);
+void lease6_reset(void);
+struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid);
+struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr);
+u64 lease_find_max_addr6(struct dhcp_context *context);
+void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface);
+void lease_update_slaac(time_t now);
+void lease_set_iaid(struct dhcp_lease *lease, int iaid);
+void lease_make_duid(time_t now);
+#endif
+void lease_set_hwaddr(struct dhcp_lease *lease, const unsigned char *hwaddr,
+		      const unsigned char *clid, int hw_len, int hw_type,
+		      int clid_len, time_t now, int force);
+void lease_set_hostname(struct dhcp_lease *lease, const char *name, int auth, char *domain, char *config_domain);
+void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now);
+void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now);
+struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,  
+					unsigned char *clid, int clid_len);
+struct dhcp_lease *lease_find_by_addr(struct in_addr addr);
+struct in_addr lease_find_max_addr(struct dhcp_context *context);
+void lease_prune(struct dhcp_lease *target, time_t now);
+void lease_update_from_configs(void);
+int do_script_run(time_t now);
+void rerun_scripts(void);
+void lease_find_interfaces(time_t now);
+#ifdef HAVE_SCRIPT
+void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, 
+			 unsigned int len, int delim);
+#endif
+#endif
+
+/* rfc2131.c */
+#ifdef HAVE_DHCP
+size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
+		  size_t sz, time_t now, int unicast_dest, int loopback,
+		  int *is_inform, int pxe, struct in_addr fallback, time_t recvtime);
+unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr, 
+			       int clid_len, unsigned char *clid, int *len_out);
+#endif
+
+/* dnsmasq.c */
+#ifdef HAVE_DHCP
+int make_icmp_sock(void);
+int icmp_ping(struct in_addr addr);
+int delay_dhcp(time_t start, int sec, int fd, uint32_t addr, unsigned short id);
+#endif
+void queue_event(int event);
+void send_alarm(time_t event, time_t now);
+void send_event(int fd, int event, int data, char *msg);
+void clear_cache_and_reload(time_t now);
+
+/* netlink.c */
+#ifdef HAVE_LINUX_NETWORK
+void netlink_init(void);
+void netlink_multicast(void);
+#endif
+
+/* bpf.c */
+#ifdef HAVE_BSD_NETWORK
+void init_bpf(void);
+void send_via_bpf(struct dhcp_packet *mess, size_t len,
+		  struct in_addr iface_addr, struct ifreq *ifr);
+void route_init(void);
+void route_sock(void);
+#endif
+
+/* bpf.c or netlink.c */
+int iface_enumerate(int family, void *parm, int (callback)());
+
+/* dbus.c */
+#ifdef HAVE_DBUS
+char *dbus_init(void);
+void check_dbus_listeners(void);
+void set_dbus_listeners(void);
+#  ifdef HAVE_DHCP
+void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
+#  endif
+#endif
+
+/* ipset.c */
+#ifdef HAVE_IPSET
+void ipset_init(void);
+int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags, int remove);
+#endif
+
+/* helper.c */
+#if defined(HAVE_SCRIPT)
+int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd);
+void helper_write(void);
+void queue_script(int action, struct dhcp_lease *lease, 
+		  char *hostname, time_t now);
+#ifdef HAVE_TFTP
+void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer);
+#endif
+void queue_arp(int action, unsigned char *mac, int maclen,
+	       int family, struct all_addr *addr);
+int helper_buf_empty(void);
+#endif
+
+/* tftp.c */
+#ifdef HAVE_TFTP
+void tftp_request(struct listener *listen, time_t now);
+void check_tftp_listeners(time_t now);
+int do_tftp_script_run(void);
+#endif
+
+/* conntrack.c */
+#ifdef HAVE_CONNTRACK
+int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
+		      int istcp, unsigned int *markp);
+#endif
+
+/* dhcp6.c */
+#ifdef HAVE_DHCP6
+void dhcp6_init(void);
+void dhcp6_packet(time_t now);
+struct dhcp_context *address6_allocate(struct dhcp_context *context,  unsigned char *clid, int clid_len, int temp_addr,
+				       int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans);
+int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr);
+struct dhcp_context *address6_available(struct dhcp_context *context, 
+					struct in6_addr *taddr,
+					struct dhcp_netid *netids,
+					int plain_range);
+struct dhcp_context *address6_valid(struct dhcp_context *context, 
+				    struct in6_addr *taddr,
+				    struct dhcp_netid *netids,
+				    int plain_range);
+struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, 
+					    int prefix, u64 addr);
+void make_duid(time_t now);
+void dhcp_construct_contexts(time_t now);
+void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, 
+		    unsigned int *maclenp, unsigned int *mactypep, time_t now);
+#endif
+  
+/* rfc3315.c */
+#ifdef HAVE_DHCP6
+unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,  
+			   struct in6_addr *fallback, struct in6_addr *ll_addr, struct in6_addr *ula_addr,
+			   size_t sz, struct in6_addr *client_addr, time_t now);
+void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, 
+		     u32 scope_id, time_t now);
+
+unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
+#endif
+
+/* dhcp-common.c */
+#ifdef HAVE_DHCP
+void dhcp_common_init(void);
+ssize_t recv_dhcp_packet(int fd, struct msghdr *msg);
+struct dhcp_netid *run_tag_if(struct dhcp_netid *tags);
+struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *context_tags,
+				 struct dhcp_opt *opts);
+int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded);
+char *strip_hostname(char *hostname);
+void log_tags(struct dhcp_netid *netid, u32 xid);
+int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
+void dhcp_update_configs(struct dhcp_config *configs);
+void display_opts(void);
+int lookup_dhcp_opt(int prot, char *name);
+int lookup_dhcp_len(int prot, int val);
+char *option_string(int prot, unsigned int opt, unsigned char *val, 
+		    int opt_len, char *buf, int buf_len);
+struct dhcp_config *find_config(struct dhcp_config *configs,
+				struct dhcp_context *context,
+				unsigned char *clid, int clid_len,
+				unsigned char *hwaddr, int hw_len, 
+				int hw_type, char *hostname);
+int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
+#ifdef HAVE_LINUX_NETWORK
+char *whichdevice(void);
+void bindtodevice(char *device, int fd);
+#endif
+#  ifdef HAVE_DHCP6
+void display_opts6(void);
+#  endif
+void log_context(int family, struct dhcp_context *context);
+void log_relay(int family, struct dhcp_relay *relay);
+#endif
+
+/* outpacket.c */
+#ifdef HAVE_DHCP6
+void end_opt6(int container);
+void reset_counter(void);
+int save_counter(int newval);
+void *expand(size_t headroom);
+int new_opt6(int opt);
+void *put_opt6(void *data, size_t len);
+void put_opt6_long(unsigned int val);
+void put_opt6_short(unsigned int val);
+void put_opt6_char(unsigned int val);
+void put_opt6_string(char *s);
+#endif
+
+/* radv.c */
+#ifdef HAVE_DHCP6
+void ra_init(time_t now);
+void icmp6_packet(time_t now);
+time_t periodic_ra(time_t now);
+void ra_start_unsolicited(time_t now, struct dhcp_context *context);
+#endif
+
+/* slaac.c */ 
+#ifdef HAVE_DHCP6
+void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force);
+time_t periodic_slaac(time_t now, struct dhcp_lease *leases);
+void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface, struct dhcp_lease *leases);
+#endif
+
+/* loop.c */
+#ifdef HAVE_LOOP
+void loop_send_probes(void);
+int detect_loop(char *query, int type);
+#endif
+
+/* inotify.c */
+#ifdef HAVE_INOTIFY
+void inotify_dnsmasq_init(void);
+int inotify_check(time_t now);
+void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz);
+#endif
+
+/* poll.c */
+void poll_reset(void);
+int poll_check(int fd, short event);
+void poll_listen(int fd, short event);
+int do_poll(int timeout);
+
+/* rrfilter.c */
+size_t rrfilter(struct dns_header *header, size_t plen, int mode);
+u16 *rrfilter_desc(int type);
+int expand_workspace(unsigned char ***wkspc, int *szp, int new);
+
+/* edns0.c */
+unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
+				   size_t *len, unsigned char **p, int *is_sign, int *is_last);
+size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
+			unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do, int replace);
+size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit);
+size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit, 
+			union mysockaddr *source, time_t now, int *check_subnet);
+int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
+
+/* arp.c */
+int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now);
+int do_arp_script_run(void);
diff --git a/src/dnssec.c b/src/dnssec.c
new file mode 100644
index 0000000..a74d01a
--- /dev/null
+++ b/src/dnssec.c
@@ -0,0 +1,2277 @@
+/* dnssec.c is Copyright (c) 2012 Giovanni Bajo <rasky@develer.com>
+           and Copyright (c) 2012-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+
+   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.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_DNSSEC
+
+#include <nettle/rsa.h>
+#include <nettle/dsa.h>
+#ifndef NO_NETTLE_ECC
+#  include <nettle/ecdsa.h>
+#  include <nettle/ecc-curve.h>
+#endif
+#include <nettle/nettle-meta.h>
+#include <nettle/bignum.h>
+
+/* Nettle-3.0 moved to a new API for DSA. We use a name that's defined in the new API
+   to detect Nettle-3, and invoke the backwards compatibility mode. */
+#ifdef dsa_params_init
+#include <nettle/dsa-compat.h>
+#endif
+
+#define SERIAL_UNDEF  -100
+#define SERIAL_EQ        0
+#define SERIAL_LT       -1
+#define SERIAL_GT        1
+
+/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
+static char *ds_digest_name(int digest)
+{
+  switch (digest)
+    {
+    case 1: return "sha1";
+    case 2: return "sha256";
+    case 3: return "gosthash94";
+    case 4: return "sha384";
+    default: return NULL;
+    }
+}
+ 
+/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
+static char *algo_digest_name(int algo)
+{
+  switch (algo)
+    {
+    case 1: return "md5";
+    case 3: return "sha1";
+    case 5: return "sha1";
+    case 6: return "sha1";
+    case 7: return "sha1";
+    case 8: return "sha256";
+    case 10: return "sha512";
+    case 12: return "gosthash94";
+    case 13: return "sha256";
+    case 14: return "sha384";
+    default: return NULL;
+    }
+}
+  
+/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
+static char *nsec3_digest_name(int digest)
+{
+  switch (digest)
+    {
+    case 1: return "sha1";
+    default: return NULL;
+    }
+}
+ 
+/* Find pointer to correct hash function in nettle library */
+static const struct nettle_hash *hash_find(char *name)
+{
+  int i;
+  
+  if (!name)
+    return NULL;
+  
+  for (i = 0; nettle_hashes[i]; i++)
+    {
+      if (strcmp(nettle_hashes[i]->name, name) == 0)
+	return nettle_hashes[i];
+    }
+
+  return NULL;
+}
+
+/* expand ctx and digest memory allocations if necessary and init hash function */
+static int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
+{
+  static void *ctx = NULL;
+  static unsigned char *digest = NULL;
+  static unsigned int ctx_sz = 0;
+  static unsigned int digest_sz = 0;
+
+  void *new;
+
+  if (ctx_sz < hash->context_size)
+    {
+      if (!(new = whine_malloc(hash->context_size)))
+	return 0;
+      if (ctx)
+	free(ctx);
+      ctx = new;
+      ctx_sz = hash->context_size;
+    }
+  
+  if (digest_sz < hash->digest_size)
+    {
+      if (!(new = whine_malloc(hash->digest_size)))
+	return 0;
+      if (digest)
+	free(digest);
+      digest = new;
+      digest_sz = hash->digest_size;
+    }
+
+  *ctxp = ctx;
+  *digestp = digest;
+
+  hash->init(ctx);
+
+  return 1;
+}
+  
+static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
+			      unsigned char *digest, size_t digest_len, int algo)
+{
+  unsigned char *p;
+  size_t exp_len;
+  
+  static struct rsa_public_key *key = NULL;
+  static mpz_t sig_mpz;
+
+  (void)digest_len;
+  
+  if (key == NULL)
+    {
+      if (!(key = whine_malloc(sizeof(struct rsa_public_key))))
+	return 0;
+      
+      nettle_rsa_public_key_init(key);
+      mpz_init(sig_mpz);
+    }
+  
+  if ((key_len < 3) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
+    return 0;
+  
+  key_len--;
+  if ((exp_len = *p++) == 0)
+    {
+      GETSHORT(exp_len, p);
+      key_len -= 2;
+    }
+  
+  if (exp_len >= key_len)
+    return 0;
+  
+  key->size =  key_len - exp_len;
+  mpz_import(key->e, exp_len, 1, 1, 0, 0, p);
+  mpz_import(key->n, key->size, 1, 1, 0, 0, p + exp_len);
+
+  mpz_import(sig_mpz, sig_len, 1, 1, 0, 0, sig);
+  
+  switch (algo)
+    {
+    case 1:
+      return nettle_rsa_md5_verify_digest(key, digest, sig_mpz);
+    case 5: case 7:
+      return nettle_rsa_sha1_verify_digest(key, digest, sig_mpz);
+    case 8:
+      return nettle_rsa_sha256_verify_digest(key, digest, sig_mpz);
+    case 10:
+      return nettle_rsa_sha512_verify_digest(key, digest, sig_mpz);
+    }
+
+  return 0;
+}  
+
+static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
+			      unsigned char *digest, size_t digest_len, int algo)
+{
+  unsigned char *p;
+  unsigned int t;
+  
+  static struct dsa_public_key *key = NULL;
+  static struct dsa_signature *sig_struct;
+  
+  (void)digest_len;
+
+  if (key == NULL)
+    {
+      if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) || 
+	  !(key = whine_malloc(sizeof(struct dsa_public_key)))) 
+	return 0;
+      
+      nettle_dsa_public_key_init(key);
+      nettle_dsa_signature_init(sig_struct);
+    }
+  
+  if ((sig_len < 41) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
+    return 0;
+  
+  t = *p++;
+  
+  if (key_len < (213 + (t * 24)))
+    return 0;
+  
+  mpz_import(key->q, 20, 1, 1, 0, 0, p); p += 20;
+  mpz_import(key->p, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
+  mpz_import(key->g, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
+  mpz_import(key->y, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
+  
+  mpz_import(sig_struct->r, 20, 1, 1, 0, 0, sig+1);
+  mpz_import(sig_struct->s, 20, 1, 1, 0, 0, sig+21);
+  
+  (void)algo;
+  
+  return nettle_dsa_sha1_verify_digest(key, digest, sig_struct);
+} 
+ 
+#ifndef NO_NETTLE_ECC
+static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len, 
+				unsigned char *sig, size_t sig_len,
+				unsigned char *digest, size_t digest_len, int algo)
+{
+  unsigned char *p;
+  unsigned int t;
+  struct ecc_point *key;
+
+  static struct ecc_point *key_256 = NULL, *key_384 = NULL;
+  static mpz_t x, y;
+  static struct dsa_signature *sig_struct;
+  
+  if (!sig_struct)
+    {
+      if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
+	return 0;
+      
+      nettle_dsa_signature_init(sig_struct);
+      mpz_init(x);
+      mpz_init(y);
+    }
+  
+  switch (algo)
+    {
+    case 13:
+      if (!key_256)
+	{
+	  if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
+	    return 0;
+	  
+	  nettle_ecc_point_init(key_256, &nettle_secp_256r1);
+	}
+      
+      key = key_256;
+      t = 32;
+      break;
+      
+    case 14:
+      if (!key_384)
+	{
+	  if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
+	    return 0;
+	  
+	  nettle_ecc_point_init(key_384, &nettle_secp_384r1);
+	}
+      
+      key = key_384;
+      t = 48;
+      break;
+        
+    default:
+      return 0;
+    }
+  
+  if (sig_len != 2*t || key_len != 2*t ||
+      !(p = blockdata_retrieve(key_data, key_len, NULL)))
+    return 0;
+  
+  mpz_import(x, t , 1, 1, 0, 0, p);
+  mpz_import(y, t , 1, 1, 0, 0, p + t);
+
+  if (!ecc_point_set(key, x, y))
+    return 0;
+  
+  mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
+  mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
+  
+  return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
+} 
+#endif 
+
+static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
+				    unsigned char *digest, size_t digest_len, int algo)
+{
+    
+  /* Enure at runtime that we have support for this digest */
+  if (!hash_find(algo_digest_name(algo)))
+    return NULL;
+  
+  /* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
+  switch (algo)
+    {
+    case 1: case 5: case 7: case 8: case 10:
+      return dnsmasq_rsa_verify;
+      
+    case 3: case 6: 
+      return dnsmasq_dsa_verify;
+ 
+#ifndef NO_NETTLE_ECC   
+    case 13: case 14:
+      return dnsmasq_ecdsa_verify;
+#endif
+    }
+  
+  return NULL;
+}
+
+static int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
+		  unsigned char *digest, size_t digest_len, int algo)
+{
+
+  int (*func)(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
+	      unsigned char *digest, size_t digest_len, int algo);
+  
+  func = verify_func(algo);
+  
+  if (!func)
+    return 0;
+
+  return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
+}
+
+/* Convert from presentation format to wire format, in place.
+   Also map UC -> LC.
+   Note that using extract_name to get presentation format
+   then calling to_wire() removes compression and maps case,
+   thus generating names in canonical form.
+   Calling to_wire followed by from_wire is almost an identity,
+   except that the UC remains mapped to LC. 
+
+   Note that both /000 and '.' are allowed within labels. These get
+   represented in presentation format using NAME_ESCAPE as an escape
+   character. In theory, if all the characters in a name were /000 or
+   '.' or NAME_ESCAPE then all would have to be escaped, so the 
+   presentation format would be twice as long as the spec (1024). 
+   The buffers are all declared as 2049 (allowing for the trailing zero) 
+   for this reason.
+*/
+static int to_wire(char *name)
+{
+  unsigned char *l, *p, *q, term;
+  int len;
+
+  for (l = (unsigned char*)name; *l != 0; l = p)
+    {
+      for (p = l; *p != '.' && *p != 0; p++)
+	if (*p >= 'A' && *p <= 'Z')
+	  *p = *p - 'A' + 'a';
+	else if (*p == NAME_ESCAPE)
+	  {
+	    for (q = p; *q; q++)
+	      *q = *(q+1);
+	    (*p)--;
+	  }
+      term = *p;
+      
+      if ((len = p - l) != 0)
+	memmove(l+1, l, len);
+      *l = len;
+      
+      p++;
+      
+      if (term == 0)
+	*p = 0;
+    }
+  
+  return l + 1 - (unsigned char *)name;
+}
+
+/* Note: no compression  allowed in input. */
+static void from_wire(char *name)
+{
+  unsigned char *l, *p, *last;
+  int len;
+  
+  for (last = (unsigned char *)name; *last != 0; last += *last+1);
+  
+  for (l = (unsigned char *)name; *l != 0; l += len+1)
+    {
+      len = *l;
+      memmove(l, l+1, len);
+      for (p = l; p < l + len; p++)
+	if (*p == '.' || *p == 0 || *p == NAME_ESCAPE)
+	  {
+	    memmove(p+1, p, 1 + last - p);
+	    len++;
+	    *p++ = NAME_ESCAPE; 
+	    (*p)++;
+	  }
+	
+      l[len] = '.';
+    }
+
+  if ((char *)l != name)
+    *(l-1) = 0;
+}
+
+/* Input in presentation format */
+static int count_labels(char *name)
+{
+  int i;
+
+  if (*name == 0)
+    return 0;
+
+  for (i = 0; *name; name++)
+    if (*name == '.')
+      i++;
+
+  return i+1;
+}
+
+/* Implement RFC1982 wrapped compare for 32-bit numbers */
+static int serial_compare_32(u32 s1, u32 s2)
+{
+  if (s1 == s2)
+    return SERIAL_EQ;
+
+  if ((s1 < s2 && (s2 - s1) < (1UL<<31)) ||
+      (s1 > s2 && (s1 - s2) > (1UL<<31)))
+    return SERIAL_LT;
+  if ((s1 < s2 && (s2 - s1) > (1UL<<31)) ||
+      (s1 > s2 && (s1 - s2) < (1UL<<31)))
+    return SERIAL_GT;
+  return SERIAL_UNDEF;
+}
+
+/* Called at startup. If the timestamp file is configured and exists, put its mtime on
+   timestamp_time. If it doesn't exist, create it, and set the mtime to 1-1-2015.
+   return -1 -> Cannot create file.
+           0 -> not using timestamp, or timestamp exists and is in past.
+           1 -> timestamp exists and is in future.
+*/
+
+static time_t timestamp_time;
+
+int setup_timestamp(void)
+{
+  struct stat statbuf;
+  
+  daemon->back_to_the_future = 0;
+  
+  if (!daemon->timestamp_file)
+    return 0;
+  
+  if (stat(daemon->timestamp_file, &statbuf) != -1)
+    {
+      timestamp_time = statbuf.st_mtime;
+    check_and_exit:
+      if (difftime(timestamp_time, time(0)) <=  0)
+	{
+	  /* time already OK, update timestamp, and do key checking from the start. */
+	  if (utimes(daemon->timestamp_file, NULL) == -1)
+	    my_syslog(LOG_ERR, _("failed to update mtime on %s: %s"), daemon->timestamp_file, strerror(errno));
+	  daemon->back_to_the_future = 1;
+	  return 0;
+	}
+      return 1;
+    }
+  
+  if (errno == ENOENT)
+    {
+      /* NB. for explanation of O_EXCL flag, see comment on pidfile in dnsmasq.c */ 
+      int fd = open(daemon->timestamp_file, O_WRONLY | O_CREAT | O_NONBLOCK | O_EXCL, 0666);
+      if (fd != -1)
+	{
+	  struct timeval tv[2];
+
+	  close(fd);
+	  
+	  timestamp_time = 1420070400; /* 1-1-2015 */
+	  tv[0].tv_sec = tv[1].tv_sec = timestamp_time;
+	  tv[0].tv_usec = tv[1].tv_usec = 0;
+	  if (utimes(daemon->timestamp_file, tv) == 0)
+	    goto check_and_exit;
+	}
+    }
+
+  return -1;
+}
+
+/* Check whether today/now is between date_start and date_end */
+static int check_date_range(u32 date_start, u32 date_end)
+{
+  unsigned long curtime = time(0);
+ 
+  /* Checking timestamps may be temporarily disabled */
+    
+  /* If the current time if _before_ the timestamp
+     on our persistent timestamp file, then assume the
+     time if not yet correct, and don't check the
+     key timestamps. As soon as the current time is
+     later then the timestamp, update the timestamp
+     and start checking keys */
+  if (daemon->timestamp_file)
+    {
+      if (daemon->back_to_the_future == 0 && difftime(timestamp_time, curtime) <= 0)
+	{
+	  if (utimes(daemon->timestamp_file, NULL) != 0)
+	    my_syslog(LOG_ERR, _("failed to update mtime on %s: %s"), daemon->timestamp_file, strerror(errno));
+	  
+	  my_syslog(LOG_INFO, _("system time considered valid, now checking DNSSEC signature timestamps."));
+	  daemon->back_to_the_future = 1;
+	  daemon->dnssec_no_time_check = 0;
+	  queue_event(EVENT_RELOAD); /* purge cache */
+	} 
+
+      if (daemon->back_to_the_future == 0)
+	return 1;
+    }
+  else if (daemon->dnssec_no_time_check)
+    return 1;
+  
+  /* We must explicitly check against wanted values, because of SERIAL_UNDEF */
+  return serial_compare_32(curtime, date_start) == SERIAL_GT
+    && serial_compare_32(curtime, date_end) == SERIAL_LT;
+}
+
+/* Return bytes of canonicalised rdata, when the return value is zero, the remaining 
+   data, pointed to by *p, should be used raw. */
+static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff, int bufflen,
+		     unsigned char **p, u16 **desc)
+{
+  int d = **desc;
+  
+  /* No more data needs mangling */
+  if (d == (u16)-1)
+    {
+      /* If there's more data than we have space for, just return what fits,
+	 we'll get called again for more chunks */
+      if (end - *p > bufflen)
+	{
+	  memcpy(buff, *p, bufflen);
+	  *p += bufflen;
+	  return bufflen;
+	}
+      
+      return 0;
+    }
+ 
+  (*desc)++;
+  
+  if (d == 0 && extract_name(header, plen, p, buff, 1, 0))
+    /* domain-name, canonicalise */
+    return to_wire(buff);
+  else
+    { 
+      /* plain data preceding a domain-name, don't run off the end of the data */
+      if ((end - *p) < d)
+	d = end - *p;
+      
+      if (d != 0)
+	{
+	  memcpy(buff, *p, d);
+	  *p += d;
+	}
+      
+      return d;
+    }
+}
+
+/* Bubble sort the RRset into the canonical order. 
+   Note that the byte-streams from two RRs may get unsynced: consider 
+   RRs which have two domain-names at the start and then other data.
+   The domain-names may have different lengths in each RR, but sort equal
+
+   ------------
+   |abcde|fghi|
+   ------------
+   |abcd|efghi|
+   ------------
+
+   leaving the following bytes as deciding the order. Hence the nasty left1 and left2 variables.
+*/
+
+static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx, 
+		       unsigned char **rrset, char *buff1, char *buff2)
+{
+  int swap, quit, i;
+  
+  do
+    {
+      for (swap = 0, i = 0; i < rrsetidx-1; i++)
+	{
+	  int rdlen1, rdlen2, left1, left2, len1, len2, len, rc;
+	  u16 *dp1, *dp2;
+	  unsigned char *end1, *end2;
+	  /* Note that these have been determined to be OK previously,
+	     so we don't need to check for NULL return here. */
+	  unsigned char *p1 = skip_name(rrset[i], header, plen, 10);
+	  unsigned char *p2 = skip_name(rrset[i+1], header, plen, 10);
+	  
+	  p1 += 8; /* skip class, type, ttl */
+	  GETSHORT(rdlen1, p1);
+	  end1 = p1 + rdlen1;
+	  
+	  p2 += 8; /* skip class, type, ttl */
+	  GETSHORT(rdlen2, p2);
+	  end2 = p2 + rdlen2; 
+	  
+	  dp1 = dp2 = rr_desc;
+	  
+	  for (quit = 0, left1 = 0, left2 = 0, len1 = 0, len2 = 0; !quit;)
+	    {
+	      if (left1 != 0)
+		memmove(buff1, buff1 + len1 - left1, left1);
+	      
+	      if ((len1 = get_rdata(header, plen, end1, buff1 + left1, (MAXDNAME * 2) - left1, &p1, &dp1)) == 0)
+		{
+		  quit = 1;
+		  len1 = end1 - p1;
+		  memcpy(buff1 + left1, p1, len1);
+		}
+	      len1 += left1;
+	      
+	      if (left2 != 0)
+		memmove(buff2, buff2 + len2 - left2, left2);
+	      
+	      if ((len2 = get_rdata(header, plen, end2, buff2 + left2, (MAXDNAME *2) - left2, &p2, &dp2)) == 0)
+		{
+		  quit = 1;
+		  len2 = end2 - p2;
+		  memcpy(buff2 + left2, p2, len2);
+		}
+	      len2 += left2;
+	       
+	      if (len1 > len2)
+		left1 = len1 - len2, left2 = 0, len = len2;
+	      else
+		left2 = len2 - len1, left1 = 0, len = len1;
+	      
+	      rc = (len == 0) ? 0 : memcmp(buff1, buff2, len);
+	      
+	      if (rc > 0 || (rc == 0 && quit && len1 > len2))
+		{
+		  unsigned char *tmp = rrset[i+1];
+		  rrset[i+1] = rrset[i];
+		  rrset[i] = tmp;
+		  swap = quit = 1;
+		}
+	      else if (rc < 0)
+		quit = 1;
+	    }
+	}
+    } while (swap);
+}
+
+static unsigned char **rrset = NULL, **sigs = NULL;
+
+/* Get pointers to RRset members and signature(s) for same.
+   Check signatures, and return keyname associated in keyname. */
+static int explore_rrset(struct dns_header *header, size_t plen, int class, int type, 
+			 char *name, char *keyname, int *sigcnt, int *rrcnt)
+{
+  static int rrset_sz = 0, sig_sz = 0; 
+  unsigned char *p;
+  int rrsetidx, sigidx, j, rdlen, res;
+  int gotkey = 0;
+
+  if (!(p = skip_questions(header, plen)))
+    return STAT_BOGUS;
+
+   /* look for RRSIGs for this RRset and get pointers to each RR in the set. */
+  for (rrsetidx = 0, sigidx = 0, j = ntohs(header->ancount) + ntohs(header->nscount); 
+       j != 0; j--) 
+    {
+      unsigned char *pstart, *pdata;
+      int stype, sclass, type_covered;
+
+      pstart = p;
+      
+      if (!(res = extract_name(header, plen, &p, name, 0, 10)))
+	return STAT_BOGUS; /* bad packet */
+      
+      GETSHORT(stype, p);
+      GETSHORT(sclass, p);
+      p += 4; /* TTL */
+      
+      pdata = p;
+
+      GETSHORT(rdlen, p);
+      
+      if (!CHECK_LEN(header, p, plen, rdlen))
+	return 0; 
+      
+      if (res == 1 && sclass == class)
+	{
+	  if (stype == type)
+	    {
+	      if (!expand_workspace(&rrset, &rrset_sz, rrsetidx))
+		return 0; 
+	      
+	      rrset[rrsetidx++] = pstart;
+	    }
+	  
+	  if (stype == T_RRSIG)
+	    {
+	      if (rdlen < 18)
+		return 0; /* bad packet */ 
+	      
+	      GETSHORT(type_covered, p);
+	      p += 16; /* algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag */
+	      
+	      if (gotkey)
+		{
+		  /* If there's more than one SIG, ensure they all have same keyname */
+		  if (extract_name(header, plen, &p, keyname, 0, 0) != 1)
+		    return 0;
+		}
+	      else
+		{
+		  gotkey = 1;
+		  
+		  if (!extract_name(header, plen, &p, keyname, 1, 0))
+		    return 0;
+		  
+		  /* RFC 4035 5.3.1 says that the Signer's Name field MUST equal
+		     the name of the zone containing the RRset. We can't tell that
+		     for certain, but we can check that  the RRset name is equal to
+		     or encloses the signers name, which should be enough to stop 
+		     an attacker using signatures made with the key of an unrelated 
+		     zone he controls. Note that the root key is always allowed. */
+		  if (*keyname != 0)
+		    {
+		      char *name_start;
+		      for (name_start = name; !hostname_isequal(name_start, keyname); )
+			if ((name_start = strchr(name_start, '.')))
+			  name_start++; /* chop a label off and try again */
+			else
+			  return 0;
+		    }
+		}
+		  
+	      
+	      if (type_covered == type)
+		{
+		  if (!expand_workspace(&sigs, &sig_sz, sigidx))
+		    return 0; 
+		  
+		  sigs[sigidx++] = pdata;
+		} 
+	      
+	      p = pdata + 2; /* restore for ADD_RDLEN */
+	    }
+	}
+      
+      if (!ADD_RDLEN(header, p, plen, rdlen))
+	return 0;
+    }
+  
+  *sigcnt = sigidx;
+  *rrcnt = rrsetidx;
+
+  return 1;
+}
+
+/* Validate a single RRset (class, type, name) in the supplied DNS reply 
+   Return code:
+   STAT_SECURE   if it validates.
+   STAT_SECURE_WILDCARD if it validates and is the result of wildcard expansion.
+   (In this case *wildcard_out points to the "body" of the wildcard within name.) 
+   STAT_BOGUS    signature is wrong, bad packet.
+   STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
+   STAT_NEED_DS  need DS to complete validation (name is returned in keyname)
+
+   If key is non-NULL, use that key, which has the algo and tag given in the params of those names,
+   otherwise find the key in the cache.
+
+   Name is unchanged on exit. keyname is used as workspace and trashed.
+
+   Call explore_rrset first to find and count RRs and sigs.
+*/
+static int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class, int type, int sigidx, int rrsetidx, 
+			  char *name, char *keyname, char **wildcard_out, struct blockdata *key, int keylen, int algo_in, int keytag_in)
+{
+  unsigned char *p;
+  int rdlen, j, name_labels, algo, labels, orig_ttl, key_tag;
+  struct crec *crecp = NULL;
+  u16 *rr_desc = rrfilter_desc(type);
+  u32 sig_expiration, sig_inception
+;
+  if (wildcard_out)
+    *wildcard_out = NULL;
+  
+  name_labels = count_labels(name); /* For 4035 5.3.2 check */
+
+  /* Sort RRset records into canonical order. 
+     Note that at this point keyname and daemon->workspacename buffs are
+     unused, and used as workspace by the sort. */
+  sort_rrset(header, plen, rr_desc, rrsetidx, rrset, daemon->workspacename, keyname);
+         
+  /* Now try all the sigs to try and find one which validates */
+  for (j = 0; j <sigidx; j++)
+    {
+      unsigned char *psav, *sig, *digest;
+      int i, wire_len, sig_len;
+      const struct nettle_hash *hash;
+      void *ctx;
+      char *name_start;
+      u32 nsigttl;
+      
+      p = sigs[j];
+      GETSHORT(rdlen, p); /* rdlen >= 18 checked previously */
+      psav = p;
+      
+      p += 2; /* type_covered - already checked */
+      algo = *p++;
+      labels = *p++;
+      GETLONG(orig_ttl, p);
+      GETLONG(sig_expiration, p);
+      GETLONG(sig_inception, p);
+      GETSHORT(key_tag, p);
+      
+      if (!extract_name(header, plen, &p, keyname, 1, 0))
+	return STAT_BOGUS;
+
+      if (!check_date_range(sig_inception, sig_expiration) ||
+	  labels > name_labels ||
+	  !(hash = hash_find(algo_digest_name(algo))) ||
+	  !hash_init(hash, &ctx, &digest))
+	continue;
+      
+      /* OK, we have the signature record, see if the relevant DNSKEY is in the cache. */
+      if (!key && !(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
+	return STAT_NEED_KEY;
+      
+      sig = p;
+      sig_len = rdlen - (p - psav);
+              
+      nsigttl = htonl(orig_ttl);
+      
+      hash->update(ctx, 18, psav);
+      wire_len = to_wire(keyname);
+      hash->update(ctx, (unsigned int)wire_len, (unsigned char*)keyname);
+      from_wire(keyname);
+      
+      for (i = 0; i < rrsetidx; ++i)
+	{
+	  int seg;
+	  unsigned char *end, *cp;
+	  u16 len, *dp;
+	  
+	  p = rrset[i];
+	  if (!extract_name(header, plen, &p, name, 1, 10)) 
+	    return STAT_BOGUS;
+
+	  name_start = name;
+	  
+	  /* if more labels than in RRsig name, hash *.<no labels in rrsig labels field>  4035 5.3.2 */
+	  if (labels < name_labels)
+	    {
+	      int k;
+	      for (k = name_labels - labels; k != 0; k--)
+		{
+		  while (*name_start != '.' && *name_start != 0)
+		    name_start++;
+		  if (k != 1 && *name_start == '.')
+		    name_start++;
+		}
+	      
+	      if (wildcard_out)
+		*wildcard_out = name_start+1;
+
+	      name_start--;
+	      *name_start = '*';
+	    }
+	  
+	  wire_len = to_wire(name_start);
+	  hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name_start);
+	  hash->update(ctx, 4, p); /* class and type */
+	  hash->update(ctx, 4, (unsigned char *)&nsigttl);
+	  
+	  p += 8; /* skip class, type, ttl */
+	  GETSHORT(rdlen, p);
+	  if (!CHECK_LEN(header, p, plen, rdlen))
+	    return STAT_BOGUS; 
+	  
+	  end = p + rdlen;
+	  
+	  /* canonicalise rdata and calculate length of same, use name buffer as workspace.
+	     Note that name buffer is twice MAXDNAME long in DNSSEC mode. */
+	  cp = p;
+	  dp = rr_desc;
+	  for (len = 0; (seg = get_rdata(header, plen, end, name, MAXDNAME * 2, &cp, &dp)) != 0; len += seg);
+	  len += end - cp;
+	  len = htons(len);
+	  hash->update(ctx, 2, (unsigned char *)&len); 
+	  
+	  /* Now canonicalise again and digest. */
+	  cp = p;
+	  dp = rr_desc;
+	  while ((seg = get_rdata(header, plen, end, name, MAXDNAME * 2, &cp, &dp)))
+	    hash->update(ctx, seg, (unsigned char *)name);
+	  if (cp != end)
+	    hash->update(ctx, end - cp, cp);
+	}
+     
+      hash->digest(ctx, hash->digest_size, digest);
+      
+      /* namebuff used for workspace above, restore to leave unchanged on exit */
+      p = (unsigned char*)(rrset[0]);
+      extract_name(header, plen, &p, name, 1, 0);
+
+      if (key)
+	{
+	  if (algo_in == algo && keytag_in == key_tag &&
+	      verify(key, keylen, sig, sig_len, digest, hash->digest_size, algo))
+	    return STAT_SECURE;
+	}
+      else
+	{
+	  /* iterate through all possible keys 4035 5.3.1 */
+	  for (; crecp; crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY))
+	    if (crecp->addr.key.algo == algo && 
+		crecp->addr.key.keytag == key_tag &&
+		crecp->uid == (unsigned int)class &&
+		verify(crecp->addr.key.keydata, crecp->addr.key.keylen, sig, sig_len, digest, hash->digest_size, algo))
+	      return (labels < name_labels) ? STAT_SECURE_WILDCARD : STAT_SECURE;
+	}
+    }
+
+  return STAT_BOGUS;
+}
+ 
+
+/* The DNS packet is expected to contain the answer to a DNSKEY query.
+   Put all DNSKEYs in the answer which are valid into the cache.
+   return codes:
+         STAT_OK        Done, key(s) in cache.
+	 STAT_BOGUS     No DNSKEYs found, which  can be validated with DS,
+	                or self-sign for DNSKEY RRset is not valid, bad packet.
+	 STAT_NEED_DS   DS records to validate a key not found, name in keyname 
+	 STAT_NEED_KEY  DNSKEY records to validate a key not found, name in keyname 
+*/
+int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
+{
+  unsigned char *psave, *p = (unsigned char *)(header+1);
+  struct crec *crecp, *recp1;
+  int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag;
+  struct blockdata *key;
+  struct all_addr a;
+
+  if (ntohs(header->qdcount) != 1 ||
+      !extract_name(header, plen, &p, name, 1, 4))
+    return STAT_BOGUS;
+
+  GETSHORT(qtype, p);
+  GETSHORT(qclass, p);
+  
+  if (qtype != T_DNSKEY || qclass != class || ntohs(header->ancount) == 0)
+    return STAT_BOGUS;
+
+  /* See if we have cached a DS record which validates this key */
+  if (!(crecp = cache_find_by_name(NULL, name, now, F_DS)))
+    {
+      strcpy(keyname, name);
+      return STAT_NEED_DS;
+    }
+  
+  /* NOTE, we need to find ONE DNSKEY which matches the DS */
+  for (valid = 0, j = ntohs(header->ancount); j != 0 && !valid; j--) 
+    {
+      /* Ensure we have type, class  TTL and length */
+      if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
+	return STAT_BOGUS; /* bad packet */
+  
+      GETSHORT(qtype, p); 
+      GETSHORT(qclass, p);
+      GETLONG(ttl, p);
+      GETSHORT(rdlen, p);
+ 
+      if (!CHECK_LEN(header, p, plen, rdlen) || rdlen < 4)
+	return STAT_BOGUS; /* bad packet */
+      
+      if (qclass != class || qtype != T_DNSKEY || rc == 2)
+	{
+	  p += rdlen;
+	  continue;
+	}
+            
+      psave = p;
+      
+      GETSHORT(flags, p);
+      if (*p++ != 3)
+	return STAT_BOGUS;
+      algo = *p++;
+      keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
+      key = NULL;
+      
+      /* key must have zone key flag set */
+      if (flags & 0x100)
+	key = blockdata_alloc((char*)p, rdlen - 4);
+      
+      p = psave;
+      
+      if (!ADD_RDLEN(header, p, plen, rdlen))
+	{
+	  if (key)
+	    blockdata_free(key);
+	  return STAT_BOGUS; /* bad packet */
+	}
+
+      /* No zone key flag or malloc failure */
+      if (!key)
+	continue;
+      
+      for (recp1 = crecp; recp1; recp1 = cache_find_by_name(recp1, name, now, F_DS))
+	{
+	  void *ctx;
+	  unsigned char *digest, *ds_digest;
+	  const struct nettle_hash *hash;
+	  int sigcnt, rrcnt;
+
+	  if (recp1->addr.ds.algo == algo && 
+	      recp1->addr.ds.keytag == keytag &&
+	      recp1->uid == (unsigned int)class &&
+	      (hash = hash_find(ds_digest_name(recp1->addr.ds.digest))) &&
+	      hash_init(hash, &ctx, &digest))
+	    
+	    {
+	      int wire_len = to_wire(name);
+	      
+	      /* Note that digest may be different between DSs, so 
+		 we can't move this outside the loop. */
+	      hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name);
+	      hash->update(ctx, (unsigned int)rdlen, psave);
+	      hash->digest(ctx, hash->digest_size, digest);
+	      
+	      from_wire(name);
+	      
+	      if (!(recp1->flags & F_NEG) &&
+		  recp1->addr.ds.keylen == (int)hash->digest_size &&
+		  (ds_digest = blockdata_retrieve(recp1->addr.key.keydata, recp1->addr.ds.keylen, NULL)) &&
+		  memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
+		  explore_rrset(header, plen, class, T_DNSKEY, name, keyname, &sigcnt, &rrcnt) &&
+		  sigcnt != 0 && rrcnt != 0 &&
+		  validate_rrset(now, header, plen, class, T_DNSKEY, sigcnt, rrcnt, name, keyname, 
+				 NULL, key, rdlen - 4, algo, keytag) == STAT_SECURE)
+		{
+		  valid = 1;
+		  break;
+		}
+	    }
+	}
+      blockdata_free(key);
+    }
+
+  if (valid)
+    {
+      /* DNSKEY RRset determined to be OK, now cache it. */
+      cache_start_insert();
+      
+      p = skip_questions(header, plen);
+
+      for (j = ntohs(header->ancount); j != 0; j--) 
+	{
+	  /* Ensure we have type, class  TTL and length */
+	  if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
+	    return STAT_BOGUS; /* bad packet */
+	  
+	  GETSHORT(qtype, p); 
+	  GETSHORT(qclass, p);
+	  GETLONG(ttl, p);
+	  GETSHORT(rdlen, p);
+	    
+	  if (!CHECK_LEN(header, p, plen, rdlen))
+	    return STAT_BOGUS; /* bad packet */
+	  
+	  if (qclass == class && rc == 1)
+	    {
+	      psave = p;
+	      
+	      if (qtype == T_DNSKEY)
+		{
+		  if (rdlen < 4)
+		    return STAT_BOGUS; /* bad packet */
+		  
+		  GETSHORT(flags, p);
+		  if (*p++ != 3)
+		    return STAT_BOGUS;
+		  algo = *p++;
+		  keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
+		  
+		  /* Cache needs to known class for DNSSEC stuff */
+		  a.addr.dnssec.class = class;
+		  
+		  if ((key = blockdata_alloc((char*)p, rdlen - 4)))
+		    {
+		      if (!(recp1 = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK)))
+			{
+			  blockdata_free(key);
+			  return STAT_BOGUS;
+			}
+		      else
+			{
+			  a.addr.log.keytag = keytag;
+			  a.addr.log.algo = algo;
+			  if (verify_func(algo))
+			    log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu");
+			  else
+			    log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)");
+			  
+			  recp1->addr.key.keylen = rdlen - 4;
+			  recp1->addr.key.keydata = key;
+			  recp1->addr.key.algo = algo;
+			  recp1->addr.key.keytag = keytag;
+			  recp1->addr.key.flags = flags;
+			}
+		    }
+		}
+	      	      
+	      p = psave;
+	    }
+
+	  if (!ADD_RDLEN(header, p, plen, rdlen))
+	    return STAT_BOGUS; /* bad packet */
+	}
+      
+      /* commit cache insert. */
+      cache_end_insert();
+      return STAT_OK;
+    }
+
+  log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY");
+  return STAT_BOGUS;
+}
+
+/* The DNS packet is expected to contain the answer to a DS query
+   Put all DSs in the answer which are valid into the cache.
+   Also handles replies which prove that there's no DS at this location, 
+   either because the zone is unsigned or this isn't a zone cut. These are
+   cached too.
+   return codes:
+   STAT_OK          At least one valid DS found and in cache.
+   STAT_BOGUS       no DS in reply or not signed, fails validation, bad packet.
+   STAT_NEED_KEY    DNSKEY records to validate a DS not found, name in keyname
+   STAT_NEED_DS     DS record needed.
+*/
+
+int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
+{
+  unsigned char *p = (unsigned char *)(header+1);
+  int qtype, qclass, rc, i, neganswer, nons;
+  int aclass, atype, rdlen;
+  unsigned long ttl;
+  struct all_addr a;
+
+  if (ntohs(header->qdcount) != 1 ||
+      !(p = skip_name(p, header, plen, 4)))
+    return STAT_BOGUS;
+  
+  GETSHORT(qtype, p);
+  GETSHORT(qclass, p);
+
+  if (qtype != T_DS || qclass != class)
+    rc = STAT_BOGUS;
+  else
+    rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons);
+  /* Note dnssec_validate_reply() will have cached positive answers */
+  
+  if (rc == STAT_INSECURE)
+    rc = STAT_BOGUS;
+ 
+  p = (unsigned char *)(header+1);
+  extract_name(header, plen, &p, name, 1, 4);
+  p += 4; /* qtype, qclass */
+  
+  /* If the key needed to validate the DS is on the same domain as the DS, we'll
+     loop getting nowhere. Stop that now. This can happen of the DS answer comes
+     from the DS's zone, and not the parent zone. */
+  if (rc == STAT_BOGUS || (rc == STAT_NEED_KEY && hostname_isequal(name, keyname)))
+    {
+      log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
+      return STAT_BOGUS;
+    }
+  
+  if (rc != STAT_SECURE)
+    return rc;
+   
+  if (!neganswer)
+    {
+      cache_start_insert();
+      
+      for (i = 0; i < ntohs(header->ancount); i++)
+	{
+	  if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
+	    return STAT_BOGUS; /* bad packet */
+	  
+	  GETSHORT(atype, p);
+	  GETSHORT(aclass, p);
+	  GETLONG(ttl, p);
+	  GETSHORT(rdlen, p);
+	  
+	  if (!CHECK_LEN(header, p, plen, rdlen))
+	    return STAT_BOGUS; /* bad packet */
+	  
+	  if (aclass == class && atype == T_DS && rc == 1)
+	    { 
+	      int algo, digest, keytag;
+	      unsigned char *psave = p;
+	      struct blockdata *key;
+	      struct crec *crecp;
+
+	      if (rdlen < 4)
+		return STAT_BOGUS; /* bad packet */
+	      
+	      GETSHORT(keytag, p);
+	      algo = *p++;
+	      digest = *p++;
+	      
+	      /* Cache needs to known class for DNSSEC stuff */
+	      a.addr.dnssec.class = class;
+	      
+	      if ((key = blockdata_alloc((char*)p, rdlen - 4)))
+		{
+		  if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
+		    {
+		      blockdata_free(key);
+		      return STAT_BOGUS;
+		    }
+		  else
+		    {
+		      a.addr.log.keytag = keytag;
+		      a.addr.log.algo = algo;
+		      a.addr.log.digest = digest;
+		      if (hash_find(ds_digest_name(digest)) && verify_func(algo))
+			log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu");
+		      else
+			log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)");
+		      
+		      crecp->addr.ds.digest = digest;
+		      crecp->addr.ds.keydata = key;
+		      crecp->addr.ds.algo = algo;
+		      crecp->addr.ds.keytag = keytag;
+		      crecp->addr.ds.keylen = rdlen - 4; 
+		    } 
+		}
+	      
+	      p = psave;
+	    }
+	  if (!ADD_RDLEN(header, p, plen, rdlen))
+	    return STAT_BOGUS; /* bad packet */
+	}
+
+      cache_end_insert();
+
+    }
+  else
+    {
+      int flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
+      unsigned long minttl = ULONG_MAX;
+      
+      if (!(p = skip_section(p, ntohs(header->ancount), header, plen)))
+	return STAT_BOGUS;
+      
+      if (RCODE(header) == NXDOMAIN)
+	flags |= F_NXDOMAIN;
+      
+      /* We only cache validated DS records, DNSSECOK flag hijacked 
+	 to store presence/absence of NS. */
+      if (nons)
+	flags &= ~F_DNSSECOK;
+      
+      for (i = ntohs(header->nscount); i != 0; i--)
+	{
+	  if (!(p = skip_name(p, header, plen, 0)))
+	    return STAT_BOGUS;
+	  
+	  GETSHORT(atype, p); 
+	  GETSHORT(aclass, p);
+	  GETLONG(ttl, p);
+	  GETSHORT(rdlen, p);
+	  
+	  if (!CHECK_LEN(header, p, plen, rdlen))
+	    return STAT_BOGUS; /* bad packet */
+	  
+	  if (aclass != class || atype != T_SOA)
+	    {
+	      p += rdlen;
+	      continue;
+	    }
+	  
+	  if (ttl < minttl)
+	    minttl = ttl;
+	  
+	  /* MNAME */
+	  if (!(p = skip_name(p, header, plen, 0)))
+	    return STAT_BOGUS;
+	  /* RNAME */
+	  if (!(p = skip_name(p, header, plen, 20)))
+	    return STAT_BOGUS;
+	  p += 16; /* SERIAL REFRESH RETRY EXPIRE */
+	  
+	  GETLONG(ttl, p); /* minTTL */
+	  if (ttl < minttl)
+	    minttl = ttl;
+	  
+	  break;
+	}
+      
+      if (i != 0)
+	{
+	  cache_start_insert();
+	  
+	  a.addr.dnssec.class = class;
+	  if (!cache_insert(name, &a, now, ttl, flags))
+	    return STAT_BOGUS;
+	  
+	  cache_end_insert();  
+	  
+	  log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "no DS");
+	}
+    }
+      
+  return STAT_OK;
+}
+
+
+/* 4034 6.1 */
+static int hostname_cmp(const char *a, const char *b)
+{
+  char *sa, *ea, *ca, *sb, *eb, *cb;
+  unsigned char ac, bc;
+  
+  sa = ea = (char *)a + strlen(a);
+  sb = eb = (char *)b + strlen(b);
+ 
+  while (1)
+    {
+      while (sa != a && *(sa-1) != '.')
+	sa--;
+      
+      while (sb != b && *(sb-1) != '.')
+	sb--;
+
+      ca = sa;
+      cb = sb;
+
+      while (1) 
+	{
+	  if (ca == ea)
+	    {
+	      if (cb == eb)
+		break;
+	      
+	      return -1;
+	    }
+	  
+	  if (cb == eb)
+	    return 1;
+	  
+	  ac = (unsigned char) *ca++;
+	  bc = (unsigned char) *cb++;
+	  
+	  if (ac >= 'A' && ac <= 'Z')
+	    ac += 'a' - 'A';
+	  if (bc >= 'A' && bc <= 'Z')
+	    bc += 'a' - 'A';
+	  
+	  if (ac < bc)
+	    return -1;
+	  else if (ac != bc)
+	    return 1;
+	}
+
+     
+      if (sa == a)
+	{
+	  if (sb == b)
+	    return 0;
+	  
+	  return -1;
+	}
+      
+      if (sb == b)
+	return 1;
+      
+      ea = --sa;
+      eb = --sb;
+    }
+}
+
+static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
+				    char *workspace1, char *workspace2, char *name, int type, int *nons)
+{
+  int i, rc, rdlen;
+  unsigned char *p, *psave;
+  int offset = (type & 0xff) >> 3;
+  int mask = 0x80 >> (type & 0x07);
+
+  if (nons)
+    *nons = 1;
+  
+  /* Find NSEC record that proves name doesn't exist */
+  for (i = 0; i < nsec_count; i++)
+    {
+      p = nsecs[i];
+      if (!extract_name(header, plen, &p, workspace1, 1, 10))
+	return 0;
+      p += 8; /* class, type, TTL */
+      GETSHORT(rdlen, p);
+      psave = p;
+      if (!extract_name(header, plen, &p, workspace2, 1, 10))
+	return 0;
+      
+      rc = hostname_cmp(workspace1, name);
+      
+      if (rc == 0)
+	{
+	  /* 4035 para 5.4. Last sentence */
+	  if (type == T_NSEC || type == T_RRSIG)
+	    return 1;
+
+	  /* NSEC with the same name as the RR we're testing, check
+	     that the type in question doesn't appear in the type map */
+	  rdlen -= p - psave;
+	  /* rdlen is now length of type map, and p points to it */
+	  
+	  /* If we can prove that there's no NS record, return that information. */
+	  if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) != 0)
+	    *nons = 0;
+	  
+	  if (rdlen >= 2 && p[0] == 0)
+	    {
+	      /* A CNAME answer would also be valid, so if there's a CNAME is should 
+		 have been returned. */
+	      if ((p[2] & (0x80 >> T_CNAME)) != 0)
+		return 0;
+	      
+	      /* If the SOA bit is set for a DS record, then we have the
+		 DS from the wrong side of the delegation. */
+	      if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
+		return 0;
+	    }
+
+	  while (rdlen >= 2)
+	    {
+	      if (!CHECK_LEN(header, p, plen, rdlen))
+		return 0;
+	      
+	      if (p[0] == type >> 8)
+		{
+		  /* Does the NSEC say our type exists? */
+		  if (offset < p[1] && (p[offset+2] & mask) != 0)
+		    return 0;
+		  
+		  break; /* finished checking */
+		}
+	      
+	      rdlen -= p[1];
+	      p +=  p[1];
+	    }
+	  
+	  return 1;
+	}
+      else if (rc == -1)
+	{
+	  /* Normal case, name falls between NSEC name and next domain name,
+	     wrap around case, name falls between NSEC name (rc == -1) and end */
+	  if (hostname_cmp(workspace2, name) >= 0 || hostname_cmp(workspace1, workspace2) >= 0)
+	    return 1;
+	}
+      else 
+	{
+	  /* wrap around case, name falls between start and next domain name */
+	  if (hostname_cmp(workspace1, workspace2) >= 0 && hostname_cmp(workspace2, name) >=0 )
+	    return 1;
+	}
+    }
+  
+  return 0;
+}
+
+/* return digest length, or zero on error */
+static int hash_name(char *in, unsigned char **out, struct nettle_hash const *hash, 
+		     unsigned char *salt, int salt_len, int iterations)
+{
+  void *ctx;
+  unsigned char *digest;
+  int i;
+
+  if (!hash_init(hash, &ctx, &digest))
+    return 0;
+ 
+  hash->update(ctx, to_wire(in), (unsigned char *)in);
+  hash->update(ctx, salt_len, salt);
+  hash->digest(ctx, hash->digest_size, digest);
+
+  for(i = 0; i < iterations; i++)
+    {
+      hash->update(ctx, hash->digest_size, digest);
+      hash->update(ctx, salt_len, salt);
+      hash->digest(ctx, hash->digest_size, digest);
+    }
+   
+  from_wire(in);
+
+  *out = digest;
+  return hash->digest_size;
+}
+
+/* Decode base32 to first "." or end of string */
+static int base32_decode(char *in, unsigned char *out)
+{
+  int oc, on, c, mask, i;
+  unsigned char *p = out;
+ 
+  for (c = *in, oc = 0, on = 0; c != 0 && c != '.'; c = *++in) 
+    {
+      if (c >= '0' && c <= '9')
+	c -= '0';
+      else if (c >= 'a' && c <= 'v')
+	c -= 'a', c += 10;
+      else if (c >= 'A' && c <= 'V')
+	c -= 'A', c += 10;
+      else
+	return 0;
+      
+      for (mask = 0x10, i = 0; i < 5; i++)
+        {
+	  if (c & mask)
+	    oc |= 1;
+	  mask = mask >> 1;
+	  if (((++on) & 7) == 0)
+	    *p++ = oc;
+	  oc = oc << 1;
+	}
+    }
+  
+  if ((on & 7) != 0)
+    return 0;
+
+  return p - out;
+}
+
+static int check_nsec3_coverage(struct dns_header *header, size_t plen, int digest_len, unsigned char *digest, int type,
+				char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count, int *nons)
+{
+  int i, hash_len, salt_len, base32_len, rdlen, flags;
+  unsigned char *p, *psave;
+
+  for (i = 0; i < nsec_count; i++)
+    if ((p = nsecs[i]))
+      {
+       	if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
+	    !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
+	  return 0;
+	
+	p += 8; /* class, type, TTL */
+	GETSHORT(rdlen, p);
+	psave = p;
+	p++; /* algo */
+	flags = *p++; /* flags */
+	p += 2; /* iterations */
+	salt_len = *p++; /* salt_len */
+	p += salt_len; /* salt */
+	hash_len = *p++; /* p now points to next hashed name */
+	
+	if (!CHECK_LEN(header, p, plen, hash_len))
+	  return 0;
+	
+	if (digest_len == base32_len && hash_len == base32_len)
+	  {
+	    int rc = memcmp(workspace2, digest, digest_len);
+
+	    if (rc == 0)
+	      {
+		/* We found an NSEC3 whose hashed name exactly matches the query, so
+		   we just need to check the type map. p points to the RR data for the record. */
+		
+		int offset = (type & 0xff) >> 3;
+		int mask = 0x80 >> (type & 0x07);
+		
+		p += hash_len; /* skip next-domain hash */
+		rdlen -= p - psave;
+
+		if (!CHECK_LEN(header, p, plen, rdlen))
+		  return 0;
+		
+		if (rdlen >= 2 && p[0] == 0)
+		  {
+		    /* If we can prove that there's no NS record, return that information. */
+		    if (nons && (p[2] & (0x80 >> T_NS)) != 0)
+		      *nons = 0;
+		
+		    /* A CNAME answer would also be valid, so if there's a CNAME is should 
+		       have been returned. */
+		    if ((p[2] & (0x80 >> T_CNAME)) != 0)
+		      return 0;
+		    
+		    /* If the SOA bit is set for a DS record, then we have the
+		       DS from the wrong side of the delegation. */
+		    if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
+		      return 0;
+		  }
+
+		while (rdlen >= 2)
+		  {
+		    if (p[0] == type >> 8)
+		      {
+			/* Does the NSEC3 say our type exists? */
+			if (offset < p[1] && (p[offset+2] & mask) != 0)
+			  return 0;
+			
+			break; /* finished checking */
+		      }
+		    
+		    rdlen -= p[1];
+		    p +=  p[1];
+		  }
+		
+		return 1;
+	      }
+	    else if (rc < 0)
+	      {
+		/* Normal case, hash falls between NSEC3 name-hash and next domain name-hash,
+		   wrap around case, name-hash falls between NSEC3 name-hash and end */
+		if (memcmp(p, digest, digest_len) >= 0 || memcmp(workspace2, p, digest_len) >= 0)
+		  {
+		    if ((flags & 0x01) && nons) /* opt out */
+		      *nons = 0;
+
+		    return 1;
+		  }
+	      }
+	    else 
+	      {
+		/* wrap around case, name falls between start and next domain name */
+		if (memcmp(workspace2, p, digest_len) >= 0 && memcmp(p, digest, digest_len) >= 0)
+		  {
+		    if ((flags & 0x01) && nons) /* opt out */
+		      *nons = 0;
+
+		    return 1;
+		  }
+	      }
+	  }
+      }
+
+  return 0;
+}
+
+static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
+				     char *workspace1, char *workspace2, char *name, int type, char *wildname, int *nons)
+{
+  unsigned char *salt, *p, *digest;
+  int digest_len, i, iterations, salt_len, base32_len, algo = 0;
+  struct nettle_hash const *hash;
+  char *closest_encloser, *next_closest, *wildcard;
+  
+  if (nons)
+    *nons = 1;
+  
+  /* Look though the NSEC3 records to find the first one with 
+     an algorithm we support.
+
+     Take the algo, iterations, and salt of that record
+     as the ones we're going to use, and prune any 
+     that don't match. */
+  
+  for (i = 0; i < nsec_count; i++)
+    {
+      if (!(p = skip_name(nsecs[i], header, plen, 15)))
+	return 0; /* bad packet */
+      
+      p += 10; /* type, class, TTL, rdlen */
+      algo = *p++;
+      
+      if ((hash = hash_find(nsec3_digest_name(algo))))
+	break; /* known algo */
+    }
+
+  /* No usable NSEC3s */
+  if (i == nsec_count)
+    return 0;
+
+  p++; /* flags */
+
+  GETSHORT (iterations, p);
+  /* Upper-bound iterations, to avoid DoS.
+     Strictly, there are lower bounds for small keys, but
+     since we don't have key size info here, at least limit
+     to the largest bound, for 4096-bit keys. RFC 5155 10.3 */
+  if (iterations > 2500)
+    return 0;
+  
+  salt_len = *p++;
+  salt = p;
+  if (!CHECK_LEN(header, salt, plen, salt_len))
+    return 0; /* bad packet */
+    
+  /* Now prune so we only have NSEC3 records with same iterations, salt and algo */
+  for (i = 0; i < nsec_count; i++)
+    {
+      unsigned char *nsec3p = nsecs[i];
+      int this_iter, flags;
+
+      nsecs[i] = NULL; /* Speculative, will be restored if OK. */
+      
+      if (!(p = skip_name(nsec3p, header, plen, 15)))
+	return 0; /* bad packet */
+      
+      p += 10; /* type, class, TTL, rdlen */
+      
+      if (*p++ != algo)
+	continue;
+ 
+      flags = *p++; /* flags */
+      
+      /* 5155 8.2 */
+      if (flags != 0 && flags != 1)
+	continue;
+
+      GETSHORT(this_iter, p);
+      if (this_iter != iterations)
+	continue;
+
+      if (salt_len != *p++)
+	continue;
+      
+      if (!CHECK_LEN(header, p, plen, salt_len))
+	return 0; /* bad packet */
+
+      if (memcmp(p, salt, salt_len) != 0)
+	continue;
+
+      /* All match, put the pointer back */
+      nsecs[i] = nsec3p;
+    }
+
+  if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
+    return 0;
+  
+  if (check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, nons))
+    return 1;
+
+  /* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3" 
+     or an answer inferred from a wildcard record. */
+  closest_encloser = name;
+  next_closest = NULL;
+
+  do
+    {
+      if (*closest_encloser == '.')
+	closest_encloser++;
+
+      if (wildname && hostname_isequal(closest_encloser, wildname))
+	break;
+
+      if ((digest_len = hash_name(closest_encloser, &digest, hash, salt, salt_len, iterations)) == 0)
+	return 0;
+      
+      for (i = 0; i < nsec_count; i++)
+	if ((p = nsecs[i]))
+	  {
+	    if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
+		!(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
+	      return 0;
+	  
+	    if (digest_len == base32_len &&
+		memcmp(digest, workspace2, digest_len) == 0)
+	      break; /* Gotit */
+	  }
+      
+      if (i != nsec_count)
+	break;
+      
+      next_closest = closest_encloser;
+    }
+  while ((closest_encloser = strchr(closest_encloser, '.')));
+  
+  if (!closest_encloser || !next_closest)
+    return 0;
+  
+  /* Look for NSEC3 that proves the non-existence of the next-closest encloser */
+  if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
+    return 0;
+
+  if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
+    return 0;
+  
+  /* Finally, check that there's no seat of wildcard synthesis */
+  if (!wildname)
+    {
+      if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
+	return 0;
+      
+      wildcard--;
+      *wildcard = '*';
+      
+      if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
+	return 0;
+      
+      if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
+	return 0;
+    }
+  
+  return 1;
+}
+
+static int prove_non_existence(struct dns_header *header, size_t plen, char *keyname, char *name, int qtype, int qclass, char *wildname, int *nons)
+{
+  static unsigned char **nsecset = NULL;
+  static int nsecset_sz = 0;
+  
+  int type_found = 0;
+  unsigned char *p = skip_questions(header, plen);
+  int type, class, rdlen, i, nsecs_found;
+  
+  /* Move to NS section */
+  if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
+    return 0;
+  
+  for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
+    {
+      unsigned char *pstart = p;
+      
+      if (!(p = skip_name(p, header, plen, 10)))
+	return 0;
+      
+      GETSHORT(type, p); 
+      GETSHORT(class, p);
+      p += 4; /* TTL */
+      GETSHORT(rdlen, p);
+
+      if (class == qclass && (type == T_NSEC || type == T_NSEC3))
+	{
+	  /* No mixed NSECing 'round here, thankyouverymuch */
+	  if (type_found != 0 && type_found != type)
+	    return 0;
+
+	  type_found = type;
+
+	  if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
+	    return 0; 
+	  
+	  nsecset[nsecs_found++] = pstart;
+	}
+      
+      if (!ADD_RDLEN(header, p, plen, rdlen))
+	return 0;
+    }
+  
+  if (type_found == T_NSEC)
+    return prove_non_existence_nsec(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
+  else if (type_found == T_NSEC3)
+    return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
+  else
+    return 0;
+}
+
+/* Check signing status of name.
+   returns:
+   STAT_SECURE   zone is signed.
+   STAT_INSECURE zone proved unsigned.
+   STAT_NEED_DS  require DS record of name returned in keyname.
+   STAT_NEED_KEY require DNSKEY record of name returned in keyname.
+   name returned unaltered.
+*/
+static int zone_status(char *name, int class, char *keyname, time_t now)
+{
+  int name_start = strlen(name); /* for when TA is root */
+  struct crec *crecp;
+  char *p;
+
+  /* First, work towards the root, looking for a trust anchor.
+     This can either be one configured, or one previously cached.
+     We can assume, if we don't find one first, that there is
+     a trust anchor at the root. */
+  for (p = name; p; p = strchr(p, '.'))
+    {
+      if (*p == '.')
+	p++;
+
+      if (cache_find_by_name(NULL, p, now, F_DS))
+	{
+	  name_start = p - name;
+	  break;
+	}
+    }
+
+  /* Now work away from the trust anchor */
+  while (1)
+    {
+      strcpy(keyname, &name[name_start]);
+      
+      if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS)))
+	return STAT_NEED_DS;
+      
+       /* F_DNSSECOK misused in DS cache records to non-existence of NS record.
+	  F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
+	  but that's because there's no NS record either, ie this isn't the start
+	  of a zone. We only prove that the DNS tree below a node is unsigned when
+	  we prove that we're at a zone cut AND there's no DS record. */
+      if (crecp->flags & F_NEG)
+	{
+	  if (crecp->flags & F_DNSSECOK)
+	    return STAT_INSECURE; /* proved no DS here */
+	}
+      else
+	{
+	  /* If all the DS records have digest and/or sig algos we don't support,
+	     then the zone is insecure. Note that if an algo
+	     appears in the DS, then RRSIGs for that algo MUST
+	     exist for each RRset: 4035 para 2.2  So if we find
+	     a DS here with digest and sig we can do, we're entitled
+	     to assume we can validate the zone and if we can't later,
+	     because an RRSIG is missing we return BOGUS.
+	  */
+	  do 
+	    {
+	      if (crecp->uid == (unsigned int)class &&
+		  hash_find(ds_digest_name(crecp->addr.ds.digest)) &&
+		  verify_func(crecp->addr.ds.algo))
+		break;
+	    }
+	  while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
+
+	  if (!crecp)
+	    return STAT_INSECURE;
+	}
+
+      if (name_start == 0)
+	break;
+
+      for (p = &name[name_start-2]; (*p != '.') && (p != name); p--);
+      
+      if (p != name)
+        p++;
+      
+      name_start = p - name;
+    } 
+
+  return STAT_SECURE;
+}
+       
+/* Validate all the RRsets in the answer and authority sections of the reply (4035:3.2.3) 
+   Return code:
+   STAT_SECURE   if it validates.
+   STAT_INSECURE at least one RRset not validated, because in unsigned zone.
+   STAT_BOGUS    signature is wrong, bad packet, no validation where there should be.
+   STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname, class in *class)
+   STAT_NEED_DS  need DS to complete validation (name is returned in keyname) 
+*/
+int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, 
+			  int *class, int check_unsigned, int *neganswer, int *nons)
+{
+  static unsigned char **targets = NULL;
+  static int target_sz = 0;
+
+  unsigned char *ans_start, *p1, *p2;
+  int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype, targetidx;
+  int i, j, rc;
+
+  if (neganswer)
+    *neganswer = 0;
+  
+  if (RCODE(header) == SERVFAIL || ntohs(header->qdcount) != 1)
+    return STAT_BOGUS;
+  
+  if (RCODE(header) != NXDOMAIN && RCODE(header) != NOERROR)
+    return STAT_INSECURE;
+
+  p1 = (unsigned char *)(header+1);
+  
+   /* Find all the targets we're looking for answers to.
+     The zeroth array element is for the query, subsequent ones
+     for CNAME targets, unless the query is for a CNAME. */
+
+  if (!expand_workspace(&targets, &target_sz, 0))
+    return STAT_BOGUS;
+  
+  targets[0] = p1;
+  targetidx = 1;
+   
+  if (!extract_name(header, plen, &p1, name, 1, 4))
+    return STAT_BOGUS;
+  
+  GETSHORT(qtype, p1);
+  GETSHORT(qclass, p1);
+  ans_start = p1;
+ 
+  /* Can't validate an RRSIG query */
+  if (qtype == T_RRSIG)
+    return STAT_INSECURE;
+  
+  if (qtype != T_CNAME)
+    for (j = ntohs(header->ancount); j != 0; j--) 
+      {
+	if (!(p1 = skip_name(p1, header, plen, 10)))
+	  return STAT_BOGUS; /* bad packet */
+	
+	GETSHORT(type2, p1); 
+	p1 += 6; /* class, TTL */
+	GETSHORT(rdlen2, p1);  
+	
+	if (type2 == T_CNAME)
+	  {
+	    if (!expand_workspace(&targets, &target_sz, targetidx))
+	      return STAT_BOGUS;
+	    
+	    targets[targetidx++] = p1; /* pointer to target name */
+	  }
+	
+	if (!ADD_RDLEN(header, p1, plen, rdlen2))
+	  return STAT_BOGUS;
+      }
+  
+  for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
+    {
+      if (!extract_name(header, plen, &p1, name, 1, 10))
+	return STAT_BOGUS; /* bad packet */
+      
+      GETSHORT(type1, p1);
+      GETSHORT(class1, p1);
+      p1 += 4; /* TTL */
+      GETSHORT(rdlen1, p1);
+      
+      /* Don't try and validate RRSIGs! */
+      if (type1 != T_RRSIG)
+	{
+	  /* Check if we've done this RRset already */
+	  for (p2 = ans_start, j = 0; j < i; j++)
+	    {
+	      if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
+		return STAT_BOGUS; /* bad packet */
+	      
+	      GETSHORT(type2, p2);
+	      GETSHORT(class2, p2);
+	      p2 += 4; /* TTL */
+	      GETSHORT(rdlen2, p2);
+	      
+	      if (type2 == type1 && class2 == class1 && rc == 1)
+		break; /* Done it before: name, type, class all match. */
+	      
+	      if (!ADD_RDLEN(header, p2, plen, rdlen2))
+		return STAT_BOGUS;
+	    }
+	  
+	  /* Not done, validate now */
+	  if (j == i)
+	    {
+	      int sigcnt, rrcnt;
+	      char *wildname;
+	      
+	      if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
+		return STAT_BOGUS;
+
+	      /* No signatures for RRset. We can be configured to assume this is OK and return a INSECURE result. */
+	      if (sigcnt == 0)
+		{
+		  if (check_unsigned)
+		    {
+		      rc = zone_status(name, class1, keyname, now);
+		      if (rc == STAT_SECURE)
+			rc = STAT_BOGUS;
+		       if (class)
+			 *class = class1; /* Class for NEED_DS or NEED_KEY */
+		    }
+		  else 
+		    rc = STAT_INSECURE; 
+		  
+		  return rc;
+		}
+	      
+	      /* explore_rrset() gives us key name from sigs in keyname.
+		 Can't overwrite name here. */
+	      strcpy(daemon->workspacename, keyname);
+	      rc = zone_status(daemon->workspacename, class1, keyname, now);
+
+	      if (rc != STAT_SECURE)
+		{
+		  /* Zone is insecure, don't need to validate RRset */
+		  if (class)
+		    *class = class1; /* Class for NEED_DS or NEED_KEY */
+		  return rc;
+		} 
+	      
+	      rc = validate_rrset(now, header, plen, class1, type1, sigcnt, rrcnt, name, keyname, &wildname, NULL, 0, 0, 0);
+	      
+	      if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
+		{
+		  if (class)
+		    *class = class1; /* Class for DS or DNSKEY */
+		  return rc;
+		} 
+	      else 
+		{
+		  /* rc is now STAT_SECURE or STAT_SECURE_WILDCARD */
+		 
+		  /* Note if we've validated either the answer to the question
+		     or the target of a CNAME. Any not noted will need NSEC or
+		     to be in unsigned space. */
+
+		  for (j = 0; j <targetidx; j++)
+		    if ((p2 = targets[j]))
+		      {
+			if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
+			  return STAT_BOGUS; /* bad packet */
+			
+			if (class1 == qclass && rc == 1 && (type1 == T_CNAME || type1 == qtype || qtype == T_ANY ))
+			  targets[j] = NULL;
+		      }
+			    
+		   /* An attacker replay a wildcard answer with a different
+		      answer and overlay a genuine RR. To prove this
+		      hasn't happened, the answer must prove that
+		      the genuine record doesn't exist. Check that here. 
+		      Note that we may not yet have validated the NSEC/NSEC3 RRsets. 
+		      That's not a problem since if the RRsets later fail
+		      we'll return BOGUS then. */
+		  if (rc == STAT_SECURE_WILDCARD && !prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL))
+		    return STAT_BOGUS;
+		}
+	    }
+	}
+
+      if (!ADD_RDLEN(header, p1, plen, rdlen1))
+	return STAT_BOGUS;
+    }
+
+  /* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */
+  for (j = 0; j <targetidx; j++)
+    if ((p2 = targets[j]))
+      {
+	if (neganswer)
+	  *neganswer = 1;
+
+	if (!extract_name(header, plen, &p2, name, 1, 10))
+	  return STAT_BOGUS; /* bad packet */
+	    
+	/* NXDOMAIN or NODATA reply, unanswered question is (name, qclass, qtype) */
+
+	/* For anything other than a DS record, this situation is OK if either
+	   the answer is in an unsigned zone, or there's a NSEC records. */
+	if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons))
+	  {
+	    /* Empty DS without NSECS */
+	    if (qtype == T_DS)
+	      return STAT_BOGUS;
+	    
+	    if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
+	      {
+		if (class)
+		  *class = qclass; /* Class for NEED_DS or NEED_KEY */
+		return rc;
+	      } 
+	    
+	    return STAT_BOGUS; /* signed zone, no NSECs */
+	  }
+      }
+  
+  return STAT_SECURE;
+}
+
+
+/* Compute keytag (checksum to quickly index a key). See RFC4034 */
+int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen)
+{
+  if (alg == 1)
+    {
+      /* Algorithm 1 (RSAMD5) has a different (older) keytag calculation algorithm.
+         See RFC4034, Appendix B.1 */
+      return key[keylen-4] * 256 + key[keylen-3];
+    }
+  else
+    {
+      unsigned long ac = flags + 0x300 + alg;
+      int i;
+
+      for (i = 0; i < keylen; ++i)
+        ac += (i & 1) ? key[i] : key[i] << 8;
+
+      ac += (ac >> 16) & 0xffff;
+      return ac & 0xffff;
+    }
+}
+
+size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class, 
+			     int type, union mysockaddr *addr, int edns_pktsz)
+{
+  unsigned char *p;
+  char *types = querystr("dnssec-query", type);
+  size_t ret;
+
+  if (addr->sa.sa_family == AF_INET) 
+    log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, name, (struct all_addr *)&addr->in.sin_addr, types);
+#ifdef HAVE_IPV6
+  else
+    log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, name, (struct all_addr *)&addr->in6.sin6_addr, types);
+#endif
+  
+  header->qdcount = htons(1);
+  header->ancount = htons(0);
+  header->nscount = htons(0);
+  header->arcount = htons(0);
+
+  header->hb3 = HB3_RD; 
+  SET_OPCODE(header, QUERY);
+  /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
+     this allows it to select auth servers when one is returning bad data. */
+  header->hb4 = option_bool(OPT_DNSSEC_DEBUG) ? HB4_CD : 0;
+
+  /* ID filled in later */
+
+  p = (unsigned char *)(header+1);
+	
+  p = do_rfc1035_name(p, name, NULL);
+  *p++ = 0;
+  PUTSHORT(type, p);
+  PUTSHORT(class, p);
+
+  ret = add_do_bit(header, p - (unsigned char *)header, end);
+
+  if (find_pseudoheader(header, ret, NULL, &p, NULL, NULL))
+    PUTSHORT(edns_pktsz, p);
+
+  return ret;
+}
+
+unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
+{
+  int q;
+  unsigned int len;
+  unsigned char *p = (unsigned char *)(header+1);
+  const struct nettle_hash *hash;
+  void *ctx;
+  unsigned char *digest;
+  
+  if (!(hash = hash_find("sha1")) || !hash_init(hash, &ctx, &digest))
+    return NULL;
+  
+  for (q = ntohs(header->qdcount); q != 0; q--) 
+    {
+      if (!extract_name(header, plen, &p, name, 1, 4))
+	break; /* bad packet */
+      
+      len = to_wire(name);
+      hash->update(ctx, len, (unsigned char *)name);
+      /* CRC the class and type as well */
+      hash->update(ctx, 4, p);
+
+      p += 4;
+      if (!CHECK_LEN(header, p, plen, 0))
+	break; /* bad packet */
+    }
+  
+  hash->digest(ctx, hash->digest_size, digest);
+  return digest;
+}
+
+#endif /* HAVE_DNSSEC */
diff --git a/src/domain.c b/src/domain.c
new file mode 100644
index 0000000..f347613
--- /dev/null
+++ b/src/domain.c
@@ -0,0 +1,246 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+
+static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c);
+#ifdef HAVE_IPV6
+static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c);
+#endif
+
+
+int is_name_synthetic(int flags, char *name, struct all_addr *addr)
+{
+  char *p;
+  struct cond_domain *c = NULL;
+  int prot = AF_INET;
+
+#ifdef HAVE_IPV6
+  if (flags & F_IPV6)
+    prot = AF_INET6;
+#endif
+
+  for (c = daemon->synth_domains; c; c = c->next)
+    {
+      int found = 0;
+      char *tail, *pref;
+      
+      for (tail = name, pref = c->prefix; *tail != 0 && pref && *pref != 0; tail++, pref++)
+	{
+	  unsigned int c1 = (unsigned char) *pref;
+	  unsigned int c2 = (unsigned char) *tail;
+	  
+	  if (c1 >= 'A' && c1 <= 'Z')
+	    c1 += 'a' - 'A';
+	  if (c2 >= 'A' && c2 <= 'Z')
+	    c2 += 'a' - 'A';
+	  
+	  if (c1 != c2)
+	    break;
+	}
+      
+      if (pref && *pref != 0)
+	continue; /* prefix match fail */
+      
+      /* NB, must not alter name if we return zero */
+      for (p = tail; *p; p++)
+	{
+	  char c = *p;
+	  
+	  if ((c >='0' && c <= '9') || c == '-')
+	    continue;
+	  
+#ifdef HAVE_IPV6
+	  if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f'))) 
+	    continue;
+#endif
+	  
+	  break;
+	}
+      
+      if (*p != '.')
+	continue;
+      
+      *p = 0;	
+      
+ #ifdef HAVE_IPV6
+      if (prot == AF_INET6 && strstr(tail, "--ffff-") == tail)
+	{
+	  /* special hack for v4-mapped. */
+	  memcpy(tail, "::ffff:", 7);
+	  for (p = tail + 7; *p; p++)
+	    if (*p == '-')
+	      *p = '.';
+	}
+      else
+#endif
+	{
+	  /* swap . or : for - */
+	  for (p = tail; *p; p++)
+	    if (*p == '-')
+	      {
+		if (prot == AF_INET)
+		  *p = '.';
+#ifdef HAVE_IPV6
+		else
+		  *p = ':';
+#endif
+	      }
+	}
+
+      if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr))
+	{
+	  if (prot == AF_INET)
+	    {
+	      if (!c->is6 &&
+		  ntohl(addr->addr.addr4.s_addr) >= ntohl(c->start.s_addr) &&
+		  ntohl(addr->addr.addr4.s_addr) <= ntohl(c->end.s_addr))
+		found = 1;
+	    }
+#ifdef HAVE_IPV6
+	  else
+	    {
+	      u64 addrpart = addr6part(&addr->addr.addr6);
+	      
+	      if (c->is6 &&
+		  is_same_net6(&addr->addr.addr6, &c->start6, 64) &&
+		  addrpart >= addr6part(&c->start6) &&
+		  addrpart <= addr6part(&c->end6))
+		found = 1;
+	    }
+#endif
+	}
+      
+      /* restore name */
+      for (p = tail; *p; p++)
+	if (*p == '.' || *p == ':')
+	  *p = '-';
+      
+      *p = '.';
+
+      if (found)
+	return 1;
+    }
+  
+  return 0;
+}
+
+
+int is_rev_synth(int flag, struct all_addr *addr, char *name)
+{
+   struct cond_domain *c;
+
+   if (flag & F_IPV4 && (c = search_domain(addr->addr.addr4, daemon->synth_domains))) 
+     {
+       char *p;
+       
+       *name = 0;
+       if (c->prefix)
+	 strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
+       
+       inet_ntop(AF_INET, &addr->addr.addr4, name + strlen(name), ADDRSTRLEN);
+       for (p = name; *p; p++)
+	 if (*p == '.')
+	   *p = '-';
+
+       strncat(name, ".", MAXDNAME);
+       strncat(name, c->domain, MAXDNAME);
+
+       return 1;
+     }
+
+#ifdef HAVE_IPV6
+   if (flag & F_IPV6 && (c = search_domain6(&addr->addr.addr6, daemon->synth_domains))) 
+     {
+       char *p;
+       
+       *name = 0;
+       if (c->prefix)
+	 strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
+       
+       inet_ntop(AF_INET6, &addr->addr.addr6, name + strlen(name), ADDRSTRLEN);
+
+       /* IPv6 presentation address can start with ":", but valid domain names
+	  cannot start with "-" so prepend a zero in that case. */
+       if (!c->prefix && *name == ':')
+	 {
+	   *name = '0';
+	   inet_ntop(AF_INET6, &addr->addr.addr6, name+1, ADDRSTRLEN);
+	 }
+
+       /* V4-mapped have periods.... */
+       for (p = name; *p; p++)
+	 if (*p == ':' || *p == '.')
+	   *p = '-';
+
+       strncat(name, ".", MAXDNAME);
+       strncat(name, c->domain, MAXDNAME);
+       
+       return 1;
+     }
+#endif
+   
+   return 0;
+}
+
+
+static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c)
+{
+  for (; c; c = c->next)
+    if (!c->is6 &&
+	ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
+        ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
+      return c;
+
+  return NULL;
+}
+
+char *get_domain(struct in_addr addr)
+{
+  struct cond_domain *c;
+
+  if ((c = search_domain(addr, daemon->cond_domain)))
+    return c->domain;
+
+  return daemon->domain_suffix;
+} 
+
+#ifdef HAVE_IPV6
+static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c)
+{
+  u64 addrpart = addr6part(addr);
+  
+  for (; c; c = c->next)
+    if (c->is6 &&
+	is_same_net6(addr, &c->start6, 64) &&
+	addrpart >= addr6part(&c->start6) &&
+        addrpart <= addr6part(&c->end6))
+      return c;
+  
+  return NULL;
+}
+
+char *get_domain6(struct in6_addr *addr)
+{
+  struct cond_domain *c;
+
+  if (addr && (c = search_domain6(addr, daemon->cond_domain)))
+    return c->domain;
+
+  return daemon->domain_suffix;
+} 
+#endif
diff --git a/src/edns0.c b/src/edns0.c
new file mode 100644
index 0000000..7ed5a47
--- /dev/null
+++ b/src/edns0.c
@@ -0,0 +1,449 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t  *len, unsigned char **p, int *is_sign, int *is_last)
+{
+  /* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it. 
+     also return length of pseudoheader in *len and pointer to the UDP size in *p
+     Finally, check to see if a packet is signed. If it is we cannot change a single bit before
+     forwarding. We look for TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
+  
+  int i, arcount = ntohs(header->arcount);
+  unsigned char *ansp = (unsigned char *)(header+1);
+  unsigned short rdlen, type, class;
+  unsigned char *ret = NULL;
+
+  if (is_sign)
+    {
+      *is_sign = 0;
+
+      if (OPCODE(header) == QUERY)
+	{
+	  for (i = ntohs(header->qdcount); i != 0; i--)
+	    {
+	      if (!(ansp = skip_name(ansp, header, plen, 4)))
+		return NULL;
+	      
+	      GETSHORT(type, ansp); 
+	      GETSHORT(class, ansp);
+	      
+	      if (class == C_IN && type == T_TKEY)
+		*is_sign = 1;
+	    }
+	}
+    }
+  else
+    {
+      if (!(ansp = skip_questions(header, plen)))
+	return NULL;
+    }
+    
+  if (arcount == 0)
+    return NULL;
+  
+  if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
+    return NULL; 
+  
+  for (i = 0; i < arcount; i++)
+    {
+      unsigned char *save, *start = ansp;
+      if (!(ansp = skip_name(ansp, header, plen, 10)))
+	return NULL; 
+
+      GETSHORT(type, ansp);
+      save = ansp;
+      GETSHORT(class, ansp);
+      ansp += 4; /* TTL */
+      GETSHORT(rdlen, ansp);
+      if (!ADD_RDLEN(header, ansp, plen, rdlen))
+	return NULL;
+      if (type == T_OPT)
+	{
+	  if (len)
+	    *len = ansp - start;
+
+	  if (p)
+	    *p = save;
+	  
+	  if (is_last)
+	    *is_last = (i == arcount-1);
+
+	  ret = start;
+	}
+      else if (is_sign && 
+	       i == arcount - 1 && 
+	       class == C_ANY && 
+	       type == T_TSIG)
+	*is_sign = 1;
+    }
+  
+  return ret;
+}
+ 
+
+/* replace == 2 ->delete existing option only. */
+size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
+			unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do, int replace)
+{ 
+  unsigned char *lenp, *datap, *p, *udp_len, *buff = NULL;
+  int rdlen = 0, is_sign, is_last;
+  unsigned short flags = set_do ? 0x8000 : 0, rcode = 0;
+
+  p = find_pseudoheader(header, plen, NULL, &udp_len, &is_sign, &is_last);
+  
+  if (is_sign)
+    return plen;
+
+  if (p)
+    {
+      /* Existing header */
+      int i;
+      unsigned short code, len;
+
+      p = udp_len;
+      GETSHORT(udp_sz, p);
+      GETSHORT(rcode, p);
+      GETSHORT(flags, p);
+
+      if (set_do)
+	{
+	  p -= 2;
+	  flags |= 0x8000;
+	  PUTSHORT(flags, p);
+	}
+
+      lenp = p;
+      GETSHORT(rdlen, p);
+      if (!CHECK_LEN(header, p, plen, rdlen))
+	return plen; /* bad packet */
+      datap = p;
+
+       /* no option to add */
+      if (optno == 0)
+	return plen;
+      	  
+      /* check if option already there */
+      for (i = 0; i + 4 < rdlen;)
+	{
+	  GETSHORT(code, p);
+	  GETSHORT(len, p);
+	  
+	  /* malformed option, delete the whole OPT RR and start again. */
+	  if (i + 4 + len > rdlen)
+	    {
+	      rdlen = 0;
+	      is_last = 0;
+	      break;
+	    }
+	  
+	  if (code == optno)
+	    {
+	      if (replace == 0)
+		return plen;
+
+	      /* delete option if we're to replace it. */
+	      p -= 4;
+	      rdlen -= len + 4;
+	      memmove(p, p+len+4, rdlen - i);
+	      PUTSHORT(rdlen, lenp);
+	      lenp -= 2;
+	    }
+	  else
+	    {
+	      p += len;
+	      i += len + 4;
+	    }
+	}
+
+      /* If we're going to extend the RR, it has to be the last RR in the packet */
+      if (!is_last)
+	{
+	  /* First, take a copy of the options. */
+	  if (rdlen != 0 && (buff = whine_malloc(rdlen)))
+	    memcpy(buff, datap, rdlen);	      
+	  
+	  /* now, delete OPT RR */
+	  plen = rrfilter(header, plen, 0);
+	  
+	  /* Now, force addition of a new one */
+	  p = NULL;	  
+	}
+    }
+  
+  if (!p)
+    {
+      /* We are (re)adding the pseudoheader */
+      if (!(p = skip_questions(header, plen)) ||
+	  !(p = skip_section(p, 
+			     ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount), 
+			     header, plen)))
+      {
+	free(buff);
+	return plen;
+      }
+      if (p + 11 > limit)
+      {
+        free(buff);
+        return plen; /* Too big */
+      }
+      *p++ = 0; /* empty name */
+      PUTSHORT(T_OPT, p);
+      PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
+      PUTSHORT(rcode, p);    /* extended RCODE and version */
+      PUTSHORT(flags, p); /* DO flag */
+      lenp = p;
+      PUTSHORT(rdlen, p);    /* RDLEN */
+      datap = p;
+      /* Copy back any options */
+      if (buff)
+	{
+          if (p + rdlen > limit)
+          {
+            free(buff);
+            return plen; /* Too big */
+          }
+	  memcpy(p, buff, rdlen);
+	  free(buff);
+	  p += rdlen;
+	}
+      
+      /* Only bump arcount if RR is going to fit */ 
+      if (((ssize_t)optlen) <= (limit - (p + 4)))
+	header->arcount = htons(ntohs(header->arcount) + 1);
+    }
+  
+  if (((ssize_t)optlen) > (limit - (p + 4)))
+    return plen; /* Too big */
+  
+  /* Add new option */
+  if (optno != 0 && replace != 2)
+    {
+      if (p + 4 > limit)
+       return plen; /* Too big */
+      PUTSHORT(optno, p);
+      PUTSHORT(optlen, p);
+      if (p + optlen > limit)
+       return plen; /* Too big */
+      memcpy(p, opt, optlen);
+      p += optlen;  
+      PUTSHORT(p - datap, lenp);
+    }
+  return p - (unsigned char *)header;
+}
+
+size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit)
+{
+  return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1, 0);
+}
+
+static unsigned char char64(unsigned char c)
+{
+  return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[c & 0x3f];
+}
+
+static void encoder(unsigned char *in, char *out)
+{
+  out[0] = char64(in[0]>>2);
+  out[1] = char64((in[0]<<4) | (in[1]>>4));
+  out[2] = char64((in[1]<<2) | (in[2]>>6));
+  out[3] = char64(in[2]);
+}
+
+static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
+{
+  int maclen, replace = 2; /* can't get mac address, just delete any incoming. */
+  unsigned char mac[DHCP_CHADDR_MAX];
+  char encode[18]; /* handle 6 byte MACs */
+
+  if ((maclen = find_mac(l3, mac, 1, now)) == 6)
+    {
+      replace = 1;
+
+      if (option_bool(OPT_MAC_HEX))
+	print_mac(encode, mac, maclen);
+      else
+	{
+	  encoder(mac, encode);
+	  encoder(mac+3, encode+4);
+	  encode[8] = 0;
+	}
+    }
+
+  return add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, strlen(encode), 0, replace); 
+}
+
+
+static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
+{
+  int maclen;
+  unsigned char mac[DHCP_CHADDR_MAX];
+
+  if ((maclen = find_mac(l3, mac, 1, now)) != 0)
+    plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0); 
+    
+  return plen; 
+}
+
+struct subnet_opt {
+  u16 family;
+  u8 source_netmask, scope_netmask;
+#ifdef HAVE_IPV6 
+  u8 addr[IN6ADDRSZ];
+#else
+  u8 addr[INADDRSZ];
+#endif
+};
+
+static void *get_addrp(union mysockaddr *addr, const short family) 
+{
+#ifdef HAVE_IPV6
+  if (family == AF_INET6)
+    return &addr->in6.sin6_addr;
+#endif
+
+  return &addr->in.sin_addr;
+}
+
+static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
+{
+  /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
+  
+  int len;
+  void *addrp = NULL;
+  int sa_family = source->sa.sa_family;
+
+  opt->source_netmask = 0;
+  opt->scope_netmask = 0;
+
+#ifdef HAVE_IPV6
+  if (source->sa.sa_family == AF_INET6 && daemon->add_subnet6)
+    {
+      opt->source_netmask = daemon->add_subnet6->mask;
+      if (daemon->add_subnet6->addr_used) 
+	{
+	  sa_family = daemon->add_subnet6->addr.sa.sa_family;
+	  addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
+	} 
+      else 
+	addrp = &source->in6.sin6_addr;
+    }
+#endif
+
+  if (source->sa.sa_family == AF_INET && daemon->add_subnet4)
+    {
+      opt->source_netmask = daemon->add_subnet4->mask;
+      if (daemon->add_subnet4->addr_used)
+	{
+	  sa_family = daemon->add_subnet4->addr.sa.sa_family;
+	  addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
+	} 
+	else 
+	  addrp = &source->in.sin_addr;
+    }
+  
+#ifdef HAVE_IPV6
+  opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
+#else
+  opt->family = htons(1);
+#endif
+  
+  len = 0;
+  
+  if (addrp && opt->source_netmask != 0)
+    {
+      len = ((opt->source_netmask - 1) >> 3) + 1;
+      memcpy(opt->addr, addrp, len);
+      if (opt->source_netmask & 7)
+	opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
+    }
+  
+  return len + 4;
+}
+ 
+static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source)
+{
+  /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
+  
+  int len;
+  struct subnet_opt opt;
+  
+  len = calc_subnet_opt(&opt, source);
+  return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, 0);
+}
+
+int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
+{
+  /* Section 9.2, Check that subnet option in reply matches. */
+  
+  int len, calc_len;
+  struct subnet_opt opt;
+  unsigned char *p;
+  int code, i, rdlen;
+  
+   calc_len = calc_subnet_opt(&opt, peer);
+   
+   if (!(p = skip_name(pseudoheader, header, plen, 10)))
+     return 1;
+   
+   p += 8; /* skip UDP length and RCODE */
+   
+   GETSHORT(rdlen, p);
+   if (!CHECK_LEN(header, p, plen, rdlen))
+     return 1; /* bad packet */
+   
+   /* check if option there */
+   for (i = 0; i + 4 < rdlen; i += len + 4)
+     {
+       GETSHORT(code, p);
+       GETSHORT(len, p);
+       if (code == EDNS0_OPTION_CLIENT_SUBNET)
+	 {
+	   /* make sure this doesn't mismatch. */
+	   opt.scope_netmask = p[3];
+	   if (len != calc_len || memcmp(p, &opt, len) != 0)
+	     return 0;
+	 }
+       p += len;
+     }
+   
+   return 1;
+}
+
+size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit, 
+			union mysockaddr *source, time_t now, int *check_subnet)    
+{
+  *check_subnet = 0;
+
+  if (option_bool(OPT_ADD_MAC))
+    plen  = add_mac(header, plen, limit, source, now);
+  
+  if (option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX))
+    plen = add_dns_client(header, plen, limit, source, now);
+
+  if (daemon->dns_client_id)
+    plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID, 
+			    (unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1);
+  
+  if (option_bool(OPT_CLIENT_SUBNET))
+    {
+      plen = add_source_addr(header, plen, limit, source); 
+      *check_subnet = 1;
+    }
+	  
+  return plen;
+}
diff --git a/src/forward.c b/src/forward.c
new file mode 100755
index 0000000..942b02d
--- /dev/null
+++ b/src/forward.c
@@ -0,0 +1,2259 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+static struct frec *lookup_frec(unsigned short id, void *hash);
+static struct frec *lookup_frec_by_sender(unsigned short id,
+					  union mysockaddr *addr,
+					  void *hash);
+static unsigned short get_id(void);
+static void free_frec(struct frec *f);
+
+/* Send a UDP packet with its source address set as "source" 
+   unless nowild is true, when we just send it with the kernel default */
+int send_from(int fd, int nowild, char *packet, size_t len, 
+	      union mysockaddr *to, struct all_addr *source,
+	      unsigned int iface)
+{
+  struct msghdr msg;
+  struct iovec iov[1]; 
+  union {
+    struct cmsghdr align; /* this ensures alignment */
+#if defined(HAVE_LINUX_NETWORK)
+    char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
+#elif defined(IP_SENDSRCADDR)
+    char control[CMSG_SPACE(sizeof(struct in_addr))];
+#endif
+#ifdef HAVE_IPV6
+    char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+#endif
+  } control_u;
+  
+  iov[0].iov_base = packet;
+  iov[0].iov_len = len;
+
+  msg.msg_control = NULL;
+  msg.msg_controllen = 0;
+  msg.msg_flags = 0;
+  msg.msg_name = to;
+  msg.msg_namelen = sa_len(to);
+  msg.msg_iov = iov;
+  msg.msg_iovlen = 1;
+  
+  if (!nowild)
+    {
+      struct cmsghdr *cmptr;
+      msg.msg_control = &control_u;
+      msg.msg_controllen = sizeof(control_u);
+      cmptr = CMSG_FIRSTHDR(&msg);
+
+      if (to->sa.sa_family == AF_INET)
+	{
+#if defined(HAVE_LINUX_NETWORK)
+	  struct in_pktinfo p;
+	  p.ipi_ifindex = 0;
+	  p.ipi_spec_dst = source->addr.addr4;
+	  memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
+	  msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+	  cmptr->cmsg_level = IPPROTO_IP;
+	  cmptr->cmsg_type = IP_PKTINFO;
+#elif defined(IP_SENDSRCADDR)
+	  memcpy(CMSG_DATA(cmptr), &(source->addr.addr4), sizeof(source->addr.addr4));
+	  msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
+	  cmptr->cmsg_level = IPPROTO_IP;
+	  cmptr->cmsg_type = IP_SENDSRCADDR;
+#endif
+	}
+      else
+#ifdef HAVE_IPV6
+	{
+	  struct in6_pktinfo p;
+	  p.ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
+	  p.ipi6_addr = source->addr.addr6;
+	  memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
+	  msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+	  cmptr->cmsg_type = daemon->v6pktinfo;
+	  cmptr->cmsg_level = IPPROTO_IPV6;
+	}
+#else
+      (void)iface; /* eliminate warning */
+#endif
+    }
+  
+  while (retry_send(sendmsg(fd, &msg, 0)));
+
+  /* If interface is still in DAD, EINVAL results - ignore that. */
+  if (errno != 0 && errno != EINVAL)
+    {
+      my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno));
+      return 0;
+    }
+  
+  return 1;
+}
+          
+static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigned int qtype,
+				   char *qdomain, int *type, char **domain, int *norebind)
+			      
+{
+  /* If the query ends in the domain in one of our servers, set
+     domain to point to that name. We find the largest match to allow both
+     domain.org and sub.domain.org to exist. */
+  
+  unsigned int namelen = strlen(qdomain);
+  unsigned int matchlen = 0;
+  struct server *serv;
+  unsigned int flags = 0;
+  
+  for (serv = daemon->servers; serv; serv=serv->next)
+    if (qtype == F_DNSSECOK && !(serv->flags & SERV_DO_DNSSEC))
+      continue;
+    /* domain matches take priority over NODOTS matches */
+    else if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
+      {
+	unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6; 
+	*type = SERV_FOR_NODOTS;
+	if (serv->flags & SERV_NO_ADDR)
+	  flags = F_NXDOMAIN;
+	else if (serv->flags & SERV_LITERAL_ADDRESS) 
+	  { 
+	    if (sflag & qtype)
+	      {
+		flags = sflag;
+		if (serv->addr.sa.sa_family == AF_INET) 
+		  *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
+#ifdef HAVE_IPV6
+		else
+		  *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
+#endif 
+	      }
+	    else if (!flags || (flags & F_NXDOMAIN))
+	      flags = F_NOERR;
+	  } 
+      }
+    else if (serv->flags & SERV_HAS_DOMAIN)
+      {
+	unsigned int domainlen = strlen(serv->domain);
+	char *matchstart = qdomain + namelen - domainlen;
+	if (namelen >= domainlen &&
+	    hostname_isequal(matchstart, serv->domain) &&
+	    (domainlen == 0 || namelen == domainlen || *(matchstart-1) == '.' ))
+	  {
+	    if ((serv->flags & SERV_NO_REBIND) && norebind)	
+	      *norebind = 1;
+	    else
+	      {
+		unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
+		/* implement priority rules for --address and --server for same domain.
+		   --address wins if the address is for the correct AF
+		   --server wins otherwise. */
+		if (domainlen != 0 && domainlen == matchlen)
+		  {
+		    if ((serv->flags & SERV_LITERAL_ADDRESS))
+		      {
+			if (!(sflag & qtype) && flags == 0)
+			  continue;
+		      }
+		    else
+		      {
+			if (flags & (F_IPV4 | F_IPV6))
+			  continue;
+		      }
+		  }
+		
+		if (domainlen >= matchlen)
+		  {
+		    *type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_DO_DNSSEC);
+		    *domain = serv->domain;
+		    matchlen = domainlen;
+		    if (serv->flags & SERV_NO_ADDR)
+		      flags = F_NXDOMAIN;
+		    else if (serv->flags & SERV_LITERAL_ADDRESS)
+		      {
+			if (sflag & qtype)
+			  {
+			    flags = sflag;
+			    if (serv->addr.sa.sa_family == AF_INET) 
+			      *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
+#ifdef HAVE_IPV6
+			    else
+			      *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
+#endif
+			  }
+			else if (!flags || (flags & F_NXDOMAIN))
+			  flags = F_NOERR;
+		      }
+		    else
+		      flags = 0;
+		  } 
+	      }
+	  }
+      }
+  
+  if (flags == 0 && !(qtype & (F_QUERY | F_DNSSECOK)) && 
+      option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
+    /* don't forward A or AAAA queries for simple names, except the empty name */
+    flags = F_NOERR;
+  
+  if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
+    flags = F_NOERR;
+
+  if (flags)
+    {
+      int logflags = 0;
+      
+      if (flags == F_NXDOMAIN || flags == F_NOERR)
+	logflags = F_NEG | qtype;
+  
+      log_query(logflags | flags | F_CONFIG | F_FORWARD, qdomain, *addrpp, NULL);
+    }
+  else if ((*type) & SERV_USE_RESOLV)
+    {
+      *type = 0; /* use normal servers for this domain */
+      *domain = NULL;
+    }
+  return  flags;
+}
+
+static int forward_query(int udpfd, union mysockaddr *udpaddr,
+			 struct all_addr *dst_addr, unsigned int dst_iface,
+			 struct dns_header *header, size_t plen, time_t now, 
+			 struct frec *forward, int ad_reqd, int do_bit)
+{
+  char *domain = NULL;
+  int type = SERV_DO_DNSSEC, norebind = 0;
+  struct all_addr *addrp = NULL;
+  unsigned int flags = 0;
+  struct server *start = NULL;
+#ifdef HAVE_DNSSEC
+  void *hash = hash_questions(header, plen, daemon->namebuff);
+  int do_dnssec = 0;
+#else
+  unsigned int crc = questions_crc(header, plen, daemon->namebuff);
+  void *hash = &crc;
+#endif
+ unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
+
+ (void)do_bit;
+
+  /* may be no servers available. */
+  if (forward || (hash && (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash))))
+    {
+      /* If we didn't get an answer advertising a maximal packet in EDNS,
+	 fall back to 1280, which should work everywhere on IPv6.
+	 If that generates an answer, it will become the new default
+	 for this server */
+      forward->flags |= FREC_TEST_PKTSZ;
+      
+#ifdef HAVE_DNSSEC
+      /* If we've already got an answer to this query, but we're awaiting keys for validation,
+	 there's no point retrying the query, retry the key query instead...... */
+      if (forward->blocking_query)
+	{
+	  int fd, is_sign;
+	  unsigned char *pheader;
+	  
+	  forward->flags &= ~FREC_TEST_PKTSZ;
+	  
+	  while (forward->blocking_query)
+	    forward = forward->blocking_query;
+	   
+	  forward->flags |= FREC_TEST_PKTSZ;
+	  
+	  blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
+	  plen = forward->stash_len;
+	  
+	  if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
+	    PUTSHORT(SAFE_PKTSZ, pheader);
+
+	  if (forward->sentto->addr.sa.sa_family == AF_INET) 
+	    log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
+#ifdef HAVE_IPV6
+	  else
+	    log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (struct all_addr *)&forward->sentto->addr.in6.sin6_addr, "dnssec");
+#endif
+  
+	  if (forward->sentto->sfd)
+	    fd = forward->sentto->sfd->fd;
+	  else
+	    {
+#ifdef HAVE_IPV6
+	      if (forward->sentto->addr.sa.sa_family == AF_INET6)
+		fd = forward->rfd6->fd;
+	      else
+#endif
+		fd = forward->rfd4->fd;
+	    }
+	  
+	  while (retry_send( sendto(fd, (char *)header, plen, 0,
+				    &forward->sentto->addr.sa,
+				    sa_len(&forward->sentto->addr))));
+	  
+	  return 1;
+	}
+#endif
+
+      /* retry on existing query, send to all available servers  */
+      domain = forward->sentto->domain;
+      forward->sentto->failed_queries++;
+      if (!option_bool(OPT_ORDER))
+	{
+	  forward->forwardall = 1;
+	  daemon->last_server = NULL;
+	}
+      type = forward->sentto->flags & SERV_TYPE;
+#ifdef HAVE_DNSSEC
+      do_dnssec = forward->sentto->flags & SERV_DO_DNSSEC;
+#endif
+
+      if (!(start = forward->sentto->next))
+	start = daemon->servers; /* at end of list, recycle */
+      header->id = htons(forward->new_id);
+    }
+  else 
+    {
+      if (gotname)
+	flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
+      
+#ifdef HAVE_DNSSEC
+      do_dnssec = type & SERV_DO_DNSSEC;
+#endif
+      type &= ~SERV_DO_DNSSEC;      
+
+      if (daemon->servers && !flags)
+	forward = get_new_frec(now, NULL, 0);
+      /* table full - flags == 0, return REFUSED */
+      
+      if (forward)
+	{
+	  forward->source = *udpaddr;
+	  forward->dest = *dst_addr;
+	  forward->iface = dst_iface;
+	  forward->orig_id = ntohs(header->id);
+	  forward->new_id = get_id();
+	  forward->fd = udpfd;
+	  memcpy(forward->hash, hash, HASH_SIZE);
+	  forward->forwardall = 0;
+	  forward->flags = 0;
+	  if (norebind)
+	    forward->flags |= FREC_NOREBIND;
+	  if (header->hb4 & HB4_CD)
+	    forward->flags |= FREC_CHECKING_DISABLED;
+	  if (ad_reqd)
+	    forward->flags |= FREC_AD_QUESTION;
+#ifdef HAVE_DNSSEC
+	  forward->work_counter = DNSSEC_WORK;
+	  if (do_bit)
+	    forward->flags |= FREC_DO_QUESTION;
+#endif
+	  
+	  header->id = htons(forward->new_id);
+	  
+	  /* In strict_order mode, always try servers in the order 
+	     specified in resolv.conf, if a domain is given 
+	     always try all the available servers,
+	     otherwise, use the one last known to work. */
+	  
+	  if (type == 0)
+	    {
+	      if (option_bool(OPT_ORDER))
+		start = daemon->servers;
+	      else if (!(start = daemon->last_server) ||
+		       daemon->forwardcount++ > FORWARD_TEST ||
+		       difftime(now, daemon->forwardtime) > FORWARD_TIME)
+		{
+		  start = daemon->servers;
+		  forward->forwardall = 1;
+		  daemon->forwardcount = 0;
+		  daemon->forwardtime = now;
+		}
+	    }
+	  else
+	    {
+	      start = daemon->servers;
+	      if (!option_bool(OPT_ORDER))
+		forward->forwardall = 1;
+	    }
+	}
+    }
+
+  /* check for send errors here (no route to host) 
+     if we fail to send to all nameservers, send back an error
+     packet straight away (helps modem users when offline)  */
+  
+  if (!flags && forward)
+    {
+      struct server *firstsentto = start;
+      int subnet, forwarded = 0;
+      size_t edns0_len;
+
+      /* If a query is retried, use the log_id for the retry when logging the answer. */
+      forward->log_id = daemon->log_id;
+      
+      edns0_len  = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->source, now, &subnet);
+      
+      if (edns0_len != plen)
+	{
+	  plen = edns0_len;
+	  forward->flags |= FREC_ADDED_PHEADER;
+	  
+	  if (subnet)
+	    forward->flags |= FREC_HAS_SUBNET;
+	}
+      
+#ifdef HAVE_DNSSEC
+      if (option_bool(OPT_DNSSEC_VALID) && do_dnssec)
+	{
+	  size_t new = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
+	 
+	  if (new != plen)
+	    forward->flags |= FREC_ADDED_PHEADER;
+
+	  plen = new;
+	      
+	  /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
+	     this allows it to select auth servers when one is returning bad data. */
+	  if (option_bool(OPT_DNSSEC_DEBUG))
+	    header->hb4 |= HB4_CD;
+
+	}
+#endif
+
+      /* If we're sending an EDNS0 with any options, we can't recreate the query from a reply. */
+      if (find_pseudoheader(header, plen, &edns0_len, NULL, NULL, NULL) && edns0_len > 11)
+	forward->flags |= FREC_HAS_EXTRADATA;
+      
+      while (1)
+	{ 
+	  /* only send to servers dealing with our domain.
+	     domain may be NULL, in which case server->domain 
+	     must be NULL also. */
+	  
+	  if (type == (start->flags & SERV_TYPE) &&
+	      (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
+	      !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
+	    {
+	      int fd;
+
+	      /* find server socket to use, may need to get random one. */
+	      if (start->sfd)
+		fd = start->sfd->fd;
+	      else 
+		{
+#ifdef HAVE_IPV6
+		  if (start->addr.sa.sa_family == AF_INET6)
+		    {
+		      if (!forward->rfd6 &&
+			  !(forward->rfd6 = allocate_rfd(AF_INET6)))
+			break;
+		      daemon->rfd_save = forward->rfd6;
+		      fd = forward->rfd6->fd;
+		    }
+		  else
+#endif
+		    {
+		      if (!forward->rfd4 &&
+			  !(forward->rfd4 = allocate_rfd(AF_INET)))
+			break;
+		      daemon->rfd_save = forward->rfd4;
+		      fd = forward->rfd4->fd;
+		    }
+
+#ifdef HAVE_CONNTRACK
+		  /* Copy connection mark of incoming query to outgoing connection. */
+		  if (option_bool(OPT_CONNTRACK))
+		    {
+		      unsigned int mark;
+		      if (get_incoming_mark(&forward->source, &forward->dest, 0, &mark))
+			setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
+		    }
+#endif
+		}
+	      
+#ifdef HAVE_DNSSEC
+	      if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER))
+		{
+		  /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP
+		     packet size to 512. But that won't provide space for the RRSIGS in many cases.
+		     The RRSIGS will be stripped out before the answer goes back, so the packet should
+		     shrink again. So, if we added a do-bit, bump the udp packet size to the value
+		     known to be OK for this server. We check returned size after stripping and set
+		     the truncated bit if it's still too big. */		  
+		  unsigned char *pheader;
+		  int is_sign;
+		  if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
+		    PUTSHORT(start->edns_pktsz, pheader);
+		}
+#endif
+
+	      if (retry_send(sendto(fd, (char *)header, plen, 0,
+				    &start->addr.sa,
+				    sa_len(&start->addr))))
+		continue;
+	    
+	      if (errno == 0)
+		{
+		  /* Keep info in case we want to re-send this packet */
+		  daemon->srv_save = start;
+		  daemon->packet_len = plen;
+		  
+		  if (!gotname)
+		    strcpy(daemon->namebuff, "query");
+		  if (start->addr.sa.sa_family == AF_INET)
+		    log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff, 
+			      (struct all_addr *)&start->addr.in.sin_addr, NULL); 
+#ifdef HAVE_IPV6
+		  else
+		    log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff, 
+			      (struct all_addr *)&start->addr.in6.sin6_addr, NULL);
+#endif 
+		  start->queries++;
+		  forwarded = 1;
+		  forward->sentto = start;
+		  if (!forward->forwardall) 
+		    break;
+		  forward->forwardall++;
+		}
+	    } 
+	  
+	  if (!(start = start->next))
+ 	    start = daemon->servers;
+	  
+	  if (start == firstsentto)
+	    break;
+	}
+      
+      if (forwarded)
+	return 1;
+      
+      /* could not send on, prepare to return */ 
+      header->id = htons(forward->orig_id);
+      free_frec(forward); /* cancel */
+    }	  
+  
+  /* could not send on, return empty answer or address if known for whole domain */
+  if (udpfd != -1)
+    {
+      plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
+      send_from(udpfd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), (char *)header, plen, udpaddr, dst_addr, dst_iface);
+    }
+
+  return 0;
+}
+
+static size_t process_reply(struct dns_header *header, time_t now, struct server *server, size_t n, int check_rebind, 
+			    int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader, 
+			    int check_subnet, union mysockaddr *query_source)
+{
+  unsigned char *pheader, *sizep;
+  char **sets = 0;
+  int munged = 0, is_sign;
+  size_t plen; 
+
+  (void)ad_reqd;
+  (void)do_bit;
+  (void)bogusanswer;
+
+#ifdef HAVE_IPSET
+  if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
+    {
+      /* Similar algorithm to search_servers. */
+      struct ipsets *ipset_pos;
+      unsigned int namelen = strlen(daemon->namebuff);
+      unsigned int matchlen = 0;
+      for (ipset_pos = daemon->ipsets; ipset_pos; ipset_pos = ipset_pos->next) 
+	{
+	  unsigned int domainlen = strlen(ipset_pos->domain);
+	  char *matchstart = daemon->namebuff + namelen - domainlen;
+	  if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
+	      (domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
+	      domainlen >= matchlen) 
+	    {
+	      matchlen = domainlen;
+	      sets = ipset_pos->sets;
+	    }
+	}
+    }
+#endif
+  
+  if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
+    {
+      if (check_subnet && !check_source(header, plen, pheader, query_source))
+	{
+	  my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
+	  return 0;
+	}
+      
+      if (!is_sign)
+	{
+	  if (added_pheader)
+	    {
+	      /* client didn't send EDNS0, we added one, strip it off before returning answer. */
+	      n = rrfilter(header, n, 0);
+	      pheader = NULL;
+	    }
+	  else
+	    {
+	      unsigned short udpsz;
+
+	      /* If upstream is advertising a larger UDP packet size
+		 than we allow, trim it so that we don't get overlarge
+		 requests for the client. We can't do this for signed packets. */
+	      GETSHORT(udpsz, sizep);
+	      if (udpsz > daemon->edns_pktsz)
+		{
+		  sizep -= 2;
+		  PUTSHORT(daemon->edns_pktsz, sizep);
+		}
+
+#ifdef HAVE_DNSSEC
+	      /* If the client didn't set the do bit, but we did, reset it. */
+	      if (option_bool(OPT_DNSSEC_VALID) && !do_bit)
+		{
+		  unsigned short flags;
+		  sizep += 2; /* skip RCODE */
+		  GETSHORT(flags, sizep);
+		  flags &= ~0x8000;
+		  sizep -= 2;
+		  PUTSHORT(flags, sizep);
+		}
+#endif
+	    }
+	}
+    }
+  
+  /* RFC 4035 sect 4.6 para 3 */
+  if (!is_sign && !option_bool(OPT_DNSSEC_PROXY))
+     header->hb4 &= ~HB4_AD;
+  
+  if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN))
+    return resize_packet(header, n, pheader, plen);
+  
+  /* Complain loudly if the upstream server is non-recursive. */
+  if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR &&
+      server && !(server->flags & SERV_WARNED_RECURSIVE))
+    {
+      prettyprint_addr(&server->addr, daemon->namebuff);
+      my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
+      if (!option_bool(OPT_LOG))
+	server->flags |= SERV_WARNED_RECURSIVE;
+    }  
+
+  if (daemon->bogus_addr && RCODE(header) != NXDOMAIN &&
+      check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
+    {
+      munged = 1;
+      SET_RCODE(header, NXDOMAIN);
+      header->hb3 &= ~HB3_AA;
+      cache_secure = 0;
+    }
+  else 
+    {
+      int doctored = 0;
+      
+      if (RCODE(header) == NXDOMAIN && 
+	  extract_request(header, n, daemon->namebuff, NULL) &&
+	  check_for_local_domain(daemon->namebuff, now))
+	{
+	  /* if we forwarded a query for a locally known name (because it was for 
+	     an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
+	     since we know that the domain exists, even if upstream doesn't */
+	  munged = 1;
+	  header->hb3 |= HB3_AA;
+	  SET_RCODE(header, NOERROR);
+	  cache_secure = 0;
+	}
+      
+      if (extract_addresses(header, n, daemon->namebuff, now, sets, is_sign, check_rebind, no_cache, cache_secure, &doctored))
+	{
+	  my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
+	  munged = 1;
+	  cache_secure = 0;
+	}
+
+      if (doctored)
+	cache_secure = 0;
+    }
+  
+#ifdef HAVE_DNSSEC
+  if (bogusanswer && !(header->hb4 & HB4_CD) && !option_bool(OPT_DNSSEC_DEBUG))
+    {
+      /* Bogus reply, turn into SERVFAIL */
+      SET_RCODE(header, SERVFAIL);
+      munged = 1;
+    }
+
+  if (option_bool(OPT_DNSSEC_VALID))
+    {
+      header->hb4 &= ~HB4_AD;
+      
+      if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
+	header->hb4 |= HB4_AD;
+      
+      /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
+      if (!do_bit)
+	n = rrfilter(header, n, 1);
+    }
+#endif
+
+  /* do this after extract_addresses. Ensure NODATA reply and remove
+     nameserver info. */
+  
+  if (munged)
+    {
+      header->ancount = htons(0);
+      header->nscount = htons(0);
+      header->arcount = htons(0);
+      header->hb3 &= ~HB3_TC;
+    }
+  
+  /* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
+     sections of the packet. Find the new length here and put back pseudoheader
+     if it was removed. */
+  return resize_packet(header, n, pheader, plen);
+}
+
+/* sets new last_server */
+void reply_query(int fd, int family, time_t now)
+{
+  /* packet from peer server, extract data for cache, and send to
+     original requester */
+  struct dns_header *header;
+  union mysockaddr serveraddr;
+  struct frec *forward;
+  socklen_t addrlen = sizeof(serveraddr);
+  ssize_t n = recvfrom(fd, daemon->packet, daemon->packet_buff_sz, 0, &serveraddr.sa, &addrlen);
+  size_t nn;
+  struct server *server;
+  void *hash;
+#ifndef HAVE_DNSSEC
+  unsigned int crc;
+#endif
+
+  /* packet buffer overwritten */
+  daemon->srv_save = NULL;
+  
+  /* Determine the address of the server replying  so that we can mark that as good */
+  serveraddr.sa.sa_family = family;
+#ifdef HAVE_IPV6
+  if (serveraddr.sa.sa_family == AF_INET6)
+    serveraddr.in6.sin6_flowinfo = 0;
+#endif
+  
+  header = (struct dns_header *)daemon->packet;
+  
+  if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR))
+    return;
+  
+  /* spoof check: answer must come from known server, */
+  for (server = daemon->servers; server; server = server->next)
+    if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
+	sockaddr_isequal(&server->addr, &serveraddr))
+      break;
+  
+  if (!server)
+    return;
+  
+#ifdef HAVE_DNSSEC
+  hash = hash_questions(header, n, daemon->namebuff);
+#else
+  hash = &crc;
+  crc = questions_crc(header, n, daemon->namebuff);
+#endif
+  
+  if (!(forward = lookup_frec(ntohs(header->id), hash)))
+    return;
+  
+  /* log_query gets called indirectly all over the place, so 
+     pass these in global variables - sorry. */
+  daemon->log_display_id = forward->log_id;
+  daemon->log_source_addr = &forward->source;
+  
+  if (daemon->ignore_addr && RCODE(header) == NOERROR &&
+      check_for_ignored_address(header, n, daemon->ignore_addr))
+    return;
+
+  /* Note: if we send extra options in the EDNS0 header, we can't recreate
+     the query from the reply. */
+  if (RCODE(header) == REFUSED &&
+      forward->forwardall == 0 &&
+      !(forward->flags & FREC_HAS_EXTRADATA))
+    /* for broken servers, attempt to send to another one. */
+    {
+      unsigned char *pheader;
+      size_t plen;
+      int is_sign;
+      
+      /* recreate query from reply */
+      pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL);
+      if (!is_sign)
+	{
+	  header->ancount = htons(0);
+	  header->nscount = htons(0);
+	  header->arcount = htons(0);
+	  if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
+	    {
+	      header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
+	      header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
+	      if (forward->flags & FREC_CHECKING_DISABLED)
+		header->hb4 |= HB4_CD;
+	      if (forward->flags & FREC_AD_QUESTION)
+		header->hb4 |= HB4_AD;
+	      if (forward->flags & FREC_DO_QUESTION)
+		add_do_bit(header, nn,  (unsigned char *)pheader + plen);
+	      forward_query(-1, NULL, NULL, 0, header, nn, now, forward, forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION);
+	      return;
+	    }
+	}
+    }   
+   
+  server = forward->sentto;
+  if ((forward->sentto->flags & SERV_TYPE) == 0)
+    {
+      if (RCODE(header) == REFUSED)
+	server = NULL;
+      else
+	{
+	  struct server *last_server;
+	  
+	  /* find good server by address if possible, otherwise assume the last one we sent to */ 
+	  for (last_server = daemon->servers; last_server; last_server = last_server->next)
+	    if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
+		sockaddr_isequal(&last_server->addr, &serveraddr))
+	      {
+		server = last_server;
+		break;
+	      }
+	} 
+      if (!option_bool(OPT_ALL_SERVERS))
+	daemon->last_server = server;
+    }
+ 
+  /* We tried resending to this server with a smaller maximum size and got an answer.
+     Make that permanent. To avoid reduxing the packet size for an single dropped packet,
+     only do this when we get a truncated answer, or one larger than the safe size. */
+  if (server && (forward->flags & FREC_TEST_PKTSZ) && 
+      ((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ))
+    server->edns_pktsz = SAFE_PKTSZ;
+  
+  /* If the answer is an error, keep the forward record in place in case
+     we get a good reply from another server. Kill it when we've
+     had replies from all to avoid filling the forwarding table when
+     everything is broken */
+  if (forward->forwardall == 0 || --forward->forwardall == 1 ||
+      (RCODE(header) != REFUSED && RCODE(header) != SERVFAIL))
+    {
+      int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
+
+      if (option_bool(OPT_NO_REBIND))
+	check_rebind = !(forward->flags & FREC_NOREBIND);
+      
+      /*   Don't cache replies where DNSSEC validation was turned off, either
+	   the upstream server told us so, or the original query specified it.  */
+      if ((header->hb4 & HB4_CD) || (forward->flags & FREC_CHECKING_DISABLED))
+	no_cache_dnssec = 1;
+      
+#ifdef HAVE_DNSSEC
+      if (server && (server->flags & SERV_DO_DNSSEC) && 
+	  option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
+	{
+	  int status = 0;
+
+	  /* We've had a reply already, which we're validating. Ignore this duplicate */
+	  if (forward->blocking_query)
+	    return;
+	  
+	   /* Truncated answer can't be validated.
+	      If this is an answer to a DNSSEC-generated query, we still
+	      need to get the client to retry over TCP, so return
+	      an answer with the TC bit set, even if the actual answer fits.
+	   */
+	  if (header->hb3 & HB3_TC)
+	    status = STAT_TRUNCATED;
+	  
+	  while (1)
+	    {
+	      /* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
+		 would invite infinite loops, since the answers to DNSKEY and DS queries
+		 will not be cached, so they'll be repeated. */
+	      if (status != STAT_BOGUS && status != STAT_TRUNCATED && status != STAT_ABANDONED)
+		{
+		  if (forward->flags & FREC_DNSKEY_QUERY)
+		    status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
+		  else if (forward->flags & FREC_DS_QUERY)
+		    status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
+		  else
+		    status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class, 
+						   option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags & SERV_DO_DNSSEC), NULL, NULL);
+		}
+	      
+	      /* Can't validate, as we're missing key data. Put this
+		 answer aside, whilst we get that. */     
+	      if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
+		{
+		  struct frec *new, *orig;
+		  
+		  /* Free any saved query */
+		  if (forward->stash)
+		    blockdata_free(forward->stash);
+		  
+		  /* Now save reply pending receipt of key data */
+		  if (!(forward->stash = blockdata_alloc((char *)header, n)))
+		    return;
+		  forward->stash_len = n;
+		  
+		  /* Find the original query that started it all.... */
+		  for (orig = forward; orig->dependent; orig = orig->dependent);
+		  
+		  if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, 1)))
+		    status = STAT_ABANDONED;
+		  else
+		    {
+		      int fd, type = SERV_DO_DNSSEC;
+		      struct frec *next = new->next;
+		      char *domain;
+		      
+		      *new = *forward; /* copy everything, then overwrite */
+		      new->next = next;
+		      new->blocking_query = NULL;
+
+		      /* Find server to forward to. This will normally be the 
+			 same as for the original query, but may be another if
+			 servers for domains are involved. */		      
+		      if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL) == 0)
+			{
+			  struct server *start = server, *new_server = NULL;
+			  
+			  while (1)
+			    {
+			      if (type == (start->flags & (SERV_TYPE | SERV_DO_DNSSEC)) &&
+				  (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
+				  !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
+				{
+				  new_server = start;
+				  if (server == start)
+				    {
+				      new_server = NULL;
+				      break;
+				    }
+				}
+			      
+			      if (!(start = start->next))
+				start = daemon->servers;
+			      if (start == server)
+				break;
+			    }
+			  
+			  if (new_server)
+			    server = new_server;
+			}
+		      
+		      new->sentto = server;
+		      new->rfd4 = NULL;
+#ifdef HAVE_IPV6
+		      new->rfd6 = NULL;
+#endif
+		      new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY);
+		      
+		      new->dependent = forward; /* to find query awaiting new one. */
+		      forward->blocking_query = new; /* for garbage cleaning */
+		      /* validate routines leave name of required record in daemon->keyname */
+		      if (status == STAT_NEED_KEY)
+			{
+			  new->flags |= FREC_DNSKEY_QUERY; 
+			  nn = dnssec_generate_query(header, ((unsigned char *) header) + server->edns_pktsz,
+						     daemon->keyname, forward->class, T_DNSKEY, &server->addr, server->edns_pktsz);
+			}
+		      else 
+			{
+			  new->flags |= FREC_DS_QUERY;
+			  nn = dnssec_generate_query(header,((unsigned char *) header) + server->edns_pktsz,
+						     daemon->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz);
+			}
+		      if ((hash = hash_questions(header, nn, daemon->namebuff)))
+			memcpy(new->hash, hash, HASH_SIZE);
+		      new->new_id = get_id();
+		      header->id = htons(new->new_id);
+		      /* Save query for retransmission */
+		      new->stash = blockdata_alloc((char *)header, nn);
+		      new->stash_len = nn;
+		      
+		      /* Don't resend this. */
+		      daemon->srv_save = NULL;
+		      
+		      if (server->sfd)
+			fd = server->sfd->fd;
+		      else
+			{
+			  fd = -1;
+#ifdef HAVE_IPV6
+			  if (server->addr.sa.sa_family == AF_INET6)
+			    {
+			      if (new->rfd6 || (new->rfd6 = allocate_rfd(AF_INET6)))
+				fd = new->rfd6->fd;
+			    }
+			  else
+#endif
+			    {
+			      if (new->rfd4 || (new->rfd4 = allocate_rfd(AF_INET)))
+				fd = new->rfd4->fd;
+			    }
+			}
+		      
+		      if (fd != -1)
+			{
+#ifdef HAVE_CONNTRACK
+			  /* Copy connection mark of incoming query to outgoing connection. */
+			  if (option_bool(OPT_CONNTRACK))
+			    {
+			      unsigned int mark;
+			      if (get_incoming_mark(&orig->source, &orig->dest, 0, &mark))
+				setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
+			    }
+#endif
+			  while (retry_send(sendto(fd, (char *)header, nn, 0, 
+						   &server->addr.sa, 
+						   sa_len(&server->addr)))); 
+			  server->queries++;
+			}
+		    }		  
+		  return;
+		}
+	  
+	      /* Validated original answer, all done. */
+	      if (!forward->dependent)
+		break;
+	      
+	      /* validated subsidiary query, (and cached result)
+		 pop that and return to the previous query we were working on. */
+	      struct frec *prev = forward->dependent;
+	      free_frec(forward);
+	      forward = prev;
+	      forward->blocking_query = NULL; /* already gone */
+	      blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
+	      n = forward->stash_len;
+	    }
+	
+	  
+	  no_cache_dnssec = 0;
+	  
+	  if (status == STAT_TRUNCATED)
+	    header->hb3 |= HB3_TC;
+	  else
+	    {
+	      char *result, *domain = "result";
+	      
+	      if (status == STAT_ABANDONED)
+		{
+		  result = "ABANDONED";
+		  status = STAT_BOGUS;
+		}
+	      else
+		result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
+	      
+	      if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
+		domain = daemon->namebuff;
+	      
+	      log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
+	    }
+	  
+	  if (status == STAT_SECURE)
+	    cache_secure = 1;
+	  else if (status == STAT_BOGUS)
+	    {
+	      no_cache_dnssec = 1;
+	      bogusanswer = 1;
+	    }
+	}
+#endif     
+      
+      /* restore CD bit to the value in the query */
+      if (forward->flags & FREC_CHECKING_DISABLED)
+	header->hb4 |= HB4_CD;
+      else
+	header->hb4 &= ~HB4_CD;
+      
+      if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer, 
+			      forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION, 
+			      forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->source)))
+	{
+	  header->id = htons(forward->orig_id);
+	  header->hb4 |= HB4_RA; /* recursion if available */
+#ifdef HAVE_DNSSEC
+	  /* We added an EDNSO header for the purpose of getting DNSSEC RRs, and set the value of the UDP payload size
+	     greater than the no-EDNS0-implied 512 to have if space for the RRSIGS. If, having stripped them and the EDNS0
+             header, the answer is still bigger than 512, truncate it and mark it so. The client then retries with TCP. */
+	  if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER) && (nn > PACKETSZ))
+	    {
+	      header->ancount = htons(0);
+	      header->nscount = htons(0);
+	      header->arcount = htons(0);
+	      header->hb3 |= HB3_TC;
+	      nn = resize_packet(header, nn, NULL, 0);
+	    }
+#endif
+	  send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn, 
+		    &forward->source, &forward->dest, forward->iface);
+	}
+      free_frec(forward); /* cancel */
+    }
+}
+
+
+void receive_query(struct listener *listen, time_t now)
+{
+  struct dns_header *header = (struct dns_header *)daemon->packet;
+  union mysockaddr source_addr;
+  unsigned char *pheader;
+  unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */
+  struct all_addr dst_addr;
+  struct in_addr netmask, dst_addr_4;
+  size_t m;
+  ssize_t n;
+  int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
+#ifdef HAVE_AUTH
+  int local_auth = 0;
+#endif
+  struct iovec iov[1];
+  struct msghdr msg;
+  struct cmsghdr *cmptr;
+  union {
+    struct cmsghdr align; /* this ensures alignment */
+#ifdef HAVE_IPV6
+    char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+#endif
+#if defined(HAVE_LINUX_NETWORK)
+    char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
+#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
+    char control[CMSG_SPACE(sizeof(struct in_addr)) +
+		 CMSG_SPACE(sizeof(unsigned int))];
+#elif defined(IP_RECVDSTADDR)
+    char control[CMSG_SPACE(sizeof(struct in_addr)) +
+		 CMSG_SPACE(sizeof(struct sockaddr_dl))];
+#endif
+  } control_u;
+#ifdef HAVE_IPV6
+   /* Can always get recvd interface for IPv6 */
+  int check_dst = !option_bool(OPT_NOWILD) || listen->family == AF_INET6;
+#else
+  int check_dst = !option_bool(OPT_NOWILD);
+#endif
+
+  /* packet buffer overwritten */
+  daemon->srv_save = NULL;
+  
+  dst_addr_4.s_addr = dst_addr.addr.addr4.s_addr = 0;
+  netmask.s_addr = 0;
+  
+  if (option_bool(OPT_NOWILD) && listen->iface)
+    {
+      auth_dns = listen->iface->dns_auth;
+     
+      if (listen->family == AF_INET)
+	{
+	  dst_addr_4 = dst_addr.addr.addr4 = listen->iface->addr.in.sin_addr;
+	  netmask = listen->iface->netmask;
+	}
+    }
+  
+  iov[0].iov_base = daemon->packet;
+  iov[0].iov_len = daemon->edns_pktsz;
+    
+  msg.msg_control = control_u.control;
+  msg.msg_controllen = sizeof(control_u);
+  msg.msg_flags = 0;
+  msg.msg_name = &source_addr;
+  msg.msg_namelen = sizeof(source_addr);
+  msg.msg_iov = iov;
+  msg.msg_iovlen = 1;
+  
+  if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
+    return;
+  
+  if (n < (int)sizeof(struct dns_header) || 
+      (msg.msg_flags & MSG_TRUNC) ||
+      (header->hb3 & HB3_QR))
+    return;
+
+  /* Clear buffer beyond request to avoid risk of
+     information disclosure. */
+  memset(daemon->packet + n, 0, daemon->edns_pktsz - n);
+  
+  source_addr.sa.sa_family = listen->family;
+  
+  if (listen->family == AF_INET)
+    {
+       /* Source-port == 0 is an error, we can't send back to that. 
+	  http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */
+      if (source_addr.in.sin_port == 0)
+	return;
+    }
+#ifdef HAVE_IPV6
+  else
+    {
+      /* Source-port == 0 is an error, we can't send back to that. */
+      if (source_addr.in6.sin6_port == 0)
+	return;
+      source_addr.in6.sin6_flowinfo = 0;
+    }
+#endif
+  
+  /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
+  if (option_bool(OPT_LOCAL_SERVICE))
+    {
+      struct addrlist *addr;
+#ifdef HAVE_IPV6
+      if (listen->family == AF_INET6) 
+	{
+	  for (addr = daemon->interface_addrs; addr; addr = addr->next)
+	    if ((addr->flags & ADDRLIST_IPV6) &&
+		is_same_net6(&addr->addr.addr.addr6, &source_addr.in6.sin6_addr, addr->prefixlen))
+	      break;
+	}
+      else
+#endif
+	{
+	  struct in_addr netmask;
+	  for (addr = daemon->interface_addrs; addr; addr = addr->next)
+	    {
+	      netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
+	      if (!(addr->flags & ADDRLIST_IPV6) &&
+		  is_same_net(addr->addr.addr.addr4, source_addr.in.sin_addr, netmask))
+		break;
+	    }
+	}
+      if (!addr)
+	{
+	  static int warned = 0;
+	  if (!warned)
+	    {
+	      my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
+	      warned = 1;
+	    }
+	  return;
+	}
+    }
+		
+  if (check_dst)
+    {
+      struct ifreq ifr;
+
+      if (msg.msg_controllen < sizeof(struct cmsghdr))
+	return;
+
+#if defined(HAVE_LINUX_NETWORK)
+      if (listen->family == AF_INET)
+	for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
+	  if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
+	    {
+	      union {
+		unsigned char *c;
+		struct in_pktinfo *p;
+	      } p;
+	      p.c = CMSG_DATA(cmptr);
+	      dst_addr_4 = dst_addr.addr.addr4 = p.p->ipi_spec_dst;
+	      if_index = p.p->ipi_ifindex;
+	    }
+#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
+      if (listen->family == AF_INET)
+	{
+	  for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
+	    {
+	      union {
+		unsigned char *c;
+		unsigned int *i;
+		struct in_addr *a;
+#ifndef HAVE_SOLARIS_NETWORK
+		struct sockaddr_dl *s;
+#endif
+	      } p;
+	       p.c = CMSG_DATA(cmptr);
+	       if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
+		 dst_addr_4 = dst_addr.addr.addr4 = *(p.a);
+	       else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
+#ifdef HAVE_SOLARIS_NETWORK
+		 if_index = *(p.i);
+#else
+  	         if_index = p.s->sdl_index;
+#endif
+	    }
+	}
+#endif
+      
+#ifdef HAVE_IPV6
+      if (listen->family == AF_INET6)
+	{
+	  for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
+	    if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
+	      {
+		union {
+		  unsigned char *c;
+		  struct in6_pktinfo *p;
+		} p;
+		p.c = CMSG_DATA(cmptr);
+		  
+		dst_addr.addr.addr6 = p.p->ipi6_addr;
+		if_index = p.p->ipi6_ifindex;
+	      }
+	}
+#endif
+      
+      /* enforce available interface configuration */
+      
+      if (!indextoname(listen->fd, if_index, ifr.ifr_name))
+	return;
+      
+      if (!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns))
+	{
+	   if (!option_bool(OPT_CLEVERBIND))
+	     enumerate_interfaces(0); 
+	   if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name) &&
+	       !label_exception(if_index, listen->family, &dst_addr))
+	     return;
+	}
+
+      if (listen->family == AF_INET && option_bool(OPT_LOCALISE))
+	{
+	  struct irec *iface;
+	  
+	  /* get the netmask of the interface which has the address we were sent to.
+	     This is no necessarily the interface we arrived on. */
+	  
+	  for (iface = daemon->interfaces; iface; iface = iface->next)
+	    if (iface->addr.sa.sa_family == AF_INET &&
+		iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
+	      break;
+	  
+	  /* interface may be new */
+	  if (!iface && !option_bool(OPT_CLEVERBIND))
+	    enumerate_interfaces(0); 
+	  
+	  for (iface = daemon->interfaces; iface; iface = iface->next)
+	    if (iface->addr.sa.sa_family == AF_INET &&
+		iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
+	      break;
+	  
+	  /* If we failed, abandon localisation */
+	  if (iface)
+	    netmask = iface->netmask;
+	  else
+	    dst_addr_4.s_addr = 0;
+	}
+    }
+   
+  /* log_query gets called indirectly all over the place, so 
+     pass these in global variables - sorry. */
+  daemon->log_display_id = ++daemon->log_id;
+  daemon->log_source_addr = &source_addr;
+  
+  if (extract_request(header, (size_t)n, daemon->namebuff, &type))
+    {
+#ifdef HAVE_AUTH
+      struct auth_zone *zone;
+#endif
+      char *types = querystr(auth_dns ? "auth" : "query", type);
+      
+      if (listen->family == AF_INET) 
+	log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff, 
+		  (struct all_addr *)&source_addr.in.sin_addr, types);
+#ifdef HAVE_IPV6
+      else
+	log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff, 
+		  (struct all_addr *)&source_addr.in6.sin6_addr, types);
+#endif
+
+#ifdef HAVE_AUTH
+      /* find queries for zones we're authoritative for, and answer them directly */
+      if (!auth_dns && !option_bool(OPT_LOCALISE))
+	for (zone = daemon->auth_zones; zone; zone = zone->next)
+	  if (in_zone(zone, daemon->namebuff, NULL))
+	    {
+	      auth_dns = 1;
+	      local_auth = 1;
+	      break;
+	    }
+#endif
+      
+#ifdef HAVE_LOOP
+      /* Check for forwarding loop */
+      if (detect_loop(daemon->namebuff, type))
+	return;
+#endif
+    }
+  
+  if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL, NULL))
+    { 
+      unsigned short flags;
+      
+      have_pseudoheader = 1;
+      GETSHORT(udp_size, pheader);
+      pheader += 2; /* ext_rcode */
+      GETSHORT(flags, pheader);
+      
+      if (flags & 0x8000)
+	do_bit = 1;/* do bit */ 
+	
+      /* If the client provides an EDNS0 UDP size, use that to limit our reply.
+	 (bounded by the maximum configured). If no EDNS0, then it
+	 defaults to 512 */
+      if (udp_size > daemon->edns_pktsz)
+	udp_size = daemon->edns_pktsz;
+      else if (udp_size < PACKETSZ)
+	udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
+    }
+
+#ifdef HAVE_AUTH
+  if (auth_dns)
+    {
+      m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr, 
+		      local_auth, do_bit, have_pseudoheader);
+      if (m >= 1)
+	{
+	  send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
+		    (char *)header, m, &source_addr, &dst_addr, if_index);
+	  daemon->auth_answer++;
+	}
+    }
+  else
+#endif
+    {
+      int ad_reqd = do_bit;
+       /* RFC 6840 5.7 */
+      if (header->hb4 & HB4_AD)
+	ad_reqd = 1;
+
+      m = answer_request(header, ((char *) header) + udp_size, (size_t)n, 
+			 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
+      
+      if (m >= 1)
+	{
+	  send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
+		    (char *)header, m, &source_addr, &dst_addr, if_index);
+	  daemon->local_answer++;
+	}
+      else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
+			     header, (size_t)n, now, NULL, ad_reqd, do_bit))
+	daemon->queries_forwarded++;
+      else
+	daemon->local_answer++;
+    }
+}
+
+#ifdef HAVE_DNSSEC
+/* Recurse up the key hierarchy */
+static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n, 
+			   int class, char *name, char *keyname, struct server *server, 
+			   int have_mark, unsigned int mark, int *keycount)
+{
+  int new_status;
+  unsigned char *packet = NULL;
+  unsigned char *payload = NULL;
+  struct dns_header *new_header = NULL;
+  u16 *length = NULL;
+ 
+  while (1)
+    {
+      int type = SERV_DO_DNSSEC;
+      char *domain;
+      size_t m; 
+      unsigned char c1, c2;
+      struct server *firstsendto = NULL;
+      
+      /* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
+      if (--(*keycount) == 0)
+	new_status = STAT_ABANDONED;
+      else if (status == STAT_NEED_KEY)
+	new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
+      else if (status == STAT_NEED_DS)
+	new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
+      else 
+	new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
+					   option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags & SERV_DO_DNSSEC), NULL, NULL);
+      
+      if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
+	break;
+
+      /* Can't validate because we need a key/DS whose name now in keyname.
+	 Make query for same, and recurse to validate */
+      if (!packet)
+	{
+	  packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
+	  payload = &packet[2];
+	  new_header = (struct dns_header *)payload;
+	  length = (u16 *)packet;
+	}
+      
+      if (!packet)
+	{
+	  new_status = STAT_ABANDONED;
+	  break;
+	}
+	 
+      m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class, 
+				new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, server->edns_pktsz);
+      
+      *length = htons(m);
+
+      /* Find server to forward to. This will normally be the 
+	 same as for the original query, but may be another if
+	 servers for domains are involved. */		      
+      if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL) != 0)
+	{
+	  new_status = STAT_ABANDONED;
+	  break;
+	}
+	
+      while (1)
+	{
+	  if (!firstsendto)
+	    firstsendto = server;
+	  else
+	    {
+	      if (!(server = server->next))
+		server = daemon->servers;
+	      if (server == firstsendto)
+		{
+		  /* can't find server to accept our query. */
+		  new_status = STAT_ABANDONED;
+		  break;
+		}
+	    }
+	  
+	  if (type != (server->flags & (SERV_TYPE | SERV_DO_DNSSEC)) ||
+	      (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, server->domain)) ||
+	      (server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
+	    continue;
+	    
+	  retry:
+	    /* may need to make new connection. */
+	    if (server->tcpfd == -1)
+	      {
+		if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
+		  continue; /* No good, next server */
+		
+#ifdef HAVE_CONNTRACK
+		/* Copy connection mark of incoming query to outgoing connection. */
+		if (have_mark)
+		  setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
+#endif	
+		
+		if (!local_bind(server->tcpfd,  &server->source_addr, server->interface, 1) ||
+		    connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
+		  {
+		    close(server->tcpfd);
+		    server->tcpfd = -1;
+		    continue; /* No good, next server */
+		  }
+		
+		server->flags &= ~SERV_GOT_TCP;
+	      }
+	  
+	  if (!read_write(server->tcpfd, packet, m + sizeof(u16), 0) ||
+	      !read_write(server->tcpfd, &c1, 1, 1) ||
+	      !read_write(server->tcpfd, &c2, 1, 1) ||
+	      !read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
+	    {
+	      close(server->tcpfd);
+	      server->tcpfd = -1;
+	      /* We get data then EOF, reopen connection to same server,
+		 else try next. This avoids DoS from a server which accepts
+		 connections and then closes them. */
+	      if (server->flags & SERV_GOT_TCP)
+		goto retry;
+	      else
+		continue;
+	    }
+	  
+	  server->flags |= SERV_GOT_TCP;
+	  
+	  m = (c1 << 8) | c2;
+	  new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
+	  break;
+	}
+      
+      if (new_status != STAT_OK)
+	break;
+    }
+    
+  if (packet)
+    free(packet);
+    
+  return new_status;
+}
+#endif
+
+
+/* The daemon forks before calling this: it should deal with one connection,
+   blocking as necessary, and then return. Note, need to be a bit careful
+   about resources for debug mode, when the fork is suppressed: that's
+   done by the caller. */
+unsigned char *tcp_request(int confd, time_t now,
+			   union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
+{
+  size_t size = 0;
+  int norebind = 0;
+#ifdef HAVE_AUTH
+  int local_auth = 0;
+#endif
+  int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
+  int check_subnet, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
+  size_t m;
+  unsigned short qtype;
+  unsigned int gotname;
+  unsigned char c1, c2;
+  /* Max TCP packet + slop + size */
+  unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
+  unsigned char *payload = &packet[2];
+  /* largest field in header is 16-bits, so this is still sufficiently aligned */
+  struct dns_header *header = (struct dns_header *)payload;
+  u16 *length = (u16 *)packet;
+  struct server *last_server;
+  struct in_addr dst_addr_4;
+  union mysockaddr peer_addr;
+  socklen_t peer_len = sizeof(union mysockaddr);
+  int query_count = 0;
+  unsigned char *pheader;
+  unsigned int mark = 0;
+  int have_mark = 0;
+
+  (void)mark;
+  (void)have_mark;
+
+  if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
+    return packet;
+
+#ifdef HAVE_CONNTRACK
+  /* Get connection mark of incoming query to set on outgoing connections. */
+  if (option_bool(OPT_CONNTRACK))
+    {
+      struct all_addr local;
+#ifdef HAVE_IPV6		      
+      if (local_addr->sa.sa_family == AF_INET6)
+	local.addr.addr6 = local_addr->in6.sin6_addr;
+      else
+#endif
+	local.addr.addr4 = local_addr->in.sin_addr;
+      
+      have_mark = get_incoming_mark(&peer_addr, &local, 1, &mark);
+    }
+#endif	
+
+  /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
+  if (option_bool(OPT_LOCAL_SERVICE))
+    {
+      struct addrlist *addr;
+#ifdef HAVE_IPV6
+      if (peer_addr.sa.sa_family == AF_INET6) 
+	{
+	  for (addr = daemon->interface_addrs; addr; addr = addr->next)
+	    if ((addr->flags & ADDRLIST_IPV6) &&
+		is_same_net6(&addr->addr.addr.addr6, &peer_addr.in6.sin6_addr, addr->prefixlen))
+	      break;
+	}
+      else
+#endif
+	{
+	  struct in_addr netmask;
+	  for (addr = daemon->interface_addrs; addr; addr = addr->next)
+	    {
+	      netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
+	      if (!(addr->flags & ADDRLIST_IPV6) && 
+		  is_same_net(addr->addr.addr.addr4, peer_addr.in.sin_addr, netmask))
+		break;
+	    }
+	}
+      if (!addr)
+	{
+	  my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
+	  return packet;
+	}
+    }
+
+  while (1)
+    {
+      if (query_count == TCP_MAX_QUERIES ||
+	  !packet ||
+	  !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
+	  !(size = c1 << 8 | c2) ||
+	  !read_write(confd, payload, size, 1))
+       	return packet; 
+  
+      if (size < (int)sizeof(struct dns_header))
+	continue;
+
+      /* Clear buffer beyond request to avoid risk of
+	 information disclosure. */
+      memset(payload + size, 0, 65536 - size);
+      
+      query_count++;
+
+      /* log_query gets called indirectly all over the place, so 
+	 pass these in global variables - sorry. */
+      daemon->log_display_id = ++daemon->log_id;
+      daemon->log_source_addr = &peer_addr;
+      
+      /* save state of "cd" flag in query */
+      if ((checking_disabled = header->hb4 & HB4_CD))
+	no_cache_dnssec = 1;
+       
+      if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
+	{
+#ifdef HAVE_AUTH
+	  struct auth_zone *zone;
+#endif
+	  char *types = querystr(auth_dns ? "auth" : "query", qtype);
+	  
+	  if (peer_addr.sa.sa_family == AF_INET) 
+	    log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff, 
+		      (struct all_addr *)&peer_addr.in.sin_addr, types);
+#ifdef HAVE_IPV6
+	  else
+	    log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff, 
+		      (struct all_addr *)&peer_addr.in6.sin6_addr, types);
+#endif
+	  
+#ifdef HAVE_AUTH
+	  /* find queries for zones we're authoritative for, and answer them directly */
+	  if (!auth_dns && !option_bool(OPT_LOCALISE))
+	    for (zone = daemon->auth_zones; zone; zone = zone->next)
+	      if (in_zone(zone, daemon->namebuff, NULL))
+		{
+		  auth_dns = 1;
+		  local_auth = 1;
+		  break;
+		}
+#endif
+	}
+      
+      if (local_addr->sa.sa_family == AF_INET)
+	dst_addr_4 = local_addr->in.sin_addr;
+      else
+	dst_addr_4.s_addr = 0;
+      
+      do_bit = 0;
+
+      if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
+	{ 
+	  unsigned short flags;
+	  
+	  have_pseudoheader = 1;
+	  pheader += 4; /* udp_size, ext_rcode */
+	  GETSHORT(flags, pheader);
+      
+	  if (flags & 0x8000)
+	    do_bit = 1; /* do bit */ 
+	}
+
+#ifdef HAVE_AUTH
+      if (auth_dns)
+	m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr, 
+			local_auth, do_bit, have_pseudoheader);
+      else
+#endif
+	{
+	   int ad_reqd = do_bit;
+	   /* RFC 6840 5.7 */
+	   if (header->hb4 & HB4_AD)
+	     ad_reqd = 1;
+	   
+	   /* m > 0 if answered from cache */
+	   m = answer_request(header, ((char *) header) + 65536, (size_t)size, 
+			      dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
+	  
+	  /* Do this by steam now we're not in the select() loop */
+	  check_log_writer(1); 
+	  
+	  if (m == 0)
+	    {
+	      unsigned int flags = 0;
+	      struct all_addr *addrp = NULL;
+	      int type = SERV_DO_DNSSEC;
+	      char *domain = NULL;
+	      size_t new_size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
+
+	      if (size != new_size)
+		{
+		  added_pheader = 1;
+		  size = new_size;
+		}
+	      
+	      if (gotname)
+		flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
+	      
+	      type &= ~SERV_DO_DNSSEC;
+	      
+	      if (type != 0  || option_bool(OPT_ORDER) || !daemon->last_server)
+		last_server = daemon->servers;
+	      else
+		last_server = daemon->last_server;
+	      
+	      if (!flags && last_server)
+		{
+		  struct server *firstsendto = NULL;
+#ifdef HAVE_DNSSEC
+		  unsigned char *newhash, hash[HASH_SIZE];
+		  if ((newhash = hash_questions(header, (unsigned int)size, daemon->namebuff)))
+		    memcpy(hash, newhash, HASH_SIZE);
+		  else
+		    memset(hash, 0, HASH_SIZE);
+#else
+		  unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);
+#endif		  
+		  /* Loop round available servers until we succeed in connecting to one.
+		     Note that this code subtly ensures that consecutive queries on this connection
+		     which can go to the same server, do so. */
+		  while (1) 
+		    {
+		      if (!firstsendto)
+			firstsendto = last_server;
+		      else
+			{
+			  if (!(last_server = last_server->next))
+			    last_server = daemon->servers;
+			  
+			  if (last_server == firstsendto)
+			    break;
+			}
+		      
+		      /* server for wrong domain */
+		      if (type != (last_server->flags & SERV_TYPE) ||
+			  (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)) ||
+			  (last_server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
+			continue;
+
+		    retry:
+		      if (last_server->tcpfd == -1)
+			{
+			  if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
+			    continue;
+			  
+#ifdef HAVE_CONNTRACK
+			  /* Copy connection mark of incoming query to outgoing connection. */
+			  if (have_mark)
+			    setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
+#endif	
+		      
+			  if ((!local_bind(last_server->tcpfd,  &last_server->source_addr, last_server->interface, 1) ||
+			       connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
+			    {
+			      close(last_server->tcpfd);
+			      last_server->tcpfd = -1;
+			      continue;
+			    }
+			  
+			  last_server->flags &= ~SERV_GOT_TCP;
+			}
+		      
+#ifdef HAVE_DNSSEC
+		      if (option_bool(OPT_DNSSEC_VALID) && (last_server->flags & SERV_DO_DNSSEC))
+			{
+			  new_size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
+			  
+			  if (size != new_size)
+			    {
+			      added_pheader = 1;
+			      size = new_size;
+			    }
+			  
+			  /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
+			     this allows it to select auth servers when one is returning bad data. */
+			  if (option_bool(OPT_DNSSEC_DEBUG))
+			    header->hb4 |= HB4_CD;
+			}
+#endif
+					      
+		      *length = htons(size);
+
+		      /* get query name again for logging - may have been overwritten */
+		      if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
+			strcpy(daemon->namebuff, "query");
+		      
+		      if (!read_write(last_server->tcpfd, packet, size + sizeof(u16), 0) ||
+			  !read_write(last_server->tcpfd, &c1, 1, 1) ||
+			  !read_write(last_server->tcpfd, &c2, 1, 1) ||
+			  !read_write(last_server->tcpfd, payload, (c1 << 8) | c2, 1))
+			{
+			  close(last_server->tcpfd);
+			  last_server->tcpfd = -1;
+			  /* We get data then EOF, reopen connection to same server,
+			     else try next. This avoids DoS from a server which accepts
+			     connections and then closes them. */
+			  if (last_server->flags & SERV_GOT_TCP)
+			    goto retry;
+			  else
+			    continue;
+			}
+		      
+		      last_server->flags |= SERV_GOT_TCP;
+
+		      m = (c1 << 8) | c2;
+		      
+		      if (last_server->addr.sa.sa_family == AF_INET)
+			log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff, 
+				  (struct all_addr *)&last_server->addr.in.sin_addr, NULL); 
+#ifdef HAVE_IPV6
+		      else
+			log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff, 
+				  (struct all_addr *)&last_server->addr.in6.sin6_addr, NULL);
+#endif 
+
+#ifdef HAVE_DNSSEC
+		      if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC))
+			{
+			  int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
+			  int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname, 
+						       last_server, have_mark, mark, &keycount);
+			  char *result, *domain = "result";
+			  
+			  if (status == STAT_ABANDONED)
+			    {
+			      result = "ABANDONED";
+			      status = STAT_BOGUS;
+			    }
+			  else
+			    result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
+			  
+			  if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL))
+			    domain = daemon->namebuff;
+
+			  log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
+			  
+			  if (status == STAT_BOGUS)
+			    {
+			      no_cache_dnssec = 1;
+			      bogusanswer = 1;
+			    }
+
+			  if (status == STAT_SECURE)
+			    cache_secure = 1;
+			}
+#endif
+
+		      /* restore CD bit to the value in the query */
+		      if (checking_disabled)
+			header->hb4 |= HB4_CD;
+		      else
+			header->hb4 &= ~HB4_CD;
+		      
+		      /* There's no point in updating the cache, since this process will exit and
+			 lose the information after a few queries. We make this call for the alias and 
+			 bogus-nxdomain side-effects. */
+		      /* If the crc of the question section doesn't match the crc we sent, then
+			 someone might be attempting to insert bogus values into the cache by 
+			 sending replies containing questions and bogus answers. */
+#ifdef HAVE_DNSSEC
+		      newhash = hash_questions(header, (unsigned int)m, daemon->namebuff);
+		      if (!newhash || memcmp(hash, newhash, HASH_SIZE) != 0)
+			{ 
+			  m = 0;
+			  break;
+			}
+#else			  
+		      if (crc != questions_crc(header, (unsigned int)m, daemon->namebuff))
+			{
+			  m = 0;
+			  break;
+			}
+#endif
+
+		      m = process_reply(header, now, last_server, (unsigned int)m, 
+					option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
+					ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr); 
+		      
+		      break;
+		    }
+		}
+	
+	      /* In case of local answer or no connections made. */
+	      if (m == 0)
+		m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
+	    }
+	}
+	  
+      check_log_writer(1);
+      
+      *length = htons(m);
+           
+      if (m == 0 || !read_write(confd, packet, m + sizeof(u16), 0))
+	return packet;
+    }
+}
+
+static struct frec *allocate_frec(time_t now)
+{
+  struct frec *f;
+  
+  if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
+    {
+      f->next = daemon->frec_list;
+      f->time = now;
+      f->sentto = NULL;
+      f->rfd4 = NULL;
+      f->flags = 0;
+#ifdef HAVE_IPV6
+      f->rfd6 = NULL;
+#endif
+#ifdef HAVE_DNSSEC
+      f->dependent = NULL;
+      f->blocking_query = NULL;
+      f->stash = NULL;
+#endif
+      daemon->frec_list = f;
+    }
+
+  return f;
+}
+
+struct randfd *allocate_rfd(int family)
+{
+  static int finger = 0;
+  int i;
+
+  /* limit the number of sockets we have open to avoid starvation of 
+     (eg) TFTP. Once we have a reasonable number, randomness should be OK */
+
+  for (i = 0; i < RANDOM_SOCKS; i++)
+    if (daemon->randomsocks[i].refcount == 0)
+      {
+	if ((daemon->randomsocks[i].fd = random_sock(family)) == -1)
+	  break;
+      
+	daemon->randomsocks[i].refcount = 1;
+	daemon->randomsocks[i].family = family;
+	return &daemon->randomsocks[i];
+      }
+
+  /* No free ones or cannot get new socket, grab an existing one */
+  for (i = 0; i < RANDOM_SOCKS; i++)
+    {
+      int j = (i+finger) % RANDOM_SOCKS;
+      if (daemon->randomsocks[j].refcount != 0 &&
+	  daemon->randomsocks[j].family == family && 
+	  daemon->randomsocks[j].refcount != 0xffff)
+	{
+	  finger = j;
+	  daemon->randomsocks[j].refcount++;
+	  return &daemon->randomsocks[j];
+	}
+    }
+
+  return NULL; /* doom */
+}
+
+void free_rfd(struct randfd *rfd)
+{
+  if (rfd && --(rfd->refcount) == 0)
+    close(rfd->fd);
+}
+
+static void free_frec(struct frec *f)
+{
+  free_rfd(f->rfd4);
+  f->rfd4 = NULL;
+  f->sentto = NULL;
+  f->flags = 0;
+  
+#ifdef HAVE_IPV6
+  free_rfd(f->rfd6);
+  f->rfd6 = NULL;
+#endif
+
+#ifdef HAVE_DNSSEC
+  if (f->stash)
+    {
+      blockdata_free(f->stash);
+      f->stash = NULL;
+    }
+
+  /* Anything we're waiting on is pointless now, too */
+  if (f->blocking_query)
+    free_frec(f->blocking_query);
+  f->blocking_query = NULL;
+  f->dependent = NULL;
+#endif
+}
+
+
+
+/* if wait==NULL return a free or older than TIMEOUT record.
+   else return *wait zero if one available, or *wait is delay to
+   when the oldest in-use record will expire. Impose an absolute
+   limit of 4*TIMEOUT before we wipe things (for random sockets).
+   If force is set, always return a result, even if we have
+   to allocate above the limit. */
+struct frec *get_new_frec(time_t now, int *wait, int force)
+{
+  struct frec *f, *oldest, *target;
+  int count;
+  
+  if (wait)
+    *wait = 0;
+
+  for (f = daemon->frec_list, oldest = NULL, target =  NULL, count = 0; f; f = f->next, count++)
+    if (!f->sentto)
+      target = f;
+    else 
+      {
+#ifdef HAVE_DNSSEC
+	    /* Don't free DNSSEC sub-queries here, as we may end up with
+	       dangling references to them. They'll go when their "real" query 
+	       is freed. */
+	    if (!f->dependent)
+#endif
+	      {
+		if (difftime(now, f->time) >= 4*TIMEOUT)
+		  {
+		    free_frec(f);
+		    target = f;
+		  }
+	     
+	    
+		if (!oldest || difftime(f->time, oldest->time) <= 0)
+		  oldest = f;
+	      }
+      }
+
+  if (target)
+    {
+      target->time = now;
+      return target;
+    }
+  
+  /* can't find empty one, use oldest if there is one
+     and it's older than timeout */
+  if (!force && oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
+    { 
+      /* keep stuff for twice timeout if we can by allocating a new
+	 record instead */
+      if (difftime(now, oldest->time) < 2*TIMEOUT && 
+	  count <= daemon->ftabsize &&
+	  (f = allocate_frec(now)))
+	return f;
+
+      if (!wait)
+	{
+	  free_frec(oldest);
+	  oldest->time = now;
+	}
+      return oldest;
+    }
+  
+  /* none available, calculate time 'till oldest record expires */
+  if (!force && count > daemon->ftabsize)
+    {
+      static time_t last_log = 0;
+      
+      if (oldest && wait)
+	*wait = oldest->time + (time_t)TIMEOUT - now;
+      
+      if ((int)difftime(now, last_log) > 5)
+	{
+	  last_log = now;
+	  my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries reached (max: %d)"), daemon->ftabsize);
+	}
+
+      return NULL;
+    }
+  
+  if (!(f = allocate_frec(now)) && wait)
+    /* wait one second on malloc failure */
+    *wait = 1;
+
+  return f; /* OK if malloc fails and this is NULL */
+}
+
+/* crc is all-ones if not known. */
+static struct frec *lookup_frec(unsigned short id, void *hash)
+{
+  struct frec *f;
+
+  for(f = daemon->frec_list; f; f = f->next)
+    if (f->sentto && f->new_id == id && 
+	(!hash || memcmp(hash, f->hash, HASH_SIZE) == 0))
+      return f;
+      
+  return NULL;
+}
+
+static struct frec *lookup_frec_by_sender(unsigned short id,
+					  union mysockaddr *addr,
+					  void *hash)
+{
+  struct frec *f;
+  
+  for(f = daemon->frec_list; f; f = f->next)
+    if (f->sentto &&
+	f->orig_id == id && 
+	memcmp(hash, f->hash, HASH_SIZE) == 0 &&
+	sockaddr_isequal(&f->source, addr))
+      return f;
+   
+  return NULL;
+}
+ 
+/* Send query packet again, if we can. */
+void resend_query()
+{
+  if (daemon->srv_save)
+    {
+      int fd;
+      
+      if (daemon->srv_save->sfd)
+	fd = daemon->srv_save->sfd->fd;
+      else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
+	fd = daemon->rfd_save->fd;
+      else
+	return;
+      
+      while(retry_send(sendto(fd, daemon->packet, daemon->packet_len, 0,
+			      &daemon->srv_save->addr.sa, 
+			      sa_len(&daemon->srv_save->addr)))); 
+    }
+}
+
+/* A server record is going away, remove references to it */
+void server_gone(struct server *server)
+{
+  struct frec *f;
+  
+  for (f = daemon->frec_list; f; f = f->next)
+    if (f->sentto && f->sentto == server)
+      free_frec(f);
+  
+  if (daemon->last_server == server)
+    daemon->last_server = NULL;
+
+  if (daemon->srv_save == server)
+    daemon->srv_save = NULL;
+}
+
+/* return unique random ids. */
+static unsigned short get_id(void)
+{
+  unsigned short ret = 0;
+  
+  do 
+    ret = rand16();
+  while (lookup_frec(ret, NULL));
+  
+  return ret;
+}
+
+
+
+
+
diff --git a/src/helper.c b/src/helper.c
new file mode 100755
index 0000000..236f916
--- /dev/null
+++ b/src/helper.c
@@ -0,0 +1,898 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_SCRIPT
+
+/* This file has code to fork a helper process which receives data via a pipe 
+   shared with the main process and which is responsible for calling a script when
+   DHCP leases change.
+
+   The helper process is forked before the main process drops root, so it retains root 
+   privs to pass on to the script. For this reason it tries to be paranoid about 
+   data received from the main process, in case that has been compromised. We don't
+   want the helper to give an attacker root. In particular, the script to be run is
+   not settable via the pipe, once the fork has taken place it is not alterable by the 
+   main process.
+*/
+
+static void my_setenv(const char *name, const char *value, int *error);
+static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end,  char *env, int *err);
+
+#ifdef HAVE_LUASCRIPT
+#define LUA_COMPAT_ALL
+#include <lua.h>  
+#include <lualib.h>  
+#include <lauxlib.h>  
+
+#ifndef lua_open
+#define lua_open()     luaL_newstate()
+#endif
+
+lua_State *lua;
+
+static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field);
+#endif
+
+
+struct script_data
+{
+  int flags;
+  int action, hwaddr_len, hwaddr_type;
+  int clid_len, hostname_len, ed_len;
+  struct in_addr addr, giaddr;
+  unsigned int remaining_time;
+#ifdef HAVE_BROKEN_RTC
+  unsigned int length;
+#else
+  time_t expires;
+#endif
+#ifdef HAVE_TFTP
+  off_t file_len;
+#endif
+#ifdef HAVE_IPV6
+  struct in6_addr addr6;
+#endif
+#ifdef HAVE_DHCP6
+  int iaid, vendorclass_count;
+#endif
+  unsigned char hwaddr[DHCP_CHADDR_MAX];
+  char interface[IF_NAMESIZE];
+};
+
+static struct script_data *buf = NULL;
+static size_t bytes_in_buf = 0, buf_size = 0;
+
+int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
+{
+  pid_t pid;
+  int i, pipefd[2];
+  struct sigaction sigact;
+  unsigned char *alloc_buff = NULL;
+  
+  /* create the pipe through which the main program sends us commands,
+     then fork our process. */
+  if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
+    {
+      send_event(err_fd, EVENT_PIPE_ERR, errno, NULL);
+      _exit(0);
+    }
+
+  if (pid != 0)
+    {
+      close(pipefd[0]); /* close reader side */
+      return pipefd[1];
+    }
+
+  /* ignore SIGTERM, so that we can clean up when the main process gets hit
+     and SIGALRM so that we can use sleep() */
+  sigact.sa_handler = SIG_IGN;
+  sigact.sa_flags = 0;
+  sigemptyset(&sigact.sa_mask);
+  sigaction(SIGTERM, &sigact, NULL);
+  sigaction(SIGALRM, &sigact, NULL);
+
+  if (!option_bool(OPT_DEBUG) && uid != 0)
+    {
+      gid_t dummy;
+      if (setgroups(0, &dummy) == -1 || 
+	  setgid(gid) == -1 || 
+	  setuid(uid) == -1)
+	{
+	  if (option_bool(OPT_NO_FORK))
+	    /* send error to daemon process if no-fork */
+	    send_event(event_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
+	  else
+	    {
+	      /* kill daemon */
+	      send_event(event_fd, EVENT_DIE, 0, NULL);
+	      /* return error */
+	      send_event(err_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
+	    }
+	  _exit(0);
+	}
+    }
+
+  /* close all the sockets etc, we don't need them here. 
+     Don't close err_fd, in case the lua-init fails.
+     Note that we have to do this before lua init
+     so we don't close any lua fds. */
+  for (max_fd--; max_fd >= 0; max_fd--)
+    if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO && 
+	max_fd != STDIN_FILENO && max_fd != pipefd[0] && 
+	max_fd != event_fd && max_fd != err_fd)
+      close(max_fd);
+
+#ifdef HAVE_LUASCRIPT
+  if (daemon->luascript)
+    {
+      const char *lua_err = NULL;
+      lua = lua_open();
+      luaL_openlibs(lua);
+      
+      /* get Lua to load our script file */
+      if (luaL_dofile(lua, daemon->luascript) != 0)
+	lua_err = lua_tostring(lua, -1);
+      else
+	{
+	  lua_getglobal(lua, "lease");
+	  if (lua_type(lua, -1) != LUA_TFUNCTION) 
+	    lua_err = _("lease() function missing in Lua script");
+	}
+      
+      if (lua_err)
+	{
+	  if (option_bool(OPT_NO_FORK) || option_bool(OPT_DEBUG))
+	    /* send error to daemon process if no-fork */
+	    send_event(event_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
+	  else
+	    {
+	      /* kill daemon */
+	      send_event(event_fd, EVENT_DIE, 0, NULL);
+	      /* return error */
+	      send_event(err_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
+	    }
+	  _exit(0);
+	}
+      
+      lua_pop(lua, 1);  /* remove nil from stack */
+      lua_getglobal(lua, "init");
+      if (lua_type(lua, -1) == LUA_TFUNCTION)
+	lua_call(lua, 0, 0);
+      else
+	lua_pop(lua, 1);  /* remove nil from stack */	
+    }
+#endif
+
+  /* All init done, close our copy of the error pipe, so that main process can return */
+  if (err_fd != -1)
+    close(err_fd);
+    
+  /* loop here */
+  while(1)
+    {
+      struct script_data data;
+      char *p, *action_str, *hostname = NULL, *domain = NULL;
+      unsigned char *buf = (unsigned char *)daemon->namebuff;
+      unsigned char *end, *extradata;
+      int is6, err = 0;
+      int pipeout[2];
+
+      /* Free rarely-allocated memory from previous iteration. */
+      if (alloc_buff)
+       {
+         free(alloc_buff);
+         alloc_buff = NULL;
+       }
+      
+      /* we read zero bytes when pipe closed: this is our signal to exit */ 
+      if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), 1))
+	{
+#ifdef HAVE_LUASCRIPT
+	  if (daemon->luascript)
+	    {
+	      lua_getglobal(lua, "shutdown");
+	      if (lua_type(lua, -1) == LUA_TFUNCTION)
+		lua_call(lua, 0, 0);
+	    }
+#endif
+	  _exit(0);
+	}
+ 
+      is6 = !!(data.flags & (LEASE_TA | LEASE_NA));
+      
+      if (data.action == ACTION_DEL)
+	action_str = "del";
+      else if (data.action == ACTION_ADD)
+	action_str = "add";
+      else if (data.action == ACTION_OLD || data.action == ACTION_OLD_HOSTNAME)
+	action_str = "old";
+      else if (data.action == ACTION_TFTP)
+	{
+	  action_str = "tftp";
+	  is6 = (data.flags != AF_INET);
+	}
+      else if (data.action == ACTION_ARP)
+	{
+	  action_str = "arp-add";
+	  is6 = (data.flags != AF_INET);
+	}
+       else if (data.action == ACTION_ARP_DEL)
+	{
+	  action_str = "arp-del";
+	  is6 = (data.flags != AF_INET);
+	  data.action = ACTION_ARP;
+	}
+       else 
+	continue;
+
+      	
+      /* stringify MAC into dhcp_buff */
+      p = daemon->dhcp_buff;
+      if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0) 
+	p += sprintf(p, "%.2x-", data.hwaddr_type);
+      for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
+	{
+	  p += sprintf(p, "%.2x", data.hwaddr[i]);
+	  if (i != data.hwaddr_len - 1)
+	    p += sprintf(p, ":");
+	}
+      
+      /* supplied data may just exceed normal buffer (unlikely) */
+      if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME && 
+	  !(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len)))
+	continue;
+      
+      if (!read_write(pipefd[0], buf, 
+		      data.hostname_len + data.ed_len + data.clid_len, 1))
+	continue;
+
+      /* CLID into packet */
+      for (p = daemon->packet, i = 0; i < data.clid_len; i++)
+	{
+	  p += sprintf(p, "%.2x", buf[i]);
+	  if (i != data.clid_len - 1) 
+	      p += sprintf(p, ":");
+	}
+
+#ifdef HAVE_DHCP6
+      if (is6)
+	{
+	  /* or IAID and server DUID for IPv6 */
+	  sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.iaid);	
+	  for (p = daemon->dhcp_packet.iov_base, i = 0; i < daemon->duid_len; i++)
+	    {
+	      p += sprintf(p, "%.2x", daemon->duid[i]);
+	      if (i != daemon->duid_len - 1) 
+		p += sprintf(p, ":");
+	    }
+
+	}
+#endif
+
+      buf += data.clid_len;
+
+      if (data.hostname_len != 0)
+	{
+	  char *dot;
+	  hostname = (char *)buf;
+	  hostname[data.hostname_len - 1] = 0;
+	  if (data.action != ACTION_TFTP)
+	    {
+	      if (!legal_hostname(hostname))
+		hostname = NULL;
+	      else if ((dot = strchr(hostname, '.')))
+		{
+		  domain = dot+1;
+		  *dot = 0;
+		} 
+	    }
+	}
+    
+      extradata = buf + data.hostname_len;
+    
+      if (!is6)
+	inet_ntop(AF_INET, &data.addr, daemon->addrbuff, ADDRSTRLEN);
+#ifdef HAVE_IPV6
+      else
+	inet_ntop(AF_INET6, &data.addr6, daemon->addrbuff, ADDRSTRLEN);
+#endif
+
+#ifdef HAVE_TFTP
+      /* file length */
+      if (data.action == ACTION_TFTP)
+	sprintf(is6 ? daemon->packet : daemon->dhcp_buff, "%lu", (unsigned long)data.file_len);
+#endif
+
+#ifdef HAVE_LUASCRIPT
+      if (daemon->luascript)
+	{
+	  if (data.action == ACTION_TFTP)
+	    {
+	      lua_getglobal(lua, "tftp"); 
+	      if (lua_type(lua, -1) != LUA_TFUNCTION)
+		lua_pop(lua, 1); /* tftp function optional */
+	      else
+		{
+		  lua_pushstring(lua, action_str); /* arg1 - action */
+		  lua_newtable(lua);               /* arg2 - data table */
+		  lua_pushstring(lua, daemon->addrbuff);
+		  lua_setfield(lua, -2, "destination_address");
+		  lua_pushstring(lua, hostname);
+		  lua_setfield(lua, -2, "file_name"); 
+		  lua_pushstring(lua, is6 ? daemon->packet : daemon->dhcp_buff);
+		  lua_setfield(lua, -2, "file_size");
+		  lua_call(lua, 2, 0);	/* pass 2 values, expect 0 */
+		}
+	    }
+	  else if (data.action == ACTION_ARP)
+	    {
+	      lua_getglobal(lua, "arp"); 
+	      if (lua_type(lua, -1) != LUA_TFUNCTION)
+		lua_pop(lua, 1); /* arp function optional */
+	      else
+		{
+		  lua_pushstring(lua, action_str); /* arg1 - action */
+		  lua_newtable(lua);               /* arg2 - data table */
+		  lua_pushstring(lua, daemon->addrbuff);
+		  lua_setfield(lua, -2, "client_address");
+		  lua_pushstring(lua, daemon->dhcp_buff);
+		  lua_setfield(lua, -2, "mac_address");
+		  lua_call(lua, 2, 0);	/* pass 2 values, expect 0 */
+		}
+	    }
+	  else
+	    {
+	      lua_getglobal(lua, "lease");     /* function to call */
+	      lua_pushstring(lua, action_str); /* arg1 - action */
+	      lua_newtable(lua);               /* arg2 - data table */
+	      
+	      if (is6)
+		{
+		  lua_pushstring(lua, daemon->packet);
+		  lua_setfield(lua, -2, "client_duid");
+		  lua_pushstring(lua, daemon->dhcp_packet.iov_base);
+		  lua_setfield(lua, -2, "server_duid");
+		  lua_pushstring(lua, daemon->dhcp_buff3);
+		  lua_setfield(lua, -2, "iaid");
+		}
+	      
+	      if (!is6 && data.clid_len != 0)
+		{
+		  lua_pushstring(lua, daemon->packet);
+		  lua_setfield(lua, -2, "client_id");
+		}
+	      
+	      if (strlen(data.interface) != 0)
+		{
+		  lua_pushstring(lua, data.interface);
+		  lua_setfield(lua, -2, "interface");
+		}
+	      
+#ifdef HAVE_BROKEN_RTC	
+	      lua_pushnumber(lua, data.length);
+	      lua_setfield(lua, -2, "lease_length");
+#else
+	      lua_pushnumber(lua, data.expires);
+	      lua_setfield(lua, -2, "lease_expires");
+#endif
+	      
+	      if (hostname)
+		{
+		  lua_pushstring(lua, hostname);
+		  lua_setfield(lua, -2, "hostname");
+		}
+	      
+	      if (domain)
+		{
+		  lua_pushstring(lua, domain);
+		  lua_setfield(lua, -2, "domain");
+		}
+	      
+	      end = extradata + data.ed_len;
+	      buf = extradata;
+	      
+	      if (!is6)
+		buf = grab_extradata_lua(buf, end, "vendor_class");
+#ifdef HAVE_DHCP6
+	      else  if (data.vendorclass_count != 0)
+		{
+		  sprintf(daemon->dhcp_buff2, "vendor_class_id");
+		  buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
+		  for (i = 0; i < data.vendorclass_count - 1; i++)
+		    {
+		      sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
+		      buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
+		    }
+		}
+#endif
+	      
+	      buf = grab_extradata_lua(buf, end, "supplied_hostname");
+	      
+	      if (!is6)
+		{
+		  buf = grab_extradata_lua(buf, end, "cpewan_oui");
+		  buf = grab_extradata_lua(buf, end, "cpewan_serial");   
+		  buf = grab_extradata_lua(buf, end, "cpewan_class");
+		  buf = grab_extradata_lua(buf, end, "circuit_id");
+		  buf = grab_extradata_lua(buf, end, "subscriber_id");
+		  buf = grab_extradata_lua(buf, end, "remote_id");
+		}
+	      
+	      buf = grab_extradata_lua(buf, end, "tags");
+	      
+	      if (is6)
+		buf = grab_extradata_lua(buf, end, "relay_address");
+	      else if (data.giaddr.s_addr != 0)
+		{
+		  lua_pushstring(lua, inet_ntoa(data.giaddr));
+		  lua_setfield(lua, -2, "relay_address");
+		}
+	      
+	      for (i = 0; buf; i++)
+		{
+		  sprintf(daemon->dhcp_buff2, "user_class%i", i);
+		  buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
+		}
+	      
+	      if (data.action != ACTION_DEL && data.remaining_time != 0)
+		{
+		  lua_pushnumber(lua, data.remaining_time);
+		  lua_setfield(lua, -2, "time_remaining");
+		}
+	      
+	      if (data.action == ACTION_OLD_HOSTNAME && hostname)
+		{
+		  lua_pushstring(lua, hostname);
+		  lua_setfield(lua, -2, "old_hostname");
+		}
+	      
+	      if (!is6 || data.hwaddr_len != 0)
+		{
+		  lua_pushstring(lua, daemon->dhcp_buff);
+		  lua_setfield(lua, -2, "mac_address");
+		}
+	      
+	      lua_pushstring(lua, daemon->addrbuff);
+	      lua_setfield(lua, -2, "ip_address");
+	    
+	      lua_call(lua, 2, 0);	/* pass 2 values, expect 0 */
+	    }
+	}
+#endif
+
+      /* no script, just lua */
+      if (!daemon->lease_change_command)
+	continue;
+
+      /* Pipe to capture stdout and stderr from script */
+      if (!option_bool(OPT_DEBUG) && pipe(pipeout) == -1)
+	continue;
+      
+      /* possible fork errors are all temporary resource problems */
+      while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
+	sleep(2);
+
+      if (pid == -1)
+        {
+	  if (!option_bool(OPT_DEBUG))
+	    {
+	      close(pipeout[0]);
+	      close(pipeout[1]);
+	    }
+	  continue;
+        }
+      
+      /* wait for child to complete */
+      if (pid != 0)
+	{
+	  if (!option_bool(OPT_DEBUG))
+	    {
+	      FILE *fp;
+	  
+	      close(pipeout[1]);
+	      
+	      /* Read lines sent to stdout/err by the script and pass them back to be logged */
+	      if (!(fp = fdopen(pipeout[0], "r")))
+		close(pipeout[0]);
+	      else
+		{
+		  while (fgets(daemon->packet, daemon->packet_buff_sz, fp))
+		    {
+		      /* do not include new lines, log will append them */
+		      size_t len = strlen(daemon->packet);
+		      if (len > 0)
+			{
+			  --len;
+			  if (daemon->packet[len] == '\n')
+			    daemon->packet[len] = 0;
+			}
+		      send_event(event_fd, EVENT_SCRIPT_LOG, 0, daemon->packet);
+		    }
+		  fclose(fp);
+		}
+	    }
+	  
+	  /* reap our children's children, if necessary */
+	  while (1)
+	    {
+	      int status;
+	      pid_t rc = wait(&status);
+	      
+	      if (rc == pid)
+		{
+		  /* On error send event back to main process for logging */
+		  if (WIFSIGNALED(status))
+		    send_event(event_fd, EVENT_KILLED, WTERMSIG(status), NULL);
+		  else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
+		    send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status), NULL);
+		  break;
+		}
+	      
+	      if (rc == -1 && errno != EINTR)
+		break;
+	    }
+	  
+	  continue;
+	}
+
+      if (!option_bool(OPT_DEBUG))
+	{
+	  /* map stdout/stderr of script to pipeout */
+	  close(pipeout[0]);
+	  dup2(pipeout[1], STDOUT_FILENO);
+	  dup2(pipeout[1], STDERR_FILENO);
+	  close(pipeout[1]);
+	}
+      
+      if (data.action != ACTION_TFTP && data.action != ACTION_ARP)
+	{
+#ifdef HAVE_DHCP6
+	  my_setenv("DNSMASQ_IAID", is6 ? daemon->dhcp_buff3 : NULL, &err);
+	  my_setenv("DNSMASQ_SERVER_DUID", is6 ? daemon->dhcp_packet.iov_base : NULL, &err); 
+	  my_setenv("DNSMASQ_MAC", is6 && data.hwaddr_len != 0 ? daemon->dhcp_buff : NULL, &err);
+#endif
+	  
+	  my_setenv("DNSMASQ_CLIENT_ID", !is6 && data.clid_len != 0 ? daemon->packet : NULL, &err);
+	  my_setenv("DNSMASQ_INTERFACE", strlen(data.interface) != 0 ? data.interface : NULL, &err);
+	  
+#ifdef HAVE_BROKEN_RTC
+	  sprintf(daemon->dhcp_buff2, "%u", data.length);
+	  my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
+#else
+	  sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
+	  my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err); 
+#endif
+	  
+	  my_setenv("DNSMASQ_DOMAIN", domain, &err);
+	  
+	  end = extradata + data.ed_len;
+	  buf = extradata;
+	  
+	  if (!is6)
+	    buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
+#ifdef HAVE_DHCP6
+	  else
+	    {
+	      if (data.vendorclass_count != 0)
+		{
+		  buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err);
+		  for (i = 0; i < data.vendorclass_count - 1; i++)
+		    {
+		      sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i);
+		      buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
+		    }
+		}
+	    }
+#endif
+	  
+	  buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err);
+	  
+	  if (!is6)
+	    {
+	      buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
+	      buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);   
+	      buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
+	      buf = grab_extradata(buf, end, "DNSMASQ_CIRCUIT_ID", &err);
+	      buf = grab_extradata(buf, end, "DNSMASQ_SUBSCRIBER_ID", &err);
+	      buf = grab_extradata(buf, end, "DNSMASQ_REMOTE_ID", &err);
+	      buf = grab_extradata(buf, end, "DNSMASQ_REQUESTED_OPTIONS", &err);
+	    }
+	  
+	  buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
+
+	  if (is6)
+	    buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
+	  else 
+	    my_setenv("DNSMASQ_RELAY_ADDRESS", data.giaddr.s_addr != 0 ? inet_ntoa(data.giaddr) : NULL, &err); 
+	  
+	  for (i = 0; buf; i++)
+	    {
+	      sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i);
+	      buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
+	    }
+	  
+	  sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
+	  my_setenv("DNSMASQ_TIME_REMAINING", data.action != ACTION_DEL && data.remaining_time != 0 ? daemon->dhcp_buff2 : NULL, &err);
+	  
+	  my_setenv("DNSMASQ_OLD_HOSTNAME", data.action == ACTION_OLD_HOSTNAME ? hostname : NULL, &err);
+	  if (data.action == ACTION_OLD_HOSTNAME)
+	    hostname = NULL;
+	  
+	  my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
+	}
+      
+      /* we need to have the event_fd around if exec fails */
+      if ((i = fcntl(event_fd, F_GETFD)) != -1)
+	fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
+      close(pipefd[0]);
+
+      p =  strrchr(daemon->lease_change_command, '/');
+      if (err == 0)
+	{
+	  execl(daemon->lease_change_command, 
+		p ? p+1 : daemon->lease_change_command, action_str, 
+		(is6 && data.action != ACTION_ARP) ? daemon->packet : daemon->dhcp_buff, 
+		daemon->addrbuff, hostname, (char*)NULL);
+	  err = errno;
+	}
+      /* failed, send event so the main process logs the problem */
+      send_event(event_fd, EVENT_EXEC_ERR, err, NULL);
+      _exit(0); 
+    }
+}
+
+static void my_setenv(const char *name, const char *value, int *error)
+{
+  if (*error == 0)
+    {
+      if (!value)
+	unsetenv(name);
+      else if (setenv(name, value, 1) != 0)
+	*error = errno;
+    }
+}
+ 
+static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end,  char *env, int *err)
+{
+  unsigned char *next = NULL;
+  char *val = NULL;
+
+  if (buf && (buf != end))
+    {
+      for (next = buf; ; next++)
+	if (next == end)
+	  {
+	    next = NULL;
+	    break;
+	  }
+	else if (*next == 0)
+	  break;
+
+      if (next && (next != buf))
+	{
+	  char *p;
+	  /* No "=" in value */
+	  if ((p = strchr((char *)buf, '=')))
+	    *p = 0;
+	  val = (char *)buf;
+	}
+    }
+  
+  my_setenv(env, val, err);
+   
+  return next ? next + 1 : NULL;
+}
+
+#ifdef HAVE_LUASCRIPT
+static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field)
+{
+  unsigned char *next;
+
+  if (!buf || (buf == end))
+    return NULL;
+
+  for (next = buf; *next != 0; next++)
+    if (next == end)
+      return NULL;
+  
+  if (next != buf)
+    {
+      lua_pushstring(lua,  (char *)buf);
+      lua_setfield(lua, -2, field);
+    }
+
+  return next + 1;
+}
+#endif
+
+static void buff_alloc(size_t size)
+{
+  if (size > buf_size)
+    {
+      struct script_data *new;
+      
+      /* start with reasonable size, will almost never need extending. */
+      if (size < sizeof(struct script_data) + 200)
+	size = sizeof(struct script_data) + 200;
+
+      if (!(new = whine_malloc(size)))
+	return;
+      if (buf)
+	free(buf);
+      buf = new;
+      buf_size = size;
+    }
+}
+
+/* pack up lease data into a buffer */    
+void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
+{
+  unsigned char *p;
+  unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
+  int fd = daemon->dhcpfd;
+#ifdef HAVE_DHCP6 
+  if (!daemon->dhcp)
+    fd = daemon->dhcp6fd;
+#endif
+
+  /* no script */
+  if (daemon->helperfd == -1)
+    return;
+
+  if (lease->extradata)
+    ed_len = lease->extradata_len;
+  if (lease->clid)
+    clid_len = lease->clid_len;
+  if (hostname)
+    hostname_len = strlen(hostname) + 1;
+
+  buff_alloc(sizeof(struct script_data) +  clid_len + ed_len + hostname_len);
+
+  buf->action = action;
+  buf->flags = lease->flags;
+#ifdef HAVE_DHCP6 
+  buf->vendorclass_count = lease->vendorclass_count;
+  buf->addr6 = lease->addr6;
+  buf->iaid = lease->iaid;
+#endif
+  buf->hwaddr_len = lease->hwaddr_len;
+  buf->hwaddr_type = lease->hwaddr_type;
+  buf->clid_len = clid_len;
+  buf->ed_len = ed_len;
+  buf->hostname_len = hostname_len;
+  buf->addr = lease->addr;
+  buf->giaddr = lease->giaddr;
+  memcpy(buf->hwaddr, lease->hwaddr, DHCP_CHADDR_MAX);
+  if (!indextoname(fd, lease->last_interface, buf->interface))
+    buf->interface[0] = 0;
+  
+#ifdef HAVE_BROKEN_RTC 
+  buf->length = lease->length;
+#else
+  buf->expires = lease->expires;
+#endif
+
+  if (lease->expires != 0)
+    buf->remaining_time = (unsigned int)difftime(lease->expires, now);
+  else
+    buf->remaining_time = 0;
+
+  p = (unsigned char *)(buf+1);
+  if (clid_len != 0)
+    {
+      memcpy(p, lease->clid, clid_len);
+      p += clid_len;
+    }
+  if (hostname_len != 0)
+    {
+      memcpy(p, hostname, hostname_len);
+      p += hostname_len;
+    }
+  if (ed_len != 0)
+    {
+      memcpy(p, lease->extradata, ed_len);
+      p += ed_len;
+    }
+  bytes_in_buf = p - (unsigned char *)buf;
+}
+
+#ifdef HAVE_TFTP
+/* This nastily re-uses DHCP-fields for TFTP stuff */
+void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
+{
+  unsigned int filename_len;
+
+  /* no script */
+  if (daemon->helperfd == -1)
+    return;
+  
+  filename_len = strlen(filename) + 1;
+  buff_alloc(sizeof(struct script_data) +  filename_len);
+  memset(buf, 0, sizeof(struct script_data));
+
+  buf->action = ACTION_TFTP;
+  buf->hostname_len = filename_len;
+  buf->file_len = file_len;
+
+  if ((buf->flags = peer->sa.sa_family) == AF_INET)
+    buf->addr = peer->in.sin_addr;
+#ifdef HAVE_IPV6
+  else
+    buf->addr6 = peer->in6.sin6_addr;
+#endif
+
+  memcpy((unsigned char *)(buf+1), filename, filename_len);
+  
+  bytes_in_buf = sizeof(struct script_data) +  filename_len;
+}
+#endif
+
+void queue_arp(int action, unsigned char *mac, int maclen, int family, struct all_addr *addr)
+{
+  /* no script */
+  if (daemon->helperfd == -1)
+    return;
+  
+  buff_alloc(sizeof(struct script_data));
+  memset(buf, 0, sizeof(struct script_data));
+
+  buf->action = action;
+  buf->hwaddr_len = maclen;
+  buf->hwaddr_type =  ARPHRD_ETHER; 
+  if ((buf->flags = family) == AF_INET)
+    buf->addr = addr->addr.addr4;
+#ifdef HAVE_IPV6
+  else
+    buf->addr6 = addr->addr.addr6;
+#endif
+  
+  memcpy(buf->hwaddr, mac, maclen);
+  
+  bytes_in_buf = sizeof(struct script_data);
+}
+
+int helper_buf_empty(void)
+{
+  return bytes_in_buf == 0;
+}
+
+void helper_write(void)
+{
+  ssize_t rc;
+
+  if (bytes_in_buf == 0)
+    return;
+  
+  if ((rc = write(daemon->helperfd, buf, bytes_in_buf)) != -1)
+    {
+      if (bytes_in_buf != (size_t)rc)
+	memmove(buf, buf + rc, bytes_in_buf - rc); 
+      bytes_in_buf -= rc;
+    }
+  else
+    {
+      if (errno == EAGAIN || errno == EINTR)
+	return;
+      bytes_in_buf = 0;
+    }
+}
+
+#endif
+
+
+
diff --git a/src/inotify.c b/src/inotify.c
new file mode 100644
index 0000000..b5a17dd
--- /dev/null
+++ b/src/inotify.c
@@ -0,0 +1,296 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+#ifdef HAVE_INOTIFY
+
+#include <sys/inotify.h>
+#include <sys/param.h> /* For MAXSYMLINKS */
+
+/* the strategy is to set a inotify on the directories containing
+   resolv files, for any files in the directory which are close-write 
+   or moved into the directory.
+   
+   When either of those happen, we look to see if the file involved
+   is actually a resolv-file, and if so, call poll-resolv with
+   the "force" argument, to ensure it's read.
+
+   This adds one new error condition: the directories containing
+   all specified resolv-files must exist at start-up, even if the actual
+   files don't. 
+*/
+
+static char *inotify_buffer;
+#define INOTIFY_SZ (sizeof(struct inotify_event) + NAME_MAX + 1)
+
+/* If path is a symbolic link, return the path it
+   points to, made absolute if relative.
+   If path doesn't exist or is not a symlink, return NULL.
+   Return value is malloc'ed */
+static char *my_readlink(char *path)
+{
+  ssize_t rc, size = 64;
+  char *buf;
+
+  while (1)
+    {
+      buf = safe_malloc(size);
+      rc = readlink(path, buf, (size_t)size);
+      
+      if (rc == -1)
+	{
+	  /* Not link or doesn't exist. */
+	  if (errno == EINVAL || errno == ENOENT)
+	    {
+	      free(buf);
+	      return NULL;
+	    }
+	  else
+	    die(_("cannot access path %s: %s"), path, EC_MISC);
+	}
+      else if (rc < size-1)
+	{
+	  char *d;
+	  
+	  buf[rc] = 0;
+	  if (buf[0] != '/' && ((d = strrchr(path, '/'))))
+	    {
+	      /* Add path to relative link */
+	      char *new_buf = safe_malloc((d - path) + strlen(buf) + 2);
+	      *(d+1) = 0;
+	      strcpy(new_buf, path);
+	      strcat(new_buf, buf);
+	      free(buf);
+	      buf = new_buf;
+	    }
+	  return buf;
+	}
+
+      /* Buffer too small, increase and retry */
+      size += 64;
+      free(buf);
+    }
+}
+
+void inotify_dnsmasq_init()
+{
+  struct resolvc *res;
+  inotify_buffer = safe_malloc(INOTIFY_SZ);
+  daemon->inotifyfd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
+  
+  if (daemon->inotifyfd == -1)
+    die(_("failed to create inotify: %s"), NULL, EC_MISC);
+
+  if (option_bool(OPT_NO_RESOLV))
+    return;
+  
+  for (res = daemon->resolv_files; res; res = res->next)
+    {
+      char *d, *new_path, *path = safe_malloc(strlen(res->name) + 1);
+      int links = MAXSYMLINKS;
+
+      strcpy(path, res->name);
+
+      /* Follow symlinks until we reach a non-symlink, or a non-existent file. */
+      while ((new_path = my_readlink(path)))
+	{
+	  if (links-- == 0)
+	    die(_("too many symlinks following %s"), res->name, EC_MISC);
+	  free(path);
+	  path = new_path;
+	}
+
+      res->wd = -1;
+
+      if ((d = strrchr(path, '/')))
+	{
+	  *d = 0; /* make path just directory */
+	  res->wd = inotify_add_watch(daemon->inotifyfd, path, IN_CLOSE_WRITE | IN_MOVED_TO);
+
+	  res->file = d+1; /* pointer to filename */
+	  *d = '/';
+	  
+	  if (res->wd == -1 && errno == ENOENT)
+	    die(_("directory %s for resolv-file is missing, cannot poll"), res->name, EC_MISC);
+	}	  
+	 
+      if (res->wd == -1)
+	die(_("failed to create inotify for %s: %s"), res->name, EC_MISC);
+	
+    }
+}
+
+
+/* initialisation for dynamic-dir. Set inotify watch for each directory, and read pre-existing files */
+void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz)
+{
+  struct hostsfile *ah;
+  
+  for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
+    {
+      DIR *dir_stream = NULL;
+      struct dirent *ent;
+      struct stat buf;
+     
+      if (!(ah->flags & flag))
+	continue;
+ 
+      if (stat(ah->fname, &buf) == -1 || !(S_ISDIR(buf.st_mode)))
+	{
+	  my_syslog(LOG_ERR, _("bad dynamic directory %s: %s"), 
+		    ah->fname, strerror(errno));
+	  continue;
+	}
+      
+       if (!(ah->flags & AH_WD_DONE))
+	 {
+	   ah->wd = inotify_add_watch(daemon->inotifyfd, ah->fname, IN_CLOSE_WRITE | IN_MOVED_TO);
+	   ah->flags |= AH_WD_DONE;
+	 }
+
+       /* Read contents of dir _after_ calling add_watch, in the hope of avoiding
+	  a race which misses files being added as we start */
+       if (ah->wd == -1 || !(dir_stream = opendir(ah->fname)))
+	 {
+	   my_syslog(LOG_ERR, _("failed to create inotify for %s: %s"),
+		     ah->fname, strerror(errno));
+	   continue;
+	 }
+
+       while ((ent = readdir(dir_stream)))
+	 {
+	   size_t lendir = strlen(ah->fname);
+	   size_t lenfile = strlen(ent->d_name);
+	   char *path;
+	   
+	   /* ignore emacs backups and dotfiles */
+	   if (lenfile == 0 || 
+	       ent->d_name[lenfile - 1] == '~' ||
+	       (ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
+	       ent->d_name[0] == '.')
+	     continue;
+	   
+	   if ((path = whine_malloc(lendir + lenfile + 2)))
+	     {
+	       strcpy(path, ah->fname);
+	       strcat(path, "/");
+	       strcat(path, ent->d_name);
+	       
+	       /* ignore non-regular files */
+	       if (stat(path, &buf) != -1 && S_ISREG(buf.st_mode))
+		 {
+		   if (ah->flags & AH_HOSTS)
+		     total_size = read_hostsfile(path, ah->index, total_size, rhash, revhashsz);
+#ifdef HAVE_DHCP
+		   else if (ah->flags & (AH_DHCP_HST | AH_DHCP_OPT))
+		     option_read_dynfile(path, ah->flags);
+#endif		   
+		 }
+
+	       free(path);
+	     }
+	 }
+
+       closedir(dir_stream);
+    }
+}
+
+int inotify_check(time_t now)
+{
+  int hit = 0;
+  struct hostsfile *ah;
+
+  while (1)
+    {
+      int rc;
+      char *p;
+      struct resolvc *res;
+      struct inotify_event *in;
+
+      while ((rc = read(daemon->inotifyfd, inotify_buffer, INOTIFY_SZ)) == -1 && errno == EINTR);
+      
+      if (rc <= 0)
+	break;
+      
+      for (p = inotify_buffer; rc - (p - inotify_buffer) >= (int)sizeof(struct inotify_event); p += sizeof(struct inotify_event) + in->len) 
+	{
+	  in = (struct inotify_event*)p;
+	  
+	  for (res = daemon->resolv_files; res; res = res->next)
+	    if (res->wd == in->wd && in->len != 0 && strcmp(res->file, in->name) == 0)
+	      hit = 1;
+
+	  /* ignore emacs backups and dotfiles */
+	  if (in->len == 0 || 
+	      in->name[in->len - 1] == '~' ||
+	      (in->name[0] == '#' && in->name[in->len - 1] == '#') ||
+	      in->name[0] == '.')
+	    continue;
+	  
+	  for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
+	    if (ah->wd == in->wd)
+	      {
+		size_t lendir = strlen(ah->fname);
+		char *path;
+		
+		if ((path = whine_malloc(lendir + in->len + 2)))
+		  {
+		    strcpy(path, ah->fname);
+		    strcat(path, "/");
+		    strcat(path, in->name);
+		     
+		    my_syslog(LOG_INFO, _("inotify, new or changed file %s"), path);
+
+		    if (ah->flags & AH_HOSTS)
+		      {
+			read_hostsfile(path, ah->index, 0, NULL, 0);
+#ifdef HAVE_DHCP
+			if (daemon->dhcp || daemon->doing_dhcp6) 
+			  {
+			    /* Propagate the consequences of loading a new dhcp-host */
+			    dhcp_update_configs(daemon->dhcp_conf);
+			    lease_update_from_configs(); 
+			    lease_update_file(now); 
+			    lease_update_dns(1);
+			  }
+#endif
+		      }
+#ifdef HAVE_DHCP
+		    else if (ah->flags & AH_DHCP_HST)
+		      {
+			if (option_read_dynfile(path, AH_DHCP_HST))
+			  {
+			    /* Propagate the consequences of loading a new dhcp-host */
+			    dhcp_update_configs(daemon->dhcp_conf);
+			    lease_update_from_configs(); 
+			    lease_update_file(now); 
+			    lease_update_dns(1);
+			  }
+		      }
+		    else if (ah->flags & AH_DHCP_OPT)
+		      option_read_dynfile(path, AH_DHCP_OPT);
+#endif
+		    
+		    free(path);
+		  }
+	      }
+	}
+    }
+  return hit;
+}
+
+#endif  /* INOTIFY */
+  
diff --git a/src/ip6addr.h b/src/ip6addr.h
new file mode 100644
index 0000000..82f2a57
--- /dev/null
+++ b/src/ip6addr.h
@@ -0,0 +1,34 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+
+#define IN6_IS_ADDR_ULA(a) \
+        ((((__const uint32_t *) (a))[0] & htonl (0xff000000))                 \
+         == htonl (0xfd000000))
+
+#define IN6_IS_ADDR_ULA_ZERO(a) \
+        (((__const uint32_t *) (a))[0] == htonl (0xfd000000)                        \
+         && ((__const uint32_t *) (a))[1] == 0                                \
+         && ((__const uint32_t *) (a))[2] == 0                                \
+         && ((__const uint32_t *) (a))[3] == 0)
+
+#define IN6_IS_ADDR_LINK_LOCAL_ZERO(a) \
+        (((__const uint32_t *) (a))[0] == htonl (0xfe800000)                  \
+         && ((__const uint32_t *) (a))[1] == 0                                \
+         && ((__const uint32_t *) (a))[2] == 0                                \
+         && ((__const uint32_t *) (a))[3] == 0)
+
diff --git a/src/ipset.c b/src/ipset.c
new file mode 100644
index 0000000..3a5ecc5
--- /dev/null
+++ b/src/ipset.c
@@ -0,0 +1,238 @@
+/* ipset.c is Copyright (c) 2013 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+
+   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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#if defined(HAVE_IPSET) && defined(HAVE_LINUX_NETWORK)
+
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/utsname.h>
+#include <arpa/inet.h>
+#include <linux/version.h>
+#include <linux/netlink.h>
+
+/* We want to be able to compile against old header files
+   Kernel version is handled at run-time. */
+
+#define NFNL_SUBSYS_IPSET 6
+
+#define IPSET_ATTR_DATA 7
+#define IPSET_ATTR_IP 1
+#define IPSET_ATTR_IPADDR_IPV4 1
+#define IPSET_ATTR_IPADDR_IPV6 2
+#define IPSET_ATTR_PROTOCOL 1
+#define IPSET_ATTR_SETNAME 2
+#define IPSET_CMD_ADD 9
+#define IPSET_CMD_DEL 10
+#define IPSET_MAXNAMELEN 32
+#define IPSET_PROTOCOL 6
+
+#ifndef NFNETLINK_V0
+#define NFNETLINK_V0    0
+#endif
+
+#ifndef NLA_F_NESTED
+#define NLA_F_NESTED		(1 << 15)
+#endif
+
+#ifndef NLA_F_NET_BYTEORDER
+#define NLA_F_NET_BYTEORDER	(1 << 14)
+#endif
+
+struct my_nlattr {
+        __u16           nla_len;
+        __u16           nla_type;
+};
+
+struct my_nfgenmsg {
+        __u8  nfgen_family;             /* AF_xxx */
+        __u8  version;          /* nfnetlink version */
+        __be16    res_id;               /* resource id */
+};
+
+
+/* data structure size in here is fixed */
+#define BUFF_SZ 256
+
+#define NL_ALIGN(len) (((len)+3) & ~(3))
+static const struct sockaddr_nl snl = { .nl_family = AF_NETLINK };
+static int ipset_sock, old_kernel;
+static char *buffer;
+
+static inline void add_attr(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data)
+{
+  struct my_nlattr *attr = (void *)nlh + NL_ALIGN(nlh->nlmsg_len);
+  uint16_t payload_len = NL_ALIGN(sizeof(struct my_nlattr)) + len;
+  attr->nla_type = type;
+  attr->nla_len = payload_len;
+  memcpy((void *)attr + NL_ALIGN(sizeof(struct my_nlattr)), data, len);
+  nlh->nlmsg_len += NL_ALIGN(payload_len);
+}
+
+void ipset_init(void)
+{
+  struct utsname utsname;
+  int version;
+  char *split;
+  
+  if (uname(&utsname) < 0)
+    die(_("failed to find kernel version: %s"), NULL, EC_MISC);
+  
+  split = strtok(utsname.release, ".");
+  version = (split ? atoi(split) : 0);
+  split = strtok(NULL, ".");
+  version = version * 256 + (split ? atoi(split) : 0);
+  split = strtok(NULL, ".");
+  version = version * 256 + (split ? atoi(split) : 0);
+  old_kernel = (version < KERNEL_VERSION(2,6,32));
+  
+  if (old_kernel && (ipset_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) != -1)
+    return;
+  
+  if (!old_kernel && 
+      (buffer = safe_malloc(BUFF_SZ)) &&
+      (ipset_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER)) != -1 &&
+      (bind(ipset_sock, (struct sockaddr *)&snl, sizeof(snl)) != -1))
+    return;
+  
+  die (_("failed to create IPset control socket: %s"), NULL, EC_MISC);
+}
+
+static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr, int af, int remove)
+{
+  struct nlmsghdr *nlh;
+  struct my_nfgenmsg *nfg;
+  struct my_nlattr *nested[2];
+  uint8_t proto;
+  int addrsz = INADDRSZ;
+
+#ifdef HAVE_IPV6
+  if (af == AF_INET6)
+    addrsz = IN6ADDRSZ;
+#endif
+    
+  if (strlen(setname) >= IPSET_MAXNAMELEN) 
+    {
+      errno = ENAMETOOLONG;
+      return -1;
+    }
+  
+  memset(buffer, 0, BUFF_SZ);
+
+  nlh = (struct nlmsghdr *)buffer;
+  nlh->nlmsg_len = NL_ALIGN(sizeof(struct nlmsghdr));
+  nlh->nlmsg_type = (remove ? IPSET_CMD_DEL : IPSET_CMD_ADD) | (NFNL_SUBSYS_IPSET << 8);
+  nlh->nlmsg_flags = NLM_F_REQUEST;
+  
+  nfg = (struct my_nfgenmsg *)(buffer + nlh->nlmsg_len);
+  nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nfgenmsg));
+  nfg->nfgen_family = af;
+  nfg->version = NFNETLINK_V0;
+  nfg->res_id = htons(0);
+  
+  proto = IPSET_PROTOCOL;
+  add_attr(nlh, IPSET_ATTR_PROTOCOL, sizeof(proto), &proto);
+  add_attr(nlh, IPSET_ATTR_SETNAME, strlen(setname) + 1, setname);
+  nested[0] = (struct my_nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
+  nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nlattr));
+  nested[0]->nla_type = NLA_F_NESTED | IPSET_ATTR_DATA;
+  nested[1] = (struct my_nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
+  nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nlattr));
+  nested[1]->nla_type = NLA_F_NESTED | IPSET_ATTR_IP;
+  add_attr(nlh, 
+	   (af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER,
+	   addrsz, &ipaddr->addr);
+  nested[1]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[1];
+  nested[0]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[0];
+	
+  while (retry_send(sendto(ipset_sock, buffer, nlh->nlmsg_len, 0,
+			   (struct sockaddr *)&snl, sizeof(snl))));
+								    
+  return errno == 0 ? 0 : -1;
+}
+
+
+static int old_add_to_ipset(const char *setname, const struct all_addr *ipaddr, int remove)
+{
+  socklen_t size;
+  struct ip_set_req_adt_get {
+    unsigned op;
+    unsigned version;
+    union {
+      char name[IPSET_MAXNAMELEN];
+      uint16_t index;
+    } set;
+    char typename[IPSET_MAXNAMELEN];
+  } req_adt_get;
+  struct ip_set_req_adt {
+    unsigned op;
+    uint16_t index;
+    uint32_t ip;
+  } req_adt;
+  
+  if (strlen(setname) >= sizeof(req_adt_get.set.name)) 
+    {
+      errno = ENAMETOOLONG;
+      return -1;
+    }
+  
+  req_adt_get.op = 0x10;
+  req_adt_get.version = 3;
+  strcpy(req_adt_get.set.name, setname);
+  size = sizeof(req_adt_get);
+  if (getsockopt(ipset_sock, SOL_IP, 83, &req_adt_get, &size) < 0)
+    return -1;
+  req_adt.op = remove ? 0x102 : 0x101;
+  req_adt.index = req_adt_get.set.index;
+  req_adt.ip = ntohl(ipaddr->addr.addr4.s_addr);
+  if (setsockopt(ipset_sock, SOL_IP, 83, &req_adt, sizeof(req_adt)) < 0)
+    return -1;
+  
+  return 0;
+}
+
+
+
+int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags, int remove)
+{
+  int ret = 0, af = AF_INET;
+
+#ifdef HAVE_IPV6
+  if (flags & F_IPV6)
+    {
+      af = AF_INET6;
+      /* old method only supports IPv4 */
+      if (old_kernel)
+	{
+	  errno = EAFNOSUPPORT ;
+	  ret = -1;
+	}
+    }
+#endif
+  
+  if (ret != -1) 
+    ret = old_kernel ? old_add_to_ipset(setname, ipaddr, remove) : new_add_to_ipset(setname, ipaddr, af, remove);
+
+  if (ret == -1)
+     my_syslog(LOG_ERR, _("failed to update ipset %s: %s"), setname, strerror(errno));
+
+  return ret;
+}
+
+#endif
diff --git a/src/lease.c b/src/lease.c
new file mode 100755
index 0000000..5b67075
--- /dev/null
+++ b/src/lease.c
@@ -0,0 +1,1205 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_DHCP
+
+static struct dhcp_lease *leases = NULL, *old_leases = NULL;
+static int dns_dirty, file_dirty, leases_left;
+
+static int read_leases(time_t now, FILE *leasestream)
+{
+  unsigned long ei;
+  struct all_addr addr;
+  struct dhcp_lease *lease;
+  int clid_len, hw_len, hw_type;
+  int items;
+  char *domain = NULL;
+
+  *daemon->dhcp_buff3 = *daemon->dhcp_buff2 = '\0';
+
+  /* client-id max length is 255 which is 255*2 digits + 254 colons
+     borrow DNS packet buffer which is always larger than 1000 bytes
+
+     Check various buffers are big enough for the code below */
+
+#if (DHCP_BUFF_SZ < 255) || (MAXDNAME < 64) || (PACKETSZ+MAXDNAME+RRFIXEDSZ  < 764)
+# error Buffer size breakage in leasefile parsing.
+#endif
+
+    while ((items=fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2)) == 2)
+      {
+	*daemon->namebuff = *daemon->dhcp_buff = *daemon->packet = '\0';
+	hw_len = hw_type = clid_len = 0;
+	
+#ifdef HAVE_DHCP6
+	if (strcmp(daemon->dhcp_buff3, "duid") == 0)
+	  {
+	    daemon->duid_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, 130, NULL, NULL);
+	    if (daemon->duid_len < 0)
+	      return 0;
+	    daemon->duid = safe_malloc(daemon->duid_len);
+	    memcpy(daemon->duid, daemon->dhcp_buff2, daemon->duid_len);
+	    continue;
+	  }
+#endif
+	
+	if (fscanf(leasestream, " %64s %255s %764s %*s",
+		   daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3)
+	  return 0;
+	
+	if (inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4))
+	  {
+	    if ((lease = lease4_allocate(addr.addr.addr4)))
+	      domain = get_domain(lease->addr);
+	    
+	    hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
+	    /* For backwards compatibility, no explicit MAC address type means ether. */
+	    if (hw_type == 0 && hw_len != 0)
+	      hw_type = ARPHRD_ETHER; 
+	  }
+#ifdef HAVE_DHCP6
+	else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6))
+	  {
+	    char *s = daemon->dhcp_buff2;
+	    int lease_type = LEASE_NA;
+
+	    if (s[0] == 'T')
+	      {
+		lease_type = LEASE_TA;
+		s++;
+	      }
+	    
+	    if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
+	      {
+		lease_set_iaid(lease, strtoul(s, NULL, 10));
+		domain = get_domain6((struct in6_addr *)lease->hwaddr);
+	      }
+	  }
+#endif
+	else
+	  return 0;
+
+	if (!lease)
+	  die (_("too many stored leases"), NULL, EC_MISC);
+
+	if (strcmp(daemon->packet, "*") != 0)
+	  clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
+	
+	lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, 
+			 hw_len, hw_type, clid_len, now, 0);
+	
+	if (strcmp(daemon->dhcp_buff, "*") !=  0)
+	  lease_set_hostname(lease, daemon->dhcp_buff, 0, domain, NULL);
+
+	ei = atol(daemon->dhcp_buff3);
+
+#ifdef HAVE_BROKEN_RTC
+	if (ei != 0)
+	  lease->expires = (time_t)ei + now;
+	else
+	  lease->expires = (time_t)0;
+	lease->length = ei;
+#else
+	/* strictly time_t is opaque, but this hack should work on all sane systems,
+	   even when sizeof(time_t) == 8 */
+	lease->expires = (time_t)ei;
+#endif
+	
+	/* set these correctly: the "old" events are generated later from
+	   the startup synthesised SIGHUP. */
+	lease->flags &= ~(LEASE_NEW | LEASE_CHANGED);
+	
+	*daemon->dhcp_buff3 = *daemon->dhcp_buff2 = '\0';
+      }
+    
+    return (items == 0 || items == EOF);
+}
+
+void lease_init(time_t now)
+{
+  FILE *leasestream;
+
+  leases_left = daemon->dhcp_max;
+
+  if (option_bool(OPT_LEASE_RO))
+    {
+      /* run "<lease_change_script> init" once to get the
+	 initial state of the database. If leasefile-ro is
+	 set without a script, we just do without any
+	 lease database. */
+#ifdef HAVE_SCRIPT
+      if (daemon->lease_change_command)
+	{
+	  strcpy(daemon->dhcp_buff, daemon->lease_change_command);
+	  strcat(daemon->dhcp_buff, " init");
+	  leasestream = popen(daemon->dhcp_buff, "r");
+	}
+      else
+#endif
+	{
+          file_dirty = dns_dirty = 0;
+          return;
+        }
+
+    }
+  else
+    {
+      /* NOTE: need a+ mode to create file if it doesn't exist */
+      leasestream = daemon->lease_stream = fopen(daemon->lease_file, "a+");
+
+      if (!leasestream)
+	die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE);
+
+      /* a+ mode leaves pointer at end. */
+      rewind(leasestream);
+    }
+
+  if (leasestream)
+    {
+      if (!read_leases(now, leasestream))
+	my_syslog(MS_DHCP | LOG_ERR, _("failed to parse lease database, invalid line: %s %s %s %s ..."),
+		  daemon->dhcp_buff3, daemon->dhcp_buff2,
+		  daemon->namebuff, daemon->dhcp_buff);
+
+      if (ferror(leasestream))
+	die(_("failed to read lease file %s: %s"), daemon->lease_file, EC_FILE);
+    }
+  
+#ifdef HAVE_SCRIPT
+  if (!daemon->lease_stream)
+    {
+      int rc = 0;
+
+      /* shell returns 127 for "command not found", 126 for bad permissions. */
+      if (!leasestream || (rc = pclose(leasestream)) == -1 || WEXITSTATUS(rc) == 127 || WEXITSTATUS(rc) == 126)
+	{
+	  if (WEXITSTATUS(rc) == 127)
+	    errno = ENOENT;
+	  else if (WEXITSTATUS(rc) == 126)
+	    errno = EACCES;
+
+	  die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command, EC_FILE);
+	}
+      
+      if (WEXITSTATUS(rc) != 0)
+	{
+	  sprintf(daemon->dhcp_buff, "%d", WEXITSTATUS(rc));
+	  die(_("lease-init script returned exit code %s"), daemon->dhcp_buff, WEXITSTATUS(rc) + EC_INIT_OFFSET);
+	}
+    }
+#endif
+
+  /* Some leases may have expired */
+  file_dirty = 0;
+  lease_prune(NULL, now);
+  dns_dirty = 1;
+}
+
+void lease_update_from_configs(void)
+{
+  /* changes to the config may change current leases. */
+  
+  struct dhcp_lease *lease;
+  struct dhcp_config *config;
+  char *name;
+  
+  for (lease = leases; lease; lease = lease->next)
+    if (lease->flags & (LEASE_TA | LEASE_NA))
+      continue;
+    else if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len, 
+				   lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) && 
+	     (config->flags & CONFIG_NAME) &&
+	     (!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
+      lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);
+    else if ((name = host_from_dns(lease->addr)))
+      lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */
+}
+
+static void ourprintf(int *errp, char *format, ...)
+{
+  va_list ap;
+  
+  va_start(ap, format);
+  if (!(*errp) && vfprintf(daemon->lease_stream, format, ap) < 0)
+    *errp = errno;
+  va_end(ap);
+}
+
+void lease_update_file(time_t now)
+{
+  struct dhcp_lease *lease;
+  time_t next_event;
+  int i, err = 0;
+
+  if (file_dirty != 0 && daemon->lease_stream)
+    {
+      errno = 0;
+      rewind(daemon->lease_stream);
+      if (errno != 0 || ftruncate(fileno(daemon->lease_stream), 0) != 0)
+	err = errno;
+      
+      for (lease = leases; lease; lease = lease->next)
+	{
+
+#ifdef HAVE_DHCP6
+	  if (lease->flags & (LEASE_TA | LEASE_NA))
+	    continue;
+#endif
+
+#ifdef HAVE_BROKEN_RTC
+	  ourprintf(&err, "%u ", lease->length);
+#else
+	  ourprintf(&err, "%lu ", (unsigned long)lease->expires);
+#endif
+
+	  if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0) 
+	    ourprintf(&err, "%.2x-", lease->hwaddr_type);
+	  for (i = 0; i < lease->hwaddr_len; i++)
+	    {
+	      ourprintf(&err, "%.2x", lease->hwaddr[i]);
+	      if (i != lease->hwaddr_len - 1)
+		ourprintf(&err, ":");
+	    }
+	  
+	  inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN); 
+
+	  ourprintf(&err, " %s ", daemon->addrbuff);
+	  ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
+	  	  
+	  if (lease->clid && lease->clid_len != 0)
+	    {
+	      for (i = 0; i < lease->clid_len - 1; i++)
+		ourprintf(&err, "%.2x:", lease->clid[i]);
+	      ourprintf(&err, "%.2x ", lease->clid[i]);
+	    }
+	  else
+	    ourprintf(&err, "* ");
+
+	  {
+	    unsigned char *p;
+	    if (lease->req_options[0] == OPTION_END)
+	      ourprintf(&err, "*");
+	    else
+	    {
+	      for (p = lease->req_options; *p != OPTION_END; p++)
+	      {
+		if (p != lease->req_options) ourprintf(&err, ",");
+		ourprintf(&err, "%u", *p);
+	      }
+	    }
+	    ourprintf(&err, "\n");
+	  }
+	}
+      
+#ifdef HAVE_DHCP6  
+      if (daemon->duid)
+	{
+	  ourprintf(&err, "duid ");
+	  for (i = 0; i < daemon->duid_len - 1; i++)
+	    ourprintf(&err, "%.2x:", daemon->duid[i]);
+	  ourprintf(&err, "%.2x\n", daemon->duid[i]);
+	  
+	  for (lease = leases; lease; lease = lease->next)
+	    {
+	      
+	      if (!(lease->flags & (LEASE_TA | LEASE_NA)))
+		continue;
+
+#ifdef HAVE_BROKEN_RTC
+	      ourprintf(&err, "%u ", lease->length);
+#else
+	      ourprintf(&err, "%lu ", (unsigned long)lease->expires);
+#endif
+    
+	      inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN);
+	 
+	      ourprintf(&err, "%s%u %s ", (lease->flags & LEASE_TA) ? "T" : "",
+			lease->iaid, daemon->addrbuff);
+	      ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
+	      
+	      if (lease->clid && lease->clid_len != 0)
+		{
+		  for (i = 0; i < lease->clid_len - 1; i++)
+		    ourprintf(&err, "%.2x:", lease->clid[i]);
+		  ourprintf(&err, "%.2x\n", lease->clid[i]);
+		}
+	      else
+		ourprintf(&err, "*\n");	  
+	    }
+	}
+#endif      
+	  
+      if (fflush(daemon->lease_stream) != 0 ||
+	  fsync(fileno(daemon->lease_stream)) < 0)
+	err = errno;
+      
+      if (!err)
+	file_dirty = 0;
+    }
+  
+  /* Set alarm for when the first lease expires. */
+  next_event = 0;
+
+#ifdef HAVE_DHCP6
+  /* do timed RAs and determine when the next is, also pings to potential SLAAC addresses */
+  if (daemon->doing_ra)
+    {
+      time_t event;
+      
+      if ((event = periodic_slaac(now, leases)) != 0)
+	{
+	  if (next_event == 0 || difftime(next_event, event) > 0.0)
+	    next_event = event;
+	}
+      
+      if ((event = periodic_ra(now)) != 0)
+	{
+	  if (next_event == 0 || difftime(next_event, event) > 0.0)
+	    next_event = event;
+	}
+    }
+#endif
+
+  for (lease = leases; lease; lease = lease->next)
+    if (lease->expires != 0 &&
+	(next_event == 0 || difftime(next_event, lease->expires) > 0.0))
+      next_event = lease->expires;
+   
+  if (err)
+    {
+      if (next_event == 0 || difftime(next_event, LEASE_RETRY + now) > 0.0)
+	next_event = LEASE_RETRY + now;
+      
+      my_syslog(MS_DHCP | LOG_ERR, _("failed to write %s: %s (retry in %us)"), 
+		daemon->lease_file, strerror(err),
+		(unsigned int)difftime(next_event, now));
+    }
+
+  send_alarm(next_event, now);
+}
+
+
+static int find_interface_v4(struct in_addr local, int if_index, char *label,
+			     struct in_addr netmask, struct in_addr broadcast, void *vparam)
+{
+  struct dhcp_lease *lease;
+  int prefix = netmask_length(netmask);
+
+  (void) label;
+  (void) broadcast;
+  (void) vparam;
+
+  for (lease = leases; lease; lease = lease->next)
+    if (!(lease->flags & (LEASE_TA | LEASE_NA)) &&
+	is_same_net(local, lease->addr, netmask) && 
+	prefix > lease->new_prefixlen) 
+      {
+	lease->new_interface = if_index;
+        lease->new_prefixlen = prefix;
+      }
+
+  return 1;
+}
+
+#ifdef HAVE_DHCP6
+static int find_interface_v6(struct in6_addr *local,  int prefix,
+			     int scope, int if_index, int flags, 
+			     int preferred, int valid, void *vparam)
+{
+  struct dhcp_lease *lease;
+
+  (void)scope;
+  (void)flags;
+  (void)preferred;
+  (void)valid;
+  (void)vparam;
+
+  for (lease = leases; lease; lease = lease->next)
+    if ((lease->flags & (LEASE_TA | LEASE_NA)))
+      if (is_same_net6(local, &lease->addr6, prefix) && prefix > lease->new_prefixlen) {
+        /* save prefix length for comparison, as we might get shorter matching
+         * prefix in upcoming netlink GETADDR responses
+         * */
+        lease->new_interface = if_index;
+        lease->new_prefixlen = prefix;
+      }
+
+  return 1;
+}
+
+void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface)
+{
+  /* We may be doing RA but not DHCPv4, in which case the lease
+     database may not exist and we have nothing to do anyway */
+  if (daemon->dhcp)
+    slaac_ping_reply(sender, packet, interface, leases);
+}
+
+void lease_update_slaac(time_t now)
+{
+  /* Called when we construct a new RA-names context, to add putative
+     new SLAAC addresses to existing leases. */
+
+  struct dhcp_lease *lease;
+  
+  if (daemon->dhcp)
+    for (lease = leases; lease; lease = lease->next)
+      slaac_add_addrs(lease, now, 0);
+}
+
+#endif
+
+
+/* Find interfaces associated with leases at start-up. This gets updated as
+   we do DHCP transactions, but information about directly-connected subnets
+   is useful from scrips and necessary for determining SLAAC addresses from
+   start-time. */
+void lease_find_interfaces(time_t now)
+{
+  struct dhcp_lease *lease;
+  
+  for (lease = leases; lease; lease = lease->next)
+    lease->new_prefixlen = lease->new_interface = 0;
+
+  iface_enumerate(AF_INET, &now, find_interface_v4);
+#ifdef HAVE_DHCP6
+  iface_enumerate(AF_INET6, &now, find_interface_v6);
+#endif
+
+  for (lease = leases; lease; lease = lease->next)
+    if (lease->new_interface != 0) 
+      lease_set_interface(lease, lease->new_interface, now);
+}
+
+#ifdef HAVE_DHCP6
+void lease_make_duid(time_t now)
+{
+  /* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
+  if (!daemon->duid && daemon->doing_dhcp6)
+    {
+      file_dirty = 1;
+      make_duid(now);
+    }
+}
+#endif
+
+
+
+
+void lease_update_dns(int force)
+{
+  struct dhcp_lease *lease;
+
+  if (daemon->port != 0 && (dns_dirty || force))
+    {
+#ifndef HAVE_BROKEN_RTC
+      /* force transfer to authoritative secondaries */
+      daemon->soa_sn++;
+#endif
+      
+      cache_unhash_dhcp();
+
+      for (lease = leases; lease; lease = lease->next)
+	{
+	  int prot = AF_INET;
+	  
+#ifdef HAVE_DHCP6
+	  if (lease->flags & (LEASE_TA | LEASE_NA))
+	    prot = AF_INET6;
+	  else if (lease->hostname || lease->fqdn)
+	    {
+	      struct slaac_address *slaac;
+
+	      for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
+		if (slaac->backoff == 0)
+		  {
+		    if (lease->fqdn)
+		      cache_add_dhcp_entry(lease->fqdn, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
+		    if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
+		      cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
+		  }
+	    }
+	  
+	  if (lease->fqdn)
+	    cache_add_dhcp_entry(lease->fqdn, prot, 
+				 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,
+				 lease->expires);
+	     
+	  if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
+	    cache_add_dhcp_entry(lease->hostname, prot, 
+				 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6, 
+				 lease->expires);
+       
+#else
+	  if (lease->fqdn)
+	    cache_add_dhcp_entry(lease->fqdn, prot, (struct all_addr *)&lease->addr, lease->expires);
+	  
+	  if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
+	    cache_add_dhcp_entry(lease->hostname, prot, (struct all_addr *)&lease->addr, lease->expires);
+#endif
+	}
+      
+      dns_dirty = 0;
+    }
+}
+
+void lease_prune(struct dhcp_lease *target, time_t now)
+{
+  struct dhcp_lease *lease, *tmp, **up;
+
+  for (lease = leases, up = &leases; lease; lease = tmp)
+    {
+      tmp = lease->next;
+      if ((lease->expires != 0 && difftime(now, lease->expires) > 0) || lease == target)
+	{
+	  file_dirty = 1;
+	  if (lease->hostname)
+	    dns_dirty = 1;
+	  
+ 	  *up = lease->next; /* unlink */
+	  
+	  /* Put on old_leases list 'till we
+	     can run the script */
+	  lease->next = old_leases;
+	  old_leases = lease;
+	  
+	  leases_left++;
+	}
+      else
+	up = &lease->next;
+    }
+} 
+	
+  
+struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
+					unsigned char *clid, int clid_len)
+{
+  struct dhcp_lease *lease;
+
+  if (clid)
+    for (lease = leases; lease; lease = lease->next)
+      {
+#ifdef HAVE_DHCP6
+	if (lease->flags & (LEASE_TA | LEASE_NA))
+	  continue;
+#endif
+	if (lease->clid && clid_len == lease->clid_len &&
+	    memcmp(clid, lease->clid, clid_len) == 0)
+	  return lease;
+      }
+  
+  for (lease = leases; lease; lease = lease->next)	
+    {
+#ifdef HAVE_DHCP6
+      if (lease->flags & (LEASE_TA | LEASE_NA))
+	continue;
+#endif   
+      if ((!lease->clid || !clid) && 
+	  hw_len != 0 && 
+	  lease->hwaddr_len == hw_len &&
+	  lease->hwaddr_type == hw_type &&
+	  memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
+	return lease;
+    }
+
+  return NULL;
+}
+
+struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
+{
+  struct dhcp_lease *lease;
+
+  for (lease = leases; lease; lease = lease->next)
+    {
+#ifdef HAVE_DHCP6
+      if (lease->flags & (LEASE_TA | LEASE_NA))
+	continue;
+#endif  
+      if (lease->addr.s_addr == addr.s_addr)
+	return lease;
+    }
+
+  return NULL;
+}
+
+#ifdef HAVE_DHCP6
+/* find address for {CLID, IAID, address} */
+struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len, 
+			       int lease_type, int iaid, struct in6_addr *addr)
+{
+  struct dhcp_lease *lease;
+  
+  for (lease = leases; lease; lease = lease->next)
+    {
+      if (!(lease->flags & lease_type) || lease->iaid != iaid)
+	continue;
+
+      if (!IN6_ARE_ADDR_EQUAL(&lease->addr6, addr))
+	continue;
+      
+      if ((clid_len != lease->clid_len ||
+	   memcmp(clid, lease->clid, clid_len) != 0))
+	continue;
+      
+      return lease;
+    }
+  
+  return NULL;
+}
+
+/* reset "USED flags */
+void lease6_reset(void)
+{
+  struct dhcp_lease *lease;
+  
+  for (lease = leases; lease; lease = lease->next)
+    lease->flags &= ~LEASE_USED;
+}
+
+/* enumerate all leases belonging to {CLID, IAID} */
+struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid)
+{
+  struct dhcp_lease *lease;
+
+  if (!first)
+    first = leases;
+  else
+    first = first->next;
+
+  for (lease = first; lease; lease = lease->next)
+    {
+      if (lease->flags & LEASE_USED)
+	continue;
+
+      if (!(lease->flags & lease_type) || lease->iaid != iaid)
+	continue;
+ 
+      if ((clid_len != lease->clid_len ||
+	   memcmp(clid, lease->clid, clid_len) != 0))
+	continue;
+
+      return lease;
+    }
+  
+  return NULL;
+}
+
+struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)
+{
+  struct dhcp_lease *lease;
+    
+  for (lease = leases; lease; lease = lease->next)
+    {
+      if (!(lease->flags & (LEASE_TA | LEASE_NA)))
+	continue;
+      
+      if (is_same_net6(&lease->addr6, net, prefix) &&
+	  (prefix == 128 || addr6part(&lease->addr6) == addr))
+	return lease;
+    }
+  
+  return NULL;
+} 
+
+/* Find largest assigned address in context */
+u64 lease_find_max_addr6(struct dhcp_context *context)
+{
+  struct dhcp_lease *lease;
+  u64 addr = addr6part(&context->start6);
+  
+  if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
+    for (lease = leases; lease; lease = lease->next)
+      {
+	if (!(lease->flags & (LEASE_TA | LEASE_NA)))
+	  continue;
+
+	if (is_same_net6(&lease->addr6, &context->start6, 64) &&
+	    addr6part(&lease->addr6) > addr6part(&context->start6) &&
+	    addr6part(&lease->addr6) <= addr6part(&context->end6) &&
+	    addr6part(&lease->addr6) > addr)
+	  addr = addr6part(&lease->addr6);
+      }
+  
+  return addr;
+}
+
+#endif
+
+/* Find largest assigned address in context */
+struct in_addr lease_find_max_addr(struct dhcp_context *context)
+{
+  struct dhcp_lease *lease;
+  struct in_addr addr = context->start;
+  
+  if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
+    for (lease = leases; lease; lease = lease->next)
+      {
+#ifdef HAVE_DHCP6
+	if (lease->flags & (LEASE_TA | LEASE_NA))
+	  continue;
+#endif
+	if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
+	    ((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) &&
+	    ((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr)))
+	  addr = lease->addr;
+      }
+  
+  return addr;
+}
+
+static struct dhcp_lease *lease_allocate(void)
+{
+  struct dhcp_lease *lease;
+  if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
+    return NULL;
+
+  memset(lease, 0, sizeof(struct dhcp_lease));
+  lease->flags = LEASE_NEW;
+  lease->expires = 1;
+#ifdef HAVE_BROKEN_RTC
+  lease->length = 0xffffffff; /* illegal value */
+#endif
+  lease->hwaddr_len = 256; /* illegal value */
+  lease->req_options[0] = OPTION_END;
+  lease->next = leases;
+  leases = lease;
+  
+  file_dirty = 1;
+  leases_left--;
+
+  return lease;
+}
+
+struct dhcp_lease *lease4_allocate(struct in_addr addr)
+{
+  struct dhcp_lease *lease = lease_allocate();
+  if (lease)
+    lease->addr = addr;
+  
+  return lease;
+}
+
+#ifdef HAVE_DHCP6
+struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
+{
+  struct dhcp_lease *lease = lease_allocate();
+
+  if (lease)
+    {
+      lease->addr6 = *addrp;
+      lease->flags |= lease_type;
+      lease->iaid = 0;
+    }
+
+  return lease;
+}
+#endif
+
+void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
+{
+  time_t exp;
+
+  if (len == 0xffffffff)
+    {
+      exp = 0;
+      len = 0;
+    }
+  else
+    {
+      exp = now + (time_t)len;
+      /* Check for 2038 overflow. Make the lease
+	 infinite in that case, as the least disruptive
+	 thing we can do. */
+      if (difftime(exp, now) <= 0.0)
+	exp = 0;
+    }
+
+  if (exp != lease->expires)
+    {
+      dns_dirty = 1;
+      lease->expires = exp;
+#ifndef HAVE_BROKEN_RTC
+      lease->flags |= LEASE_AUX_CHANGED;
+      file_dirty = 1;
+#endif
+    }
+  
+#ifdef HAVE_BROKEN_RTC
+  if (len != lease->length)
+    {
+      lease->length = len;
+      lease->flags |= LEASE_AUX_CHANGED;
+      file_dirty = 1; 
+    }
+#endif
+} 
+
+#ifdef HAVE_DHCP6
+void lease_set_iaid(struct dhcp_lease *lease, int iaid)
+{
+  if (lease->iaid != iaid)
+    {
+      lease->iaid = iaid;
+      lease->flags |= LEASE_CHANGED;
+    }
+}
+#endif
+
+void lease_set_hwaddr(struct dhcp_lease *lease, const unsigned char *hwaddr,
+		      const unsigned char *clid, int hw_len, int hw_type,
+		      int clid_len, time_t now, int force)
+{
+#ifdef HAVE_DHCP6
+  int change = force;
+  lease->flags |= LEASE_HAVE_HWADDR;
+#endif
+
+  (void)force;
+  (void)now;
+
+  if (hw_len != lease->hwaddr_len ||
+      hw_type != lease->hwaddr_type || 
+      (hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
+    {
+      if (hw_len != 0)
+	memcpy(lease->hwaddr, hwaddr, hw_len);
+      lease->hwaddr_len = hw_len;
+      lease->hwaddr_type = hw_type;
+      lease->flags |= LEASE_CHANGED;
+      file_dirty = 1; /* run script on change */
+    }
+
+  /* only update clid when one is available, stops packets
+     without a clid removing the record. Lease init uses
+     clid_len == 0 for no clid. */
+  if (clid_len != 0 && clid)
+    {
+      if (!lease->clid)
+	lease->clid_len = 0;
+
+      if (lease->clid_len != clid_len)
+	{
+	  lease->flags |= LEASE_AUX_CHANGED;
+	  file_dirty = 1;
+	  free(lease->clid);
+	  if (!(lease->clid = whine_malloc(clid_len)))
+	    return;
+#ifdef HAVE_DHCP6
+	  change = 1;
+#endif	   
+	}
+      else if (memcmp(lease->clid, clid, clid_len) != 0)
+	{
+	  lease->flags |= LEASE_AUX_CHANGED;
+	  file_dirty = 1;
+#ifdef HAVE_DHCP6
+	  change = 1;
+#endif	
+	}
+      
+      lease->clid_len = clid_len;
+      memcpy(lease->clid, clid, clid_len);
+    }
+  
+#ifdef HAVE_DHCP6
+  if (change)
+    slaac_add_addrs(lease, now, force);
+#endif
+}
+
+static void kill_name(struct dhcp_lease *lease)
+{
+  /* run script to say we lost our old name */
+  
+  /* this shouldn't happen unless updates are very quick and the
+     script very slow, we just avoid a memory leak if it does. */
+  free(lease->old_hostname);
+  
+  /* If we know the fqdn, pass that. The helper will derive the
+     unqualified name from it, free the unqualified name here. */
+
+  if (lease->fqdn)
+    {
+      lease->old_hostname = lease->fqdn;
+      free(lease->hostname);
+    }
+  else
+    lease->old_hostname = lease->hostname;
+
+  lease->hostname = lease->fqdn = NULL;
+}
+
+void lease_set_hostname(struct dhcp_lease *lease, const char *name, int auth, char *domain, char *config_domain)
+{
+  struct dhcp_lease *lease_tmp;
+  char *new_name = NULL, *new_fqdn = NULL;
+
+  if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
+    my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, name);
+  
+  if (lease->hostname && name && hostname_isequal(lease->hostname, name))
+    {
+      if (auth)
+	lease->flags |= LEASE_AUTH_NAME;
+      return;
+    }
+  
+  if (!name && !lease->hostname)
+    return;
+
+  /* If a machine turns up on a new net without dropping the old lease,
+     or two machines claim the same name, then we end up with two interfaces with
+     the same name. Check for that here and remove the name from the old lease.
+     Note that IPv6 leases are different. All the leases to the same DUID are 
+     allowed the same name.
+
+     Don't allow a name from the client to override a name from dnsmasq config. */
+  
+  if (name)
+    {
+      if ((new_name = whine_malloc(strlen(name) + 1)))
+	{
+	  strcpy(new_name, name);
+	  if (domain && (new_fqdn = whine_malloc(strlen(new_name) + strlen(domain) + 2)))
+	    {
+	      strcpy(new_fqdn, name);
+	      strcat(new_fqdn, ".");
+	      strcat(new_fqdn, domain);
+	    }
+	}
+	  
+      /* Depending on mode, we check either unqualified name or FQDN. */
+      for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
+	{
+	  if (option_bool(OPT_DHCP_FQDN))
+	    {
+	      if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn))
+		continue;
+	    }
+	  else
+	    {
+	      if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
+		continue; 
+	    }
+
+	  if (lease->flags & (LEASE_TA | LEASE_NA))
+	    {
+	      if (!(lease_tmp->flags & (LEASE_TA | LEASE_NA)))
+		continue;
+
+	      /* another lease for the same DUID is OK for IPv6 */
+	      if (lease->clid_len == lease_tmp->clid_len &&
+		  lease->clid && lease_tmp->clid &&
+		  memcmp(lease->clid, lease_tmp->clid, lease->clid_len) == 0)
+		continue;	      
+	    }
+	  else if (lease_tmp->flags & (LEASE_TA | LEASE_NA))
+	    continue;
+		   
+	  if ((lease_tmp->flags & LEASE_AUTH_NAME) && !auth)
+	    {
+	      free(new_name);
+	      free(new_fqdn);
+	      return;
+	    }
+	
+	  kill_name(lease_tmp);
+	  break;
+	}
+    }
+
+  if (lease->hostname)
+    kill_name(lease);
+
+  lease->hostname = new_name;
+  lease->fqdn = new_fqdn;
+  
+  if (auth)
+    lease->flags |= LEASE_AUTH_NAME;
+  
+  file_dirty = 1;
+  dns_dirty = 1; 
+  lease->flags |= LEASE_CHANGED; /* run script on change */
+}
+
+void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
+{
+  (void)now;
+
+  if (lease->last_interface == interface)
+    return;
+
+  lease->last_interface = interface;
+  lease->flags |= LEASE_CHANGED; 
+
+#ifdef HAVE_DHCP6
+  slaac_add_addrs(lease, now, 0);
+#endif
+}
+
+void rerun_scripts(void)
+{
+  struct dhcp_lease *lease;
+  
+  for (lease = leases; lease; lease = lease->next)
+    lease->flags |= LEASE_CHANGED; 
+}
+
+/* deleted leases get transferred to the old_leases list.
+   remove them here, after calling the lease change
+   script. Also run the lease change script on new/modified leases.
+
+   Return zero if nothing to do. */
+int do_script_run(time_t now)
+{
+  struct dhcp_lease *lease;
+
+  (void)now;
+
+#ifdef HAVE_DBUS
+  /* If we're going to be sending DBus signals, but the connection is not yet up,
+     delay everything until it is. */
+  if (option_bool(OPT_DBUS) && !daemon->dbus)
+    return 0;
+#endif
+
+  if (old_leases)
+    {
+      lease = old_leases;
+                  
+      /* If the lease still has an old_hostname, do the "old" action on that first */
+      if (lease->old_hostname)
+	{
+#ifdef HAVE_SCRIPT
+	  queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
+#endif
+	  free(lease->old_hostname);
+	  lease->old_hostname = NULL;
+	  return 1;
+	}
+      else 
+	{
+#ifdef HAVE_DHCP6
+	  struct slaac_address *slaac, *tmp;
+	  for (slaac = lease->slaac_address; slaac; slaac = tmp)
+	    {
+	      tmp = slaac->next;
+	      free(slaac);
+	    }
+#endif
+	  kill_name(lease);
+#ifdef HAVE_SCRIPT
+	  queue_script(ACTION_DEL, lease, lease->old_hostname, now);
+#endif
+#ifdef HAVE_DBUS
+	  emit_dbus_signal(ACTION_DEL, lease, lease->old_hostname);
+#endif
+	  old_leases = lease->next;
+	  
+	  free(lease->old_hostname); 
+	  free(lease->clid);
+	  free(lease->extradata);
+	  free(lease);
+	    
+	  return 1; 
+	}
+    }
+  
+  /* make sure we announce the loss of a hostname before its new location. */
+  for (lease = leases; lease; lease = lease->next)
+    if (lease->old_hostname)
+      {	
+#ifdef HAVE_SCRIPT
+	queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
+#endif
+	free(lease->old_hostname);
+	lease->old_hostname = NULL;
+	return 1;
+      }
+  
+  for (lease = leases; lease; lease = lease->next)
+    if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) || 
+	((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)))
+      {
+#ifdef HAVE_SCRIPT
+	queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease, 
+		     lease->fqdn ? lease->fqdn : lease->hostname, now);
+#endif
+#ifdef HAVE_DBUS
+	emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
+			 lease->fqdn ? lease->fqdn : lease->hostname);
+#endif
+	lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED);
+	
+	/* this is used for the "add" call, then junked, since they're not in the database */
+	free(lease->extradata);
+	lease->extradata = NULL;
+	
+	return 1;
+      }
+
+  return 0; /* nothing to do */
+}
+
+#ifdef HAVE_SCRIPT
+/* delim == -1 -> delim = 0, but embedded 0s, creating extra records, are OK. */
+void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)
+{
+  unsigned int i;
+  
+  if (delim == -1)
+    delim = 0;
+  else
+    /* check for embedded NULLs */
+    for (i = 0; i < len; i++)
+      if (data[i] == 0)
+	{
+	  len = i;
+	  break;
+	}
+  
+  if ((lease->extradata_size - lease->extradata_len) < (len + 1))
+    {
+      size_t newsz = lease->extradata_len + len + 100;
+      unsigned char *new = whine_malloc(newsz);
+  
+      if (!new)
+	return;
+      
+      if (lease->extradata)
+	{
+	  memcpy(new, lease->extradata, lease->extradata_len);
+	  free(lease->extradata);
+	}
+
+      lease->extradata = new;
+      lease->extradata_size = newsz;
+    }
+
+  if (len != 0)
+    memcpy(lease->extradata + lease->extradata_len, data, len);
+  lease->extradata[lease->extradata_len + len] = delim;
+  lease->extradata_len += len + 1; 
+}
+#endif
+
+#endif
+	  
+
+      
+
diff --git a/src/log.c b/src/log.c
new file mode 100755
index 0000000..993d064
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,485 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#ifdef __ANDROID__
+#ifdef EUREKA
+#include <cutils/log.h>
+#else
+#include <android/log.h>
+#endif
+#endif
+
+/* Implement logging to /dev/log asynchronously. If syslogd is 
+   making DNS lookups through dnsmasq, and dnsmasq blocks awaiting
+   syslogd, then the two daemons can deadlock. We get around this
+   by not blocking when talking to syslog, instead we queue up to 
+   MAX_LOGS messages. If more are queued, they will be dropped,
+   and the drop event itself logged. */
+
+/* The "wire" protocol for logging is defined in RFC 3164 */
+
+/* From RFC 3164 */
+#define MAX_MESSAGE 1024
+
+/* defaults in case we die() before we log_start() */
+static int log_fac = LOG_DAEMON;
+static int log_stderr = 0;
+static int echo_stderr = 0;
+static int log_fd = -1;
+static int log_to_file = 0;
+static int entries_alloced = 0;
+static int entries_lost = 0;
+static int connection_good = 1;
+static int max_logs = 0;
+static int connection_type = SOCK_DGRAM;
+
+struct log_entry {
+  int offset, length;
+  pid_t pid; /* to avoid duplicates over a fork */
+  struct log_entry *next;
+  char payload[MAX_MESSAGE];
+};
+
+static struct log_entry *entries = NULL;
+static struct log_entry *free_entries = NULL;
+
+
+int log_start(struct passwd *ent_pw, int errfd)
+{
+  int ret = 0;
+
+  echo_stderr = option_bool(OPT_DEBUG);
+
+  if (daemon->log_fac != -1)
+    log_fac = daemon->log_fac;
+#ifdef LOG_LOCAL0
+  else if (option_bool(OPT_DEBUG))
+    log_fac = LOG_LOCAL0;
+#endif
+
+  if (daemon->log_file)
+    { 
+      log_to_file = 1;
+      daemon->max_logs = 0;
+      if (strcmp(daemon->log_file, "-") == 0)
+	{
+	  log_stderr = 1;
+	  echo_stderr = 0;
+	  log_fd = dup(STDERR_FILENO);
+	}
+    }
+  
+  max_logs = daemon->max_logs;
+
+  if (!log_reopen(daemon->log_file))
+    {
+      send_event(errfd, EVENT_LOG_ERR, errno, daemon->log_file ? daemon->log_file : "");
+      _exit(0);
+    }
+
+  /* if queuing is inhibited, make sure we allocate
+     the one required buffer now. */
+  if (max_logs == 0)
+    {  
+      free_entries = safe_malloc(sizeof(struct log_entry));
+      free_entries->next = NULL;
+      entries_alloced = 1;
+    }
+
+  /* If we're running as root and going to change uid later,
+     change the ownership here so that the file is always owned by
+     the dnsmasq user. Then logrotate can just copy the owner.
+     Failure of the chown call is OK, (for instance when started as non-root) */
+  if (log_to_file && !log_stderr && ent_pw && ent_pw->pw_uid != 0 && 
+      fchown(log_fd, ent_pw->pw_uid, -1) != 0)
+    ret = errno;
+
+  return ret;
+}
+
+int log_reopen(char *log_file)
+{
+  if (!log_stderr)
+    {      
+      if (log_fd != -1)
+	close(log_fd);
+      
+      /* NOTE: umask is set to 022 by the time this gets called */
+      
+      if (log_file)
+	log_fd = open(log_file, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);      
+      else
+	{
+#if defined(HAVE_SOLARIS_NETWORK) || defined(__ANDROID__)
+	  /* Solaris logging is "different", /dev/log is not unix-domain socket.
+	     Just leave log_fd == -1 and use the vsyslog call for everything.... */
+#ifndef _PATH_LOG
+#   define _PATH_LOG ""  /* dummy */
+#endif
+	  return 1;
+#else
+	  int flags;
+	  log_fd = socket(AF_UNIX, connection_type, 0);
+	  
+	  /* if max_logs is zero, leave the socket blocking */
+	  if (log_fd != -1 && max_logs != 0 && (flags = fcntl(log_fd, F_GETFL)) != -1)
+	    fcntl(log_fd, F_SETFL, flags | O_NONBLOCK);
+#endif
+	}
+    }
+  
+  return log_fd != -1;
+}
+
+static void free_entry(void)
+{
+  struct log_entry *tmp = entries;
+  entries = tmp->next;
+  tmp->next = free_entries;
+  free_entries = tmp;
+}      
+
+static void log_write(void)
+{
+  ssize_t rc;
+   
+  while (entries)
+    {
+      /* The data in the payload is written with a terminating zero character 
+	 and the length reflects this. For a stream connection we need to 
+	 send the zero as a record terminator, but this isn't done for a 
+	 datagram connection, so treat the length as one less than reality 
+	 to elide the zero. If we're logging to a file, turn the zero into 
+	 a newline, and leave the length alone. */
+      int len_adjust = 0;
+
+      if (log_to_file)
+	entries->payload[entries->offset + entries->length - 1] = '\n';
+      else if (connection_type == SOCK_DGRAM)
+	len_adjust = 1;
+
+      /* Avoid duplicates over a fork() */
+      if (entries->pid != getpid())
+	{
+	  free_entry();
+	  continue;
+	}
+
+      connection_good = 1;
+
+      if ((rc = write(log_fd, entries->payload + entries->offset, entries->length - len_adjust)) != -1)
+	{
+	  entries->length -= rc;
+	  entries->offset += rc;
+	  if (entries->length == len_adjust)
+	    {
+	      free_entry();
+	      if (entries_lost != 0)
+		{
+		  int e = entries_lost;
+		  entries_lost = 0; /* avoid wild recursion */
+		  my_syslog(LOG_WARNING, _("overflow: %d log entries lost"), e);
+		}	  
+	    }
+	  continue;
+	}
+      
+      if (errno == EINTR)
+	continue;
+
+      if (errno == EAGAIN || errno == EWOULDBLOCK)
+	return; /* syslogd busy, go again when select() or poll() says so */
+      
+      if (errno == ENOBUFS)
+	{
+	  connection_good = 0;
+	  return;
+	}
+
+      /* errors handling after this assumes sockets */ 
+      if (!log_to_file)
+	{
+	  /* Once a stream socket hits EPIPE, we have to close and re-open
+	     (we ignore SIGPIPE) */
+	  if (errno == EPIPE)
+	    {
+	      if (log_reopen(NULL))
+		continue;
+	    }
+	  else if (errno == ECONNREFUSED || 
+		   errno == ENOTCONN || 
+		   errno == EDESTADDRREQ || 
+		   errno == ECONNRESET)
+	    {
+	      /* socket went (syslogd down?), try and reconnect. If we fail,
+		 stop trying until the next call to my_syslog() 
+		 ECONNREFUSED -> connection went down
+		 ENOTCONN -> nobody listening
+		 (ECONNRESET, EDESTADDRREQ are *BSD equivalents) */
+	      
+	      struct sockaddr_un logaddr;
+	      
+#ifdef HAVE_SOCKADDR_SA_LEN
+	      logaddr.sun_len = sizeof(logaddr) - sizeof(logaddr.sun_path) + strlen(_PATH_LOG) + 1; 
+#endif
+	      logaddr.sun_family = AF_UNIX;
+	      strncpy(logaddr.sun_path, _PATH_LOG, sizeof(logaddr.sun_path));
+	      
+	      /* Got connection back? try again. */
+	      if (connect(log_fd, (struct sockaddr *)&logaddr, sizeof(logaddr)) != -1)
+		continue;
+	      
+	      /* errors from connect which mean we should keep trying */
+	      if (errno == ENOENT || 
+		  errno == EALREADY || 
+		  errno == ECONNREFUSED ||
+		  errno == EISCONN || 
+		  errno == EINTR ||
+		  errno == EAGAIN || 
+		  errno == EWOULDBLOCK)
+		{
+		  /* try again on next syslog() call */
+		  connection_good = 0;
+		  return;
+		}
+	      
+	      /* try the other sort of socket... */
+	      if (errno == EPROTOTYPE)
+		{
+		  connection_type = connection_type == SOCK_DGRAM ? SOCK_STREAM : SOCK_DGRAM;
+		  if (log_reopen(NULL))
+		    continue;
+		}
+	    }
+	}
+
+      /* give up - fall back to syslog() - this handles out-of-space
+	 when logging to a file, for instance. */
+      log_fd = -1;
+      my_syslog(LOG_CRIT, _("log failed: %s"), strerror(errno));
+      return;
+    }
+}
+
+/* priority is one of LOG_DEBUG, LOG_INFO, LOG_NOTICE, etc. See sys/syslog.h.
+   OR'd to priority can be MS_TFTP, MS_DHCP, ... to be able to do log separation between
+   DNS, DHCP and TFTP services.
+*/
+void my_syslog(int priority, const char *format, ...)
+{
+  va_list ap;
+  struct log_entry *entry;
+  time_t time_now;
+  char *p;
+  size_t len;
+  pid_t pid = getpid();
+  char *func = "";
+
+  if ((LOG_FACMASK & priority) == MS_TFTP)
+    func = "-tftp";
+  else if ((LOG_FACMASK & priority) == MS_DHCP)
+    func = "-dhcp";
+  else if ((LOG_FACMASK & priority) == MS_SCRIPT)
+    func = "-script";
+	    
+#ifdef LOG_PRI
+  priority = LOG_PRI(priority);
+#else
+  /* Solaris doesn't have LOG_PRI */
+  priority &= LOG_PRIMASK;
+#endif
+
+  if (echo_stderr) 
+    {
+      fprintf(stderr, "dnsmasq%s: ", func);
+      va_start(ap, format);
+      vfprintf(stderr, format, ap);
+      va_end(ap);
+      fputc('\n', stderr);
+    }
+
+  if (log_fd == -1)
+    {
+#ifdef __ANDROID__
+      /* do android-specific logging. 
+	 log_fd is always -1 on Android except when logging to a file. */
+      int alog_lvl;
+      
+      if (priority <= LOG_ERR)
+	alog_lvl = ANDROID_LOG_ERROR;
+      else if (priority == LOG_WARNING)
+	alog_lvl = ANDROID_LOG_WARN;
+      else if (priority <= LOG_INFO)
+	alog_lvl = ANDROID_LOG_INFO;
+      else
+	alog_lvl = ANDROID_LOG_DEBUG;
+
+      va_start(ap, format);
+#ifdef EUREKA
+      __android_log_buf_vprint(LOG_ID_SYSTEM, alog_lvl, "dnsmasq", format, ap);
+#else
+      __android_log_vprint(alog_lvl, "dnsmasq", format, ap);
+#endif
+      va_end(ap);
+#else
+      /* fall-back to syslog if we die during startup or 
+	 fail during running (always on Solaris). */
+      static int isopen = 0;
+
+      if (!isopen)
+	{
+	  openlog("dnsmasq", LOG_PID, log_fac);
+	  isopen = 1;
+	}
+      va_start(ap, format);  
+      vsyslog(priority, format, ap);
+      va_end(ap);
+#endif
+
+      return;
+    }
+  
+  if ((entry = free_entries))
+    free_entries = entry->next;
+  else if (entries_alloced < max_logs && (entry = malloc(sizeof(struct log_entry))))
+    entries_alloced++;
+  
+  if (!entry)
+    entries_lost++;
+  else
+    {
+      /* add to end of list, consumed from the start */
+      entry->next = NULL;
+      if (!entries)
+	entries = entry;
+      else
+	{
+	  struct log_entry *tmp;
+	  for (tmp = entries; tmp->next; tmp = tmp->next);
+	  tmp->next = entry;
+	}
+      
+      time(&time_now);
+      p = entry->payload;
+      if (!log_to_file)
+	p += sprintf(p, "<%d>", priority | log_fac);
+
+      /* Omit timestamp for default daemontools situation */
+      if (!log_stderr || !option_bool(OPT_NO_FORK)) 
+	p += sprintf(p, "%.15s ", ctime(&time_now) + 4);
+      
+      p += sprintf(p, "dnsmasq%s[%d]: ", func, (int)pid);
+        
+      len = p - entry->payload;
+      va_start(ap, format);  
+      len += vsnprintf(p, MAX_MESSAGE - len, format, ap) + 1; /* include zero-terminator */
+      va_end(ap);
+      entry->length = len > MAX_MESSAGE ? MAX_MESSAGE : len;
+      entry->offset = 0;
+      entry->pid = pid;
+    }
+  
+  /* almost always, logging won't block, so try and write this now,
+     to save collecting too many log messages during a select loop. */
+  log_write();
+  
+  /* Since we're doing things asynchronously, a cache-dump, for instance,
+     can now generate log lines very fast. With a small buffer (desirable),
+     that means it can overflow the log-buffer very quickly,
+     so that the cache dump becomes mainly a count of how many lines 
+     overflowed. To avoid this, we delay here, the delay is controlled 
+     by queue-occupancy, and grows exponentially. The delay is limited to (2^8)ms.
+     The scaling stuff ensures that when the queue is bigger than 8, the delay
+     only occurs for the last 8 entries. Once the queue is full, we stop delaying
+     to preserve performance.
+  */
+
+  if (entries && max_logs != 0)
+    {
+      int d;
+      
+      for (d = 0,entry = entries; entry; entry = entry->next, d++);
+      
+      if (d == max_logs)
+	d = 0;
+      else if (max_logs > 8)
+	d -= max_logs - 8;
+
+      if (d > 0)
+	{
+	  struct timespec waiter;
+	  waiter.tv_sec = 0;
+	  waiter.tv_nsec = 1000000 << (d - 1); /* 1 ms */
+	  nanosleep(&waiter, NULL);
+      
+	  /* Have another go now */
+	  log_write();
+	}
+    } 
+}
+
+void set_log_writer(void)
+{
+  if (entries && log_fd != -1 && connection_good)
+    poll_listen(log_fd, POLLOUT);
+}
+
+void check_log_writer(int force)
+{
+  if (log_fd != -1 && (force || poll_check(log_fd, POLLOUT)))
+    log_write();
+}
+
+void flush_log(void)
+{
+  /* write until queue empty, but don't loop forever if there's
+   no connection to the syslog in existence */
+  while (log_fd != -1)
+    {
+      struct timespec waiter;
+      log_write();
+      if (!entries || !connection_good)
+	{
+	  close(log_fd);	
+	  break;
+	}
+      waiter.tv_sec = 0;
+      waiter.tv_nsec = 1000000; /* 1 ms */
+      nanosleep(&waiter, NULL);
+    }
+}
+
+void die(char *message, char *arg1, int exit_code)
+{
+  char *errmess = strerror(errno);
+  
+  if (!arg1)
+    arg1 = errmess;
+
+  if (!log_stderr)
+    {
+      echo_stderr = 1; /* print as well as log when we die.... */
+      fputc('\n', stderr); /* prettyfy  startup-script message */
+    }
+  my_syslog(LOG_CRIT, message, arg1, errmess);
+  echo_stderr = 0;
+  my_syslog(LOG_CRIT, _("FAILED to start up"));
+  flush_log();
+  
+  exit(exit_code);
+}
diff --git a/src/loop.c b/src/loop.c
new file mode 100644
index 0000000..c7f9aaa
--- /dev/null
+++ b/src/loop.c
@@ -0,0 +1,117 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_LOOP
+static ssize_t loop_make_probe(u32 uid);
+
+void loop_send_probes()
+{
+   struct server *serv;
+   
+   if (!option_bool(OPT_LOOP_DETECT))
+     return;
+
+   /* Loop through all upstream servers not for particular domains, and send a query to that server which is
+      identifiable, via the uid. If we see that query back again, then the server is looping, and we should not use it. */
+   for (serv = daemon->servers; serv; serv = serv->next)
+     if (!(serv->flags & 
+	   (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_LOOP)))
+       {
+	 ssize_t len = loop_make_probe(serv->uid);
+	 int fd;
+	 struct randfd *rfd = NULL;
+	 
+	 if (serv->sfd)
+	   fd = serv->sfd->fd;
+	 else 
+	   {
+	     if (!(rfd = allocate_rfd(serv->addr.sa.sa_family)))
+	       continue;
+	     fd = rfd->fd;
+	   }
+
+	 while (retry_send(sendto(fd, daemon->packet, len, 0, 
+				  &serv->addr.sa, sa_len(&serv->addr))));
+	 
+	 free_rfd(rfd);
+       }
+}
+  
+static ssize_t loop_make_probe(u32 uid)
+{
+  struct dns_header *header = (struct dns_header *)daemon->packet;
+  unsigned char *p = (unsigned char *)(header+1);
+
+  /* packet buffer overwritten */
+  daemon->srv_save = NULL;
+  
+  header->id = rand16();
+  header->ancount = header->nscount = header->arcount = htons(0);
+  header->qdcount = htons(1);
+  header->hb3 = HB3_RD;
+  header->hb4 = 0;
+  SET_OPCODE(header, QUERY);
+
+  *p++ = 8;
+  sprintf((char *)p, "%.8x", uid);
+  p += 8;
+  *p++ = strlen(LOOP_TEST_DOMAIN);
+  strcpy((char *)p, LOOP_TEST_DOMAIN); /* Add terminating zero */
+  p += strlen(LOOP_TEST_DOMAIN) + 1;
+
+  PUTSHORT(LOOP_TEST_TYPE, p);
+  PUTSHORT(C_IN, p);
+
+  return p - (unsigned char *)header;
+}
+  
+
+int detect_loop(char *query, int type)
+{
+  int i;
+  u32 uid;
+  struct server *serv;
+  
+  if (!option_bool(OPT_LOOP_DETECT))
+    return 0;
+
+  if (type != LOOP_TEST_TYPE ||
+      strlen(LOOP_TEST_DOMAIN) + 9 != strlen(query) ||
+      strstr(query, LOOP_TEST_DOMAIN) != query + 9)
+    return 0;
+
+  for (i = 0; i < 8; i++)
+    if (!isxdigit(query[i]))
+      return 0;
+
+  uid = strtol(query, NULL, 16);
+
+  for (serv = daemon->servers; serv; serv = serv->next)
+     if (!(serv->flags & 
+	   (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_LOOP)) &&
+	 uid == serv->uid)
+       {
+	 serv->flags |= SERV_LOOP;
+	 check_servers(); /* log new state */
+	 return 1;
+       }
+
+  return 0;
+}
+
+#endif
diff --git a/src/nameser.h b/src/nameser.h
new file mode 100644
index 0000000..937519c
--- /dev/null
+++ b/src/nameser.h
@@ -0,0 +1,398 @@
+/*	$OpenBSD: nameser.h,v 1.11 2005/12/20 02:06:56 millert Exp $	*/
+
+/*
+ * ++Copyright++ 1983, 1989, 1993
+ * -
+ * Copyright (c) 1983, 1989, 1993
+ *    The Regents of the University of California.  All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ * 
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ * --Copyright--
+ */
+
+/*
+ *      @(#)nameser.h	8.1 (Berkeley) 6/2/93
+ *	$From: nameser.h,v 8.11 1996/10/08 04:51:02 vixie Exp $
+ */
+
+#ifndef _NAMESER_H_
+#define _NAMESER_H_
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+
+/*
+ * revision information.  this is the release date in YYYYMMDD format.
+ * it can change every day so the right thing to do with it is use it
+ * in preprocessor commands such as "#if (__BIND > 19931104)".  do not
+ * compare for equality; rather, use it to determine whether your resolver
+ * is new enough to contain a certain feature.
+ */
+
+#define __BIND		19960801	/* interface version stamp */
+
+/*
+ * Define constants based on rfc883
+ */
+#define PACKETSZ	512		/* maximum packet size */
+#define MAXDNAME	1025		/* maximum presentation domain name */
+#define MAXCDNAME	255		/* maximum compressed domain name */
+#define MAXLABEL	63		/* maximum length of domain label */
+#define HFIXEDSZ	12		/* #/bytes of fixed data in header */
+#define QFIXEDSZ	4		/* #/bytes of fixed data in query */
+#define RRFIXEDSZ	10		/* #/bytes of fixed data in r record */
+#define INT32SZ		4		/* for systems without 32-bit ints */
+#define INT16SZ		2		/* for systems without 16-bit ints */
+#define INADDRSZ	4		/* IPv4 T_A */
+#define IN6ADDRSZ	16		/* IPv6 T_AAAA */
+
+/*
+ * Internet nameserver port number
+ */
+#define NAMESERVER_PORT	53
+
+/*
+ * Currently defined opcodes
+ */
+#define QUERY		0x0		/* standard query */
+#define IQUERY		0x1		/* inverse query */
+#define STATUS		0x2		/* nameserver status query */
+/*#define xxx		0x3*/		/* 0x3 reserved */
+#define NS_NOTIFY_OP	0x4		/* notify secondary of SOA change */
+/*
+ * Currently defined response codes
+ */
+#define NOERROR		0		/* no error */
+#define FORMERR		1		/* format error */
+#define SERVFAIL	2		/* server failure */
+#define NXDOMAIN	3		/* non existent domain */
+#define NOTIMP		4		/* not implemented */
+#define REFUSED		5		/* query refused */
+
+/*
+ * Type values for resources and queries
+ */
+#define T_A		1		/* host address */
+#define T_NS		2		/* authoritative server */
+#define T_MD		3		/* mail destination */
+#define T_MF		4		/* mail forwarder */
+#define T_CNAME		5		/* canonical name */
+#define T_SOA		6		/* start of authority zone */
+#define T_MB		7		/* mailbox domain name */
+#define T_MG		8		/* mail group member */
+#define T_MR		9		/* mail rename name */
+#define T_NULL		10		/* null resource record */
+#define T_WKS		11		/* well known service */
+#define T_PTR		12		/* domain name pointer */
+#define T_HINFO		13		/* host information */
+#define T_MINFO		14		/* mailbox information */
+#define T_MX		15		/* mail routing information */
+#define T_TXT		16		/* text strings */
+#define T_RP		17		/* responsible person */
+#define T_AFSDB		18		/* AFS cell database */
+#define T_X25		19		/* X_25 calling address */
+#define T_ISDN		20		/* ISDN calling address */
+#define T_RT		21		/* router */
+#define T_NSAP		22		/* NSAP address */
+#define T_NSAP_PTR	23		/* reverse NSAP lookup (deprecated) */
+#define T_SIG		24		/* security signature */
+#define T_KEY		25		/* security key */
+#define T_PX		26		/* X.400 mail mapping */
+#define T_GPOS		27		/* geographical position (withdrawn) */
+#define T_AAAA		28		/* IP6 Address */
+#define T_LOC		29		/* Location Information */
+#define T_NXT		30		/* Next Valid Name in Zone */
+#define T_EID		31		/* Endpoint identifier */
+#define T_NIMLOC	32		/* Nimrod locator */
+#define T_SRV		33		/* Server selection */
+#define T_ATMA		34		/* ATM Address */
+#define T_NAPTR		35		/* Naming Authority PoinTeR */
+#define T_KX		36		/* Key Exchanger */
+#define T_CERT		37		/* CERT */
+#define T_A6		38		/* A6 */
+#define T_DNAME		39		/* DNAME */
+#define T_SINK		40		/* SINK */
+#define T_OPT		41		/* OPT pseudo-RR, RFC2671 */
+#define T_APL		42		/* APL */
+#define T_DS		43		/* Delegation Signer */
+#define T_SSHFP		44		/* SSH Key Fingerprint */
+#define T_RRSIG		46		/* RRSIG */
+#define T_NSEC		47		/* NSEC */
+#define T_DNSKEY	48		/* DNSKEY */
+	/* non standard */
+#define T_UINFO		100		/* user (finger) information */
+#define T_UID		101		/* user ID */
+#define T_GID		102		/* group ID */
+#define T_UNSPEC	103		/* Unspecified format (binary data) */
+	/* Query type values which do not appear in resource records */
+#define	T_TKEY		249		/* Transaction Key */
+#define	T_TSIG		250		/* Transaction Signature */
+#define	T_IXFR		251		/* incremental zone transfer */
+#define T_AXFR		252		/* transfer zone of authority */
+#define T_MAILB		253		/* transfer mailbox records */
+#define T_MAILA		254		/* transfer mail agent records */
+#define T_ANY		255		/* wildcard match */
+
+/*
+ * Values for class field
+ */
+
+#define C_IN		1		/* the arpa internet */
+#define C_CHAOS		3		/* for chaos net (MIT) */
+#define C_HS		4		/* for Hesiod name server (MIT) (XXX) */
+	/* Query class values which do not appear in resource records */
+#define C_ANY		255		/* wildcard match */
+
+/*
+ * Flags field of the KEY RR rdata
+ */
+#define	KEYFLAG_TYPEMASK	0xC000	/* Mask for "type" bits */
+#define	KEYFLAG_TYPE_AUTH_CONF	0x0000	/* Key usable for both */
+#define	KEYFLAG_TYPE_CONF_ONLY	0x8000	/* Key usable for confidentiality */
+#define	KEYFLAG_TYPE_AUTH_ONLY	0x4000	/* Key usable for authentication */
+#define	KEYFLAG_TYPE_NO_KEY	0xC000	/* No key usable for either; no key */
+/* The type bits can also be interpreted independently, as single bits: */
+#define	KEYFLAG_NO_AUTH		0x8000	/* Key not usable for authentication */
+#define	KEYFLAG_NO_CONF		0x4000	/* Key not usable for confidentiality */
+
+#define	KEYFLAG_EXPERIMENTAL	0x2000	/* Security is *mandatory* if bit=0 */
+#define	KEYFLAG_RESERVED3	0x1000  /* reserved - must be zero */
+#define	KEYFLAG_RESERVED4	0x0800  /* reserved - must be zero */
+#define	KEYFLAG_USERACCOUNT	0x0400	/* key is assoc. with a user acct */
+#define	KEYFLAG_ENTITY		0x0200	/* key is assoc. with entity eg host */
+#define	KEYFLAG_ZONEKEY		0x0100	/* key is zone key for the zone named */
+#define	KEYFLAG_IPSEC		0x0080  /* key is for IPSEC use (host or user)*/
+#define	KEYFLAG_EMAIL		0x0040  /* key is for email (MIME security) */
+#define	KEYFLAG_RESERVED10	0x0020  /* reserved - must be zero */
+#define	KEYFLAG_RESERVED11	0x0010  /* reserved - must be zero */
+#define	KEYFLAG_SIGNATORYMASK	0x000F	/* key can sign DNS RR's of same name */
+
+#define  KEYFLAG_RESERVED_BITMASK ( KEYFLAG_RESERVED3 | \
+				    KEYFLAG_RESERVED4 | \
+				    KEYFLAG_RESERVED10| KEYFLAG_RESERVED11) 
+
+/* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */
+#define	ALGORITHM_MD5RSA	1	/* MD5 with RSA */
+#define	ALGORITHM_EXPIRE_ONLY	253	/* No alg, no security */
+#define	ALGORITHM_PRIVATE_OID	254	/* Key begins with OID indicating alg */
+
+/* Signatures */
+					/* Size of a mod or exp in bits */
+#define	MIN_MD5RSA_KEY_PART_BITS	 512
+#define	MAX_MD5RSA_KEY_PART_BITS	2552
+					/* Total of binary mod and exp, bytes */
+#define	MAX_MD5RSA_KEY_BYTES		((MAX_MD5RSA_KEY_PART_BITS+7/8)*2+3)
+					/* Max length of text sig block */
+#define	MAX_KEY_BASE64			(((MAX_MD5RSA_KEY_BYTES+2)/3)*4)
+
+/*
+ * EDNS0 Z-field extended flags
+ */
+#define DNS_MESSAGEEXTFLAG_DO	0x8000U
+
+/*
+ * Status return codes for T_UNSPEC conversion routines
+ */
+#define CONV_SUCCESS	0
+#define CONV_OVERFLOW	(-1)
+#define CONV_BADFMT	(-2)
+#define CONV_BADCKSUM	(-3)
+#define CONV_BADBUFLEN	(-4)
+
+// GOOGLETV - _BYTE_ORDER is defined by Android.
+// Typical GNU toolchain defines __BYTE_ORDER and BYTE_ORDER, not _BYTE_ORDER
+// We could fix this in the toolchain, but it seems inappropriate.
+#if !defined(_BYTE_ORDER)
+#if !defined(__BYTE_ORDER)
+#error _BYTE_ORDER AND __BYTE_ORDER are undefined
+#else
+#define _BYTE_ORDER __BYTE_ORDER
+#endif
+#endif
+
+// Ditto for _BIG_ENDIAN and _LITTLE_ENDIAN
+#if !defined(_BIG_ENDIAN)
+#if !defined(__BIG_ENDIAN)
+#error _BIG_ENDIAN AND __BIG_ENDIAN are undefined
+#else
+#define _BIG_ENDIAN __BIG_ENDIAN
+#endif
+#endif
+
+#if !defined(_LITTLE_ENDIAN)
+#if !defined(__LITTLE_ENDIAN)
+#error _LITTLE_ENDIAN AND __LITTLE_ENDIAN are undefined
+#else
+#define _LITTLE_ENDIAN __LITTLE_ENDIAN
+#endif
+#endif
+
+#if !defined(_BYTE_ORDER) || \
+    (_BYTE_ORDER != _BIG_ENDIAN && _BYTE_ORDER != _LITTLE_ENDIAN && \
+    _BYTE_ORDER != _PDP_ENDIAN)
+	/* you must determine what the correct bit order is for
+	 * your compiler - the next line is an intentional error
+	 * which will force your compiles to bomb until you fix
+	 * the above macros.
+	 */
+#error "Undefined or invalid _BYTE_ORDER";
+#endif
+
+/*
+ * Structure for query header.  The order of the fields is machine- and
+ * compiler-dependent, depending on the byte/bit order and the layout
+ * of bit fields.  We use bit fields only in int variables, as this
+ * is all ANSI requires.  This requires a somewhat confusing rearrangement.
+ */
+
+typedef struct {
+	unsigned	id :16;		/* query identification number */
+#if _BYTE_ORDER == _BIG_ENDIAN
+			/* fields in third byte */
+	unsigned	qr: 1;		/* response flag */
+	unsigned	opcode: 4;	/* purpose of message */
+	unsigned	aa: 1;		/* authoritive answer */
+	unsigned	tc: 1;		/* truncated message */
+	unsigned	rd: 1;		/* recursion desired */
+			/* fields in fourth byte */
+	unsigned	ra: 1;		/* recursion available */
+	unsigned	unused :1;	/* unused bits (MBZ as of 4.9.3a3) */
+	unsigned	ad: 1;		/* authentic data from named */
+	unsigned	cd: 1;		/* checking disabled by resolver */
+	unsigned	rcode :4;	/* response code */
+#endif
+#if _BYTE_ORDER == _LITTLE_ENDIAN || _BYTE_ORDER == _PDP_ENDIAN
+			/* fields in third byte */
+	unsigned	rd :1;		/* recursion desired */
+	unsigned	tc :1;		/* truncated message */
+	unsigned	aa :1;		/* authoritive answer */
+	unsigned	opcode :4;	/* purpose of message */
+	unsigned	qr :1;		/* response flag */
+			/* fields in fourth byte */
+	unsigned	rcode :4;	/* response code */
+	unsigned	cd: 1;		/* checking disabled by resolver */
+	unsigned	ad: 1;		/* authentic data from named */
+	unsigned	unused :1;	/* unused bits (MBZ as of 4.9.3a3) */
+	unsigned	ra :1;		/* recursion available */
+#endif
+			/* remaining bytes */
+	unsigned	qdcount :16;	/* number of question entries */
+	unsigned	ancount :16;	/* number of answer entries */
+	unsigned	nscount :16;	/* number of authority entries */
+	unsigned	arcount :16;	/* number of resource entries */
+} HEADER;
+
+/*
+ * Defines for handling compressed domain names
+ */
+#define INDIR_MASK	0xc0
+
+extern	u_int16_t	_getshort(const unsigned char *);
+extern	u_int32_t	_getlong(const unsigned char *);
+
+/*
+ * Inline versions of get/put short/long.  Pointer is advanced.
+ *
+ * These macros demonstrate the property of C whereby it can be
+ * portable or it can be elegant but rarely both.
+ */
+#define GETSHORT(s, cp) { \
+	unsigned char *t_cp = (unsigned char *)(cp); \
+	(s) = ((u_int16_t)t_cp[0] << 8) \
+	    | ((u_int16_t)t_cp[1]) \
+	    ; \
+	(cp) += INT16SZ; \
+}
+
+#define GETLONG(l, cp) { \
+	unsigned char *t_cp = (unsigned char *)(cp); \
+	(l) = ((u_int32_t)t_cp[0] << 24) \
+	    | ((u_int32_t)t_cp[1] << 16) \
+	    | ((u_int32_t)t_cp[2] << 8) \
+	    | ((u_int32_t)t_cp[3]) \
+	    ; \
+	(cp) += INT32SZ; \
+}
+
+#define PUTSHORT(s, cp) { \
+	u_int16_t t_s = (u_int16_t)(s); \
+	unsigned char *t_cp = (unsigned char *)(cp); \
+	*t_cp++ = t_s >> 8; \
+	*t_cp   = t_s; \
+	(cp) += INT16SZ; \
+}
+
+#define PUTLONG(l, cp) { \
+	u_int32_t t_l = (u_int32_t)(l); \
+	unsigned char *t_cp = (unsigned char *)(cp); \
+	*t_cp++ = t_l >> 24; \
+	*t_cp++ = t_l >> 16; \
+	*t_cp++ = t_l >> 8; \
+	*t_cp   = t_l; \
+	(cp) += INT32SZ; \
+}
+
+#endif /* !_NAMESER_H_ */
diff --git a/src/netlink.c b/src/netlink.c
new file mode 100755
index 0000000..4d4ca56
--- /dev/null
+++ b/src/netlink.c
@@ -0,0 +1,374 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_LINUX_NETWORK
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+/* linux 2.6.19 buggers up the headers, patch it up here. */ 
+#ifndef IFA_RTA
+#  define IFA_RTA(r)  \
+       ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
+
+#  include <linux/if_addr.h>
+#endif
+
+#ifndef NDA_RTA
+#  define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) 
+#endif 
+
+
+static struct iovec iov;
+static u32 netlink_pid;
+
+static void nl_async(struct nlmsghdr *h);
+
+void netlink_init(void)
+{
+  struct sockaddr_nl addr;
+  socklen_t slen = sizeof(addr);
+
+  addr.nl_family = AF_NETLINK;
+  addr.nl_pad = 0;
+  addr.nl_pid = 0; /* autobind */
+  addr.nl_groups = RTMGRP_IPV4_ROUTE;
+  if (option_bool(OPT_CLEVERBIND))
+    addr.nl_groups |= RTMGRP_IPV4_IFADDR;  
+#ifdef HAVE_IPV6
+  addr.nl_groups |= RTMGRP_IPV6_ROUTE;
+  if (option_bool(OPT_CLEVERBIND))
+    addr.nl_groups |= RTMGRP_IPV6_IFADDR;
+#endif
+#ifdef HAVE_DHCP6
+  if (daemon->doing_ra || daemon->doing_dhcp6)
+    addr.nl_groups |= RTMGRP_IPV6_IFADDR;
+#endif
+  
+  /* May not be able to have permission to set multicast groups don't die in that case */
+  if ((daemon->netlinkfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) != -1)
+    {
+      if (bind(daemon->netlinkfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
+	{
+	  addr.nl_groups = 0;
+	  if (errno != EPERM || bind(daemon->netlinkfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
+	    daemon->netlinkfd = -1;
+	}
+    }
+  
+  if (daemon->netlinkfd == -1 || 
+      getsockname(daemon->netlinkfd, (struct sockaddr *)&addr, &slen) == -1)
+    die(_("cannot create netlink socket: %s"), NULL, EC_MISC);
+   
+  /* save pid assigned by bind() and retrieved by getsockname() */ 
+  netlink_pid = addr.nl_pid;
+  
+  iov.iov_len = 100;
+  iov.iov_base = safe_malloc(iov.iov_len);
+}
+
+static ssize_t netlink_recv(void)
+{
+  struct msghdr msg;
+  struct sockaddr_nl nladdr;
+  ssize_t rc;
+
+  while (1)
+    {
+      msg.msg_control = NULL;
+      msg.msg_controllen = 0;
+      msg.msg_name = &nladdr;
+      msg.msg_namelen = sizeof(nladdr);
+      msg.msg_iov = &iov;
+      msg.msg_iovlen = 1;
+      msg.msg_flags = 0;
+      
+      while ((rc = recvmsg(daemon->netlinkfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
+      
+      /* make buffer big enough */
+      if (rc != -1 && (msg.msg_flags & MSG_TRUNC))
+	{
+	  /* Very new Linux kernels return the actual size needed, older ones always return truncated size */
+	  if ((size_t)rc == iov.iov_len)
+	    {
+	      if (expand_buf(&iov, rc + 100))
+		continue;
+	    }
+	  else
+	    expand_buf(&iov, rc);
+	}
+
+      /* read it for real */
+      msg.msg_flags = 0;
+      while ((rc = recvmsg(daemon->netlinkfd, &msg, 0)) == -1 && errno == EINTR);
+      
+      /* Make sure this is from the kernel */
+      if (rc == -1 || nladdr.nl_pid == 0)
+	break;
+    }
+      
+  /* discard stuff which is truncated at this point (expand_buf() may fail) */
+  if (msg.msg_flags & MSG_TRUNC)
+    {
+      rc = -1;
+      errno = ENOMEM;
+    }
+  
+  return rc;
+}
+  
+
+/* family = AF_UNSPEC finds ARP table entries.
+   family = AF_LOCAL finds MAC addresses. */
+int iface_enumerate(int family, void *parm, int (*callback)())
+{
+  struct sockaddr_nl addr;
+  struct nlmsghdr *h;
+  ssize_t len;
+  static unsigned int seq = 0;
+  int callback_ok = 1;
+
+  struct {
+    struct nlmsghdr nlh;
+    struct rtgenmsg g; 
+  } req;
+
+  addr.nl_family = AF_NETLINK;
+  addr.nl_pad = 0;
+  addr.nl_groups = 0;
+  addr.nl_pid = 0; /* address to kernel */
+ 
+ again: 
+  if (family == AF_UNSPEC)
+    req.nlh.nlmsg_type = RTM_GETNEIGH;
+  else if (family == AF_LOCAL)
+    req.nlh.nlmsg_type = RTM_GETLINK;
+  else
+    req.nlh.nlmsg_type = RTM_GETADDR;
+
+  req.nlh.nlmsg_len = sizeof(req);
+  req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST | NLM_F_ACK; 
+  req.nlh.nlmsg_pid = 0;
+  req.nlh.nlmsg_seq = ++seq;
+  req.g.rtgen_family = family; 
+
+  /* Don't block in recvfrom if send fails */
+  while(retry_send(sendto(daemon->netlinkfd, (void *)&req, sizeof(req), 0, 
+			  (struct sockaddr *)&addr, sizeof(addr))));
+
+  if (errno != 0)
+    return 0;
+    
+  while (1)
+    {
+      if ((len = netlink_recv()) == -1)
+	{
+	  if (errno == ENOBUFS)
+	    {
+	      sleep(1);
+	      goto again;
+	    }
+	  return 0;
+	}
+
+      for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
+	if (h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
+	  {
+	    /* May be multicast arriving async */
+	    nl_async(h);
+	  }
+	else if (h->nlmsg_seq != seq)
+	  {
+	    /* May be part of incomplete response to previous request after
+	       ENOBUFS. Drop it. */
+	    continue;
+	  }
+	else if (h->nlmsg_type == NLMSG_DONE)
+	  return callback_ok;
+	else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
+	  {
+	    struct ifaddrmsg *ifa = NLMSG_DATA(h);  
+	    struct rtattr *rta = IFA_RTA(ifa);
+	    unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa));
+	    
+	    if (ifa->ifa_family == family)
+	      {
+		if (ifa->ifa_family == AF_INET)
+		  {
+		    struct in_addr netmask, addr, broadcast;
+		    char *label = NULL;
+
+		    netmask.s_addr = htonl(~(in_addr_t)0 << (32 - ifa->ifa_prefixlen));
+
+		    addr.s_addr = 0;
+		    broadcast.s_addr = 0;
+		    
+		    while (RTA_OK(rta, len1))
+		      {
+			if (rta->rta_type == IFA_LOCAL)
+			  addr = *((struct in_addr *)(rta+1));
+			else if (rta->rta_type == IFA_BROADCAST)
+			  broadcast = *((struct in_addr *)(rta+1));
+			else if (rta->rta_type == IFA_LABEL)
+			  label = RTA_DATA(rta);
+			
+			rta = RTA_NEXT(rta, len1);
+		      }
+		    
+		    if (addr.s_addr && callback_ok)
+		      if (!((*callback)(addr, ifa->ifa_index, label,  netmask, broadcast, parm)))
+			callback_ok = 0;
+		  }
+#ifdef HAVE_IPV6
+		else if (ifa->ifa_family == AF_INET6)
+		  {
+		    struct in6_addr *addrp = NULL;
+		    u32 valid = 0, preferred = 0;
+		    int flags = 0;
+		    
+		    while (RTA_OK(rta, len1))
+		      {
+			if (rta->rta_type == IFA_ADDRESS)
+			  addrp = ((struct in6_addr *)(rta+1)); 
+			else if (rta->rta_type == IFA_CACHEINFO)
+			  {
+			    struct ifa_cacheinfo *ifc = (struct ifa_cacheinfo *)(rta+1);
+			    preferred = ifc->ifa_prefered;
+			    valid = ifc->ifa_valid;
+			  }
+			rta = RTA_NEXT(rta, len1);
+		      }
+		    
+		    if (ifa->ifa_flags & IFA_F_TENTATIVE)
+		      flags |= IFACE_TENTATIVE;
+		    
+		    if (ifa->ifa_flags & IFA_F_DEPRECATED)
+		      flags |= IFACE_DEPRECATED;
+		    
+		    if (!(ifa->ifa_flags & IFA_F_TEMPORARY))
+		      flags |= IFACE_PERMANENT;
+    		    
+		    if (addrp && callback_ok)
+		      if (!((*callback)(addrp, (int)(ifa->ifa_prefixlen), (int)(ifa->ifa_scope), 
+					(int)(ifa->ifa_index), flags, 
+					(int) preferred, (int)valid, parm)))
+			callback_ok = 0;
+		  }
+#endif
+	      }
+	  }
+	else if (h->nlmsg_type == RTM_NEWNEIGH && family == AF_UNSPEC)
+	  {
+	    struct ndmsg *neigh = NLMSG_DATA(h);  
+	    struct rtattr *rta = NDA_RTA(neigh);
+	    unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*neigh));
+	    size_t maclen = 0;
+	    char *inaddr = NULL, *mac = NULL;
+	    
+	    while (RTA_OK(rta, len1))
+	      {
+		if (rta->rta_type == NDA_DST)
+		  inaddr = (char *)(rta+1);
+		else if (rta->rta_type == NDA_LLADDR)
+		  {
+		    maclen = rta->rta_len - sizeof(struct rtattr);
+		    mac = (char *)(rta+1);
+		  }
+		
+		rta = RTA_NEXT(rta, len1);
+	      }
+
+	    if (!(neigh->ndm_state & (NUD_NOARP | NUD_INCOMPLETE | NUD_FAILED)) &&
+		inaddr && mac && callback_ok)
+	      if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
+		callback_ok = 0;
+	  }
+#ifdef HAVE_DHCP6
+	else if (h->nlmsg_type == RTM_NEWLINK && family == AF_LOCAL)
+	  {
+	    struct ifinfomsg *link =  NLMSG_DATA(h);
+	    struct rtattr *rta = IFLA_RTA(link);
+	    unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*link));
+	    char *mac = NULL;
+	    size_t maclen = 0;
+
+	    while (RTA_OK(rta, len1))
+	      {
+		if (rta->rta_type == IFLA_ADDRESS)
+		  {
+		    maclen = rta->rta_len - sizeof(struct rtattr);
+		    mac = (char *)(rta+1);
+		  }
+		
+		rta = RTA_NEXT(rta, len1);
+	      }
+
+	    if (mac && callback_ok && !((link->ifi_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) && 
+		!((*callback)((int)link->ifi_index, (unsigned int)link->ifi_type, mac, maclen, parm)))
+	      callback_ok = 0;
+	  }
+#endif
+    }
+}
+
+void netlink_multicast(void)
+{
+  ssize_t len;
+  struct nlmsghdr *h;
+  int flags;
+  
+  /* don't risk blocking reading netlink messages here. */
+  if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
+      fcntl(daemon->netlinkfd, F_SETFL, flags | O_NONBLOCK) == -1) 
+    return;
+  
+  if ((len = netlink_recv()) != -1)
+    for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
+      nl_async(h);
+  
+  /* restore non-blocking status */
+  fcntl(daemon->netlinkfd, F_SETFL, flags);
+}
+
+static void nl_async(struct nlmsghdr *h)
+{
+  if (h->nlmsg_type == NLMSG_ERROR)
+    {
+      struct nlmsgerr *err = NLMSG_DATA(h);
+      if (err->error != 0)
+	my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
+    }
+  else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE) 
+    {
+      /* We arrange to receive netlink multicast messages whenever the network route is added.
+	 If this happens and we still have a DNS packet in the buffer, we re-send it.
+	 This helps on DoD links, where frequently the packet which triggers dialling is
+	 a DNS query, which then gets lost. By re-sending, we can avoid the lookup
+	 failing. */ 
+      struct rtmsg *rtm = NLMSG_DATA(h);
+      
+      if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK)
+	queue_event(EVENT_NEWROUTE);
+    }
+  else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) 
+    queue_event(EVENT_NEWADDR);
+}
+#endif
+
+      
diff --git a/src/network.c b/src/network.c
new file mode 100755
index 0000000..c87b879
--- /dev/null
+++ b/src/network.c
@@ -0,0 +1,1713 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_LINUX_NETWORK
+
+int indextoname(int fd, int index, char *name)
+{
+  struct ifreq ifr;
+  
+  if (index == 0)
+    return 0;
+
+  ifr.ifr_ifindex = index;
+  if (ioctl(fd, SIOCGIFNAME, &ifr) == -1)
+    return 0;
+
+  strncpy(name, ifr.ifr_name, IF_NAMESIZE);
+
+  return 1;
+}
+
+
+#elif defined(HAVE_SOLARIS_NETWORK)
+
+#include <zone.h>
+#include <alloca.h>
+#ifndef LIFC_UNDER_IPMP
+#  define LIFC_UNDER_IPMP 0
+#endif
+
+int indextoname(int fd, int index, char *name)
+{
+  int64_t lifc_flags;
+  struct lifnum lifn;
+  int numifs, bufsize, i;
+  struct lifconf lifc;
+  struct lifreq *lifrp;
+  
+  if (index == 0)
+    return 0;
+  
+  if (getzoneid() == GLOBAL_ZONEID) 
+    {
+      if (!if_indextoname(index, name))
+	return 0;
+      return 1;
+    }
+  
+  lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES | LIFC_UNDER_IPMP;
+  lifn.lifn_family = AF_UNSPEC;
+  lifn.lifn_flags = lifc_flags;
+  if (ioctl(fd, SIOCGLIFNUM, &lifn) < 0) 
+    return 0;
+  
+  numifs = lifn.lifn_count;
+  bufsize = numifs * sizeof(struct lifreq);
+  
+  lifc.lifc_family = AF_UNSPEC;
+  lifc.lifc_flags = lifc_flags;
+  lifc.lifc_len = bufsize;
+  lifc.lifc_buf = alloca(bufsize);
+  
+  if (ioctl(fd, SIOCGLIFCONF, &lifc) < 0)  
+    return 0;
+  
+  lifrp = lifc.lifc_req;
+  for (i = lifc.lifc_len / sizeof(struct lifreq); i; i--, lifrp++) 
+    {
+      struct lifreq lifr;
+      strncpy(lifr.lifr_name, lifrp->lifr_name, IF_NAMESIZE);
+      if (ioctl(fd, SIOCGLIFINDEX, &lifr) < 0) 
+	return 0;
+      
+      if (lifr.lifr_index == index) {
+	strncpy(name, lifr.lifr_name, IF_NAMESIZE);
+	return 1;
+      }
+    }
+  return 0;
+}
+
+
+#else
+
+int indextoname(int fd, int index, char *name)
+{ 
+  (void)fd;
+
+  if (index == 0 || !if_indextoname(index, name))
+    return 0;
+
+  return 1;
+}
+
+#endif
+
+int iface_check(int family, struct all_addr *addr, char *name, int *auth)
+{
+  struct iname *tmp;
+  int ret = 1, match_addr = 0;
+
+  /* Note: have to check all and not bail out early, so that we set the
+     "used" flags.
+
+     May be called with family == AF_LOCALto check interface by name only. */
+  
+  if (auth)
+    *auth = 0;
+  
+  if (daemon->if_names || daemon->if_addrs)
+    {
+      ret = 0;
+
+      for (tmp = daemon->if_names; tmp; tmp = tmp->next)
+	if (tmp->name && wildcard_match(tmp->name, name))
+	  ret = tmp->used = 1;
+	        
+      if (addr)
+	for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
+	  if (tmp->addr.sa.sa_family == family)
+	    {
+	      if (family == AF_INET &&
+		  tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
+		ret = match_addr = tmp->used = 1;
+#ifdef HAVE_IPV6
+	      else if (family == AF_INET6 &&
+		       IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, 
+					  &addr->addr.addr6))
+		ret = match_addr = tmp->used = 1;
+#endif
+	    }          
+    }
+  
+  if (!match_addr)
+    for (tmp = daemon->if_except; tmp; tmp = tmp->next)
+      if (tmp->name && wildcard_match(tmp->name, name))
+	ret = 0;
+    
+
+  for (tmp = daemon->authinterface; tmp; tmp = tmp->next)
+    if (tmp->name)
+      {
+	if (strcmp(tmp->name, name) == 0 &&
+	    (tmp->addr.sa.sa_family == 0 || tmp->addr.sa.sa_family == family))
+	  break;
+      }
+    else if (addr && tmp->addr.sa.sa_family == AF_INET && family == AF_INET &&
+	     tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
+      break;
+#ifdef HAVE_IPV6
+    else if (addr && tmp->addr.sa.sa_family == AF_INET6 && family == AF_INET6 &&
+	     IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, &addr->addr.addr6))
+      break;
+#endif      
+
+  if (tmp && auth) 
+    {
+      *auth = 1;
+      ret = 1;
+    }
+
+  return ret; 
+}
+
+
+/* Fix for problem that the kernel sometimes reports the loopback interface as the
+   arrival interface when a packet originates locally, even when sent to address of 
+   an interface other than the loopback. Accept packet if it arrived via a loopback 
+   interface, even when we're not accepting packets that way, as long as the destination
+   address is one we're believing. Interface list must be up-to-date before calling. */
+int loopback_exception(int fd, int family, struct all_addr *addr, char *name)    
+{
+  struct ifreq ifr;
+  struct irec *iface;
+
+  strncpy(ifr.ifr_name, name, IF_NAMESIZE);
+  if (ioctl(fd, SIOCGIFFLAGS, &ifr) != -1 &&
+      ifr.ifr_flags & IFF_LOOPBACK)
+    {
+      for (iface = daemon->interfaces; iface; iface = iface->next)
+	if (iface->addr.sa.sa_family == family)
+	  {
+	    if (family == AF_INET)
+	      {
+		if (iface->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
+		  return 1;
+	      }
+#ifdef HAVE_IPV6
+	    else if (IN6_ARE_ADDR_EQUAL(&iface->addr.in6.sin6_addr, &addr->addr.addr6))
+	      return 1;
+#endif
+	    
+	  }
+    }
+  return 0;
+}
+
+/* If we're configured with something like --interface=eth0:0 then we'll listen correctly
+   on the relevant address, but the name of the arrival interface, derived from the
+   index won't match the config. Check that we found an interface address for the arrival 
+   interface: daemon->interfaces must be up-to-date. */
+int label_exception(int index, int family, struct all_addr *addr)
+{
+  struct irec *iface;
+
+  /* labels only supported on IPv4 addresses. */
+  if (family != AF_INET)
+    return 0;
+
+  for (iface = daemon->interfaces; iface; iface = iface->next)
+    if (iface->index == index && iface->addr.sa.sa_family == AF_INET &&
+	iface->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
+      return 1;
+
+  return 0;
+}
+
+struct iface_param {
+  struct addrlist *spare;
+  int fd;
+};
+
+static int iface_allowed(struct iface_param *param, int if_index, char *label,
+			 union mysockaddr *addr, struct in_addr netmask, int prefixlen, int iface_flags) 
+{
+  struct irec *iface;
+  int mtu = 0, loopback;
+  struct ifreq ifr;
+  int tftp_ok = !!option_bool(OPT_TFTP);
+  int dhcp_ok = 1;
+  int auth_dns = 0;
+  int is_label = 0;
+#if defined(HAVE_DHCP) || defined(HAVE_TFTP)
+  struct iname *tmp;
+#endif
+
+  (void)prefixlen;
+
+  if (!indextoname(param->fd, if_index, ifr.ifr_name) ||
+      ioctl(param->fd, SIOCGIFFLAGS, &ifr) == -1)
+    return 0;
+   
+  loopback = ifr.ifr_flags & IFF_LOOPBACK;
+  
+  if (loopback)
+    dhcp_ok = 0;
+  
+  if (ioctl(param->fd, SIOCGIFMTU, &ifr) != -1)
+    mtu = ifr.ifr_mtu;
+  
+  if (!label)
+    label = ifr.ifr_name;
+  else
+    is_label = strcmp(label, ifr.ifr_name);
+ 
+  /* maintain a list of all addresses on all interfaces for --local-service option */
+  if (option_bool(OPT_LOCAL_SERVICE))
+    {
+      struct addrlist *al;
+
+      if (param->spare)
+	{
+	  al = param->spare;
+	  param->spare = al->next;
+	}
+      else
+	al = whine_malloc(sizeof(struct addrlist));
+      
+      if (al)
+	{
+	  al->next = daemon->interface_addrs;
+	  daemon->interface_addrs = al;
+	  al->prefixlen = prefixlen;
+	  
+	  if (addr->sa.sa_family == AF_INET)
+	    {
+	      al->addr.addr.addr4 = addr->in.sin_addr;
+	      al->flags = 0;
+	    }
+#ifdef HAVE_IPV6
+	  else
+	    {
+	      al->addr.addr.addr6 = addr->in6.sin6_addr;
+	      al->flags = ADDRLIST_IPV6;
+	    } 
+#endif
+	}
+    }
+  
+#ifdef HAVE_IPV6
+  if (addr->sa.sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr))
+#endif
+    {
+      struct interface_name *int_name;
+      struct addrlist *al;
+#ifdef HAVE_AUTH
+      struct auth_zone *zone;
+      struct auth_name_list *name;
+
+      /* Find subnets in auth_zones */
+      for (zone = daemon->auth_zones; zone; zone = zone->next)
+	for (name = zone->interface_names; name; name = name->next)
+	  if (wildcard_match(name->name, label))
+	    {
+	      if (addr->sa.sa_family == AF_INET && (name->flags & AUTH4))
+		{
+		  if (param->spare)
+		    {
+		      al = param->spare;
+		      param->spare = al->next;
+		    }
+		  else
+		    al = whine_malloc(sizeof(struct addrlist));
+		  
+		  if (al)
+		    {
+		      al->next = zone->subnet;
+		      zone->subnet = al;
+		      al->prefixlen = prefixlen;
+		      al->addr.addr.addr4 = addr->in.sin_addr;
+		      al->flags = 0;
+		    }
+		}
+	      
+#ifdef HAVE_IPV6
+	      if (addr->sa.sa_family == AF_INET6 && (name->flags & AUTH6))
+		{
+		  if (param->spare)
+		    {
+		      al = param->spare;
+		      param->spare = al->next;
+		    }
+		  else
+		    al = whine_malloc(sizeof(struct addrlist));
+		  
+		  if (al)
+		    {
+		      al->next = zone->subnet;
+		      zone->subnet = al;
+		      al->prefixlen = prefixlen;
+		      al->addr.addr.addr6 = addr->in6.sin6_addr;
+		      al->flags = ADDRLIST_IPV6;
+		    }
+		} 
+#endif
+	      
+	    }
+#endif
+       
+      /* Update addresses from interface_names. These are a set independent
+	 of the set we're listening on. */  
+      for (int_name = daemon->int_names; int_name; int_name = int_name->next)
+	if (strncmp(label, int_name->intr, IF_NAMESIZE) == 0 && 
+	    (addr->sa.sa_family == int_name->family || int_name->family == 0))
+	  {
+	    if (param->spare)
+	      {
+		al = param->spare;
+		param->spare = al->next;
+	      }
+	    else
+	      al = whine_malloc(sizeof(struct addrlist));
+	    
+	    if (al)
+	      {
+		al->next = int_name->addr;
+		int_name->addr = al;
+		
+		if (addr->sa.sa_family == AF_INET)
+		  {
+		    al->addr.addr.addr4 = addr->in.sin_addr;
+		    al->flags = 0;
+		  }
+#ifdef HAVE_IPV6
+		else
+		 {
+		    al->addr.addr.addr6 = addr->in6.sin6_addr;
+		    al->flags = ADDRLIST_IPV6;
+		    /* Privacy addresses and addresses still undergoing DAD and deprecated addresses
+		       don't appear in forward queries, but will in reverse ones. */
+		    if (!(iface_flags & IFACE_PERMANENT) || (iface_flags & (IFACE_DEPRECATED | IFACE_TENTATIVE)))
+		      al->flags |= ADDRLIST_REVONLY;
+		 } 
+#endif
+	      }
+	  }
+    }
+ 
+  /* check whether the interface IP has been added already 
+     we call this routine multiple times. */
+  for (iface = daemon->interfaces; iface; iface = iface->next) 
+    if (sockaddr_isequal(&iface->addr, addr))
+      {
+	iface->dad = !!(iface_flags & IFACE_TENTATIVE);
+	iface->found = 1; /* for garbage collection */
+	return 1;
+      }
+
+ /* If we are restricting the set of interfaces to use, make
+     sure that loopback interfaces are in that set. */
+  if (daemon->if_names && loopback)
+    {
+      struct iname *lo;
+      for (lo = daemon->if_names; lo; lo = lo->next)
+	if (lo->name && strcmp(lo->name, ifr.ifr_name) == 0)
+	  break;
+      
+      if (!lo && (lo = whine_malloc(sizeof(struct iname)))) 
+	{
+	  if ((lo->name = whine_malloc(strlen(ifr.ifr_name)+1)))
+	    {
+	      strcpy(lo->name, ifr.ifr_name);
+	      lo->used = 1;
+	      lo->next = daemon->if_names;
+	      daemon->if_names = lo;
+	    }
+	  else
+	    free(lo);
+	}
+    }
+  
+  if (addr->sa.sa_family == AF_INET &&
+      !iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, label, &auth_dns))
+    return 1;
+
+#ifdef HAVE_IPV6
+  if (addr->sa.sa_family == AF_INET6 &&
+      !iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, label, &auth_dns))
+    return 1;
+#endif
+    
+#ifdef HAVE_DHCP
+  /* No DHCP where we're doing auth DNS. */
+  if (auth_dns)
+    {
+      tftp_ok = 0;
+      dhcp_ok = 0;
+    }
+  else
+    for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
+      if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
+	{
+	  tftp_ok = 0;
+	  dhcp_ok = 0;
+	}
+#endif
+ 
+  
+#ifdef HAVE_TFTP
+  if (daemon->tftp_interfaces)
+    {
+      /* dedicated tftp interface list */
+      tftp_ok = 0;
+      for (tmp = daemon->tftp_interfaces; tmp; tmp = tmp->next)
+	if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
+	  tftp_ok = 1;
+    }
+#endif
+  
+  /* add to list */
+  if ((iface = whine_malloc(sizeof(struct irec))))
+    {
+      iface->addr = *addr;
+      iface->netmask = netmask;
+      iface->tftp_ok = tftp_ok;
+      iface->dhcp_ok = dhcp_ok;
+      iface->dns_auth = auth_dns;
+      iface->mtu = mtu;
+      iface->dad = !!(iface_flags & IFACE_TENTATIVE);
+      iface->found = 1;
+      iface->done = iface->multicast_done = iface->warned = 0;
+      iface->index = if_index;
+      iface->label = is_label;
+      if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
+	{
+	  strcpy(iface->name, ifr.ifr_name);
+	  iface->next = daemon->interfaces;
+	  daemon->interfaces = iface;
+	  return 1;
+	}
+      free(iface);
+
+    }
+  
+  errno = ENOMEM; 
+  return 0;
+}
+
+#ifdef HAVE_IPV6
+static int iface_allowed_v6(struct in6_addr *local, int prefix, 
+			    int scope, int if_index, int flags, 
+			    int preferred, int valid, void *vparam)
+{
+  union mysockaddr addr;
+  struct in_addr netmask; /* dummy */
+  netmask.s_addr = 0;
+
+  (void)scope; /* warning */
+  (void)preferred;
+  (void)valid;
+  
+  memset(&addr, 0, sizeof(addr));
+#ifdef HAVE_SOCKADDR_SA_LEN
+  addr.in6.sin6_len = sizeof(addr.in6);
+#endif
+  addr.in6.sin6_family = AF_INET6;
+  addr.in6.sin6_addr = *local;
+  addr.in6.sin6_port = htons(daemon->port);
+  /* FreeBSD insists this is zero for non-linklocal addresses */
+  if (IN6_IS_ADDR_LINKLOCAL(local))
+    addr.in6.sin6_scope_id = if_index;
+  else
+    addr.in6.sin6_scope_id = 0;
+  
+  return iface_allowed((struct iface_param *)vparam, if_index, NULL, &addr, netmask, prefix, flags);
+}
+#endif
+
+static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
+			    struct in_addr netmask, struct in_addr broadcast, void *vparam)
+{
+  union mysockaddr addr;
+  int prefix, bit;
+ 
+  (void)broadcast; /* warning */
+
+  memset(&addr, 0, sizeof(addr));
+#ifdef HAVE_SOCKADDR_SA_LEN
+  addr.in.sin_len = sizeof(addr.in);
+#endif
+  addr.in.sin_family = AF_INET;
+  addr.in.sin_addr = local;
+  addr.in.sin_port = htons(daemon->port);
+
+  /* determine prefix length from netmask */
+  for (prefix = 32, bit = 1; (bit & ntohl(netmask.s_addr)) == 0 && prefix != 0; bit = bit << 1, prefix--);
+
+  return iface_allowed((struct iface_param *)vparam, if_index, label, &addr, netmask, prefix, 0);
+}
+   
+int enumerate_interfaces(int reset)
+{
+  static struct addrlist *spare = NULL;
+  static int done = 0;
+  struct iface_param param;
+  int errsave, ret = 1;
+  struct addrlist *addr, *tmp;
+  struct interface_name *intname;
+  struct irec *iface;
+#ifdef HAVE_AUTH
+  struct auth_zone *zone;
+#endif
+
+  /* Do this max once per select cycle  - also inhibits netlink socket use
+   in TCP child processes. */
+
+  if (reset)
+    {
+      done = 0;
+      return 1;
+    }
+
+  if (done)
+    return 1;
+
+  done = 1;
+
+  if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
+    return 0;
+ 
+  /* Mark interfaces for garbage collection */
+  for (iface = daemon->interfaces; iface; iface = iface->next) 
+    iface->found = 0;
+
+  /* remove addresses stored against interface_names */
+  for (intname = daemon->int_names; intname; intname = intname->next)
+    {
+      for (addr = intname->addr; addr; addr = tmp)
+	{
+	  tmp = addr->next;
+	  addr->next = spare;
+	  spare = addr;
+	}
+      
+      intname->addr = NULL;
+    }
+
+  /* Remove list of addresses of local interfaces */
+  for (addr = daemon->interface_addrs; addr; addr = tmp)
+    {
+      tmp = addr->next;
+      addr->next = spare;
+      spare = addr;
+    }
+  daemon->interface_addrs = NULL;
+  
+#ifdef HAVE_AUTH
+  /* remove addresses stored against auth_zone subnets, but not 
+   ones configured as address literals */
+  for (zone = daemon->auth_zones; zone; zone = zone->next)
+    if (zone->interface_names)
+      {
+	struct addrlist **up;
+	for (up = &zone->subnet, addr = zone->subnet; addr; addr = tmp)
+	  {
+	    tmp = addr->next;
+	    if (addr->flags & ADDRLIST_LITERAL)
+	      up = &addr->next;
+	    else
+	      {
+		*up = addr->next;
+		addr->next = spare;
+		spare = addr;
+	      }
+	  }
+      }
+#endif
+
+  param.spare = spare;
+  
+#ifdef HAVE_IPV6
+  ret = iface_enumerate(AF_INET6, &param, iface_allowed_v6);
+#endif
+
+  if (ret)
+    ret = iface_enumerate(AF_INET, &param, iface_allowed_v4); 
+ 
+  errsave = errno;
+  close(param.fd);
+  
+  if (option_bool(OPT_CLEVERBIND))
+    { 
+      /* Garbage-collect listeners listening on addresses that no longer exist.
+	 Does nothing when not binding interfaces or for listeners on localhost, 
+	 since the ->iface field is NULL. Note that this needs the protections
+	 against reentrancy, hence it's here.  It also means there's a possibility,
+	 in OPT_CLEVERBIND mode, that at listener will just disappear after
+	 a call to enumerate_interfaces, this is checked OK on all calls. */
+      struct listener *l, *tmp, **up;
+      
+      for (up = &daemon->listeners, l = daemon->listeners; l; l = tmp)
+	{
+	  tmp = l->next;
+	  
+	  if (!l->iface || l->iface->found)
+	    up = &l->next;
+	  else
+	    {
+	      *up = l->next;
+	      
+	      /* In case it ever returns */
+	      l->iface->done = 0;
+	      
+	      if (l->fd != -1)
+		close(l->fd);
+	      if (l->tcpfd != -1)
+		close(l->tcpfd);
+	      if (l->tftpfd != -1)
+		close(l->tftpfd);
+	      
+	      free(l);
+	    }
+	}
+    }
+  
+  errno = errsave;
+  spare = param.spare;
+    
+  return ret;
+}
+
+/* set NONBLOCK bit on fd: See Stevens 16.6 */
+int fix_fd(int fd)
+{
+  int flags;
+
+  if ((flags = fcntl(fd, F_GETFL)) == -1 ||
+      fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
+    return 0;
+  
+  return 1;
+}
+
+static int make_sock(union mysockaddr *addr, int type, int dienow)
+{
+  int family = addr->sa.sa_family;
+  int fd, rc, opt = 1;
+  
+  if ((fd = socket(family, type, 0)) == -1)
+    {
+      int port, errsave;
+      char *s;
+
+      /* No error if the kernel just doesn't support this IP flavour */
+      if (errno == EPROTONOSUPPORT ||
+	  errno == EAFNOSUPPORT ||
+	  errno == EINVAL)
+	return -1;
+      
+    err:
+      errsave = errno;
+      port = prettyprint_addr(addr, daemon->addrbuff);
+      if (!option_bool(OPT_NOWILD) && !option_bool(OPT_CLEVERBIND))
+	sprintf(daemon->addrbuff, "port %d", port);
+      s = _("failed to create listening socket for %s: %s");
+      
+      if (fd != -1)
+	close (fd);
+	
+      errno = errsave;
+
+      if (dienow)
+	{
+	  /* failure to bind addresses given by --listen-address at this point
+	     is OK if we're doing bind-dynamic */
+	  if (!option_bool(OPT_CLEVERBIND))
+	    die(s, daemon->addrbuff, EC_BADNET);
+	}
+      else
+	my_syslog(LOG_WARNING, s, daemon->addrbuff, strerror(errno));
+      
+      return -1;
+    }	
+  
+  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || !fix_fd(fd))
+    goto err;
+  
+#ifdef HAVE_IPV6
+  if (family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
+    goto err;
+#endif
+  
+  if ((rc = bind(fd, (struct sockaddr *)addr, sa_len(addr))) == -1)
+    goto err;
+  
+  if (type == SOCK_STREAM)
+    {
+      if (listen(fd, TCP_BACKLOG) == -1)
+	goto err;
+    }
+  else if (family == AF_INET)
+    {
+      if (!option_bool(OPT_NOWILD))
+	{
+#if defined(HAVE_LINUX_NETWORK) 
+	  if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1)
+	    goto err;
+#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
+	  if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
+	      setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1)
+	    goto err;
+#endif
+	}
+    }
+#ifdef HAVE_IPV6
+  else if (!set_ipv6pktinfo(fd))
+    goto err;
+#endif
+  
+  return fd;
+}
+
+#ifdef HAVE_IPV6  
+int set_ipv6pktinfo(int fd)
+{
+  int opt = 1;
+
+  /* The API changed around Linux 2.6.14 but the old ABI is still supported:
+     handle all combinations of headers and kernel.
+     OpenWrt note that this fixes the problem addressed by your very broken patch. */
+  daemon->v6pktinfo = IPV6_PKTINFO;
+  
+#ifdef IPV6_RECVPKTINFO
+  if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt, sizeof(opt)) != -1)
+    return 1;
+# ifdef IPV6_2292PKTINFO
+  else if (errno == ENOPROTOOPT && setsockopt(fd, IPPROTO_IPV6, IPV6_2292PKTINFO, &opt, sizeof(opt)) != -1)
+    {
+      daemon->v6pktinfo = IPV6_2292PKTINFO;
+      return 1;
+    }
+# endif 
+#else
+  if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &opt, sizeof(opt)) != -1)
+    return 1;
+#endif
+
+  return 0;
+}
+#endif
+
+
+/* Find the interface on which a TCP connection arrived, if possible, or zero otherwise. */
+int tcp_interface(int fd, int af)
+{ 
+  int if_index = 0;
+
+#ifdef HAVE_LINUX_NETWORK
+  int opt = 1;
+  struct cmsghdr *cmptr;
+  struct msghdr msg;
+  socklen_t len;
+  
+  /* use mshdr so that the CMSDG_* macros are available */
+  msg.msg_control = daemon->packet;
+  msg.msg_controllen = len = daemon->packet_buff_sz;
+  
+  /* we overwrote the buffer... */
+  daemon->srv_save = NULL;
+  
+  if (af == AF_INET)
+    {
+      if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) != -1 &&
+	  getsockopt(fd, IPPROTO_IP, IP_PKTOPTIONS, msg.msg_control, &len) != -1)
+	{
+	  msg.msg_controllen = len;
+	  for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
+	    if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
+	      {
+		union {
+		  unsigned char *c;
+		  struct in_pktinfo *p;
+		} p;
+		
+		p.c = CMSG_DATA(cmptr);
+		if_index = p.p->ipi_ifindex;
+	      }
+	}
+    }
+#ifdef HAVE_IPV6
+  else
+    {
+      /* Only the RFC-2292 API has the ability to find the interface for TCP connections,
+	 it was removed in RFC-3542 !!!! 
+
+	 Fortunately, Linux kept the 2292 ABI when it moved to 3542. The following code always
+	 uses the old ABI, and should work with pre- and post-3542 kernel headers */
+
+#ifdef IPV6_2292PKTOPTIONS   
+#  define PKTOPTIONS IPV6_2292PKTOPTIONS
+#else
+#  define PKTOPTIONS IPV6_PKTOPTIONS
+#endif
+
+      if (set_ipv6pktinfo(fd) &&
+	  getsockopt(fd, IPPROTO_IPV6, PKTOPTIONS, msg.msg_control, &len) != -1)
+	{
+          msg.msg_controllen = len;
+	  for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
+            if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
+              {
+                union {
+                  unsigned char *c;
+                  struct in6_pktinfo *p;
+                } p;
+                p.c = CMSG_DATA(cmptr);
+		
+		if_index = p.p->ipi6_ifindex;
+              }
+	}
+    }
+#endif /* IPV6 */
+#endif /* Linux */
+ 
+  return if_index;
+}
+      
+static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, int dienow)
+{
+  struct listener *l = NULL;
+  int fd = -1, tcpfd = -1, tftpfd = -1;
+
+  (void)do_tftp;
+
+  if (daemon->port != 0)
+    {
+      fd = make_sock(addr, SOCK_DGRAM, dienow);
+      tcpfd = make_sock(addr, SOCK_STREAM, dienow);
+    }
+  
+#ifdef HAVE_TFTP
+  if (do_tftp)
+    {
+      if (addr->sa.sa_family == AF_INET)
+	{
+	  /* port must be restored to DNS port for TCP code */
+	  short save = addr->in.sin_port;
+	  addr->in.sin_port = htons(TFTP_PORT);
+	  tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
+	  addr->in.sin_port = save;
+	}
+#  ifdef HAVE_IPV6
+      else
+	{
+	  short save = addr->in6.sin6_port;
+	  addr->in6.sin6_port = htons(TFTP_PORT);
+	  tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
+	  addr->in6.sin6_port = save;
+	}  
+#  endif
+    }
+#endif
+
+  if (fd != -1 || tcpfd != -1 || tftpfd != -1)
+    {
+      l = safe_malloc(sizeof(struct listener));
+      l->next = NULL;
+      l->family = addr->sa.sa_family;
+      l->fd = fd;
+      l->tcpfd = tcpfd;
+      l->tftpfd = tftpfd;	
+      l->iface = NULL;
+    }
+
+  return l;
+}
+
+void create_wildcard_listeners(void)
+{
+  union mysockaddr addr;
+  struct listener *l, *l6;
+
+  memset(&addr, 0, sizeof(addr));
+#ifdef HAVE_SOCKADDR_SA_LEN
+  addr.in.sin_len = sizeof(addr.in);
+#endif
+  addr.in.sin_family = AF_INET;
+  addr.in.sin_addr.s_addr = INADDR_ANY;
+  addr.in.sin_port = htons(daemon->port);
+
+  l = create_listeners(&addr, !!option_bool(OPT_TFTP), 1);
+
+#ifdef HAVE_IPV6
+  memset(&addr, 0, sizeof(addr));
+#  ifdef HAVE_SOCKADDR_SA_LEN
+  addr.in6.sin6_len = sizeof(addr.in6);
+#  endif
+  addr.in6.sin6_family = AF_INET6;
+  addr.in6.sin6_addr = in6addr_any;
+  addr.in6.sin6_port = htons(daemon->port);
+ 
+  l6 = create_listeners(&addr, !!option_bool(OPT_TFTP), 1);
+  if (l) 
+    l->next = l6;
+  else 
+    l = l6;
+#endif
+
+  daemon->listeners = l;
+}
+
+void create_bound_listeners(int dienow)
+{
+  struct listener *new;
+  struct irec *iface;
+  struct iname *if_tmp;
+
+  for (iface = daemon->interfaces; iface; iface = iface->next)
+    if (!iface->done && !iface->dad && iface->found &&
+	(new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
+      {
+	new->iface = iface;
+	new->next = daemon->listeners;
+	daemon->listeners = new;
+	iface->done = 1;
+      }
+
+  /* Check for --listen-address options that haven't been used because there's
+     no interface with a matching address. These may be valid: eg it's possible
+     to listen on 127.0.1.1 even if the loopback interface is 127.0.0.1
+
+     If the address isn't valid the bind() will fail and we'll die() 
+     (except in bind-dynamic mode, when we'll complain but keep trying.)
+
+     The resulting listeners have the ->iface field NULL, and this has to be
+     handled by the DNS and TFTP code. It disables --localise-queries processing
+     (no netmask) and some MTU login the tftp code. */
+
+  for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
+    if (!if_tmp->used && 
+	(new = create_listeners(&if_tmp->addr, !!option_bool(OPT_TFTP), dienow)))
+      {
+	new->next = daemon->listeners;
+	daemon->listeners = new;
+      }
+}
+
+/* In --bind-interfaces, the only access control is the addresses we're listening on. 
+   There's nothing to avoid a query to the address of an internal interface arriving via
+   an external interface where we don't want to accept queries, except that in the usual 
+   case the addresses of internal interfaces are RFC1918. When bind-interfaces in use, 
+   and we listen on an address that looks like it's probably globally routeable, shout.
+
+   The fix is to use --bind-dynamic, which actually checks the arrival interface too.
+   Tough if your platform doesn't support this.
+
+   Note that checking the arrival interface is supported in the standard IPv6 API and
+   always done, so we don't warn about any IPv6 addresses here.
+*/
+
+void warn_bound_listeners(void)
+{
+  struct irec *iface; 	
+  int advice = 0;
+
+  for (iface = daemon->interfaces; iface; iface = iface->next)
+    if (!iface->dns_auth)
+      {
+	if (iface->addr.sa.sa_family == AF_INET)
+	  {
+	    if (!private_net(iface->addr.in.sin_addr, 1))
+	      {
+		inet_ntop(AF_INET, &iface->addr.in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
+		iface->warned = advice = 1;
+		my_syslog(LOG_WARNING, 
+			  _("LOUD WARNING: listening on %s may accept requests via interfaces other than %s"),
+			  daemon->addrbuff, iface->name);
+	      }
+	  }
+      }
+  
+  if (advice)
+    my_syslog(LOG_WARNING, _("LOUD WARNING: use --bind-dynamic rather than --bind-interfaces to avoid DNS amplification attacks via these interface(s)")); 
+}
+
+void warn_wild_labels(void)
+{
+  struct irec *iface;
+
+  for (iface = daemon->interfaces; iface; iface = iface->next)
+    if (iface->found && iface->name && iface->label)
+      my_syslog(LOG_WARNING, _("warning: using interface %s instead"), iface->name);
+}
+
+void warn_int_names(void)
+{
+  struct interface_name *intname;
+ 
+  for (intname = daemon->int_names; intname; intname = intname->next)
+    if (!intname->addr)
+      my_syslog(LOG_WARNING, _("warning: no addresses found for interface %s"), intname->intr);
+}
+ 
+int is_dad_listeners(void)
+{
+  struct irec *iface;
+  
+  if (option_bool(OPT_NOWILD))
+    for (iface = daemon->interfaces; iface; iface = iface->next)
+      if (iface->dad && !iface->done)
+	return 1;
+  
+  return 0;
+}
+
+#ifdef HAVE_DHCP6
+void join_multicast(int dienow)      
+{
+  struct irec *iface, *tmp;
+
+  for (iface = daemon->interfaces; iface; iface = iface->next)
+    if (iface->addr.sa.sa_family == AF_INET6 && iface->dhcp_ok && !iface->multicast_done)
+      {
+	/* There's an irec per address but we only want to join for multicast 
+	   once per interface. Weed out duplicates. */
+	for (tmp = daemon->interfaces; tmp; tmp = tmp->next)
+	  if (tmp->multicast_done && tmp->index == iface->index)
+	    break;
+	
+	iface->multicast_done = 1;
+	
+	if (!tmp)
+	  {
+	    struct ipv6_mreq mreq;
+	    int err = 0;
+
+	    mreq.ipv6mr_interface = iface->index;
+	    
+	    inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
+	    
+	    if ((daemon->doing_dhcp6 || daemon->relay6) &&
+		setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
+	      err = errno;
+	    
+	    inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
+	    
+	    if (daemon->doing_dhcp6 && 
+		setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
+	      err = errno;
+	    
+	    inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
+	    
+	    if (daemon->doing_ra &&
+		setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
+	      err = errno;
+	    
+	    if (err)
+	      {
+		char *s = _("interface %s failed to join DHCPv6 multicast group: %s");
+		errno = err;
+
+#ifdef HAVE_LINUX_NETWORK
+		if (errno == ENOMEM)
+		  my_syslog(LOG_ERR, _("try increasing /proc/sys/net/core/optmem_max"));
+#endif
+
+		if (dienow)
+		  die(s, iface->name, EC_BADNET);
+		else
+		  my_syslog(LOG_ERR, s, iface->name, strerror(errno));
+	      }
+	  }
+      }
+}
+#endif
+
+/* return a UDP socket bound to a random port, have to cope with straying into
+   occupied port nos and reserved ones. */
+int random_sock(int family)
+{
+  int fd;
+
+  if ((fd = socket(family, SOCK_DGRAM, 0)) != -1)
+    {
+      union mysockaddr addr;
+      unsigned int ports_avail = ((unsigned short)daemon->max_port - (unsigned short)daemon->min_port) + 1;
+      int tries = ports_avail < 30 ? 3 * ports_avail : 100;
+
+      memset(&addr, 0, sizeof(addr));
+      addr.sa.sa_family = family;
+
+      /* don't loop forever if all ports in use. */
+
+      if (fix_fd(fd))
+	while(tries--)
+	  {
+	    unsigned short port = rand16();
+	    
+            if (daemon->min_port != 0 || daemon->max_port != MAX_PORT)
+              port = htons(daemon->min_port + (port % ((unsigned short)ports_avail)));
+	    
+	    if (family == AF_INET) 
+	      {
+		addr.in.sin_addr.s_addr = INADDR_ANY;
+		addr.in.sin_port = port;
+#ifdef HAVE_SOCKADDR_SA_LEN
+		addr.in.sin_len = sizeof(struct sockaddr_in);
+#endif
+	      }
+#ifdef HAVE_IPV6
+	    else
+	      {
+		addr.in6.sin6_addr = in6addr_any; 
+		addr.in6.sin6_port = port;
+#ifdef HAVE_SOCKADDR_SA_LEN
+		addr.in6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+	      }
+#endif
+	    
+	    if (bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == 0)
+	      return fd;
+	    
+	    if (errno != EADDRINUSE && errno != EACCES)
+	      break;
+	  }
+
+      close(fd);
+    }
+
+  return -1; 
+}
+  
+
+int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
+{
+  union mysockaddr addr_copy = *addr;
+
+  /* cannot set source _port_ for TCP connections. */
+  if (is_tcp)
+    {
+      if (addr_copy.sa.sa_family == AF_INET)
+	addr_copy.in.sin_port = 0;
+#ifdef HAVE_IPV6
+      else
+	addr_copy.in6.sin6_port = 0;
+#endif
+    }
+  
+  if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) == -1)
+    return 0;
+    
+#if defined(SO_BINDTODEVICE)
+  if (intname[0] != 0 &&
+      setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE) == -1)
+    return 0;
+#endif
+
+  return 1;
+}
+
+static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
+{
+  struct serverfd *sfd;
+  unsigned int ifindex = 0;
+  int errsave;
+
+  /* when using random ports, servers which would otherwise use
+     the INADDR_ANY/port0 socket have sfd set to NULL */
+  if (!daemon->osport && intname[0] == 0)
+    {
+      errno = 0;
+      
+      if (addr->sa.sa_family == AF_INET &&
+	  addr->in.sin_addr.s_addr == INADDR_ANY &&
+	  addr->in.sin_port == htons(0)) 
+	return NULL;
+
+#ifdef HAVE_IPV6
+      if (addr->sa.sa_family == AF_INET6 &&
+	  memcmp(&addr->in6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0 &&
+	  addr->in6.sin6_port == htons(0)) 
+	return NULL;
+#endif
+    }
+
+  if (intname && strlen(intname) != 0)
+    ifindex = if_nametoindex(intname); /* index == 0 when not binding to an interface */
+      
+  /* may have a suitable one already */
+  for (sfd = daemon->sfds; sfd; sfd = sfd->next )
+    if (sockaddr_isequal(&sfd->source_addr, addr) &&
+	strcmp(intname, sfd->interface) == 0 &&
+	ifindex == sfd->ifindex) 
+      return sfd;
+  
+  /* need to make a new one. */
+  errno = ENOMEM; /* in case malloc fails. */
+  if (!(sfd = whine_malloc(sizeof(struct serverfd))))
+    return NULL;
+  
+  if ((sfd->fd = socket(addr->sa.sa_family, SOCK_DGRAM, 0)) == -1)
+    {
+      free(sfd);
+      return NULL;
+    }
+  
+  if (!local_bind(sfd->fd, addr, intname, 0) || !fix_fd(sfd->fd))
+    { 
+      errsave = errno; /* save error from bind. */
+      close(sfd->fd);
+      free(sfd);
+      errno = errsave;
+      return NULL;
+    }
+
+  strcpy(sfd->interface, intname); 
+  sfd->source_addr = *addr;
+  sfd->next = daemon->sfds;
+  sfd->ifindex = ifindex;
+  daemon->sfds = sfd;
+
+  return sfd; 
+}
+
+/* create upstream sockets during startup, before root is dropped which may be needed
+   this allows query_port to be a low port and interface binding */
+void pre_allocate_sfds(void)
+{
+  struct server *srv;
+  
+  if (daemon->query_port != 0)
+    {
+      union  mysockaddr addr;
+      memset(&addr, 0, sizeof(addr));
+      addr.in.sin_family = AF_INET;
+      addr.in.sin_addr.s_addr = INADDR_ANY;
+      addr.in.sin_port = htons(daemon->query_port);
+#ifdef HAVE_SOCKADDR_SA_LEN
+      addr.in.sin_len = sizeof(struct sockaddr_in);
+#endif
+      allocate_sfd(&addr, "");
+#ifdef HAVE_IPV6
+      memset(&addr, 0, sizeof(addr));
+      addr.in6.sin6_family = AF_INET6;
+      addr.in6.sin6_addr = in6addr_any;
+      addr.in6.sin6_port = htons(daemon->query_port);
+#ifdef HAVE_SOCKADDR_SA_LEN
+      addr.in6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+      allocate_sfd(&addr, "");
+#endif
+    }
+  
+  for (srv = daemon->servers; srv; srv = srv->next)
+    if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
+	!allocate_sfd(&srv->source_addr, srv->interface) &&
+	errno != 0 &&
+	option_bool(OPT_NOWILD))
+      {
+	prettyprint_addr(&srv->source_addr, daemon->namebuff);
+	if (srv->interface[0] != 0)
+	  {
+	    strcat(daemon->namebuff, " ");
+	    strcat(daemon->namebuff, srv->interface);
+	  }
+	die(_("failed to bind server socket for %s: %s"),
+	    daemon->namebuff, EC_BADNET);
+      }  
+}
+
+void mark_servers(int flag)
+{
+  struct server *serv;
+
+  /* mark everything with argument flag */
+  for (serv = daemon->servers; serv; serv = serv->next)
+    {
+      if (serv->flags & flag)
+	serv->flags |= SERV_MARK;
+#ifdef HAVE_LOOP
+      /* Give looped servers another chance */
+      serv->flags &= ~SERV_LOOP;
+#endif
+    }
+}
+
+void cleanup_servers(void)
+{
+  struct server *serv, *tmp, **up;
+
+  /* unlink and free anything still marked. */
+  for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp) 
+    {
+      tmp = serv->next;
+      if (serv->flags & SERV_MARK)
+       {
+         server_gone(serv);
+         *up = serv->next;
+         if (serv->domain)
+	   free(serv->domain);
+	 free(serv);
+       }
+      else 
+       up = &serv->next;
+    }
+
+#ifdef HAVE_LOOP
+  /* Now we have a new set of servers, test for loops. */
+  loop_send_probes();
+#endif
+}
+
+void add_update_server(int flags,
+		       union mysockaddr *addr,
+		       union mysockaddr *source_addr,
+		       const char *interface,
+		       const char *domain)
+{
+  struct server *serv, *next = NULL;
+  char *domain_str = NULL;
+  
+  /* See if there is a suitable candidate, and unmark */
+  for (serv = daemon->servers; serv; serv = serv->next)
+    if (serv->flags & SERV_MARK)
+      {
+	if (domain)
+	  {
+	    if (!(serv->flags & SERV_HAS_DOMAIN) || !hostname_isequal(domain, serv->domain))
+	      continue;
+	  }
+	else
+	  {
+	    if (serv->flags & SERV_HAS_DOMAIN)
+	      continue;
+	  }
+	
+        break;
+      }
+
+  if (serv)
+    {
+      domain_str = serv->domain;
+      next = serv->next;
+    }
+  else if ((serv = whine_malloc(sizeof (struct server))))
+    {
+      /* Not found, create a new one. */
+      if (domain && !(domain_str = whine_malloc(strlen(domain)+1)))
+	{
+	  free(serv);
+          serv = NULL;
+        }
+      else
+        {
+	  struct server *s;
+	  /* Add to the end of the chain, for order */
+	  if (!daemon->servers)
+	    daemon->servers = serv;
+	  else
+	    {
+	      for (s = daemon->servers; s->next; s = s->next);
+	      s->next = serv;
+	    }
+	  if (domain)
+	    strcpy(domain_str, domain);
+	}
+    }
+  
+  if (serv)
+    {
+      memset(serv, 0, sizeof(struct server));
+      serv->flags = flags;
+      serv->domain = domain_str;
+      serv->next = next;
+      serv->queries = serv->failed_queries = 0;
+#ifdef HAVE_LOOP
+      serv->uid = rand32();
+#endif      
+
+      if (domain)
+	serv->flags |= SERV_HAS_DOMAIN;
+      
+      if (interface)
+	strcpy(serv->interface, interface);      
+      if (addr)
+	serv->addr = *addr;
+      if (source_addr)
+	serv->source_addr = *source_addr;
+    }
+}
+
+void check_servers(void)
+{
+  struct irec *iface;
+  struct server *serv;
+  struct serverfd *sfd, *tmp, **up;
+  int port = 0, count;
+  int locals = 0;
+
+  /* interface may be new since startup */
+  if (!option_bool(OPT_NOWILD))
+    enumerate_interfaces(0);
+  
+  for (sfd = daemon->sfds; sfd; sfd = sfd->next)
+    sfd->used = 0;
+
+#ifdef HAVE_DNSSEC
+ /* Disable DNSSEC validation when using server=/domain/.... servers
+    unless there's a configured trust anchor. */
+  for (serv = daemon->servers; serv; serv = serv->next)
+    serv->flags |= SERV_DO_DNSSEC;
+#endif
+
+  for (count = 0, serv = daemon->servers; serv; serv = serv->next)
+    {
+      if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
+	{
+	  /* Init edns_pktsz for newly created server records. */
+	  if (serv->edns_pktsz == 0)
+	    serv->edns_pktsz = daemon->edns_pktsz;
+	  
+#ifdef HAVE_DNSSEC
+	  if (option_bool(OPT_DNSSEC_VALID))
+	    { 
+	      if (serv->flags & SERV_HAS_DOMAIN)
+		{
+		  struct ds_config *ds;
+		  char *domain = serv->domain;
+		  
+		  /* .example.com is valid */
+		  while (*domain == '.')
+		    domain++;
+		  
+		  for (ds = daemon->ds; ds; ds = ds->next)
+		    if (ds->name[0] != 0 && hostname_isequal(domain, ds->name))
+		      break;
+		  
+		  if (!ds)
+		    serv->flags &= ~SERV_DO_DNSSEC;
+		}
+	      else if (serv->flags & SERV_FOR_NODOTS) 
+		serv->flags &= ~SERV_DO_DNSSEC;
+	    }
+#endif
+
+	  port = prettyprint_addr(&serv->addr, daemon->namebuff);
+	  
+	  /* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
+	  if (serv->addr.sa.sa_family == AF_INET &&
+	      serv->addr.in.sin_addr.s_addr == 0)
+	    {
+	      serv->flags |= SERV_MARK;
+	      continue;
+	    }
+
+	  for (iface = daemon->interfaces; iface; iface = iface->next)
+	    if (sockaddr_isequal(&serv->addr, &iface->addr))
+	      break;
+	  if (iface)
+	    {
+	      my_syslog(LOG_WARNING, _("ignoring nameserver %s - local interface"), daemon->namebuff);
+	      serv->flags |= SERV_MARK;
+	      continue;
+	    }
+	  
+	  /* Do we need a socket set? */
+	  if (!serv->sfd && 
+	      !(serv->sfd = allocate_sfd(&serv->source_addr, serv->interface)) &&
+	      errno != 0)
+	    {
+	      my_syslog(LOG_WARNING, 
+			_("ignoring nameserver %s - cannot make/bind socket: %s"),
+			daemon->namebuff, strerror(errno));
+	      serv->flags |= SERV_MARK;
+	      continue;
+	    }
+	  
+	  if (serv->sfd)
+	    serv->sfd->used = 1;
+	}
+      
+      if (!(serv->flags & SERV_NO_REBIND) && !(serv->flags & SERV_LITERAL_ADDRESS))
+	{
+	  if (++count > SERVERS_LOGGED)
+	    continue;
+	  
+	  if (serv->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV))
+	    {
+	      char *s1, *s2, *s3 = "";
+#ifdef HAVE_DNSSEC
+	      if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC))
+		s3 = _("(no DNSSEC)");
+#endif
+	      if (!(serv->flags & SERV_HAS_DOMAIN))
+		s1 = _("unqualified"), s2 = _("names");
+	      else if (strlen(serv->domain) == 0)
+		s1 = _("default"), s2 = "";
+	      else
+		s1 = _("domain"), s2 = serv->domain;
+	      
+	      if (serv->flags & SERV_NO_ADDR)
+		{
+		  count--;
+		  if (++locals <= LOCALS_LOGGED)
+			my_syslog(LOG_INFO, _("using local addresses only for %s %s"), s1, s2);
+	        }
+	      else if (serv->flags & SERV_USE_RESOLV)
+		my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2);
+	      else 
+		my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s %s"), daemon->namebuff, port, s1, s2, s3);
+	    }
+#ifdef HAVE_LOOP
+	  else if (serv->flags & SERV_LOOP)
+	    my_syslog(LOG_INFO, _("NOT using nameserver %s#%d - query loop detected"), daemon->namebuff, port); 
+#endif
+	  else if (serv->interface[0] != 0)
+	    my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, serv->interface); 
+	  else
+	    my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port); 
+	}
+    }
+  
+  if (locals > LOCALS_LOGGED)
+    my_syslog(LOG_INFO, _("using %d more local addresses"), locals - LOCALS_LOGGED);
+  if (count - 1 > SERVERS_LOGGED)
+    my_syslog(LOG_INFO, _("using %d more nameservers"), count - SERVERS_LOGGED - 1);
+
+  /* Remove unused sfds */
+  for (sfd = daemon->sfds, up = &daemon->sfds; sfd; sfd = tmp)
+    {
+       tmp = sfd->next;
+       if (!sfd->used) 
+	{
+	  *up = sfd->next;
+	  close(sfd->fd);
+	  free(sfd);
+	} 
+      else
+	up = &sfd->next;
+    }
+  
+  cleanup_servers();
+}
+
+/* Return zero if no servers found, in that case we keep polling.
+   This is a protection against an update-time/write race on resolv.conf */
+int reload_servers(char *fname)
+{
+  FILE *f;
+  char *line;
+  int gotone = 0;
+
+  /* buff happens to be MAXDNAME long... */
+  if (!(f = fopen(fname, "r")))
+    {
+      my_syslog(LOG_ERR, _("failed to read %s: %s"), fname, strerror(errno));
+      return 0;
+    }
+   
+  mark_servers(SERV_FROM_RESOLV);
+    
+  while ((line = fgets(daemon->namebuff, MAXDNAME, f)))
+    {
+      union mysockaddr addr, source_addr;
+      char *token = strtok(line, " \t\n\r");
+      
+      if (!token)
+	continue;
+      if (strcmp(token, "nameserver") != 0 && strcmp(token, "server") != 0)
+	continue;
+      if (!(token = strtok(NULL, " \t\n\r")))
+	continue;
+      
+      memset(&addr, 0, sizeof(addr));
+      memset(&source_addr, 0, sizeof(source_addr));
+      
+      if ((addr.in.sin_addr.s_addr = inet_addr(token)) != (in_addr_t) -1)
+	{
+#ifdef HAVE_SOCKADDR_SA_LEN
+	  source_addr.in.sin_len = addr.in.sin_len = sizeof(source_addr.in);
+#endif
+	  source_addr.in.sin_family = addr.in.sin_family = AF_INET;
+	  addr.in.sin_port = htons(NAMESERVER_PORT);
+	  source_addr.in.sin_addr.s_addr = INADDR_ANY;
+	  source_addr.in.sin_port = htons(daemon->query_port);
+	}
+#ifdef HAVE_IPV6
+      else 
+	{	
+	  int scope_index = 0;
+	  char *scope_id = strchr(token, '%');
+	  
+	  if (scope_id)
+	    {
+	      *(scope_id++) = 0;
+	      scope_index = if_nametoindex(scope_id);
+	    }
+	  
+	  if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0)
+	    {
+#ifdef HAVE_SOCKADDR_SA_LEN
+	      source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(source_addr.in6);
+#endif
+	      source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
+	      source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = 0;
+	      addr.in6.sin6_port = htons(NAMESERVER_PORT);
+	      addr.in6.sin6_scope_id = scope_index;
+	      source_addr.in6.sin6_addr = in6addr_any;
+	      source_addr.in6.sin6_port = htons(daemon->query_port);
+	      source_addr.in6.sin6_scope_id = 0;
+	    }
+	  else
+	    continue;
+	}
+#else /* IPV6 */
+      else
+	continue;
+#endif 
+
+      add_update_server(SERV_FROM_RESOLV, &addr, &source_addr, NULL, NULL);
+      gotone = 1;
+    }
+  
+  fclose(f);
+  cleanup_servers();
+
+  return gotone;
+}
+
+/* Called when addresses are added or deleted from an interface */
+void newaddress(time_t now)
+{
+  (void)now;
+  
+  if (option_bool(OPT_CLEVERBIND) || option_bool(OPT_LOCAL_SERVICE) ||
+      daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
+    enumerate_interfaces(0);
+  
+  if (option_bool(OPT_CLEVERBIND))
+    create_bound_listeners(0);
+  
+#ifdef HAVE_DHCP6
+  if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
+    join_multicast(0);
+  
+  if (daemon->doing_dhcp6 || daemon->doing_ra)
+    dhcp_construct_contexts(now);
+  
+  if (daemon->doing_dhcp6)
+    lease_find_interfaces(now);
+#endif
+}
+
+
+
+
+
diff --git a/src/option.c b/src/option.c
new file mode 100755
index 0000000..f4d22a2
--- /dev/null
+++ b/src/option.c
@@ -0,0 +1,4925 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* define this to get facilitynames */
+#define SYSLOG_NAMES
+#include "dnsmasq.h"
+#include <setjmp.h>
+
+static volatile int mem_recover = 0;
+static jmp_buf mem_jmp;
+static int one_file(char *file, int hard_opt);
+
+/* Solaris headers don't have facility names. */
+#ifdef HAVE_SOLARIS_NETWORK
+static const struct {
+  char *c_name;
+  unsigned int c_val;
+}  facilitynames[] = {
+  { "kern",   LOG_KERN },
+  { "user",   LOG_USER },
+  { "mail",   LOG_MAIL },
+  { "daemon", LOG_DAEMON },
+  { "auth",   LOG_AUTH },
+  { "syslog", LOG_SYSLOG },
+  { "lpr",    LOG_LPR },
+  { "news",   LOG_NEWS },
+  { "uucp",   LOG_UUCP },
+  { "audit",  LOG_AUDIT },
+  { "cron",   LOG_CRON },
+  { "local0", LOG_LOCAL0 },
+  { "local1", LOG_LOCAL1 },
+  { "local2", LOG_LOCAL2 },
+  { "local3", LOG_LOCAL3 },
+  { "local4", LOG_LOCAL4 },
+  { "local5", LOG_LOCAL5 },
+  { "local6", LOG_LOCAL6 },
+  { "local7", LOG_LOCAL7 },
+  { NULL, 0 }
+};
+#endif
+
+#ifndef HAVE_GETOPT_LONG
+struct myoption {
+  const char *name;
+  int has_arg;
+  int *flag;
+  int val;
+};
+#endif
+
+#define OPTSTRING "951yZDNLERKzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:J:W:Y:2:4:6:7:8:0:3:"
+
+/* options which don't have a one-char version */
+#define LOPT_RELOAD        256
+#define LOPT_NO_NAMES      257
+#define LOPT_TFTP          258
+#define LOPT_SECURE        259
+#define LOPT_PREFIX        260
+#define LOPT_PTR           261
+#define LOPT_BRIDGE        262
+#define LOPT_TFTP_MAX      263
+#define LOPT_FORCE         264
+#define LOPT_NOBLOCK       265
+#define LOPT_LOG_OPTS      266
+#define LOPT_MAX_LOGS      267
+#define LOPT_CIRCUIT       268
+#define LOPT_REMOTE        269
+#define LOPT_SUBSCR        270
+#define LOPT_INTNAME       271
+#define LOPT_BANK          272
+#define LOPT_DHCP_HOST     273
+#define LOPT_APREF         274
+#define LOPT_OVERRIDE      275
+#define LOPT_TFTPPORTS     276
+#define LOPT_REBIND        277
+#define LOPT_NOLAST        278
+#define LOPT_OPTS          279
+#define LOPT_DHCP_OPTS     280
+#define LOPT_MATCH         281
+#define LOPT_BROADCAST     282
+#define LOPT_NEGTTL        283
+#define LOPT_ALTPORT       284
+#define LOPT_SCRIPTUSR     285
+#define LOPT_LOCAL         286
+#define LOPT_NAPTR         287
+#define LOPT_MINPORT       288
+#define LOPT_DHCP_FQDN     289
+#define LOPT_CNAME         290
+#define LOPT_PXE_PROMT     291
+#define LOPT_PXE_SERV      292
+#define LOPT_TEST          293
+#define LOPT_TAG_IF        294
+#define LOPT_PROXY         295
+#define LOPT_GEN_NAMES     296
+#define LOPT_MAXTTL        297
+#define LOPT_NO_REBIND     298
+#define LOPT_LOC_REBND     299
+#define LOPT_ADD_MAC       300
+#define LOPT_DNSSEC        301
+#define LOPT_INCR_ADDR     302
+#define LOPT_CONNTRACK     303
+#define LOPT_FQDN          304
+#define LOPT_LUASCRIPT     305
+#define LOPT_RA            306
+#define LOPT_DUID          307
+#define LOPT_HOST_REC      308
+#define LOPT_TFTP_LC       309
+#define LOPT_RR            310
+#define LOPT_CLVERBIND     311
+#define LOPT_MAXCTTL       312
+#define LOPT_AUTHZONE      313
+#define LOPT_AUTHSERV      314
+#define LOPT_AUTHTTL       315
+#define LOPT_AUTHSOA       316
+#define LOPT_AUTHSFS       317
+#define LOPT_AUTHPEER      318
+#define LOPT_IPSET         319
+#define LOPT_SYNTH         320
+#ifdef OPTION6_PREFIX_CLASS 
+#define LOPT_PREF_CLSS     321
+#endif
+#define LOPT_RELAY         323
+#define LOPT_RA_PARAM      324
+#define LOPT_ADD_SBNET     325
+#define LOPT_QUIET_DHCP    326
+#define LOPT_QUIET_DHCP6   327
+#define LOPT_QUIET_RA      328
+#define LOPT_SEC_VALID     329
+#define LOPT_TRUST_ANCHOR  330
+#define LOPT_DNSSEC_DEBUG  331
+#define LOPT_REV_SERV      332
+#define LOPT_SERVERS_FILE  333
+#define LOPT_DNSSEC_CHECK  334
+#define LOPT_LOCAL_SERVICE 335
+#define LOPT_DNSSEC_TIME   336
+#define LOPT_LOOP_DETECT   337
+#define LOPT_IGNORE_ADDR   338
+#define LOPT_MINCTTL       339
+#define LOPT_DHCP_INOTIFY  340
+#define LOPT_DHOPT_INOTIFY 341
+#define LOPT_HOST_INOTIFY  342
+#define LOPT_DNSSEC_STAMP  343
+#define LOPT_TFTP_NO_FAIL  344
+#define LOPT_MAXPORT       345
+#define LOPT_CPE_ID        346
+#define LOPT_SCRIPT_ARP    347
+#define LOPT_DHCPTTL       348
+#define LOPT_TFTP_MTU      349
+#define LOPT_REPLY_DELAY   350
+ 
+#ifdef HAVE_GETOPT_LONG
+static const struct option opts[] =  
+#else
+static const struct myoption opts[] = 
+#endif
+  { 
+    { "version", 0, 0, 'v' },
+    { "no-hosts", 0, 0, 'h' },
+    { "no-poll", 0, 0, 'n' },
+    { "help", 0, 0, 'w' },
+    { "no-daemon", 0, 0, 'd' },
+    { "log-queries", 2, 0, 'q' },
+    { "user", 2, 0, 'u' },
+    { "group", 2, 0, 'g' },
+    { "resolv-file", 2, 0, 'r' },
+    { "servers-file", 1, 0, LOPT_SERVERS_FILE },
+    { "mx-host", 1, 0, 'm' },
+    { "mx-target", 1, 0, 't' },
+    { "cache-size", 2, 0, 'c' },
+    { "port", 1, 0, 'p' },
+    { "dhcp-leasefile", 2, 0, 'l' },
+    { "dhcp-lease", 1, 0, 'l' },
+    { "dhcp-host", 1, 0, 'G' },
+    { "dhcp-range", 1, 0, 'F' },
+    { "dhcp-option", 1, 0, 'O' },
+    { "dhcp-boot", 1, 0, 'M' },
+    { "domain", 1, 0, 's' },
+    { "domain-suffix", 1, 0, 's' },
+    { "interface", 1, 0, 'i' },
+    { "listen-address", 1, 0, 'a' },
+    { "local-service", 0, 0, LOPT_LOCAL_SERVICE },
+    { "bogus-priv", 0, 0, 'b' },
+    { "bogus-nxdomain", 1, 0, 'B' },
+    { "ignore-address", 1, 0, LOPT_IGNORE_ADDR },
+    { "selfmx", 0, 0, 'e' },
+    { "filterwin2k", 0, 0, 'f' },
+    { "pid-file", 2, 0, 'x' },
+    { "strict-order", 0, 0, 'o' },
+    { "server", 1, 0, 'S' },
+    { "rev-server", 1, 0, LOPT_REV_SERV },
+    { "local", 1, 0, LOPT_LOCAL },
+    { "address", 1, 0, 'A' },
+    { "conf-file", 2, 0, 'C' },
+    { "no-resolv", 0, 0, 'R' },
+    { "expand-hosts", 0, 0, 'E' },
+    { "localmx", 0, 0, 'L' },
+    { "local-ttl", 1, 0, 'T' },
+    { "no-negcache", 0, 0, 'N' },
+    { "addn-hosts", 1, 0, 'H' },
+    { "hostsdir", 1, 0, LOPT_HOST_INOTIFY },
+    { "query-port", 1, 0, 'Q' },
+    { "except-interface", 1, 0, 'I' },
+    { "no-dhcp-interface", 1, 0, '2' },
+    { "domain-needed", 0, 0, 'D' },
+    { "dhcp-lease-max", 1, 0, 'X' },
+    { "bind-interfaces", 0, 0, 'z' },
+    { "read-ethers", 0, 0, 'Z' },
+    { "alias", 1, 0, 'V' },
+    { "dhcp-vendorclass", 1, 0, 'U' },
+    { "dhcp-userclass", 1, 0, 'j' },
+    { "dhcp-ignore", 1, 0, 'J' },
+    { "edns-packet-max", 1, 0, 'P' },
+    { "keep-in-foreground", 0, 0, 'k' },
+    { "dhcp-authoritative", 0, 0, 'K' },
+    { "srv-host", 1, 0, 'W' },
+    { "localise-queries", 0, 0, 'y' },
+    { "txt-record", 1, 0, 'Y' },
+    { "dns-rr", 1, 0, LOPT_RR },
+    { "enable-dbus", 2, 0, '1' },
+    { "bootp-dynamic", 2, 0, '3' },
+    { "dhcp-mac", 1, 0, '4' },
+    { "no-ping", 0, 0, '5' },
+    { "dhcp-script", 1, 0, '6' },
+    { "conf-dir", 1, 0, '7' },
+    { "log-facility", 1, 0 ,'8' },
+    { "leasefile-ro", 0, 0, '9' },
+    { "dns-forward-max", 1, 0, '0' },
+    { "clear-on-reload", 0, 0, LOPT_RELOAD },
+    { "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
+    { "enable-tftp", 2, 0, LOPT_TFTP },
+    { "tftp-secure", 0, 0, LOPT_SECURE },
+    { "tftp-no-fail", 0, 0, LOPT_TFTP_NO_FAIL },
+    { "tftp-unique-root", 2, 0, LOPT_APREF },
+    { "tftp-root", 1, 0, LOPT_PREFIX },
+    { "tftp-max", 1, 0, LOPT_TFTP_MAX },
+    { "tftp-mtu", 1, 0, LOPT_TFTP_MTU },
+    { "tftp-lowercase", 0, 0, LOPT_TFTP_LC },
+    { "ptr-record", 1, 0, LOPT_PTR },
+    { "naptr-record", 1, 0, LOPT_NAPTR },
+    { "bridge-interface", 1, 0 , LOPT_BRIDGE },
+    { "dhcp-option-force", 1, 0, LOPT_FORCE },
+    { "tftp-no-blocksize", 0, 0, LOPT_NOBLOCK },
+    { "log-dhcp", 0, 0, LOPT_LOG_OPTS },
+    { "log-async", 2, 0, LOPT_MAX_LOGS },
+    { "dhcp-circuitid", 1, 0, LOPT_CIRCUIT },
+    { "dhcp-remoteid", 1, 0, LOPT_REMOTE },
+    { "dhcp-subscrid", 1, 0, LOPT_SUBSCR },
+    { "interface-name", 1, 0, LOPT_INTNAME },
+    { "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
+    { "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
+    { "dhcp-hostsdir", 1, 0, LOPT_DHCP_INOTIFY },
+    { "dhcp-optsdir", 1, 0, LOPT_DHOPT_INOTIFY },
+    { "dhcp-no-override", 0, 0, LOPT_OVERRIDE },
+    { "tftp-port-range", 1, 0, LOPT_TFTPPORTS },
+    { "stop-dns-rebind", 0, 0, LOPT_REBIND },
+    { "rebind-domain-ok", 1, 0, LOPT_NO_REBIND },
+    { "all-servers", 0, 0, LOPT_NOLAST }, 
+    { "dhcp-match", 1, 0, LOPT_MATCH }, 
+    { "dhcp-broadcast", 2, 0, LOPT_BROADCAST },
+    { "neg-ttl", 1, 0, LOPT_NEGTTL },
+    { "max-ttl", 1, 0, LOPT_MAXTTL },
+    { "min-cache-ttl", 1, 0, LOPT_MINCTTL },
+    { "max-cache-ttl", 1, 0, LOPT_MAXCTTL },
+    { "dhcp-alternate-port", 2, 0, LOPT_ALTPORT },
+    { "dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },
+    { "min-port", 1, 0, LOPT_MINPORT },
+    { "max-port", 1, 0, LOPT_MAXPORT },
+    { "dhcp-fqdn", 0, 0, LOPT_DHCP_FQDN },
+    { "cname", 1, 0, LOPT_CNAME },
+    { "pxe-prompt", 1, 0, LOPT_PXE_PROMT },
+    { "pxe-service", 1, 0, LOPT_PXE_SERV },
+    { "test", 0, 0, LOPT_TEST },
+    { "tag-if", 1, 0, LOPT_TAG_IF },
+    { "dhcp-proxy", 2, 0, LOPT_PROXY },
+    { "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES },
+    { "rebind-localhost-ok", 0, 0,  LOPT_LOC_REBND },
+    { "add-mac", 2, 0, LOPT_ADD_MAC },
+    { "add-subnet", 2, 0, LOPT_ADD_SBNET },
+    { "add-cpe-id", 1, 0 , LOPT_CPE_ID },
+    { "proxy-dnssec", 0, 0, LOPT_DNSSEC },
+    { "dhcp-sequential-ip", 0, 0,  LOPT_INCR_ADDR },
+    { "conntrack", 0, 0, LOPT_CONNTRACK },
+    { "dhcp-client-update", 0, 0, LOPT_FQDN },
+    { "dhcp-luascript", 1, 0, LOPT_LUASCRIPT },
+    { "enable-ra", 0, 0, LOPT_RA },
+    { "dhcp-duid", 1, 0, LOPT_DUID },
+    { "host-record", 1, 0, LOPT_HOST_REC },
+    { "bind-dynamic", 0, 0, LOPT_CLVERBIND },
+    { "auth-zone", 1, 0, LOPT_AUTHZONE },
+    { "auth-server", 1, 0, LOPT_AUTHSERV },
+    { "auth-ttl", 1, 0, LOPT_AUTHTTL },
+    { "auth-soa", 1, 0, LOPT_AUTHSOA },
+    { "auth-sec-servers", 1, 0, LOPT_AUTHSFS },
+    { "auth-peer", 1, 0, LOPT_AUTHPEER }, 
+    { "ipset", 1, 0, LOPT_IPSET },
+    { "synth-domain", 1, 0, LOPT_SYNTH },
+    { "dnssec", 0, 0, LOPT_SEC_VALID },
+    { "trust-anchor", 1, 0, LOPT_TRUST_ANCHOR },
+    { "dnssec-debug", 0, 0, LOPT_DNSSEC_DEBUG },
+    { "dnssec-check-unsigned", 0, 0, LOPT_DNSSEC_CHECK },
+    { "dnssec-no-timecheck", 0, 0, LOPT_DNSSEC_TIME },
+    { "dnssec-timestamp", 1, 0, LOPT_DNSSEC_STAMP },
+#ifdef OPTION6_PREFIX_CLASS 
+    { "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
+#endif
+    { "dhcp-relay", 1, 0, LOPT_RELAY },
+    { "ra-param", 1, 0, LOPT_RA_PARAM },
+    { "quiet-dhcp", 0, 0, LOPT_QUIET_DHCP },
+    { "quiet-dhcp6", 0, 0, LOPT_QUIET_DHCP6 },
+    { "quiet-ra", 0, 0, LOPT_QUIET_RA },
+    { "dns-loop-detect", 0, 0, LOPT_LOOP_DETECT },
+    { "script-arp", 0, 0, LOPT_SCRIPT_ARP },
+    { "dhcp-ttl", 1, 0 , LOPT_DHCPTTL },
+    { "dhcp-reply-delay", 1, 0, LOPT_REPLY_DELAY },
+    { NULL, 0, 0, 0 }
+  };
+
+
+#define ARG_DUP       OPT_LAST
+#define ARG_ONE       OPT_LAST + 1
+#define ARG_USED_CL   OPT_LAST + 2
+#define ARG_USED_FILE OPT_LAST + 3
+
+static struct {
+  int opt;
+  unsigned int rept;
+  char * const flagdesc;
+  char * const desc;
+  char * const arg;
+} usage[] = {
+  { 'a', ARG_DUP, "<ipaddr>",  gettext_noop("Specify local address(es) to listen on."), NULL },
+  { 'A', ARG_DUP, "/<domain>/<ipaddr>", gettext_noop("Return ipaddr for all hosts in specified domains."), NULL },
+  { 'b', OPT_BOGUSPRIV, NULL, gettext_noop("Fake reverse lookups for RFC1918 private address ranges."), NULL },
+  { 'B', ARG_DUP, "<ipaddr>", gettext_noop("Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."), NULL }, 
+  { 'c', ARG_ONE, "<integer>", gettext_noop("Specify the size of the cache in entries (defaults to %s)."), "$" },
+  { 'C', ARG_DUP, "<path>", gettext_noop("Specify configuration file (defaults to %s)."), CONFFILE },
+  { 'd', OPT_DEBUG, NULL, gettext_noop("Do NOT fork into the background: run in debug mode."), NULL },
+  { 'D', OPT_NODOTS_LOCAL, NULL, gettext_noop("Do NOT forward queries with no domain part."), NULL }, 
+  { 'e', OPT_SELFMX, NULL, gettext_noop("Return self-pointing MX records for local hosts."), NULL },
+  { 'E', OPT_EXPAND, NULL, gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL },
+  { 'f', OPT_FILTER, NULL, gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL },
+  { 'F', ARG_DUP, "<ipaddr>,...", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
+  { 'g', ARG_ONE, "<groupname>", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
+  { 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
+  { LOPT_DHCP_HOST, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from file."), NULL },
+  { LOPT_DHCP_OPTS, ARG_DUP, "<path>", gettext_noop("Read DHCP option specs from file."), NULL },
+  { LOPT_DHCP_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from a directory."), NULL }, 
+  { LOPT_DHOPT_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read DHCP options from a directory."), NULL }, 
+  { LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL },
+  { 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
+  { 'H', ARG_DUP, "<path>", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
+  { LOPT_HOST_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read hosts files from a directory."), NULL },
+  { 'i', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) to listen on."), NULL },
+  { 'I', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) NOT to listen on.") , NULL },
+  { 'j', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL },
+  { LOPT_CIRCUIT, ARG_DUP, "set:<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
+  { LOPT_REMOTE, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
+  { LOPT_SUBSCR, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
+  { 'J', ARG_DUP, "tag:<tag>...", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
+  { LOPT_BROADCAST, ARG_DUP, "[=tag:<tag>...]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL }, 
+  { 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
+  { 'K', OPT_AUTHORITATIVE, NULL, gettext_noop("Assume we are the only DHCP server on the local network."), NULL },
+  { 'l', ARG_ONE, "<path>", gettext_noop("Specify where to store DHCP leases (defaults to %s)."), LEASEFILE },
+  { 'L', OPT_LOCALMX, NULL, gettext_noop("Return MX records for local hosts."), NULL },
+  { 'm', ARG_DUP, "<host_name>,<target>,<pref>", gettext_noop("Specify an MX record."), NULL },
+  { 'M', ARG_DUP, "<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL },
+  { 'n', OPT_NO_POLL, NULL, gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE }, 
+  { 'N', OPT_NO_NEG, NULL, gettext_noop("Do NOT cache failed search results."), NULL },
+  { 'o', OPT_ORDER, NULL, gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE },
+  { 'O', ARG_DUP, "<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL },
+  { LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL},
+  { 'p', ARG_ONE, "<integer>", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
+  { 'P', ARG_ONE, "<integer>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
+  { 'q', ARG_DUP, NULL, gettext_noop("Log DNS queries."), NULL },
+  { 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
+  { 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },
+  { 'r', ARG_DUP, "<path>", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE }, 
+  { LOPT_SERVERS_FILE, ARG_ONE, "<path>", gettext_noop("Specify path to file with server= options"), NULL },
+  { 'S', ARG_DUP, "/<domain>/<ipaddr>", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL },
+  { LOPT_REV_SERV, ARG_DUP, "<addr>/<prefix>,<ipaddr>", gettext_noop("Specify address of upstream servers for reverse address queries"), NULL },
+  { LOPT_LOCAL, ARG_DUP, "/<domain>/", gettext_noop("Never forward queries to specified domains."), NULL },
+  { 's', ARG_DUP, "<domain>[,<range>]", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL },
+  { 't', ARG_ONE, "<host_name>", gettext_noop("Specify default target in an MX record."), NULL },
+  { 'T', ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
+  { LOPT_NEGTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
+  { LOPT_MAXTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for maximum TTL to send to clients."), NULL },
+  { LOPT_MAXCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live ceiling for cache."), NULL },
+  { LOPT_MINCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live floor for cache."), NULL },
+  { 'u', ARG_ONE, "<username>", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER }, 
+  { 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
+  { 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },
+  { 'V', ARG_DUP, "<ipaddr>,<ipaddr>,<netmask>", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL },
+  { 'W', ARG_DUP, "<name>,<target>,...", gettext_noop("Specify a SRV record."), NULL },
+  { 'w', 0, NULL, gettext_noop("Display this message. Use --help dhcp or --help dhcp6 for known DHCP options."), NULL },
+  { 'x', ARG_ONE, "<path>", gettext_noop("Specify path of PID file (defaults to %s)."), RUNFILE },
+  { 'X', ARG_ONE, "<integer>", gettext_noop("Specify maximum number of DHCP leases (defaults to %s)."), "&" },
+  { 'y', OPT_LOCALISE, NULL, gettext_noop("Answer DNS queries based on the interface a query was sent to."), NULL },
+  { 'Y', ARG_DUP, "<name>,<txt>[,<txt]", gettext_noop("Specify TXT DNS record."), NULL },
+  { LOPT_PTR, ARG_DUP, "<name>,<target>", gettext_noop("Specify PTR DNS record."), NULL },
+  { LOPT_INTNAME, ARG_DUP, "<name>,<interface>", gettext_noop("Give DNS name to IPv4 address of interface."), NULL },
+  { 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL },
+  { 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
+  { '1', ARG_ONE, "[=<busname>]", gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
+  { '2', ARG_DUP, "<interface>", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
+  { '3', ARG_DUP, "[=tag:<tag>]...", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
+  { '4', ARG_DUP, "set:<tag>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
+  { LOPT_BRIDGE, ARG_DUP, "<iface>,<alias>..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL },
+  { '5', OPT_NO_PING, NULL, gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL },
+  { '6', ARG_ONE, "<path>", gettext_noop("Shell script to run on DHCP lease creation and destruction."), NULL },
+  { LOPT_LUASCRIPT, ARG_DUP, "path", gettext_noop("Lua script to run on DHCP lease creation and destruction."), NULL },
+  { LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change scripts as this user."), NULL },
+  { LOPT_SCRIPT_ARP, OPT_SCRIPT_ARP, NULL, gettext_noop("Call dhcp-script with changes to local ARP table."), NULL },
+  { '7', ARG_DUP, "<path>", gettext_noop("Read configuration from all the files in this directory."), NULL },
+  { '8', ARG_ONE, "<facility>|<file>", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL },
+  { '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL },
+  { '0', ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" }, 
+  { LOPT_RELOAD, OPT_RELOAD, NULL, gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
+  { LOPT_NO_NAMES, ARG_DUP, "[=tag:<tag>]...", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
+  { LOPT_OVERRIDE, OPT_NO_OVERRIDE, NULL, gettext_noop("Do NOT reuse filename and server fields for extra DHCP options."), NULL },
+  { LOPT_TFTP, ARG_DUP, "[=<intr>[,<intr>]]", gettext_noop("Enable integrated read-only TFTP server."), NULL },
+  { LOPT_PREFIX, ARG_DUP, "<dir>[,<iface>]", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
+  { LOPT_APREF, ARG_DUP, "[=ip|mac]", gettext_noop("Add client IP or hardware address to tftp-root."), NULL },
+  { LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
+  { LOPT_TFTP_NO_FAIL, OPT_TFTP_NO_FAIL, NULL, gettext_noop("Do not terminate the service if TFTP directories are inaccessible."), NULL },
+  { LOPT_TFTP_MAX, ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent TFTP transfers (defaults to %s)."), "#" },
+  { LOPT_TFTP_MTU, ARG_ONE, "<integer>", gettext_noop("Maximum MTU to use for TFTP transfers."), NULL },
+  { LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },
+  { LOPT_TFTP_LC, OPT_TFTP_LC, NULL, gettext_noop("Convert TFTP filenames to lowercase"), NULL },
+  { LOPT_TFTPPORTS, ARG_ONE, "<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL },
+  { LOPT_LOG_OPTS, OPT_LOG_OPTS, NULL, gettext_noop("Extra logging for DHCP."), NULL },
+  { LOPT_MAX_LOGS, ARG_ONE, "[=<integer>]", gettext_noop("Enable async. logging; optionally set queue length."), NULL },
+  { LOPT_REBIND, OPT_NO_REBIND, NULL, gettext_noop("Stop DNS rebinding. Filter private IP ranges when resolving."), NULL },
+  { LOPT_LOC_REBND, OPT_LOCAL_REBIND, NULL, gettext_noop("Allow rebinding of 127.0.0.0/8, for RBL servers."), NULL },
+  { LOPT_NO_REBIND, ARG_DUP, "/<domain>/", gettext_noop("Inhibit DNS-rebind protection on this domain."), NULL },
+  { LOPT_NOLAST, OPT_ALL_SERVERS, NULL, gettext_noop("Always perform DNS queries to all servers."), NULL },
+  { LOPT_MATCH, ARG_DUP, "set:<tag>,<optspec>", gettext_noop("Set tag if client includes matching option in request."), NULL },
+  { LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
+  { LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
+  { LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
+  { LOPT_MAXPORT, ARG_ONE, "<port>", gettext_noop("Specify highest port available for DNS query transmission."), NULL },
+  { LOPT_DHCP_FQDN, OPT_DHCP_FQDN, NULL, gettext_noop("Use only fully qualified domain names for DHCP clients."), NULL },
+  { LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},
+  { LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },
+  { LOPT_RELAY, ARG_DUP, "<local-addr>,<server>[,<iface>]", gettext_noop("Relay DHCP requests to a remote server"), NULL},
+  { LOPT_CNAME, ARG_DUP, "<alias>,<target>[,<ttl>]", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
+  { LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
+  { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
+  { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
+  { LOPT_ADD_MAC, ARG_DUP, "[=base64|text]", gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
+  { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add specified IP subnet to forwarded DNS queries."), NULL },
+  { LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add client identification to forwarded DNS queries."), NULL },
+  { LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
+  { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
+  { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
+  { LOPT_FQDN, OPT_FQDN_UPDATE, NULL, gettext_noop("Allow DHCP clients to do their own DDNS updates."), NULL },
+  { LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL },
+  { LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
+  { LOPT_HOST_REC, ARG_DUP, "<name>,<address>[,<ttl>]", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
+  { LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
+  { LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL },
+  { LOPT_AUTHSERV, ARG_ONE, "<NS>,<interface>", gettext_noop("Export local names to global DNS"), NULL },
+  { LOPT_AUTHZONE, ARG_DUP, "<domain>,[<subnet>...]", gettext_noop("Domain to export to global DNS"), NULL },
+  { LOPT_AUTHTTL, ARG_ONE, "<integer>", gettext_noop("Set TTL for authoritative replies"), NULL },
+  { LOPT_AUTHSOA, ARG_ONE, "<serial>[,...]", gettext_noop("Set authoritative zone information"), NULL },
+  { LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL },
+  { LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL },
+  { LOPT_IPSET, ARG_DUP, "/<domain>[/<domain>...]/<ipset>...", gettext_noop("Specify ipsets to which matching domains should be added"), NULL },
+  { LOPT_SYNTH, ARG_DUP, "<domain>,<range>,[<prefix>]", gettext_noop("Specify a domain and address range for synthesised names"), NULL },
+  { LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL },
+  { LOPT_TRUST_ANCHOR, ARG_DUP, "<domain>,[<class>],...", gettext_noop("Specify trust anchor key digest."), NULL },
+  { LOPT_DNSSEC_DEBUG, OPT_DNSSEC_DEBUG, NULL, gettext_noop("Disable upstream checking for DNSSEC debugging."), NULL },
+  { LOPT_DNSSEC_CHECK, OPT_DNSSEC_NO_SIGN, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL },
+  { LOPT_DNSSEC_TIME, OPT_DNSSEC_TIME, NULL, gettext_noop("Don't check DNSSEC signature timestamps until first cache-reload"), NULL },
+  { LOPT_DNSSEC_STAMP, ARG_ONE, "<path>", gettext_noop("Timestamp file to verify system clock for DNSSEC"), NULL },
+#ifdef OPTION6_PREFIX_CLASS 
+  { LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
+#endif
+  { LOPT_RA_PARAM, ARG_DUP, "<iface>,[mtu:<value>|<interface>|off,][<prio>,]<intval>[,<lifetime>]", gettext_noop("Set MTU, priority, resend-interval and router-lifetime"), NULL },
+  { LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
+  { LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
+  { LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },
+  { LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks."), NULL },
+  { LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops."), NULL },
+  { LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL }, 
+  { LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL }, 
+  { LOPT_REPLY_DELAY, ARG_ONE, "<integer>", gettext_noop("Delay DHCP replies for at least number of seconds."), NULL },
+  { 0, 0, NULL, NULL, NULL }
+}; 
+
+/* We hide metacharacters in quoted strings by mapping them into the ASCII control
+   character space. Note that the \0, \t \b \r \033 and \n characters are carefully placed in the
+   following sequence so that they map to themselves: it is therefore possible to call
+   unhide_metas repeatedly on string without breaking things.
+   The transformation gets undone by opt_canonicalise, atoi_check and opt_string_alloc, and a 
+   couple of other places. 
+   Note that space is included here so that
+   --dhcp-option=3, string
+   has five characters, whilst
+   --dhcp-option=3," string"
+   has six.
+*/
+
+static const char meta[] = "\000123456 \b\t\n78\r90abcdefABCDE\033F:,.";
+
+static char hide_meta(char c)
+{
+  unsigned int i;
+
+  for (i = 0; i < (sizeof(meta) - 1); i++)
+    if (c == meta[i])
+      return (char)i;
+  
+  return c;
+}
+
+static char unhide_meta(char cr)
+{ 
+  unsigned int c = cr;
+  
+  if (c < (sizeof(meta) - 1))
+    cr = meta[c];
+  
+  return cr;
+}
+
+static void unhide_metas(char *cp)
+{
+  if (cp)
+    for(; *cp; cp++)
+      *cp = unhide_meta(*cp);
+}
+
+static void *opt_malloc(size_t size)
+{
+  void *ret;
+
+  if (mem_recover)
+    {
+      ret = whine_malloc(size);
+      if (!ret)
+	longjmp(mem_jmp, 1);
+    }
+  else
+    ret = safe_malloc(size);
+  
+  return ret;
+}
+
+static char *opt_string_alloc(char *cp)
+{
+  char *ret = NULL;
+  
+  if (cp && strlen(cp) != 0)
+    {
+      ret = opt_malloc(strlen(cp)+1);
+      strcpy(ret, cp); 
+      
+      /* restore hidden metachars */
+      unhide_metas(ret);
+    }
+    
+  return ret;
+}
+
+
+/* find next comma, split string with zero and eliminate spaces.
+   return start of string following comma */
+
+static char *split_chr(char *s, char c)
+{
+  char *comma, *p;
+
+  if (!s || !(comma = strchr(s, c)))
+    return NULL;
+  
+  p = comma;
+  *comma = ' ';
+  
+  for (; *comma == ' '; comma++);
+ 
+  for (; (p >= s) && *p == ' '; p--)
+    *p = 0;
+    
+  return comma;
+}
+
+static char *split(char *s)
+{
+  return split_chr(s, ',');
+}
+
+static char *canonicalise_opt(char *s)
+{
+  char *ret;
+  int nomem;
+
+  if (!s)
+    return 0;
+
+  unhide_metas(s);
+  if (!(ret = canonicalise(s, &nomem)) && nomem)
+    {
+      if (mem_recover)
+	longjmp(mem_jmp, 1);
+      else
+	die(_("could not get memory"), NULL, EC_NOMEM);
+    }
+
+  return ret;
+}
+
+static int atoi_check(char *a, int *res)
+{
+  char *p;
+
+  if (!a)
+    return 0;
+
+  unhide_metas(a);
+  
+  for (p = a; *p; p++)
+     if (*p < '0' || *p > '9')
+       return 0;
+
+  *res = atoi(a);
+  return 1;
+}
+
+static int atoi_check16(char *a, int *res)
+{
+  if (!(atoi_check(a, res)) ||
+      *res < 0 ||
+      *res > 0xffff)
+    return 0;
+
+  return 1;
+}
+
+#ifdef HAVE_DNSSEC
+static int atoi_check8(char *a, int *res)
+{
+  if (!(atoi_check(a, res)) ||
+      *res < 0 ||
+      *res > 0xff)
+    return 0;
+
+  return 1;
+}
+#endif
+
+#ifndef NO_ID
+static void add_txt(char *name, char *txt, int stat)
+{
+  struct txt_record *r = opt_malloc(sizeof(struct txt_record));
+
+  if (txt)
+    {
+      size_t len = strlen(txt);
+      r->txt = opt_malloc(len+1);
+      r->len = len+1;
+      *(r->txt) = len;
+      memcpy((r->txt)+1, txt, len);
+    }
+
+  r->stat = stat;
+  r->name = opt_string_alloc(name);
+  r->next = daemon->txt;
+  daemon->txt = r;
+  r->class = C_CHAOS;
+}
+#endif
+
+static void do_usage(void)
+{
+  char buff[100];
+  int i, j;
+
+  struct {
+    char handle;
+    int val;
+  } tab[] = {
+    { '$', CACHESIZ },
+    { '*', EDNS_PKTSZ },
+    { '&', MAXLEASES },
+    { '!', FTABSIZ },
+    { '#', TFTP_MAX_CONNECTIONS },
+    { '\0', 0 }
+  };
+
+  printf(_("Usage: dnsmasq [options]\n\n"));
+#ifndef HAVE_GETOPT_LONG
+  printf(_("Use short options only on the command line.\n"));
+#endif
+  printf(_("Valid options are:\n"));
+  
+  for (i = 0; usage[i].opt != 0; i++)
+    {
+      char *desc = usage[i].flagdesc; 
+      char *eq = "=";
+      
+      if (!desc || *desc == '[')
+	eq = "";
+      
+      if (!desc)
+	desc = "";
+
+      for ( j = 0; opts[j].name; j++)
+	if (opts[j].val == usage[i].opt)
+	  break;
+      if (usage[i].opt < 256)
+	sprintf(buff, "-%c, ", usage[i].opt);
+      else
+	sprintf(buff, "    ");
+      
+      sprintf(buff+4, "--%s%s%s", opts[j].name, eq, desc);
+      printf("%-55.55s", buff);
+	     
+      if (usage[i].arg)
+	{
+	  strcpy(buff, usage[i].arg);
+	  for (j = 0; tab[j].handle; j++)
+	    if (tab[j].handle == *(usage[i].arg))
+	      sprintf(buff, "%d", tab[j].val);
+	}
+      printf(_(usage[i].desc), buff);
+      printf("\n");
+    }
+}
+
+#define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
+
+static char *parse_mysockaddr(char *arg, union mysockaddr *addr) 
+{
+  if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
+    addr->sa.sa_family = AF_INET;
+#ifdef HAVE_IPV6
+  else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
+    addr->sa.sa_family = AF_INET6;
+#endif
+  else
+    return _("bad address");
+   
+  return NULL;
+}
+
+char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags)
+{
+  int source_port = 0, serv_port = NAMESERVER_PORT;
+  char *portno, *source;
+  char *interface_opt = NULL;
+#ifdef HAVE_IPV6
+  int scope_index = 0;
+  char *scope_id;
+#endif
+  
+  if (!arg || strlen(arg) == 0)
+    {
+      *flags |= SERV_NO_ADDR;
+      *interface = 0;
+      return NULL;
+    }
+
+  if ((source = split_chr(arg, '@')) && /* is there a source. */
+      (portno = split_chr(source, '#')) &&
+      !atoi_check16(portno, &source_port))
+    return _("bad port");
+  
+  if ((portno = split_chr(arg, '#')) && /* is there a port no. */
+      !atoi_check16(portno, &serv_port))
+    return _("bad port");
+  
+#ifdef HAVE_IPV6
+  scope_id = split_chr(arg, '%');
+#endif
+  
+  if (source) {
+    interface_opt = split_chr(source, '@');
+
+    if (interface_opt)
+      {
+#if defined(SO_BINDTODEVICE)
+	strncpy(interface, interface_opt, IF_NAMESIZE - 1);
+#else
+	return _("interface binding not supported");
+#endif
+      }
+  }
+
+  if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
+    {
+      addr->in.sin_port = htons(serv_port);	
+      addr->sa.sa_family = source_addr->sa.sa_family = AF_INET;
+#ifdef HAVE_SOCKADDR_SA_LEN
+      source_addr->in.sin_len = addr->in.sin_len = sizeof(struct sockaddr_in);
+#endif
+      source_addr->in.sin_addr.s_addr = INADDR_ANY;
+      source_addr->in.sin_port = htons(daemon->query_port);
+      
+      if (source)
+	{
+	  if (flags)
+	    *flags |= SERV_HAS_SOURCE;
+	  source_addr->in.sin_port = htons(source_port);
+	  if (!(inet_pton(AF_INET, source, &source_addr->in.sin_addr) > 0))
+	    {
+#if defined(SO_BINDTODEVICE)
+	      if (interface_opt)
+		return _("interface can only be specified once");
+	      
+	      source_addr->in.sin_addr.s_addr = INADDR_ANY;
+	      strncpy(interface, source, IF_NAMESIZE - 1);
+#else
+	      return _("interface binding not supported");
+#endif
+	    }
+	}
+    }
+#ifdef HAVE_IPV6
+  else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
+    {
+      if (scope_id && (scope_index = if_nametoindex(scope_id)) == 0)
+	return _("bad interface name");
+      
+      addr->in6.sin6_port = htons(serv_port);
+      addr->in6.sin6_scope_id = scope_index;
+      source_addr->in6.sin6_addr = in6addr_any; 
+      source_addr->in6.sin6_port = htons(daemon->query_port);
+      source_addr->in6.sin6_scope_id = 0;
+      addr->sa.sa_family = source_addr->sa.sa_family = AF_INET6;
+      addr->in6.sin6_flowinfo = source_addr->in6.sin6_flowinfo = 0;
+#ifdef HAVE_SOCKADDR_SA_LEN
+      addr->in6.sin6_len = source_addr->in6.sin6_len = sizeof(addr->in6);
+#endif
+      if (source)
+	{
+	  if (flags)
+	    *flags |= SERV_HAS_SOURCE;
+	  source_addr->in6.sin6_port = htons(source_port);
+	  if (inet_pton(AF_INET6, source, &source_addr->in6.sin6_addr) == 0)
+	    {
+#if defined(SO_BINDTODEVICE)
+	      if (interface_opt)
+		return _("interface can only be specified once");
+	      
+	      source_addr->in6.sin6_addr = in6addr_any;
+	      strncpy(interface, source, IF_NAMESIZE - 1);
+#else
+	      return _("interface binding not supported");
+#endif
+	    }
+	}
+    }
+#endif
+  else
+    return _("bad address");
+
+  return NULL;
+}
+
+static struct server *add_rev4(struct in_addr addr, int msize)
+{
+  struct server *serv = opt_malloc(sizeof(struct server));
+  in_addr_t  a = ntohl(addr.s_addr);
+  char *p;
+
+  memset(serv, 0, sizeof(struct server));
+  p = serv->domain = opt_malloc(29); /* strlen("xxx.yyy.zzz.ttt.in-addr.arpa")+1 */
+
+  switch (msize)
+    {
+    case 32:
+      p += sprintf(p, "%u.", a & 0xff);
+      /* fall through */
+    case 24:
+      p += sprintf(p, "%d.", (a >> 8) & 0xff);
+      /* fall through */
+    case 16:
+      p += sprintf(p, "%d.", (a >> 16) & 0xff);
+      /* fall through */
+    case 8:
+      p += sprintf(p, "%d.", (a >> 24) & 0xff);
+      break;
+    default:
+      return NULL;
+    }
+
+  p += sprintf(p, "in-addr.arpa");
+  
+  serv->flags = SERV_HAS_DOMAIN;
+  serv->next = daemon->servers;
+  daemon->servers = serv;
+
+  return serv;
+
+}
+
+static struct server *add_rev6(struct in6_addr *addr, int msize)
+{
+  struct server *serv = opt_malloc(sizeof(struct server));
+  char *p;
+  int i;
+				  
+  memset(serv, 0, sizeof(struct server));
+  p = serv->domain = opt_malloc(73); /* strlen("32*<n.>ip6.arpa")+1 */
+  
+  for (i = msize-1; i >= 0; i -= 4)
+    { 
+      int dig = ((unsigned char *)addr)[i>>3];
+      p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
+    }
+  p += sprintf(p, "ip6.arpa");
+  
+  serv->flags = SERV_HAS_DOMAIN;
+  serv->next = daemon->servers;
+  daemon->servers = serv;
+  
+  return serv;
+}
+
+#ifdef HAVE_DHCP
+
+static int is_tag_prefix(char *arg)
+{
+  if (arg && (strstr(arg, "net:") == arg || strstr(arg, "tag:") == arg))
+    return 1;
+  
+  return 0;
+}
+
+static char *set_prefix(char *arg)
+{
+   if (strstr(arg, "set:") == arg)
+     return arg+4;
+   
+   return arg;
+}
+
+/* This is too insanely large to keep in-line in the switch */
+static int parse_dhcp_opt(char *errstr, char *arg, int flags)
+{
+  struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
+  char lenchar = 0, *cp;
+  int addrs, digs, is_addr, is_addr6, is_hex, is_dec, is_string, dots;
+  char *comma = NULL;
+  struct dhcp_netid *np = NULL;
+  u16 opt_len = 0;
+  int is6 = 0;
+  int option_ok = 0;
+
+  new->len = 0;
+  new->flags = flags;
+  new->netid = NULL;
+  new->val = NULL;
+  new->opt = 0;
+  
+  while (arg)
+    {
+      comma = split(arg);      
+
+      for (cp = arg; *cp; cp++)
+	if (*cp < '0' || *cp > '9')
+	  break;
+      
+      if (!*cp)
+	{
+	  new->opt = atoi(arg);
+	  opt_len = 0;
+	  option_ok = 1;
+	  break;
+	}
+      
+      if (strstr(arg, "option:") == arg)
+	{
+	  if ((new->opt = lookup_dhcp_opt(AF_INET, arg+7)) != -1)
+	    {
+	      opt_len = lookup_dhcp_len(AF_INET, new->opt);
+	      /* option:<optname> must follow tag and vendor string. */
+	      if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
+		option_ok = 1;
+	    }
+	  break;
+	}
+#ifdef HAVE_DHCP6
+      else if (strstr(arg, "option6:") == arg)
+	{
+	  for (cp = arg+8; *cp; cp++)
+	    if (*cp < '0' || *cp > '9')
+	      break;
+	 
+	  if (!*cp)
+	    {
+	      new->opt = atoi(arg+8);
+	      opt_len = 0;
+	      option_ok = 1;
+	    }
+	  else
+	    {
+	      if ((new->opt = lookup_dhcp_opt(AF_INET6, arg+8)) != -1)
+		{
+		  opt_len = lookup_dhcp_len(AF_INET6, new->opt);
+		  if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
+		    option_ok = 1;
+		}
+	    }
+	  /* option6:<opt>|<optname> must follow tag and vendor string. */
+	  is6 = 1;
+	  break;
+	}
+#endif
+      else if (strstr(arg, "vendor:") == arg)
+	{
+	  new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7);
+	  new->flags |= DHOPT_VENDOR;
+	}
+      else if (strstr(arg, "encap:") == arg)
+	{
+	  new->u.encap = atoi(arg+6);
+	  new->flags |= DHOPT_ENCAPSULATE;
+	}
+      else if (strstr(arg, "vi-encap:") == arg)
+	{
+	  new->u.encap = atoi(arg+9);
+	  new->flags |= DHOPT_RFC3925;
+	  if (flags == DHOPT_MATCH)
+	    {
+	      option_ok = 1;
+	      break;
+	    }
+	}
+      else
+	{
+	  new->netid = opt_malloc(sizeof (struct dhcp_netid));
+	  /* allow optional "net:" or "tag:" for consistency */
+	  if (is_tag_prefix(arg))
+	    new->netid->net = opt_string_alloc(arg+4);
+	  else
+	    new->netid->net = opt_string_alloc(set_prefix(arg));
+	  new->netid->next = np;
+	  np = new->netid;
+	}
+      
+      arg = comma; 
+    }
+
+#ifdef HAVE_DHCP6
+  if (is6)
+    {
+      if (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))
+	ret_err(_("unsupported encapsulation for IPv6 option"));
+      
+      if (opt_len == 0 &&
+	  !(new->flags & DHOPT_RFC3925))
+	opt_len = lookup_dhcp_len(AF_INET6, new->opt);
+    }
+  else
+#endif
+    if (opt_len == 0 &&
+	!(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925)))
+      opt_len = lookup_dhcp_len(AF_INET, new->opt);
+  
+  /* option may be missing with rfc3925 match */
+  if (!option_ok)
+    ret_err(_("bad dhcp-option"));
+  
+  if (comma)
+    {
+      /* characterise the value */
+      char c;
+      int found_dig = 0;
+      is_addr = is_addr6 = is_hex = is_dec = is_string = 1;
+      addrs = digs = 1;
+      dots = 0;
+      for (cp = comma; (c = *cp); cp++)
+	if (c == ',')
+	  {
+	    addrs++;
+	    is_dec = is_hex = 0;
+	  }
+	else if (c == ':')
+	  {
+	    digs++;
+	    is_dec = is_addr = 0;
+	  }
+	else if (c == '/') 
+	  {
+	    is_addr6 = is_dec = is_hex = 0;
+	    if (cp == comma) /* leading / means a pathname */
+	      is_addr = 0;
+	  } 
+	else if (c == '.')	
+	  {
+	    is_addr6 = is_dec = is_hex = 0;
+	    dots++;
+	  }
+	else if (c == '-')
+	  is_hex = is_addr = is_addr6 = 0;
+	else if (c == ' ')
+	  is_dec = is_hex = 0;
+	else if (!(c >='0' && c <= '9'))
+	  {
+	    is_addr = 0;
+	    if (cp[1] == 0 && is_dec &&
+		(c == 'b' || c == 's' || c == 'i'))
+	      {
+		lenchar = c;
+		*cp = 0;
+	      }
+	    else
+	      is_dec = 0;
+	    if (!((c >='A' && c <= 'F') ||
+		  (c >='a' && c <= 'f') || 
+		  (c == '*' && (flags & DHOPT_MATCH))))
+	      {
+		is_hex = 0;
+		if (c != '[' && c != ']')
+		  is_addr6 = 0;
+	      }
+	  }
+	else
+	  found_dig = 1;
+     
+      if (!found_dig)
+	is_dec = is_addr = 0;
+     
+      /* We know that some options take addresses */
+      if (opt_len & OT_ADDR_LIST)
+	{
+	  is_string = is_dec = is_hex = 0;
+	  
+	  if (!is6 && (!is_addr || dots == 0))
+	    ret_err(_("bad IP address"));
+
+	   if (is6 && !is_addr6)
+	     ret_err(_("bad IPv6 address"));
+	}
+      /* or names */
+      else if (opt_len & (OT_NAME | OT_RFC1035_NAME | OT_CSTRING))
+	is_addr6 = is_addr = is_dec = is_hex = 0;
+      
+      if (found_dig && (opt_len & OT_TIME) && strlen(comma) > 0)
+	{
+	  int val, fac = 1;
+
+	  switch (comma[strlen(comma) - 1])
+	    {
+	    case 'w':
+	    case 'W':
+	      fac *= 7;
+	      /* fall through */
+	    case 'd':
+	    case 'D':
+	      fac *= 24;
+	      /* fall though */
+	    case 'h':
+	    case 'H':
+	      fac *= 60;
+	      /* fall through */
+	    case 'm':
+	    case 'M':
+	      fac *= 60;
+	      /* fall through */
+	    case 's':
+	    case 'S':
+	      comma[strlen(comma) - 1] = 0;
+	    }
+	  
+	  new->len = 4;
+	  new->val = opt_malloc(4);
+	  val = atoi(comma);
+	  *((int *)new->val) = htonl(val * fac);	  
+	}  
+      else if (is_hex && digs > 1)
+	{
+	  new->len = digs;
+	  new->val = opt_malloc(new->len);
+	  parse_hex(comma, new->val, digs, (flags & DHOPT_MATCH) ? &new->u.wildcard_mask : NULL, NULL);
+	  new->flags |= DHOPT_HEX;
+	}
+      else if (is_dec)
+	{
+	  int i, val = atoi(comma);
+	  /* assume numeric arg is 1 byte except for
+	     options where it is known otherwise.
+	     For vendor class option, we have to hack. */
+	  if (opt_len != 0)
+	    new->len = opt_len;
+	  else if (val & 0xffff0000)
+	    new->len = 4;
+	  else if (val & 0xff00)
+	    new->len = 2;
+	  else
+	    new->len = 1;
+
+	  if (lenchar == 'b')
+	    new->len = 1;
+	  else if (lenchar == 's')
+	    new->len = 2;
+	  else if (lenchar == 'i')
+	    new->len = 4;
+	  
+	  new->val = opt_malloc(new->len);
+	  for (i=0; i<new->len; i++)
+	    new->val[i] = val>>((new->len - i - 1)*8);
+	}
+      else if (is_addr && !is6)	
+	{
+	  struct in_addr in;
+	  unsigned char *op;
+	  char *slash;
+	  /* max length of address/subnet descriptor is five bytes,
+	     add one for the option 120 enc byte too */
+	  new->val = op = opt_malloc((5 * addrs) + 1);
+	  new->flags |= DHOPT_ADDR;
+
+	  if (!(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) && 
+	      new->opt == OPTION_SIP_SERVER)
+	    {
+	      *(op++) = 1; /* RFC 3361 "enc byte" */
+	      new->flags &= ~DHOPT_ADDR;
+	    }
+	  while (addrs--) 
+	    {
+	      cp = comma;
+	      comma = split(cp);
+	      slash = split_chr(cp, '/');
+	      if (!inet_pton(AF_INET, cp, &in))
+		ret_err(_("bad IPv4 address"));
+	      if (!slash)
+		{
+		  memcpy(op, &in, INADDRSZ);
+		  op += INADDRSZ;
+		}
+	      else
+		{
+		  unsigned char *p = (unsigned char *)&in;
+		  int netsize = atoi(slash);
+		  *op++ = netsize;
+		  if (netsize > 0)
+		    *op++ = *p++;
+		  if (netsize > 8)
+		    *op++ = *p++;
+		  if (netsize > 16)
+		    *op++ = *p++;
+		  if (netsize > 24)
+		    *op++ = *p++;
+		  new->flags &= ~DHOPT_ADDR; /* cannot re-write descriptor format */
+		} 
+	    }
+	  new->len = op - new->val;
+	}
+      else if (is_addr6 && is6)
+	{
+	  unsigned char *op;
+	  new->val = op = opt_malloc(16 * addrs);
+	  new->flags |= DHOPT_ADDR6;
+	  while (addrs--) 
+	    {
+	      cp = comma;
+	      comma = split(cp);
+	      
+	      /* check for [1234::7] */
+	      if (*cp == '[')
+		cp++;
+	      if (strlen(cp) > 1 && cp[strlen(cp)-1] == ']')
+		cp[strlen(cp)-1] = 0;
+	      
+	      if (inet_pton(AF_INET6, cp, op))
+		{
+		  op += IN6ADDRSZ;
+		  continue;
+		}
+	  
+	      ret_err(_("bad IPv6 address"));
+	    } 
+	  new->len = op - new->val;
+	}
+      else if (is_string)
+	{
+ 	  /* text arg */
+	  if ((new->opt == OPTION_DOMAIN_SEARCH || new->opt == OPTION_SIP_SERVER) &&
+	      !is6 && !(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
+	    {
+	      /* dns search, RFC 3397, or SIP, RFC 3361 */
+	      unsigned char *q, *r, *tail;
+	      unsigned char *p, *m = NULL, *newp;
+	      size_t newlen, len = 0;
+	      int header_size = (new->opt == OPTION_DOMAIN_SEARCH) ? 0 : 1;
+	      
+	      arg = comma;
+	      comma = split(arg);
+	      
+	      while (arg && *arg)
+		{
+		  char *in, *dom = NULL;
+		  size_t domlen = 1;
+		  /* Allow "." as an empty domain */
+		  if (strcmp (arg, ".") != 0)
+		    {
+		      if (!(dom = canonicalise_opt(arg)))
+			ret_err(_("bad domain in dhcp-option"));
+			
+		      domlen = strlen(dom) + 2;
+		    }
+		      
+		  newp = opt_malloc(len + domlen + header_size);
+		  if (m)
+		    {
+		      memcpy(newp, m, header_size + len);
+		      free(m);
+		    }
+		  m = newp;
+		  p = m + header_size;
+		  q = p + len;
+		  
+		  /* add string on the end in RFC1035 format */
+		  for (in = dom; in && *in;) 
+		    {
+		      unsigned char *cp = q++;
+		      int j;
+		      for (j = 0; *in && (*in != '.'); in++, j++)
+			*q++ = *in;
+		      *cp = j;
+		      if (*in)
+			in++;
+		    }
+		  *q++ = 0;
+		  free(dom);
+		  
+		  /* Now tail-compress using earlier names. */
+		  newlen = q - p;
+		  for (tail = p + len; *tail; tail += (*tail) + 1)
+		    for (r = p; r - p < (int)len; r += (*r) + 1)
+		      if (strcmp((char *)r, (char *)tail) == 0)
+			{
+			  PUTSHORT((r - p) | 0xc000, tail); 
+			  newlen = tail - p;
+			  goto end;
+			}
+		end:
+		  len = newlen;
+		  
+		  arg = comma;
+		  comma = split(arg);
+		}
+      
+	      /* RFC 3361, enc byte is zero for names */
+	      if (new->opt == OPTION_SIP_SERVER)
+		m[0] = 0;
+	      new->len = (int) len + header_size;
+	      new->val = m;
+	    }
+#ifdef HAVE_DHCP6
+	  else if (comma && (opt_len & OT_CSTRING))
+	    {
+	      /* length fields are two bytes so need 16 bits for each string */
+	      int i, commas = 1;
+	      unsigned char *p, *newp;
+
+	      for (i = 0; comma[i]; i++)
+		if (comma[i] == ',')
+		  commas++;
+	      
+	      newp = opt_malloc(strlen(comma)+(2*commas));	  
+	      p = newp;
+	      arg = comma;
+	      comma = split(arg);
+	      
+	      while (arg && *arg)
+		{
+		  u16 len = strlen(arg);
+		  unhide_metas(arg);
+		  PUTSHORT(len, p);
+		  memcpy(p, arg, len);
+		  p += len; 
+
+		  arg = comma;
+		  comma = split(arg);
+		}
+
+	      new->val = newp;
+	      new->len = p - newp;
+	    }
+	  else if (comma && (opt_len & OT_RFC1035_NAME))
+	    {
+	      unsigned char *p = NULL, *newp, *end;
+	      int len = 0;
+	      arg = comma;
+	      comma = split(arg);
+	      
+	      while (arg && *arg)
+		{
+		  char *dom = canonicalise_opt(arg);
+		  if (!dom)
+		    ret_err(_("bad domain in dhcp-option"));
+		    		  
+		  newp = opt_malloc(len + strlen(dom) + 2);
+		  
+		  if (p)
+		    {
+		      memcpy(newp, p, len);
+		      free(p);
+		    }
+		  
+		  p = newp;
+		  end = do_rfc1035_name(p + len, dom, NULL);
+		  *end++ = 0;
+		  len = end - p;
+		  free(dom);
+
+		  arg = comma;
+		  comma = split(arg);
+		}
+	      
+	      new->val = p;
+	      new->len = len;
+	    }
+#endif
+	  else
+	    {
+	      new->len = strlen(comma);
+	      /* keep terminating zero on string */
+	      new->val = (unsigned char *)opt_string_alloc(comma);
+	      new->flags |= DHOPT_STRING;
+	    }
+	}
+    }
+
+  if (!is6 && 
+      ((new->len > 255) || 
+      (new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))) ||
+       (new->len > 250 && (new->flags & DHOPT_RFC3925))))
+    ret_err(_("dhcp-option too long"));
+  
+  if (flags == DHOPT_MATCH)
+    {
+      if ((new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)) ||
+	  !new->netid ||
+	  new->netid->next)
+	ret_err(_("illegal dhcp-match"));
+       
+      if (is6)
+	{
+	  new->next = daemon->dhcp_match6;
+	  daemon->dhcp_match6 = new;
+	}
+      else
+	{
+	  new->next = daemon->dhcp_match;
+	  daemon->dhcp_match = new;
+	}
+    }
+  else if (is6)
+    {
+      new->next = daemon->dhcp_opts6;
+      daemon->dhcp_opts6 = new;
+    }
+  else
+    {
+      new->next = daemon->dhcp_opts;
+      daemon->dhcp_opts = new;
+    }
+    
+  return 1;
+}
+
+#endif
+
+void set_option_bool(unsigned int opt)
+{
+  if (opt < 32)
+    daemon->options |= 1u << opt;
+  else
+    daemon->options2 |= 1u << (opt - 32);
+}
+
+void reset_option_bool(unsigned int opt)
+{
+  if (opt < 32)
+    daemon->options &= ~(1u << opt);
+  else
+    daemon->options2 &= ~(1u << (opt - 32));
+}
+
+static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only)
+{      
+  int i;
+  char *comma;
+
+  if (option == '?')
+    ret_err(gen_err);
+  
+  for (i=0; usage[i].opt != 0; i++)
+    if (usage[i].opt == option)
+      {
+	 int rept = usage[i].rept;
+	 
+	 if (command_line)
+	   {
+	     /* command line */
+	     if (rept == ARG_USED_CL)
+	       ret_err(_("illegal repeated flag"));
+	     if (rept == ARG_ONE)
+	       usage[i].rept = ARG_USED_CL;
+	   }
+	 else
+	   {
+	     /* allow file to override command line */
+	     if (rept == ARG_USED_FILE)
+	       ret_err(_("illegal repeated keyword"));
+	     if (rept == ARG_USED_CL || rept == ARG_ONE)
+	       usage[i].rept = ARG_USED_FILE;
+	   }
+
+	 if (rept != ARG_DUP && rept != ARG_ONE && rept != ARG_USED_CL) 
+	   {
+	     set_option_bool(rept);
+	     return 1;
+	   }
+       
+	 break;
+      }
+  
+  switch (option)
+    { 
+    case 'C': /* --conf-file */
+      {
+	char *file = opt_string_alloc(arg);
+	if (file)
+	  {
+	    one_file(file, 0);
+	    free(file);
+	  }
+	break;
+      }
+
+    case '7': /* --conf-dir */	      
+      {
+	DIR *dir_stream;
+	struct dirent *ent;
+	char *directory, *path;
+	struct list {
+	  char *suffix;
+	  struct list *next;
+	} *ignore_suffix = NULL, *match_suffix = NULL, *li;
+	
+	comma = split(arg);
+	if (!(directory = opt_string_alloc(arg)))
+	  break;
+	
+	for (arg = comma; arg; arg = comma) 
+	  {
+	    comma = split(arg);
+	    if (strlen(arg) != 0)
+	      {
+		li = opt_malloc(sizeof(struct list));
+		if (*arg == '*')
+		  {
+		    /* "*" with no suffix is a no-op */
+		    if (arg[1] == 0)
+		      free(li);
+		    else
+		      {
+			li->next = match_suffix;
+			match_suffix = li;
+			/* Have to copy: buffer is overwritten */
+			li->suffix = opt_string_alloc(arg+1);
+		      }
+		  }
+		else
+		  {
+		    li->next = ignore_suffix;
+		    ignore_suffix = li;
+		    /* Have to copy: buffer is overwritten */
+		    li->suffix = opt_string_alloc(arg);
+		  }
+	      }
+	  }
+	
+	if (!(dir_stream = opendir(directory)))
+	  die(_("cannot access directory %s: %s"), directory, EC_FILE);
+	
+	while ((ent = readdir(dir_stream)))
+	  {
+	    size_t len = strlen(ent->d_name);
+	    struct stat buf;
+	    
+	    /* ignore emacs backups and dotfiles */
+	    if (len == 0 ||
+		ent->d_name[len - 1] == '~' ||
+		(ent->d_name[0] == '#' && ent->d_name[len - 1] == '#') ||
+		ent->d_name[0] == '.')
+	      continue;
+
+	    if (match_suffix)
+	      {
+		for (li = match_suffix; li; li = li->next)
+		  {
+		    /* check for required suffices */
+		    size_t ls = strlen(li->suffix);
+		    if (len > ls &&
+			strcmp(li->suffix, &ent->d_name[len - ls]) == 0)
+		      break;
+		  }
+		if (!li)
+		  continue;
+	      }
+	    
+	    for (li = ignore_suffix; li; li = li->next)
+	      {
+		/* check for proscribed suffices */
+		size_t ls = strlen(li->suffix);
+		if (len > ls &&
+		    strcmp(li->suffix, &ent->d_name[len - ls]) == 0)
+		  break;
+	      }
+	    if (li)
+	      continue;
+	    
+	    path = opt_malloc(strlen(directory) + len + 2);
+	    strcpy(path, directory);
+	    strcat(path, "/");
+	    strcat(path, ent->d_name);
+
+	    /* files must be readable */
+	    if (stat(path, &buf) == -1)
+	      die(_("cannot access %s: %s"), path, EC_FILE);
+	    
+	    /* only reg files allowed. */
+	    if (S_ISREG(buf.st_mode))
+	      one_file(path, 0);
+	    
+	    free(path);
+	  }
+     
+	closedir(dir_stream);
+	free(directory);
+	for(; ignore_suffix; ignore_suffix = li)
+	  {
+	    li = ignore_suffix->next;
+	    free(ignore_suffix->suffix);
+	    free(ignore_suffix);
+	  }
+	for(; match_suffix; match_suffix = li)
+	  {
+	    li = match_suffix->next;
+	    free(match_suffix->suffix);
+	    free(match_suffix);
+	  }
+	break;
+      }
+
+    case LOPT_ADD_SBNET: /* --add-subnet */
+      set_option_bool(OPT_CLIENT_SUBNET);
+      if (arg)
+	{
+          char *err, *end;
+	  comma = split(arg);
+
+          struct mysubnet* new = opt_malloc(sizeof(struct mysubnet));
+          if ((end = split_chr(arg, '/')))
+	    {
+	      /* has subnet+len */
+	      err = parse_mysockaddr(arg, &new->addr);
+	      if (err)
+		ret_err(err);
+	      if (!atoi_check(end, &new->mask))
+		ret_err(gen_err);
+	      new->addr_used = 1;
+	    } 
+	  else if (!atoi_check(arg, &new->mask))
+	    ret_err(gen_err);
+	    
+          daemon->add_subnet4 = new;
+
+          if (comma)
+            {
+	      new = opt_malloc(sizeof(struct mysubnet));
+	      if ((end = split_chr(comma, '/')))
+		{
+		  /* has subnet+len */
+                  err = parse_mysockaddr(comma, &new->addr);
+                  if (err)
+                    ret_err(err);
+                  if (!atoi_check(end, &new->mask))
+                    ret_err(gen_err);
+                  new->addr_used = 1;
+                }
+              else
+                {
+                  if (!atoi_check(comma, &new->mask))
+                    ret_err(gen_err);
+                }
+          
+	      daemon->add_subnet6 = new;
+	    }
+	}
+      break;
+
+    case '1': /* --enable-dbus */
+      set_option_bool(OPT_DBUS);
+      if (arg)
+	daemon->dbus_name = opt_string_alloc(arg);
+      else
+	daemon->dbus_name = DNSMASQ_SERVICE;
+      break;
+      
+    case '8': /* --log-facility */
+      /* may be a filename */
+      if (strchr(arg, '/') || strcmp (arg, "-") == 0)
+	daemon->log_file = opt_string_alloc(arg);
+      else
+	{	  
+#ifdef __ANDROID__
+	  ret_err(_("setting log facility is not possible under Android"));
+#else
+	  for (i = 0; facilitynames[i].c_name; i++)
+	    if (hostname_isequal((char *)facilitynames[i].c_name, arg))
+	      break;
+	  
+	  if (facilitynames[i].c_name)
+	    daemon->log_fac = facilitynames[i].c_val;
+	  else
+	    ret_err(_("bad log facility"));
+#endif
+	}
+      break;
+      
+    case 'x': /* --pid-file */
+      daemon->runfile = opt_string_alloc(arg);
+      break;
+
+    case 'r': /* --resolv-file */
+      {
+	char *name = opt_string_alloc(arg);
+	struct resolvc *new, *list = daemon->resolv_files;
+	
+	if (list && list->is_default)
+	  {
+	    /* replace default resolv file - possibly with nothing */
+	    if (name)
+	      {
+		list->is_default = 0;
+		list->name = name;
+	      }
+	    else
+	      list = NULL;
+	  }
+	else if (name)
+	  {
+	    new = opt_malloc(sizeof(struct resolvc));
+	    new->next = list;
+	    new->name = name;
+	    new->is_default = 0;
+	    new->mtime = 0;
+	    new->logged = 0;
+	    list = new;
+	  }
+	daemon->resolv_files = list;
+	break;
+      }
+
+    case LOPT_SERVERS_FILE:
+      daemon->servers_file = opt_string_alloc(arg);
+      break;
+      
+    case 'm':  /* --mx-host */
+      {
+	int pref = 1;
+	struct mx_srv_record *new;
+	char *name, *target = NULL;
+
+	if ((comma = split(arg)))
+	  {
+	    char *prefstr;
+	    if ((prefstr = split(comma)) && !atoi_check16(prefstr, &pref))
+	      ret_err(_("bad MX preference"));
+	  }
+	
+	if (!(name = canonicalise_opt(arg)) || 
+	    (comma && !(target = canonicalise_opt(comma))))
+	  ret_err(_("bad MX name"));
+	
+	new = opt_malloc(sizeof(struct mx_srv_record));
+	new->next = daemon->mxnames;
+	daemon->mxnames = new;
+	new->issrv = 0;
+	new->name = name;
+	new->target = target; /* may be NULL */
+	new->weight = pref;
+	break;
+      }
+      
+    case 't': /*  --mx-target */
+      if (!(daemon->mxtarget = canonicalise_opt(arg)))
+	ret_err(_("bad MX target"));
+      break;
+
+#ifdef HAVE_DHCP      
+    case 'l':  /* --dhcp-leasefile */
+      daemon->lease_file = opt_string_alloc(arg);
+      break;
+      
+      /* Sorry about the gross pre-processor abuse */
+    case '6':             /* --dhcp-script */
+    case LOPT_LUASCRIPT:  /* --dhcp-luascript */
+#  if defined(NO_FORK)
+      ret_err(_("cannot run scripts under uClinux"));
+#  elif !defined(HAVE_SCRIPT)
+      ret_err(_("recompile with HAVE_SCRIPT defined to enable lease-change scripts"));
+#  else
+      if (option == LOPT_LUASCRIPT)
+#    if !defined(HAVE_LUASCRIPT)
+	ret_err(_("recompile with HAVE_LUASCRIPT defined to enable Lua scripts"));
+#    else
+        daemon->luascript = opt_string_alloc(arg);
+#    endif
+      else
+        daemon->lease_change_command = opt_string_alloc(arg);
+#  endif
+      break;
+#endif /* HAVE_DHCP */
+
+    case LOPT_DHCP_HOST:     /* --dhcp-hostsfile */
+    case LOPT_DHCP_OPTS:     /* --dhcp-optsfile */
+    case LOPT_DHCP_INOTIFY:  /* --dhcp-hostsdir */
+    case LOPT_DHOPT_INOTIFY: /* --dhcp-optsdir */
+    case LOPT_HOST_INOTIFY:  /* --hostsdir */
+    case 'H':                /* --addn-hosts */
+      {
+	struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
+	static unsigned int hosts_index = SRC_AH;
+	new->fname = opt_string_alloc(arg);
+	new->index = hosts_index++;
+	new->flags = 0;
+	if (option == 'H')
+	  {
+	    new->next = daemon->addn_hosts;
+	    daemon->addn_hosts = new;
+	  }
+	else if (option == LOPT_DHCP_HOST)
+	  {
+	    new->next = daemon->dhcp_hosts_file;
+	    daemon->dhcp_hosts_file = new;
+	  }
+	else if (option == LOPT_DHCP_OPTS)
+	  {
+	    new->next = daemon->dhcp_opts_file;
+	    daemon->dhcp_opts_file = new;
+	  } 	  
+	else 
+	  {
+	    new->next = daemon->dynamic_dirs;
+	    daemon->dynamic_dirs = new; 
+	    if (option == LOPT_DHCP_INOTIFY)
+	      new->flags |= AH_DHCP_HST;
+	    else if (option == LOPT_DHOPT_INOTIFY)
+	      new->flags |= AH_DHCP_OPT;
+	    else if (option == LOPT_HOST_INOTIFY)
+	      new->flags |= AH_HOSTS;
+	  }
+	
+	break;
+      }
+      
+
+#ifdef HAVE_AUTH
+    case LOPT_AUTHSERV: /* --auth-server */
+      if (!(comma = split(arg)))
+	ret_err(gen_err);
+      
+      daemon->authserver = opt_string_alloc(arg);
+      arg = comma;
+      do {
+	struct iname *new = opt_malloc(sizeof(struct iname));
+	comma = split(arg);
+	new->name = NULL;
+	unhide_metas(arg);
+	if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0)
+	  new->addr.sa.sa_family = AF_INET;
+#ifdef HAVE_IPV6
+	else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
+	  new->addr.sa.sa_family = AF_INET6;
+#endif
+	else
+	  {
+	    char *fam = split_chr(arg, '/');
+	    new->name = opt_string_alloc(arg);
+	    new->addr.sa.sa_family = 0;
+	    if (fam)
+	      {
+		if (strcmp(fam, "4") == 0)
+		  new->addr.sa.sa_family = AF_INET;
+#ifdef HAVE_IPV6
+		else if (strcmp(fam, "6") == 0)
+		  new->addr.sa.sa_family = AF_INET6;
+#endif
+		else
+		  ret_err(gen_err);
+	      } 
+	  }
+	new->next = daemon->authinterface;
+	daemon->authinterface = new;
+	
+	arg = comma;
+      } while (arg);
+            
+      break;
+
+    case LOPT_AUTHSFS: /* --auth-sec-servers */
+      {
+	struct name_list *new;
+
+	do {
+	  comma = split(arg);
+	  new = opt_malloc(sizeof(struct name_list));
+	  new->name = opt_string_alloc(arg);
+	  new->next = daemon->secondary_forward_server;
+	  daemon->secondary_forward_server = new;
+	  arg = comma;
+	} while (arg);
+	break;
+      }
+	
+    case LOPT_AUTHZONE: /* --auth-zone */
+      {
+	struct auth_zone *new;
+	
+	comma = split(arg);
+		
+	new = opt_malloc(sizeof(struct auth_zone));
+	new->domain = opt_string_alloc(arg);
+	new->subnet = NULL;
+	new->exclude = NULL;
+	new->interface_names = NULL;
+	new->next = daemon->auth_zones;
+	daemon->auth_zones = new;
+
+	while ((arg = comma))
+	  {
+	    int prefixlen = 0;
+	    int is_exclude = 0;
+	    char *prefix;
+	    struct addrlist *subnet =  NULL;
+	    struct all_addr addr;
+
+	    comma = split(arg);
+	    prefix = split_chr(arg, '/');
+	    
+	    if (prefix && !atoi_check(prefix, &prefixlen))
+	      ret_err(gen_err);
+	    
+	    if (strstr(arg, "exclude:") == arg)
+	      {
+		    is_exclude = 1;
+		    arg = arg+8;
+	      }
+
+	    if (inet_pton(AF_INET, arg, &addr.addr.addr4))
+	      {
+		subnet = opt_malloc(sizeof(struct addrlist));
+		subnet->prefixlen = (prefixlen == 0) ? 24 : prefixlen;
+		subnet->flags = ADDRLIST_LITERAL;
+	      }
+#ifdef HAVE_IPV6
+	    else if (inet_pton(AF_INET6, arg, &addr.addr.addr6))
+	      {
+		subnet = opt_malloc(sizeof(struct addrlist));
+		subnet->prefixlen = (prefixlen == 0) ? 64 : prefixlen;
+		subnet->flags = ADDRLIST_LITERAL | ADDRLIST_IPV6;
+	      }
+#endif
+	    else 
+	      {
+		struct auth_name_list *name =  opt_malloc(sizeof(struct auth_name_list));
+		name->name = opt_string_alloc(arg);
+		name->flags = AUTH4 | AUTH6;
+		name->next = new->interface_names;
+		new->interface_names = name;
+		if (prefix)
+		  {
+		    if (prefixlen == 4)
+		      name->flags &= ~AUTH6;
+#ifdef HAVE_IPV6
+		    else if (prefixlen == 6)
+		      name->flags &= ~AUTH4;
+#endif
+		    else
+		      ret_err(gen_err);
+		  }
+	      }
+	    
+	    if (subnet)
+	      {
+		subnet->addr = addr;
+
+		if (is_exclude)
+		  {
+		    subnet->next = new->exclude;
+		    new->exclude = subnet;
+		  }
+		else
+		  {
+		    subnet->next = new->subnet;
+		    new->subnet = subnet;
+		  }
+	      }
+	  }
+	break;
+      }
+      
+    case  LOPT_AUTHSOA: /* --auth-soa */
+      comma = split(arg);
+      daemon->soa_sn = (u32)atoi(arg);
+      if (comma)
+	{
+	  char *cp;
+	  arg = comma;
+	  comma = split(arg);
+	  daemon->hostmaster = opt_string_alloc(arg);
+	  for (cp = daemon->hostmaster; *cp; cp++)
+	    if (*cp == '@')
+	      *cp = '.';
+
+	  if (comma)
+	    {
+	      arg = comma;
+	      comma = split(arg); 
+	      daemon->soa_refresh = (u32)atoi(arg);
+	      if (comma)
+		{
+		  arg = comma;
+		  comma = split(arg); 
+		  daemon->soa_retry = (u32)atoi(arg);
+		  if (comma)
+		    daemon->soa_expiry = (u32)atoi(comma);
+		}
+	    }
+	}
+
+      break;
+#endif
+
+    case 's':         /* --domain */
+    case LOPT_SYNTH:  /* --synth-domain */
+      if (strcmp (arg, "#") == 0)
+	set_option_bool(OPT_RESOLV_DOMAIN);
+      else
+	{
+	  char *d;
+	  comma = split(arg);
+	  if (!(d = canonicalise_opt(arg)))
+	    ret_err(gen_err);
+	  else
+	    {
+	      if (comma)
+		{
+		  struct cond_domain *new = opt_malloc(sizeof(struct cond_domain));
+		  char *netpart;
+		  
+		  new->prefix = NULL;
+
+		  unhide_metas(comma);
+		  if ((netpart = split_chr(comma, '/')))
+		    {
+		      int msize;
+
+		      arg = split(netpart);
+		      if (!atoi_check(netpart, &msize))
+			ret_err(gen_err);
+		      else if (inet_pton(AF_INET, comma, &new->start))
+			{
+			  int mask = (1 << (32 - msize)) - 1;
+			  new->is6 = 0; 			  
+			  new->start.s_addr = ntohl(htonl(new->start.s_addr) & ~mask);
+			  new->end.s_addr = new->start.s_addr | htonl(mask);
+			  if (arg)
+			    {
+			      if (option != 's')
+				{
+				  if (!(new->prefix = canonicalise_opt(arg)) ||
+				      strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
+				    ret_err(_("bad prefix"));
+				}
+			      else if (strcmp(arg, "local") != 0 ||
+				       (msize != 8 && msize != 16 && msize != 24))
+				ret_err(gen_err);
+			      else
+				{
+				   /* generate the equivalent of
+				      local=/xxx.yyy.zzz.in-addr.arpa/ */
+				  struct server *serv = add_rev4(new->start, msize);
+				  if (!serv)
+				    ret_err(_("bad prefix"));
+
+				  serv->flags |= SERV_NO_ADDR;
+
+				  /* local=/<domain>/ */
+				  serv = opt_malloc(sizeof(struct server));
+				  memset(serv, 0, sizeof(struct server));
+				  serv->domain = d;
+				  serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
+				  serv->next = daemon->servers;
+				  daemon->servers = serv;
+				}
+			    }
+			}
+#ifdef HAVE_IPV6
+		      else if (inet_pton(AF_INET6, comma, &new->start6))
+			{
+			  u64 mask = (1LLU << (128 - msize)) - 1LLU;
+			  u64 addrpart = addr6part(&new->start6);
+			  new->is6 = 1;
+			  
+			  /* prefix==64 overflows the mask calculation above */
+			  if (msize == 64)
+			    mask = (u64)-1LL;
+			  
+			  new->end6 = new->start6;
+			  setaddr6part(&new->start6, addrpart & ~mask);
+			  setaddr6part(&new->end6, addrpart | mask);
+			  
+			  if (msize < 64)
+			    ret_err(gen_err);
+			  else if (arg)
+			    {
+			      if (option != 's')
+				{
+				  if (!(new->prefix = canonicalise_opt(arg)) ||
+				      strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN)
+				    ret_err(_("bad prefix"));
+				}	
+			      else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
+				ret_err(gen_err);
+			      else 
+				{
+				  /* generate the equivalent of
+				     local=/xxx.yyy.zzz.ip6.arpa/ */
+				  struct server *serv = add_rev6(&new->start6, msize);
+				  serv->flags |= SERV_NO_ADDR;
+				  
+				  /* local=/<domain>/ */
+				  serv = opt_malloc(sizeof(struct server));
+				  memset(serv, 0, sizeof(struct server));
+				  serv->domain = d;
+				  serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
+				  serv->next = daemon->servers;
+				  daemon->servers = serv;
+				}
+			    }
+			}
+#endif
+		      else
+			ret_err(gen_err);
+		    }
+		  else
+		    {
+		      char *prefstr;
+		      arg = split(comma);
+		      prefstr = split(arg);
+
+		      if (inet_pton(AF_INET, comma, &new->start))
+			{
+			  new->is6 = 0;
+			  if (!arg)
+			    new->end.s_addr = new->start.s_addr;
+			  else if (!inet_pton(AF_INET, arg, &new->end))
+			    ret_err(gen_err);
+			}
+#ifdef HAVE_IPV6
+		      else if (inet_pton(AF_INET6, comma, &new->start6))
+			{
+			  new->is6 = 1;
+			  if (!arg)
+			    memcpy(&new->end6, &new->start6, IN6ADDRSZ);
+			  else if (!inet_pton(AF_INET6, arg, &new->end6))
+			    ret_err(gen_err);
+			}
+#endif
+		      else 
+			ret_err(gen_err);
+
+		      if (option != 's' && prefstr)
+			{
+			  if (!(new->prefix = canonicalise_opt(prefstr)) ||
+			      strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
+			    ret_err(_("bad prefix"));
+			}
+		    }
+
+		  new->domain = d;
+		  if (option  == 's')
+		    {
+		      new->next = daemon->cond_domain;
+		      daemon->cond_domain = new;
+		    }
+		  else
+		    {
+		      new->next = daemon->synth_domains;
+		      daemon->synth_domains = new;
+		    }
+		}
+	      else if (option == 's')
+		daemon->domain_suffix = d;
+	      else 
+		ret_err(gen_err);
+	    }
+	}
+      break;
+      
+    case LOPT_CPE_ID: /* --add-dns-client */
+      if (arg)
+	daemon->dns_client_id = opt_string_alloc(arg);
+      break;
+
+    case LOPT_ADD_MAC: /* --add-mac */
+      if (!arg)
+	set_option_bool(OPT_ADD_MAC);
+      else
+	{
+	  unhide_metas(arg);
+	  if (strcmp(arg, "base64") == 0)
+	    set_option_bool(OPT_MAC_B64);
+	  else if (strcmp(arg, "text") == 0)
+	    set_option_bool(OPT_MAC_HEX);
+	  else
+	    ret_err(gen_err);
+	}
+      break;
+
+    case 'u':  /* --user */
+      daemon->username = opt_string_alloc(arg);
+      break;
+      
+    case 'g':  /* --group */
+      daemon->groupname = opt_string_alloc(arg);
+      daemon->group_set = 1;
+      break;
+
+#ifdef HAVE_DHCP
+    case LOPT_SCRIPTUSR: /* --scriptuser */
+      daemon->scriptuser = opt_string_alloc(arg);
+      break;
+#endif
+      
+    case 'i':  /* --interface */
+      do {
+	struct iname *new = opt_malloc(sizeof(struct iname));
+	comma = split(arg);
+	new->next = daemon->if_names;
+	daemon->if_names = new;
+	/* new->name may be NULL if someone does
+	   "interface=" to disable all interfaces except loop. */
+	new->name = opt_string_alloc(arg);
+	new->used = 0;
+	arg = comma;
+      } while (arg);
+      break;
+      
+    case LOPT_TFTP: /* --enable-tftp */
+      set_option_bool(OPT_TFTP);
+      if (!arg)
+	break;
+      /* fall through */
+
+    case 'I':  /* --except-interface */
+    case '2':  /* --no-dhcp-interface */
+      do {
+	struct iname *new = opt_malloc(sizeof(struct iname));
+	comma = split(arg);
+	new->name = opt_string_alloc(arg);
+	if (option == 'I')
+	  {
+	    new->next = daemon->if_except;
+	    daemon->if_except = new;
+	  }
+	else if (option == LOPT_TFTP)
+	   {
+	    new->next = daemon->tftp_interfaces;
+	    daemon->tftp_interfaces = new;
+	  }
+	else
+	  {
+	    new->next = daemon->dhcp_except;
+	    daemon->dhcp_except = new;
+	  }
+	arg = comma;
+      } while (arg);
+      break;
+      
+    case 'B':  /* --bogus-nxdomain */
+    case LOPT_IGNORE_ADDR: /* --ignore-address */
+     {
+	struct in_addr addr;
+	unhide_metas(arg);
+	if (arg && (inet_pton(AF_INET, arg, &addr) > 0))
+	  {
+	    struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
+	    if (option == 'B')
+	      {
+		baddr->next = daemon->bogus_addr;
+		daemon->bogus_addr = baddr;
+	      }
+	    else
+	      {
+		baddr->next = daemon->ignore_addr;
+		daemon->ignore_addr = baddr;
+	      }
+	    baddr->addr = addr;
+	  }
+	else
+	  ret_err(gen_err); /* error */
+	break;	
+      }
+      
+    case 'a':  /* --listen-address */
+    case LOPT_AUTHPEER: /* --auth-peer */
+      do {
+	struct iname *new = opt_malloc(sizeof(struct iname));
+	comma = split(arg);
+	unhide_metas(arg);
+	if (arg && (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0))
+	  {
+	    new->addr.sa.sa_family = AF_INET;
+	    new->addr.in.sin_port = 0;
+#ifdef HAVE_SOCKADDR_SA_LEN
+	    new->addr.in.sin_len = sizeof(new->addr.in);
+#endif
+	  }
+#ifdef HAVE_IPV6
+	else if (arg && inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
+	  {
+	    new->addr.sa.sa_family = AF_INET6;
+	    new->addr.in6.sin6_flowinfo = 0;
+	    new->addr.in6.sin6_scope_id = 0;
+	    new->addr.in6.sin6_port = 0;
+#ifdef HAVE_SOCKADDR_SA_LEN
+	    new->addr.in6.sin6_len = sizeof(new->addr.in6);
+#endif
+	  }
+#endif
+	else
+	  ret_err(gen_err);
+
+	new->used = 0;
+	if (option == 'a')
+	  {
+	    new->next = daemon->if_addrs;
+	    daemon->if_addrs = new;
+	  }
+	else
+	  {
+	    new->next = daemon->auth_peers;
+	    daemon->auth_peers = new;
+	  } 
+	arg = comma;
+      } while (arg);
+      break;
+      
+    case 'S':            /*  --server */
+    case LOPT_LOCAL:     /*  --local */
+    case 'A':            /*  --address */
+    case LOPT_NO_REBIND: /*  --rebind-domain-ok */
+      {
+	struct server *serv, *newlist = NULL;
+	
+	unhide_metas(arg);
+	
+	if (arg && (*arg == '/' || option == LOPT_NO_REBIND))
+	  {
+	    int rebind = !(*arg == '/');
+	    char *end = NULL;
+	    if (!rebind)
+	      arg++;
+	    while (rebind || (end = split_chr(arg, '/')))
+	      {
+		char *domain = NULL;
+		/* elide leading dots - they are implied in the search algorithm */
+		while (*arg == '.') arg++;
+		/* # matches everything and becomes a zero length domain string */
+		if (strcmp(arg, "#") == 0)
+		  domain = "";
+		else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))
+		  option = '?';
+		serv = opt_malloc(sizeof(struct server));
+		memset(serv, 0, sizeof(struct server));
+		serv->next = newlist;
+		newlist = serv;
+		serv->domain = domain;
+		serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
+		arg = end;
+		if (rebind)
+		  break;
+	      }
+	    if (!newlist)
+	      ret_err(gen_err);
+	  }
+	else
+	  {
+	    newlist = opt_malloc(sizeof(struct server));
+	    memset(newlist, 0, sizeof(struct server));
+#ifdef HAVE_LOOP
+	    newlist->uid = rand32();
+#endif
+	  }
+	
+	if (servers_only && option == 'S')
+	  newlist->flags |= SERV_FROM_FILE;
+	
+	if (option == 'A')
+	  {
+	    newlist->flags |= SERV_LITERAL_ADDRESS;
+	    if (!(newlist->flags & SERV_TYPE))
+	      ret_err(gen_err);
+	  }
+	else if (option == LOPT_NO_REBIND)
+	  newlist->flags |= SERV_NO_REBIND;
+	
+	if (!arg || !*arg)
+	  {
+	    if (!(newlist->flags & SERV_NO_REBIND))
+	      newlist->flags |= SERV_NO_ADDR; /* no server */
+	  }
+
+	else if (strcmp(arg, "#") == 0)
+	  {
+	    newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
+	    if (newlist->flags & SERV_LITERAL_ADDRESS)
+	      ret_err(gen_err);
+	  }
+	else
+	  {
+	    char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
+	    if (err)
+	      ret_err(err);
+	  }
+	
+	serv = newlist;
+	while (serv->next)
+	  {
+	    serv->next->flags = serv->flags;
+	    serv->next->addr = serv->addr;
+	    serv->next->source_addr = serv->source_addr;
+	    strcpy(serv->next->interface, serv->interface);
+	    serv = serv->next;
+	  }
+	serv->next = daemon->servers;
+	daemon->servers = newlist;
+	break;
+      }
+
+    case LOPT_REV_SERV: /* --rev-server */
+      {
+	char *string;
+	int size;
+	struct server *serv;
+	struct in_addr addr4;
+#ifdef HAVE_IPV6
+	struct in6_addr addr6;
+#endif
+ 
+	unhide_metas(arg);
+	if (!arg || !(comma=split(arg)) || !(string = split_chr(arg, '/')) || !atoi_check(string, &size))
+	  ret_err(gen_err);
+
+	if (inet_pton(AF_INET, arg, &addr4))
+	  {
+	    serv = add_rev4(addr4, size);
+	    if (!serv)
+	      ret_err(_("bad prefix"));
+	  }
+#ifdef HAVE_IPV6
+	else if (inet_pton(AF_INET6, arg, &addr6))
+	  serv = add_rev6(&addr6, size);
+#endif
+	else
+	  ret_err(gen_err);
+ 
+	string = parse_server(comma, &serv->addr, &serv->source_addr, serv->interface, &serv->flags);
+	
+	if (string)
+	  ret_err(string);
+	
+	if (servers_only)
+	  serv->flags |= SERV_FROM_FILE;
+	
+	break;
+      }
+
+    case LOPT_IPSET: /* --ipset */
+#ifndef HAVE_IPSET
+      ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives"));
+      break;
+#else
+      {
+	 struct ipsets ipsets_head;
+	 struct ipsets *ipsets = &ipsets_head;
+	 int size;
+	 char *end;
+	 char **sets, **sets_pos;
+	 memset(ipsets, 0, sizeof(struct ipsets));
+	 unhide_metas(arg);
+	 if (arg && *arg == '/') 
+	   {
+	     arg++;
+	     while ((end = split_chr(arg, '/'))) 
+	       {
+		 char *domain = NULL;
+		 /* elide leading dots - they are implied in the search algorithm */
+		 while (*arg == '.')
+		   arg++;
+		 /* # matches everything and becomes a zero length domain string */
+		 if (strcmp(arg, "#") == 0 || !*arg)
+		   domain = "";
+		 else if (strlen(arg) != 0 && !(domain = canonicalise_opt(arg)))
+		   option = '?';
+		 ipsets->next = opt_malloc(sizeof(struct ipsets));
+		 ipsets = ipsets->next;
+		 memset(ipsets, 0, sizeof(struct ipsets));
+		 ipsets->domain = domain;
+		 arg = end;
+	       }
+	   } 
+	 else 
+	   {
+	     ipsets->next = opt_malloc(sizeof(struct ipsets));
+	     ipsets = ipsets->next;
+	     memset(ipsets, 0, sizeof(struct ipsets));
+	     ipsets->domain = "";
+	   }
+	 if (!arg || !*arg)
+	   {
+	     option = '?';
+	     break;
+	   }
+	 size = 2;
+	 for (end = arg; *end; ++end) 
+	   if (*end == ',')
+	       ++size;
+     
+	 sets = sets_pos = opt_malloc(sizeof(char *) * size);
+	 
+	 do {
+	   end = split(arg);
+	   *sets_pos++ = opt_string_alloc(arg);
+	   arg = end;
+	 } while (end);
+	 *sets_pos = 0;
+	 for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next)
+	   ipsets->next->sets = sets;
+	 ipsets->next = daemon->ipsets;
+	 daemon->ipsets = ipsets_head.next;
+	 
+	 break;
+      }
+#endif
+      
+    case 'c':  /* --cache-size */
+      {
+	int size;
+	
+	if (!atoi_check(arg, &size))
+	  ret_err(gen_err);
+	else
+	  {
+	    /* zero is OK, and means no caching. */
+	    
+	    if (size < 0)
+	      size = 0;
+	    else if (size > 10000)
+	      size = 10000;
+	    
+	    daemon->cachesize = size;
+	  }
+	break;
+      }
+      
+    case 'p':  /* --port */
+      if (!atoi_check16(arg, &daemon->port))
+	ret_err(gen_err);
+      break;
+    
+    case LOPT_MINPORT:  /* --min-port */
+      if (!atoi_check16(arg, &daemon->min_port))
+	ret_err(gen_err);
+      break;
+
+    case LOPT_MAXPORT:  /* --max-port */
+      if (!atoi_check16(arg, &daemon->max_port))
+	ret_err(gen_err);
+      break;
+
+    case '0':  /* --dns-forward-max */
+      if (!atoi_check(arg, &daemon->ftabsize))
+	ret_err(gen_err);
+      break;  
+    
+    case 'q': /* --log-queries */
+      set_option_bool(OPT_LOG);
+      if (arg && strcmp(arg, "extra") == 0)
+	set_option_bool(OPT_EXTRALOG);
+      break;
+
+    case LOPT_MAX_LOGS:  /* --log-async */
+      daemon->max_logs = LOG_MAX; /* default */
+      if (arg && !atoi_check(arg, &daemon->max_logs))
+	ret_err(gen_err);
+      else if (daemon->max_logs > 100)
+	daemon->max_logs = 100;
+      break;  
+
+    case 'P': /* --edns-packet-max */
+      {
+	int i;
+	if (!atoi_check(arg, &i))
+	  ret_err(gen_err);
+	daemon->edns_pktsz = (unsigned short)i;	
+	break;
+      }
+      
+    case 'Q':  /* --query-port */
+      if (!atoi_check16(arg, &daemon->query_port))
+	ret_err(gen_err);
+      /* if explicitly set to zero, use single OS ephemeral port
+	 and disable random ports */
+      if (daemon->query_port == 0)
+	daemon->osport = 1;
+      break;
+      
+    case 'T':         /* --local-ttl */
+    case LOPT_NEGTTL: /* --neg-ttl */
+    case LOPT_MAXTTL: /* --max-ttl */
+    case LOPT_MINCTTL: /* --min-cache-ttl */
+    case LOPT_MAXCTTL: /* --max-cache-ttl */
+    case LOPT_AUTHTTL: /* --auth-ttl */
+    case LOPT_DHCPTTL: /* --dhcp-ttl */
+      {
+	int ttl;
+	if (!atoi_check(arg, &ttl))
+	  ret_err(gen_err);
+	else if (option == LOPT_NEGTTL)
+	  daemon->neg_ttl = (unsigned long)ttl;
+	else if (option == LOPT_MAXTTL)
+	  daemon->max_ttl = (unsigned long)ttl;
+	else if (option == LOPT_MINCTTL)
+	  {
+	    if (ttl > TTL_FLOOR_LIMIT)
+	      ttl = TTL_FLOOR_LIMIT;
+	    daemon->min_cache_ttl = (unsigned long)ttl;
+	  }
+	else if (option == LOPT_MAXCTTL)
+	  daemon->max_cache_ttl = (unsigned long)ttl;
+	else if (option == LOPT_AUTHTTL)
+	  daemon->auth_ttl = (unsigned long)ttl;
+	else if (option == LOPT_DHCPTTL)
+	  {
+	    daemon->dhcp_ttl = (unsigned long)ttl;
+	    daemon->use_dhcp_ttl = 1;
+	  }
+	else
+	  daemon->local_ttl = (unsigned long)ttl;
+	break;
+      }
+      
+#ifdef HAVE_DHCP
+    case 'X': /* --dhcp-lease-max */
+      if (!atoi_check(arg, &daemon->dhcp_max))
+	ret_err(gen_err);
+      break;
+#endif
+      
+#ifdef HAVE_TFTP
+    case LOPT_TFTP_MAX:  /*  --tftp-max */
+      if (!atoi_check(arg, &daemon->tftp_max))
+	ret_err(gen_err);
+      break;  
+
+    case LOPT_TFTP_MTU:  /*  --tftp-mtu */
+      if (!atoi_check(arg, &daemon->tftp_mtu))
+	ret_err(gen_err);
+      break;
+
+    case LOPT_PREFIX: /* --tftp-prefix */
+      comma = split(arg);
+      if (comma)
+	{
+	  struct tftp_prefix *new = opt_malloc(sizeof(struct tftp_prefix));
+	  new->interface = opt_string_alloc(comma);
+	  new->prefix = opt_string_alloc(arg);
+	  new->next = daemon->if_prefix;
+	  daemon->if_prefix = new;
+	}
+      else
+	daemon->tftp_prefix = opt_string_alloc(arg);
+      break;
+
+    case LOPT_TFTPPORTS: /* --tftp-port-range */
+      if (!(comma = split(arg)) || 
+	  !atoi_check16(arg, &daemon->start_tftp_port) ||
+	  !atoi_check16(comma, &daemon->end_tftp_port))
+	ret_err(_("bad port range"));
+      
+      if (daemon->start_tftp_port > daemon->end_tftp_port)
+	{
+	  int tmp = daemon->start_tftp_port;
+	  daemon->start_tftp_port = daemon->end_tftp_port;
+	  daemon->end_tftp_port = tmp;
+	} 
+      
+      break;
+
+    case LOPT_APREF: /* --tftp-unique-root */
+      if (!arg || strcasecmp(arg, "ip") == 0)
+        set_option_bool(OPT_TFTP_APREF_IP);
+      else if (strcasecmp(arg, "mac") == 0)
+        set_option_bool(OPT_TFTP_APREF_MAC);
+      else
+        ret_err(gen_err);
+      break;
+#endif
+	      
+    case LOPT_BRIDGE:   /* --bridge-interface */
+      {
+	struct dhcp_bridge *new = opt_malloc(sizeof(struct dhcp_bridge));
+	if (!(comma = split(arg)) || strlen(arg) > IF_NAMESIZE - 1 )
+	  ret_err(_("bad bridge-interface"));
+	
+	strcpy(new->iface, arg);
+	new->alias = NULL;
+	new->next = daemon->bridges;
+	daemon->bridges = new;
+
+	do {
+	  arg = comma;
+	  comma = split(arg);
+	  if (strlen(arg) != 0 && strlen(arg) <= IF_NAMESIZE - 1)
+	    {
+	      struct dhcp_bridge *b = opt_malloc(sizeof(struct dhcp_bridge)); 
+	      b->next = new->alias;
+	      new->alias = b;
+	      strcpy(b->iface, arg);
+	    }
+	} while (comma);
+	
+	break;
+      }
+
+#ifdef HAVE_DHCP
+    case 'F':  /* --dhcp-range */
+      {
+	int k, leasepos = 2;
+	char *cp, *a[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+	struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
+	
+	memset (new, 0, sizeof(*new));
+	new->lease_time = DEFLEASE;
+	
+	if (!arg)
+	  {
+	    option = '?';
+	    break;
+	  }
+	
+	while(1)
+	  {
+	    for (cp = arg; *cp; cp++)
+	      if (!(*cp == ' ' || *cp == '.' || *cp == ':' || 
+		    (*cp >= 'a' && *cp <= 'f') || (*cp >= 'A' && *cp <= 'F') ||
+		    (*cp >='0' && *cp <= '9')))
+		break;
+	    
+	    if (*cp != ',' && (comma = split(arg)))
+	      {
+		if (is_tag_prefix(arg))
+		  {
+		    struct dhcp_netid *tt = opt_malloc(sizeof (struct dhcp_netid));
+		    tt->net = opt_string_alloc(arg+4);
+		    tt->next = new->filter;
+		    /* ignore empty tag */
+		    if (tt->net)
+		      new->filter = tt;
+		  }
+		else
+		  {
+		    if (new->netid.net)
+		      ret_err(_("only one tag allowed"));
+		    else if (strstr(arg, "set:") == arg)
+		      new->netid.net = opt_string_alloc(arg+4);
+		    else
+		      new->netid.net = opt_string_alloc(arg);
+		  }
+		arg = comma;
+	      }
+	    else
+	      {
+		a[0] = arg;
+		break;
+	      }
+	  }
+	
+	for (k = 1; k < 8; k++)
+	  if (!(a[k] = split(a[k-1])))
+	    break;
+	
+	if (k < 2)
+	  ret_err(_("bad dhcp-range"));
+	
+	if (inet_pton(AF_INET, a[0], &new->start))
+	  {
+	    new->next = daemon->dhcp;
+	    daemon->dhcp = new;
+	    new->end = new->start;
+	    if (strcmp(a[1], "static") == 0)
+	      new->flags |= CONTEXT_STATIC;
+	    else if (strcmp(a[1], "proxy") == 0)
+	      new->flags |= CONTEXT_PROXY;
+	    else if (!inet_pton(AF_INET, a[1], &new->end))
+	      ret_err(_("bad dhcp-range"));
+	    
+	    if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
+	      {
+		struct in_addr tmp = new->start;
+		new->start = new->end;
+		new->end = tmp;
+	      }
+	    
+	    if (k >= 3 && strchr(a[2], '.') &&  
+		(inet_pton(AF_INET, a[2], &new->netmask) > 0))
+	      {
+		new->flags |= CONTEXT_NETMASK;
+		leasepos = 3;
+		if (!is_same_net(new->start, new->end, new->netmask))
+		  ret_err(_("inconsistent DHCP range"));
+		
+	    
+		if (k >= 4 && strchr(a[3], '.') &&  
+		    (inet_pton(AF_INET, a[3], &new->broadcast) > 0))
+		  {
+		    new->flags |= CONTEXT_BRDCAST;
+		    leasepos = 4;
+		  }
+	      }
+	  }
+#ifdef HAVE_DHCP6
+	else if (inet_pton(AF_INET6, a[0], &new->start6))
+	  {
+	    new->flags |= CONTEXT_V6; 
+	    new->prefix = 64; /* default */
+	    new->end6 = new->start6;
+	    new->next = daemon->dhcp6;
+	    daemon->dhcp6 = new;
+
+	    for (leasepos = 1; leasepos < k; leasepos++)
+	      {
+		if (strcmp(a[leasepos], "static") == 0)
+		  new->flags |= CONTEXT_STATIC | CONTEXT_DHCP;
+		else if (strcmp(a[leasepos], "ra-only") == 0 || strcmp(a[leasepos], "slaac") == 0 )
+		  new->flags |= CONTEXT_RA;
+		else if (strcmp(a[leasepos], "ra-names") == 0)
+		  new->flags |= CONTEXT_RA_NAME | CONTEXT_RA;
+		else if (strcmp(a[leasepos], "ra-advrouter") == 0)
+		  new->flags |= CONTEXT_RA_ROUTER | CONTEXT_RA;
+		else if (strcmp(a[leasepos], "ra-stateless") == 0)
+		  new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP | CONTEXT_RA;
+		else if (strcmp(a[leasepos], "off-link") == 0)
+		  new->flags |= CONTEXT_RA_OFF_LINK;
+		else if (leasepos == 1 && inet_pton(AF_INET6, a[leasepos], &new->end6))
+		  new->flags |= CONTEXT_DHCP; 
+		else if (strstr(a[leasepos], "constructor:") == a[leasepos])
+		  {
+		    new->template_interface = opt_string_alloc(a[leasepos] + 12);
+		    new->flags |= CONTEXT_TEMPLATE;
+		  }
+		else  
+		  break;
+	      }
+	   	    	     
+	    /* bare integer < 128 is prefix value */
+	    if (leasepos < k)
+	      {
+		int pref;
+		for (cp = a[leasepos]; *cp; cp++)
+		  if (!(*cp >= '0' && *cp <= '9'))
+		    break;
+		if (!*cp && (pref = atoi(a[leasepos])) <= 128)
+		  {
+		    new->prefix = pref;
+		    leasepos++;
+		  }
+	      }
+	    
+	    if (new->prefix != 64)
+	      {
+		if (new->flags & CONTEXT_RA)
+		  ret_err(_("prefix length must be exactly 64 for RA subnets"));
+		else if (new->flags & CONTEXT_TEMPLATE)
+		  ret_err(_("prefix length must be exactly 64 for subnet constructors"));
+	      }
+
+	    if (new->prefix < 64)
+	      ret_err(_("prefix length must be at least 64"));
+	    
+	    if (!is_same_net6(&new->start6, &new->end6, new->prefix))
+	      ret_err(_("inconsistent DHCPv6 range"));
+
+	    /* dhcp-range=:: enables DHCP stateless on any interface */
+	    if (IN6_IS_ADDR_UNSPECIFIED(&new->start6) && !(new->flags & CONTEXT_TEMPLATE))
+	      new->prefix = 0;
+	    
+	    if (new->flags & CONTEXT_TEMPLATE)
+	      {
+		struct in6_addr zero;
+		memset(&zero, 0, sizeof(zero));
+		if (!is_same_net6(&zero, &new->start6, new->prefix))
+		  ret_err(_("prefix must be zero with \"constructor:\" argument"));
+	      }
+	    
+	    if (addr6part(&new->start6) > addr6part(&new->end6))
+	      {
+		struct in6_addr tmp = new->start6;
+		new->start6 = new->end6;
+		new->end6 = tmp;
+	      }
+	  }
+#endif
+	else
+	  ret_err(_("bad dhcp-range"));
+	
+	if (leasepos < k)
+	  {
+	    if (leasepos != k-1)
+	      ret_err(_("bad dhcp-range"));
+	    
+	    if (strcmp(a[leasepos], "infinite") == 0)
+	      new->lease_time = 0xffffffff;
+	    else if (strcmp(a[leasepos], "deprecated") == 0)
+	      new->flags |= CONTEXT_DEPRECATE;
+	    else
+	      {
+		int fac = 1;
+		if (strlen(a[leasepos]) > 0)
+		  {
+		    switch (a[leasepos][strlen(a[leasepos]) - 1])
+		      {
+		      case 'w':
+		      case 'W':
+			fac *= 7;
+			/* fall through */
+		      case 'd':
+		      case 'D':
+			fac *= 24;
+			/* fall though */
+		      case 'h':
+		      case 'H':
+			fac *= 60;
+			/* fall through */
+		      case 'm':
+		      case 'M':
+			fac *= 60;
+			/* fall through */
+		      case 's':
+		      case 'S':
+			a[leasepos][strlen(a[leasepos]) - 1] = 0;
+		      }
+		    
+		    for (cp = a[leasepos]; *cp; cp++)
+		      if (!(*cp >= '0' && *cp <= '9'))
+			break;
+
+		    if (*cp || (leasepos+1 < k))
+		      ret_err(_("bad dhcp-range"));
+		    
+		    new->lease_time = atoi(a[leasepos]) * fac;
+		    /* Leases of a minute or less confuse
+		       some clients, notably Apple's */
+		    if (new->lease_time < 120)
+		      new->lease_time = 120;
+		  }
+	      }
+	  }
+	break;
+      }
+
+    case LOPT_BANK:
+    case 'G':  /* --dhcp-host */
+      {
+	int j, k = 0;
+	char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+	struct dhcp_config *new;
+	struct in_addr in;
+	
+	new = opt_malloc(sizeof(struct dhcp_config));
+	
+	new->next = daemon->dhcp_conf;
+	new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
+	new->hwaddr = NULL;
+	new->netid = NULL;
+
+	if ((a[0] = arg))
+	  for (k = 1; k < 7; k++)
+	    if (!(a[k] = split(a[k-1])))
+	      break;
+	
+	for (j = 0; j < k; j++)
+	  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] == ':')
+		{
+		  if (arg[3] == '*')
+		    new->flags |= CONFIG_NOCLID;
+		  else
+		    {
+		      int len;
+		      arg += 3; /* dump id: */
+		      if (strchr(arg, ':'))
+			len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL);
+		      else
+			{
+			  unhide_metas(arg);
+			  len = (int) strlen(arg);
+			}
+
+		      if (len == -1)
+			ret_err(_("bad hex constant"));
+		      else if ((new->clid = opt_malloc(len)))
+			{
+			  new->flags |= CONFIG_CLID;
+			  new->clid_len = len;
+			  memcpy(new->clid, arg, len);
+			}
+		    }
+		}
+	      /* dhcp-host has strange backwards-compat needs. */
+	      else if (strstr(arg, "net:") == arg || strstr(arg, "set:") == arg)
+		{
+		  struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
+		  struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
+		  newtag->net = opt_malloc(strlen(arg + 4) + 1);
+		  newlist->next = new->netid;
+		  new->netid = newlist;
+		  newlist->list = newtag;
+		  strcpy(newtag->net, arg+4);
+		  unhide_metas(newtag->net);
+		}
+	      else if (strstr(arg, "tag:") == arg)
+		ret_err(_("cannot match tags in --dhcp-host"));
+#ifdef HAVE_DHCP6
+	      else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
+		{
+		  arg[strlen(arg)-1] = 0;
+		  arg++;
+		  
+		  if (!inet_pton(AF_INET6, arg, &new->addr6))
+		    ret_err(_("bad IPv6 address"));
+
+		  for (i= 0; i < 8; i++)
+		    if (new->addr6.s6_addr[i] != 0)
+		      break;
+
+		  /* set WILDCARD if network part all zeros */
+		  if (i == 8)
+		    new->flags |= CONFIG_WILDCARD;
+		  
+		  new->flags |= CONFIG_ADDR6;
+		}
+#endif
+	      else
+		{
+		  struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
+		  if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX, 
+						     &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)
+		    ret_err(_("bad hex constant"));
+		  else
+		    {
+		      
+		      newhw->next = new->hwaddr;
+		      new->hwaddr = newhw;
+		    }		    
+		}
+	    }
+	  else if (strchr(a[j], '.') && (inet_pton(AF_INET, a[j], &in) > 0))
+	    {
+	      struct dhcp_config *configs;
+	      
+	      new->addr = in;
+	      new->flags |= CONFIG_ADDR;
+
+	      /* If the same IP appears in more than one host config, then DISCOVER
+		 for one of the hosts will get the address, but REQUEST will be NAKed,
+		 since the address is reserved by the other one -> protocol loop. */
+	      for (configs = daemon->dhcp_conf; configs; configs = configs->next) 
+		if ((configs->flags & CONFIG_ADDR) && configs->addr.s_addr == in.s_addr)
+		  {
+		    sprintf(errstr, _("duplicate dhcp-host IP address %s"),  inet_ntoa(in));
+		    return 0;
+		  }	      
+	    }
+	  else
+	    {
+	      char *cp, *lastp = NULL, last = 0;
+	      int fac = 1, isdig = 0;
+	      
+	      if (strlen(a[j]) > 1)
+		{
+		  lastp = a[j] + strlen(a[j]) - 1;
+		  last = *lastp;
+		  switch (last)
+		    {
+		    case 'w':
+		    case 'W':
+		      fac *= 7;
+		      /* fall through */
+		    case 'd':
+		    case 'D':
+		      fac *= 24;
+		      /* fall through */
+		    case 'h':
+		    case 'H':
+		      fac *= 60;
+		      /* fall through */
+		    case 'm':
+		    case 'M':
+		      fac *= 60;
+		      /* fall through */
+		    case 's':
+		    case 'S':
+		      *lastp = 0;
+		    }
+		}
+	      
+	      for (cp = a[j]; *cp; cp++)
+		if (isdigit((unsigned char)*cp))
+		  isdig = 1;
+		else if (*cp != ' ')
+		  break;
+
+	      if (*cp)
+		{
+		  if (lastp)
+		    *lastp = last;
+		  if (strcmp(a[j], "infinite") == 0)
+		    {
+		      new->lease_time = 0xffffffff;
+		      new->flags |= CONFIG_TIME;
+		    }
+		  else if (strcmp(a[j], "ignore") == 0)
+		    new->flags |= CONFIG_DISABLE;
+		  else
+		    {
+		      if (!(new->hostname = canonicalise_opt(a[j])) ||
+			  !legal_hostname(new->hostname))
+			ret_err(_("bad DHCP host name"));
+		     
+		      new->flags |= CONFIG_NAME;
+		      new->domain = strip_hostname(new->hostname);			
+		    }
+		}
+	      else if (isdig)
+		{
+		  new->lease_time = atoi(a[j]) * fac; 
+		  /* Leases of a minute or less confuse
+		     some clients, notably Apple's */
+		  if (new->lease_time < 120)
+		    new->lease_time = 120;
+		  new->flags |= CONFIG_TIME;
+		}
+	    }
+	
+	daemon->dhcp_conf = new;
+	break;
+      }
+
+    case LOPT_TAG_IF:  /* --tag-if */
+      {
+	struct tag_if *new = opt_malloc(sizeof(struct tag_if));
+		
+	new->tag = NULL;
+	new->set = NULL;
+	new->next = NULL;
+	
+	/* preserve order */
+	if (!daemon->tag_if)
+	  daemon->tag_if = new;
+	else
+	  {
+	    struct tag_if *tmp;
+	    for (tmp = daemon->tag_if; tmp->next; tmp = tmp->next);
+	    tmp->next = new;
+	  }
+
+	while (arg)
+	  {
+	    size_t len;
+
+	    comma = split(arg);
+	    len = strlen(arg);
+
+	    if (len < 5)
+	      {
+		new->set = NULL;
+		break;
+	      }
+	    else
+	      {
+		struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
+		newtag->net = opt_malloc(len - 3);
+		strcpy(newtag->net, arg+4);
+		unhide_metas(newtag->net);
+
+		if (strstr(arg, "set:") == arg)
+		  {
+		    struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
+		    newlist->next = new->set;
+		    new->set = newlist;
+		    newlist->list = newtag;
+		  }
+		else if (strstr(arg, "tag:") == arg)
+		  {
+		    newtag->next = new->tag;
+		    new->tag = newtag;
+		  }
+		else 
+		  {
+		    new->set = NULL;
+		    free(newtag);
+		    break;
+		  }
+	      }
+	    
+	    arg = comma;
+	  }
+
+	if (!new->set)
+	  ret_err(_("bad tag-if"));
+	  
+	break;
+      }
+
+      
+    case 'O':           /* --dhcp-option */
+    case LOPT_FORCE:    /* --dhcp-option-force */
+    case LOPT_OPTS:
+    case LOPT_MATCH:    /* --dhcp-match */
+      return parse_dhcp_opt(errstr, arg, 
+			    option == LOPT_FORCE ? DHOPT_FORCE : 
+			    (option == LOPT_MATCH ? DHOPT_MATCH :
+			     (option == LOPT_OPTS ? DHOPT_BANK : 0)));
+     
+    case 'M': /* --dhcp-boot */
+      {
+	struct dhcp_netid *id = NULL;
+	while (is_tag_prefix(arg))
+	  {
+	    struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
+	    newid->next = id;
+	    id = newid;
+	    comma = split(arg);
+	    newid->net = opt_string_alloc(arg+4);
+	    arg = comma;
+	  };
+	
+	if (!arg)
+	  ret_err(gen_err);
+	else 
+	  {
+	    char *dhcp_file, *dhcp_sname = NULL, *tftp_sname = NULL;
+	    struct in_addr dhcp_next_server;
+	    struct dhcp_boot *new;
+	    comma = split(arg);
+	    dhcp_file = opt_string_alloc(arg);
+	    dhcp_next_server.s_addr = 0;
+	    if (comma)
+	      {
+		arg = comma;
+		comma = split(arg);
+		dhcp_sname = opt_string_alloc(arg);
+		if (comma)
+		  {
+		    unhide_metas(comma);
+		    if (!(inet_pton(AF_INET, comma, &dhcp_next_server) > 0))
+		      {
+			/*
+			 * The user may have specified the tftp hostname here.
+			 * save it so that it can be resolved/looked up during
+			 * actual dhcp_reply().
+			 */	
+			
+			tftp_sname = opt_string_alloc(comma);
+			dhcp_next_server.s_addr = 0;
+		      }
+		  }
+	      }
+	    
+	    new = opt_malloc(sizeof(struct dhcp_boot));
+	    new->file = dhcp_file;
+	    new->sname = dhcp_sname;
+	    new->tftp_sname = tftp_sname;
+	    new->next_server = dhcp_next_server;
+	    new->netid = id;
+	    new->next = daemon->boot_config;
+	    daemon->boot_config = new;
+	  }
+      
+	break;
+      }
+
+    case LOPT_REPLY_DELAY: /* --dhcp-reply-delay */
+      {
+	struct dhcp_netid *id = NULL;
+	while (is_tag_prefix(arg))
+	  {
+	    struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
+	    newid->next = id;
+	    id = newid;
+	    comma = split(arg);
+	    newid->net = opt_string_alloc(arg+4);
+	    arg = comma;
+	  };
+	
+	if (!arg)
+	  ret_err(gen_err);
+	else
+	  {
+	    struct delay_config *new;
+	    int delay;
+	    if (!atoi_check(arg, &delay))
+              ret_err(gen_err);
+	    
+	    new = opt_malloc(sizeof(struct delay_config));
+	    new->delay = delay;
+	    new->netid = id;
+            new->next = daemon->delay_conf;
+            daemon->delay_conf = new;
+	  }
+	
+	break;
+      }
+      
+    case LOPT_PXE_PROMT:  /* --pxe-prompt */
+       {
+	 struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
+	 int timeout;
+	 
+	 new->netid = NULL;
+	 new->opt = 10; /* PXE_MENU_PROMPT */
+
+	 while (is_tag_prefix(arg))
+	  {
+	     struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
+	     comma = split(arg);
+	     nn->next = new->netid;
+	     new->netid = nn;
+	     nn->net = opt_string_alloc(arg+4);
+	     arg = comma;
+	   }
+	 
+	 if (!arg)
+	   ret_err(gen_err);
+	 else
+	   {
+	     comma = split(arg);
+	     unhide_metas(arg);
+	     new->len = strlen(arg) + 1;
+	     new->val = opt_malloc(new->len);
+	     memcpy(new->val + 1, arg, new->len - 1);
+	     
+	     new->u.vendor_class = (unsigned char *)"PXEClient";
+	     new->flags = DHOPT_VENDOR;
+	     
+	     if (comma && atoi_check(comma, &timeout))
+	       *(new->val) = timeout;
+	     else
+	       *(new->val) = 255;
+
+	     new->next = daemon->dhcp_opts;
+	     daemon->dhcp_opts = new;
+	     daemon->enable_pxe = 1;
+	   }
+	 
+	 break;
+       }
+       
+    case LOPT_PXE_SERV:  /* --pxe-service */
+       {
+	 struct pxe_service *new = opt_malloc(sizeof(struct pxe_service));
+	 char *CSA[] = { "x86PC", "PC98", "IA64_EFI", "Alpha", "Arc_x86", "Intel_Lean_Client",
+			 "IA32_EFI", "x86-64_EFI", "Xscale_EFI", "BC_EFI",
+			 "ARM32_EFI", "ARM64_EFI", NULL };  
+	 static int boottype = 32768;
+	 
+	 new->netid = NULL;
+	 new->sname = NULL;
+	 new->server.s_addr = 0;
+
+	 while (is_tag_prefix(arg))
+	   {
+	     struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
+	     comma = split(arg);
+	     nn->next = new->netid;
+	     new->netid = nn;
+	     nn->net = opt_string_alloc(arg+4);
+	     arg = comma;
+	   }
+       
+	 if (arg && (comma = split(arg)))
+	   {
+	     for (i = 0; CSA[i]; i++)
+	       if (strcasecmp(CSA[i], arg) == 0)
+		 break;
+	     
+	     if (CSA[i] || atoi_check(arg, &i))
+	       {
+		 arg = comma;
+		 comma = split(arg);
+		 
+		 new->CSA = i;
+		 new->menu = opt_string_alloc(arg);
+		 
+		 if (!comma)
+		   {
+		     new->type = 0; /* local boot */
+		     new->basename = NULL;
+		   }
+		 else
+		   {
+		     arg = comma;
+		     comma = split(arg);
+		     if (atoi_check(arg, &i))
+		       {
+			 new->type = i;
+			 new->basename = NULL;
+		       }
+		     else
+		       {
+			 new->type = boottype++;
+			 new->basename = opt_string_alloc(arg);
+		       }
+		     
+		     if (comma)
+		       {
+			 if (!inet_pton(AF_INET, comma, &new->server))
+			   {
+			     new->server.s_addr = 0;
+			     new->sname = opt_string_alloc(comma);
+			   }
+		       
+		       }
+		   }
+		 
+		 /* Order matters */
+		 new->next = NULL;
+		 if (!daemon->pxe_services)
+		   daemon->pxe_services = new; 
+		 else
+		   {
+		     struct pxe_service *s;
+		     for (s = daemon->pxe_services; s->next; s = s->next);
+		     s->next = new;
+		   }
+		 
+		 daemon->enable_pxe = 1;
+		 break;
+		
+	       }
+	   }
+	 
+	 ret_err(gen_err);
+       }
+	 
+    case '4':  /* --dhcp-mac */
+      {
+	if (!(comma = split(arg)))
+	  ret_err(gen_err);
+	else
+	  {
+	    struct dhcp_mac *new = opt_malloc(sizeof(struct dhcp_mac));
+	    new->netid.net = opt_string_alloc(set_prefix(arg));
+	    unhide_metas(comma);
+	    new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
+	    if (new->hwaddr_len == -1)
+	      ret_err(gen_err);
+	    else
+	      {
+		new->next = daemon->dhcp_macs;
+		daemon->dhcp_macs = new;
+	      }
+	  }
+      }
+      break;
+
+#ifdef OPTION6_PREFIX_CLASS 
+    case LOPT_PREF_CLSS: /* --dhcp-prefix-class */
+      {
+	struct prefix_class *new = opt_malloc(sizeof(struct prefix_class));
+	
+	if (!(comma = split(arg)) ||
+	    !atoi_check16(comma, &new->class))
+	  ret_err(gen_err);
+	
+	new->tag.net = opt_string_alloc(set_prefix(arg));
+	new->next = daemon->prefix_classes;
+	daemon->prefix_classes = new;
+	
+	break;
+      }
+#endif
+			      
+
+    case 'U':           /* --dhcp-vendorclass */
+    case 'j':           /* --dhcp-userclass */
+    case LOPT_CIRCUIT:  /* --dhcp-circuitid */
+    case LOPT_REMOTE:   /* --dhcp-remoteid */
+    case LOPT_SUBSCR:   /* --dhcp-subscrid */
+      {
+	 unsigned char *p;
+	 int dig = 0;
+	 struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
+	 
+	 if (!(comma = split(arg)))
+	   ret_err(gen_err);
+	
+	 new->netid.net = opt_string_alloc(set_prefix(arg));
+	 /* check for hex string - must digits may include : must not have nothing else, 
+	    only allowed for agent-options. */
+	 
+	 arg = comma;
+	 if ((comma = split(arg)))
+	   {
+	     if (option  != 'U' || strstr(arg, "enterprise:") != arg)
+	       ret_err(gen_err);
+	     else
+	       new->enterprise = atoi(arg+11);
+	   }
+	 else
+	   comma = arg;
+	 
+	 for (p = (unsigned char *)comma; *p; p++)
+	   if (isxdigit(*p))
+	     dig = 1;
+	   else if (*p != ':')
+	     break;
+	 unhide_metas(comma);
+	 if (option == 'U' || option == 'j' || *p || !dig)
+	   {
+	     new->len = strlen(comma);  
+	     new->data = opt_malloc(new->len);
+	     memcpy(new->data, comma, new->len);
+	   }
+	 else
+	   {
+	     new->len = parse_hex(comma, (unsigned char *)comma, strlen(comma), NULL, NULL);
+	     new->data = opt_malloc(new->len);
+	     memcpy(new->data, comma, new->len);
+	   }
+	 
+	 switch (option)
+	   {
+	   case 'j':
+	     new->match_type = MATCH_USER;
+	     break;
+	   case 'U':
+	     new->match_type = MATCH_VENDOR;
+	     break; 
+	   case LOPT_CIRCUIT:
+	     new->match_type = MATCH_CIRCUIT;
+	     break;
+	   case LOPT_REMOTE:
+	     new->match_type = MATCH_REMOTE;
+	     break;
+	   case LOPT_SUBSCR:
+	     new->match_type = MATCH_SUBSCRIBER;
+	     break;
+	   }
+	 new->next = daemon->dhcp_vendors;
+	 daemon->dhcp_vendors = new;
+
+	 break;
+      }
+      
+    case LOPT_ALTPORT:   /* --dhcp-alternate-port */
+      if (!arg)
+	{
+	  daemon->dhcp_server_port = DHCP_SERVER_ALTPORT;
+	  daemon->dhcp_client_port = DHCP_CLIENT_ALTPORT;
+	}
+      else
+	{
+	  comma = split(arg);
+	  if (!atoi_check16(arg, &daemon->dhcp_server_port) || 
+	      (comma && !atoi_check16(comma, &daemon->dhcp_client_port)))
+	    ret_err(_("invalid port number"));
+	  if (!comma)
+	    daemon->dhcp_client_port = daemon->dhcp_server_port+1; 
+	}
+      break;
+
+    case 'J':            /* --dhcp-ignore */
+    case LOPT_NO_NAMES:  /* --dhcp-ignore-names */
+    case LOPT_BROADCAST: /* --dhcp-broadcast */
+    case '3':            /* --bootp-dynamic */
+    case LOPT_GEN_NAMES: /* --dhcp-generate-names */
+      {
+	struct dhcp_netid_list *new = opt_malloc(sizeof(struct dhcp_netid_list));
+	struct dhcp_netid *list = NULL;
+	if (option == 'J')
+	  {
+	    new->next = daemon->dhcp_ignore;
+	    daemon->dhcp_ignore = new;
+	  }
+	else if (option == LOPT_BROADCAST)
+	  {
+	    new->next = daemon->force_broadcast;
+	    daemon->force_broadcast = new;
+	  }
+	else if (option == '3')
+	  {
+	    new->next = daemon->bootp_dynamic;
+	    daemon->bootp_dynamic = new;
+	  }
+	else if (option == LOPT_GEN_NAMES)
+	  {
+	    new->next = daemon->dhcp_gen_names;
+	    daemon->dhcp_gen_names = new;
+	  }
+	else
+	  {
+	    new->next = daemon->dhcp_ignore_names;
+	    daemon->dhcp_ignore_names = new;
+	  }
+	
+	while (arg) {
+	  struct dhcp_netid *member = opt_malloc(sizeof(struct dhcp_netid));
+	  comma = split(arg);
+	  member->next = list;
+	  list = member;
+	  if (is_tag_prefix(arg))
+	    member->net = opt_string_alloc(arg+4);
+	  else
+	    member->net = opt_string_alloc(arg);
+	  arg = comma;
+	}
+	
+	new->list = list;
+	break;
+      }
+
+    case LOPT_PROXY: /* --dhcp-proxy */
+      daemon->override = 1;
+      while (arg) {
+	struct addr_list *new = opt_malloc(sizeof(struct addr_list));
+	comma = split(arg);
+	if (!(inet_pton(AF_INET, arg, &new->addr) > 0))
+	  ret_err(_("bad dhcp-proxy address"));
+	new->next = daemon->override_relays;
+	daemon->override_relays = new;
+	arg = comma;
+      }
+      break;
+
+    case LOPT_RELAY: /* --dhcp-relay */
+      {
+	struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
+	comma = split(arg);
+	new->interface = opt_string_alloc(split(comma));
+	new->iface_index = 0;
+	if (inet_pton(AF_INET, arg, &new->local) && inet_pton(AF_INET, comma, &new->server))
+	  {
+	    new->next = daemon->relay4;
+	    daemon->relay4 = new;
+	  }
+#ifdef HAVE_DHCP6
+	else if (inet_pton(AF_INET6, arg, &new->local) && inet_pton(AF_INET6, comma, &new->server))
+	  {
+	    new->next = daemon->relay6;
+	    daemon->relay6 = new;
+	  }
+#endif
+	else
+	  ret_err(_("Bad dhcp-relay"));
+	
+	break;
+      }
+
+#endif
+      
+#ifdef HAVE_DHCP6
+    case LOPT_RA_PARAM: /* --ra-param */
+      if ((comma = split(arg)))
+	{
+	  struct ra_interface *new = opt_malloc(sizeof(struct ra_interface));
+	  new->lifetime = -1;
+	  new->prio = 0;
+	  new->mtu = 0;
+	  new->mtu_name = NULL;
+	  new->name = opt_string_alloc(arg);
+	  if (strcasestr(comma, "mtu:") == comma)
+	    {
+	      arg = comma + 4;
+	      if (!(comma = split(comma)))
+	        goto err;
+	      if (!strcasecmp(arg, "off"))
+	        new->mtu = -1;
+	      else if (!atoi_check(arg, &new->mtu))
+	        new->mtu_name = opt_string_alloc(arg);
+	      else if (new->mtu < 1280)
+	        goto err;
+	    }
+	  if (strcasestr(comma, "high") == comma || strcasestr(comma, "low") == comma)
+	    {
+	      if (*comma == 'l' || *comma == 'L')
+		new->prio = 0x18;
+	      else
+		new->prio = 0x08;
+	      comma = split(comma);
+	    }
+	   arg = split(comma);
+	   if (!atoi_check(comma, &new->interval) || 
+	      (arg && !atoi_check(arg, &new->lifetime)))
+err:
+	    ret_err(_("bad RA-params"));
+	  
+	  new->next = daemon->ra_interfaces;
+	  daemon->ra_interfaces = new;
+	}
+      break;
+      
+    case LOPT_DUID: /* --dhcp-duid */
+      if (!(comma = split(arg)) || !atoi_check(arg, (int *)&daemon->duid_enterprise))
+	ret_err(_("bad DUID"));
+      else
+	{
+	  daemon->duid_config_len = parse_hex(comma,(unsigned char *)comma, strlen(comma), NULL, NULL);
+	  daemon->duid_config = opt_malloc(daemon->duid_config_len);
+	  memcpy(daemon->duid_config, comma, daemon->duid_config_len);
+	}
+      break;
+#endif
+
+    case 'V':  /* --alias */
+      {
+	char *dash, *a[3] = { NULL, NULL, NULL };
+	int k = 0;
+	struct doctor *new = opt_malloc(sizeof(struct doctor));
+	new->next = daemon->doctors;
+	daemon->doctors = new;
+	new->mask.s_addr = 0xffffffff;
+	new->end.s_addr = 0;
+
+	if ((a[0] = arg))
+	  for (k = 1; k < 3; k++)
+	    {
+	      if (!(a[k] = split(a[k-1])))
+		break;
+	      unhide_metas(a[k]);
+	    }
+	
+	dash = split_chr(a[0], '-');
+
+	if ((k < 2) || 
+	    (!(inet_pton(AF_INET, a[0], &new->in) > 0)) ||
+	    (!(inet_pton(AF_INET, a[1], &new->out) > 0)))
+	  option = '?';
+	
+	if (k == 3 && !inet_pton(AF_INET, a[2], &new->mask))
+	  option = '?';
+	
+	if (dash && 
+	    (!(inet_pton(AF_INET, dash, &new->end) > 0) ||
+	     !is_same_net(new->in, new->end, new->mask) ||
+	     ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
+	  ret_err(_("invalid alias range"));
+	
+	break;
+      }
+      
+    case LOPT_INTNAME:  /* --interface-name */
+      {
+	struct interface_name *new, **up;
+	char *domain = NULL;
+
+	comma = split(arg);
+	
+	if (!comma || !(domain = canonicalise_opt(arg)))
+	  ret_err(_("bad interface name"));
+	
+	new = opt_malloc(sizeof(struct interface_name));
+	new->next = NULL;
+	new->addr = NULL;
+	
+	/* Add to the end of the list, so that first name
+	   of an interface is used for PTR lookups. */
+	for (up = &daemon->int_names; *up; up = &((*up)->next));
+	*up = new;
+	new->name = domain;
+	new->family = 0;
+	arg = split_chr(comma, '/');
+	if (arg)
+	  {
+	    if (strcmp(arg, "4") == 0)
+	      new->family = AF_INET;
+#ifdef HAVE_IPV6
+	    else if (strcmp(arg, "6") == 0)
+	      new->family = AF_INET6;
+#endif
+	    else
+	      ret_err(gen_err);
+	  } 
+	new->intr = opt_string_alloc(comma);
+	break;
+      }
+      
+    case LOPT_CNAME: /* --cname */
+      {
+	struct cname *new;
+	char *alias, *target, *last, *pen;
+	int ttl = -1;
+
+	for (last = pen = NULL, comma = arg; comma; comma = split(comma))
+	  {
+	    pen = last;
+	    last = comma;
+	  }
+
+	if (!pen)
+	  ret_err(_("bad CNAME"));
+	
+	if (pen != arg && atoi_check(last, &ttl))
+	  last = pen;
+	  	
+    	target = canonicalise_opt(last);
+
+	while (arg != last)
+	  {
+	    alias = canonicalise_opt(arg);
+
+	    if (!alias || !target)
+	      ret_err(_("bad CNAME"));
+	    
+	    for (new = daemon->cnames; new; new = new->next)
+	      if (hostname_isequal(new->alias, alias))
+		ret_err(_("duplicate CNAME"));
+	    new = opt_malloc(sizeof(struct cname));
+	    new->next = daemon->cnames;
+	    daemon->cnames = new;
+	    new->alias = alias;
+	    new->target = target;
+	    new->ttl = ttl;
+
+	    arg += strlen(arg)+1;
+	  }
+      
+	break;
+      }
+
+    case LOPT_PTR:  /* --ptr-record */
+      {
+	struct ptr_record *new;
+	char *dom, *target = NULL;
+
+	comma = split(arg);
+	
+	if (!(dom = canonicalise_opt(arg)) ||
+	    (comma && !(target = canonicalise_opt(comma))))
+	  ret_err(_("bad PTR record"));
+	else
+	  {
+	    new = opt_malloc(sizeof(struct ptr_record));
+	    new->next = daemon->ptr;
+	    daemon->ptr = new;
+	    new->name = dom;
+	    new->ptr = target;
+	  }
+	break;
+      }
+
+    case LOPT_NAPTR: /* --naptr-record */
+      {
+	char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+	int k = 0;
+	struct naptr *new;
+	int order, pref;
+	char *name, *replace = NULL;
+
+	if ((a[0] = arg))
+	  for (k = 1; k < 7; k++)
+	    if (!(a[k] = split(a[k-1])))
+	      break;
+	
+	
+	if (k < 6 || 
+	    !(name = canonicalise_opt(a[0])) ||
+	    !atoi_check16(a[1], &order) || 
+	    !atoi_check16(a[2], &pref) ||
+	    (k == 7 && !(replace = canonicalise_opt(a[6]))))
+	  ret_err(_("bad NAPTR record"));
+	else
+	  {
+	    new = opt_malloc(sizeof(struct naptr));
+	    new->next = daemon->naptr;
+	    daemon->naptr = new;
+	    new->name = name;
+	    new->flags = opt_string_alloc(a[3]);
+	    new->services = opt_string_alloc(a[4]);
+	    new->regexp = opt_string_alloc(a[5]);
+	    new->replace = replace;
+	    new->order = order;
+	    new->pref = pref;
+	  }
+	break;
+      }
+
+    case LOPT_RR: /* dns-rr */
+      {
+       	struct txt_record *new;
+	size_t len = 0;
+	char *data;
+	int val;
+
+	comma = split(arg);
+	data = split(comma);
+		
+	new = opt_malloc(sizeof(struct txt_record));
+	new->next = daemon->rr;
+	daemon->rr = new;
+	
+	if (!atoi_check(comma, &val) || 
+	    !(new->name = canonicalise_opt(arg)) ||
+	    (data && (len = parse_hex(data, (unsigned char *)data, -1, NULL, NULL)) == -1U))
+	  ret_err(_("bad RR record"));
+	   	
+	new->class = val;
+	new->len = 0;
+	
+	if (data)
+	  {
+	    new->txt=opt_malloc(len);
+	    new->len = len;
+	    memcpy(new->txt, data, len);
+	  }
+	
+	break;
+      }
+
+    case 'Y':  /* --txt-record */
+      {
+	struct txt_record *new;
+	unsigned char *p, *cnt;
+	size_t len;
+
+	comma = split(arg);
+		
+	new = opt_malloc(sizeof(struct txt_record));
+	new->next = daemon->txt;
+	daemon->txt = new;
+	new->class = C_IN;
+	new->stat = 0;
+
+	if (!(new->name = canonicalise_opt(arg)))
+	  ret_err(_("bad TXT record"));
+	
+	len = comma ? strlen(comma) : 0;
+	len += (len/255) + 1; /* room for extra counts */
+	new->txt = p = opt_malloc(len);
+
+	cnt = p++;
+	*cnt = 0;
+	
+	while (comma && *comma)
+	  {
+	    unsigned char c = (unsigned char)*comma++;
+
+	    if (c == ',' || *cnt == 255)
+	      {
+		if (c != ',')
+		  comma--;
+		cnt = p++;
+		*cnt = 0;
+	      }
+	    else
+	      {
+		*p++ = unhide_meta(c);
+		(*cnt)++;
+	      }
+	  }
+
+	new->len = p - new->txt;
+
+	break;
+      }
+      
+    case 'W':  /* --srv-host */
+      {
+	int port = 1, priority = 0, weight = 0;
+	char *name, *target = NULL;
+	struct mx_srv_record *new;
+	
+	comma = split(arg);
+	
+	if (!(name = canonicalise_opt(arg)))
+	  ret_err(_("bad SRV record"));
+	
+	if (comma)
+	  {
+	    arg = comma;
+	    comma = split(arg);
+	    if (!(target = canonicalise_opt(arg)))
+	      ret_err(_("bad SRV target"));
+		
+	    if (comma)
+	      {
+		arg = comma;
+		comma = split(arg);
+		if (!atoi_check16(arg, &port))
+		  ret_err(_("invalid port number"));
+		
+		if (comma)
+		  {
+		    arg = comma;
+		    comma = split(arg);
+		    if (!atoi_check16(arg, &priority))
+		      ret_err(_("invalid priority"));
+			
+		    if (comma && !atoi_check16(comma, &weight))
+		      ret_err(_("invalid weight"));
+		  }
+	      }
+	  }
+	
+	new = opt_malloc(sizeof(struct mx_srv_record));
+	new->next = daemon->mxnames;
+	daemon->mxnames = new;
+	new->issrv = 1;
+	new->name = name;
+	new->target = target;
+	new->srvport = port;
+	new->priority = priority;
+	new->weight = weight;
+	break;
+      }
+      
+    case LOPT_HOST_REC: /* --host-record */
+      {
+	struct host_record *new = opt_malloc(sizeof(struct host_record));
+	memset(new, 0, sizeof(struct host_record));
+	new->ttl = -1;
+
+	if (!arg || !(comma = split(arg)))
+	  ret_err(_("Bad host-record"));
+	
+	while (arg)
+	  {
+	    struct all_addr addr;
+	    char *dig;
+
+	    for (dig = arg; *dig != 0; dig++)
+	      if (*dig < '0' || *dig > '9')
+		break;
+	    if (*dig == 0)
+	      new->ttl = atoi(arg);
+	    else if (inet_pton(AF_INET, arg, &addr))
+	      new->addr = addr.addr.addr4;
+#ifdef HAVE_IPV6
+	    else if (inet_pton(AF_INET6, arg, &addr))
+	      new->addr6 = addr.addr.addr6;
+#endif
+	    else
+	      {
+		int nomem;
+		char *canon = canonicalise(arg, &nomem);
+		struct name_list *nl = opt_malloc(sizeof(struct name_list));
+		if (!canon)
+		  ret_err(_("Bad name in host-record"));
+
+		nl->name = canon;
+		/* keep order, so that PTR record goes to first name */
+		nl->next = NULL;
+		if (!new->names)
+		  new->names = nl;
+		else
+		  { 
+		    struct name_list *tmp;
+		    for (tmp = new->names; tmp->next; tmp = tmp->next);
+		    tmp->next = nl;
+		  }
+	      }
+	    
+	    arg = comma;
+	    comma = split(arg);
+	  }
+
+	/* Keep list order */
+	if (!daemon->host_records_tail)
+	  daemon->host_records = new;
+	else
+	  daemon->host_records_tail->next = new;
+	new->next = NULL;
+	daemon->host_records_tail = new;
+	break;
+      }
+
+#ifdef HAVE_DNSSEC
+    case LOPT_DNSSEC_STAMP:
+      daemon->timestamp_file = opt_string_alloc(arg); 
+      break;
+
+    case LOPT_TRUST_ANCHOR:
+      {
+	struct ds_config *new = opt_malloc(sizeof(struct ds_config));
+      	char *cp, *cp1, *keyhex, *digest, *algo = NULL;
+	int len;
+	
+	new->class = C_IN;
+
+	if ((comma = split(arg)) && (algo = split(comma)))
+	  {
+	    int class = 0;
+	    if (strcmp(comma, "IN") == 0)
+	      class = C_IN;
+	    else if (strcmp(comma, "CH") == 0)
+	      class = C_CHAOS;
+	    else if (strcmp(comma, "HS") == 0)
+	      class = C_HESIOD;
+	    
+	    if (class != 0)
+	      {
+		new->class = class;
+		comma = algo;
+		algo = split(comma);
+	      }
+	  }
+		  
+       	if (!comma || !algo || !(digest = split(algo)) || !(keyhex = split(digest)) ||
+	    !atoi_check16(comma, &new->keytag) || 
+	    !atoi_check8(algo, &new->algo) ||
+	    !atoi_check8(digest, &new->digest_type) ||
+	    !(new->name = canonicalise_opt(arg)))
+	  ret_err(_("bad trust anchor"));
+	    
+	/* Upper bound on length */
+	len = (2*strlen(keyhex))+1;
+	new->digest = opt_malloc(len);
+	unhide_metas(keyhex);
+	/* 4034: "Whitespace is allowed within digits" */
+	for (cp = keyhex; *cp; )
+	  if (isspace(*cp))
+	    for (cp1 = cp; *cp1; cp1++)
+	      *cp1 = *(cp1+1);
+	  else
+	    cp++;
+	if ((new->digestlen = parse_hex(keyhex, (unsigned char *)new->digest, len, NULL, NULL)) == -1)
+	  ret_err(_("bad HEX in trust anchor"));
+	
+	new->next = daemon->ds;
+	daemon->ds = new;
+	
+	break;
+      }
+#endif
+		
+    default:
+      ret_err(_("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"));
+      
+    }
+  
+  return 1;
+}
+
+static void read_file(char *file, FILE *f, int hard_opt)	
+{
+  volatile int lineno = 0;
+  char *buff = daemon->namebuff;
+  
+  while (fgets(buff, MAXDNAME, f))
+    {
+      int white, i;
+      volatile int option = (hard_opt == LOPT_REV_SERV) ? 0 : hard_opt;
+      char *errmess, *p, *arg, *start;
+      size_t len;
+
+      /* Memory allocation failure longjmps here if mem_recover == 1 */ 
+      if (option != 0 || hard_opt == LOPT_REV_SERV)
+	{
+	  if (setjmp(mem_jmp))
+	    continue;
+	  mem_recover = 1;
+	}
+      
+      arg = NULL;
+      lineno++;
+      errmess = NULL;
+      
+      /* Implement quotes, inside quotes we allow \\ \" \n and \t 
+	 metacharacters get hidden also strip comments */
+      for (white = 1, p = buff; *p; p++)
+	{
+	  if (*p == '"')
+	    {
+	      memmove(p, p+1, strlen(p+1)+1);
+
+	      for(; *p && *p != '"'; p++)
+		{
+		  if (*p == '\\' && strchr("\"tnebr\\", p[1]))
+		    {
+		      if (p[1] == 't')
+			p[1] = '\t';
+		      else if (p[1] == 'n')
+			p[1] = '\n';
+		      else if (p[1] == 'b')
+			p[1] = '\b';
+		      else if (p[1] == 'r')
+			p[1] = '\r';
+		      else if (p[1] == 'e') /* escape */
+			p[1] = '\033';
+		      memmove(p, p+1, strlen(p+1)+1);
+		    }
+		  *p = hide_meta(*p);
+		}
+
+	      if (*p == 0) 
+		{
+		  errmess = _("missing \"");
+		  goto oops; 
+		}
+
+	      memmove(p, p+1, strlen(p+1)+1);
+	    }
+
+	  if (isspace(*p))
+	    {
+	      *p = ' ';
+	      white = 1;
+	    }
+	  else 
+	    {
+	      if (white && *p == '#')
+		{ 
+		  *p = 0;
+		  break;
+		}
+	      white = 0;
+	    } 
+	}
+
+      
+      /* strip leading spaces */
+      for (start = buff; *start && *start == ' '; start++);
+      
+      /* strip trailing spaces */
+      for (len = strlen(start); (len != 0) && (start[len-1] == ' '); len--);
+      
+      if (len == 0)
+	continue; 
+      else
+	start[len] = 0;
+      
+      if (option != 0)
+	arg = start;
+      else if ((p=strchr(start, '=')))
+	{
+	  /* allow spaces around "=" */
+	  for (arg = p+1; *arg == ' '; arg++);
+	  for (; p >= start && (*p == ' ' || *p == '='); p--)
+	    *p = 0;
+	}
+      else
+	arg = NULL;
+
+      if (option == 0)
+	{
+	  for (option = 0, i = 0; opts[i].name; i++) 
+	    if (strcmp(opts[i].name, start) == 0)
+	      {
+		option = opts[i].val;
+		break;
+	      }
+	  
+	  if (!option)
+	    errmess = _("bad option");
+	  else if (opts[i].has_arg == 0 && arg)
+	    errmess = _("extraneous parameter");
+	  else if (opts[i].has_arg == 1 && !arg)
+	    errmess = _("missing parameter");
+	  else if (hard_opt == LOPT_REV_SERV && option != 'S' && option != LOPT_REV_SERV)
+	    errmess = _("illegal option");
+	}
+
+    oops:
+      if (errmess)
+	strcpy(daemon->namebuff, errmess);
+	  
+      if (errmess || !one_opt(option, arg, buff, _("error"), 0, hard_opt == LOPT_REV_SERV))
+	{
+	  sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file);
+	  if (hard_opt != 0)
+	    my_syslog(LOG_ERR, "%s", daemon->namebuff);
+	  else
+	    die("%s", daemon->namebuff, EC_BADCONF);
+	}
+    }
+
+  mem_recover = 0;
+  fclose(f);
+}
+
+#ifdef HAVE_DHCP
+int option_read_dynfile(char *file, int flags)
+{
+  my_syslog(MS_DHCP | LOG_INFO, _("read %s"), file);
+  
+  if (flags & AH_DHCP_HST)
+    return one_file(file, LOPT_BANK);
+  else if (flags & AH_DHCP_OPT)
+    return one_file(file, LOPT_OPTS);
+  
+  return 0;
+}
+#endif
+
+static int one_file(char *file, int hard_opt)
+{
+  FILE *f;
+  int nofile_ok = 0;
+  static int read_stdin = 0;
+  static struct fileread {
+    dev_t dev;
+    ino_t ino;
+    struct fileread *next;
+  } *filesread = NULL;
+  
+  if (hard_opt == '7')
+    {
+      /* default conf-file reading */
+      hard_opt = 0;
+      nofile_ok = 1;
+    }
+
+  if (hard_opt == 0 && strcmp(file, "-") == 0)
+    {
+      if (read_stdin == 1)
+	return 1;
+      read_stdin = 1;
+      file = "stdin";
+      f = stdin;
+    }
+  else
+    {
+      /* ignore repeated files. */
+      struct stat statbuf;
+    
+      if (hard_opt == 0 && stat(file, &statbuf) == 0)
+	{
+	  struct fileread *r;
+	  
+	  for (r = filesread; r; r = r->next)
+	    if (r->dev == statbuf.st_dev && r->ino == statbuf.st_ino)
+	      return 1;
+	  
+	  r = safe_malloc(sizeof(struct fileread));
+	  r->next = filesread;
+	  filesread = r;
+	  r->dev = statbuf.st_dev;
+	  r->ino = statbuf.st_ino;
+	}
+      
+      if (!(f = fopen(file, "r")))
+	{   
+	  if (errno == ENOENT && nofile_ok)
+	    return 1; /* No conffile, all done. */
+	  else
+	    {
+	      char *str = _("cannot read %s: %s");
+	      if (hard_opt != 0)
+		{
+		  my_syslog(LOG_ERR, str, file, strerror(errno));
+		  return 0;
+		}
+	      else
+		die(str, file, EC_FILE);
+	    }
+	} 
+    }
+  
+  read_file(file, f, hard_opt);
+  return 1;
+}
+
+/* expand any name which is a directory */
+struct hostsfile *expand_filelist(struct hostsfile *list)
+{
+  unsigned int i;
+  struct hostsfile *ah;
+
+  /* find largest used index */
+  for (i = SRC_AH, ah = list; ah; ah = ah->next)
+    {
+      if (i <= ah->index)
+	i = ah->index + 1;
+
+      if (ah->flags & AH_DIR)
+	ah->flags |= AH_INACTIVE;
+      else
+	ah->flags &= ~AH_INACTIVE;
+    }
+
+  for (ah = list; ah; ah = ah->next)
+    if (!(ah->flags & AH_INACTIVE))
+      {
+	struct stat buf;
+	if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode))
+	  {
+	    DIR *dir_stream;
+	    struct dirent *ent;
+	    
+	    /* don't read this as a file */
+	    ah->flags |= AH_INACTIVE;
+	    
+	    if (!(dir_stream = opendir(ah->fname)))
+	      my_syslog(LOG_ERR, _("cannot access directory %s: %s"), 
+			ah->fname, strerror(errno));
+	    else
+	      {
+		while ((ent = readdir(dir_stream)))
+		  {
+		    size_t lendir = strlen(ah->fname);
+		    size_t lenfile = strlen(ent->d_name);
+		    struct hostsfile *ah1;
+		    char *path;
+		    
+		    /* ignore emacs backups and dotfiles */
+		    if (lenfile == 0 || 
+			ent->d_name[lenfile - 1] == '~' ||
+			(ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
+			ent->d_name[0] == '.')
+		      continue;
+		    
+		    /* see if we have an existing record.
+		       dir is ah->fname 
+		       file is ent->d_name
+		       path to match is ah1->fname */
+		    
+		    for (ah1 = list; ah1; ah1 = ah1->next)
+		      {
+			if (lendir < strlen(ah1->fname) &&
+			    strstr(ah1->fname, ah->fname) == ah1->fname &&
+			    ah1->fname[lendir] == '/' &&
+			    strcmp(ah1->fname + lendir + 1, ent->d_name) == 0)
+			  {
+			    ah1->flags &= ~AH_INACTIVE;
+			    break;
+			  }
+		      }
+		    
+		    /* make new record */
+		    if (!ah1)
+		      {
+			if (!(ah1 = whine_malloc(sizeof(struct hostsfile))))
+			  continue;
+			
+			if (!(path = whine_malloc(lendir + lenfile + 2)))
+			  {
+			    free(ah1);
+			    continue;
+			  }
+		      	
+			strcpy(path, ah->fname);
+			strcat(path, "/");
+			strcat(path, ent->d_name);
+			ah1->fname = path;
+			ah1->index = i++;
+			ah1->flags = AH_DIR;
+			ah1->next = list;
+			list = ah1;
+		      }
+		    
+		    /* inactivate record if not regular file */
+		    if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode))
+		      ah1->flags |= AH_INACTIVE; 
+		    
+		  }
+		closedir(dir_stream);
+	      }
+	  }
+      }
+  
+  return list;
+}
+
+void read_servers_file(void)
+{
+  FILE *f;
+
+  if (!(f = fopen(daemon->servers_file, "r")))
+    {
+       my_syslog(LOG_ERR, _("cannot read %s: %s"), daemon->servers_file, strerror(errno));
+       return;
+    }
+  
+  mark_servers(SERV_FROM_FILE);
+  cleanup_servers();
+  
+  read_file(daemon->servers_file, f, LOPT_REV_SERV);
+}
+ 
+
+#ifdef HAVE_DHCP
+void reread_dhcp(void)
+{
+  struct hostsfile *hf;
+
+  if (daemon->dhcp_hosts_file)
+    {
+      struct dhcp_config *configs, *cp, **up;
+  
+      /* remove existing... */
+      for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
+	{
+	  cp = configs->next;
+	  
+	  if (configs->flags & CONFIG_BANK)
+	    {
+	      struct hwaddr_config *mac, *tmp;
+	      struct dhcp_netid_list *list, *tmplist;
+	      
+	      for (mac = configs->hwaddr; mac; mac = tmp)
+		{
+		  tmp = mac->next;
+		  free(mac);
+		}
+
+	      if (configs->flags & CONFIG_CLID)
+		free(configs->clid);
+
+	      for (list = configs->netid; list; list = tmplist)
+		{
+		  free(list->list);
+		  tmplist = list->next;
+		  free(list);
+		}
+	      
+	      if (configs->flags & CONFIG_NAME)
+		free(configs->hostname);
+	      
+	      *up = configs->next;
+	      free(configs);
+	    }
+	  else
+	    up = &configs->next;
+	}
+      
+      daemon->dhcp_hosts_file = expand_filelist(daemon->dhcp_hosts_file);
+      for (hf = daemon->dhcp_hosts_file; hf; hf = hf->next)
+	 if (!(hf->flags & AH_INACTIVE))
+	   {
+	     if (one_file(hf->fname, LOPT_BANK))  
+	       my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
+	   }
+    }
+
+  if (daemon->dhcp_opts_file)
+    {
+      struct dhcp_opt *opts, *cp, **up;
+      struct dhcp_netid *id, *next;
+
+      for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
+	{
+	  cp = opts->next;
+	  
+	  if (opts->flags & DHOPT_BANK)
+	    {
+	      if ((opts->flags & DHOPT_VENDOR))
+		free(opts->u.vendor_class);
+	      free(opts->val);
+	      for (id = opts->netid; id; id = next)
+		{
+		  next = id->next;
+		  free(id->net);
+		  free(id);
+		}
+	      *up = opts->next;
+	      free(opts);
+	    }
+	  else
+	    up = &opts->next;
+	}
+      
+      daemon->dhcp_opts_file = expand_filelist(daemon->dhcp_opts_file);
+      for (hf = daemon->dhcp_opts_file; hf; hf = hf->next)
+	if (!(hf->flags & AH_INACTIVE))
+	  {
+	    if (one_file(hf->fname, LOPT_OPTS))  
+	      my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
+	  }
+    }
+}
+#endif
+    
+void read_opts(int argc, char **argv, char *compile_opts)
+{
+  char *buff = opt_malloc(MAXDNAME);
+  int option, conffile_opt = '7', testmode = 0;
+  char *arg, *conffile = CONFFILE;
+      
+  opterr = 0;
+
+  daemon = opt_malloc(sizeof(struct daemon));
+  memset(daemon, 0, sizeof(struct daemon));
+  daemon->namebuff = buff;
+
+  /* Set defaults - everything else is zero or NULL */
+  daemon->cachesize = CACHESIZ;
+  daemon->ftabsize = FTABSIZ;
+  daemon->port = NAMESERVER_PORT;
+  daemon->dhcp_client_port = DHCP_CLIENT_PORT;
+  daemon->dhcp_server_port = DHCP_SERVER_PORT;
+  daemon->default_resolv.is_default = 1;
+  daemon->default_resolv.name = RESOLVFILE;
+  daemon->resolv_files = &daemon->default_resolv;
+  daemon->username = CHUSER;
+  daemon->runfile =  RUNFILE;
+  daemon->dhcp_max = MAXLEASES;
+  daemon->tftp_max = TFTP_MAX_CONNECTIONS;
+  daemon->edns_pktsz = EDNS_PKTSZ;
+  daemon->log_fac = -1;
+  daemon->auth_ttl = AUTH_TTL; 
+  daemon->soa_refresh = SOA_REFRESH;
+  daemon->soa_retry = SOA_RETRY;
+  daemon->soa_expiry = SOA_EXPIRY;
+  daemon->max_port = MAX_PORT;
+
+#ifndef NO_ID
+  add_txt("version.bind", "dnsmasq-" VERSION, 0 );
+  add_txt("authors.bind", "Simon Kelley", 0);
+  add_txt("copyright.bind", COPYRIGHT, 0);
+  add_txt("cachesize.bind", NULL, TXT_STAT_CACHESIZE);
+  add_txt("insertions.bind", NULL, TXT_STAT_INSERTS);
+  add_txt("evictions.bind", NULL, TXT_STAT_EVICTIONS);
+  add_txt("misses.bind", NULL, TXT_STAT_MISSES);
+  add_txt("hits.bind", NULL, TXT_STAT_HITS);
+#ifdef HAVE_AUTH
+  add_txt("auth.bind", NULL, TXT_STAT_AUTH);
+#endif
+  add_txt("servers.bind", NULL, TXT_STAT_SERVERS);
+#endif
+
+  while (1) 
+    {
+#ifdef HAVE_GETOPT_LONG
+      option = getopt_long(argc, argv, OPTSTRING, opts, NULL);
+#else
+      option = getopt(argc, argv, OPTSTRING);
+#endif
+      
+      if (option == -1)
+	{
+	  for (; optind < argc; optind++)
+	    {
+	      unsigned char *c = (unsigned char *)argv[optind];
+	      for (; *c != 0; c++)
+		if (!isspace(*c))
+		  die(_("junk found in command line"), NULL, EC_BADCONF);
+	    }
+	  break;
+	}
+
+      /* Copy optarg so that argv doesn't get changed */
+      if (optarg)
+	{
+	  strncpy(buff, optarg, MAXDNAME);
+	  buff[MAXDNAME-1] = 0;
+	  arg = buff;
+	}
+      else
+	arg = NULL;
+      
+      /* command-line only stuff */
+      if (option == LOPT_TEST)
+	testmode = 1;
+      else if (option == 'w')
+	{
+#ifdef HAVE_DHCP
+	  if (argc == 3 && strcmp(argv[2], "dhcp") == 0)
+	    display_opts();
+#ifdef HAVE_DHCP6
+	  else if (argc == 3 && strcmp(argv[2], "dhcp6") == 0)
+	    display_opts6();
+#endif
+	  else
+#endif
+	    do_usage();
+
+	  exit(0);
+	}
+      else if (option == 'v')
+	{
+	  printf(_("Dnsmasq version %s  %s\n"), VERSION, COPYRIGHT);
+	  printf(_("Compile time options: %s\n\n"), compile_opts); 
+	  printf(_("This software comes with ABSOLUTELY NO WARRANTY.\n"));
+	  printf(_("Dnsmasq is free software, and you are welcome to redistribute it\n"));
+	  printf(_("under the terms of the GNU General Public License, version 2 or 3.\n"));
+          exit(0);
+        }
+      else if (option == 'C')
+	{
+	  conffile_opt = 0; /* file must exist */
+	  conffile = opt_string_alloc(arg);
+	}
+      else
+	{
+#ifdef HAVE_GETOPT_LONG
+	  if (!one_opt(option, arg, daemon->namebuff, _("try --help"), 1, 0))
+#else 
+	    if (!one_opt(option, arg, daemon->namebuff, _("try -w"), 1, 0)) 
+#endif  
+	    die(_("bad command line options: %s"), daemon->namebuff, EC_BADCONF);
+	}
+    }
+
+  if (conffile)
+    {
+      one_file(conffile, conffile_opt);
+      if (conffile_opt == 0)
+	free(conffile);
+    }
+
+  /* port might not be known when the address is parsed - fill in here */
+  if (daemon->servers)
+    {
+      struct server *tmp;
+      for (tmp = daemon->servers; tmp; tmp = tmp->next)
+	if (!(tmp->flags & SERV_HAS_SOURCE))
+	  {
+	    if (tmp->source_addr.sa.sa_family == AF_INET)
+	      tmp->source_addr.in.sin_port = htons(daemon->query_port);
+#ifdef HAVE_IPV6
+	    else if (tmp->source_addr.sa.sa_family == AF_INET6)
+	      tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
+#endif 
+	  }
+    } 
+  
+  if (daemon->host_records)
+    {
+      struct host_record *hr;
+      
+      for (hr = daemon->host_records; hr; hr = hr->next)
+	if (hr->ttl == -1)
+	  hr->ttl = daemon->local_ttl;
+    }
+
+  if (daemon->cnames)
+    {
+      struct cname *cn, *cn2, *cn3;
+
+#define NOLOOP 1
+#define TESTLOOP 2      
+
+      /* Fill in TTL for CNAMES noe we have local_ttl.
+	 Also prepare to do loop detection. */
+      for (cn = daemon->cnames; cn; cn = cn->next)
+	{
+	  if (cn->ttl == -1)
+	    cn->ttl = daemon->local_ttl;
+	  cn->flag = 0;
+	  cn->targetp = NULL;
+	  for (cn2 = daemon->cnames; cn2; cn2 = cn2->next)
+	    if (hostname_isequal(cn->target, cn2->alias))
+	      {
+		cn->targetp = cn2;
+		break;
+	      }
+	}
+      
+      /* Find any CNAME loops.*/
+      for (cn = daemon->cnames; cn; cn = cn->next)
+	{
+	  for (cn2 = cn->targetp; cn2; cn2 = cn2->targetp)
+	    {
+	      if (cn2->flag == NOLOOP)
+		break;
+	      
+	      if (cn2->flag == TESTLOOP)
+		die(_("CNAME loop involving %s"), cn->alias, EC_BADCONF);
+	      
+	      cn2->flag = TESTLOOP;
+	    }
+	  
+	  for (cn3 = cn->targetp; cn3 != cn2; cn3 = cn3->targetp)
+	    cn3->flag = NOLOOP;
+	}
+    }
+
+  if (daemon->if_addrs)
+    {  
+      struct iname *tmp;
+      for(tmp = daemon->if_addrs; tmp; tmp = tmp->next)
+	if (tmp->addr.sa.sa_family == AF_INET)
+	  tmp->addr.in.sin_port = htons(daemon->port);
+#ifdef HAVE_IPV6
+	else if (tmp->addr.sa.sa_family == AF_INET6)
+	  tmp->addr.in6.sin6_port = htons(daemon->port);
+#endif /* IPv6 */
+    }
+	
+  /* create default, if not specified */
+  if (daemon->authserver && !daemon->hostmaster)
+    {
+      strcpy(buff, "hostmaster.");
+      strcat(buff, daemon->authserver);
+      daemon->hostmaster = opt_string_alloc(buff);
+    }
+  
+  /* only one of these need be specified: the other defaults to the host-name */
+  if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
+    {
+      struct mx_srv_record *mx;
+      
+      if (gethostname(buff, MAXDNAME) == -1)
+	die(_("cannot get host-name: %s"), NULL, EC_MISC);
+      
+      for (mx = daemon->mxnames; mx; mx = mx->next)
+	if (!mx->issrv && hostname_isequal(mx->name, buff))
+	  break;
+      
+      if ((daemon->mxtarget || option_bool(OPT_LOCALMX)) && !mx)
+	{
+	  mx = opt_malloc(sizeof(struct mx_srv_record));
+	  mx->next = daemon->mxnames;
+	  mx->issrv = 0;
+	  mx->target = NULL;
+	  mx->name = opt_string_alloc(buff);
+	  daemon->mxnames = mx;
+	}
+      
+      if (!daemon->mxtarget)
+	daemon->mxtarget = opt_string_alloc(buff);
+
+      for (mx = daemon->mxnames; mx; mx = mx->next)
+	if (!mx->issrv && !mx->target)
+	  mx->target = daemon->mxtarget;
+    }
+
+  if (!option_bool(OPT_NO_RESOLV) &&
+      daemon->resolv_files && 
+      daemon->resolv_files->next && 
+      option_bool(OPT_NO_POLL))
+    die(_("only one resolv.conf file allowed in no-poll mode."), NULL, EC_BADCONF);
+  
+  if (option_bool(OPT_RESOLV_DOMAIN))
+    {
+      char *line;
+      FILE *f;
+
+      if (option_bool(OPT_NO_RESOLV) ||
+	  !daemon->resolv_files || 
+	  (daemon->resolv_files)->next)
+	die(_("must have exactly one resolv.conf to read domain from."), NULL, EC_BADCONF);
+      
+      if (!(f = fopen((daemon->resolv_files)->name, "r")))
+	die(_("failed to read %s: %s"), (daemon->resolv_files)->name, EC_FILE);
+      
+      while ((line = fgets(buff, MAXDNAME, f)))
+	{
+	  char *token = strtok(line, " \t\n\r");
+	  
+	  if (!token || strcmp(token, "search") != 0)
+	    continue;
+	  
+	  if ((token = strtok(NULL, " \t\n\r")) &&  
+	      (daemon->domain_suffix = canonicalise_opt(token)))
+	    break;
+	}
+
+      fclose(f);
+
+      if (!daemon->domain_suffix)
+	die(_("no search directive found in %s"), (daemon->resolv_files)->name, EC_MISC);
+    }
+
+  if (daemon->domain_suffix)
+    {
+       /* add domain for any srv record without one. */
+      struct mx_srv_record *srv;
+      
+      for (srv = daemon->mxnames; srv; srv = srv->next)
+	if (srv->issrv &&
+	    strchr(srv->name, '.') && 
+	    strchr(srv->name, '.') == strrchr(srv->name, '.'))
+	  {
+	    strcpy(buff, srv->name);
+	    strcat(buff, ".");
+	    strcat(buff, daemon->domain_suffix);
+	    free(srv->name);
+	    srv->name = opt_string_alloc(buff);
+	  }
+    }
+  else if (option_bool(OPT_DHCP_FQDN))
+    die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
+
+  /* If there's access-control config, then ignore --local-service, it's intended
+     as a system default to keep otherwise unconfigured installations safe. */
+  if (daemon->if_names || daemon->if_except || daemon->if_addrs || daemon->authserver)
+    reset_option_bool(OPT_LOCAL_SERVICE); 
+
+  if (testmode)
+    {
+      fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));
+      exit(0);
+    }
+}  
diff --git a/src/outpacket.c b/src/outpacket.c
new file mode 100644
index 0000000..e14bde0
--- /dev/null
+++ b/src/outpacket.c
@@ -0,0 +1,118 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "dnsmasq.h"
+ 
+#ifdef HAVE_DHCP6
+
+static size_t outpacket_counter;
+
+void end_opt6(int container)
+{
+   void *p = daemon->outpacket.iov_base + container + 2;
+   u16 len = outpacket_counter - container - 4 ;
+   
+   PUTSHORT(len, p);
+}
+
+void reset_counter(void)
+{
+  /* Clear out buffer when starting from beginning */
+  if (daemon->outpacket.iov_base)
+    memset(daemon->outpacket.iov_base, 0, daemon->outpacket.iov_len);
+ 
+  save_counter(0);
+}
+
+int save_counter(int newval)
+{
+  int ret = outpacket_counter;
+  
+  if (newval != -1)
+    outpacket_counter = newval;
+
+  return ret;
+}
+
+void *expand(size_t headroom)
+{
+  void *ret;
+
+  if (expand_buf(&daemon->outpacket, outpacket_counter + headroom))
+    {
+      ret = daemon->outpacket.iov_base + outpacket_counter;
+      outpacket_counter += headroom;
+      return ret;
+    }
+  
+  return NULL;
+}
+    
+int new_opt6(int opt)
+{
+  int ret = outpacket_counter;
+  void *p;
+
+  if ((p = expand(4)))
+    {
+      PUTSHORT(opt, p);
+      PUTSHORT(0, p);
+    }
+
+  return ret;
+}
+
+void *put_opt6(void *data, size_t len)
+{
+  void *p;
+
+  if ((p = expand(len)) && data)
+    memcpy(p, data, len);   
+  
+  return p;
+}
+  
+void put_opt6_long(unsigned int val)
+{
+  void *p;
+  
+  if ((p = expand(4)))  
+    PUTLONG(val, p);
+}
+
+void put_opt6_short(unsigned int val)
+{
+  void *p;
+
+  if ((p = expand(2)))
+    PUTSHORT(val, p);   
+}
+
+void put_opt6_char(unsigned int val)
+{
+  unsigned char *p;
+
+  if ((p = expand(1)))
+    *p = val;   
+}
+
+void put_opt6_string(char *s)
+{
+  put_opt6(s, strlen(s));
+}
+
+#endif
diff --git a/src/poll.c b/src/poll.c
new file mode 100644
index 0000000..17ca999
--- /dev/null
+++ b/src/poll.c
@@ -0,0 +1,125 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+/* Wrapper for poll(). Allocates and extends array of struct pollfds,
+   keeps them in fd order so that we can set and test conditions on
+   fd using a simple but efficient binary chop. */
+
+/* poll_reset()
+   poll_listen(fd, event)
+   .
+   .
+   poll_listen(fd, event);
+
+   hits = do_poll(timeout);
+
+   if (poll_check(fd, event)
+    .
+    .
+
+   if (poll_check(fd, event)
+    .
+    .
+
+    event is OR of POLLIN, POLLOUT, POLLERR, etc
+*/
+
+static struct pollfd *pollfds = NULL;
+static nfds_t nfds, arrsize = 0;
+
+/* Binary search. Returns either the pollfd with fd, or
+   if the fd doesn't match, or return equals nfds, the entry
+   to the left of which a new record should be inserted. */
+static nfds_t fd_search(int fd)
+{
+  nfds_t left, right, mid;
+  
+  if ((right = nfds) == 0)
+    return 0;
+  
+  left = 0;
+  
+  while (1)
+    {
+      if (right == left + 1)
+	return (pollfds[left].fd >= fd) ? left : right;
+      
+      mid = (left + right)/2;
+      
+      if (pollfds[mid].fd > fd)
+	right = mid;
+      else 
+	left = mid;
+    }
+}
+
+void poll_reset(void)
+{
+  nfds = 0;
+}
+
+int do_poll(int timeout)
+{
+  return poll(pollfds, nfds, timeout);
+}
+
+int poll_check(int fd, short event)
+{
+  nfds_t i = fd_search(fd);
+  
+  if (i < nfds && pollfds[i].fd == fd)
+    return pollfds[i].revents & event;
+
+  return 0;
+}
+
+void poll_listen(int fd, short event)
+{
+   nfds_t i = fd_search(fd);
+  
+   if (i < nfds && pollfds[i].fd == fd)
+     pollfds[i].events |= event;
+   else
+     {
+       if (arrsize != nfds)
+	 memmove(&pollfds[i+1], &pollfds[i], (nfds - i) * sizeof(struct pollfd));
+       else
+	 {
+	   /* Array too small, extend. */
+	   struct pollfd *new;
+
+	   arrsize = (arrsize == 0) ? 64 : arrsize * 2;
+
+	   if (!(new = whine_malloc(arrsize * sizeof(struct pollfd))))
+	     return;
+
+	   if (pollfds)
+	     {
+	       memcpy(new, pollfds, i * sizeof(struct pollfd));
+	       memcpy(&new[i+1], &pollfds[i], (nfds - i) * sizeof(struct pollfd));
+	       free(pollfds);
+	     }
+	   
+	   pollfds = new;
+	 }
+       
+       pollfds[i].fd = fd;
+       pollfds[i].events = event;
+       nfds++;
+     }
+}
diff --git a/src/radv-protocol.h b/src/radv-protocol.h
new file mode 100644
index 0000000..aec5135
--- /dev/null
+++ b/src/radv-protocol.h
@@ -0,0 +1,58 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define ALL_NODES                 "FF02::1"
+#define ALL_ROUTERS               "FF02::2"
+
+struct ping_packet {
+  u8 type, code;
+  u16 checksum;
+  u16 identifier;
+  u16 sequence_no;
+};
+
+struct ra_packet {
+  u8 type, code;
+  u16 checksum;
+  u8 hop_limit, flags;
+  u16 lifetime;
+  u32 reachable_time;
+  u32 retrans_time;
+};
+
+struct neigh_packet {
+  u8 type, code;
+  u16 checksum;
+  u16 reserved;
+  struct in6_addr target;
+};
+
+struct prefix_opt {
+  u8 type, len, prefix_len, flags;
+  u32 valid_lifetime, preferred_lifetime, reserved;
+  struct in6_addr prefix;
+};
+
+#define ICMP6_OPT_SOURCE_MAC   1
+#define ICMP6_OPT_PREFIX       3
+#define ICMP6_OPT_MTU          5
+#define ICMP6_OPT_ADV_INTERVAL 7
+#define ICMP6_OPT_RT_INFO     24
+#define ICMP6_OPT_RDNSS       25
+#define ICMP6_OPT_DNSSL       31
+
+
+
diff --git a/src/radv.c b/src/radv.c
new file mode 100644
index 0000000..9b7e52c
--- /dev/null
+++ b/src/radv.c
@@ -0,0 +1,1000 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/* NB. This code may be called during a DHCPv4 or transaction which is in ping-wait
+   It therefore cannot use any DHCP buffer resources except outpacket, which is
+   not used by DHCPv4 code. This code may also be called when DHCP 4 or 6 isn't
+   active, so we ensure that outpacket is allocated here too */
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_DHCP6
+
+#include <netinet/icmp6.h>
+
+struct ra_param {
+  time_t now;
+  int ind, managed, other, first, adv_router;
+  char *if_name;
+  struct dhcp_netid *tags;
+  struct in6_addr link_local, link_global, ula;
+  unsigned int glob_pref_time, link_pref_time, ula_pref_time, adv_interval, prio;
+  struct dhcp_context *found_context;
+};
+
+struct search_param {
+  time_t now; int iface;
+  char name[IF_NAMESIZE+1];
+};
+
+struct alias_param {
+  int iface;
+  struct dhcp_bridge *bridge;
+  int num_alias_ifs;
+  int max_alias_ifs;
+  int *alias_ifs;
+};
+
+static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
+static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_addr *dest,
+                    int send_iface);
+static int send_ra_to_aliases(int index, unsigned int type, char *mac, size_t maclen, void *parm);
+static int add_prefixes(struct in6_addr *local,  int prefix,
+			int scope, int if_index, int flags, 
+			unsigned int preferred, unsigned int valid, void *vparam);
+static int iface_search(struct in6_addr *local,  int prefix,
+			int scope, int if_index, int flags, 
+			int prefered, int valid, void *vparam);
+static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
+static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now);
+static unsigned int calc_lifetime(struct ra_interface *ra);
+static unsigned int calc_interval(struct ra_interface *ra);
+static unsigned int calc_prio(struct ra_interface *ra);
+static struct ra_interface *find_iface_param(char *iface);
+
+static int hop_limit;
+
+void ra_init(time_t now)
+{
+  struct icmp6_filter filter;
+  int fd;
+#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
+  int class = IPTOS_CLASS_CS6;
+#endif
+  int val = 255; /* radvd uses this value */
+  socklen_t len = sizeof(int);
+  struct dhcp_context *context;
+  
+  /* ensure this is around even if we're not doing DHCPv6 */
+  expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
+ 
+  /* See if we're guessing SLAAC addresses, if so we need to receive ping replies */
+  for (context = daemon->dhcp6; context; context = context->next)
+    if ((context->flags & CONTEXT_RA_NAME))
+      break;
+  
+  /* Need ICMP6 socket for transmission for DHCPv6 even when not doing RA. */
+
+  ICMP6_FILTER_SETBLOCKALL(&filter);
+  if (daemon->doing_ra)
+    {
+      ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
+      if (context)
+	ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
+    }
+  
+  if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 ||
+      getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
+#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
+      setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
+#endif
+      !fix_fd(fd) ||
+      !set_ipv6pktinfo(fd) ||
+      setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val)) ||
+      setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val)) ||
+      setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) == -1)
+    die (_("cannot create ICMPv6 socket: %s"), NULL, EC_BADNET);
+  
+   daemon->icmp6fd = fd;
+   
+   if (daemon->doing_ra)
+     ra_start_unsolicited(now, NULL);
+}
+
+void ra_start_unsolicited(time_t now, struct dhcp_context *context)
+{   
+   /* init timers so that we do ra's for some/all soon. some ra_times will end up zeroed
+     if it's not appropriate to advertise those contexts.
+     This gets re-called on a netlink route-change to re-do the advertisement
+     and pick up new interfaces */
+  
+  if (context)
+    context->ra_short_period_start = context->ra_time = now;
+  else
+    for (context = daemon->dhcp6; context; context = context->next)
+      if (!(context->flags & CONTEXT_TEMPLATE))
+	{
+	  context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
+	  /* re-do frequently for a minute or so, in case the first gets lost. */
+	  context->ra_short_period_start = now;
+	}
+}
+
+void icmp6_packet(time_t now)
+{
+  char interface[IF_NAMESIZE+1];
+  ssize_t sz; 
+  int if_index = 0;
+  struct cmsghdr *cmptr;
+  struct msghdr msg;
+  union {
+    struct cmsghdr align; /* this ensures alignment */
+    char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+  } control_u;
+  struct sockaddr_in6 from;
+  unsigned char *packet;
+  struct iname *tmp;
+
+  /* Note: use outpacket for input buffer */
+  msg.msg_control = control_u.control6;
+  msg.msg_controllen = sizeof(control_u);
+  msg.msg_flags = 0;
+  msg.msg_name = &from;
+  msg.msg_namelen = sizeof(from);
+  msg.msg_iov = &daemon->outpacket;
+  msg.msg_iovlen = 1;
+  
+  if ((sz = recv_dhcp_packet(daemon->icmp6fd, &msg)) == -1 || sz < 8)
+    return;
+   
+  packet = (unsigned char *)daemon->outpacket.iov_base;
+  
+  for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
+    if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
+      {
+	union {
+	  unsigned char *c;
+	  struct in6_pktinfo *p;
+	} p;
+	p.c = CMSG_DATA(cmptr);
+        
+	if_index = p.p->ipi6_ifindex;
+      }
+  
+  if (!indextoname(daemon->icmp6fd, if_index, interface))
+    return;
+    
+  if (!iface_check(AF_LOCAL, NULL, interface, NULL))
+    return;
+  
+  for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
+    if (tmp->name && wildcard_match(tmp->name, interface))
+      return;
+ 
+  if (packet[1] != 0)
+    return;
+  
+  if (packet[0] == ICMP6_ECHO_REPLY)
+    lease_ping_reply(&from.sin6_addr, packet, interface); 
+  else if (packet[0] == ND_ROUTER_SOLICIT)
+    {
+      char *mac = "";
+      struct dhcp_bridge *bridge, *alias;
+      
+      /* look for link-layer address option for logging */
+      if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz)
+	{
+	  if ((packet[9] * 8 - 2) * 3 - 1 >= MAXDNAME) {
+	    return;
+	  }
+	  print_mac(daemon->namebuff, &packet[10], (packet[9] * 8) - 2);
+	  mac = daemon->namebuff;
+	}
+         
+      if (!option_bool(OPT_QUIET_RA))
+	my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
+
+      /* If the incoming interface is an alias of some other one (as
+         specified by the --bridge-interface option), send an RA using
+         the context of the aliased interface. */
+      for (bridge = daemon->bridges; bridge; bridge = bridge->next)
+        {
+          int bridge_index = if_nametoindex(bridge->iface);
+          if (bridge_index)
+	    {
+	      for (alias = bridge->alias; alias; alias = alias->next)
+		if (wildcard_matchn(alias->iface, interface, IF_NAMESIZE))
+		  {
+		    /* Send an RA on if_index with information from
+		       bridge_index. */
+		    send_ra_alias(now, bridge_index, bridge->iface, NULL, if_index);
+		    break;
+		  }
+	      if (alias)
+		break;
+	    }
+        }
+
+      /* If the incoming interface wasn't an alias, send an RA using
+	 the context of the incoming interface. */
+      if (!bridge)
+	/* source address may not be valid in solicit request. */
+	send_ra(now, if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
+    }
+}
+
+static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_addr *dest, int send_iface)
+{
+  struct ra_packet *ra;
+  struct ra_param parm;
+  struct sockaddr_in6 addr;
+  struct dhcp_context *context, *tmp,  **up;
+  struct dhcp_netid iface_id;
+  struct dhcp_opt *opt_cfg;
+  struct ra_interface *ra_param = find_iface_param(iface_name);
+  int done_dns = 0, old_prefix = 0, mtu = 0;
+  unsigned int min_pref_time;
+#ifdef HAVE_LINUX_NETWORK
+  FILE *f;
+#endif
+  
+  parm.ind = iface;
+  parm.managed = 0;
+  parm.other = 0;
+  parm.found_context = NULL;
+  parm.adv_router = 0;
+  parm.if_name = iface_name;
+  parm.first = 1;
+  parm.now = now;
+  parm.glob_pref_time = parm.link_pref_time = parm.ula_pref_time = 0;
+  parm.adv_interval = calc_interval(ra_param);
+  parm.prio = calc_prio(ra_param);
+  
+  reset_counter();
+  
+  if (!(ra = expand(sizeof(struct ra_packet))))
+    return;
+  
+  ra->type = ND_ROUTER_ADVERT;
+  ra->code = 0;
+  ra->hop_limit = hop_limit;
+  ra->flags = parm.prio;
+  ra->lifetime = htons(calc_lifetime(ra_param));
+  ra->reachable_time = 0;
+  ra->retrans_time = 0;
+
+  /* set tag with name == interface */
+  iface_id.net = iface_name;
+  iface_id.next = NULL;
+  parm.tags = &iface_id; 
+  
+  for (context = daemon->dhcp6; context; context = context->next)
+    {
+      context->flags &= ~CONTEXT_RA_DONE;
+      context->netid.next = &context->netid;
+    }
+
+  if (!iface_enumerate(AF_INET6, &parm, add_prefixes))
+    return;
+
+  /* Find smallest preferred time within address classes,
+     to use as lifetime for options. This is a rather arbitrary choice. */
+  min_pref_time = 0xffffffff;
+  if (parm.glob_pref_time != 0 && parm.glob_pref_time < min_pref_time)
+    min_pref_time = parm.glob_pref_time;
+  
+  if (parm.ula_pref_time != 0 && parm.ula_pref_time < min_pref_time)
+    min_pref_time = parm.ula_pref_time;
+
+  if (parm.link_pref_time != 0 && parm.link_pref_time < min_pref_time)
+    min_pref_time = parm.link_pref_time;
+
+  /* Look for constructed contexts associated with addresses which have gone, 
+     and advertise them with preferred_time == 0  RFC 6204 4.3 L-13 */
+  for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
+    {
+      tmp = context->next;
+
+      if (context->if_index == iface && (context->flags & CONTEXT_OLD))
+	{
+	  unsigned int old = difftime(now, context->address_lost_time);
+	  
+	  if (old > context->saved_valid)
+	    { 
+	      /* We've advertised this enough, time to go */
+	     
+	      /* If this context held the timeout, and there's another context in use
+		 transfer the timeout there. */
+	      if (context->ra_time != 0 && parm.found_context && parm.found_context->ra_time == 0)
+		new_timeout(parm.found_context, iface_name, now);
+	      
+	      *up = context->next;
+	      free(context);
+	    }
+	  else
+	    {
+	      struct prefix_opt *opt;
+	      struct in6_addr local = context->start6;
+	      int do_slaac = 0;
+
+	      old_prefix = 1;
+
+	      /* zero net part of address */
+	      setaddr6part(&local, addr6part(&local) & ~((context->prefix == 64) ? (u64)-1LL : (1LLU << (128 - context->prefix)) - 1LLU));
+	     
+	      
+	      if (context->flags & CONTEXT_RA)
+		{
+		  do_slaac = 1;
+		  if (context->flags & CONTEXT_DHCP)
+		    {
+		      parm.other = 1; 
+		      if (!(context->flags & CONTEXT_RA_STATELESS))
+			parm.managed = 1;
+		    }
+		}
+	      else
+		{
+		  /* don't do RA for non-ra-only unless --enable-ra is set */
+		  if (option_bool(OPT_RA))
+		    {
+		      parm.managed = 1;
+		      parm.other = 1;
+		    }
+		}
+
+	      if ((opt = expand(sizeof(struct prefix_opt))))
+		{
+		  opt->type = ICMP6_OPT_PREFIX;
+		  opt->len = 4;
+		  opt->prefix_len = context->prefix;
+		  /* autonomous only if we're not doing dhcp, set
+                     "on-link" unless "off-link" was specified */
+		  opt->flags = (do_slaac ? 0x40 : 0) |
+                    ((context->flags & CONTEXT_RA_OFF_LINK) ? 0 : 0x80);
+		  opt->valid_lifetime = htonl(context->saved_valid - old);
+		  opt->preferred_lifetime = htonl(0);
+		  opt->reserved = 0; 
+		  opt->prefix = local;
+		  
+		  inet_ntop(AF_INET6, &local, daemon->addrbuff, ADDRSTRLEN);
+		  if (!option_bool(OPT_QUIET_RA))
+		    my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s old prefix", iface_name, daemon->addrbuff); 		    
+		}
+	   
+	      up = &context->next;
+	    }
+	}
+      else
+	up = &context->next;
+    }
+    
+  /* If we're advertising only old prefixes, set router lifetime to zero. */
+  if (old_prefix && !parm.found_context)
+    ra->lifetime = htons(0);
+
+  /* No prefixes to advertise. */
+  if (!old_prefix && !parm.found_context)
+    return; 
+  
+  /* If we're sending router address instead of prefix in at least on prefix,
+     include the advertisement interval option. */
+  if (parm.adv_router)
+    {
+      put_opt6_char(ICMP6_OPT_ADV_INTERVAL);
+      put_opt6_char(1);
+      put_opt6_short(0);
+      /* interval value is in milliseconds */
+      put_opt6_long(1000 * calc_interval(find_iface_param(iface_name)));
+    }
+
+  /* Set the MTU from ra_param if any, an MTU of 0 mean automatic for linux, */
+  /* an MTU of -1 prevents the option from being sent. */
+  if (ra_param)
+    mtu = ra_param->mtu;
+#ifdef HAVE_LINUX_NETWORK
+  /* Note that IPv6 MTU is not neccessarily the same as the IPv4 MTU
+     available from SIOCGIFMTU */
+  if (mtu == 0)
+    {
+      char *mtu_name = ra_param ? ra_param->mtu_name : NULL;
+      sprintf(daemon->namebuff, "/proc/sys/net/ipv6/conf/%s/mtu", mtu_name ? : iface_name);
+      if ((f = fopen(daemon->namebuff, "r")))
+        {
+          if (fgets(daemon->namebuff, MAXDNAME, f))
+            mtu = atoi(daemon->namebuff);
+          fclose(f);
+        }
+    }
+#endif
+  if (mtu > 0)
+    {
+      put_opt6_char(ICMP6_OPT_MTU);
+      put_opt6_char(1);
+      put_opt6_short(0);
+      put_opt6_long(mtu);
+    }
+     
+  iface_enumerate(AF_LOCAL, &send_iface, add_lla);
+ 
+  /* RDNSS, RFC 6106, use relevant DHCP6 options */
+  (void)option_filter(parm.tags, NULL, daemon->dhcp_opts6);
+  
+  for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
+    {
+      int i;
+      
+      /* netids match and not encapsulated? */
+      if (!(opt_cfg->flags & DHOPT_TAGOK))
+        continue;
+      
+      if (opt_cfg->opt == OPTION6_DNS_SERVER)
+        {
+	  struct in6_addr *a;
+	  int len;
+
+	  done_dns = 1;
+
+          if (opt_cfg->len == 0)
+	    continue;
+	  
+	  /* reduce len for any addresses we can't substitute */
+	  for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, i = 0; 
+	       i < opt_cfg->len; i += IN6ADDRSZ, a++)
+	    if ((IN6_IS_ADDR_UNSPECIFIED(a) && parm.glob_pref_time == 0) ||
+		(IN6_IS_ADDR_ULA_ZERO(a) && parm.ula_pref_time == 0) ||
+		(IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && parm.link_pref_time == 0))
+	      len -= IN6ADDRSZ;
+
+	  if (len != 0)
+	    {
+	      put_opt6_char(ICMP6_OPT_RDNSS);
+	      put_opt6_char((len/8) + 1);
+	      put_opt6_short(0);
+	      put_opt6_long(min_pref_time);
+	 
+	      for (a = (struct in6_addr *)opt_cfg->val, i = 0; i <  opt_cfg->len; i += IN6ADDRSZ, a++)
+		if (IN6_IS_ADDR_UNSPECIFIED(a))
+		  {
+		    if (parm.glob_pref_time != 0)
+		      put_opt6(&parm.link_global, IN6ADDRSZ);
+		  }
+		else if (IN6_IS_ADDR_ULA_ZERO(a))
+		  {
+		    if (parm.ula_pref_time != 0)
+		    put_opt6(&parm.ula, IN6ADDRSZ);
+		  }
+		else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
+		  {
+		    if (parm.link_pref_time != 0)
+		      put_opt6(&parm.link_local, IN6ADDRSZ);
+		  }
+		else
+		  put_opt6(a, IN6ADDRSZ);
+	    }
+	}
+      
+      if (opt_cfg->opt == OPTION6_DOMAIN_SEARCH && opt_cfg->len != 0)
+	{
+	  int len = ((opt_cfg->len+7)/8);
+	  
+	  put_opt6_char(ICMP6_OPT_DNSSL);
+	  put_opt6_char(len + 1);
+	  put_opt6_short(0);
+	  put_opt6_long(min_pref_time); 
+	  put_opt6(opt_cfg->val, opt_cfg->len);
+	  
+	  /* pad */
+	  for (i = opt_cfg->len; i < len * 8; i++)
+	    put_opt6_char(0);
+	}
+    }
+	
+  if (daemon->port == NAMESERVER_PORT && !done_dns && parm.link_pref_time != 0)
+    {
+      /* default == us, as long as we are supplying DNS service. */
+      put_opt6_char(ICMP6_OPT_RDNSS);
+      put_opt6_char(3);
+      put_opt6_short(0);
+      put_opt6_long(min_pref_time); 
+      put_opt6(&parm.link_local, IN6ADDRSZ);
+    }
+
+  /* set managed bits unless we're providing only RA on this link */
+  if (parm.managed)
+    ra->flags |= 0x80; /* M flag, managed, */
+   if (parm.other)
+    ra->flags |= 0x40; /* O flag, other */ 
+			
+  /* decide where we're sending */
+  memset(&addr, 0, sizeof(addr));
+#ifdef HAVE_SOCKADDR_SA_LEN
+  addr.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+  addr.sin6_family = AF_INET6;
+  addr.sin6_port = htons(IPPROTO_ICMPV6);
+  if (dest)
+    {
+      addr.sin6_addr = *dest;
+      if (IN6_IS_ADDR_LINKLOCAL(dest) ||
+	  IN6_IS_ADDR_MC_LINKLOCAL(dest))
+	addr.sin6_scope_id = iface;
+    }
+  else
+    {
+      inet_pton(AF_INET6, ALL_NODES, &addr.sin6_addr); 
+      setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &send_iface, sizeof(send_iface));
+    }
+  
+  while (retry_send(sendto(daemon->icmp6fd, daemon->outpacket.iov_base, 
+			   save_counter(-1), 0, (struct sockaddr *)&addr, 
+			   sizeof(addr))));
+  
+}
+
+static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
+{
+  /* Send an RA on the same interface that the RA content is based
+     on. */
+  send_ra_alias(now, iface, iface_name, dest, iface);
+}
+
+static int add_prefixes(struct in6_addr *local,  int prefix,
+			int scope, int if_index, int flags, 
+			unsigned int preferred, unsigned int valid, void *vparam)
+{
+  struct ra_param *param = vparam;
+
+  (void)scope; /* warning */
+  
+  if (if_index == param->ind)
+    {
+      if (IN6_IS_ADDR_LINKLOCAL(local))
+	{
+	  /* Can there be more than one LL address?
+	     Select the one with the longest preferred time 
+	     if there is. */
+	  if (preferred > param->link_pref_time)
+	    {
+	      param->link_pref_time = preferred;
+	      param->link_local = *local;
+	    }
+	}
+      else if (!IN6_IS_ADDR_LOOPBACK(local) &&
+	       !IN6_IS_ADDR_MULTICAST(local))
+	{
+	  int real_prefix = 0;
+	  int do_slaac = 0;
+	  int deprecate  = 0;
+	  int constructed = 0;
+	  int adv_router = 0;
+	  int off_link = 0;
+	  unsigned int time = 0xffffffff;
+	  struct dhcp_context *context;
+	  
+	  for (context = daemon->dhcp6; context; context = context->next)
+	    if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
+		prefix <= context->prefix &&
+		is_same_net6(local, &context->start6, context->prefix) &&
+		is_same_net6(local, &context->end6, context->prefix))
+	      {
+		context->saved_valid = valid;
+
+		if (context->flags & CONTEXT_RA) 
+		  {
+		    do_slaac = 1;
+		    if (context->flags & CONTEXT_DHCP)
+		      {
+			param->other = 1; 
+			if (!(context->flags & CONTEXT_RA_STATELESS))
+			  param->managed = 1;
+		      }
+		  }
+		else
+		  {
+		    /* don't do RA for non-ra-only unless --enable-ra is set */
+		    if (!option_bool(OPT_RA))
+		      continue;
+		    param->managed = 1;
+		    param->other = 1;
+		  }
+
+		/* Configured to advertise router address, not prefix. See RFC 3775 7.2 
+		 In this case we do all addresses associated with a context, 
+		 hence the real_prefix setting here. */
+		if (context->flags & CONTEXT_RA_ROUTER)
+		  {
+		    adv_router = 1;
+		    param->adv_router = 1;
+		    real_prefix = context->prefix;
+		  }
+
+		/* find floor time, don't reduce below 3 * RA interval. */
+		if (time > context->lease_time)
+		  {
+		    time = context->lease_time;
+		    if (time < ((unsigned int)(3 * param->adv_interval)))
+		      time = 3 * param->adv_interval;
+		  }
+
+		if (context->flags & CONTEXT_DEPRECATE)
+		  deprecate = 1;
+		
+		if (context->flags & CONTEXT_CONSTRUCTED)
+		  constructed = 1;
+
+
+		/* collect dhcp-range tags */
+		if (context->netid.next == &context->netid && context->netid.net)
+		  {
+		    context->netid.next = param->tags;
+		    param->tags = &context->netid;
+		  }
+		  
+		/* subsequent prefixes on the same interface 
+		   and subsequent instances of this prefix don't need timers.
+		   Be careful not to find the same prefix twice with different
+		   addresses unless we're advertising the actual addresses. */
+		if (!(context->flags & CONTEXT_RA_DONE))
+		  {
+		    if (!param->first)
+		      context->ra_time = 0;
+		    context->flags |= CONTEXT_RA_DONE;
+		    real_prefix = context->prefix;
+                    off_link = (context->flags & CONTEXT_RA_OFF_LINK);
+		  }
+
+		param->first = 0;
+		/* found_context is the _last_ one we found, so if there's 
+		   more than one, it's not the first. */
+		param->found_context = context;
+	      }
+
+	  /* configured time is ceiling */
+	  if (!constructed || valid > time)
+	    valid = time;
+	  
+	  if (flags & IFACE_DEPRECATED)
+	    preferred = 0;
+	  
+	  if (deprecate)
+	    time = 0;
+	  
+	  /* configured time is ceiling */
+	  if (!constructed || preferred > time)
+	    preferred = time;
+	  
+	  if (IN6_IS_ADDR_ULA(local))
+	    {
+	      if (preferred > param->ula_pref_time)
+		{
+		  param->ula_pref_time = preferred;
+		  param->ula = *local;
+		}
+	    }
+	  else 
+	    {
+	      if (preferred > param->glob_pref_time)
+		{
+		  param->glob_pref_time = preferred;
+		  param->link_global = *local;
+		}
+	    }
+	  
+	  if (real_prefix != 0)
+	    {
+	      struct prefix_opt *opt;
+	     	      
+	      if ((opt = expand(sizeof(struct prefix_opt))))
+		{
+		  /* zero net part of address */
+		  if (!adv_router)
+		    setaddr6part(local, addr6part(local) & ~((real_prefix == 64) ? (u64)-1LL : (1LLU << (128 - real_prefix)) - 1LLU));
+		  
+		  opt->type = ICMP6_OPT_PREFIX;
+		  opt->len = 4;
+		  opt->prefix_len = real_prefix;
+		  /* autonomous only if we're not doing dhcp, set
+                     "on-link" unless "off-link" was specified */
+		  opt->flags = (off_link ? 0 : 0x80);
+		  if (do_slaac)
+		    opt->flags |= 0x40;
+		  if (adv_router)
+		    opt->flags |= 0x20;
+		  opt->valid_lifetime = htonl(valid);
+		  opt->preferred_lifetime = htonl(preferred);
+		  opt->reserved = 0; 
+		  opt->prefix = *local;
+		  
+		  inet_ntop(AF_INET6, local, daemon->addrbuff, ADDRSTRLEN);
+		  if (!option_bool(OPT_QUIET_RA))
+		    my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff); 		    
+		}
+	    }
+	}
+    }          
+  return 1;
+}
+
+static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm)
+{
+  (void)type;
+
+  if (index == *((int *)parm))
+    {
+      /* size is in units of 8 octets and includes type and length (2 bytes)
+	 add 7 to round up */
+      int len = (maclen + 9) >> 3;
+      unsigned char *p = expand(len << 3);
+      memset(p, 0, len << 3);
+      *p++ = ICMP6_OPT_SOURCE_MAC;
+      *p++ = len;
+      memcpy(p, mac, maclen);
+
+      return 0;
+    }
+
+  return 1;
+}
+
+time_t periodic_ra(time_t now)
+{
+  struct search_param param;
+  struct dhcp_context *context;
+  time_t next_event;
+  struct alias_param aparam;
+    
+  param.now = now;
+  param.iface = 0;
+
+  while (1)
+    {
+      /* find overdue events, and time of first future event */
+      for (next_event = 0, context = daemon->dhcp6; context; context = context->next)
+	if (context->ra_time != 0)
+	  {
+	    if (difftime(context->ra_time, now) <= 0.0)
+	      break; /* overdue */
+	    
+	    if (next_event == 0 || difftime(next_event, context->ra_time) > 0.0)
+	      next_event = context->ra_time;
+	  }
+      
+      /* none overdue */
+      if (!context)
+	break;
+      
+      if ((context->flags & CONTEXT_OLD) && 
+	  context->if_index != 0 && 
+	  indextoname(daemon->icmp6fd, context->if_index, param.name))
+	{
+	  /* A context for an old address. We'll not find the interface by 
+	     looking for addresses, but we know it anyway, since the context is
+	     constructed */
+	  param.iface = context->if_index;
+	  new_timeout(context, param.name, now);
+	}
+      else if (iface_enumerate(AF_INET6, &param, iface_search))
+	/* There's a context overdue, but we can't find an interface
+	   associated with it, because it's for a subnet we dont 
+	   have an interface on. Probably we're doing DHCP on
+	   a remote subnet via a relay. Zero the timer, since we won't
+	   ever be able to send ra's and satisfy it. */
+	context->ra_time = 0;
+      
+      if (param.iface != 0 &&
+	  iface_check(AF_LOCAL, NULL, param.name, NULL))
+	{
+	  struct iname *tmp;
+	  for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
+	    if (tmp->name && wildcard_match(tmp->name, param.name))
+	      break;
+	  if (!tmp)
+            {
+              send_ra(now, param.iface, param.name, NULL); 
+
+              /* Also send on all interfaces that are aliases of this
+                 one. */
+              for (aparam.bridge = daemon->bridges;
+                   aparam.bridge;
+                   aparam.bridge = aparam.bridge->next)
+                if ((int)if_nametoindex(aparam.bridge->iface) == param.iface)
+                  {
+                    /* Count the number of alias interfaces for this
+                       'bridge', by calling iface_enumerate with
+                       send_ra_to_aliases and NULL alias_ifs. */
+                    aparam.iface = param.iface;
+                    aparam.alias_ifs = NULL;
+                    aparam.num_alias_ifs = 0;
+                    iface_enumerate(AF_LOCAL, &aparam, send_ra_to_aliases);
+                    my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s => %d alias(es)",
+                              param.name, daemon->addrbuff, aparam.num_alias_ifs);
+
+                    /* Allocate memory to store the alias interface
+                       indices. */
+                    aparam.alias_ifs = (int *)whine_malloc(aparam.num_alias_ifs *
+                                                           sizeof(int));
+                    if (aparam.alias_ifs)
+                      {
+                        /* Use iface_enumerate again to get the alias
+                           interface indices, then send on each of
+                           those. */
+                        aparam.max_alias_ifs = aparam.num_alias_ifs;
+                        aparam.num_alias_ifs = 0;
+                        iface_enumerate(AF_LOCAL, &aparam, send_ra_to_aliases);
+                        for (; aparam.num_alias_ifs; aparam.num_alias_ifs--)
+                          {
+                            my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s => i/f %d",
+                                      param.name, daemon->addrbuff,
+                                      aparam.alias_ifs[aparam.num_alias_ifs - 1]);
+                            send_ra_alias(now,
+                                          param.iface,
+                                          param.name,
+                                          NULL,
+                                          aparam.alias_ifs[aparam.num_alias_ifs - 1]);
+                          }
+                        free(aparam.alias_ifs);
+                      }
+
+                    /* The source interface can only appear in at most
+                       one --bridge-interface. */
+                    break;
+                  }
+            }
+	}
+    }      
+  return next_event;
+}
+
+static int send_ra_to_aliases(int index, unsigned int type, char *mac, size_t maclen, void *parm)
+{
+  struct alias_param *aparam = (struct alias_param *)parm;
+  char ifrn_name[IFNAMSIZ];
+  struct dhcp_bridge *alias;
+
+  (void)type;
+  (void)mac;
+  (void)maclen;
+
+  if (if_indextoname(index, ifrn_name))
+    for (alias = aparam->bridge->alias; alias; alias = alias->next)
+      if (wildcard_matchn(alias->iface, ifrn_name, IFNAMSIZ))
+        {
+          if (aparam->alias_ifs && (aparam->num_alias_ifs < aparam->max_alias_ifs))
+            aparam->alias_ifs[aparam->num_alias_ifs] = index;
+          aparam->num_alias_ifs++;
+        }
+
+  return 1;
+}
+
+static int iface_search(struct in6_addr *local,  int prefix,
+			int scope, int if_index, int flags, 
+			int preferred, int valid, void *vparam)
+{
+  struct search_param *param = vparam;
+  struct dhcp_context *context;
+
+  (void)scope;
+  (void)preferred;
+  (void)valid;
+ 
+  for (context = daemon->dhcp6; context; context = context->next)
+    if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
+	prefix <= context->prefix &&
+	is_same_net6(local, &context->start6, context->prefix) &&
+	is_same_net6(local, &context->end6, context->prefix) &&
+	context->ra_time != 0 && 
+	difftime(context->ra_time, param->now) <= 0.0)
+      {
+	/* found an interface that's overdue for RA determine new 
+	   timeout value and arrange for RA to be sent unless interface is
+	   still doing DAD.*/
+	
+	if (!(flags & IFACE_TENTATIVE))
+	  param->iface = if_index;
+	
+	/* should never fail */
+	if (!indextoname(daemon->icmp6fd, if_index, param->name))
+	  {
+	    param->iface = 0;
+	    return 0;
+	  }
+	
+	new_timeout(context, param->name, param->now);
+	
+	/* zero timers for other contexts on the same subnet, so they don't timeout 
+	   independently */
+	for (context = context->next; context; context = context->next)
+	  if (prefix <= context->prefix &&
+	      is_same_net6(local, &context->start6, context->prefix) &&
+	      is_same_net6(local, &context->end6, context->prefix))
+	    context->ra_time = 0;
+	
+	return 0; /* found, abort */
+      }
+  
+  return 1; /* keep searching */
+}
+ 
+static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now)
+{
+  if (difftime(now, context->ra_short_period_start) < 60.0)
+    /* range 5 - 20 */
+    context->ra_time = now + 5 + (rand16()/4400);
+  else
+    {
+      /* range 3/4 - 1 times MaxRtrAdvInterval */
+      unsigned int adv_interval = calc_interval(find_iface_param(iface_name));
+      context->ra_time = now + (3 * adv_interval)/4 + ((adv_interval * (unsigned int)rand16()) >> 18);
+    }
+}
+
+static struct ra_interface *find_iface_param(char *iface)
+{
+  struct ra_interface *ra;
+  
+  for (ra = daemon->ra_interfaces; ra; ra = ra->next)
+    if (wildcard_match(ra->name, iface))
+      return ra;
+
+  return NULL;
+}
+
+static unsigned int calc_interval(struct ra_interface *ra)
+{
+  int interval = 600;
+  
+  if (ra && ra->interval != 0)
+    {
+      interval = ra->interval;
+      if (interval > 1800)
+	interval = 1800;
+      else if (interval < 4)
+	interval = 4;
+    }
+  
+  return (unsigned int)interval;
+}
+
+static unsigned int calc_lifetime(struct ra_interface *ra)
+{
+  int lifetime, interval = (int)calc_interval(ra);
+  
+  if (!ra || ra->lifetime == -1) /* not specified */
+    lifetime = 3 * interval;
+  else
+    {
+      lifetime = ra->lifetime;
+      if (lifetime < interval && lifetime != 0)
+	lifetime = interval;
+      else if (lifetime > 9000)
+	lifetime = 9000;
+    }
+  
+  return (unsigned int)lifetime;
+}
+
+static unsigned int calc_prio(struct ra_interface *ra)
+{
+  if (ra)
+    return ra->prio;
+  
+  return 0;
+}
+
+#endif
diff --git a/src/rfc1035.c b/src/rfc1035.c
new file mode 100755
index 0000000..56ab88b
--- /dev/null
+++ b/src/rfc1035.c
@@ -0,0 +1,1956 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, 
+		 char *name, int isExtract, int extrabytes)
+{
+  unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
+  unsigned int j, l, namelen = 0, hops = 0;
+  int retvalue = 1;
+  
+  if (isExtract)
+    *cp = 0;
+
+  while (1)
+    { 
+      unsigned int label_type;
+
+      if (!CHECK_LEN(header, p, plen, 1))
+	return 0;
+      
+      if ((l = *p++) == 0) 
+	/* end marker */
+	{
+	  /* check that there are the correct no of bytes after the name */
+	  if (!CHECK_LEN(header, p1 ? p1 : p, plen, extrabytes))
+	    return 0;
+	  
+	  if (isExtract)
+	    {
+	      if (cp != (unsigned char *)name)
+		cp--;
+	      *cp = 0; /* terminate: lose final period */
+	    }
+	  else if (*cp != 0)
+	    retvalue = 2;
+	  
+	  if (p1) /* we jumped via compression */
+	    *pp = p1;
+	  else
+	    *pp = p;
+	  
+	  return retvalue;
+	}
+
+      label_type = l & 0xc0;
+      
+      if (label_type == 0xc0) /* pointer */
+	{ 
+	  if (!CHECK_LEN(header, p, plen, 1))
+	    return 0;
+	      
+	  /* get offset */
+	  l = (l&0x3f) << 8;
+	  l |= *p++;
+	  
+	  if (!p1) /* first jump, save location to go back to */
+	    p1 = p;
+	      
+	  hops++; /* break malicious infinite loops */
+	  if (hops > 255)
+	    return 0;
+	  
+	  p = l + (unsigned char *)header;
+	}
+      else if (label_type == 0x00)
+	{ /* label_type = 0 -> label. */
+	  namelen += l + 1; /* include period */
+	  if (namelen >= MAXDNAME)
+	    return 0;
+	  if (!CHECK_LEN(header, p, plen, l))
+	    return 0;
+	  
+	  for(j=0; j<l; j++, p++)
+	    if (isExtract)
+	      {
+		unsigned char c = *p;
+#ifdef HAVE_DNSSEC
+		if (option_bool(OPT_DNSSEC_VALID))
+		  {
+		    if (c == 0 || c == '.' || c == NAME_ESCAPE)
+		      {
+			*cp++ = NAME_ESCAPE;
+			*cp++ = c+1;
+		      }
+		    else
+		      *cp++ = c; 
+		  }
+		else
+#endif
+		if (c != 0 && c != '.')
+		  *cp++ = c;
+		else
+		  return 0;
+	      }
+	    else 
+	      {
+		unsigned char c1 = *cp, c2 = *p;
+		
+		if (c1 == 0)
+		  retvalue = 2;
+		else 
+		  {
+		    cp++;
+		    if (c1 >= 'A' && c1 <= 'Z')
+		      c1 += 'a' - 'A';
+#ifdef HAVE_DNSSEC
+		    if (option_bool(OPT_DNSSEC_VALID) && c1 == NAME_ESCAPE)
+		      c1 = (*cp++)-1;
+#endif
+		    
+		    if (c2 >= 'A' && c2 <= 'Z')
+		      c2 += 'a' - 'A';
+		     
+		    if (c1 != c2)
+		      retvalue =  2;
+		  }
+	      }
+	    
+	  if (isExtract)
+	    *cp++ = '.';
+	  else if (*cp != 0 && *cp++ != '.')
+	    retvalue = 2;
+	}
+      else
+	return 0; /* label types 0x40 and 0x80 not supported */
+    }
+}
+ 
+/* Max size of input string (for IPv6) is 75 chars.) */
+#define MAXARPANAME 75
+int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
+{
+  int j;
+  char name[MAXARPANAME+1], *cp1;
+  unsigned char *addr = (unsigned char *)addrp;
+  char *lastchunk = NULL, *penchunk = NULL;
+  
+  if (strlen(namein) > MAXARPANAME)
+    return 0;
+
+  memset(addrp, 0, sizeof(struct all_addr));
+
+  /* turn name into a series of asciiz strings */
+  /* j counts no of labels */
+  for(j = 1,cp1 = name; *namein; cp1++, namein++)
+    if (*namein == '.')
+      {
+	penchunk = lastchunk;
+        lastchunk = cp1 + 1;
+	*cp1 = 0;
+	j++;
+      }
+    else
+      *cp1 = *namein;
+  
+  *cp1 = 0;
+
+  if (j<3)
+    return 0;
+
+  if (hostname_isequal(lastchunk, "arpa") && hostname_isequal(penchunk, "in-addr"))
+    {
+      /* IP v4 */
+      /* address arrives as a name of the form
+	 www.xxx.yyy.zzz.in-addr.arpa
+	 some of the low order address octets might be missing
+	 and should be set to zero. */
+      for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
+	{
+	  /* check for digits only (weeds out things like
+	     50.0/24.67.28.64.in-addr.arpa which are used 
+	     as CNAME targets according to RFC 2317 */
+	  char *cp;
+	  for (cp = cp1; *cp; cp++)
+	    if (!isdigit((unsigned char)*cp))
+	      return 0;
+	  
+	  addr[3] = addr[2];
+	  addr[2] = addr[1];
+	  addr[1] = addr[0];
+	  addr[0] = atoi(cp1);
+	}
+
+      return F_IPV4;
+    }
+#ifdef HAVE_IPV6
+  else if (hostname_isequal(penchunk, "ip6") && 
+	   (hostname_isequal(lastchunk, "int") || hostname_isequal(lastchunk, "arpa")))
+    {
+      /* IP v6:
+         Address arrives as 0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.ip6.[int|arpa]
+    	 or \[xfedcba9876543210fedcba9876543210/128].ip6.[int|arpa]
+      
+	 Note that most of these the various representations are obsolete and 
+	 left-over from the many DNS-for-IPv6 wars. We support all the formats
+	 that we can since there is no reason not to.
+      */
+
+      if (*name == '\\' && *(name+1) == '[' && 
+	  (*(name+2) == 'x' || *(name+2) == 'X'))
+	{	  
+	  for (j = 0, cp1 = name+3; *cp1 && isxdigit((unsigned char) *cp1) && j < 32; cp1++, j++)
+	    {
+	      char xdig[2];
+	      xdig[0] = *cp1;
+	      xdig[1] = 0;
+	      if (j%2)
+		addr[j/2] |= strtol(xdig, NULL, 16);
+	      else
+		addr[j/2] = strtol(xdig, NULL, 16) << 4;
+	    }
+	  
+	  if (*cp1 == '/' && j == 32)
+	    return F_IPV6;
+	}
+      else
+	{
+	  for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
+	    {
+	      if (*(cp1+1) || !isxdigit((unsigned char)*cp1))
+		return 0;
+	      
+	      for (j = sizeof(struct all_addr)-1; j>0; j--)
+		addr[j] = (addr[j] >> 4) | (addr[j-1] << 4);
+	      addr[0] = (addr[0] >> 4) | (strtol(cp1, NULL, 16) << 4);
+	    }
+	  
+	  return F_IPV6;
+	}
+    }
+#endif
+  
+  return 0;
+}
+
+unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes)
+{
+  while(1)
+    {
+      unsigned int label_type;
+      
+      if (!CHECK_LEN(header, ansp, plen, 1))
+	return NULL;
+      
+      label_type = (*ansp) & 0xc0;
+
+      if (label_type == 0xc0)
+	{
+	  /* pointer for compression. */
+	  ansp += 2;	
+	  break;
+	}
+      else if (label_type == 0x80)
+	return NULL; /* reserved */
+      else if (label_type == 0x40)
+	{
+	  /* Extended label type */
+	  unsigned int count;
+	  
+	  if (!CHECK_LEN(header, ansp, plen, 2))
+	    return NULL;
+	  
+	  if (((*ansp++) & 0x3f) != 1)
+	    return NULL; /* we only understand bitstrings */
+	  
+	  count = *(ansp++); /* Bits in bitstring */
+	  
+	  if (count == 0) /* count == 0 means 256 bits */
+	    ansp += 32;
+	  else
+	    ansp += ((count-1)>>3)+1;
+	}
+      else
+	{ /* label type == 0 Bottom six bits is length */
+	  unsigned int len = (*ansp++) & 0x3f;
+	  
+	  if (!ADD_RDLEN(header, ansp, plen, len))
+	    return NULL;
+
+	  if (len == 0)
+	    break; /* zero length label marks the end. */
+	}
+    }
+
+  if (!CHECK_LEN(header, ansp, plen, extrabytes))
+    return NULL;
+  
+  return ansp;
+}
+
+unsigned char *skip_questions(struct dns_header *header, size_t plen)
+{
+  int q;
+  unsigned char *ansp = (unsigned char *)(header+1);
+
+  for (q = ntohs(header->qdcount); q != 0; q--)
+    {
+      if (!(ansp = skip_name(ansp, header, plen, 4)))
+	return NULL;
+      ansp += 4; /* class and type */
+    }
+  
+  return ansp;
+}
+
+unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen)
+{
+  int i, rdlen;
+  
+  for (i = 0; i < count; i++)
+    {
+      if (!(ansp = skip_name(ansp, header, plen, 10)))
+	return NULL; 
+      ansp += 8; /* type, class, TTL */
+      GETSHORT(rdlen, ansp);
+      if (!ADD_RDLEN(header, ansp, plen, rdlen))
+	return NULL;
+    }
+
+  return ansp;
+}
+
+/* CRC the question section. This is used to safely detect query 
+   retransmission and to detect answers to questions we didn't ask, which 
+   might be poisoning attacks. Note that we decode the name rather 
+   than CRC the raw bytes, since replies might be compressed differently. 
+   We ignore case in the names for the same reason. Return all-ones
+   if there is not question section. */
+#ifndef HAVE_DNSSEC
+unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
+{
+  int q;
+  unsigned int crc = 0xffffffff;
+  unsigned char *p1, *p = (unsigned char *)(header+1);
+
+  for (q = ntohs(header->qdcount); q != 0; q--) 
+    {
+      if (!extract_name(header, plen, &p, name, 1, 4))
+	return crc; /* bad packet */
+      
+      for (p1 = (unsigned char *)name; *p1; p1++)
+	{
+	  int i = 8;
+	  char c = *p1;
+
+	  if (c >= 'A' && c <= 'Z')
+	    c += 'a' - 'A';
+
+	  crc ^= c << 24;
+	  while (i--)
+	    crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
+	}
+      
+      /* CRC the class and type as well */
+      for (p1 = p; p1 < p+4; p1++)
+	{
+	  int i = 8;
+	  crc ^= *p1 << 24;
+	  while (i--)
+	    crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
+	}
+
+      p += 4;
+      if (!CHECK_LEN(header, p, plen, 0))
+	return crc; /* bad packet */
+    }
+
+  return crc;
+}
+#endif
+
+size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
+{
+  unsigned char *ansp = skip_questions(header, plen);
+    
+  /* if packet is malformed, just return as-is. */
+  if (!ansp)
+    return plen;
+  
+  if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
+			    header, plen)))
+    return plen;
+    
+  /* restore pseudoheader */
+  if (pheader && ntohs(header->arcount) == 0)
+    {
+      /* must use memmove, may overlap */
+      memmove(ansp, pheader, hlen);
+      header->arcount = htons(1);
+      ansp += hlen;
+    }
+
+  return ansp - (unsigned char *)header;
+}
+
+/* is addr in the non-globally-routed IP space? */ 
+int private_net(struct in_addr addr, int ban_localhost) 
+{
+  in_addr_t ip_addr = ntohl(addr.s_addr);
+
+  return
+    (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost)  /* 127.0.0.0/8    (loopback) */ ||
+    ((ip_addr & 0xFF000000) == 0x00000000)  /* RFC 5735 section 3. "here" network */ ||
+    ((ip_addr & 0xFF000000) == 0x0A000000)  /* 10.0.0.0/8     (private)  */ ||
+    ((ip_addr & 0xFFF00000) == 0xAC100000)  /* 172.16.0.0/12  (private)  */ ||
+    ((ip_addr & 0xFFFF0000) == 0xC0A80000)  /* 192.168.0.0/16 (private)  */ ||
+    ((ip_addr & 0xFFFF0000) == 0xA9FE0000)  /* 169.254.0.0/16 (zeroconf) */ ||
+    ((ip_addr & 0xFFFFFF00) == 0xC0000200)  /* 192.0.2.0/24   (test-net) */ ||
+    ((ip_addr & 0xFFFFFF00) == 0xC6336400)  /* 198.51.100.0/24(test-net) */ ||
+    ((ip_addr & 0xFFFFFF00) == 0xCB007100)  /* 203.0.113.0/24 (test-net) */ ||
+    ((ip_addr & 0xFFFFFFFF) == 0xFFFFFFFF)  /* 255.255.255.255/32 (broadcast)*/ ;
+}
+
+#ifdef HAVE_IPV6
+static int private_net6(struct in6_addr *a)
+{
+  return 
+    IN6_IS_ADDR_UNSPECIFIED(a) || /* RFC 6303 4.3 */
+    IN6_IS_ADDR_LOOPBACK(a) ||    /* RFC 6303 4.3 */
+    IN6_IS_ADDR_LINKLOCAL(a) ||   /* RFC 6303 4.5 */
+    ((unsigned char *)a)[0] == 0xfd ||   /* RFC 6303 4.4 */
+    ((u32 *)a)[0] == htonl(0x20010db8); /* RFC 6303 4.6 */
+}
+#endif
+
+
+static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name, int *doctored)
+{
+  int i, qtype, qclass, rdlen;
+
+  for (i = count; i != 0; i--)
+    {
+      if (name && option_bool(OPT_LOG))
+	{
+	  if (!extract_name(header, qlen, &p, name, 1, 10))
+	    return 0;
+	}
+      else if (!(p = skip_name(p, header, qlen, 10)))
+	return 0; /* bad packet */
+      
+      GETSHORT(qtype, p); 
+      GETSHORT(qclass, p);
+      p += 4; /* ttl */
+      GETSHORT(rdlen, p);
+      
+      if (qclass == C_IN && qtype == T_A)
+	{
+	  struct doctor *doctor;
+	  struct in_addr addr;
+	  
+	  if (!CHECK_LEN(header, p, qlen, INADDRSZ))
+	    return 0;
+	  
+	  /* alignment */
+	  memcpy(&addr, p, INADDRSZ);
+	  
+	  for (doctor = daemon->doctors; doctor; doctor = doctor->next)
+	    {
+	      if (doctor->end.s_addr == 0)
+		{
+		  if (!is_same_net(doctor->in, addr, doctor->mask))
+		    continue;
+		}
+	      else if (ntohl(doctor->in.s_addr) > ntohl(addr.s_addr) || 
+		       ntohl(doctor->end.s_addr) < ntohl(addr.s_addr))
+		continue;
+	      
+	      addr.s_addr &= ~doctor->mask.s_addr;
+	      addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
+	      /* Since we munged the data, the server it came from is no longer authoritative */
+	      header->hb3 &= ~HB3_AA;
+	      *doctored = 1;
+	      memcpy(p, &addr, INADDRSZ);
+	      break;
+	    }
+	}
+      else if (qtype == T_TXT && name && option_bool(OPT_LOG))
+	{
+	  unsigned char *p1 = p;
+	  if (!CHECK_LEN(header, p1, qlen, rdlen))
+	    return 0;
+	  while ((p1 - p) < rdlen)
+	    {
+	      unsigned int i, len = *p1;
+	      unsigned char *p2 = p1;
+	      if ((p1 + len - p) >= rdlen)
+	        return 0; /* bad packet */
+	      /* make counted string zero-term  and sanitise */
+	      for (i = 0; i < len; i++)
+		{
+		  if (!isprint((int)*(p2+1)))
+		    break;
+		  
+		  *p2 = *(p2+1);
+		  p2++;
+		}
+	      *p2 = 0;
+	      my_syslog(LOG_INFO, "reply %s is %s", name, p1);
+	      /* restore */
+	      memmove(p1 + 1, p1, i);
+	      *p1 = len;
+	      p1 += len+1;
+	    }
+	}		  
+      
+      if (!ADD_RDLEN(header, p, qlen, rdlen))
+	 return 0; /* bad packet */
+    }
+  
+  return p; 
+}
+
+static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doctored)
+{
+  unsigned char *p;
+  int qtype, qclass, rdlen;
+  unsigned long ttl, minttl = ULONG_MAX;
+  int i, found_soa = 0;
+  
+  /* first move to NS section and find TTL from any SOA section */
+  if (!(p = skip_questions(header, qlen)) ||
+      !(p = do_doctor(p, ntohs(header->ancount), header, qlen, name, doctored)))
+    return 0;  /* bad packet */
+  
+  for (i = ntohs(header->nscount); i != 0; i--)
+    {
+      if (!(p = skip_name(p, header, qlen, 10)))
+	return 0; /* bad packet */
+      
+      GETSHORT(qtype, p); 
+      GETSHORT(qclass, p);
+      GETLONG(ttl, p);
+      GETSHORT(rdlen, p);
+      
+      if ((qclass == C_IN) && (qtype == T_SOA))
+	{
+	  found_soa = 1;
+	  if (ttl < minttl)
+	    minttl = ttl;
+
+	  /* MNAME */
+	  if (!(p = skip_name(p, header, qlen, 0)))
+	    return 0;
+	  /* RNAME */
+	  if (!(p = skip_name(p, header, qlen, 20)))
+	    return 0;
+	  p += 16; /* SERIAL REFRESH RETRY EXPIRE */
+	  
+	  GETLONG(ttl, p); /* minTTL */
+	  if (ttl < minttl)
+	    minttl = ttl;
+	}
+      else if (!ADD_RDLEN(header, p, qlen, rdlen))
+	return 0; /* bad packet */
+    }
+  
+  /* rewrite addresses in additional section too */
+  if (!do_doctor(p, ntohs(header->arcount), header, qlen, NULL, doctored))
+    return 0;
+  
+  if (!found_soa)
+    minttl = daemon->neg_ttl;
+
+  return minttl;
+}
+
+/* Note that the following code can create CNAME chains that don't point to a real record,
+   either because of lack of memory, or lack of SOA records.  These are treated by the cache code as 
+   expired and cleaned out that way. 
+   Return 1 if we reject an address because it look like part of dns-rebinding attack. */
+int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now, 
+		      char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec, int secure, int *doctored)
+{
+  unsigned char *p, *p1, *endrr, *namep;
+  int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
+  unsigned long ttl = 0;
+  struct all_addr addr;
+#ifdef HAVE_IPSET
+  char **ipsets_cur;
+#else
+  (void)ipsets; /* unused */
+#endif
+  
+  cache_start_insert();
+
+  /* find_soa is needed for dns_doctor and logging side-effects, so don't call it lazily if there are any. */
+  if (daemon->doctors || option_bool(OPT_LOG) || option_bool(OPT_DNSSEC_VALID))
+    {
+      searched_soa = 1;
+      ttl = find_soa(header, qlen, name, doctored);
+#ifdef HAVE_DNSSEC
+      if (*doctored && secure)
+	return 0;
+#endif
+    }
+  
+  /* go through the questions. */
+  p = (unsigned char *)(header+1);
+  
+  for (i = ntohs(header->qdcount); i != 0; i--)
+    {
+      int found = 0, cname_count = CNAME_CHAIN;
+      struct crec *cpp = NULL;
+      int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
+      int secflag = secure ?  F_DNSSECOK : 0;
+      unsigned long cttl = ULONG_MAX, attl;
+
+      namep = p;
+      if (!extract_name(header, qlen, &p, name, 1, 4))
+	return 0; /* bad packet */
+           
+      GETSHORT(qtype, p); 
+      GETSHORT(qclass, p);
+      
+      if (qclass != C_IN)
+	continue;
+
+      /* PTRs: we chase CNAMEs here, since we have no way to 
+	 represent them in the cache. */
+      if (qtype == T_PTR)
+	{ 
+	  int name_encoding = in_arpa_name_2_addr(name, &addr);
+	  
+	  if (!name_encoding)
+	    continue;
+
+	  if (!(flags & F_NXDOMAIN))
+	    {
+	    cname_loop:
+	      if (!(p1 = skip_questions(header, qlen)))
+		return 0;
+	      
+	      for (j = ntohs(header->ancount); j != 0; j--) 
+		{
+		  unsigned char *tmp = namep;
+		  /* the loop body overwrites the original name, so get it back here. */
+		  if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
+		      !(res = extract_name(header, qlen, &p1, name, 0, 10)))
+		    return 0; /* bad packet */
+		  
+		  GETSHORT(aqtype, p1); 
+		  GETSHORT(aqclass, p1);
+		  GETLONG(attl, p1);
+		  if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
+		    {
+		      (p1) -= 4;
+		      PUTLONG(daemon->max_ttl, p1);
+		    }
+		  GETSHORT(ardlen, p1);
+		  endrr = p1+ardlen;
+		  
+		  /* TTL of record is minimum of CNAMES and PTR */
+		  if (attl < cttl)
+		    cttl = attl;
+
+		  if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
+		    {
+		      if (!extract_name(header, qlen, &p1, name, 1, 0))
+			return 0;
+		      
+		      if (aqtype == T_CNAME)
+			{
+			  if (!cname_count-- || secure)
+			    return 0; /* looped CNAMES, or DNSSEC, which we can't cache. */
+			  goto cname_loop;
+			}
+		      
+		      cache_insert(name, &addr, now, cttl, name_encoding | secflag | F_REVERSE);
+		      found = 1; 
+		    }
+		  
+		  p1 = endrr;
+		  if (!CHECK_LEN(header, p1, qlen, 0))
+		    return 0; /* bad packet */
+		}
+	    }
+	  
+	   if (!found && !option_bool(OPT_NO_NEG))
+	    {
+	      if (!searched_soa)
+		{
+		  searched_soa = 1;
+		  ttl = find_soa(header, qlen, NULL, doctored);
+		}
+	      if (ttl)
+		cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | secflag);	
+	    }
+	}
+      else
+	{
+	  /* everything other than PTR */
+	  struct crec *newc;
+	  int addrlen;
+
+	  if (qtype == T_A)
+	    {
+	      addrlen = INADDRSZ;
+	      flags |= F_IPV4;
+	    }
+#ifdef HAVE_IPV6
+	  else if (qtype == T_AAAA)
+	    {
+	      addrlen = IN6ADDRSZ;
+	      flags |= F_IPV6;
+	    }
+#endif
+	  else 
+	    continue;
+	    
+	cname_loop1:
+	  if (!(p1 = skip_questions(header, qlen)))
+	    return 0;
+	  
+	  for (j = ntohs(header->ancount); j != 0; j--) 
+	    {
+	      if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
+		return 0; /* bad packet */
+	      
+	      GETSHORT(aqtype, p1); 
+	      GETSHORT(aqclass, p1);
+	      GETLONG(attl, p1);
+	      if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
+		{
+		  (p1) -= 4;
+		  PUTLONG(daemon->max_ttl, p1);
+		}
+	      GETSHORT(ardlen, p1);
+	      endrr = p1+ardlen;
+	      
+	      if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
+		{
+		  if (aqtype == T_CNAME)
+		    {
+		      if (!cname_count--)
+			return 0; /* looped CNAMES */
+		      newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD | secflag);
+		      if (newc)
+			{
+			  newc->addr.cname.target.cache = NULL;
+			  /* anything other than zero, to avoid being mistaken for CNAME to interface-name */ 
+			  newc->addr.cname.uid = 1; 
+			  if (cpp)
+			    {
+			      cpp->addr.cname.target.cache = newc;
+			      cpp->addr.cname.uid = newc->uid;
+			    }
+			}
+		      
+		      cpp = newc;
+		      if (attl < cttl)
+			cttl = attl;
+		      
+		      if (!extract_name(header, qlen, &p1, name, 1, 0))
+			return 0;
+		      goto cname_loop1;
+		    }
+		  else if (!(flags & F_NXDOMAIN))
+		    {
+		      found = 1;
+		      
+		      /* copy address into aligned storage */
+		      if (!CHECK_LEN(header, p1, qlen, addrlen))
+			return 0; /* bad packet */
+		      memcpy(&addr, p1, addrlen);
+		      
+		      /* check for returned address in private space */
+		      if (check_rebind)
+			{
+			  if ((flags & F_IPV4) &&
+			      private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
+			    return 1;
+			  
+#ifdef HAVE_IPV6
+			  if ((flags & F_IPV6) &&
+			      IN6_IS_ADDR_V4MAPPED(&addr.addr.addr6))
+			    {
+			      struct in_addr v4;
+			      v4.s_addr = ((const uint32_t *) (&addr.addr.addr6))[3];
+			      if (private_net(v4, !option_bool(OPT_LOCAL_REBIND)))
+				return 1;
+			    }
+#endif
+			}
+		      
+#ifdef HAVE_IPSET
+		      if (ipsets && (flags & (F_IPV4 | F_IPV6)))
+			{
+			  ipsets_cur = ipsets;
+			  while (*ipsets_cur)
+			    {
+			      log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, name, &addr, *ipsets_cur);
+			      add_to_ipset(*ipsets_cur++, &addr, flags, 0);
+			    }
+			}
+#endif
+		      
+		      newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD | secflag);
+		      if (newc && cpp)
+			{
+			  cpp->addr.cname.target.cache = newc;
+			  cpp->addr.cname.uid = newc->uid;
+			}
+		      cpp = NULL;
+		    }
+		}
+	      
+	      p1 = endrr;
+	      if (!CHECK_LEN(header, p1, qlen, 0))
+		return 0; /* bad packet */
+	    }
+	  
+	  if (!found && !option_bool(OPT_NO_NEG))
+	    {
+	      if (!searched_soa)
+		{
+		  searched_soa = 1;
+		  ttl = find_soa(header, qlen, NULL, doctored);
+		}
+	      /* If there's no SOA to get the TTL from, but there is a CNAME 
+		 pointing at this, inherit its TTL */
+	      if (ttl || cpp)
+		{
+		  newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | secflag);	
+		  if (newc && cpp)
+		    {
+		      cpp->addr.cname.target.cache = newc;
+		      cpp->addr.cname.uid = newc->uid;
+		    }
+		}
+	    }
+	}
+    }
+  
+  /* Don't put stuff from a truncated packet into the cache.
+     Don't cache replies from non-recursive nameservers, since we may get a 
+     reply containing a CNAME but not its target, even though the target 
+     does exist. */
+  if (!(header->hb3 & HB3_TC) && 
+      !(header->hb4 & HB4_CD) &&
+      (header->hb4 & HB4_RA) &&
+      !no_cache_dnssec)
+    cache_end_insert();
+
+  return 0;
+}
+
+/* If the packet holds exactly one query
+   return F_IPV4 or F_IPV6  and leave the name from the query in name */
+unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
+{
+  unsigned char *p = (unsigned char *)(header+1);
+  int qtype, qclass;
+
+  if (typep)
+    *typep = 0;
+
+  if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
+    return 0; /* must be exactly one query. */
+  
+  if (!extract_name(header, qlen, &p, name, 1, 4))
+    return 0; /* bad packet */
+   
+  GETSHORT(qtype, p); 
+  GETSHORT(qclass, p);
+
+  if (typep)
+    *typep = qtype;
+
+  if (qclass == C_IN)
+    {
+      if (qtype == T_A)
+	return F_IPV4;
+      if (qtype == T_AAAA)
+	return F_IPV6;
+      if (qtype == T_ANY)
+	return  F_IPV4 | F_IPV6;
+    }
+  
+  return F_QUERY;
+}
+
+
+size_t setup_reply(struct dns_header *header, size_t qlen,
+		struct all_addr *addrp, unsigned int flags, unsigned long ttl)
+{
+  unsigned char *p;
+
+  if (!(p = skip_questions(header, qlen)))
+    return 0;
+  
+  /* clear authoritative and truncated flags, set QR flag */
+  header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
+  /* set RA flag */
+  header->hb4 |= HB4_RA;
+
+  header->nscount = htons(0);
+  header->arcount = htons(0);
+  header->ancount = htons(0); /* no answers unless changed below */
+  if (flags == F_NOERR)
+    SET_RCODE(header, NOERROR); /* empty domain */
+  else if (flags == F_NXDOMAIN)
+    SET_RCODE(header, NXDOMAIN);
+  else if (flags == F_IPV4)
+    { /* we know the address */
+      SET_RCODE(header, NOERROR);
+      header->ancount = htons(1);
+      header->hb3 |= HB3_AA;
+      add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
+    }
+#ifdef HAVE_IPV6
+  else if (flags == F_IPV6)
+    {
+      SET_RCODE(header, NOERROR);
+      header->ancount = htons(1);
+      header->hb3 |= HB3_AA;
+      add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
+    }
+#endif
+  else /* nowhere to forward to */
+    SET_RCODE(header, REFUSED);
+ 
+  return p - (unsigned char *)header;
+}
+
+/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
+int check_for_local_domain(char *name, time_t now)
+{
+  struct crec *crecp;
+  struct mx_srv_record *mx;
+  struct txt_record *txt;
+  struct interface_name *intr;
+  struct ptr_record *ptr;
+  struct naptr *naptr;
+
+  /* Note: the call to cache_find_by_name is intended to find any record which matches
+     ie A, AAAA, CNAME. */
+
+  if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME |F_NO_RR)) &&
+      (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
+    return 1;
+  
+  for (naptr = daemon->naptr; naptr; naptr = naptr->next)
+     if (hostname_isequal(name, naptr->name))
+      return 1;
+
+   for (mx = daemon->mxnames; mx; mx = mx->next)
+    if (hostname_isequal(name, mx->name))
+      return 1;
+
+  for (txt = daemon->txt; txt; txt = txt->next)
+    if (hostname_isequal(name, txt->name))
+      return 1;
+
+  for (intr = daemon->int_names; intr; intr = intr->next)
+    if (hostname_isequal(name, intr->name))
+      return 1;
+
+  for (ptr = daemon->ptr; ptr; ptr = ptr->next)
+    if (hostname_isequal(name, ptr->name))
+      return 1;
+ 
+  return 0;
+}
+
+/* Is the packet a reply with the answer address equal to addr?
+   If so mung is into an NXDOMAIN reply and also put that information
+   in the cache. */
+int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name, 
+			     struct bogus_addr *baddr, time_t now)
+{
+  unsigned char *p;
+  int i, qtype, qclass, rdlen;
+  unsigned long ttl;
+  struct bogus_addr *baddrp;
+
+  /* skip over questions */
+  if (!(p = skip_questions(header, qlen)))
+    return 0; /* bad packet */
+
+  for (i = ntohs(header->ancount); i != 0; i--)
+    {
+      if (!extract_name(header, qlen, &p, name, 1, 10))
+	return 0; /* bad packet */
+  
+      GETSHORT(qtype, p); 
+      GETSHORT(qclass, p);
+      GETLONG(ttl, p);
+      GETSHORT(rdlen, p);
+      
+      if (qclass == C_IN && qtype == T_A)
+	{
+	  if (!CHECK_LEN(header, p, qlen, INADDRSZ))
+	    return 0;
+	  
+	  for (baddrp = baddr; baddrp; baddrp = baddrp->next)
+	    if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
+	      {
+		/* Found a bogus address. Insert that info here, since there no SOA record
+		   to get the ttl from in the normal processing */
+		cache_start_insert();
+		cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN);
+		cache_end_insert();
+		
+		return 1;
+	      }
+	}
+      
+      if (!ADD_RDLEN(header, p, qlen, rdlen))
+	return 0;
+    }
+  
+  return 0;
+}
+
+int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr)
+{
+  unsigned char *p;
+  int i, qtype, qclass, rdlen;
+  struct bogus_addr *baddrp;
+
+  /* skip over questions */
+  if (!(p = skip_questions(header, qlen)))
+    return 0; /* bad packet */
+
+  for (i = ntohs(header->ancount); i != 0; i--)
+    {
+      if (!(p = skip_name(p, header, qlen, 10)))
+	return 0; /* bad packet */
+      
+      GETSHORT(qtype, p); 
+      GETSHORT(qclass, p);
+      p += 4; /* TTL */
+      GETSHORT(rdlen, p);
+      
+      if (qclass == C_IN && qtype == T_A)
+	{
+	  if (!CHECK_LEN(header, p, qlen, INADDRSZ))
+	    return 0;
+	  
+	  for (baddrp = baddr; baddrp; baddrp = baddrp->next)
+	    if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
+	      return 1;
+	}
+      
+      if (!ADD_RDLEN(header, p, qlen, rdlen))
+	return 0;
+    }
+  
+  return 0;
+}
+
+
+int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp, 
+			unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
+{
+  va_list ap;
+  unsigned char *sav, *p = *pp;
+  int j;
+  unsigned short usval;
+  long lval;
+  char *sval;
+#define CHECK_LIMIT(size) \
+  if (limit && p + (size) > (unsigned char*)limit) \
+    { \
+      va_end(ap); \
+      goto truncated; \
+    }
+
+  if (truncp && *truncp)
+    return 0;
+
+  va_start(ap, format);   /* make ap point to 1st unamed argument */
+
+  if (nameoffset > 0)
+    {
+      CHECK_LIMIT(2);
+      PUTSHORT(nameoffset | 0xc000, p);
+    }
+  else
+    {
+      char *name = va_arg(ap, char *);
+      if (name && !(p = do_rfc1035_name(p, name, limit)))
+	{
+	  va_end(ap);
+	  goto truncated;
+	}
+      
+      if (nameoffset < 0)
+	{
+	  CHECK_LIMIT(2);
+	  PUTSHORT(-nameoffset | 0xc000, p);
+	}
+      else
+	{
+	  CHECK_LIMIT(1);
+	  *p++ = 0;
+	}
+    }
+
+  /* type (2) + class (2) + ttl (4) + rdlen (2) */
+  CHECK_LIMIT(10);
+  
+  PUTSHORT(type, p);
+  PUTSHORT(class, p);
+  PUTLONG(ttl, p);      /* TTL */
+
+  sav = p;              /* Save pointer to RDLength field */
+  PUTSHORT(0, p);       /* Placeholder RDLength */
+
+  for (; *format; format++)
+    switch (*format)
+      {
+#ifdef HAVE_IPV6
+      case '6':
+        CHECK_LIMIT(IN6ADDRSZ);
+	sval = va_arg(ap, char *); 
+	memcpy(p, sval, IN6ADDRSZ);
+	p += IN6ADDRSZ;
+	break;
+#endif
+	
+      case '4':
+        CHECK_LIMIT(INADDRSZ);
+	sval = va_arg(ap, char *); 
+	memcpy(p, sval, INADDRSZ);
+	p += INADDRSZ;
+	break;
+	
+      case 'b':
+        CHECK_LIMIT(1);
+	usval = va_arg(ap, int);
+	*p++ = usval;
+	break;
+	
+      case 's':
+        CHECK_LIMIT(2);
+	usval = va_arg(ap, int);
+	PUTSHORT(usval, p);
+	break;
+	
+      case 'l':
+        CHECK_LIMIT(4);
+	lval = va_arg(ap, long);
+	PUTLONG(lval, p);
+	break;
+	
+      case 'd':
+        /* get domain-name answer arg and store it in RDATA field */
+        if (offset)
+          *offset = p - (unsigned char *)header;
+        p = do_rfc1035_name(p, va_arg(ap, char *), limit);
+        if (!p)
+          {
+            va_end(ap);
+            goto truncated;
+          }
+        CHECK_LIMIT(1);
+        *p++ = 0;
+	break;
+	
+      case 't':
+	usval = va_arg(ap, int);
+        CHECK_LIMIT(usval);
+	sval = va_arg(ap, char *);
+	if (usval != 0)
+	  memcpy(p, sval, usval);
+	p += usval;
+	break;
+
+      case 'z':
+	sval = va_arg(ap, char *);
+	usval = sval ? strlen(sval) : 0;
+	if (usval > 255)
+	  usval = 255;
+        CHECK_LIMIT(usval + 1);
+	*p++ = (unsigned char)usval;
+	memcpy(p, sval, usval);
+	p += usval;
+	break;
+      }
+
+#undef CHECK_LIMIT
+  va_end(ap);	/* clean up variable argument pointer */
+  
+  j = p - sav - 2;
+ /* this has already been checked against limit before */
+ PUTSHORT(j, sav);     /* Now, store real RDLength */
+  
+  /* check for overflow of buffer */
+  if (limit && ((unsigned char *)limit - p) < 0)
+    {
+truncated:
+      if (truncp)
+	*truncp = 1;
+      return 0;
+    }
+  
+  *pp = p;
+  return 1;
+}
+
+static unsigned long crec_ttl(struct crec *crecp, time_t now)
+{
+  /* Return 0 ttl for DHCP entries, which might change
+     before the lease expires, unless configured otherwise. */
+
+  if (crecp->flags & F_DHCP)
+    {
+      int conf_ttl = daemon->use_dhcp_ttl ? daemon->dhcp_ttl : daemon->local_ttl;
+      
+      /* Apply ceiling of actual lease length to configured TTL. */
+      if (!(crecp->flags & F_IMMORTAL) && (crecp->ttd - now) < conf_ttl)
+	return crecp->ttd - now;
+      
+      return conf_ttl;
+    }	  
+  
+  /* Immortal entries other than DHCP are local, and hold TTL in TTD field. */
+  if (crecp->flags & F_IMMORTAL)
+    return crecp->ttd;
+
+  /* Return the Max TTL value if it is lower than the actual TTL */
+  if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
+    return crecp->ttd - now;
+  else
+    return daemon->max_ttl;
+}
+  
+
+/* return zero if we can't answer from cache, or packet size if we can */
+size_t answer_request(struct dns_header *header, char *limit, size_t qlen,  
+		      struct in_addr local_addr, struct in_addr local_netmask, 
+		      time_t now, int ad_reqd, int do_bit, int have_pseudoheader) 
+{
+  char *name = daemon->namebuff;
+  unsigned char *p, *ansp;
+  unsigned int qtype, qclass;
+  struct all_addr addr;
+  int nameoffset;
+  unsigned short flag;
+  int q, ans, anscount = 0, addncount = 0;
+  int dryrun = 0;
+  struct crec *crecp;
+  int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
+  struct mx_srv_record *rec;
+  size_t len;
+
+  if (ntohs(header->ancount) != 0 ||
+      ntohs(header->nscount) != 0 ||
+      ntohs(header->qdcount) == 0 || 
+      OPCODE(header) != QUERY )
+    return 0;
+  
+  /* Don't return AD set if checking disabled. */
+  if (header->hb4 & HB4_CD)
+    sec_data = 0;
+  
+  /* If there is an  additional data section then it will be overwritten by
+     partial replies, so we have to do a dry run to see if we can answer
+     the query. */
+  if (ntohs(header->arcount) != 0)
+    dryrun = 1;
+
+  for (rec = daemon->mxnames; rec; rec = rec->next)
+    rec->offset = 0;
+  
+ rerun:
+  /* determine end of question section (we put answers there) */
+  if (!(ansp = skip_questions(header, qlen)))
+    return 0; /* bad packet */
+   
+  /* now process each question, answers go in RRs after the question */
+  p = (unsigned char *)(header+1);
+
+  for (q = ntohs(header->qdcount); q != 0; q--)
+    {
+      /* save pointer to name for copying into answers */
+      nameoffset = p - (unsigned char *)header;
+
+      /* now extract name as .-concatenated string into name */
+      if (!extract_name(header, qlen, &p, name, 1, 4))
+	return 0; /* bad packet */
+            
+      GETSHORT(qtype, p); 
+      GETSHORT(qclass, p);
+
+      ans = 0; /* have we answered this question */
+      
+      if (qtype == T_TXT || qtype == T_ANY)
+	{
+	  struct txt_record *t;
+	  for(t = daemon->txt; t ; t = t->next)
+	    {
+	      if (t->class == qclass && hostname_isequal(name, t->name))
+		{
+		  ans = 1;
+		  if (!dryrun)
+		    {
+		      unsigned long ttl = daemon->local_ttl;
+		      int ok = 1;
+		      log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
+#ifndef NO_ID
+		      /* Dynamically generate stat record */
+		      if (t->stat != 0)
+			{
+			  ttl = 0;
+			  if (!cache_make_stat(t))
+			    ok = 0;
+			}
+#endif
+		      if (ok && add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+						    ttl, NULL,
+						    T_TXT, t->class, "t", t->len, t->txt))
+			anscount++;
+
+		    }
+		}
+	    }
+	}
+
+      if (qclass == C_IN)
+	{
+	  struct txt_record *t;
+
+	  for (t = daemon->rr; t; t = t->next)
+	    if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
+	      {
+		ans = 1;
+		sec_data = 0;
+		if (!dryrun)
+		  {
+		    log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
+		    if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+					    daemon->local_ttl, NULL,
+					    t->class, C_IN, "t", t->len, t->txt))
+		      anscount ++;
+		  }
+	      }
+		
+	  if (qtype == T_PTR || qtype == T_ANY)
+	    {
+	      /* see if it's w.z.y.z.in-addr.arpa format */
+	      int is_arpa = in_arpa_name_2_addr(name, &addr);
+	      struct ptr_record *ptr;
+	      struct interface_name* intr = NULL;
+
+	      for (ptr = daemon->ptr; ptr; ptr = ptr->next)
+		if (hostname_isequal(name, ptr->name))
+		  break;
+
+	      if (is_arpa == F_IPV4)
+		for (intr = daemon->int_names; intr; intr = intr->next)
+		  {
+		    struct addrlist *addrlist;
+		    
+		    for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
+		      if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
+			break;
+		    
+		    if (addrlist)
+		      break;
+		    else
+		      while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
+			intr = intr->next;
+		  }
+#ifdef HAVE_IPV6
+	      else if (is_arpa == F_IPV6)
+		for (intr = daemon->int_names; intr; intr = intr->next)
+		  {
+		    struct addrlist *addrlist;
+		    
+		    for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
+		      if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
+			break;
+		    
+		    if (addrlist)
+		      break;
+		    else
+		      while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
+			intr = intr->next;
+		  }
+#endif
+	      
+	      if (intr)
+		{
+		  sec_data = 0;
+		  ans = 1;
+		  if (!dryrun)
+		    {
+		      log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
+		      if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+					      daemon->local_ttl, NULL,
+					      T_PTR, C_IN, "d", intr->name))
+			anscount++;
+		    }
+		}
+	      else if (ptr)
+		{
+		  ans = 1;
+		  sec_data = 0;
+		  if (!dryrun)
+		    {
+		      log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
+		      for (ptr = daemon->ptr; ptr; ptr = ptr->next)
+			if (hostname_isequal(name, ptr->name) &&
+			    add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+						daemon->local_ttl, NULL,
+						T_PTR, C_IN, "d", ptr->ptr))
+			  anscount++;
+			 
+		    }
+		}
+	      else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
+		{
+		  /* Don't use cache when DNSSEC data required, unless we know that
+		     the zone is unsigned, which implies that we're doing
+		     validation. */
+		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || 
+		      !do_bit || 
+		      (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
+		    {
+		      do 
+			{ 
+			  /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
+			  if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
+			    continue;
+			  
+			  if (!(crecp->flags & F_DNSSECOK))
+			    sec_data = 0;
+			   
+			  ans = 1;
+			   
+			  if (crecp->flags & F_NEG)
+			    {
+			      auth = 0;
+			      if (crecp->flags & F_NXDOMAIN)
+				nxdomain = 1;
+			      if (!dryrun)
+				log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
+			    }
+			  else
+			    {
+			      if (!(crecp->flags & (F_HOSTS | F_DHCP)))
+				auth = 0;
+			      if (!dryrun)
+				{
+				  log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr, 
+					    record_source(crecp->uid));
+				  
+				  if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+							  crec_ttl(crecp, now), NULL,
+							  T_PTR, C_IN, "d", cache_get_name(crecp)))
+				    anscount++;
+				}
+			    }
+			} while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
+		    }
+		}
+	      else if (is_rev_synth(is_arpa, &addr, name))
+		{
+		  ans = 1;
+		  sec_data = 0;
+		  if (!dryrun)
+		    {
+		      log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL); 
+		      
+		      if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+					      daemon->local_ttl, NULL,
+					      T_PTR, C_IN, "d", name))
+			      anscount++;
+		    }
+		}
+	      else if (option_bool(OPT_BOGUSPRIV) && (
+#ifdef HAVE_IPV6
+		       (is_arpa == F_IPV6 && private_net6(&addr.addr.addr6)) ||
+#endif
+		       (is_arpa == F_IPV4 && private_net(addr.addr.addr4, 1))))
+		{
+		  struct server *serv;
+		  unsigned int namelen = strlen(name);
+		  char *nameend = name + namelen;
+
+		  /* see if have rev-server set */
+		  for (serv = daemon->servers; serv; serv = serv->next)
+		    {
+		      unsigned int domainlen;
+		      char *matchstart;
+
+		      if ((serv->flags & (SERV_HAS_DOMAIN | SERV_NO_ADDR)) != SERV_HAS_DOMAIN)
+		        continue;
+
+		      domainlen = strlen(serv->domain);
+		      if (domainlen == 0 || domainlen > namelen)
+		        continue;
+
+		      matchstart = nameend - domainlen;
+		      if (hostname_isequal(matchstart, serv->domain) &&
+		          (namelen == domainlen || *(matchstart-1) == '.' ))
+			break;
+		    }
+
+		  /* if no configured server, not in cache, enabled and private IPV4 address, return NXDOMAIN */
+		  if (!serv)
+		    {
+		      ans = 1;
+		      sec_data = 0;
+		      nxdomain = 1;
+		      if (!dryrun)
+			log_query(F_CONFIG | F_REVERSE | is_arpa | F_NEG | F_NXDOMAIN,
+				  name, &addr, NULL);
+		    }
+		}
+	    }
+	  
+	  for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
+	    {
+	      unsigned short type = T_A;
+	      struct interface_name *intr;
+
+	      if (flag == F_IPV6)
+#ifdef HAVE_IPV6
+		type = T_AAAA;
+#else
+	        break;
+#endif
+	      
+	      if (qtype != type && qtype != T_ANY)
+		continue;
+	      
+	      /* Check for "A for A"  queries; be rather conservative 
+		 about what looks like dotted-quad.  */
+	      if (qtype == T_A)
+		{
+		  char *cp;
+		  unsigned int i, a;
+		  int x;
+
+		  for (cp = name, i = 0, a = 0; *cp; i++)
+		    {
+		      if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255) 
+			{
+			  i = 5;
+			  break;
+			}
+		      
+		      a = (a << 8) + x;
+		      
+		      if (*cp == '.') 
+			cp++;
+		    }
+		  
+		  if (i == 4)
+		    {
+		      ans = 1;
+		      sec_data = 0;
+		      if (!dryrun)
+			{
+			  addr.addr.addr4.s_addr = htonl(a);
+			  log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
+			  if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+						  daemon->local_ttl, NULL, type, C_IN, "4", &addr))
+			    anscount++;
+			}
+		      continue;
+		    }
+		}
+
+	      /* interface name stuff */
+	    intname_restart:
+	      for (intr = daemon->int_names; intr; intr = intr->next)
+		if (hostname_isequal(name, intr->name))
+		  break;
+	      
+	      if (intr)
+		{
+		  struct addrlist *addrlist;
+		  int gotit = 0, localise = 0;
+
+		  enumerate_interfaces(0);
+		    
+		  /* See if a putative address is on the network from which we received
+		     the query, is so we'll filter other answers. */
+		  if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && type == T_A)
+		    for (intr = daemon->int_names; intr; intr = intr->next)
+		      if (hostname_isequal(name, intr->name))
+			for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
+#ifdef HAVE_IPV6
+			  if (!(addrlist->flags & ADDRLIST_IPV6))
+#endif
+			    if (is_same_net(*((struct in_addr *)&addrlist->addr), local_addr, local_netmask))
+			      {
+				localise = 1;
+				break;
+			      }
+		  
+		  for (intr = daemon->int_names; intr; intr = intr->next)
+		    if (hostname_isequal(name, intr->name))
+		      {
+			for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
+#ifdef HAVE_IPV6
+			  if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == type)
+#endif
+			    {
+			      if (localise && 
+				  !is_same_net(*((struct in_addr *)&addrlist->addr), local_addr, local_netmask))
+				continue;
+
+#ifdef HAVE_IPV6
+			      if (addrlist->flags & ADDRLIST_REVONLY)
+				continue;
+#endif	
+			      ans = 1;	
+			      sec_data = 0;
+			      if (!dryrun)
+				{
+				  gotit = 1;
+				  log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
+				  if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+							  daemon->local_ttl, NULL, type, C_IN, 
+							  type == T_A ? "4" : "6", &addrlist->addr))
+				    anscount++;
+				}
+			    }
+		      }
+		  
+		  if (!dryrun && !gotit)
+		    log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
+		     
+		  continue;
+		}
+
+	    cname_restart:
+	      if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME | (dryrun ? F_NO_RR : 0))))
+		{
+		  int localise = 0;
+		  
+		  /* See if a putative address is on the network from which we received
+		     the query, is so we'll filter other answers. */
+		  if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
+		    {
+		      struct crec *save = crecp;
+		      do {
+			if ((crecp->flags & F_HOSTS) &&
+			    is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
+			  {
+			    localise = 1;
+			    break;
+			  } 
+			} while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
+		      crecp = save;
+		    }
+
+		  /* If the client asked for DNSSEC  don't use cached data. */
+		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK))
+		    do
+		      { 
+			/* don't answer wildcard queries with data not from /etc/hosts
+			   or DHCP leases */
+			if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
+			  break;
+			
+			if (!(crecp->flags & F_DNSSECOK))
+			  sec_data = 0;
+			
+			if (crecp->flags & F_CNAME)
+			  {
+			    char *cname_target = cache_get_cname_target(crecp);
+			    
+			    if (!dryrun)
+			      {
+				log_query(crecp->flags, name, NULL, record_source(crecp->uid));
+				if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+							crec_ttl(crecp, now), &nameoffset,
+							T_CNAME, C_IN, "d", cname_target))
+				  anscount++;
+			      }
+			    
+			    strcpy(name, cname_target);
+			    /* check if target interface_name */
+			    if (crecp->addr.cname.uid == SRC_INTERFACE)
+			      goto intname_restart;
+			    else
+			      goto cname_restart;
+			  }
+			
+			if (crecp->flags & F_NEG)
+			  {
+			    ans = 1;
+			    auth = 0;
+			    if (crecp->flags & F_NXDOMAIN)
+			      nxdomain = 1;
+			    if (!dryrun)
+			      log_query(crecp->flags, name, NULL, NULL);
+			  }
+			else 
+			  {
+			    /* If we are returning local answers depending on network,
+			       filter here. */
+			    if (localise && 
+				(crecp->flags & F_HOSTS) &&
+				!is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
+			      continue;
+			    
+			    if (!(crecp->flags & (F_HOSTS | F_DHCP)))
+			      auth = 0;
+			    
+			    ans = 1;
+			    if (!dryrun)
+			      {
+				log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
+					  record_source(crecp->uid));
+				
+				if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+							crec_ttl(crecp, now), NULL, type, C_IN, 
+							type == T_A ? "4" : "6", &crecp->addr))
+				  anscount++;
+			      }
+			  }
+		      } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
+		}
+	      else if (is_name_synthetic(flag, name, &addr))
+		{
+		  ans = 1;
+		  if (!dryrun)
+		    {
+		      log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
+		      if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+					      daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
+			anscount++;
+		    }
+		}
+	    }
+
+	  if (qtype == T_CNAME || qtype == T_ANY)
+	    {
+	      if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
+		  (qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG  | (dryrun ? F_NO_RR : 0)))))
+		{
+		  if (!(crecp->flags & F_DNSSECOK))
+		    sec_data = 0;
+		  
+		  ans = 1;
+		  if (!dryrun)
+		    {
+		      log_query(crecp->flags, name, NULL, record_source(crecp->uid));
+		      if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+					      crec_ttl(crecp, now), &nameoffset,
+					      T_CNAME, C_IN, "d", cache_get_cname_target(crecp)))
+			anscount++;
+		    }
+		}
+	    }
+
+	  if (qtype == T_MX || qtype == T_ANY)
+	    {
+	      int found = 0;
+	      for (rec = daemon->mxnames; rec; rec = rec->next)
+		if (!rec->issrv && hostname_isequal(name, rec->name))
+		  {
+		  ans = found = 1;
+		  if (!dryrun)
+		    {
+		      int offset;
+		      log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
+		      if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
+					      &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
+			{
+			  anscount++;
+			  if (rec->target)
+			    rec->offset = offset;
+			}
+		    }
+		  }
+	      
+	      if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) && 
+		  cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP | F_NO_RR))
+		{ 
+		  ans = 1;
+		  if (!dryrun)
+		    {
+		      log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
+		      if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL, 
+					      T_MX, C_IN, "sd", 1, 
+					      option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
+			anscount++;
+		    }
+		}
+	    }
+	  	  
+	  if (qtype == T_SRV || qtype == T_ANY)
+	    {
+	      int found = 0;
+	      struct mx_srv_record *move = NULL, **up = &daemon->mxnames;
+
+	      for (rec = daemon->mxnames; rec; rec = rec->next)
+		if (rec->issrv && hostname_isequal(name, rec->name))
+		  {
+		    found = ans = 1;
+		    if (!dryrun)
+		      {
+			int offset;
+			log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
+			if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, 
+						&offset, T_SRV, C_IN, "sssd", 
+						rec->priority, rec->weight, rec->srvport, rec->target))
+			  {
+			    anscount++;
+			    if (rec->target)
+			      rec->offset = offset;
+			  }
+		      }
+		    
+		    /* unlink first SRV record found */
+		    if (!move)
+		      {
+			move = rec;
+			*up = rec->next;
+		      }
+		    else
+		      up = &rec->next;      
+		  }
+		else
+		  up = &rec->next;
+
+	      /* put first SRV record back at the end. */
+	      if (move)
+		{
+		  *up = move;
+		  move->next = NULL;
+		}
+	      
+	      if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
+		{
+		  ans = 1;
+		  if (!dryrun)
+		    log_query(F_CONFIG | F_NEG, name, NULL, NULL);
+		}
+	    }
+
+	  if (qtype == T_NAPTR || qtype == T_ANY)
+	    {
+	      struct naptr *na;
+	      for (na = daemon->naptr; na; na = na->next)
+		if (hostname_isequal(name, na->name))
+		  {
+		    ans = 1;
+		    if (!dryrun)
+		      {
+			log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
+			if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, 
+						NULL, T_NAPTR, C_IN, "sszzzd", 
+						na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
+			  anscount++;
+		      }
+		  }
+	    }
+	  
+	  if (qtype == T_MAILB)
+	    ans = 1, nxdomain = 1;
+
+	  if (qtype == T_SOA && option_bool(OPT_FILTER))
+	    {
+	      ans = 1; 
+	      if (!dryrun)
+		log_query(F_CONFIG | F_NEG, name, &addr, NULL);
+	    }
+	}
+
+      if (!ans)
+	return 0; /* failed to answer a question */
+    }
+  
+  if (dryrun)
+    {
+      dryrun = 0;
+      goto rerun;
+    }
+  
+  /* create an additional data section, for stuff in SRV and MX record replies. */
+  for (rec = daemon->mxnames; rec; rec = rec->next)
+    if (rec->offset != 0)
+      {
+	/* squash dupes */
+	struct mx_srv_record *tmp;
+	for (tmp = rec->next; tmp; tmp = tmp->next)
+	  if (tmp->offset != 0 && hostname_isequal(rec->target, tmp->target))
+	    tmp->offset = 0;
+	
+	crecp = NULL;
+	while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
+	  {
+#ifdef HAVE_IPV6
+	    int type =  crecp->flags & F_IPV4 ? T_A : T_AAAA;
+#else
+	    int type = T_A;
+#endif
+	    if (crecp->flags & F_NEG)
+	      continue;
+
+	    if (add_resource_record(header, limit, NULL, rec->offset, &ansp, 
+				    crec_ttl(crecp, now), NULL, type, C_IN, 
+				    crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
+	      addncount++;
+	  }
+      }
+  
+  /* done all questions, set up header and return length of result */
+  /* clear authoritative and truncated flags, set QR flag */
+  header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
+  /* set RA flag */
+  header->hb4 |= HB4_RA;
+   
+  /* authoritative - only hosts and DHCP derived names. */
+  if (auth)
+    header->hb3 |= HB3_AA;
+  
+  /* truncation */
+  if (trunc)
+    header->hb3 |= HB3_TC;
+  
+  if (nxdomain)
+    SET_RCODE(header, NXDOMAIN);
+  else
+    SET_RCODE(header, NOERROR); /* no error */
+  header->ancount = htons(anscount);
+  header->nscount = htons(0);
+  header->arcount = htons(addncount);
+
+  len = ansp - (unsigned char *)header;
+  
+  /* Advertise our packet size limit in our reply */
+  if (have_pseudoheader)
+    len = add_pseudoheader(header, len, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
+  
+  if (ad_reqd && sec_data)
+    header->hb4 |= HB4_AD;
+  else
+    header->hb4 &= ~HB4_AD;
+  
+  return len;
+}
diff --git a/src/rfc2131.c b/src/rfc2131.c
new file mode 100755
index 0000000..b2941d9
--- /dev/null
+++ b/src/rfc2131.c
@@ -0,0 +1,2672 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_DHCP
+
+#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
+#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
+
+#ifdef HAVE_SCRIPT
+static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt);
+#endif
+
+static int sanitise(unsigned char *opt, char *buf);
+static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback);
+static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
+static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val);
+static void option_put_string(struct dhcp_packet *mess, unsigned char *end, 
+			      int opt, char *string, int null_term);
+static struct in_addr option_addr(unsigned char *opt);
+static unsigned int option_uint(unsigned char *opt, int offset, int size);
+static void log_packet(char *type, void *addr, unsigned char *ext_mac, 
+		       int mac_len, char *interface, char *string, char *err, u32 xid);
+static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
+static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
+static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end);
+static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
+static int in_list(unsigned char *list, int opt);
+static void do_options(struct dhcp_context *context,
+		       struct dhcp_packet *mess,
+		       unsigned char *end,
+		       unsigned char *req_options,
+		       char *hostname, 
+		       char *domain,
+		       struct dhcp_netid *netid,
+		       struct in_addr subnet_addr, 
+		       unsigned char fqdn_flags,
+		       int null_term, int pxe_arch,
+		       unsigned char *uuid,
+		       int vendor_class_len,
+		       time_t now,
+		       unsigned int lease_time,
+		       unsigned short fuzz);
+
+
+static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt); 
+static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
+static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid);
+static int prune_vendor_opts(struct dhcp_netid *netid);
+static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);
+struct dhcp_boot *find_boot(struct dhcp_netid *netid);
+static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dhcp_packet *mess, struct in_addr local, time_t now, int pxe);
+static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid);
+
+size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
+		  size_t sz, time_t now, int unicast_dest, int loopback,
+		  int *is_inform, int pxe, struct in_addr fallback, time_t recvtime)
+{
+  unsigned char *opt, *clid = NULL;
+  struct dhcp_lease *ltmp, *lease = NULL;
+  struct dhcp_vendor *vendor;
+  struct dhcp_mac *mac;
+  struct dhcp_netid_list *id_list;
+  int clid_len = 0, ignore = 0, do_classes = 0, selecting = 0, pxearch = -1;
+  struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
+  unsigned char *end = (unsigned char *)(mess + 1); 
+  unsigned char *real_end = (unsigned char *)(mess + 1); 
+  char *hostname = NULL, *offer_hostname = NULL, *client_hostname = NULL, *domain = NULL;
+  int hostname_auth = 0, borken_opt = 0;
+  unsigned char *req_options = NULL;
+  char *message = NULL;
+  unsigned int time;
+  struct dhcp_config *config;
+  struct dhcp_netid *netid, *tagif_netid;
+  struct in_addr subnet_addr, override;
+  unsigned short fuzz = 0;
+  unsigned int mess_type = 0;
+  unsigned char fqdn_flags = 0;
+  unsigned char *agent_id = NULL, *uuid = NULL;
+  unsigned char *emac = NULL;
+  int vendor_class_len = 0, emac_len = 0;
+  struct dhcp_netid known_id, iface_id, cpewan_id;
+  struct dhcp_opt *o;
+  unsigned char pxe_uuid[17];
+  unsigned char *oui = NULL, *serial = NULL;
+#ifdef HAVE_SCRIPT
+  unsigned char *class = NULL;
+#endif
+
+  subnet_addr.s_addr = override.s_addr = 0;
+
+  /* set tag with name == interface */
+  iface_id.net = iface_name;
+  iface_id.next = NULL;
+  netid = &iface_id; 
+  
+  if (mess->op != BOOTREQUEST || mess->hlen > DHCP_CHADDR_MAX)
+    return 0;
+   
+  if (mess->htype == 0 && mess->hlen != 0)
+    return 0;
+
+  /* check for DHCP rather than BOOTP */
+  if ((opt = option_find(mess, sz, OPTION_MESSAGE_TYPE, 1)))
+    {
+      u32 cookie = htonl(DHCP_COOKIE);
+      
+      /* only insist on a cookie for DHCP. */
+      if (memcmp(mess->options, &cookie, sizeof(u32)) != 0)
+	return 0;
+      
+      mess_type = option_uint(opt, 0, 1);
+      
+      /* two things to note here: expand_buf may move the packet,
+	 so reassign mess from daemon->packet. Also, the size
+	 sent includes the IP and UDP headers, hence the magic "-28" */
+      if ((opt = option_find(mess, sz, OPTION_MAXMESSAGE, 2)))
+	{
+	  size_t size = (size_t)option_uint(opt, 0, 2) - 28;
+	  
+	  if (size > DHCP_PACKET_MAX)
+	    size = DHCP_PACKET_MAX;
+	  else if (size < sizeof(struct dhcp_packet))
+	    size = sizeof(struct dhcp_packet);
+	  
+	  if (expand_buf(&daemon->dhcp_packet, size))
+	    {
+	      mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
+	      real_end = end = ((unsigned char *)mess) + size;
+	    }
+	}
+
+      /* 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, INADDRSZ) || mess_type == DHCPDISCOVER))
+	mess->ciaddr.s_addr = 0;
+
+      /* search for device identity from CPEWAN devices, we pass this through to the script */
+      if ((opt = option_find(mess, sz, OPTION_VENDOR_IDENT_OPT, 5)))
+	{
+	  unsigned  int elen, offset, len = option_len(opt);
+	  
+	  for (offset = 0; offset < (len - 5); offset += elen + 5)
+	    {
+	      elen = option_uint(opt, offset + 4 , 1);
+	      if (option_uint(opt, offset, 4) == BRDBAND_FORUM_IANA && offset + elen + 5 <= len)
+		{
+		  unsigned char *x = option_ptr(opt, offset + 5);
+		  unsigned char *y = option_ptr(opt, offset + elen + 5);
+		  oui = option_find1(x, y, 1, 1);
+		  serial = option_find1(x, y, 2, 1);
+#ifdef HAVE_SCRIPT
+		  class = option_find1(x, y, 3, 1);		  
+#endif
+		  /* If TR069-id is present set the tag "cpewan-id" to facilitate echoing 
+		     the gateway id back. Note that the device class is optional */
+		  if (oui && serial)
+		    {
+		      cpewan_id.net = "cpewan-id";
+		      cpewan_id.next = netid;
+		      netid = &cpewan_id;
+		    }
+		  break;
+		}
+	    }
+	}
+      
+      if ((opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
+	{
+	  /* Any agent-id needs to be copied back out, verbatim, as the last option
+	     in the packet. Here, we shift it to the very end of the buffer, if it doesn't
+	     get overwritten, then it will be shuffled back at the end of processing.
+	     Note that the incoming options must not be overwritten here, so there has to 
+	     be enough free space at the end of the packet to copy the option. */
+	  unsigned char *sopt;
+	  unsigned int total = option_len(opt) + 2;
+	  unsigned char *last_opt = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + sz,
+						 OPTION_END, 0);
+	  if (last_opt && last_opt < end - total)
+	    {
+	      end -= total;
+	      agent_id = end;
+	      memcpy(agent_id, opt, total);
+	    }
+
+	  /* look for RFC3527 Link selection sub-option */
+	  if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBNET_SELECT, INADDRSZ)))
+	    subnet_addr = option_addr(sopt);
+
+	  /* look for RFC5107 server-identifier-override */
+	  if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SERVER_OR, INADDRSZ)))
+	    override = option_addr(sopt);
+	  
+	  /* if a circuit-id or remote-is option is provided, exact-match to options. */ 
+	  for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
+	    {
+	      int search;
+	      
+	      if (vendor->match_type == MATCH_CIRCUIT)
+		search = SUBOPT_CIRCUIT_ID;
+	      else if (vendor->match_type == MATCH_REMOTE)
+		search = SUBOPT_REMOTE_ID;
+	      else if (vendor->match_type == MATCH_SUBSCRIBER)
+		search = SUBOPT_SUBSCR_ID;
+	      else 
+		continue;
+
+	      if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), search, 1)) &&
+		  vendor->len == option_len(sopt) &&
+		  memcmp(option_ptr(sopt, 0), vendor->data, vendor->len) == 0)
+		{
+		  vendor->netid.next = netid;
+		  netid = &vendor->netid;
+		} 
+	    }
+	}
+
+      /* Check for RFC3011 subnet selector - only if RFC3527 one not present */
+      if (subnet_addr.s_addr == 0 && (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, 1)))
+	{
+	  clid_len = option_len(opt);
+	  clid = option_ptr(opt, 0);
+	}
+
+      /* do we have a lease in store? */
+      lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, clid, clid_len);
+
+      /* If this request is missing a clid, but we've seen one before, 
+	 use it again for option matching etc. */
+      if (lease && !clid && lease->clid)
+	{
+	  clid_len = lease->clid_len;
+	  clid = lease->clid;
+	}
+
+      /* find mac to use for logging and hashing */
+      emac = extended_hwaddr(mess->htype, mess->hlen, mess->chaddr, clid_len, clid, &emac_len);
+    }
+  
+  for (mac = daemon->dhcp_macs; mac; mac = mac->next)
+    if (mac->hwaddr_len == mess->hlen &&
+	(mac->hwaddr_type == mess->htype || mac->hwaddr_type == 0) &&
+	memcmp_masked(mac->hwaddr, mess->chaddr, mess->hlen, mac->mask))
+      {
+	mac->netid.next = netid;
+	netid = &mac->netid;
+      }
+  
+  /* Determine network for this packet. Our caller will have already linked all the 
+     contexts which match the addresses of the receiving interface but if the 
+     machine has an address already, or came via a relay, or we have a subnet selector, 
+     we search again. If we don't have have a giaddr or explicit subnet selector, 
+     use the ciaddr. This is necessary because a  machine which got a lease via a 
+     relay won't use the relay to renew. If matching a ciaddr fails but we have a context 
+     from the physical network, continue using that to allow correct DHCPNAK generation later. */
+  if (mess->giaddr.s_addr || subnet_addr.s_addr || mess->ciaddr.s_addr)
+    {
+      struct dhcp_context *context_tmp, *context_new = NULL;
+      struct in_addr addr;
+      int force = 0;
+      
+      if (subnet_addr.s_addr)
+	{
+	  addr = subnet_addr;
+	  force = 1;
+	}
+      else if (mess->giaddr.s_addr)
+	{
+	  addr = mess->giaddr;
+	  force = 1;
+	}
+      else
+	{
+	  /* If ciaddr is in the hardware derived set of contexts, leave that unchanged */
+	  addr = mess->ciaddr;
+	  for (context_tmp = context; context_tmp; context_tmp = context_tmp->current)
+	    if (context_tmp->netmask.s_addr && 
+		is_same_net(addr, context_tmp->start, context_tmp->netmask) &&
+		is_same_net(addr, context_tmp->end, context_tmp->netmask))
+	      {
+		context_new = context;
+		break;
+	      }
+	} 
+		
+      if (!context_new)
+	for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
+	  {
+	    struct in_addr netmask = context_tmp->netmask;
+
+	    /* guess the netmask for relayed networks */
+	    if (!(context_tmp->flags & CONTEXT_NETMASK) && context_tmp->netmask.s_addr == 0)
+	      {
+		if (IN_CLASSA(ntohl(context_tmp->start.s_addr)) && IN_CLASSA(ntohl(context_tmp->end.s_addr)))
+		  netmask.s_addr = htonl(0xff000000);
+		else if (IN_CLASSB(ntohl(context_tmp->start.s_addr)) && IN_CLASSB(ntohl(context_tmp->end.s_addr)))
+		  netmask.s_addr = htonl(0xffff0000);
+		else if (IN_CLASSC(ntohl(context_tmp->start.s_addr)) && IN_CLASSC(ntohl(context_tmp->end.s_addr)))
+		  netmask.s_addr = htonl(0xffffff00); 
+	      }
+	    
+	    /* This section fills in context mainly when a client which is on a remote (relayed)
+	       network renews a lease without using the relay, after dnsmasq has restarted. */
+	    if (netmask.s_addr != 0  && 
+		is_same_net(addr, context_tmp->start, netmask) &&
+		is_same_net(addr, context_tmp->end, netmask))
+	      {
+		context_tmp->netmask = netmask;
+		if (context_tmp->local.s_addr == 0)
+		  context_tmp->local = fallback;
+		if (context_tmp->router.s_addr == 0)
+		  context_tmp->router = mess->giaddr;
+	   
+		/* fill in missing broadcast addresses for relayed ranges */
+		if (!(context_tmp->flags & CONTEXT_BRDCAST) && context_tmp->broadcast.s_addr == 0 )
+		  context_tmp->broadcast.s_addr = context_tmp->start.s_addr | ~context_tmp->netmask.s_addr;
+		
+		context_tmp->current = context_new;
+		context_new = context_tmp;
+	      }
+	  }
+      
+      if (context_new || force)
+	context = context_new; 
+    }
+  
+  if (!context)
+    {
+      my_syslog(MS_DHCP | LOG_WARNING, _("no address range available for DHCP request %s %s"), 
+		subnet_addr.s_addr ? _("with subnet selector") : _("via"),
+		subnet_addr.s_addr ? inet_ntoa(subnet_addr) : (mess->giaddr.s_addr ? inet_ntoa(mess->giaddr) : iface_name));
+      return 0;
+    }
+
+  if (option_bool(OPT_LOG_OPTS))
+    {
+      struct dhcp_context *context_tmp;
+      for (context_tmp = context; context_tmp; context_tmp = context_tmp->current)
+	{
+	  strcpy(daemon->namebuff, inet_ntoa(context_tmp->start));
+	  if (context_tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
+	    my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP subnet: %s/%s"),
+		      ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->netmask));
+	  else
+	    my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP range: %s -- %s"), 
+		      ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->end));
+	}
+    }
+  
+  /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
+     Otherwise assume the option is an array, and look for a matching element. 
+     If no data given, existence of the option is enough. This code handles 
+     rfc3925 V-I classes too. */
+  for (o = daemon->dhcp_match; o; o = o->next)
+    {
+      unsigned int len, elen, match = 0;
+      size_t offset, o2;
+
+      if (o->flags & DHOPT_RFC3925)
+	{
+	  if (!(opt = option_find(mess, sz, OPTION_VENDOR_IDENT, 5)))
+	    continue;
+	  
+	  for (offset = 0; offset < (option_len(opt) - 5u); offset += len + 5)
+	    {
+	      len = option_uint(opt, offset + 4 , 1);
+	      /* Need to take care that bad data can't run us off the end of the packet */
+	      if ((offset + len + 5 <= (unsigned)(option_len(opt))) &&
+		  (option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
+		for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
+		  { 
+		    elen = option_uint(opt, o2, 1);
+		    if ((o2 + elen + 1 <= option_len(opt)) &&
+			(match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
+		      break;
+		  }
+	      if (match) 
+		break;
+	    }	  
+	}
+      else
+	{
+	  if (!(opt = option_find(mess, sz, o->opt, 1)))
+	    continue;
+	  
+	  match = match_bytes(o, option_ptr(opt, 0), option_len(opt));
+	} 
+
+      if (match)
+	{
+	  o->netid->next = netid;
+	  netid = o->netid;
+	}
+    }
+	
+  /* user-class options are, according to RFC3004, supposed to contain
+     a set of counted strings. Here we check that this is so (by seeing
+     if the counts are consistent with the overall option length) and if
+     so zero the counts so that we don't get spurious matches between 
+     the vendor string and the counts. If the lengths don't add up, we
+     assume that the option is a single string and non RFC3004 compliant 
+     and just do the substring match. dhclient provides these broken options.
+     The code, later, which sends user-class data to the lease-change script
+     relies on the transformation done here.
+  */
+
+  if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
+    {
+      unsigned char *ucp = option_ptr(opt, 0);
+      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)
+	  {
+	    tmp = j + ucp[j] + 1;
+	    ucp[j] = 0;
+	  }
+    }
+    
+  for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
+    {
+      int mopt;
+      
+      if (vendor->match_type == MATCH_VENDOR)
+	mopt = OPTION_VENDOR_ID;
+      else if (vendor->match_type == MATCH_USER)
+	mopt = OPTION_USER_CLASS; 
+      else
+	continue;
+
+      if ((opt = option_find(mess, sz, mopt, 1)))
+	{
+	  int i;
+	  for (i = 0; i <= (option_len(opt) - vendor->len); i++)
+	    if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
+	      {
+		vendor->netid.next = netid;
+		netid = &vendor->netid;
+		break;
+	      }
+	}
+    }
+
+  /* mark vendor-encapsulated options which match the client-supplied vendor class,
+     save client-supplied vendor class */
+  if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
+    {
+      memcpy(daemon->dhcp_buff3, option_ptr(opt, 0), option_len(opt));
+      vendor_class_len = option_len(opt);
+    }
+  match_vendor_opts(opt, daemon->dhcp_opts);
+  
+  if (option_bool(OPT_LOG_OPTS))
+    {
+      if (sanitise(opt, daemon->namebuff))
+	my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
+      if (sanitise(option_find(mess, sz, OPTION_USER_CLASS, 1), daemon->namebuff))
+	my_syslog(MS_DHCP | LOG_INFO, _("%u user class: %s"), ntohl(mess->xid), daemon->namebuff);
+    }
+
+  mess->op = BOOTREPLY;
+  
+  config = find_config(daemon->dhcp_conf, context, clid, clid_len, 
+		       mess->chaddr, mess->hlen, mess->htype, NULL);
+
+  /* set "known" tag for known hosts */
+  if (config)
+    {
+      known_id.net = "known";
+      known_id.next = netid;
+      netid = &known_id;
+    }
+  else if (find_config(daemon->dhcp_conf, NULL, clid, clid_len, 
+		       mess->chaddr, mess->hlen, mess->htype, NULL))
+    {
+      known_id.net = "known-othernet";
+      known_id.next = netid;
+      netid = &known_id;
+    }
+  
+  if (mess_type == 0 && !pxe)
+    {
+      /* BOOTP request */
+      struct dhcp_netid id, bootp_id;
+      struct in_addr *logaddr = NULL;
+
+      /* must have a MAC addr for bootp */
+      if (mess->htype == 0 || mess->hlen == 0 || (context->flags & CONTEXT_PROXY))
+	return 0;
+      
+      if (have_config(config, CONFIG_DISABLE))
+	message = _("disabled");
+
+      end = mess->options + 64; /* BOOTP vend area is only 64 bytes */
+            
+      if (have_config(config, CONFIG_NAME))
+	{
+	  hostname = config->hostname;
+	  domain = config->domain;
+	}
+
+      if (config)
+	{
+	  struct dhcp_netid_list *list;
+
+	  for (list = config->netid; list; list = list->next)
+	    {
+	      list->list->next = netid;
+	      netid = list->list;
+	    }
+	}
+
+      /* Match incoming filename field as a netid. */
+      if (mess->file[0])
+	{
+	  memcpy(daemon->dhcp_buff2, mess->file, sizeof(mess->file));
+	  daemon->dhcp_buff2[sizeof(mess->file) + 1] = 0; /* ensure zero term. */
+	  id.net = (char *)daemon->dhcp_buff2;
+	  id.next = netid;
+	  netid = &id;
+	}
+
+      /* Add "bootp" as a tag to allow different options, address ranges etc
+	 for BOOTP clients */
+      bootp_id.net = "bootp";
+      bootp_id.next = netid;
+      netid = &bootp_id;
+      
+      tagif_netid = run_tag_if(netid);
+
+      for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
+	if (match_netid(id_list->list, tagif_netid, 0))
+	  message = _("ignored");
+      
+      if (!message)
+	{
+	  int nailed = 0;
+
+	  if (have_config(config, CONFIG_ADDR))
+	    {
+	      nailed = 1;
+	      logaddr = &config->addr;
+	      mess->yiaddr = config->addr;
+	      if ((lease = lease_find_by_addr(config->addr)) &&
+		  (lease->hwaddr_len != mess->hlen ||
+		   lease->hwaddr_type != mess->htype ||
+		   memcmp(lease->hwaddr, mess->chaddr, lease->hwaddr_len) != 0))
+		message = _("address in use");
+	    }
+	  else
+	    {
+	      if (!(lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, NULL, 0)) ||
+		  !address_available(context, lease->addr, tagif_netid))
+		{
+		   if (lease)
+		     {
+		       /* lease exists, wrong network. */
+		       lease_prune(lease, now);
+		       lease = NULL;
+		     }
+		   if (!address_allocate(context, &mess->yiaddr, mess->chaddr, mess->hlen, tagif_netid, now, loopback))
+		     message = _("no address available");
+		}
+	      else
+		mess->yiaddr = lease->addr;
+	    }
+	  
+	  if (!message && !(context = narrow_context(context, mess->yiaddr, netid)))
+	    message = _("wrong network");
+	  else if (context->netid.net)
+	    {
+	      context->netid.next = netid;
+	      tagif_netid = run_tag_if(&context->netid);
+	    }
+
+	  log_tags(tagif_netid, ntohl(mess->xid));
+	    
+	  if (!message && !nailed)
+	    {
+	      for (id_list = daemon->bootp_dynamic; id_list; id_list = id_list->next)
+		if ((!id_list->list) || match_netid(id_list->list, tagif_netid, 0))
+		  break;
+	      if (!id_list)
+		message = _("no address configured");
+	    }
+
+	  if (!message && 
+	      !lease && 
+	      (!(lease = lease4_allocate(mess->yiaddr))))
+	    message = _("no leases left");
+	  
+	  if (!message)
+	    {
+	      logaddr = &mess->yiaddr;
+		
+	      lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0, now, 1);
+	      if (hostname)
+		lease_set_hostname(lease, hostname, 1, get_domain(lease->addr), domain); 
+	      /* infinite lease unless nailed in dhcp-host line. */
+	      lease_set_expires(lease,  
+				have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff, 
+				now); 
+	      lease_set_interface(lease, int_index, now);
+	      
+	      clear_packet(mess, end);
+	      do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr), 
+			 netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0);
+	    }
+	}
+      
+      log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, NULL, message, mess->xid);
+      
+      return message ? 0 : dhcp_packet_size(mess, agent_id, real_end);
+    }
+      
+  if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 3)))
+    {
+      /* http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/draft-ietf-dhc-fqdn-option-10.txt */
+      int len = option_len(opt);
+      char *pq = daemon->dhcp_buff;
+      unsigned char *pp, *op = option_ptr(opt, 0);
+      
+      fqdn_flags = *op;
+      len -= 3;
+      op += 3;
+      pp = op;
+      
+      /* NB, the following always sets at least one bit */
+      if (option_bool(OPT_FQDN_UPDATE))
+	{
+	  if (fqdn_flags & 0x01)
+	    {
+	      fqdn_flags |= 0x02; /* set O */
+	      fqdn_flags &= ~0x01; /* clear S */
+	    }
+	  fqdn_flags |= 0x08; /* set N */
+	}
+      else 
+	{
+	  if (!(fqdn_flags & 0x01))
+	    fqdn_flags |= 0x03; /* set S and O */
+	  fqdn_flags &= ~0x08; /* clear N */
+	}
+      
+      if (fqdn_flags & 0x04)
+	while (*op != 0 && ((op + (*op)) - pp) < len)
+	  {
+	    memcpy(pq, op+1, *op);
+	    pq += *op;
+	    op += (*op)+1;
+	    *(pq++) = '.';
+	  }
+      else
+	{
+	  memcpy(pq, op, len);
+	  if (len > 0 && op[len-1] == 0)
+	    borken_opt = 1;
+	  pq += len + 1;
+	}
+      
+      if (pq != daemon->dhcp_buff)
+	pq--;
+      
+      *pq = 0;
+      
+      if (legal_hostname(daemon->dhcp_buff))
+	offer_hostname = client_hostname = daemon->dhcp_buff;
+    }
+  else if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
+    {
+      int len = option_len(opt);
+      memcpy(daemon->dhcp_buff, option_ptr(opt, 0), len);
+      /* Microsoft clients are broken, and need zero-terminated strings
+	 in options. We detect this state here, and do the same in
+	 any options we send */
+      if (len > 0 && daemon->dhcp_buff[len-1] == 0)
+	borken_opt = 1;
+      else
+	daemon->dhcp_buff[len] = 0;
+      if (legal_hostname(daemon->dhcp_buff))
+	client_hostname = daemon->dhcp_buff;
+    }
+
+  if (client_hostname && option_bool(OPT_LOG_OPTS))
+    my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), ntohl(mess->xid), client_hostname);
+  
+  if (have_config(config, CONFIG_NAME))
+    {
+      hostname = config->hostname;
+      domain = config->domain;
+      hostname_auth = 1;
+      /* be careful not to send an OFFER with a hostname not matching the DISCOVER. */
+      if (fqdn_flags != 0 || !client_hostname || hostname_isequal(hostname, client_hostname))
+        offer_hostname = hostname;
+    }
+  else if (client_hostname)
+    {
+      domain = strip_hostname(client_hostname);
+      
+      if (strlen(client_hostname) != 0)
+	{
+	  hostname = client_hostname;
+	  if (!config)
+	    {
+	      /* Search again now we have a hostname. 
+		 Only accept configs without CLID and HWADDR here, (they won't match)
+		 to avoid impersonation by name. */
+	      struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0,
+						    mess->chaddr, mess->hlen, 
+						    mess->htype, hostname);
+	      if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
+		{
+		  config = new;
+		  /* set "known" tag for known hosts */
+		  known_id.net = "known";
+		  known_id.next = netid;
+		  netid = &known_id;
+		}
+	    }
+	}
+    }
+  
+  if (config)
+    {
+      struct dhcp_netid_list *list;
+      
+      for (list = config->netid; list; list = list->next)
+	{
+	  list->list->next = netid;
+	  netid = list->list;
+	}
+    }
+  
+  tagif_netid = run_tag_if(netid);
+  
+  /* if all the netids in the ignore list are present, ignore this client */
+  for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
+    if (match_netid(id_list->list, tagif_netid, 0))
+      ignore = 1;
+
+  /* If configured, we can override the server-id to be the address of the relay, 
+     so that all traffic goes via the relay and can pick up agent-id info. This can be
+     configured for all relays, or by address. */
+  if (daemon->override && mess->giaddr.s_addr != 0 && override.s_addr == 0)
+    {
+      if (!daemon->override_relays)
+	override = mess->giaddr;
+      else
+	{
+	  struct addr_list *l;
+	  for (l = daemon->override_relays; l; l = l->next)
+	    if (l->addr.s_addr == mess->giaddr.s_addr)
+	      break;
+	  if (l)
+	    override = mess->giaddr;
+	}
+    }
+
+  /* Can have setting to ignore the client ID for a particular MAC address or hostname */
+  if (have_config(config, CONFIG_NOCLID))
+    clid = NULL;
+          
+  /* Check if client is PXE client. */
+  if (daemon->enable_pxe && 
+      (opt = option_find(mess, sz, OPTION_VENDOR_ID, 9)) && 
+      strncmp(option_ptr(opt, 0), "PXEClient", 9) == 0)
+    {
+      if ((opt = option_find(mess, sz, OPTION_PXE_UUID, 17)))
+	{
+	  memcpy(pxe_uuid, option_ptr(opt, 0), 17);
+	  uuid = pxe_uuid;
+	}
+
+      /* Check if this is really a PXE bootserver request, and handle specially if so. */
+      if ((mess_type == DHCPREQUEST || mess_type == DHCPINFORM) &&
+	  (opt = option_find(mess, sz, OPTION_VENDOR_CLASS_OPT, 1)) &&
+	  (opt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_PXE_BOOT_ITEM, 4)))
+	{
+	  struct pxe_service *service;
+	  int type = option_uint(opt, 0, 2);
+	  int layer = option_uint(opt, 2, 2);
+	  unsigned char save71[4];
+	  struct dhcp_opt opt71;
+
+	  if (ignore)
+	    return 0;
+
+	  if (layer & 0x8000)
+	    {
+	      my_syslog(MS_DHCP | LOG_ERR, _("PXE BIS not supported"));
+	      return 0;
+	    }
+
+	  memcpy(save71, option_ptr(opt, 0), 4);
+	  
+	  for (service = daemon->pxe_services; service; service = service->next)
+	    if (service->type == type)
+	      break;
+	  
+	  for (; context; context = context->current)
+	    if (match_netid(context->filter, tagif_netid, 1) &&
+		is_same_net(mess->ciaddr, context->start, context->netmask))
+	      break;
+	  
+	  if (!service || !service->basename || !context)
+	    return 0;
+	  	  
+	  clear_packet(mess, end);
+	  
+	  mess->yiaddr = mess->ciaddr;
+	  mess->ciaddr.s_addr = 0;
+	  if (service->sname)
+	    mess->siaddr = a_record_from_hosts(service->sname, now);
+	  else if (service->server.s_addr != 0)
+	    mess->siaddr = service->server; 
+	  else
+	    mess->siaddr = context->local; 
+	  
+	  if (strchr(service->basename, '.'))
+	    snprintf((char *)mess->file, sizeof(mess->file),
+		"%s", service->basename);
+	  else
+	    snprintf((char *)mess->file, sizeof(mess->file),
+		"%s.%d", service->basename, layer);
+	  
+	  option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
+	  option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
+	  pxe_misc(mess, end, uuid);
+	  
+	  prune_vendor_opts(tagif_netid);
+	  opt71.val = save71;
+	  opt71.opt = SUBOPT_PXE_BOOT_ITEM;
+	  opt71.len = 4;
+	  opt71.flags = DHOPT_VENDOR_MATCH;
+	  opt71.netid = NULL;
+	  opt71.next = daemon->dhcp_opts;
+	  do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
+	  
+	  log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, NULL, mess->xid);
+	  log_tags(tagif_netid, ntohl(mess->xid));
+	  return dhcp_packet_size(mess, agent_id, real_end);	  
+	}
+      
+      if ((opt = option_find(mess, sz, OPTION_ARCH, 2)))
+	{
+	  pxearch = option_uint(opt, 0, 2);
+
+	  /* proxy DHCP here. */
+	  if ((mess_type == DHCPDISCOVER || (pxe && mess_type == DHCPREQUEST)))
+	    {
+	      struct dhcp_context *tmp;
+	      int workaround = 0;
+	      
+	      for (tmp = context; tmp; tmp = tmp->current)
+		if ((tmp->flags & CONTEXT_PROXY) &&
+		    match_netid(tmp->filter, tagif_netid, 1))
+		  break;
+	      
+	      if (tmp)
+		{
+		  struct dhcp_boot *boot;
+		  int redirect4011 = 0;
+
+		  if (tmp->netid.net)
+		    {
+		      tmp->netid.next = netid;
+		      tagif_netid = run_tag_if(&tmp->netid);
+		    }
+		  
+		  boot = find_boot(tagif_netid);
+		  
+		  mess->yiaddr.s_addr = 0;
+		  if  (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0)
+		    {
+		      mess->ciaddr.s_addr = 0;
+		      mess->flags |= htons(0x8000); /* broadcast */
+		    }
+		  
+		  clear_packet(mess, end);
+		  
+		  /* Redirect EFI clients to port 4011 */
+		  if (pxearch >= 6)
+		    {
+		      redirect4011 = 1;
+		      mess->siaddr = tmp->local;
+		    }
+		  
+		  /* Returns true if only one matching service is available. On port 4011, 
+		     it also inserts the boot file and server name. */
+		  workaround = pxe_uefi_workaround(pxearch, tagif_netid, mess, tmp->local, now, pxe);
+		  
+		  if (!workaround && boot)
+		    {
+		      /* Provide the bootfile here, for gPXE, and in case we have no menu items
+			 and set discovery_control = 8 */
+		      if (boot->next_server.s_addr) 
+			mess->siaddr = boot->next_server;
+		      else if (boot->tftp_sname) 
+			mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
+		      
+		      if (boot->file)
+			strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
+		    }
+		  
+		  option_put(mess, end, OPTION_MESSAGE_TYPE, 1, 
+			     mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
+		  option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));
+		  pxe_misc(mess, end, uuid);
+		  prune_vendor_opts(tagif_netid);
+		  if ((pxe && !workaround) || !redirect4011)
+		    do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
+	    
+		  log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid);
+		  log_tags(tagif_netid, ntohl(mess->xid));
+		  if (!ignore)
+		    apply_delay(mess->xid, recvtime, tagif_netid);
+		  return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);	  
+		}
+	    }
+	}
+    }
+
+  /* if we're just a proxy server, go no further */
+  if ((context->flags & CONTEXT_PROXY) || pxe)
+    return 0;
+  
+  if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
+    {
+      req_options = (unsigned char *)daemon->dhcp_buff2;
+      memcpy(req_options, option_ptr(opt, 0), option_len(opt));
+      req_options[option_len(opt)] = OPTION_END;
+    }
+  
+  switch (mess_type)
+    {
+    case DHCPDECLINE:
+      if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
+	  option_addr(opt).s_addr != server_id(context, override, fallback).s_addr)
+	return 0;
+      
+      /* sanitise any message. Paranoid? Moi? */
+      sanitise(option_find(mess, sz, OPTION_MESSAGE, 1), daemon->dhcp_buff);
+      
+      if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
+	return 0;
+      
+      log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, NULL, daemon->dhcp_buff, mess->xid);
+      
+      if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
+	lease_prune(lease, now);
+      
+      if (have_config(config, CONFIG_ADDR) && 
+	  config->addr.s_addr == option_addr(opt).s_addr)
+	{
+	  prettyprint_time(daemon->dhcp_buff, DECLINE_BACKOFF);
+	  my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"), 
+		    inet_ntoa(config->addr), daemon->dhcp_buff);
+	  config->flags |= CONFIG_DECLINED;
+	  config->decline_time = now;
+	}
+      else
+	/* make sure this host gets a different address next time. */
+	for (; context; context = context->current)
+	  context->addr_epoch++;
+      
+      return 0;
+
+    case DHCPRELEASE:
+      if (!(context = narrow_context(context, mess->ciaddr, tagif_netid)) ||
+	  !(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
+	  option_addr(opt).s_addr != server_id(context, override, fallback).s_addr)
+	return 0;
+      
+      if (lease && lease->addr.s_addr == mess->ciaddr.s_addr)
+	lease_prune(lease, now);
+      else
+	message = _("unknown lease");
+
+      log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
+	
+      return 0;
+      
+    case DHCPDISCOVER:
+      if (ignore || have_config(config, CONFIG_DISABLE))
+	{
+	  if (option_bool(OPT_QUIET_DHCP))
+	    return 0;
+	  message = _("ignored");
+	  opt = NULL;
+	}
+      else 
+	{
+	  struct in_addr addr, conf;
+	  
+	  addr.s_addr = conf.s_addr = 0;
+
+	  if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))	 
+	    addr = option_addr(opt);
+	  
+	  if (have_config(config, CONFIG_ADDR))
+	    {
+	      char *addrs = inet_ntoa(config->addr);
+	      
+	      if ((ltmp = lease_find_by_addr(config->addr)) && 
+		  ltmp != lease &&
+		  !config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
+		{
+		  int len;
+		  unsigned char *mac = extended_hwaddr(ltmp->hwaddr_type, ltmp->hwaddr_len,
+						       ltmp->hwaddr, ltmp->clid_len, ltmp->clid, &len);
+		  my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is leased to %s"),
+			    addrs, print_mac(daemon->namebuff, mac, len));
+		}
+	      else
+		{
+		  struct dhcp_context *tmp;
+		  for (tmp = context; tmp; tmp = tmp->current)
+		    if (context->router.s_addr == config->addr.s_addr)
+		      break;
+		  if (tmp)
+		    my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by the server or relay"), addrs);
+		  else if (have_config(config, CONFIG_DECLINED) &&
+			   difftime(now, config->decline_time) < (float)DECLINE_BACKOFF)
+		    my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"), addrs);
+		  else
+		    conf = config->addr;
+		}
+	    }
+	  
+	  if (conf.s_addr)
+	    mess->yiaddr = conf;
+	  else if (lease && 
+		   address_available(context, lease->addr, tagif_netid) && 
+		   !config_find_by_address(daemon->dhcp_conf, lease->addr))
+	    mess->yiaddr = lease->addr;
+	  else if (opt && address_available(context, addr, tagif_netid) && !lease_find_by_addr(addr) && 
+		   !config_find_by_address(daemon->dhcp_conf, addr) && do_icmp_ping(now, addr, 0, loopback))
+	    mess->yiaddr = addr;
+	  else if (emac_len == 0)
+	    message = _("no unique-id");
+	  else if (!address_allocate(context, &mess->yiaddr, emac, emac_len, tagif_netid, now, loopback))
+	    message = _("no address available");      
+	}
+      
+      log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, NULL, message, mess->xid); 
+
+      if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid)))
+	return 0;
+
+      if (context->netid.net)
+	{
+	  context->netid.next = netid;
+	  tagif_netid = run_tag_if(&context->netid);
+	}
+
+      log_tags(tagif_netid, ntohl(mess->xid));
+      apply_delay(mess->xid, recvtime, tagif_netid);
+      log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
+      
+      time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
+      clear_packet(mess, end);
+      option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
+      option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
+      option_put(mess, end, OPTION_LEASE_TIME, 4, time);
+      /* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
+      do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr), 
+		 netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
+      
+      return dhcp_packet_size(mess, agent_id, real_end);
+      
+    case DHCPREQUEST:
+      if (ignore || have_config(config, CONFIG_DISABLE))
+	return 0;
+      if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
+	{
+	  /* SELECTING  or INIT_REBOOT */
+	  mess->yiaddr = option_addr(opt);
+	  
+	  /* send vendor and user class info for new or recreated lease */
+	  do_classes = 1;
+	  
+	  if ((opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)))
+	    {
+	      /* SELECTING */
+	      selecting = 1;
+	      
+	      if (override.s_addr != 0)
+		{
+		  if (option_addr(opt).s_addr != override.s_addr)
+		    return 0;
+		}
+	      else 
+		{
+		  for (; context; context = context->current)
+		    if (context->local.s_addr == option_addr(opt).s_addr)
+		      break;
+		  
+		  if (!context)
+		    {
+		      /* Handle very strange configs where clients have more than one route to the server.
+			 If a clients idea of its server-id matches any of our DHCP interfaces, we let it pass.
+			 Have to set override to make sure we echo back the correct server-id */
+		      struct irec *intr;
+		      
+		      enumerate_interfaces(0);
+
+		      for (intr = daemon->interfaces; intr; intr = intr->next)
+			if (intr->addr.sa.sa_family == AF_INET &&
+			    intr->addr.in.sin_addr.s_addr == option_addr(opt).s_addr &&
+			    intr->tftp_ok)
+			  break;
+
+		      if (intr)
+			override = intr->addr.in.sin_addr;
+		      else
+			{
+			  /* In auth mode, a REQUEST sent to the wrong server
+			     should be faulted, so that the client establishes 
+			     communication with us, otherwise, silently ignore. */
+			  if (!option_bool(OPT_AUTHORITATIVE))
+			    return 0;
+			  message = _("wrong server-ID");
+			}
+		    }
+		}
+
+	      /* If a lease exists for this host and another address, squash it. */
+	      if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
+		{
+		  lease_prune(lease, now);
+		  lease = NULL;
+		}
+	    }
+	  else
+	    {
+	      /* INIT-REBOOT */
+	      if (!lease && !option_bool(OPT_AUTHORITATIVE))
+		return 0;
+	      
+	      if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
+		message = _("wrong address");
+	    }
+	}
+      else
+	{
+	  /* RENEWING or REBINDING */ 
+	  /* Check existing lease for this address.
+	     We allow it to be missing if dhcp-authoritative mode
+	     as long as we can allocate the lease now - checked below.
+	     This makes for a smooth recovery from a lost lease DB */
+	  if ((lease && mess->ciaddr.s_addr != lease->addr.s_addr) ||
+	      (!lease && !option_bool(OPT_AUTHORITATIVE)))
+	    {
+	      /* A client rebinding will broadcast the request, so we may see it even 
+		 if the lease is held by another server. Just ignore it in that case. 
+		 If the request is unicast to us, then somethings wrong, NAK */
+	      if (!unicast_dest)
+		return 0;
+	      message = _("lease not found");
+	      /* ensure we broadcast NAK */
+	      unicast_dest = 0;
+	    }
+
+	  /* desynchronise renewals */
+	  fuzz = rand16();
+	  mess->yiaddr = mess->ciaddr;
+	}
+      
+      log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
+ 
+      if (!message)
+	{
+	  struct dhcp_config *addr_config;
+	  struct dhcp_context *tmp = NULL;
+	  
+	  if (have_config(config, CONFIG_ADDR))
+	    for (tmp = context; tmp; tmp = tmp->current)
+	      if (context->router.s_addr == config->addr.s_addr)
+		break;
+	  
+	  if (!(context = narrow_context(context, mess->yiaddr, tagif_netid)))
+	    {
+	      /* If a machine moves networks whilst it has a lease, we catch that here. */
+	      message = _("wrong network");
+	      /* ensure we broadcast NAK */
+	      unicast_dest = 0;
+	    }
+	  
+	  /* Check for renewal of a lease which is outside the allowed range. */
+	  else if (!address_available(context, mess->yiaddr, tagif_netid) &&
+		   (!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
+	    message = _("address not available");
+	  
+	  /* Check if a new static address has been configured. Be very sure that
+	     when the client does DISCOVER, it will get the static address, otherwise
+	     an endless protocol loop will ensue. */
+	  else if (!tmp && !selecting &&
+		   have_config(config, CONFIG_ADDR) && 
+		   (!have_config(config, CONFIG_DECLINED) ||
+		    difftime(now, config->decline_time) > (float)DECLINE_BACKOFF) &&
+		   config->addr.s_addr != mess->yiaddr.s_addr &&
+		   (!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
+	    message = _("static lease available");
+
+	  /* Check to see if the address is reserved as a static address for another host */
+	  else if ((addr_config = config_find_by_address(daemon->dhcp_conf, mess->yiaddr)) && addr_config != config)
+	    message = _("address reserved");
+
+	  else if (!lease && (ltmp = lease_find_by_addr(mess->yiaddr)))
+	    {
+	      /* If a host is configured with more than one MAC address, it's OK to 'nix 
+		 a lease from one of it's MACs to give the address to another. */
+	      if (config && config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
+		{
+		  my_syslog(MS_DHCP | LOG_INFO, _("abandoning lease to %s of %s"),
+			    print_mac(daemon->namebuff, ltmp->hwaddr, ltmp->hwaddr_len), 
+			    inet_ntoa(ltmp->addr));
+		  lease = ltmp;
+		}
+	      else
+		message = _("address in use");
+	    }
+
+	  if (!message)
+	    {
+	      if (emac_len == 0)
+		message = _("no unique-id");
+	      
+	      else if (!lease)
+		{	     
+		  if ((lease = lease4_allocate(mess->yiaddr)))
+		    do_classes = 1;
+		  else
+		    message = _("no leases left");
+		}
+	    }
+	}
+
+      if (message)
+	{
+	  log_packet("DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
+	  
+	  mess->yiaddr.s_addr = 0;
+	  clear_packet(mess, end);
+	  option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
+	  option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
+	  option_put_string(mess, end, OPTION_MESSAGE, message, borken_opt);
+	  /* This fixes a problem with the DHCP spec, broadcasting a NAK to a host on 
+	     a distant subnet which unicast a REQ to us won't work. */
+	  if (!unicast_dest || mess->giaddr.s_addr != 0 || 
+	      mess->ciaddr.s_addr == 0 || is_same_net(context->local, mess->ciaddr, context->netmask))
+	    {
+	      mess->flags |= htons(0x8000); /* broadcast */
+	      mess->ciaddr.s_addr = 0;
+	    }
+	}
+      else
+	{
+	  if (context->netid.net)
+	    {
+	      context->netid.next = netid;
+	      tagif_netid = run_tag_if( &context->netid);
+	    }
+
+	  log_tags(tagif_netid, ntohl(mess->xid));
+	  
+	  if (do_classes)
+	    {
+	      /* pick up INIT-REBOOT events. */
+	      lease->flags |= LEASE_CHANGED;
+
+	      if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
+		{
+		  int len = sizeof(lease->req_options) - 1;
+		  if (option_len(opt) < len) {
+		    len = option_len(opt);
+		  }
+		  memcpy(lease->req_options, option_ptr(opt, 0), len);
+		  lease->req_options[len] = OPTION_END;
+		}
+
+#ifdef HAVE_SCRIPT
+	      if (daemon->lease_change_command)
+		{
+		  struct dhcp_netid *n;
+		  
+		  if (mess->giaddr.s_addr)
+		    lease->giaddr = mess->giaddr;
+		  
+		  free(lease->extradata);
+		  lease->extradata = NULL;
+		  lease->extradata_size = lease->extradata_len = 0;
+		  
+		  add_extradata_opt(lease, option_find(mess, sz, OPTION_VENDOR_ID, 1));
+		  add_extradata_opt(lease, option_find(mess, sz, OPTION_HOSTNAME, 1));
+		  add_extradata_opt(lease, oui);
+		  add_extradata_opt(lease, serial);
+		  add_extradata_opt(lease, class);
+
+		  if ((opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
+		    {
+		      add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_CIRCUIT_ID, 1));
+		      add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBSCR_ID, 1));
+		      add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_REMOTE_ID, 1));
+		    }
+		  else
+		    {
+		      add_extradata_opt(lease, NULL);
+		      add_extradata_opt(lease, NULL);
+		      add_extradata_opt(lease, NULL);
+		    }
+
+		  /* DNSMASQ_REQUESTED_OPTIONS */
+		  if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 1)))
+		    {
+		      int len = option_len(opt);
+		      unsigned char *rop = option_ptr(opt, 0);
+		      char *q = daemon->namebuff;
+		      int i;
+		      for (i = 0; i < len; i++)
+		        {
+		          q += snprintf(q, MAXDNAME - (q - daemon->namebuff), "%d%s", rop[i], i + 1 == len ? "" : ",");
+		        }
+		      lease_add_extradata(lease, (unsigned char *)daemon->namebuff, (q - daemon->namebuff), 0); 
+		    }
+		  else
+		    {
+		      add_extradata_opt(lease, NULL);
+		    }
+
+		  /* space-concat tag set */
+		  if (!tagif_netid)
+		    add_extradata_opt(lease, NULL);
+		  else
+		    for (n = tagif_netid; n; n = n->next)
+		      {
+			struct dhcp_netid *n1;
+			/* kill dupes */
+			for (n1 = n->next; n1; n1 = n1->next)
+			  if (strcmp(n->net, n1->net) == 0)
+			    break;
+			if (!n1)
+			  lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0); 
+		      }
+		  
+		  if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
+		    {
+		      int len = option_len(opt);
+		      unsigned char *ucp = option_ptr(opt, 0);
+		      /* If the user-class option started as counted strings, the first byte will be zero. */
+		      if (len != 0 && ucp[0] == 0)
+			ucp++, len--;
+		      lease_add_extradata(lease, ucp, len, -1);
+		    }
+		}
+#endif
+	    }
+	  
+	  if (!hostname_auth && (client_hostname = host_from_dns(mess->yiaddr)))
+	    {
+	      domain = get_domain(mess->yiaddr);
+	      hostname = client_hostname;
+	      hostname_auth = 1;
+	    }
+	  
+	  time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
+	  lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len, now, do_classes);
+	  
+	  /* if all the netids in the ignore_name list are present, ignore client-supplied name */
+	  if (!hostname_auth)
+	    {
+	      for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
+		if ((!id_list->list) || match_netid(id_list->list, tagif_netid, 0))
+		  break;
+	      if (id_list)
+		hostname = NULL;
+	    }
+	  
+	  /* Last ditch, if configured, generate hostname from mac address */
+	  if (!hostname && emac_len != 0)
+	    {
+	      for (id_list = daemon->dhcp_gen_names; id_list; id_list = id_list->next)
+		if ((!id_list->list) || match_netid(id_list->list, tagif_netid, 0))
+		  break;
+	      if (id_list)
+		{
+		  int i;
+
+		  hostname = daemon->dhcp_buff;
+		  /* buffer is 256 bytes, 3 bytes per octet */
+		  for (i = 0; (i < emac_len) && (i < 80); i++)
+		    hostname += sprintf(hostname, "%.2x%s", emac[i], (i == emac_len - 1) ? "" : "-");
+		  hostname = daemon->dhcp_buff;
+		}
+	    }
+
+	  if (hostname)
+	    lease_set_hostname(lease, hostname, hostname_auth, get_domain(lease->addr), domain);
+	  
+	  lease_set_expires(lease, time, now);
+	  lease_set_interface(lease, int_index, now);
+
+	  if (override.s_addr != 0)
+	    lease->override = override;
+	  else
+	    override = lease->override;
+
+	  log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);  
+	  
+	  clear_packet(mess, end);
+	  option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
+	  option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
+	  option_put(mess, end, OPTION_LEASE_TIME, 4, time);
+	  do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr), 
+		     netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
+	}
+
+      return dhcp_packet_size(mess, agent_id, real_end); 
+      
+    case DHCPINFORM:
+      if (ignore || have_config(config, CONFIG_DISABLE))
+	message = _("ignored");
+      
+      log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, NULL, mess->xid);
+     
+      if (message || mess->ciaddr.s_addr == 0)
+	return 0;
+
+      /* For DHCPINFORM only, cope without a valid context */
+      context = narrow_context(context, mess->ciaddr, tagif_netid);
+      
+      /* Find a least based on IP address if we didn't
+	 get one from MAC address/client-d */
+      if (!lease &&
+	  (lease = lease_find_by_addr(mess->ciaddr)) && 
+	  lease->hostname)
+	hostname = lease->hostname;
+      
+      if (!hostname)
+	hostname = host_from_dns(mess->ciaddr);
+      
+      if (context && context->netid.net)
+	{
+	  context->netid.next = netid;
+	  tagif_netid = run_tag_if(&context->netid);
+	}
+
+      log_tags(tagif_netid, ntohl(mess->xid));
+      
+      log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);
+      
+      if (lease)
+	{
+	  lease_set_interface(lease, int_index, now);
+	  if (override.s_addr != 0)
+	    lease->override = override;
+	  else
+	    override = lease->override;
+	}
+
+      clear_packet(mess, end);
+      option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
+      option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
+     
+      /* RFC 2131 says that DHCPINFORM shouldn't include lease-time parameters, but 
+	 we supply a utility which makes DHCPINFORM requests to get this information.
+	 Only include lease time if OPTION_LEASE_TIME is in the parameter request list,
+	 which won't be true for ordinary clients, but will be true for the 
+	 dhcp_lease_time utility. */
+      if (lease && in_list(req_options, OPTION_LEASE_TIME))
+	{
+	  if (lease->expires == 0)
+	    time = 0xffffffff;
+	  else
+	    time = (unsigned int)difftime(lease->expires, now);
+	  option_put(mess, end, OPTION_LEASE_TIME, 4, time);
+	}
+
+      do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
+		 netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0);
+      
+      *is_inform = 1; /* handle reply differently */
+      return dhcp_packet_size(mess, agent_id, real_end); 
+    }
+  
+  return 0;
+}
+
+/* find a good value to use as MAC address for logging and address-allocation hashing.
+   This is normally just the chaddr field from the DHCP packet,
+   but eg Firewire will have hlen == 0 and use the client-id instead. 
+   This could be anything, but will normally be EUI64 for Firewire.
+   We assume that if the first byte of the client-id equals the htype byte
+   then the client-id is using the usual encoding and use the rest of the 
+   client-id: if not we can use the whole client-id. This should give
+   sane MAC address logs. */
+unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr, 
+				      int clid_len, unsigned char *clid, int *len_out)
+{
+  if (hwlen == 0 && clid && clid_len > 3)
+    {
+      if (clid[0]  == hwtype)
+	{
+	  *len_out = clid_len - 1 ;
+	  return clid + 1;
+	}
+
+#if defined(ARPHRD_EUI64) && defined(ARPHRD_IEEE1394)
+      if (clid[0] ==  ARPHRD_EUI64 && hwtype == ARPHRD_IEEE1394)
+	{
+	  *len_out = clid_len - 1 ;
+	  return clid + 1;
+	}
+#endif
+      
+      *len_out = clid_len;
+      return clid;
+    }
+  
+  *len_out = hwlen;
+  return hwaddr;
+}
+
+static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt)
+{
+  unsigned int time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
+  
+  if (opt)
+    { 
+      unsigned int req_time = option_uint(opt, 0, 4);
+      if (req_time < 120 )
+	req_time = 120; /* sanity */
+      if (time == 0xffffffff || (req_time != 0xffffffff && req_time < time))
+	time = req_time;
+    }
+
+  return time;
+}
+
+static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback)
+{
+  if (override.s_addr != 0)
+    return override;
+  else if (context && context->local.s_addr != 0)
+    return context->local;
+  else
+    return fallback;
+}
+
+static int sanitise(unsigned char *opt, char *buf)
+{
+  char *p;
+  int i;
+  
+  *buf = 0;
+  
+  if (!opt)
+    return 0;
+
+  p = option_ptr(opt, 0);
+
+  for (i = option_len(opt); i > 0; i--)
+    {
+      char c = *p++;
+      if (isprint((int)c))
+	*buf++ = c;
+    }
+  *buf = 0; /* add terminator */
+  
+  return 1;
+}
+
+#ifdef HAVE_SCRIPT
+static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt)
+{
+  if (!opt)
+    lease_add_extradata(lease, NULL, 0, 0);
+  else
+    lease_add_extradata(lease, option_ptr(opt, 0), option_len(opt), 0); 
+}
+#endif
+
+static void log_packet(char *type, void *addr, unsigned char *ext_mac, 
+		       int mac_len, char *interface, char *string, char *err, u32 xid)
+{
+  struct in_addr a;
+ 
+  if (!err && !option_bool(OPT_LOG_OPTS) && option_bool(OPT_QUIET_DHCP))
+    return;
+  
+  /* addr may be misaligned */
+  if (addr)
+    memcpy(&a, addr, sizeof(a));
+  
+  print_mac(daemon->namebuff, ext_mac, mac_len);
+  
+  if(option_bool(OPT_LOG_OPTS))
+     my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s %s%s",
+	       ntohl(xid), 
+	       type,
+	       interface, 
+	       addr ? inet_ntoa(a) : "",
+	       addr ? " " : "",
+	       daemon->namebuff,
+	       string ? string : "",
+	       err ? err : "");
+  else
+    my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s%s %s%s",
+	      type,
+	      interface, 
+	      addr ? inet_ntoa(a) : "",
+	      addr ? " " : "",
+	      daemon->namebuff,
+	      string ? string : "",
+	      err ? err : "");
+}
+
+static void log_options(unsigned char *start, u32 xid)
+{
+  while (*start != OPTION_END)
+    {
+      char *optname = option_string(AF_INET, start[0], option_ptr(start, 0), option_len(start), daemon->namebuff, MAXDNAME);
+      
+      my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d %s  %s", 
+		ntohl(xid), option_len(start), start[0], optname, daemon->namebuff);
+      start += start[1] + 2;
+    }
+}
+
+static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize)
+{
+  while (1) 
+    {
+      if (p >= end)
+	return NULL;
+      else if (*p == OPTION_END)
+	return opt == OPTION_END ? p : NULL;
+      else if (*p == OPTION_PAD)
+	p++;
+      else 
+	{ 
+	  int opt_len;
+	  if (p > end - 2)
+	    return NULL; /* malformed packet */
+	  opt_len = option_len(p);
+	  if (p > end - (2 + opt_len))
+	    return NULL; /* malformed packet */
+	  if (*p == opt && opt_len >= minsize)
+	    return p;
+	  p += opt_len + 2;
+	}
+    }
+}
+ 
+static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize)
+{
+  unsigned char *ret, *overload;
+  
+  /* skip over DHCP cookie; */
+  if ((ret = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + size, opt_type, minsize)))
+    return ret;
+
+  /* look for overload option. */
+  if (!(overload = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + size, OPTION_OVERLOAD, 1)))
+    return NULL;
+  
+  /* Can we look in filename area ? */
+  if ((overload[2] & 1) &&
+      (ret = option_find1(&mess->file[0], &mess->file[128], opt_type, minsize)))
+    return ret;
+
+  /* finally try sname area */
+  if ((overload[2] & 2) &&
+      (ret = option_find1(&mess->sname[0], &mess->sname[64], opt_type, minsize)))
+    return ret;
+
+  return NULL;
+}
+
+static struct in_addr option_addr(unsigned char *opt)
+{
+   /* this worries about unaligned data in the option. */
+  /* struct in_addr is network byte order */
+  struct in_addr ret;
+
+  memcpy(&ret, option_ptr(opt, 0), INADDRSZ);
+
+  return ret;
+}
+
+static unsigned int option_uint(unsigned char *opt, int offset, int size)
+{
+  /* this worries about unaligned data and byte order */
+  unsigned int ret = 0;
+  int i;
+  unsigned char *p = option_ptr(opt, offset);
+  
+  for (i = 0; i < size; i++)
+    ret = (ret << 8) | *p++;
+
+  return ret;
+}
+
+static unsigned char *dhcp_skip_opts(unsigned char *start)
+{
+  while (*start != 0)
+    start += start[1] + 2;
+  return start;
+}
+
+/* only for use when building packet: doesn't check for bad data. */ 
+static unsigned char *find_overload(struct dhcp_packet *mess)
+{
+  unsigned char *p = &mess->options[0] + sizeof(u32);
+  
+  while (*p != 0)
+    {
+      if (*p == OPTION_OVERLOAD)
+	return p;
+      p += p[1] + 2;
+    }
+  return NULL;
+}
+
+static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end)
+{
+  unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
+  unsigned char *overload;
+  size_t ret;
+  
+  /* move agent_id back down to the end of the packet */
+  if (agent_id)
+    {
+      memmove(p, agent_id, real_end - agent_id);
+      p += real_end - agent_id;
+      memset(p, 0, real_end - p); /* in case of overlap */
+    }
+  
+  /* add END options to the regions. */
+  overload = find_overload(mess);
+  
+  if (overload && (option_uint(overload, 0, 1) & 1))
+    {
+      *dhcp_skip_opts(mess->file) = OPTION_END;
+      if (option_bool(OPT_LOG_OPTS))
+	log_options(mess->file, mess->xid);
+    }
+  else if (option_bool(OPT_LOG_OPTS) && strlen((char *)mess->file) != 0)
+    my_syslog(MS_DHCP | LOG_INFO, _("%u bootfile name: %s"), ntohl(mess->xid), (char *)mess->file);
+  
+  if (overload && (option_uint(overload, 0, 1) & 2))
+    {
+      *dhcp_skip_opts(mess->sname) = OPTION_END;
+      if (option_bool(OPT_LOG_OPTS))
+	log_options(mess->sname, mess->xid);
+    }
+  else if (option_bool(OPT_LOG_OPTS) && strlen((char *)mess->sname) != 0)
+    my_syslog(MS_DHCP | LOG_INFO, _("%u server name: %s"), ntohl(mess->xid), (char *)mess->sname);
+
+
+  *p++ = OPTION_END;
+  
+  if (option_bool(OPT_LOG_OPTS))
+    {
+      if (mess->siaddr.s_addr != 0)
+	my_syslog(MS_DHCP | LOG_INFO, _("%u next server: %s"), ntohl(mess->xid), inet_ntoa(mess->siaddr));
+      
+      if ((mess->flags & htons(0x8000)) && mess->ciaddr.s_addr == 0)
+	my_syslog(MS_DHCP | LOG_INFO, _("%u broadcast response"), ntohl(mess->xid));
+      
+      log_options(&mess->options[0] + sizeof(u32), mess->xid);
+    } 
+  
+  ret = (size_t)(p - (unsigned char *)mess);
+  
+  if (ret < MIN_PACKETSZ)
+    ret = MIN_PACKETSZ;
+  
+  return ret;
+}
+
+static unsigned char *free_space(struct dhcp_packet *mess, unsigned char *end, int opt, int len)
+{
+  unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
+  
+  if (p + len + 3 >= end)
+    /* not enough space in options area, try and use overload, if poss */
+    {
+      unsigned char *overload;
+      
+      if (!(overload = find_overload(mess)) &&
+	  (mess->file[0] == 0 || mess->sname[0] == 0))
+	{
+	  /* attempt to overload fname and sname areas, we've reserved space for the
+	     overflow option previuously. */
+	  overload = p;
+	  *(p++) = OPTION_OVERLOAD;
+	  *(p++) = 1;
+	}
+      
+      p = NULL;
+      
+      /* using filename field ? */
+      if (overload)
+	{
+	  if (mess->file[0] == 0)
+	    overload[2] |= 1;
+	  
+	  if (overload[2] & 1)
+	    {
+	      p = dhcp_skip_opts(mess->file);
+	      if (p + len + 3 >= mess->file + sizeof(mess->file))
+		p = NULL;
+	    }
+	  
+	  if (!p)
+	    {
+	      /* try to bring sname into play (it may be already) */
+	      if (mess->sname[0] == 0)
+		overload[2] |= 2;
+	      
+	      if (overload[2] & 2)
+		{
+		  p = dhcp_skip_opts(mess->sname);
+		  if (p + len + 3 >= mess->sname + sizeof(mess->sname))
+		    p = NULL;
+		}
+	    }
+	}
+      
+      if (!p)
+	my_syslog(MS_DHCP | LOG_WARNING, _("cannot send DHCP/BOOTP option %d: no space left in packet"), opt);
+    }
+ 
+  if (p)
+    {
+      *(p++) = opt;
+      *(p++) = len;
+    }
+
+  return p;
+}
+	      
+static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val)
+{
+  int i;
+  unsigned char *p = free_space(mess, end, opt, len);
+  
+  if (p) 
+    for (i = 0; i < len; i++)
+      *(p++) = val >> (8 * (len - (i + 1)));
+}
+
+static void option_put_string(struct dhcp_packet *mess, unsigned char *end, int opt, 
+			      char *string, int null_term)
+{
+  unsigned char *p;
+  size_t len = strlen(string);
+
+  if (null_term && len != 255)
+    len++;
+
+  if ((p = free_space(mess, end, opt, len)))
+    memcpy(p, string, len);
+}
+
+/* return length, note this only does the data part */
+static int do_opt(struct dhcp_opt *opt, unsigned char *p, struct dhcp_context *context, int null_term)
+{
+  int len = opt->len;
+  
+  if ((opt->flags & DHOPT_STRING) && null_term && len != 255)
+    len++;
+
+  if (p && len != 0)
+    {
+      if (context && (opt->flags & DHOPT_ADDR))
+	{
+	  int j;
+	  struct in_addr *a = (struct in_addr *)opt->val;
+	  for (j = 0; j < opt->len; j+=INADDRSZ, a++)
+	    {
+	      /* zero means "self" (but not in vendorclass options.) */
+	      if (a->s_addr == 0)
+		memcpy(p, &context->local, INADDRSZ);
+	      else
+		memcpy(p, a, INADDRSZ);
+	      p += INADDRSZ;
+	    }
+	}
+      else
+	/* empty string may be extended to "\0" by null_term */
+	memcpy(p, opt->val ? opt->val : (unsigned char *)"", len);
+    }  
+  return len;
+}
+
+static int in_list(unsigned char *list, int opt)
+{
+  int i;
+
+   /* If no requested options, send everything, not nothing. */
+  if (!list)
+    return 1;
+  
+  for (i = 0; list[i] != OPTION_END; i++)
+    if (opt == list[i])
+      return 1;
+
+  return 0;
+}
+
+static struct dhcp_opt *option_find2(int opt)
+{
+  struct dhcp_opt *opts;
+  
+  for (opts = daemon->dhcp_opts; opts; opts = opts->next)
+    if (opts->opt == opt && (opts->flags & DHOPT_TAGOK))
+      return opts;
+  
+  return NULL;
+}
+
+/* mark vendor-encapsulated options which match the client-supplied  or
+   config-supplied vendor class */
+static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
+{
+  for (; dopt; dopt = dopt->next)
+    {
+      dopt->flags &= ~DHOPT_VENDOR_MATCH;
+      if (opt && (dopt->flags & DHOPT_VENDOR))
+	{
+	  int i, len = 0;
+	  if (dopt->u.vendor_class)
+	    len = strlen((char *)dopt->u.vendor_class);
+	  for (i = 0; i <= (option_len(opt) - len); i++)
+	    if (len == 0 || memcmp(dopt->u.vendor_class, option_ptr(opt, i), len) == 0)
+	      {
+		dopt->flags |= DHOPT_VENDOR_MATCH;
+		break;
+	      }
+	}
+    }
+}
+
+static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag,  
+			 struct dhcp_packet *mess, unsigned char *end, int null_term)
+{
+  int len, enc_len, ret = 0;
+  struct dhcp_opt *start;
+  unsigned char *p;
+    
+  /* find size in advance */
+  for (enc_len = 0, start = opt; opt; opt = opt->next)
+    if (opt->flags & flag)
+      {
+	int new = do_opt(opt, NULL, NULL, null_term) + 2;
+	ret  = 1;
+	if (enc_len + new <= 255)
+	  enc_len += new;
+	else
+	  {
+	    p = free_space(mess, end, encap, enc_len);
+	    for (; start && start != opt; start = start->next)
+	      if (p && (start->flags & flag))
+		{
+		  len = do_opt(start, p + 2, NULL, null_term);
+		  *(p++) = start->opt;
+		  *(p++) = len;
+		  p += len;
+		}
+	    enc_len = new;
+	    start = opt;
+	  }
+      }
+  
+  if (enc_len != 0 &&
+      (p = free_space(mess, end, encap, enc_len + 1)))
+    {
+      for (; start; start = start->next)
+	if (start->flags & flag)
+	  {
+	    len = do_opt(start, p + 2, NULL, null_term);
+	    *(p++) = start->opt;
+	    *(p++) = len;
+	    p += len;
+	  }
+      *p = OPTION_END;
+    }
+
+  return ret;
+}
+
+static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid)
+{
+  unsigned char *p;
+
+  option_put_string(mess, end, OPTION_VENDOR_ID, "PXEClient", 0);
+  if (uuid && (p = free_space(mess, end, OPTION_PXE_UUID, 17)))
+    memcpy(p, uuid, 17);
+}
+
+static int prune_vendor_opts(struct dhcp_netid *netid)
+{
+  int force = 0;
+  struct dhcp_opt *opt;
+
+  /* prune vendor-encapsulated options based on netid, and look if we're forcing them to be sent */
+  for (opt = daemon->dhcp_opts; opt; opt = opt->next)
+    if (opt->flags & DHOPT_VENDOR_MATCH)
+      {
+	if (!match_netid(opt->netid, netid, 1))
+	  opt->flags &= ~DHOPT_VENDOR_MATCH;
+	else if (opt->flags & DHOPT_FORCE)
+	  force = 1;
+      }
+  return force;
+}
+
+
+/* Many UEFI PXE implementations have badly broken menu code.
+   If there's exactly one relevant menu item, we abandon the menu system,
+   and jamb the data direct into the DHCP file, siaddr and sname fields.
+   Note that in this case, we have to assume that layer zero would be requested
+   by the client PXE stack. */
+static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dhcp_packet *mess, struct in_addr local, time_t now, int pxe)
+{
+  struct pxe_service *service, *found;
+
+  /* Only workaround UEFI archs. */
+  if (pxe_arch < 6)
+    return 0;
+  
+  for (found = NULL, service = daemon->pxe_services; service; service = service->next)
+    if (pxe_arch == service->CSA && service->basename && match_netid(service->netid, netid, 1))
+      {
+	if (found)
+	  return 0; /* More than one relevant menu item */
+	  
+	found = service;
+      }
+
+  if (!found)
+    return 0; /* No relevant menu items. */
+  
+  if (!pxe)
+     return 1;
+  
+  if (found->sname)
+    {
+      mess->siaddr = a_record_from_hosts(found->sname, now);
+      snprintf((char *)mess->sname, sizeof(mess->sname), "%s", found->sname);
+    }
+  else 
+    {
+      if (found->server.s_addr != 0)
+	mess->siaddr = found->server; 
+      else
+	mess->siaddr = local;
+  
+      inet_ntop(AF_INET, &mess->siaddr, (char *)mess->sname, INET_ADDRSTRLEN);
+    }
+  
+  snprintf((char *)mess->file, sizeof(mess->file), 
+	   strchr(found->basename, '.') ? "%s" : "%s.0", found->basename);
+  
+  return 1;
+}
+
+static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now)
+{
+#define NUM_OPTS 4  
+
+  unsigned  char *p, *q;
+  struct pxe_service *service;
+  static struct dhcp_opt *o, *ret;
+  int i, j = NUM_OPTS - 1;
+  struct in_addr boot_server;
+  
+  /* We pass back references to these, hence they are declared static */
+  static unsigned char discovery_control;
+  static unsigned char fake_prompt[] = { 0, 'P', 'X', 'E' }; 
+  static struct dhcp_opt *fake_opts = NULL;
+  
+  /* Disable multicast, since we don't support it, and broadcast
+     unless we need it */
+  discovery_control = 3;
+  
+  ret = daemon->dhcp_opts;
+  
+  if (!fake_opts && !(fake_opts = whine_malloc(NUM_OPTS * sizeof(struct dhcp_opt))))
+    return ret;
+
+  for (i = 0; i < NUM_OPTS; i++)
+    {
+      fake_opts[i].flags = DHOPT_VENDOR_MATCH;
+      fake_opts[i].netid = NULL;
+      fake_opts[i].next = i == (NUM_OPTS - 1) ? ret : &fake_opts[i+1];
+    }
+  
+  /* create the data for the PXE_MENU and PXE_SERVERS options. */
+  p = (unsigned char *)daemon->dhcp_buff;
+  q = (unsigned char *)daemon->dhcp_buff3;
+
+  for (i = 0, service = daemon->pxe_services; service; service = service->next)
+    if (pxe_arch == service->CSA && match_netid(service->netid, netid, 1))
+      {
+	size_t len = strlen(service->menu);
+	/* opt 43 max size is 255. encapsulated option has type and length
+	   bytes, so its max size is 253. */
+	if (p - (unsigned char *)daemon->dhcp_buff + len + 3 < 253)
+	  {
+	    *(p++) = service->type >> 8;
+	    *(p++) = service->type;
+	    *(p++) = len;
+	    memcpy(p, service->menu, len);
+	    p += len;
+	    i++;
+	  }
+	else
+	  {
+	  toobig:
+	    my_syslog(MS_DHCP | LOG_ERR, _("PXE menu too large"));
+	    return daemon->dhcp_opts;
+	  }
+	
+	boot_server = service->basename ? local : 
+	  (service->sname ? a_record_from_hosts(service->sname, now) : service->server);
+	
+	if (boot_server.s_addr != 0)
+	  {
+	    if (q - (unsigned char *)daemon->dhcp_buff3 + 3 + INADDRSZ >= 253)
+	      goto toobig;
+	    
+	    /* Boot service with known address - give it */
+	    *(q++) = service->type >> 8;
+	    *(q++) = service->type;
+	    *(q++) = 1;
+	    /* dest misaligned */
+	    memcpy(q, &boot_server.s_addr, INADDRSZ);
+	    q += INADDRSZ;
+	  }
+	else if (service->type != 0)
+	  /* We don't know the server for a service type, so we'll
+	     allow the client to broadcast for it */
+	  discovery_control = 2;
+      }
+
+  /* if no prompt, wait forever if there's a choice */
+  fake_prompt[0] = (i > 1) ? 255 : 0;
+  
+  if (i == 0)
+    discovery_control = 8; /* no menu - just use use mess->filename */
+  else
+    {
+      ret = &fake_opts[j--];
+      ret->len = p - (unsigned char *)daemon->dhcp_buff;
+      ret->val = (unsigned char *)daemon->dhcp_buff;
+      ret->opt = SUBOPT_PXE_MENU;
+
+      if (q - (unsigned char *)daemon->dhcp_buff3 != 0)
+	{
+	  ret = &fake_opts[j--]; 
+	  ret->len = q - (unsigned char *)daemon->dhcp_buff3;
+	  ret->val = (unsigned char *)daemon->dhcp_buff3;
+	  ret->opt = SUBOPT_PXE_SERVERS;
+	}
+    }
+
+  for (o = daemon->dhcp_opts; o; o = o->next)
+    if ((o->flags & DHOPT_VENDOR_MATCH) && o->opt == SUBOPT_PXE_MENU_PROMPT)
+      break;
+  
+  if (!o)
+    {
+      ret = &fake_opts[j--]; 
+      ret->len = sizeof(fake_prompt);
+      ret->val = fake_prompt;
+      ret->opt = SUBOPT_PXE_MENU_PROMPT;
+    }
+  
+  ret = &fake_opts[j--]; 
+  ret->len = 1;
+  ret->opt = SUBOPT_PXE_DISCOVERY;
+  ret->val= &discovery_control;
+ 
+  return ret;
+}
+  
+static void clear_packet(struct dhcp_packet *mess, unsigned char *end)
+{
+  memset(mess->sname, 0, sizeof(mess->sname));
+  memset(mess->file, 0, sizeof(mess->file));
+  memset(&mess->options[0] + sizeof(u32), 0, end - (&mess->options[0] + sizeof(u32)));
+  mess->siaddr.s_addr = 0;
+}
+
+struct dhcp_boot *find_boot(struct dhcp_netid *netid)
+{
+  struct dhcp_boot *boot;
+
+  /* decide which dhcp-boot option we're using */
+  for (boot = daemon->boot_config; boot; boot = boot->next)
+    if (match_netid(boot->netid, netid, 0))
+      break;
+  if (!boot)
+    /* No match, look for one without a netid */
+    for (boot = daemon->boot_config; boot; boot = boot->next)
+      if (match_netid(boot->netid, netid, 1))
+	break;
+
+  return boot;
+}
+
+static void do_options(struct dhcp_context *context,
+		       struct dhcp_packet *mess,
+		       unsigned char *end, 
+		       unsigned char *req_options,
+		       char *hostname, 
+		       char *domain,
+		       struct dhcp_netid *netid,
+		       struct in_addr subnet_addr,
+		       unsigned char fqdn_flags,
+		       int null_term, int pxe_arch,
+		       unsigned char *uuid,
+		       int vendor_class_len,
+		       time_t now,
+		       unsigned int lease_time,
+		       unsigned short fuzz)
+{
+  struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
+  struct dhcp_boot *boot;
+  unsigned char *p;
+  int i, len, force_encap = 0;
+  unsigned char f0 = 0, s0 = 0;
+  int done_file = 0, done_server = 0;
+  int done_vendor_class = 0;
+  struct dhcp_netid *tagif;
+  struct dhcp_netid_list *id_list;
+
+  /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
+  if (context)
+    context->netid.next = NULL;
+  tagif = option_filter(netid, context && context->netid.net ? &context->netid : NULL, config_opts);
+	
+  /* logging */
+  if (option_bool(OPT_LOG_OPTS) && req_options)
+    {
+      char *q = daemon->namebuff;
+      for (i = 0; req_options[i] != OPTION_END; i++)
+	{
+	  char *s = option_string(AF_INET, req_options[i], NULL, 0, NULL, 0);
+	  q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
+			"%d%s%s%s", 
+			req_options[i],
+			strlen(s) != 0 ? ":" : "",
+			s, 
+			req_options[i+1] == OPTION_END ? "" : ", ");
+	  if (req_options[i+1] == OPTION_END || (q - daemon->namebuff) > 40)
+	    {
+	      q = daemon->namebuff;
+	      my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), ntohl(mess->xid), daemon->namebuff);
+	    }
+	}
+    }
+      
+  for (id_list = daemon->force_broadcast; id_list; id_list = id_list->next)
+    if ((!id_list->list) || match_netid(id_list->list, netid, 0))
+      break;
+  if (id_list)
+    mess->flags |= htons(0x8000); /* force broadcast */
+  
+  if (context)
+    mess->siaddr = context->local;
+  
+  /* See if we can send the boot stuff as options.
+     To do this we need a requested option list, BOOTP
+     and very old DHCP clients won't have this, we also 
+     provide an manual option to disable it.
+     Some PXE ROMs have bugs (surprise!) and need zero-terminated 
+     names, so we always send those.  */
+  if ((boot = find_boot(tagif)))
+    {
+      if (boot->sname)
+	{	  
+	  if (!option_bool(OPT_NO_OVERRIDE) &&
+	      req_options && 
+	      in_list(req_options, OPTION_SNAME))
+	    option_put_string(mess, end, OPTION_SNAME, boot->sname, 1);
+	  else
+	    strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname)-1);
+	}
+      
+      if (boot->file)
+	{
+	  if (!option_bool(OPT_NO_OVERRIDE) &&
+	      req_options && 
+	      in_list(req_options, OPTION_FILENAME))
+	    option_put_string(mess, end, OPTION_FILENAME, boot->file, 1);
+	  else
+	    strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
+	}
+      
+      if (boot->next_server.s_addr) 
+	mess->siaddr = boot->next_server;
+      else if (boot->tftp_sname)
+	mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
+    }
+  else
+    /* Use the values of the relevant options if no dhcp-boot given and
+       they're not explicitly asked for as options. OPTION_END is used
+       as an internal way to specify siaddr without using dhcp-boot, for use in
+       dhcp-optsfile. */
+    {
+      if ((!req_options || !in_list(req_options, OPTION_FILENAME)) &&
+	  (opt = option_find2(OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
+	{
+	  strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1);
+	  done_file = 1;
+	}
+      
+      if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
+	  (opt = option_find2(OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
+	{
+	  strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1);
+	  done_server = 1;
+	}
+      
+      if ((opt = option_find2(OPTION_END)))
+	mess->siaddr.s_addr = ((struct in_addr *)opt->val)->s_addr;	
+    }
+        
+  /* We don't want to do option-overload for BOOTP, so make the file and sname
+     fields look like they are in use, even when they aren't. This gets restored
+     at the end of this function. */
+
+  if (!req_options || option_bool(OPT_NO_OVERRIDE))
+    {
+      f0 = mess->file[0];
+      mess->file[0] = 1;
+      s0 = mess->sname[0];
+      mess->sname[0] = 1;
+    }
+      
+  /* At this point, if mess->sname or mess->file are zeroed, they are available
+     for option overload, reserve space for the overload option. */
+  if (mess->file[0] == 0 || mess->sname[0] == 0)
+    end -= 3;
+
+  /* rfc3011 says this doesn't need to be in the requested options list. */
+  if (subnet_addr.s_addr)
+    option_put(mess, end, OPTION_SUBNET_SELECT, INADDRSZ, ntohl(subnet_addr.s_addr));
+   
+  if (lease_time != 0xffffffff)
+    { 
+      unsigned int t1val = lease_time/2; 
+      unsigned int t2val = (lease_time*7)/8;
+      unsigned int hval;
+      
+      /* If set by user, sanity check, so not longer than lease. */
+      if ((opt = option_find2(OPTION_T1)))
+	{
+	  hval = ntohl(*((unsigned int *)opt->val));
+	  if (hval < lease_time && hval > 2)
+	    t1val = hval;
+	}
+
+       if ((opt = option_find2(OPTION_T2)))
+	{
+	  hval = ntohl(*((unsigned int *)opt->val));
+	  if (hval < lease_time && hval > 2)
+	    t2val = hval;
+	}
+       	  
+       /* ensure T1 is still < T2 */
+       if (t2val <= t1val)
+	 t1val = t2val - 1; 
+
+       while (fuzz > (t1val/8))
+	 fuzz = fuzz/2;
+	 
+       t1val -= fuzz;
+       t2val -= fuzz;
+       
+       option_put(mess, end, OPTION_T1, 4, t1val);
+       option_put(mess, end, OPTION_T2, 4, t2val);
+    }
+
+  /* replies to DHCPINFORM may not have a valid context */
+  if (context)
+    {
+      if (!option_find2(OPTION_NETMASK))
+	option_put(mess, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
+  
+      /* May not have a "guessed" broadcast address if we got no packets via a relay
+	 from this net yet (ie just unicast renewals after a restart */
+      if (context->broadcast.s_addr &&
+	  !option_find2(OPTION_BROADCAST))
+	option_put(mess, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
+      
+      /* Same comments as broadcast apply, and also may not be able to get a sensible
+	 default when using subnet select.  User must configure by steam in that case. */
+      if (context->router.s_addr &&
+	  in_list(req_options, OPTION_ROUTER) &&
+	  !option_find2(OPTION_ROUTER))
+	option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
+      
+      if (daemon->port == NAMESERVER_PORT &&
+	  in_list(req_options, OPTION_DNSSERVER) &&
+	  !option_find2(OPTION_DNSSERVER))
+	option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
+    }
+
+  if (domain && in_list(req_options, OPTION_DOMAINNAME) && 
+      !option_find2(OPTION_DOMAINNAME))
+    option_put_string(mess, end, OPTION_DOMAINNAME, domain, null_term);
+ 
+  /* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */
+  if (hostname)
+    {
+      if (in_list(req_options, OPTION_HOSTNAME) &&
+	  !option_find2(OPTION_HOSTNAME))
+	option_put_string(mess, end, OPTION_HOSTNAME, hostname, null_term);
+      
+      if (fqdn_flags != 0)
+	{
+	  len = strlen(hostname) + 3;
+	  
+	  if (fqdn_flags & 0x04)
+	    len += 2;
+	  else if (null_term)
+	    len++;
+
+	  if (domain)
+	    len += strlen(domain) + 1;
+	  else if (fqdn_flags & 0x04)
+	    len--;
+
+	  if ((p = free_space(mess, end, OPTION_CLIENT_FQDN, len)))
+	    {
+	      *(p++) = fqdn_flags & 0x0f; /* MBZ bits to zero */ 
+	      *(p++) = 255;
+	      *(p++) = 255;
+
+	      if (fqdn_flags & 0x04)
+		{
+		  p = do_rfc1035_name(p, hostname, NULL);
+		  if (domain)
+		    {
+		      p = do_rfc1035_name(p, domain, NULL);
+		      *p++ = 0;
+		    }
+		}
+	      else
+		{
+		  memcpy(p, hostname, strlen(hostname));
+		  p += strlen(hostname);
+		  if (domain)
+		    {
+		      *(p++) = '.';
+		      memcpy(p, domain, strlen(domain));
+		      p += strlen(domain);
+		    }
+		  if (null_term)
+		    *(p++) = 0;
+		}
+	    }
+	}
+    }      
+
+  for (opt = config_opts; opt; opt = opt->next)
+    {
+      int optno = opt->opt;
+
+      /* netids match and not encapsulated? */
+      if (!(opt->flags & DHOPT_TAGOK))
+	continue;
+      
+      /* was it asked for, or are we sending it anyway? */
+      if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
+	continue;
+      
+      /* prohibit some used-internally options. T1 and T2 already handled. */
+      if (optno == OPTION_CLIENT_FQDN ||
+	  optno == OPTION_MAXMESSAGE ||
+	  optno == OPTION_OVERLOAD ||
+	  optno == OPTION_PAD ||
+	  optno == OPTION_END ||
+	  optno == OPTION_T1 ||
+	  optno == OPTION_T2)
+	continue;
+
+      if (optno == OPTION_SNAME && done_server)
+	continue;
+
+      if (optno == OPTION_FILENAME && done_file)
+	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 && 
+	  (optno == OPTION_NETMASK ||
+	   optno == OPTION_BROADCAST ||
+	   optno == OPTION_ROUTER ||
+	   optno == OPTION_DNSSERVER || 
+	   optno == OPTION_DOMAINNAME ||
+	   optno == OPTION_HOSTNAME))
+	continue;
+
+      /* vendor-class comes from elsewhere for PXE */
+      if (pxe_arch != -1 && optno == OPTION_VENDOR_ID)
+	continue;
+      
+      /* always force null-term for filename and servername - buggy PXE again. */
+      len = do_opt(opt, NULL, context, 
+		   (optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
+
+      if ((p = free_space(mess, end, optno, len)))
+	{
+	  do_opt(opt, p, context, 
+		 (optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
+	  
+	  /* If we send a vendor-id, revisit which vendor-ops we consider 
+	     it appropriate to send. */
+	  if (optno == OPTION_VENDOR_ID)
+	    {
+	      match_vendor_opts(p - 2, config_opts);
+	      done_vendor_class = 1;
+	    }
+	}  
+    }
+
+  /* Now send options to be encapsulated in arbitrary options, 
+     eg dhcp-option=encap:172,17,.......
+     Also handle vendor-identifying vendor-encapsulated options,
+     dhcp-option = vi-encap:13,17,.......
+     The may be more that one "outer" to do, so group
+     all the options which match each outer in turn. */
+  for (opt = config_opts; opt; opt = opt->next)
+    opt->flags &= ~DHOPT_ENCAP_DONE;
+  
+  for (opt = config_opts; opt; opt = opt->next)
+    {
+      int flags;
+      
+      if ((flags = (opt->flags & (DHOPT_ENCAPSULATE | DHOPT_RFC3925))))
+	{
+	  int found = 0;
+	  struct dhcp_opt *o;
+
+	  if (opt->flags & DHOPT_ENCAP_DONE)
+	    continue;
+
+	  for (len = 0, o = config_opts; o; o = o->next)
+	    {
+	      int outer = flags & DHOPT_ENCAPSULATE ? o->u.encap : OPTION_VENDOR_IDENT_OPT;
+
+	      o->flags &= ~DHOPT_ENCAP_MATCH;
+	      
+	      if (!(o->flags & flags) || opt->u.encap != o->u.encap)
+		continue;
+	      
+	      o->flags |= DHOPT_ENCAP_DONE;
+	      if (match_netid(o->netid, tagif, 1) &&
+		  ((o->flags & DHOPT_FORCE) || in_list(req_options, outer)))
+		{
+		  o->flags |= DHOPT_ENCAP_MATCH;
+		  found = 1;
+		  len += do_opt(o, NULL, NULL, 0) + 2;
+		}
+	    } 
+	  
+	  if (found)
+	    { 
+	      if (flags & DHOPT_ENCAPSULATE)
+		do_encap_opts(config_opts, opt->u.encap, DHOPT_ENCAP_MATCH, mess, end, null_term);
+	      else if (len > 250)
+		my_syslog(MS_DHCP | LOG_WARNING, _("cannot send RFC3925 option: too many options for enterprise number %d"), opt->u.encap);
+	      else if ((p = free_space(mess, end,  OPTION_VENDOR_IDENT_OPT, len + 5)))
+		{
+		  int swap_ent = htonl(opt->u.encap);
+		  memcpy(p, &swap_ent, 4);
+		  p += 4;
+		  *(p++) = len;
+		  for (o = config_opts; o; o = o->next)
+		    if (o->flags & DHOPT_ENCAP_MATCH)
+		      {
+			len = do_opt(o, p + 2, NULL, 0);
+			*(p++) = o->opt;
+			*(p++) = len;
+			p += len;
+		      }     
+		}
+	    }
+	}
+    }      
+
+  force_encap = prune_vendor_opts(tagif);
+  
+  if (context && pxe_arch != -1)
+    {
+      pxe_misc(mess, end, uuid);
+      if (!pxe_uefi_workaround(pxe_arch, tagif, mess, context->local, now, 0))
+	config_opts = pxe_opts(pxe_arch, tagif, context->local, now);
+    }
+
+  if ((force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT)) &&
+      do_encap_opts(config_opts, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, null_term) && 
+      pxe_arch == -1 && !done_vendor_class && vendor_class_len != 0 &&
+      (p = free_space(mess, end, OPTION_VENDOR_ID, vendor_class_len)))
+    /* If we send vendor encapsulated options, and haven't already sent option 60,
+       echo back the value we got from the client. */
+    memcpy(p, daemon->dhcp_buff3, vendor_class_len);	    
+   
+   /* restore BOOTP anti-overload hack */
+  if (!req_options || option_bool(OPT_NO_OVERRIDE))
+    {
+      mess->file[0] = f0;
+      mess->sname[0] = s0;
+    }
+}
+
+static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid)
+{
+  struct delay_config *delay_conf;
+  
+  /* Decide which delay_config option we're using */
+  for (delay_conf = daemon->delay_conf; delay_conf; delay_conf = delay_conf->next)
+    if (match_netid(delay_conf->netid, netid, 0))
+      break;
+  
+  if (!delay_conf)
+    /* No match, look for one without a netid */
+    for (delay_conf = daemon->delay_conf; delay_conf; delay_conf = delay_conf->next)
+      if (match_netid(delay_conf->netid, netid, 1))
+        break;
+
+  if (delay_conf)
+    {
+      if (!option_bool(OPT_QUIET_DHCP))
+	my_syslog(MS_DHCP | LOG_INFO, _("%u reply delay: %d"), ntohl(xid), delay_conf->delay);
+      delay_dhcp(recvtime, delay_conf->delay, -1, 0, 0);
+    }
+}
+
+#endif
+  
+
+  
+  
+
+
+  
diff --git a/src/rfc3315.c b/src/rfc3315.c
new file mode 100644
index 0000000..4ca43e0
--- /dev/null
+++ b/src/rfc3315.c
@@ -0,0 +1,2197 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_DHCP6
+
+struct state {
+  unsigned char *clid;
+  int clid_len, iaid, ia_type, interface, hostname_auth, lease_allocate;
+  char *client_hostname, *hostname, *domain, *send_domain;
+  struct dhcp_context *context;
+  struct in6_addr *link_address, *fallback, *ll_addr, *ula_addr;
+  unsigned int xid, fqdn_flags;
+  char *iface_name;
+  void *packet_options, *end;
+  struct dhcp_netid *tags, *context_tags;
+  unsigned char mac[DHCP_CHADDR_MAX];
+  unsigned int mac_len, mac_type;
+#ifdef OPTION6_PREFIX_CLASS
+  struct prefix_class *send_prefix_class;
+#endif
+};
+
+static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, 
+			     struct in6_addr *client_addr, int is_unicast, time_t now);
+static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now);
+static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts);
+static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string);
+static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string);
+static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize);
+static void *opt6_next(void *opts, void *end);
+static unsigned int opt6_uint(unsigned char *opt, int offset, int size);
+static void get_context_tag(struct state *state, struct dhcp_context *context);
+static int check_ia(struct state *state, void *opt, void **endp, void **ia_option);
+static int build_ia(struct state *state, int *t1cntr);
+static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz);
+#ifdef OPTION6_PREFIX_CLASS
+static struct prefix_class *prefix_class_from_context(struct dhcp_context *context);
+#endif
+static void mark_context_used(struct state *state, struct in6_addr *addr);
+static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr);
+static int check_address(struct state *state, struct in6_addr *addr);
+static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option, 
+			unsigned int *min_time, struct in6_addr *addr, time_t now);
+static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now);
+static int add_local_addrs(struct dhcp_context *context);
+static struct dhcp_netid *add_options(struct state *state, int do_refresh);
+static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep, 
+			    unsigned int *preferred_timep, unsigned int lease_time);
+
+#define opt6_len(opt) ((int)(opt6_uint(opt, -2, 2)))
+#define opt6_type(opt) (opt6_uint(opt, -4, 2))
+#define opt6_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[4+(i)]))
+
+#define opt6_user_vendor_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2+(i)]))
+#define opt6_user_vendor_len(opt) ((int)(opt6_uint(opt, -4, 2)))
+#define opt6_user_vendor_next(opt, end) (opt6_next(((void *) opt) - 2, end))
+ 
+
+unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
+			   struct in6_addr *fallback,  struct in6_addr *ll_addr, struct in6_addr *ula_addr,
+			   size_t sz, struct in6_addr *client_addr, time_t now)
+{
+  struct dhcp_vendor *vendor;
+  int msg_type;
+  struct state state;
+  
+  if (sz <= 4)
+    return 0;
+  
+  msg_type = *((unsigned char *)daemon->dhcp_packet.iov_base);
+  
+  /* Mark these so we only match each at most once, to avoid tangled linked lists */
+  for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
+    vendor->netid.next = &vendor->netid;
+  
+  reset_counter();
+  state.context = context;
+  state.interface = interface;
+  state.iface_name = iface_name;
+  state.fallback = fallback;
+  state.ll_addr = ll_addr;
+  state.ula_addr = ula_addr;
+  state.mac_len = 0;
+  state.tags = NULL;
+  state.link_address = NULL;
+
+  if (dhcp6_maybe_relay(&state, daemon->dhcp_packet.iov_base, sz, client_addr, 
+			IN6_IS_ADDR_MULTICAST(client_addr), now))
+    return msg_type == DHCP6RELAYFORW ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
+
+  return 0;
+}
+
+/* This cost me blood to write, it will probably cost you blood to understand - srk. */
+static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, 
+			     struct in6_addr *client_addr, int is_unicast, time_t now)
+{
+  void *end = inbuff + sz;
+  void *opts = inbuff + 34;
+  int msg_type = *((unsigned char *)inbuff);
+  unsigned char *outmsgtypep;
+  void *opt;
+  struct dhcp_vendor *vendor;
+
+  /* if not an encapsulated relayed message, just do the stuff */
+  if (msg_type != DHCP6RELAYFORW)
+    {
+      /* if link_address != NULL if points to the link address field of the 
+	 innermost nested RELAYFORW message, which is where we find the
+	 address of the network on which we can allocate an address.
+	 Recalculate the available contexts using that information. 
+
+      link_address == NULL means there's no relay in use, so we try and find the client's 
+      MAC address from the local ND cache. */
+      
+      if (!state->link_address)
+	get_client_mac(client_addr, state->interface, state->mac, &state->mac_len, &state->mac_type, now);
+      else
+	{
+	  struct dhcp_context *c;
+	  state->context = NULL;
+	   
+	  if (!IN6_IS_ADDR_LOOPBACK(state->link_address) &&
+	      !IN6_IS_ADDR_LINKLOCAL(state->link_address) &&
+	      !IN6_IS_ADDR_MULTICAST(state->link_address))
+	    for (c = daemon->dhcp6; c; c = c->next)
+	      if ((c->flags & CONTEXT_DHCP) &&
+		  !(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
+		  is_same_net6(state->link_address, &c->start6, c->prefix) &&
+		  is_same_net6(state->link_address, &c->end6, c->prefix))
+		{
+		  c->preferred = c->valid = 0xffffffff;
+		  c->current = state->context;
+		  state->context = c;
+		}
+	  
+	  if (!state->context)
+	    {
+	      inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN); 
+	      my_syslog(MS_DHCP | LOG_WARNING, 
+			_("no address range available for DHCPv6 request from relay at %s"),
+			daemon->addrbuff);
+	      return 0;
+	    }
+	}
+	  
+      if (!state->context)
+	{
+	  my_syslog(MS_DHCP | LOG_WARNING, 
+		    _("no address range available for DHCPv6 request via %s"), state->iface_name);
+	  return 0;
+	}
+
+      return dhcp6_no_relay(state, msg_type, inbuff, sz, is_unicast, now);
+    }
+
+  /* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
+     which is               1   +    1   +    16      +     16     + 2 + 2 = 38 */
+  if (sz < 38)
+    return 0;
+  
+  /* copy header stuff into reply message and set type to reply */
+  if (!(outmsgtypep = put_opt6(inbuff, 34)))
+    return 0;
+  *outmsgtypep = DHCP6RELAYREPL;
+
+  /* look for relay options and set tags if found. */
+  for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
+    {
+      int mopt;
+      
+      if (vendor->match_type == MATCH_SUBSCRIBER)
+	mopt = OPTION6_SUBSCRIBER_ID;
+      else if (vendor->match_type == MATCH_REMOTE)
+	mopt = OPTION6_REMOTE_ID; 
+      else
+	continue;
+
+      if ((opt = opt6_find(opts, end, mopt, 1)) &&
+	  vendor->len == opt6_len(opt) &&
+	  memcmp(vendor->data, opt6_ptr(opt, 0), vendor->len) == 0 &&
+	  vendor->netid.next != &vendor->netid)
+	{
+	  vendor->netid.next = state->tags;
+	  state->tags = &vendor->netid;
+	  break;
+	}
+    }
+  
+  /* RFC-6939 */
+  if ((opt = opt6_find(opts, end, OPTION6_CLIENT_MAC, 3)))
+    {
+      if (opt6_len(opt) - 2 > DHCP_CHADDR_MAX) {
+        return 0;
+      }
+      state->mac_type = opt6_uint(opt, 0, 2);
+      state->mac_len = opt6_len(opt) - 2;
+      memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len);
+    }
+  
+  for (opt = opts; opt; opt = opt6_next(opt, end))
+    {
+      if (opt6_ptr(opt, 0) + opt6_len(opt) >= end) {
+        return 0;
+      }
+      int o = new_opt6(opt6_type(opt));
+      if (opt6_type(opt) == OPTION6_RELAY_MSG)
+	{
+	  struct in6_addr align;
+	  /* the packet data is unaligned, copy to aligned storage */
+	  memcpy(&align, inbuff + 2, IN6ADDRSZ); 
+	  state->link_address = &align;
+	  /* zero is_unicast since that is now known to refer to the 
+	     relayed packet, not the original sent by the client */
+	  if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, 0, now))
+	    return 0;
+	}
+      else if (opt6_type(opt) != OPTION6_CLIENT_MAC)
+	put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
+      end_opt6(o);	    
+    }
+  
+  return 1;
+}
+
+static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now)
+{
+  void *opt;
+  int i, o, o1, start_opts;
+  struct dhcp_opt *opt_cfg;
+  struct dhcp_netid *tagif;
+  struct dhcp_config *config = NULL;
+  struct dhcp_netid known_id, iface_id, v6_id;
+  unsigned char *outmsgtypep;
+  struct dhcp_vendor *vendor;
+  struct dhcp_context *context_tmp;
+  struct dhcp_mac *mac_opt;
+  unsigned int ignore = 0;
+#ifdef OPTION6_PREFIX_CLASS
+  struct prefix_class *p;
+  int dump_all_prefix_classes = 0;
+#endif
+
+  state->packet_options = inbuff + 4;
+  state->end = inbuff + sz;
+  state->clid = NULL;
+  state->clid_len = 0;
+  state->lease_allocate = 0;
+  state->context_tags = NULL;
+  state->domain = NULL;
+  state->send_domain = NULL;
+  state->hostname_auth = 0;
+  state->hostname = NULL;
+  state->client_hostname = NULL;
+  state->fqdn_flags = 0x01; /* default to send if we receive no FQDN option */
+#ifdef OPTION6_PREFIX_CLASS
+  state->send_prefix_class = NULL;
+#endif
+
+  /* set tag with name == interface */
+  iface_id.net = state->iface_name;
+  iface_id.next = state->tags;
+  state->tags = &iface_id; 
+
+  /* set tag "dhcpv6" */
+  v6_id.net = "dhcpv6";
+  v6_id.next = state->tags;
+  state->tags = &v6_id;
+
+  /* copy over transaction-id, and save pointer to message type */
+  if (!(outmsgtypep = put_opt6(inbuff, 4)))
+    return 0;
+  start_opts = save_counter(-1);
+  state->xid = outmsgtypep[3] | outmsgtypep[2] << 8 | outmsgtypep[1] << 16;
+   
+  /* We're going to be linking tags from all context we use. 
+     mark them as unused so we don't link one twice and break the list */
+  for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
+    {
+      context_tmp->netid.next = &context_tmp->netid;
+
+      if (option_bool(OPT_LOG_OPTS))
+	{
+	   inet_ntop(AF_INET6, &context_tmp->start6, daemon->dhcp_buff, ADDRSTRLEN); 
+	   inet_ntop(AF_INET6, &context_tmp->end6, daemon->dhcp_buff2, ADDRSTRLEN); 
+	   if (context_tmp->flags & (CONTEXT_STATIC))
+	     my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCPv6 subnet: %s/%d"),
+		       state->xid, daemon->dhcp_buff, context_tmp->prefix);
+	   else
+	     my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP range: %s -- %s"), 
+		       state->xid, daemon->dhcp_buff, daemon->dhcp_buff2);
+	}
+    }
+
+  if ((opt = opt6_find(state->packet_options, state->end, OPTION6_CLIENT_ID, 1)))
+    {
+      state->clid = opt6_ptr(opt, 0);
+      state->clid_len = opt6_len(opt);
+      o = new_opt6(OPTION6_CLIENT_ID);
+      put_opt6(state->clid, state->clid_len);
+      end_opt6(o);
+    }
+  else if (msg_type != DHCP6IREQ)
+    return 0;
+
+  /* server-id must match except for SOLICIT, CONFIRM and REBIND messages */
+  if (msg_type != DHCP6SOLICIT && msg_type != DHCP6CONFIRM && msg_type != DHCP6IREQ && msg_type != DHCP6REBIND &&
+      (!(opt = opt6_find(state->packet_options, state->end, OPTION6_SERVER_ID, 1)) ||
+       opt6_len(opt) != daemon->duid_len ||
+       memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
+    return 0;
+  
+  o = new_opt6(OPTION6_SERVER_ID);
+  put_opt6(daemon->duid, daemon->duid_len);
+  end_opt6(o);
+
+  if (is_unicast &&
+      (msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE))
+    
+    {  
+      *outmsgtypep = DHCP6REPLY;
+      o1 = new_opt6(OPTION6_STATUS_CODE);
+      put_opt6_short(DHCP6USEMULTI);
+      put_opt6_string("Use multicast");
+      end_opt6(o1);
+      return 1;
+    }
+
+  /* match vendor and user class options */
+  for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
+    {
+      int mopt;
+      
+      if (vendor->match_type == MATCH_VENDOR)
+	mopt = OPTION6_VENDOR_CLASS;
+      else if (vendor->match_type == MATCH_USER)
+	mopt = OPTION6_USER_CLASS; 
+      else
+	continue;
+
+      if ((opt = opt6_find(state->packet_options, state->end, mopt, 2)))
+	{
+	  void *enc_opt, *enc_end = opt6_ptr(opt, opt6_len(opt));
+	  int offset = 0;
+	  
+	  if (mopt == OPTION6_VENDOR_CLASS)
+	    {
+	      if (opt6_len(opt) < 4)
+		continue;
+	      
+	      if (vendor->enterprise != opt6_uint(opt, 0, 4))
+		continue;
+	    
+	      offset = 4;
+	    }
+ 
+	  /* Note that format if user/vendor classes is different to DHCP options - no option types. */
+	  for (enc_opt = opt6_ptr(opt, offset); enc_opt; enc_opt = opt6_user_vendor_next(enc_opt, enc_end))
+	    for (i = 0; i <= (opt6_user_vendor_len(enc_opt) - vendor->len); i++)
+	      if (memcmp(vendor->data, opt6_user_vendor_ptr(enc_opt, i), vendor->len) == 0)
+		{
+		  vendor->netid.next = state->tags;
+		  state->tags = &vendor->netid;
+		  break;
+		}
+	}
+    }
+
+  if (option_bool(OPT_LOG_OPTS) && (opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
+    my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %u"), state->xid, opt6_uint(opt, 0, 4));
+  
+  /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
+     Otherwise assume the option is an array, and look for a matching element. 
+     If no data given, existence of the option is enough. This code handles 
+     V-I opts too. */
+  for (opt_cfg = daemon->dhcp_match6; opt_cfg; opt_cfg = opt_cfg->next)
+    {
+      int match = 0;
+      
+      if (opt_cfg->flags & DHOPT_RFC3925)
+	{
+	  for (opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_OPTS, 4);
+	       opt;
+	       opt = opt6_find(opt6_next(opt, state->end), state->end, OPTION6_VENDOR_OPTS, 4))
+	    {
+	      void *vopt;
+	      void *vend = opt6_ptr(opt, opt6_len(opt));
+	      
+	      for (vopt = opt6_find(opt6_ptr(opt, 4), vend, opt_cfg->opt, 0);
+		   vopt;
+		   vopt = opt6_find(opt6_next(vopt, vend), vend, opt_cfg->opt, 0))
+		if ((match = match_bytes(opt_cfg, opt6_ptr(vopt, 0), opt6_len(vopt))))
+		  break;
+	    }
+	  if (match)
+	    break;
+	}
+      else
+	{
+	  if (!(opt = opt6_find(state->packet_options, state->end, opt_cfg->opt, 1)))
+	    continue;
+	  
+	  match = match_bytes(opt_cfg, opt6_ptr(opt, 0), opt6_len(opt));
+	} 
+  
+      if (match)
+	{
+	  opt_cfg->netid->next = state->tags;
+	  state->tags = opt_cfg->netid;
+	}
+    }
+
+  if (state->mac_len != 0)
+    {
+      if (option_bool(OPT_LOG_OPTS))
+	{
+	  print_mac(daemon->dhcp_buff, state->mac, state->mac_len);
+	  my_syslog(MS_DHCP | LOG_INFO, _("%u client MAC address: %s"), state->xid, daemon->dhcp_buff);
+	}
+
+      for (mac_opt = daemon->dhcp_macs; mac_opt; mac_opt = mac_opt->next)
+	if ((unsigned)mac_opt->hwaddr_len == state->mac_len &&
+	    ((unsigned)mac_opt->hwaddr_type == state->mac_type || mac_opt->hwaddr_type == 0) &&
+	    memcmp_masked(mac_opt->hwaddr, state->mac, state->mac_len, mac_opt->mask))
+	  {
+	    mac_opt->netid.next = state->tags;
+	    state->tags = &mac_opt->netid;
+	  }
+    }
+  
+  if ((opt = opt6_find(state->packet_options, state->end, OPTION6_FQDN, 1)))
+    {
+      /* RFC4704 refers */
+       int len = opt6_len(opt) - 1;
+       
+       state->fqdn_flags = opt6_uint(opt, 0, 1);
+       
+       /* Always force update, since the client has no way to do it itself. */
+       if (!option_bool(OPT_FQDN_UPDATE) && !(state->fqdn_flags & 0x01))
+	 state->fqdn_flags |= 0x03;
+ 
+       state->fqdn_flags &= ~0x04;
+
+       if (len != 0 && len < 255)
+	 {
+	   unsigned char *pp, *op = opt6_ptr(opt, 1);
+	   char *pq = daemon->dhcp_buff;
+	   
+	   pp = op;
+	   while (*op != 0 && ((op + (*op)) - pp) < len)
+	     {
+	       memcpy(pq, op+1, *op);
+	       pq += *op;
+	       op += (*op)+1;
+	       *(pq++) = '.';
+	     }
+	   
+	   if (pq != daemon->dhcp_buff)
+	     pq--;
+	   *pq = 0;
+	   
+	   if (legal_hostname(daemon->dhcp_buff))
+	     {
+	       state->client_hostname = daemon->dhcp_buff;
+	       if (option_bool(OPT_LOG_OPTS))
+		 my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), state->xid, state->client_hostname); 
+	     }
+	 }
+    }	 
+  
+  if (state->clid)
+    {
+      config = find_config(daemon->dhcp_conf, state->context, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL);
+      
+      if (have_config(config, CONFIG_NAME))
+	{
+	  state->hostname = config->hostname;
+	  state->domain = config->domain;
+	  state->hostname_auth = 1;
+	}
+      else if (state->client_hostname)
+	{
+	  state->domain = strip_hostname(state->client_hostname);
+	  
+	  if (strlen(state->client_hostname) != 0)
+	    {
+	      state->hostname = state->client_hostname;
+	      if (!config)
+		{
+		  /* Search again now we have a hostname. 
+		     Only accept configs without CLID here, (it won't match)
+		     to avoid impersonation by name. */
+		  struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname);
+		  if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
+		    config = new;
+		}
+	    }
+	}
+    }
+
+  if (config)
+    {
+      struct dhcp_netid_list *list;
+      
+      for (list = config->netid; list; list = list->next)
+        {
+          list->list->next = state->tags;
+          state->tags = list->list;
+        }
+
+      /* set "known" tag for known hosts */
+      known_id.net = "known";
+      known_id.next = state->tags;
+      state->tags = &known_id;
+
+      if (have_config(config, CONFIG_DISABLE))
+	ignore = 1;
+    }
+  else if (state->clid &&
+	   find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL))
+    {
+      known_id.net = "known-othernet";
+      known_id.next = state->tags;
+      state->tags = &known_id;
+    }
+  
+#ifdef OPTION6_PREFIX_CLASS
+  /* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
+  if (daemon->prefix_classes && (msg_type == DHCP6SOLICIT || msg_type == DHCP6REQUEST))
+    {
+      void *oro;
+      
+      if ((oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0)))
+	for (i = 0; i <  opt6_len(oro) - 1; i += 2)
+	  if (opt6_uint(oro, i, 2) == OPTION6_PREFIX_CLASS)
+	    {
+	      dump_all_prefix_classes = 1;
+	      break;
+	    }
+      
+      if (msg_type != DHCP6SOLICIT || dump_all_prefix_classes)
+	/* Add the tags associated with prefix classes so we can use the DHCP ranges.
+	   Not done for SOLICIT as we add them  one-at-time. */
+	for (p = daemon->prefix_classes; p ; p = p->next)
+	  {
+	    p->tag.next = state->tags;
+	    state->tags = &p->tag;
+	  }
+    }    
+#endif
+
+  tagif = run_tag_if(state->tags);
+  
+  /* if all the netids in the ignore list are present, ignore this client */
+  if (daemon->dhcp_ignore)
+    {
+      struct dhcp_netid_list *id_list;
+     
+      for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
+	if (match_netid(id_list->list, tagif, 0))
+	  ignore = 1;
+    }
+  
+  /* if all the netids in the ignore_name list are present, ignore client-supplied name */
+  if (!state->hostname_auth)
+    {
+       struct dhcp_netid_list *id_list;
+       
+       for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
+	 if ((!id_list->list) || match_netid(id_list->list, tagif, 0))
+	   break;
+       if (id_list)
+	 state->hostname = NULL;
+    }
+  
+
+  switch (msg_type)
+    {
+    default:
+      return 0;
+      
+      
+    case DHCP6SOLICIT:
+      {
+      	int address_assigned = 0;
+	/* tags without all prefix-class tags */
+	struct dhcp_netid *solicit_tags;
+	struct dhcp_context *c;
+	
+	*outmsgtypep = DHCP6ADVERTISE;
+	
+	if (opt6_find(state->packet_options, state->end, OPTION6_RAPID_COMMIT, 0))
+	  {
+	    *outmsgtypep = DHCP6REPLY;
+	    state->lease_allocate = 1;
+	    o = new_opt6(OPTION6_RAPID_COMMIT);
+	    end_opt6(o);
+	  }
+	
+  	log6_quiet(state, "DHCPSOLICIT", NULL, ignore ? _("ignored") : NULL);
+
+      request_no_address:
+	solicit_tags = tagif;
+	
+	if (ignore)
+	  return 0;
+	
+	/* reset USED bits in leases */
+	lease6_reset();
+
+	/* Can use configured address max once per prefix */
+	for (c = state->context; c; c = c->current)
+	  c->flags &= ~CONTEXT_CONF_USED;
+
+	for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
+	  {   
+	    void *ia_option, *ia_end;
+	    unsigned int min_time = 0xffffffff;
+	    int t1cntr;
+	    int ia_counter;
+	    /* set unless we're sending a particular prefix-class, when we
+	       want only dhcp-ranges with the correct tags set and not those without any tags. */
+	    int plain_range = 1;
+	    u32 lease_time;
+	    struct dhcp_lease *ltmp;
+	    struct in6_addr *req_addr;
+	    struct in6_addr addr;
+
+	    if (!check_ia(state, opt, &ia_end, &ia_option))
+	      continue;
+	    
+	    /* reset USED bits in contexts - one address per prefix per IAID */
+	    for (c = state->context; c; c = c->current)
+	      c->flags &= ~CONTEXT_USED;
+
+#ifdef OPTION6_PREFIX_CLASS
+	    if (daemon->prefix_classes && state->ia_type == OPTION6_IA_NA)
+	      {
+		void *prefix_opt;
+		int prefix_class;
+		
+		if (dump_all_prefix_classes)
+		  /* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
+		  plain_range = 0;
+		else 
+		  { 
+		    if ((prefix_opt = opt6_find(opt6_ptr(opt, 12), ia_end, OPTION6_PREFIX_CLASS, 2)))
+		      {
+			
+			prefix_class = opt6_uint(prefix_opt, 0, 2);
+			
+			for (p = daemon->prefix_classes; p ; p = p->next)
+			  if (p->class == prefix_class)
+			    break;
+			
+			if (!p)
+			  my_syslog(MS_DHCP | LOG_WARNING, _("unknown prefix-class %d"), prefix_class);
+			else
+			  {
+			    /* add tag to list, and exclude undecorated dhcp-ranges */
+			    p->tag.next = state->tags;
+			    solicit_tags = run_tag_if(&p->tag);
+			    plain_range = 0;
+			    state->send_prefix_class = p;
+			  }
+		      }
+		    else
+		      {
+			/* client didn't ask for a prefix class, lets see if we can find one. */
+			for (p = daemon->prefix_classes; p ; p = p->next)
+			  {
+			    p->tag.next = NULL;
+			    if (match_netid(&p->tag, solicit_tags, 1))
+			      break;
+			  }
+			
+			if (p)
+			  {
+			    plain_range = 0;
+			    state->send_prefix_class = p;
+			  }
+		      }
+
+		    if (p && option_bool(OPT_LOG_OPTS))
+		      my_syslog(MS_DHCP | LOG_INFO, "%u prefix class %d tag:%s", state->xid, p->class, p->tag.net); 
+		  }
+	      }
+#endif
+
+	    o = build_ia(state, &t1cntr);
+	    if (address_assigned)
+		address_assigned = 2;
+
+	    for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
+	      {
+		req_addr = opt6_ptr(ia_option, 0);
+				
+		if ((c = address6_valid(state->context, req_addr, solicit_tags, plain_range)))
+		  {
+		    lease_time = c->lease_time;
+		    /* If the client asks for an address on the same network as a configured address, 
+		       offer the configured address instead, to make moving to newly-configured
+		       addresses automatic. */
+		    if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr))
+		      {
+			req_addr = &addr;
+			mark_config_used(c, &addr);
+			if (have_config(config, CONFIG_TIME))
+			  lease_time = config->lease_time;
+		      }
+		    else if (!(c = address6_available(state->context, req_addr, solicit_tags, plain_range)))
+		      continue; /* not an address we're allowed */
+		    else if (!check_address(state, req_addr))
+		      continue; /* address leased elsewhere */
+		    
+		    /* add address to output packet */
+#ifdef OPTION6_PREFIX_CLASS
+		    if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
+		      state->send_prefix_class = prefix_class_from_context(c);
+#endif		    
+		    add_address(state, c, lease_time, ia_option, &min_time, req_addr, now);
+		    mark_context_used(state, req_addr);
+		    get_context_tag(state, c);
+		    address_assigned = 1;
+		  }
+	      }
+	    
+	    /* Suggest configured address(es) */
+	    for (c = state->context; c; c = c->current) 
+	      if (!(c->flags & CONTEXT_CONF_USED) &&
+		  match_netid(c->filter, solicit_tags, plain_range) &&
+		  config_valid(config, c, &addr) && 
+		  check_address(state, &addr))
+		{
+		  mark_config_used(state->context, &addr);
+		  if (have_config(config, CONFIG_TIME))
+		    lease_time = config->lease_time;
+		  else
+		    lease_time = c->lease_time;
+		  /* add address to output packet */
+#ifdef OPTION6_PREFIX_CLASS
+		  if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
+		    state->send_prefix_class = prefix_class_from_context(c);
+#endif
+		  add_address(state, c, lease_time, NULL, &min_time, &addr, now);
+		  mark_context_used(state, &addr);
+		  get_context_tag(state, c);
+		  address_assigned = 1;
+		}
+	    
+	    /* return addresses for existing leases */
+	    ltmp = NULL;
+	    while ((ltmp = lease6_find_by_client(ltmp, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state->clid, state->clid_len, state->iaid)))
+	      {
+		req_addr = &ltmp->addr6;
+		if ((c = address6_available(state->context, req_addr, solicit_tags, plain_range)))
+		  {
+#ifdef OPTION6_PREFIX_CLASS
+		    if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
+		      state->send_prefix_class = prefix_class_from_context(c);
+#endif
+		    add_address(state, c, c->lease_time, NULL, &min_time, req_addr, now);
+		    mark_context_used(state, req_addr);
+		    get_context_tag(state, c);
+		    address_assigned = 1;
+		  }
+	      }
+		 	   
+	    /* Return addresses for all valid contexts which don't yet have one */
+	    while ((c = address6_allocate(state->context, state->clid, state->clid_len, state->ia_type == OPTION6_IA_TA,
+					  state->iaid, ia_counter, solicit_tags, plain_range, &addr)))
+	      {
+#ifdef OPTION6_PREFIX_CLASS
+		if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
+		  state->send_prefix_class = prefix_class_from_context(c);
+#endif
+		add_address(state, c, c->lease_time, NULL, &min_time, &addr, now);
+		mark_context_used(state, &addr);
+		get_context_tag(state, c);
+		address_assigned = 1;
+	      }
+	    
+	    if (address_assigned != 1)
+	      {
+		/* If the server will not assign any addresses to any IAs in a
+		   subsequent Request from the client, the server MUST send an Advertise
+		   message to the client that doesn't include any IA options. */
+		if (!state->lease_allocate)
+		  {
+		    save_counter(o);
+		    continue;
+		  }
+		
+		/* If the server cannot assign any addresses to an IA in the message
+		   from the client, the server MUST include the IA in the Reply message
+		   with no addresses in the IA and a Status Code option in the IA
+		   containing status code NoAddrsAvail. */
+		o1 = new_opt6(OPTION6_STATUS_CODE);
+		put_opt6_short(DHCP6NOADDRS);
+		put_opt6_string(_("address unavailable"));
+		end_opt6(o1);
+	      }
+	    
+	    end_ia(t1cntr, min_time, 0);
+	    end_opt6(o);	
+	  }
+
+	if (address_assigned) 
+	  {
+	    o1 = new_opt6(OPTION6_STATUS_CODE);
+	    put_opt6_short(DHCP6SUCCESS);
+	    put_opt6_string(_("success"));
+	    end_opt6(o1);
+	    
+	    /* If --dhcp-authoritative is set, we can tell client not to wait for
+	       other possible servers */
+	    o = new_opt6(OPTION6_PREFERENCE);
+	    put_opt6_char(option_bool(OPT_AUTHORITATIVE) ? 255 : 0);
+	    end_opt6(o);
+	    tagif = add_options(state, 0);
+	  }
+	else
+	  { 
+	    /* no address, return error */
+	    o1 = new_opt6(OPTION6_STATUS_CODE);
+	    put_opt6_short(DHCP6NOADDRS);
+	    put_opt6_string(_("no addresses available"));
+	    end_opt6(o1);
+
+	    /* Some clients will ask repeatedly when we're not giving
+	       out addresses because we're in stateless mode. Avoid spamming
+	       the log in that case. */
+	    for (c = state->context; c; c = c->current)
+	      if (!(c->flags & CONTEXT_RA_STATELESS))
+		{
+		  log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", NULL, _("no addresses available"));
+		  break;
+		}
+	  }
+
+	break;
+      }
+      
+    case DHCP6REQUEST:
+      {
+	int address_assigned = 0;
+	int start = save_counter(-1);
+
+	/* set reply message type */
+	*outmsgtypep = DHCP6REPLY;
+	state->lease_allocate = 1;
+
+	log6_quiet(state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL);
+	
+	if (ignore)
+	  return 0;
+	
+	for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
+	  {   
+	    void *ia_option, *ia_end;
+	    unsigned int min_time = 0xffffffff;
+	    int t1cntr;
+	    
+	     if (!check_ia(state, opt, &ia_end, &ia_option))
+	       continue;
+
+	     if (!ia_option)
+	       {
+		 /* If we get a request with a IA_*A without addresses, treat it exactly like
+		    a SOLICT with rapid commit set. */
+		 save_counter(start);
+		 goto request_no_address; 
+	       }
+
+	    o = build_ia(state, &t1cntr);
+	      
+	    for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
+	      {
+		struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
+		struct dhcp_context *dynamic, *c;
+		unsigned int lease_time;
+		struct in6_addr addr;
+		int config_ok = 0;
+		
+		if ((c = address6_valid(state->context, req_addr, tagif, 1)))
+		  config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr);
+		
+		if ((dynamic = address6_available(state->context, req_addr, tagif, 1)) || c)
+		  {
+		    if (!dynamic && !config_ok)
+		      {
+			/* Static range, not configured. */
+			o1 = new_opt6(OPTION6_STATUS_CODE);
+			put_opt6_short(DHCP6NOADDRS);
+			put_opt6_string(_("address unavailable"));
+			end_opt6(o1);
+		      }
+		    else if (!check_address(state, req_addr))
+		      {
+			/* Address leased to another DUID/IAID */
+			o1 = new_opt6(OPTION6_STATUS_CODE);
+			put_opt6_short(DHCP6UNSPEC);
+			put_opt6_string(_("address in use"));
+			end_opt6(o1);
+		      } 
+		    else 
+		      {
+			if (!dynamic)
+			  dynamic = c;
+
+			lease_time = dynamic->lease_time;
+			
+			if (config_ok && have_config(config, CONFIG_TIME))
+			  lease_time = config->lease_time;
+
+#ifdef OPTION6_PREFIX_CLASS
+			if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
+			  state->send_prefix_class = prefix_class_from_context(c);
+#endif
+			add_address(state, dynamic, lease_time, ia_option, &min_time, req_addr, now);
+			get_context_tag(state, dynamic);
+			address_assigned = 1;
+		      }
+		  }
+		else 
+		  {
+		    /* requested address not on the correct link */
+		    o1 = new_opt6(OPTION6_STATUS_CODE);
+		    put_opt6_short(DHCP6NOTONLINK);
+		    put_opt6_string(_("not on link"));
+		    end_opt6(o1);
+		  }
+	      }
+	 
+	    end_ia(t1cntr, min_time, 0);
+	    end_opt6(o);	
+	  }
+
+	if (address_assigned) 
+	  {
+	    o1 = new_opt6(OPTION6_STATUS_CODE);
+	    put_opt6_short(DHCP6SUCCESS);
+	    put_opt6_string(_("success"));
+	    end_opt6(o1);
+	  }
+	else
+	  { 
+	    /* no address, return error */
+	    o1 = new_opt6(OPTION6_STATUS_CODE);
+	    put_opt6_short(DHCP6NOADDRS);
+	    put_opt6_string(_("no addresses available"));
+	    end_opt6(o1);
+	    log6_packet(state, "DHCPREPLY", NULL, _("no addresses available"));
+	  }
+
+	tagif = add_options(state, 0);
+	break;
+      }
+      
+  
+    case DHCP6RENEW:
+      {
+	/* set reply message type */
+	*outmsgtypep = DHCP6REPLY;
+	
+	log6_quiet(state, "DHCPRENEW", NULL, NULL);
+
+	for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
+	  {
+	    void *ia_option, *ia_end;
+	    unsigned int min_time = 0xffffffff;
+	    int t1cntr, iacntr;
+	    
+	    if (!check_ia(state, opt, &ia_end, &ia_option))
+	      continue;
+	    
+	    o = build_ia(state, &t1cntr);
+	    iacntr = save_counter(-1); 
+	    
+	    for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
+	      {
+		struct dhcp_lease *lease = NULL;
+		struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
+		unsigned int preferred_time =  opt6_uint(ia_option, 16, 4);
+		unsigned int valid_time =  opt6_uint(ia_option, 20, 4);
+		char *message = NULL;
+		struct dhcp_context *this_context;
+		
+		if (!(lease = lease6_find(state->clid, state->clid_len,
+					  state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, 
+					  state->iaid, req_addr)))
+		  {
+		    /* If the server cannot find a client entry for the IA the server
+		       returns the IA containing no addresses with a Status Code option set
+		       to NoBinding in the Reply message. */
+		    save_counter(iacntr);
+		    t1cntr = 0;
+		    
+		    log6_packet(state, "DHCPREPLY", req_addr, _("lease not found"));
+		    
+		    o1 = new_opt6(OPTION6_STATUS_CODE);
+		    put_opt6_short(DHCP6NOBINDING);
+		    put_opt6_string(_("no binding found"));
+		    end_opt6(o1);
+
+		    preferred_time = valid_time = 0;
+		    break;
+		  }
+		
+		
+		if ((this_context = address6_available(state->context, req_addr, tagif, 1)) ||
+		    (this_context = address6_valid(state->context, req_addr, tagif, 1)))
+		  {
+		    struct in6_addr addr;
+		    unsigned int lease_time;
+
+		    get_context_tag(state, this_context);
+		    
+		    if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr) && have_config(config, CONFIG_TIME))
+		      lease_time = config->lease_time;
+		    else 
+		      lease_time = this_context->lease_time;
+		    
+		    calculate_times(this_context, &min_time, &valid_time, &preferred_time, lease_time); 
+		    
+		    lease_set_expires(lease, valid_time, now);
+		    /* Update MAC record in case it's new information. */
+		    if (state->mac_len != 0)
+		      lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);
+		    if (state->ia_type == OPTION6_IA_NA && state->hostname)
+		      {
+			char *addr_domain = get_domain6(req_addr);
+			if (!state->send_domain)
+			  state->send_domain = addr_domain;
+			lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain); 
+			message = state->hostname;
+		      }
+		    
+		    
+		    if (preferred_time == 0)
+		      message = _("deprecated");
+		  }
+		else
+		  {
+		    preferred_time = valid_time = 0;
+		    message = _("address invalid");
+		  } 
+
+		if (message && (message != state->hostname))
+		  log6_packet(state, "DHCPREPLY", req_addr, message);	
+		else
+		  log6_quiet(state, "DHCPREPLY", req_addr, message);
+	
+		o1 =  new_opt6(OPTION6_IAADDR);
+		put_opt6(req_addr, sizeof(*req_addr));
+		put_opt6_long(preferred_time);
+		put_opt6_long(valid_time);
+		end_opt6(o1);
+	      }
+	    
+	    end_ia(t1cntr, min_time, 1);
+	    end_opt6(o);
+	  }
+	
+	tagif = add_options(state, 0);
+	break;
+	
+      }
+      
+    case DHCP6CONFIRM:
+      {
+	int good_addr = 0;
+
+	/* set reply message type */
+	*outmsgtypep = DHCP6REPLY;
+	
+	log6_quiet(state, "DHCPCONFIRM", NULL, NULL);
+	
+	for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
+	  {
+	    void *ia_option, *ia_end;
+	    
+	    for (check_ia(state, opt, &ia_end, &ia_option);
+		 ia_option;
+		 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
+	      {
+		struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
+		
+		if (!address6_valid(state->context, req_addr, tagif, 1))
+		  {
+		    o1 = new_opt6(OPTION6_STATUS_CODE);
+		    put_opt6_short(DHCP6NOTONLINK);
+		    put_opt6_string(_("confirm failed"));
+		    end_opt6(o1);
+		    return 1;
+		  }
+
+		good_addr = 1;
+		log6_quiet(state, "DHCPREPLY", req_addr, state->hostname);
+	      }
+	  }	 
+	
+	/* No addresses, no reply: RFC 3315 18.2.2 */
+	if (!good_addr)
+	  return 0;
+
+	o1 = new_opt6(OPTION6_STATUS_CODE);
+	put_opt6_short(DHCP6SUCCESS );
+	put_opt6_string(_("all addresses still on link"));
+	end_opt6(o1);
+	break;
+    }
+      
+    case DHCP6IREQ:
+      {
+	/* We can't discriminate contexts based on address, as we don't know it.
+	   If there is only one possible context, we can use its tags */
+	if (state->context && state->context->netid.net && !state->context->current)
+	  {
+	    state->context->netid.next = NULL;
+	    state->context_tags =  &state->context->netid;
+	  }
+
+	/* Similarly, we can't determine domain from address, but if the FQDN is
+	   given in --dhcp-host, we can use that, and failing that we can use the 
+	   unqualified configured domain, if any. */
+	if (state->hostname_auth)
+	  state->send_domain = state->domain;
+	else
+	  state->send_domain = get_domain6(NULL);
+
+	log6_quiet(state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state->hostname);
+	if (ignore)
+	  return 0;
+	*outmsgtypep = DHCP6REPLY;
+	tagif = add_options(state, 1);
+	break;
+      }
+      
+      
+    case DHCP6RELEASE:
+      {
+	/* set reply message type */
+	*outmsgtypep = DHCP6REPLY;
+
+	log6_quiet(state, "DHCPRELEASE", NULL, NULL);
+
+	for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
+	  {
+	    void *ia_option, *ia_end;
+	    int made_ia = 0;
+	    	    
+	    for (check_ia(state, opt, &ia_end, &ia_option);
+		 ia_option;
+		 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) 
+	      {
+		struct dhcp_lease *lease;
+		
+		if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
+					 state->iaid, opt6_ptr(ia_option, 0))))
+		  lease_prune(lease, now);
+		else
+		  {
+		    if (!made_ia)
+		      {
+			o = new_opt6(state->ia_type);
+			put_opt6_long(state->iaid);
+			if (state->ia_type == OPTION6_IA_NA)
+			  {
+			    put_opt6_long(0);
+			    put_opt6_long(0); 
+			  }
+			made_ia = 1;
+		      }
+		    
+		    o1 = new_opt6(OPTION6_IAADDR);
+		    put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
+		    put_opt6_long(0);
+		    put_opt6_long(0);
+		    end_opt6(o1);
+		  }
+	      }
+	    
+	    if (made_ia)
+	      {
+		o1 = new_opt6(OPTION6_STATUS_CODE);
+		put_opt6_short(DHCP6NOBINDING);
+		put_opt6_string(_("no binding found"));
+		end_opt6(o1);
+		
+		end_opt6(o);
+	      }
+	  }
+	
+	o1 = new_opt6(OPTION6_STATUS_CODE);
+	put_opt6_short(DHCP6SUCCESS);
+	put_opt6_string(_("release received"));
+	end_opt6(o1);
+	
+	break;
+      }
+
+    case DHCP6DECLINE:
+      {
+	/* set reply message type */
+	*outmsgtypep = DHCP6REPLY;
+	
+	log6_quiet(state, "DHCPDECLINE", NULL, NULL);
+
+	for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
+	  {
+	    void *ia_option, *ia_end;
+	    int made_ia = 0;
+	    	    
+	    for (check_ia(state, opt, &ia_end, &ia_option);
+		 ia_option;
+		 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) 
+	      {
+		struct dhcp_lease *lease;
+		struct in6_addr *addrp = opt6_ptr(ia_option, 0);
+
+		if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, addrp))
+		  {
+		    prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
+		    inet_ntop(AF_INET6, addrp, daemon->addrbuff, ADDRSTRLEN);
+		    my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"), 
+			      daemon->addrbuff, daemon->dhcp_buff3);
+		    config->flags |= CONFIG_DECLINED;
+		    config->decline_time = now;
+		  }
+		else
+		  /* make sure this host gets a different address next time. */
+		  for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
+		    context_tmp->addr_epoch++;
+		
+		if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
+					 state->iaid, opt6_ptr(ia_option, 0))))
+		  lease_prune(lease, now);
+		else
+		  {
+		    if (!made_ia)
+		      {
+			o = new_opt6(state->ia_type);
+			put_opt6_long(state->iaid);
+			if (state->ia_type == OPTION6_IA_NA)
+			  {
+			    put_opt6_long(0);
+			    put_opt6_long(0); 
+			  }
+			made_ia = 1;
+		      }
+		    
+		    o1 = new_opt6(OPTION6_IAADDR);
+		    put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
+		    put_opt6_long(0);
+		    put_opt6_long(0);
+		    end_opt6(o1);
+		  }
+	      }
+	    
+	    if (made_ia)
+	      {
+		o1 = new_opt6(OPTION6_STATUS_CODE);
+		put_opt6_short(DHCP6NOBINDING);
+		put_opt6_string(_("no binding found"));
+		end_opt6(o1);
+		
+		end_opt6(o);
+	      }
+	    
+	  }
+
+	/* We must answer with 'success' in global section anyway */
+	o1 = new_opt6(OPTION6_STATUS_CODE);
+	put_opt6_short(DHCP6SUCCESS);
+	put_opt6_string(_("success"));
+	end_opt6(o1);
+	break;
+      }
+
+    }
+  
+  log_tags(tagif, state->xid);
+  log6_opts(0, state->xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1));
+  
+  return 1;
+
+}
+
+static struct dhcp_netid *add_options(struct state *state, int do_refresh)  
+{
+  void *oro;
+  /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
+  struct dhcp_netid *tagif = option_filter(state->tags, state->context_tags, daemon->dhcp_opts6);
+  struct dhcp_opt *opt_cfg;
+  int done_dns = 0, done_refresh = !do_refresh, do_encap = 0;
+  int i, o, o1;
+
+  oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0);
+  
+  for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
+    {
+      /* netids match and not encapsulated? */
+      if (!(opt_cfg->flags & DHOPT_TAGOK))
+	continue;
+      
+      if (!(opt_cfg->flags & DHOPT_FORCE) && oro)
+	{
+	  for (i = 0; i <  opt6_len(oro) - 1; i += 2)
+	    if (opt6_uint(oro, i, 2) == (unsigned)opt_cfg->opt)
+	      break;
+	  
+	  /* option not requested */
+	  if (i >=  opt6_len(oro) - 1)
+	    continue;
+	}
+      
+      if (opt_cfg->opt == OPTION6_REFRESH_TIME)
+	done_refresh = 1;
+       
+      if (opt_cfg->opt == OPTION6_DNS_SERVER)
+	done_dns = 1;
+      
+      if (opt_cfg->flags & DHOPT_ADDR6)
+	{
+	  int len, j;
+	  struct in6_addr *a;
+	  
+	  for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, j = 0; 
+	       j < opt_cfg->len; j += IN6ADDRSZ, a++)
+	    if ((IN6_IS_ADDR_ULA_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) ||
+		(IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ll_addr)))
+	      len -= IN6ADDRSZ;
+	  
+	  if (len != 0)
+	    {
+	      
+	      o = new_opt6(opt_cfg->opt);
+	      	  
+	      for (a = (struct in6_addr *)opt_cfg->val, j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)
+		{
+		  if (IN6_IS_ADDR_UNSPECIFIED(a))
+		    {
+		      if (!add_local_addrs(state->context))
+			put_opt6(state->fallback, IN6ADDRSZ);
+		    }
+		  else if (IN6_IS_ADDR_ULA_ZERO(a))
+		    {
+		      if (!IN6_IS_ADDR_UNSPECIFIED(state->ula_addr))
+			put_opt6(state->ula_addr, IN6ADDRSZ);
+		    }
+		  else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
+		    {
+		      if (!IN6_IS_ADDR_UNSPECIFIED(state->ll_addr))
+			put_opt6(state->ll_addr, IN6ADDRSZ);
+		    }
+		  else
+		    put_opt6(a, IN6ADDRSZ);
+		}
+
+	      end_opt6(o);
+	    }
+	}
+      else
+	{
+	  o = new_opt6(opt_cfg->opt);
+	  if (opt_cfg->val)
+	    put_opt6(opt_cfg->val, opt_cfg->len);
+	  end_opt6(o);
+	}
+    }
+  
+  if (daemon->port == NAMESERVER_PORT && !done_dns)
+    {
+      o = new_opt6(OPTION6_DNS_SERVER);
+      if (!add_local_addrs(state->context))
+	put_opt6(state->fallback, IN6ADDRSZ);
+      end_opt6(o); 
+    }
+
+  if (state->context && !done_refresh)
+    {
+      struct dhcp_context *c;
+      unsigned int lease_time = 0xffffffff;
+      
+      /* Find the smallest lease tie of all contexts,
+	 subject to the RFC-4242 stipulation that this must not 
+	 be less than 600. */
+      for (c = state->context; c; c = c->next)
+	if (c->lease_time < lease_time)
+	  {
+	    if (c->lease_time < 600)
+	      lease_time = 600;
+	    else
+	      lease_time = c->lease_time;
+	  }
+
+      o = new_opt6(OPTION6_REFRESH_TIME);
+      put_opt6_long(lease_time);
+      end_opt6(o); 
+    }
+   
+    /* handle vendor-identifying vendor-encapsulated options,
+       dhcp-option = vi-encap:13,17,....... */
+  for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
+    opt_cfg->flags &= ~DHOPT_ENCAP_DONE;
+    
+  if (oro)
+    for (i = 0; i <  opt6_len(oro) - 1; i += 2)
+      if (opt6_uint(oro, i, 2) == OPTION6_VENDOR_OPTS)
+	do_encap = 1;
+  
+  for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
+    { 
+      if (opt_cfg->flags & DHOPT_RFC3925)
+	{
+	  int found = 0;
+	  struct dhcp_opt *oc;
+	  
+	  if (opt_cfg->flags & DHOPT_ENCAP_DONE)
+	    continue;
+	  
+	  for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
+	    {
+	      oc->flags &= ~DHOPT_ENCAP_MATCH;
+	      
+	      if (!(oc->flags & DHOPT_RFC3925) || opt_cfg->u.encap != oc->u.encap)
+		continue;
+	      
+	      oc->flags |= DHOPT_ENCAP_DONE;
+	      if (match_netid(oc->netid, tagif, 1))
+		{
+		  /* option requested/forced? */
+		  if (!oro || do_encap || (oc->flags & DHOPT_FORCE))
+		    {
+		      oc->flags |= DHOPT_ENCAP_MATCH;
+		      found = 1;
+		    }
+		} 
+	    }
+	  
+	  if (found)
+	    { 
+	      o = new_opt6(OPTION6_VENDOR_OPTS);	      
+	      put_opt6_long(opt_cfg->u.encap);	
+	     
+	      for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
+		if (oc->flags & DHOPT_ENCAP_MATCH)
+		  {
+		    o1 = new_opt6(oc->opt);
+		    put_opt6(oc->val, oc->len);
+		    end_opt6(o1);
+		  }
+	      end_opt6(o);
+	    }
+	}
+    }      
+
+
+  if (state->hostname)
+    {
+      unsigned char *p;
+      size_t len = strlen(state->hostname);
+      
+      if (state->send_domain)
+	len += strlen(state->send_domain) + 2;
+
+      o = new_opt6(OPTION6_FQDN);
+      if ((p = expand(len + 2)))
+	{
+	  *(p++) = state->fqdn_flags;
+	  p = do_rfc1035_name(p, state->hostname, NULL);
+	  if (state->send_domain)
+	    {
+	      p = do_rfc1035_name(p, state->send_domain, NULL);
+	      *p = 0;
+	    }
+	}
+      end_opt6(o);
+    }
+
+
+  /* logging */
+  if (option_bool(OPT_LOG_OPTS) && oro)
+    {
+      char *q = daemon->namebuff;
+      for (i = 0; i <  opt6_len(oro) - 1; i += 2)
+	{
+	  char *s = option_string(AF_INET6, opt6_uint(oro, i, 2), NULL, 0, NULL, 0);
+	  q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
+			"%d%s%s%s", 
+			opt6_uint(oro, i, 2),
+			strlen(s) != 0 ? ":" : "",
+			s, 
+			(i > opt6_len(oro) - 3) ? "" : ", ");
+	  if ( i >  opt6_len(oro) - 3 || (q - daemon->namebuff) > 40)
+	    {
+	      q = daemon->namebuff;
+	      my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), state->xid, daemon->namebuff);
+	    }
+	}
+    } 
+
+  return tagif;
+}
+ 
+static int add_local_addrs(struct dhcp_context *context)
+{
+  int done = 0;
+  
+  for (; context; context = context->current)
+    if ((context->flags & CONTEXT_USED) && !IN6_IS_ADDR_UNSPECIFIED(&context->local6))
+      {
+	/* squash duplicates */
+	struct dhcp_context *c;
+	for (c = context->current; c; c = c->current)
+	  if ((c->flags & CONTEXT_USED) &&
+	      IN6_ARE_ADDR_EQUAL(&context->local6, &c->local6))
+	    break;
+	
+	if (!c)
+	  { 
+	    done = 1;
+	    put_opt6(&context->local6, IN6ADDRSZ);
+	  }
+      }
+
+  return done;
+}
+
+
+static void get_context_tag(struct state *state, struct dhcp_context *context)
+{
+  /* get tags from context if we've not used it before */
+  if (context->netid.next == &context->netid && context->netid.net)
+    {
+      context->netid.next = state->context_tags;
+      state->context_tags = &context->netid;
+      if (!state->hostname_auth)
+	{
+	  struct dhcp_netid_list *id_list;
+	  
+	  for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
+	    if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
+	      break;
+	  if (id_list)
+	    state->hostname = NULL;
+	}
+    }
+} 
+
+#ifdef OPTION6_PREFIX_CLASS
+static struct prefix_class *prefix_class_from_context(struct dhcp_context *context)
+{
+  struct prefix_class *p;
+  struct dhcp_netid *t;
+  
+  for (p = daemon->prefix_classes; p ; p = p->next)
+    for (t = context->filter; t; t = t->next)
+      if (strcmp(p->tag.net, t->net) == 0)
+	return p;
+  
+ return NULL;
+}
+#endif
+
+static int check_ia(struct state *state, void *opt, void **endp, void **ia_option)
+{
+  state->ia_type = opt6_type(opt);
+  *ia_option = NULL;
+
+  if (state->ia_type != OPTION6_IA_NA && state->ia_type != OPTION6_IA_TA)
+    return 0;
+  
+  if (state->ia_type == OPTION6_IA_NA && opt6_len(opt) < 12)
+    return 0;
+	    
+  if (state->ia_type == OPTION6_IA_TA && opt6_len(opt) < 4)
+    return 0;
+  
+  *endp = opt6_ptr(opt, opt6_len(opt));
+  state->iaid = opt6_uint(opt, 0, 4);
+  *ia_option = opt6_find(opt6_ptr(opt, state->ia_type == OPTION6_IA_NA ? 12 : 4), *endp, OPTION6_IAADDR, 24);
+
+  return 1;
+}
+
+
+static int build_ia(struct state *state, int *t1cntr)
+{
+  int  o = new_opt6(state->ia_type);
+ 
+  put_opt6_long(state->iaid);
+  *t1cntr = 0;
+	    
+  if (state->ia_type == OPTION6_IA_NA)
+    {
+      /* save pointer */
+      *t1cntr = save_counter(-1);
+      /* so we can fill these in later */
+      put_opt6_long(0);
+      put_opt6_long(0); 
+    }
+
+  return o;
+}
+
+static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz)
+{
+  if (t1cntr != 0)
+    {
+      /* go back an fill in fields in IA_NA option */
+      int sav = save_counter(t1cntr);
+      unsigned int t1, t2, fuzz = 0;
+
+      if (do_fuzz)
+	{
+	  fuzz = rand16();
+      
+	  while (fuzz > (min_time/16))
+	    fuzz = fuzz/2;
+	}
+      
+      t1 = (min_time == 0xffffffff) ? 0xffffffff : min_time/2 - fuzz;
+      t2 = (min_time == 0xffffffff) ? 0xffffffff : ((min_time/8)*7) - fuzz;
+      put_opt6_long(t1);
+      put_opt6_long(t2);
+      save_counter(sav);
+    }	
+}
+
+static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option, 
+			unsigned int *min_time, struct in6_addr *addr, time_t now)
+{
+  unsigned int valid_time = 0, preferred_time = 0;
+  int o = new_opt6(OPTION6_IAADDR);
+  struct dhcp_lease *lease;
+
+  /* get client requested times */
+  if (ia_option)
+    {
+      preferred_time =  opt6_uint(ia_option, 16, 4);
+      valid_time =  opt6_uint(ia_option, 20, 4);
+    }
+
+  calculate_times(context, min_time, &valid_time, &preferred_time, lease_time); 
+  
+  put_opt6(addr, sizeof(*addr));
+  put_opt6_long(preferred_time);
+  put_opt6_long(valid_time); 		    
+  
+#ifdef OPTION6_PREFIX_CLASS
+  if (state->send_prefix_class)
+    {
+      int o1 = new_opt6(OPTION6_PREFIX_CLASS);
+      put_opt6_short(state->send_prefix_class->class);
+      end_opt6(o1);
+    }
+#endif
+
+  end_opt6(o);
+  
+  if (state->lease_allocate)
+    update_leases(state, context, addr, valid_time, now);
+
+  if ((lease = lease6_find_by_addr(addr, 128, 0)))
+    lease->flags |= LEASE_USED;
+
+  /* get tags from context if we've not used it before */
+  if (context->netid.next == &context->netid && context->netid.net)
+    {
+      context->netid.next = state->context_tags;
+      state->context_tags = &context->netid;
+      
+      if (!state->hostname_auth)
+	{
+	  struct dhcp_netid_list *id_list;
+	  
+	  for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
+	    if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
+	      break;
+	  if (id_list)
+	    state->hostname = NULL;
+	}
+    }
+
+  log6_quiet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", addr, state->hostname);
+
+}
+
+static void mark_context_used(struct state *state, struct in6_addr *addr)
+{
+  struct dhcp_context *context;
+
+  /* Mark that we have an address for this prefix. */
+#ifdef OPTION6_PREFIX_CLASS
+  for (context = state->context; context; context = context->current)
+    if (is_same_net6(addr, &context->start6, context->prefix) &&
+	(!state->send_prefix_class || state->send_prefix_class == prefix_class_from_context(context)))
+      context->flags |= CONTEXT_USED;
+#else
+  for (context = state->context; context; context = context->current)
+    if (is_same_net6(addr, &context->start6, context->prefix))
+      context->flags |= CONTEXT_USED;
+#endif
+}
+
+static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr)
+{
+  for (; context; context = context->current)
+    if (is_same_net6(addr, &context->start6, context->prefix))
+      context->flags |= CONTEXT_CONF_USED;
+}
+
+/* make sure address not leased to another CLID/IAID */
+static int check_address(struct state *state, struct in6_addr *addr)
+{ 
+  struct dhcp_lease *lease;
+
+  if (!(lease = lease6_find_by_addr(addr, 128, 0)))
+    return 1;
+
+  if (lease->clid_len != state->clid_len || 
+      memcmp(lease->clid, state->clid, state->clid_len) != 0 ||
+      lease->iaid != state->iaid)
+    return 0;
+
+  return 1;
+}
+
+
+/* Calculate valid and preferred times to send in leases/renewals. 
+
+   Inputs are:
+
+   *valid_timep, *preferred_timep - requested times from IAADDR options.
+   context->valid, context->preferred - times associated with subnet address on local interface.
+   context->flags | CONTEXT_DEPRECATE - "deprecated" flag in dhcp-range.
+   lease_time - configured time for context for individual client.
+   *min_time - smallest valid time sent so far.
+
+   Outputs are :
+   
+   *valid_timep, *preferred_timep - times to be send in IAADDR option.
+   *min_time - smallest valid time sent so far, to calculate T1 and T2.
+   
+   */
+static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep, 
+			    unsigned int *preferred_timep, unsigned int lease_time)
+{
+  unsigned int req_preferred = *preferred_timep, req_valid = *valid_timep;
+  unsigned int valid_time = lease_time, preferred_time = lease_time;
+  
+  /* RFC 3315: "A server ignores the lifetimes set
+     by the client if the preferred lifetime is greater than the valid
+     lifetime. */
+  if (req_preferred <= req_valid)
+    {
+      if (req_preferred != 0)
+	{
+	  /* 0 == "no preference from client" */
+	  if (req_preferred < 120u)
+	    req_preferred = 120u; /* sanity */
+	  
+	  if (req_preferred < preferred_time)
+	    preferred_time = req_preferred;
+	}
+      
+      if (req_valid != 0)
+	/* 0 == "no preference from client" */
+	{
+	  if (req_valid < 120u)
+	    req_valid = 120u; /* sanity */
+	  
+	  if (req_valid < valid_time)
+	    valid_time = req_valid;
+	}
+    }
+
+  /* deprecate (preferred == 0) which configured, or when local address 
+     is deprecated */
+  if ((context->flags & CONTEXT_DEPRECATE) || context->preferred == 0)
+    preferred_time = 0;
+  
+  if (preferred_time != 0 && preferred_time < *min_time)
+    *min_time = preferred_time;
+  
+  if (valid_time != 0 && valid_time < *min_time)
+    *min_time = valid_time;
+  
+  *valid_timep = valid_time;
+  *preferred_timep = preferred_time;
+}
+
+static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now)
+{
+  struct dhcp_lease *lease = lease6_find_by_addr(addr, 128, 0);
+#ifdef HAVE_SCRIPT
+  struct dhcp_netid *tagif = run_tag_if(state->tags);
+#endif
+
+  (void)context;
+
+  if (!lease)
+    lease = lease6_allocate(addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA);
+  
+  if (lease)
+    {
+      lease_set_expires(lease, lease_time, now);
+      lease_set_iaid(lease, state->iaid); 
+      lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);
+      lease_set_interface(lease, state->interface, now);
+      if (state->hostname && state->ia_type == OPTION6_IA_NA)
+	{
+	  char *addr_domain = get_domain6(addr);
+	  if (!state->send_domain)
+	    state->send_domain = addr_domain;
+	  lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
+	}
+      
+#ifdef HAVE_SCRIPT
+      if (daemon->lease_change_command)
+	{
+	  void *class_opt;
+	  lease->flags |= LEASE_CHANGED;
+	  free(lease->extradata);
+	  lease->extradata = NULL;
+	  lease->extradata_size = lease->extradata_len = 0;
+	  lease->vendorclass_count = 0; 
+	  
+	  if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
+	    {
+	      void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
+	      lease->vendorclass_count++;
+	      /* send enterprise number first  */
+	      sprintf(daemon->dhcp_buff2, "%u", opt6_uint(class_opt, 0, 4));
+	      lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0);
+	      
+	      if (opt6_len(class_opt) >= 6) 
+		for (enc_opt = opt6_ptr(class_opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
+		  {
+		    lease->vendorclass_count++;
+		    lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
+		  }
+	    }
+	  
+	  lease_add_extradata(lease, (unsigned char *)state->client_hostname, 
+			      state->client_hostname ? strlen(state->client_hostname) : 0, 0);				
+	  
+	  /* space-concat tag set */
+	  if (!tagif && !context->netid.net)
+	    lease_add_extradata(lease, NULL, 0, 0);
+	  else
+	    {
+	      if (context->netid.net)
+		lease_add_extradata(lease, (unsigned char *)context->netid.net, strlen(context->netid.net), tagif ? ' ' : 0);
+	      
+	      if (tagif)
+		{
+		  struct dhcp_netid *n;
+		  for (n = tagif; n; n = n->next)
+		    {
+		      struct dhcp_netid *n1;
+		      /* kill dupes */
+		      for (n1 = n->next; n1; n1 = n1->next)
+			if (strcmp(n->net, n1->net) == 0)
+			  break;
+		      if (!n1)
+			lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0); 
+		    }
+		}
+	    }
+	  
+	  if (state->link_address)
+	    inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN);
+	  
+	  lease_add_extradata(lease, (unsigned char *)daemon->addrbuff, state->link_address ? strlen(daemon->addrbuff) : 0, 0);
+	  
+	  if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_USER_CLASS, 2)))
+	    {
+	      void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
+	      for (enc_opt = opt6_ptr(class_opt, 0); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
+		lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
+	    }
+	}
+#endif	
+      
+    }
+}
+			  
+			
+	
+static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts)
+{
+  void *opt;
+  char *desc = nest ? "nest" : "sent";
+  
+  if (!option_bool(OPT_LOG_OPTS) || start_opts == end_opts)
+    return;
+  
+  for (opt = start_opts; opt; opt = opt6_next(opt, end_opts))
+    {
+      int type = opt6_type(opt);
+      void *ia_options = NULL;
+      char *optname;
+      
+      if (type == OPTION6_IA_NA)
+	{
+	  sprintf(daemon->namebuff, "IAID=%u T1=%u T2=%u",
+		  opt6_uint(opt, 0, 4), opt6_uint(opt, 4, 4), opt6_uint(opt, 8, 4));
+	  optname = "ia-na";
+	  ia_options = opt6_ptr(opt, 12);
+	}
+      else if (type == OPTION6_IA_TA)
+	{
+	  sprintf(daemon->namebuff, "IAID=%u", opt6_uint(opt, 0, 4));
+	  optname = "ia-ta";
+	  ia_options = opt6_ptr(opt, 4);
+	}
+      else if (type == OPTION6_IAADDR)
+	{
+	  inet_ntop(AF_INET6, opt6_ptr(opt, 0), daemon->addrbuff, ADDRSTRLEN);
+	  sprintf(daemon->namebuff, "%s PL=%u VL=%u", 
+		  daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));
+	  optname = "iaaddr";
+	  ia_options = opt6_ptr(opt, 24);
+	}
+#ifdef OPTION6_PREFIX_CLASS
+      else if (type == OPTION6_PREFIX_CLASS)
+	{
+	  optname = "prefix-class";
+	  sprintf(daemon->namebuff, "class=%u", opt6_uint(opt, 0, 2));
+	}
+#endif
+      else if (type == OPTION6_STATUS_CODE)
+	{
+	  int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2));
+	  memcpy(daemon->namebuff + len, opt6_ptr(opt, 2), opt6_len(opt)-2);
+	  daemon->namebuff[len + opt6_len(opt) - 2] = 0;
+	  optname = "status";
+	}
+      else
+	{
+	  /* account for flag byte on FQDN */
+	  int offset = type == OPTION6_FQDN ? 1 : 0;
+	  optname = option_string(AF_INET6, type, opt6_ptr(opt, offset), opt6_len(opt) - offset, daemon->namebuff, MAXDNAME);
+	}
+      
+      my_syslog(MS_DHCP | LOG_INFO, "%u %s size:%3d option:%3d %s  %s", 
+		xid, desc, opt6_len(opt), type, optname, daemon->namebuff);
+      
+      if (ia_options)
+	log6_opts(1, xid, ia_options, opt6_ptr(opt, opt6_len(opt)));
+    }
+}		 
+ 
+static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string)
+{
+  if (option_bool(OPT_LOG_OPTS) || !option_bool(OPT_QUIET_DHCP6))
+    log6_packet(state, type, addr, string);
+}
+
+static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string)
+{
+  int clid_len = state->clid_len;
+
+  /* avoid buffer overflow */
+  if (clid_len > 100)
+    clid_len = 100;
+  
+  print_mac(daemon->namebuff, state->clid, clid_len);
+
+  if (addr)
+    {
+      inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, DHCP_BUFF_SZ - 1);
+      strcat(daemon->dhcp_buff2, " ");
+    }
+  else
+    daemon->dhcp_buff2[0] = 0;
+
+  if(option_bool(OPT_LOG_OPTS))
+    my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s %s",
+	      state->xid, 
+	      type,
+	      state->iface_name, 
+	      daemon->dhcp_buff2,
+	      daemon->namebuff,
+	      string ? string : "");
+  else
+    my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s %s",
+	      type,
+	      state->iface_name, 
+	      daemon->dhcp_buff2,
+	      daemon->namebuff,
+	      string ? string : "");
+}
+
+static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize)
+{
+  u16 opt, opt_len;
+  void *start;
+  
+  if (!opts)
+    return NULL;
+    
+  while (1)
+    {
+      if (end - opts < 4) 
+	return NULL;
+      
+      start = opts;
+      GETSHORT(opt, opts);
+      GETSHORT(opt_len, opts);
+      
+      if (opt_len > (end - opts))
+	return NULL;
+      
+      if (opt == search && (opt_len >= minsize))
+	return start;
+      
+      opts += opt_len;
+    }
+}
+
+static void *opt6_next(void *opts, void *end)
+{
+  u16 opt_len;
+  
+  if (end - opts < 4) 
+    return NULL;
+  
+  opts += 2;
+  GETSHORT(opt_len, opts);
+  
+  if (opt_len >= (end - opts))
+    return NULL;
+  
+  return opts + opt_len;
+}
+
+static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
+{
+  /* this worries about unaligned data and byte order */
+  unsigned int ret = 0;
+  int i;
+  unsigned char *p = opt6_ptr(opt, offset);
+  
+  for (i = 0; i < size; i++)
+    ret = (ret << 8) | *p++;
+  
+  return ret;
+} 
+
+void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, 
+		     struct in6_addr *peer_address, u32 scope_id, time_t now)
+{
+  /* ->local is same value for all relays on ->current chain */
+  
+  struct all_addr from;
+  unsigned char *header;
+  unsigned char *inbuff = daemon->dhcp_packet.iov_base;
+  int msg_type = *inbuff;
+  int hopcount;
+  struct in6_addr multicast;
+  unsigned int maclen, mactype;
+  unsigned char mac[DHCP_CHADDR_MAX];
+
+  inet_pton(AF_INET6, ALL_SERVERS, &multicast);
+  get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now);
+
+  /* source address == relay address */
+  from.addr.addr6 = relay->local.addr.addr6;
+    
+  /* Get hop count from nested relayed message */ 
+  if (msg_type == DHCP6RELAYFORW)
+    hopcount = *((unsigned char *)inbuff+1) + 1;
+  else
+    hopcount = 0;
+
+  /* RFC 3315 HOP_COUNT_LIMIT */
+  if (hopcount > 32)
+    return;
+
+  reset_counter();
+
+  if ((header = put_opt6(NULL, 34)))
+    {
+      int o;
+
+      header[0] = DHCP6RELAYFORW;
+      header[1] = hopcount;
+      memcpy(&header[2],  &relay->local.addr.addr6, IN6ADDRSZ);
+      memcpy(&header[18], peer_address, IN6ADDRSZ);
+ 
+      /* RFC-6939 */
+      if (maclen != 0)
+	{
+	  o = new_opt6(OPTION6_CLIENT_MAC);
+	  put_opt6_short(mactype);
+	  put_opt6(mac, maclen);
+	  end_opt6(o);
+	}
+      
+      o = new_opt6(OPTION6_RELAY_MSG);
+      put_opt6(inbuff, sz);
+      end_opt6(o);
+      
+      for (; relay; relay = relay->current)
+	{
+	  union mysockaddr to;
+	  
+	  to.sa.sa_family = AF_INET6;
+	  to.in6.sin6_addr = relay->server.addr.addr6;
+	  to.in6.sin6_port = htons(DHCPV6_SERVER_PORT);
+	  to.in6.sin6_flowinfo = 0;
+	  to.in6.sin6_scope_id = 0;
+
+	  if (IN6_ARE_ADDR_EQUAL(&relay->server.addr.addr6, &multicast))
+	    {
+	      int multicast_iface;
+	      if (!relay->interface || strchr(relay->interface, '*') ||
+		  (multicast_iface = if_nametoindex(relay->interface)) == 0 ||
+		  setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1)
+		my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface"));
+	    }
+		
+	  send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0);
+	  
+	  if (option_bool(OPT_LOG_OPTS))
+	    {
+	      inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
+	      inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
+	      my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->namebuff);
+	    }
+
+	  /* Save this for replies */
+	  relay->iface_index = scope_id;
+	}
+    }
+}
+
+unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
+{
+  struct dhcp_relay *relay;
+  struct in6_addr link;
+  unsigned char *inbuff = daemon->dhcp_packet.iov_base;
+  
+  /* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
+     which is               1   +    1   +    16      +     16     + 2 + 2 = 38 */
+  
+  if (sz < 38 || *inbuff != DHCP6RELAYREPL)
+    return 0;
+  
+  memcpy(&link, &inbuff[2], IN6ADDRSZ); 
+  
+  for (relay = daemon->relay6; relay; relay = relay->next)
+    if (IN6_ARE_ADDR_EQUAL(&link, &relay->local.addr.addr6) &&
+	(!relay->interface || wildcard_match(relay->interface, arrival_interface)))
+      break;
+      
+  reset_counter();
+
+  if (relay)
+    {
+      void *opt, *opts = inbuff + 34;
+      void *end = inbuff + sz;
+      for (opt = opts; opt; opt = opt6_next(opt, end))
+	if (opt6_type(opt) == OPTION6_RELAY_MSG && opt6_len(opt) > 0)
+	  {
+	    int encap_type = *((unsigned char *)opt6_ptr(opt, 0));
+	    put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
+	    memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ); 
+	    peer->sin6_scope_id = relay->iface_index;
+	    return encap_type == DHCP6RELAYREPL ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
+	  }
+    }
+
+  return 0;
+}
+
+#endif
diff --git a/src/rrfilter.c b/src/rrfilter.c
new file mode 100644
index 0000000..36ff347
--- /dev/null
+++ b/src/rrfilter.c
@@ -0,0 +1,339 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Code to safely remove RRs from an DNS answer */ 
+
+#include "dnsmasq.h"
+
+/* Go through a domain name, find "pointers" and fix them up based on how many bytes
+   we've chopped out of the packet, or check they don't point into an elided part.  */
+static int check_name(unsigned char **namep, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
+{
+  unsigned char *ansp = *namep;
+
+  while(1)
+    {
+      unsigned int label_type;
+      
+      if (!CHECK_LEN(header, ansp, plen, 1))
+	return 0;
+      
+      label_type = (*ansp) & 0xc0;
+
+      if (label_type == 0xc0)
+	{
+	  /* pointer for compression. */
+	  unsigned int offset;
+	  int i;
+	  unsigned char *p;
+	  
+	  if (!CHECK_LEN(header, ansp, plen, 2))
+	    return 0;
+
+	  offset = ((*ansp++) & 0x3f) << 8;
+	  offset |= *ansp++;
+
+	  p = offset + (unsigned char *)header;
+	  
+	  for (i = 0; i < rr_count; i++)
+	    if (p < rrs[i])
+	      break;
+	    else
+	      if (i & 1)
+		offset -= rrs[i] - rrs[i-1];
+
+	  /* does the pointer end up in an elided RR? */
+	  if (i & 1)
+	    return 0;
+
+	  /* No, scale the pointer */
+	  if (fixup)
+	    {
+	      ansp -= 2;
+	      *ansp++ = (offset >> 8) | 0xc0;
+	      *ansp++ = offset & 0xff;
+	    }
+	  break;
+	}
+      else if (label_type == 0x80)
+	return 0; /* reserved */
+      else if (label_type == 0x40)
+	{
+	  /* Extended label type */
+	  unsigned int count;
+	  
+	  if (!CHECK_LEN(header, ansp, plen, 2))
+	    return 0;
+	  
+	  if (((*ansp++) & 0x3f) != 1)
+	    return 0; /* we only understand bitstrings */
+	  
+	  count = *(ansp++); /* Bits in bitstring */
+	  
+	  if (count == 0) /* count == 0 means 256 bits */
+	    ansp += 32;
+	  else
+	    ansp += ((count-1)>>3)+1;
+	}
+      else
+	{ /* label type == 0 Bottom six bits is length */
+	  unsigned int len = (*ansp++) & 0x3f;
+	  
+	  if (!ADD_RDLEN(header, ansp, plen, len))
+	    return 0;
+
+	  if (len == 0)
+	    break; /* zero length label marks the end. */
+	}
+    }
+
+  *namep = ansp;
+
+  return 1;
+}
+
+/* Go through RRs and check or fixup the domain names contained within */
+static int check_rrs(unsigned char *p, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
+{
+  int i, j, type, class, rdlen;
+  unsigned char *pp;
+  
+  for (i = 0; i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount); i++)
+    {
+      pp = p;
+
+      if (!(p = skip_name(p, header, plen, 10)))
+	return 0;
+      
+      GETSHORT(type, p); 
+      GETSHORT(class, p);
+      p += 4; /* TTL */
+      GETSHORT(rdlen, p);
+
+      /* If this RR is to be elided, don't fix up its contents */
+      for (j = 0; j < rr_count; j += 2)
+	if (rrs[j] == pp)
+	  break;
+
+      if (j >= rr_count)
+	{
+	  /* fixup name of RR */
+	  if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
+	    return 0;
+	  
+	  if (class == C_IN)
+	    {
+	      u16 *d;
+ 
+	      for (pp = p, d = rrfilter_desc(type); *d != (u16)-1; d++)
+		{
+		  if (*d != 0)
+		    pp += *d;
+		  else if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
+		    return 0;
+		}
+	    }
+	}
+      
+      if (!ADD_RDLEN(header, p, plen, rdlen))
+	return 0;
+    }
+  
+  return 1;
+}
+	
+
+/* mode is 0 to remove EDNS0, 1 to filter DNSSEC RRs */
+size_t rrfilter(struct dns_header *header, size_t plen, int mode)
+{
+  static unsigned char **rrs;
+  static int rr_sz = 0;
+
+  unsigned char *p = (unsigned char *)(header+1);
+  int i, rdlen, qtype, qclass, rr_found, chop_an, chop_ns, chop_ar;
+
+  if (ntohs(header->qdcount) != 1 ||
+      !(p = skip_name(p, header, plen, 4)))
+    return plen;
+  
+  GETSHORT(qtype, p);
+  GETSHORT(qclass, p);
+
+  /* First pass, find pointers to start and end of all the records we wish to elide:
+     records added for DNSSEC, unless explicitly queried for */
+  for (rr_found = 0, chop_ns = 0, chop_an = 0, chop_ar = 0, i = 0; 
+       i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount);
+       i++)
+    {
+      unsigned char *pstart = p;
+      int type, class;
+
+      if (!(p = skip_name(p, header, plen, 10)))
+	return plen;
+      
+      GETSHORT(type, p); 
+      GETSHORT(class, p);
+      p += 4; /* TTL */
+      GETSHORT(rdlen, p);
+        
+      if (!ADD_RDLEN(header, p, plen, rdlen))
+	return plen;
+
+      /* Don't remove the answer. */
+      if (i < ntohs(header->ancount) && type == qtype && class == qclass)
+	continue;
+      
+      if (mode == 0) /* EDNS */
+	{
+	  /* EDNS mode, remove T_OPT from additional section only */
+	  if (i < (ntohs(header->nscount) + ntohs(header->ancount)) || type != T_OPT)
+	    continue;
+	}
+      else if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG)
+	/* DNSSEC mode, remove SIGs and NSECs from all three sections. */
+	continue;
+      
+      
+      if (!expand_workspace(&rrs, &rr_sz, rr_found + 1))
+	return plen; 
+      
+      rrs[rr_found++] = pstart;
+      rrs[rr_found++] = p;
+      
+      if (i < ntohs(header->ancount))
+	chop_an++;
+      else if (i < (ntohs(header->nscount) + ntohs(header->ancount)))
+	chop_ns++;
+      else
+	chop_ar++;
+    }
+  
+  /* Nothing to do. */
+  if (rr_found == 0)
+    return plen;
+
+  /* Second pass, look for pointers in names in the records we're keeping and make sure they don't
+     point to records we're going to elide. This is theoretically possible, but unlikely. If
+     it happens, we give up and leave the answer unchanged. */
+  p = (unsigned char *)(header+1);
+  
+  /* question first */
+  if (!check_name(&p, header, plen, 0, rrs, rr_found))
+    return plen;
+  p += 4; /* qclass, qtype */
+  
+  /* Now answers and NS */
+  if (!check_rrs(p, header, plen, 0, rrs, rr_found))
+    return plen;
+  
+  /* Third pass, actually fix up pointers in the records */
+  p = (unsigned char *)(header+1);
+  
+  check_name(&p, header, plen, 1, rrs, rr_found);
+  p += 4; /* qclass, qtype */
+  
+  check_rrs(p, header, plen, 1, rrs, rr_found);
+
+  /*  Fouth pass, elide records */
+  for (p = rrs[0], i = 1; i < rr_found; i += 2)
+    {
+      unsigned char *start = rrs[i];
+      unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)header) + plen;
+      
+      memmove(p, start, end-start);
+      p += end-start;
+    }
+     
+  plen = p - (unsigned char *)header;
+  header->ancount = htons(ntohs(header->ancount) - chop_an);
+  header->nscount = htons(ntohs(header->nscount) - chop_ns);
+  header->arcount = htons(ntohs(header->arcount) - chop_ar);
+
+  return plen;
+}
+
+/* This is used in the DNSSEC code too, hence it's exported */
+u16 *rrfilter_desc(int type)
+{
+  /* List of RRtypes which include domains in the data.
+     0 -> domain
+     integer -> no of plain bytes
+     -1 -> end
+
+     zero is not a valid RRtype, so the final entry is returned for
+     anything which needs no mangling.
+  */
+  
+  static u16 rr_desc[] = 
+    { 
+      T_NS, 0, -1, 
+      T_MD, 0, -1,
+      T_MF, 0, -1,
+      T_CNAME, 0, -1,
+      T_SOA, 0, 0, -1,
+      T_MB, 0, -1,
+      T_MG, 0, -1,
+      T_MR, 0, -1,
+      T_PTR, 0, -1,
+      T_MINFO, 0, 0, -1,
+      T_MX, 2, 0, -1,
+      T_RP, 0, 0, -1,
+      T_AFSDB, 2, 0, -1,
+      T_RT, 2, 0, -1,
+      T_SIG, 18, 0, -1,
+      T_PX, 2, 0, 0, -1,
+      T_NXT, 0, -1,
+      T_KX, 2, 0, -1,
+      T_SRV, 6, 0, -1,
+      T_DNAME, 0, -1,
+      0, -1 /* wildcard/catchall */
+    }; 
+  
+  u16 *p = rr_desc;
+  
+  while (*p != type && *p != 0)
+    while (*p++ != (u16)-1);
+
+  return p+1;
+}
+
+int expand_workspace(unsigned char ***wkspc, int *szp, int new)
+{
+  unsigned char **p;
+  int old = *szp;
+
+  if (old >= new+1)
+    return 1;
+
+  if (new >= 100)
+    return 0;
+
+  new += 5;
+  
+  if (!(p = whine_malloc(new * sizeof(unsigned char *))))
+    return 0;  
+  
+  if (old != 0 && *wkspc)
+    {
+      memcpy(p, *wkspc, old * sizeof(unsigned char *));
+      free(*wkspc);
+    }
+  
+  *wkspc = p;
+  *szp = new;
+
+  return 1;
+}
diff --git a/src/slaac.c b/src/slaac.c
new file mode 100644
index 0000000..50c58aa
--- /dev/null
+++ b/src/slaac.c
@@ -0,0 +1,212 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_DHCP6
+
+#include <netinet/icmp6.h>
+
+static int ping_id = 0;
+
+void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
+{
+  struct slaac_address *slaac, *old, **up;
+  struct dhcp_context *context;
+  int dns_dirty = 0;
+  
+  if (!(lease->flags & LEASE_HAVE_HWADDR) || 
+      (lease->flags & (LEASE_TA | LEASE_NA)) ||
+      lease->last_interface == 0 ||
+      !lease->hostname)
+    return ;
+  
+  old = lease->slaac_address;
+  lease->slaac_address = NULL;
+
+  for (context = daemon->dhcp6; context; context = context->next) 
+    if ((context->flags & CONTEXT_RA_NAME) && 
+	!(context->flags & CONTEXT_OLD) &&
+	lease->last_interface == context->if_index)
+      {
+	struct in6_addr addr = context->start6;
+	if (lease->hwaddr_len == 6 &&
+	    (lease->hwaddr_type == ARPHRD_ETHER || lease->hwaddr_type == ARPHRD_IEEE802))
+	  {
+	    /* convert MAC address to EUI-64 */
+	    memcpy(&addr.s6_addr[8], lease->hwaddr, 3);
+	    memcpy(&addr.s6_addr[13], &lease->hwaddr[3], 3);
+	    addr.s6_addr[11] = 0xff;
+	    addr.s6_addr[12] = 0xfe;
+	  }
+#if defined(ARPHRD_EUI64)
+	else if (lease->hwaddr_len == 8 &&
+		 lease->hwaddr_type == ARPHRD_EUI64)
+	  memcpy(&addr.s6_addr[8], lease->hwaddr, 8);
+#endif
+#if defined(ARPHRD_IEEE1394) && defined(ARPHRD_EUI64)
+	else if (lease->clid_len == 9 && 
+		 lease->clid[0] ==  ARPHRD_EUI64 &&
+		 lease->hwaddr_type == ARPHRD_IEEE1394)
+	  /* firewire has EUI-64 identifier as clid */
+	  memcpy(&addr.s6_addr[8], &lease->clid[1], 8);
+#endif
+	else
+	  continue;
+	
+	addr.s6_addr[8] ^= 0x02;
+	
+	/* check if we already have this one */
+	for (up = &old, slaac = old; slaac; slaac = slaac->next)
+	  {
+	    if (IN6_ARE_ADDR_EQUAL(&addr, &slaac->addr))
+	      {
+		*up = slaac->next;
+		/* recheck when DHCPv4 goes through init-reboot */
+		if (force)
+		  {
+		    slaac->ping_time = now;
+		    slaac->backoff = 1;
+		    dns_dirty = 1;
+		  }
+		break;
+	      }
+	    up = &slaac->next;
+	  }
+	    
+	/* No, make new one */
+	if (!slaac && (slaac = whine_malloc(sizeof(struct slaac_address))))
+	  {
+	    slaac->ping_time = now;
+	    slaac->backoff = 1;
+	    slaac->addr = addr;
+	    /* Do RA's to prod it */
+	    ra_start_unsolicited(now, context);
+	  }
+	
+	if (slaac)
+	  {
+	    slaac->next = lease->slaac_address;
+	    lease->slaac_address = slaac;
+	  }
+      }
+  
+  if (old || dns_dirty)
+    lease_update_dns(1);
+  
+  /* Free any no reused */
+  for (; old; old = slaac)
+    {
+      slaac = old->next;
+      free(old);
+    }
+}
+
+
+time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
+{
+  struct dhcp_context *context;
+  struct dhcp_lease *lease;
+  struct slaac_address *slaac;
+  time_t next_event = 0;
+  
+  for (context = daemon->dhcp6; context; context = context->next)
+    if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
+      break;
+
+  /* nothing configured */
+  if (!context)
+    return 0;
+
+  while (ping_id == 0)
+    ping_id = rand16();
+
+  for (lease = leases; lease; lease = lease->next)
+    for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
+      {
+	/* confirmed or given up? */
+	if (slaac->backoff == 0 || slaac->ping_time == 0)
+	  continue;
+	
+	if (difftime(slaac->ping_time, now) <= 0.0)
+	  {
+	    struct ping_packet *ping;
+	    struct sockaddr_in6 addr;
+ 
+	    reset_counter();
+
+	    if (!(ping = expand(sizeof(struct ping_packet))))
+	      continue;
+
+	    ping->type = ICMP6_ECHO_REQUEST;
+	    ping->code = 0;
+	    ping->identifier = ping_id;
+	    ping->sequence_no = slaac->backoff;
+	    
+	    memset(&addr, 0, sizeof(addr));
+#ifdef HAVE_SOCKADDR_SA_LEN
+	    addr.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+	    addr.sin6_family = AF_INET6;
+	    addr.sin6_port = htons(IPPROTO_ICMPV6);
+	    addr.sin6_addr = slaac->addr;
+	    
+	    if (sendto(daemon->icmp6fd, daemon->outpacket.iov_base, save_counter(-1), 0,
+		       (struct sockaddr *)&addr,  sizeof(addr)) == -1 &&
+		errno == EHOSTUNREACH)
+	      slaac->ping_time = 0; /* Give up */ 
+	    else
+	      {
+		slaac->ping_time += (1 << (slaac->backoff - 1)) + (rand16()/21785); /* 0 - 3 */
+		if (slaac->backoff > 4)
+		  slaac->ping_time += rand16()/4000; /* 0 - 15 */
+		if (slaac->backoff < 12)
+		  slaac->backoff++;
+	      }
+	  }
+	
+	if (slaac->ping_time != 0 &&
+	    (next_event == 0 || difftime(next_event, slaac->ping_time) >= 0.0))
+	  next_event = slaac->ping_time;
+      }
+
+  return next_event;
+}
+
+
+void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface, struct dhcp_lease *leases)
+{
+  struct dhcp_lease *lease;
+  struct slaac_address *slaac;
+  struct ping_packet *ping = (struct ping_packet *)packet;
+  int gotone = 0;
+  
+  if (ping->identifier == ping_id)
+    for (lease = leases; lease; lease = lease->next)
+      for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
+	if (slaac->backoff != 0 && IN6_ARE_ADDR_EQUAL(sender, &slaac->addr))
+	  {
+	    slaac->backoff = 0;
+	    gotone = 1;
+	    inet_ntop(AF_INET6, sender, daemon->addrbuff, ADDRSTRLEN);
+	    if (!option_bool(OPT_QUIET_DHCP6))
+	      my_syslog(MS_DHCP | LOG_INFO, "SLAAC-CONFIRM(%s) %s %s", interface, daemon->addrbuff, lease->hostname); 
+	  }
+  
+  lease_update_dns(gotone);
+}
+	
+#endif
diff --git a/src/tables.c b/src/tables.c
new file mode 100644
index 0000000..a3382ce
--- /dev/null
+++ b/src/tables.c
@@ -0,0 +1,145 @@
+/* tables.c is Copyright (c) 2014 Sven Falempin  All Rights Reserved.
+
+   Author's email: sfalempin@citypassenger.com 
+
+   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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#if defined(HAVE_IPSET) && defined(HAVE_BSD_NETWORK)
+
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <net/pfvar.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#define UNUSED(x) (void)(x)
+
+static char *pf_device = "/dev/pf";
+static int dev = -1;
+
+static char *pfr_strerror(int errnum)
+{
+  switch (errnum) 
+    {
+    case ESRCH:
+      return "Table does not exist";
+    case ENOENT:
+      return "Anchor or Ruleset does not exist";
+    default:
+      return strerror(errnum);
+    }
+}
+
+
+void ipset_init(void) 
+{
+  dev = open( pf_device, O_RDWR);
+  if (dev == -1)
+    {
+      err(1, "%s", pf_device);
+      die (_("failed to access pf devices: %s"), NULL, EC_MISC);
+    }
+}
+
+int add_to_ipset(const char *setname, const struct all_addr *ipaddr,
+		 int flags, int remove)
+{
+  struct pfr_addr addr;
+  struct pfioc_table io;
+  struct pfr_table table;
+
+  if (dev == -1) 
+    {
+      my_syslog(LOG_ERR, _("warning: no opened pf devices %s"), pf_device);
+      return -1;
+    }
+
+  bzero(&table, sizeof(struct pfr_table));
+  table.pfrt_flags |= PFR_TFLAG_PERSIST;
+  if (strlen(setname) >= PF_TABLE_NAME_SIZE)
+    {
+      my_syslog(LOG_ERR, _("error: cannot use table name %s"), setname);
+      errno = ENAMETOOLONG;
+      return -1;
+    }
+  
+  if (strlcpy(table.pfrt_name, setname,
+	      sizeof(table.pfrt_name)) >= sizeof(table.pfrt_name)) 
+    {
+      my_syslog(LOG_ERR, _("error: cannot strlcpy table name %s"), setname);
+      return -1;
+    }
+  
+  bzero(&io, sizeof io);
+  io.pfrio_flags = 0;
+  io.pfrio_buffer = &table;
+  io.pfrio_esize = sizeof(table);
+  io.pfrio_size = 1;
+  if (ioctl(dev, DIOCRADDTABLES, &io))
+    {
+      my_syslog(LOG_WARNING, _("IPset: error:%s"), pfr_strerror(errno));
+      
+      return -1;
+    }
+  
+  table.pfrt_flags &= ~PFR_TFLAG_PERSIST;
+  if (io.pfrio_nadd)
+    my_syslog(LOG_INFO, _("info: table created"));
+ 
+  bzero(&addr, sizeof(addr));
+#ifdef HAVE_IPV6
+  if (flags & F_IPV6) 
+    {
+      addr.pfra_af = AF_INET6;
+      addr.pfra_net = 0x80;
+      memcpy(&(addr.pfra_ip6addr), &(ipaddr->addr), sizeof(struct in6_addr));
+    } 
+  else 
+#endif
+    {
+      addr.pfra_af = AF_INET;
+      addr.pfra_net = 0x20;
+      addr.pfra_ip4addr.s_addr = ipaddr->addr.addr4.s_addr;
+    }
+
+  bzero(&io, sizeof(io));
+  io.pfrio_flags = 0;
+  io.pfrio_table = table;
+  io.pfrio_buffer = &addr;
+  io.pfrio_esize = sizeof(addr);
+  io.pfrio_size = 1;
+  if (ioctl(dev, ( remove ? DIOCRDELADDRS : DIOCRADDADDRS ), &io)) 
+    {
+      my_syslog(LOG_WARNING, _("warning: DIOCR%sADDRS: %s"), ( remove ? "DEL" : "ADD" ), pfr_strerror(errno));
+      return -1;
+    }
+  
+  my_syslog(LOG_INFO, _("%d addresses %s"),
+            io.pfrio_nadd, ( remove ? "removed" : "added" ));
+  
+  return io.pfrio_nadd;
+}
+
+
+#endif
diff --git a/src/tftp.c b/src/tftp.c
new file mode 100755
index 0000000..131e6de
--- /dev/null
+++ b/src/tftp.c
@@ -0,0 +1,819 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+     
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_TFTP
+
+static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix);
+static void free_transfer(struct tftp_transfer *transfer);
+static ssize_t tftp_err(int err, char *packet, char *message, char *file);
+static ssize_t tftp_err_oops(char *packet, char *file);
+static ssize_t get_block(char *packet, struct tftp_transfer *transfer);
+static char *next(char **p, char *end);
+static void sanitise(char *buf);
+
+#define OP_RRQ  1
+#define OP_WRQ  2
+#define OP_DATA 3
+#define OP_ACK  4
+#define OP_ERR  5
+#define OP_OACK 6
+
+#define ERR_NOTDEF 0
+#define ERR_FNF    1
+#define ERR_PERM   2
+#define ERR_FULL   3
+#define ERR_ILL    4
+
+void tftp_request(struct listener *listen, time_t now)
+{
+  ssize_t len;
+  char *packet = daemon->packet;
+  char *filename, *mode, *p, *end, *opt;
+  union mysockaddr addr, peer;
+  struct msghdr msg;
+  struct iovec iov;
+  struct ifreq ifr;
+  int is_err = 1, if_index = 0, mtu = 0;
+  struct iname *tmp;
+  struct tftp_transfer *transfer;
+  int port = daemon->start_tftp_port; /* may be zero to use ephemeral port */
+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
+  int mtuflag = IP_PMTUDISC_DONT;
+#endif
+  char namebuff[IF_NAMESIZE];
+  char *name = NULL;
+  char *prefix = daemon->tftp_prefix;
+  struct tftp_prefix *pref;
+  struct all_addr addra;
+#ifdef HAVE_IPV6
+  /* Can always get recvd interface for IPv6 */
+  int check_dest = !option_bool(OPT_NOWILD) || listen->family == AF_INET6;
+#else
+  int check_dest = !option_bool(OPT_NOWILD);
+#endif
+  union {
+    struct cmsghdr align; /* this ensures alignment */
+#ifdef HAVE_IPV6
+    char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+#endif
+#if defined(HAVE_LINUX_NETWORK)
+    char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
+#elif defined(HAVE_SOLARIS_NETWORK)
+    char control[CMSG_SPACE(sizeof(unsigned int))];
+#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
+    char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
+#endif
+  } control_u; 
+
+  msg.msg_controllen = sizeof(control_u);
+  msg.msg_control = control_u.control;
+  msg.msg_flags = 0;
+  msg.msg_name = &peer;
+  msg.msg_namelen = sizeof(peer);
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+
+  iov.iov_base = packet;
+  iov.iov_len = daemon->packet_buff_sz;
+
+  /* we overwrote the buffer... */
+  daemon->srv_save = NULL;
+
+  if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)
+    return;
+
+  /* Can always get recvd interface for IPv6 */
+  if (!check_dest)
+    {
+      if (listen->iface)
+	{
+	  addr = listen->iface->addr;
+	  name = listen->iface->name;
+	  mtu = listen->iface->mtu;
+	  if (daemon->tftp_mtu != 0 && daemon->tftp_mtu < mtu)
+	    mtu = daemon->tftp_mtu;
+	}
+      else
+	{
+	  /* we're listening on an address that doesn't appear on an interface,
+	     ask the kernel what the socket is bound to */
+	  socklen_t tcp_len = sizeof(union mysockaddr);
+	  if (getsockname(listen->tftpfd, (struct sockaddr *)&addr, &tcp_len) == -1)
+	    return;
+	}
+    }
+  else
+    {
+      struct cmsghdr *cmptr;
+
+      if (msg.msg_controllen < sizeof(struct cmsghdr))
+        return;
+      
+      addr.sa.sa_family = listen->family;
+      
+#if defined(HAVE_LINUX_NETWORK)
+      if (listen->family == AF_INET)
+	for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
+	  if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
+	    {
+	      union {
+		unsigned char *c;
+		struct in_pktinfo *p;
+	      } p;
+	      p.c = CMSG_DATA(cmptr);
+	      addr.in.sin_addr = p.p->ipi_spec_dst;
+	      if_index = p.p->ipi_ifindex;
+	    }
+      
+#elif defined(HAVE_SOLARIS_NETWORK)
+      if (listen->family == AF_INET)
+	for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
+	  {
+	    union {
+	      unsigned char *c;
+	      struct in_addr *a;
+	      unsigned int *i;
+	    } p;
+	    p.c = CMSG_DATA(cmptr);
+	    if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
+	    addr.in.sin_addr = *(p.a);
+	    else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
+	    if_index = *(p.i);
+	  }
+      
+#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
+      if (listen->family == AF_INET)
+	for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
+	  {
+	    union {
+	      unsigned char *c;
+	      struct in_addr *a;
+	      struct sockaddr_dl *s;
+	    } p;
+	    p.c = CMSG_DATA(cmptr);
+	    if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
+	      addr.in.sin_addr = *(p.a);
+	    else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
+	      if_index = p.s->sdl_index;
+	  }
+	  
+#endif
+
+#ifdef HAVE_IPV6
+      if (listen->family == AF_INET6)
+        {
+          for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
+            if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
+              {
+                union {
+                  unsigned char *c;
+                  struct in6_pktinfo *p;
+                } p;
+                p.c = CMSG_DATA(cmptr);
+                  
+                addr.in6.sin6_addr = p.p->ipi6_addr;
+                if_index = p.p->ipi6_ifindex;
+              }
+        }
+#endif
+      
+      if (!indextoname(listen->tftpfd, if_index, namebuff))
+	return;
+
+      name = namebuff;
+      
+      addra.addr.addr4 = addr.in.sin_addr;
+
+#ifdef HAVE_IPV6
+      if (listen->family == AF_INET6)
+	addra.addr.addr6 = addr.in6.sin6_addr;
+#endif
+
+      if (daemon->tftp_interfaces)
+	{
+	  /* dedicated tftp interface list */
+	  for (tmp = daemon->tftp_interfaces; tmp; tmp = tmp->next)
+	    if (tmp->name && wildcard_match(tmp->name, name))
+	      break;
+
+	  if (!tmp)
+	    return;
+	}
+      else
+	{
+	  /* Do the same as DHCP */
+	  if (!iface_check(listen->family, &addra, name, NULL))
+	    {
+	      if (!option_bool(OPT_CLEVERBIND))
+		enumerate_interfaces(0); 
+	      if (!loopback_exception(listen->tftpfd, listen->family, &addra, name) &&
+		  !label_exception(if_index, listen->family, &addra) )
+		return;
+	    }
+	  
+#ifdef HAVE_DHCP      
+	  /* allowed interfaces are the same as for DHCP */
+	  for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
+	    if (tmp->name && wildcard_match(tmp->name, name))
+	      return;
+#endif
+	}
+
+      strncpy(ifr.ifr_name, name, IF_NAMESIZE);
+      if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
+	{
+	  mtu = ifr.ifr_mtu;  
+	  if (daemon->tftp_mtu != 0 && daemon->tftp_mtu < mtu)
+	    mtu = daemon->tftp_mtu;    
+	}
+    }
+
+  /* Failed to get interface mtu - can use configured value. */
+  if (mtu == 0)
+    mtu = daemon->tftp_mtu;
+
+  if (name)
+    {
+      /* check for per-interface prefix */ 
+      for (pref = daemon->if_prefix; pref; pref = pref->next)
+	if (strcmp(pref->interface, name) == 0)
+	  prefix = pref->prefix;  
+    }
+
+  if (listen->family == AF_INET)
+    {
+      addr.in.sin_port = htons(port);
+#ifdef HAVE_SOCKADDR_SA_LEN
+      addr.in.sin_len = sizeof(addr.in);
+#endif
+    }
+#ifdef HAVE_IPV6
+  else
+    {
+      addr.in6.sin6_port = htons(port);
+      addr.in6.sin6_flowinfo = 0;
+      addr.in6.sin6_scope_id = 0;
+#ifdef HAVE_SOCKADDR_SA_LEN
+      addr.in6.sin6_len = sizeof(addr.in6);
+#endif
+    }
+#endif
+
+  if (!(transfer = whine_malloc(sizeof(struct tftp_transfer))))
+    return;
+  
+  if ((transfer->sockfd = socket(listen->family, SOCK_DGRAM, 0)) == -1)
+    {
+      free(transfer);
+      return;
+    }
+  
+  transfer->peer = peer;
+  transfer->timeout = now + 2;
+  transfer->backoff = 1;
+  transfer->block = 1;
+  transfer->blocksize = 512;
+  transfer->offset = 0;
+  transfer->file = NULL;
+  transfer->opt_blocksize = transfer->opt_transize = 0;
+  transfer->netascii = transfer->carrylf = 0;
+ 
+  prettyprint_addr(&peer, daemon->addrbuff);
+  
+  /* if we have a nailed-down range, iterate until we find a free one. */
+  while (1)
+    {
+      if (bind(transfer->sockfd, &addr.sa, sa_len(&addr)) == -1 ||
+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
+	  setsockopt(transfer->sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 ||
+#endif
+	  !fix_fd(transfer->sockfd))
+	{
+	  if (errno == EADDRINUSE && daemon->start_tftp_port != 0)
+	    {
+	      if (++port <= daemon->end_tftp_port)
+		{ 
+		  if (listen->family == AF_INET)
+		    addr.in.sin_port = htons(port);
+#ifdef HAVE_IPV6
+		  else
+		     addr.in6.sin6_port = htons(port);
+#endif
+		  continue;
+		}
+	      my_syslog(MS_TFTP | LOG_ERR, _("unable to get free port for TFTP"));
+	    }
+	  free_transfer(transfer);
+	  return;
+	}
+      break;
+    }
+  
+  p = packet + 2;
+  end = packet + len;
+
+  if (ntohs(*((unsigned short *)packet)) != OP_RRQ ||
+      !(filename = next(&p, end)) ||
+      !(mode = next(&p, end)) ||
+      (strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
+    {
+      len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), daemon->addrbuff);
+      is_err = 1;
+    }
+  else
+    {
+      if (strcasecmp(mode, "netascii") == 0)
+	transfer->netascii = 1;
+      
+      while ((opt = next(&p, end)))
+	{
+	  if (strcasecmp(opt, "blksize") == 0)
+	    {
+	      if ((opt = next(&p, end)) && !option_bool(OPT_TFTP_NOBLOCK))
+		{
+		  /* 32 bytes for IP, UDP and TFTP headers, 52 bytes for IPv6 */
+		  int overhead = (listen->family == AF_INET) ? 32 : 52;
+		  transfer->blocksize = atoi(opt);
+		  if (transfer->blocksize < 1)
+		    transfer->blocksize = 1;
+		  if (transfer->blocksize > (unsigned)daemon->packet_buff_sz - 4)
+		    transfer->blocksize = (unsigned)daemon->packet_buff_sz - 4;
+		  if (mtu != 0 && transfer->blocksize > (unsigned)mtu - overhead)
+		    transfer->blocksize = (unsigned)mtu - overhead;
+		  transfer->opt_blocksize = 1;
+		  transfer->block = 0;
+		}
+	    }
+	  else if (strcasecmp(opt, "tsize") == 0 && next(&p, end) && !transfer->netascii)
+	    {
+	      transfer->opt_transize = 1;
+	      transfer->block = 0;
+	    }
+	}
+
+      /* cope with backslashes from windows boxen. */
+      for (p = filename; *p; p++)
+	if (*p == '\\')
+	  *p = '/';
+	else if (option_bool(OPT_TFTP_LC))
+	  *p = tolower(*p);
+		
+      strcpy(daemon->namebuff, "/");
+      if (prefix)
+	{
+	  if (prefix[0] == '/')
+	    daemon->namebuff[0] = 0;
+	  strncat(daemon->namebuff, prefix, (MAXDNAME-1) - strlen(daemon->namebuff));
+	  if (prefix[strlen(prefix)-1] != '/')
+	    strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
+
+	  if (option_bool(OPT_TFTP_APREF_IP))
+	    {
+	      size_t oldlen = strlen(daemon->namebuff);
+	      struct stat statbuf;
+	      
+	      strncat(daemon->namebuff, daemon->addrbuff, (MAXDNAME-1) - strlen(daemon->namebuff));
+	      strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
+	      
+	      /* remove unique-directory if it doesn't exist */
+	      if (stat(daemon->namebuff, &statbuf) == -1 || !S_ISDIR(statbuf.st_mode))
+		daemon->namebuff[oldlen] = 0;
+	    }
+	  
+	  if (option_bool(OPT_TFTP_APREF_MAC))
+	    {
+	      unsigned char *macaddr = NULL;
+	      unsigned char macbuf[DHCP_CHADDR_MAX];
+	      
+#ifdef HAVE_DHCP
+	      if (daemon->dhcp && peer.sa.sa_family == AF_INET)
+	        {
+		  /* Check if the client IP is in our lease database */
+		  struct dhcp_lease *lease = lease_find_by_addr(peer.in.sin_addr);
+		  if (lease && lease->hwaddr_type == ARPHRD_ETHER && lease->hwaddr_len == ETHER_ADDR_LEN)
+		    macaddr = lease->hwaddr;
+		}
+#endif
+	      
+	      /* If no luck, try to find in ARP table. This only works if client is in same (V)LAN */
+	      if (!macaddr && find_mac(&peer, macbuf, 1, now) > 0)
+		macaddr = macbuf;
+	      
+	      if (macaddr)
+	        {
+		  size_t oldlen = strlen(daemon->namebuff);
+		  struct stat statbuf;
+
+		  snprintf(daemon->namebuff + oldlen, (MAXDNAME-1) - oldlen, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x/",
+			   macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]);
+		  
+		  /* remove unique-directory if it doesn't exist */
+		  if (stat(daemon->namebuff, &statbuf) == -1 || !S_ISDIR(statbuf.st_mode))
+		    daemon->namebuff[oldlen] = 0;
+		}
+	    }
+	  
+	  /* Absolute pathnames OK if they match prefix */
+	  if (filename[0] == '/')
+	    {
+	      if (strstr(filename, daemon->namebuff) == filename)
+		daemon->namebuff[0] = 0;
+	      else
+		filename++;
+	    }
+	}
+      else if (filename[0] == '/')
+	daemon->namebuff[0] = 0;
+      strncat(daemon->namebuff, filename, (MAXDNAME-1) - strlen(daemon->namebuff));
+      
+      /* check permissions and open file */
+      if ((transfer->file = check_tftp_fileperm(&len, prefix)))
+	{
+	  if ((len = get_block(packet, transfer)) == -1)
+	    len = tftp_err_oops(packet, daemon->namebuff);
+	  else
+	    is_err = 0;
+	}
+    }
+  
+  while (sendto(transfer->sockfd, packet, len, 0, 
+		(struct sockaddr *)&peer, sa_len(&peer)) == -1 && errno == EINTR);
+  
+  if (is_err)
+    free_transfer(transfer);
+  else
+    {
+      transfer->next = daemon->tftp_trans;
+      daemon->tftp_trans = transfer;
+    }
+}
+ 
+static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix)
+{
+  char *packet = daemon->packet, *namebuff = daemon->namebuff;
+  struct tftp_file *file;
+  struct tftp_transfer *t;
+  uid_t uid = geteuid();
+  struct stat statbuf;
+  int fd = -1;
+
+  /* trick to ban moving out of the subtree */
+  if (prefix && strstr(namebuff, "/../"))
+    goto perm;
+  
+  if ((fd = open(namebuff, O_RDONLY)) == -1)
+    {
+      if (errno == ENOENT)
+	{
+	  *len = tftp_err(ERR_FNF, packet, _("file %s not found"), namebuff);
+	  return NULL;
+	}
+      else if (errno == EACCES)
+	goto perm;
+      else
+	goto oops;
+    }
+  
+  /* stat the file descriptor to avoid stat->open races */
+  if (fstat(fd, &statbuf) == -1)
+    goto oops;
+  
+  /* running as root, must be world-readable */
+  if (uid == 0)
+    {
+      if (!(statbuf.st_mode & S_IROTH))
+	goto perm;
+    }
+  /* in secure mode, must be owned by user running dnsmasq */
+  else if (option_bool(OPT_TFTP_SECURE) && uid != statbuf.st_uid)
+    goto perm;
+      
+  /* If we're doing many transfers from the same file, only 
+     open it once this saves lots of file descriptors 
+     when mass-booting a big cluster, for instance. 
+     Be conservative and only share when inode and name match
+     this keeps error messages sane. */
+  for (t = daemon->tftp_trans; t; t = t->next)
+    if (t->file->dev == statbuf.st_dev && 
+	t->file->inode == statbuf.st_ino &&
+	strcmp(t->file->filename, namebuff) == 0)
+      {
+	close(fd);
+	t->file->refcount++;
+	return t->file;
+      }
+  
+  if (!(file = whine_malloc(sizeof(struct tftp_file) + strlen(namebuff) + 1)))
+    {
+      errno = ENOMEM;
+      goto oops;
+    }
+
+  file->fd = fd;
+  file->size = statbuf.st_size;
+  file->dev = statbuf.st_dev;
+  file->inode = statbuf.st_ino;
+  file->refcount = 1;
+  strcpy(file->filename, namebuff);
+  return file;
+  
+ perm:
+  errno = EACCES;
+  *len =  tftp_err(ERR_PERM, packet, _("cannot access %s: %s"), namebuff);
+  if (fd != -1)
+    close(fd);
+  return NULL;
+
+ oops:
+  *len =  tftp_err_oops(packet, namebuff);
+  if (fd != -1)
+    close(fd);
+  return NULL;
+}
+
+void check_tftp_listeners(time_t now)
+{
+  struct tftp_transfer *transfer, *tmp, **up;
+  ssize_t len;
+  
+  struct ack {
+    unsigned short op, block;
+  } *mess = (struct ack *)daemon->packet;
+  
+  /* Check for activity on any existing transfers */
+  for (transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; transfer = tmp)
+    {
+      tmp = transfer->next;
+      
+      prettyprint_addr(&transfer->peer, daemon->addrbuff);
+     
+      if (poll_check(transfer->sockfd, POLLIN))
+	{
+	  /* we overwrote the buffer... */
+	  daemon->srv_save = NULL;
+	  
+	  if ((len = recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0)) >= (ssize_t)sizeof(struct ack))
+	    {
+	      if (ntohs(mess->op) == OP_ACK && ntohs(mess->block) == (unsigned short)transfer->block) 
+		{
+		  /* Got ack, ensure we take the (re)transmit path */
+		  transfer->timeout = now;
+		  transfer->backoff = 0;
+		  if (transfer->block++ != 0)
+		    transfer->offset += transfer->blocksize - transfer->expansion;
+		}
+	      else if (ntohs(mess->op) == OP_ERR)
+		{
+		  char *p = daemon->packet + sizeof(struct ack);
+		  char *end = daemon->packet + len;
+		  char *err = next(&p, end);
+		  
+		  /* Sanitise error message */
+		  if (!err)
+		    err = "";
+		  else
+		    sanitise(err);
+		  
+		  my_syslog(MS_TFTP | LOG_ERR, _("error %d %s received from %s"),
+			    (int)ntohs(mess->block), err, 
+			    daemon->addrbuff);	
+		  
+		  /* Got err, ensure we take abort */
+		  transfer->timeout = now;
+		  transfer->backoff = 100;
+		}
+	    }
+	}
+      
+      if (difftime(now, transfer->timeout) >= 0.0)
+	{
+	  int endcon = 0;
+
+	  /* timeout, retransmit */
+	  transfer->timeout += 1 + (1<<transfer->backoff);
+	  	  
+	  /* we overwrote the buffer... */
+	  daemon->srv_save = NULL;
+	 
+	  if ((len = get_block(daemon->packet, transfer)) == -1)
+	    {
+	      len = tftp_err_oops(daemon->packet, transfer->file->filename);
+	      endcon = 1;
+	    }
+	  /* don't complain about timeout when we're awaiting the last
+	     ACK, some clients never send it */
+	  else if (++transfer->backoff > 7 && len != 0)
+	    {
+	      endcon = 1;
+	      len = 0;
+	    }
+
+	  if (len != 0)
+	    while(sendto(transfer->sockfd, daemon->packet, len, 0, 
+			 (struct sockaddr *)&transfer->peer, sa_len(&transfer->peer)) == -1 && errno == EINTR);
+	  
+	  if (endcon || len == 0)
+	    {
+	      strcpy(daemon->namebuff, transfer->file->filename);
+	      sanitise(daemon->namebuff);
+	      my_syslog(MS_TFTP | LOG_INFO, endcon ? _("failed sending %s to %s") : _("sent %s to %s"), daemon->namebuff, daemon->addrbuff);
+	      /* unlink */
+	      *up = tmp;
+	      if (endcon)
+		free_transfer(transfer);
+	      else
+		{
+		  /* put on queue to be sent to script and deleted */
+		  transfer->next = daemon->tftp_done_trans;
+		  daemon->tftp_done_trans = transfer;
+		}
+	      continue;
+	    }
+	}
+
+      up = &transfer->next;
+    }    
+}
+
+static void free_transfer(struct tftp_transfer *transfer)
+{
+  close(transfer->sockfd);
+  if (transfer->file && (--transfer->file->refcount) == 0)
+    {
+      close(transfer->file->fd);
+      free(transfer->file);
+    }
+  free(transfer);
+}
+
+static char *next(char **p, char *end)
+{
+  char *ret = *p;
+  size_t len;
+
+  if (*(end-1) != 0 || 
+      *p == end ||
+      (len = strlen(ret)) == 0)
+    return NULL;
+
+  *p += len + 1;
+  return ret;
+}
+
+static void sanitise(char *buf)
+{
+  unsigned char *q, *r;
+  for (q = r = (unsigned char *)buf; *r; r++)
+    if (isprint((int)*r))
+      *(q++) = *r;
+  *q = 0;
+
+}
+
+#define MAXMESSAGE 500 /* limit to make packet < 512 bytes and definitely smaller than buffer */ 
+static ssize_t tftp_err(int err, char *packet, char *message, char *file)
+{
+  struct errmess {
+    unsigned short op, err;
+    char message[];
+  } *mess = (struct errmess *)packet;
+  ssize_t len, ret = 4;
+  char *errstr = strerror(errno);
+  
+  memset(packet, 0, daemon->packet_buff_sz);
+  sanitise(file);
+  
+  mess->op = htons(OP_ERR);
+  mess->err = htons(err);
+  len = snprintf(mess->message, MAXMESSAGE,  message, file, errstr);
+  ret += (len < MAXMESSAGE) ? len + 1 : MAXMESSAGE; /* include terminating zero */
+  
+  my_syslog(MS_TFTP | LOG_ERR, "%s", mess->message);
+  
+  return  ret;
+}
+
+static ssize_t tftp_err_oops(char *packet, char *file)
+{
+  /* May have >1 refs to file, so potentially mangle a copy of the name */
+  strcpy(daemon->namebuff, file);
+  return tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), daemon->namebuff);
+}
+
+/* return -1 for error, zero for done. */
+static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
+{
+  memset(packet, 0, daemon->packet_buff_sz);
+  
+  if (transfer->block == 0)
+    {
+      /* send OACK */
+      char *p;
+      struct oackmess {
+	unsigned short op;
+	char data[];
+      } *mess = (struct oackmess *)packet;
+      
+      p = mess->data;
+      mess->op = htons(OP_OACK);
+      if (transfer->opt_blocksize)
+	{
+	  p += (sprintf(p, "blksize") + 1);
+	  p += (sprintf(p, "%u", transfer->blocksize) + 1);
+	}
+      if (transfer->opt_transize)
+	{
+	  p += (sprintf(p,"tsize") + 1);
+	  p += (sprintf(p, "%u", (unsigned int)transfer->file->size) + 1);
+	}
+
+      return p - packet;
+    }
+  else
+    {
+      /* send data packet */
+      struct datamess {
+	unsigned short op, block;
+	unsigned char data[];
+      } *mess = (struct datamess *)packet;
+      
+      size_t size = transfer->file->size - transfer->offset; 
+      
+      if (transfer->offset > transfer->file->size)
+	return 0; /* finished */
+      
+      if (size > transfer->blocksize)
+	size = transfer->blocksize;
+      
+      mess->op = htons(OP_DATA);
+      mess->block = htons((unsigned short)(transfer->block));
+      
+      if (lseek(transfer->file->fd, transfer->offset, SEEK_SET) == (off_t)-1 ||
+	  !read_write(transfer->file->fd, mess->data, size, 1))
+	return -1;
+      
+      transfer->expansion = 0;
+      
+      /* Map '\n' to CR-LF in netascii mode */
+      if (transfer->netascii)
+	{
+	  size_t i;
+	  int newcarrylf;
+
+	  for (i = 0, newcarrylf = 0; i < size; i++)
+	    if (mess->data[i] == '\n' && ( i != 0 || !transfer->carrylf))
+	      {
+		transfer->expansion++;
+
+		if (size != transfer->blocksize)
+		  size++; /* room in this block */
+		else  if (i == size - 1)
+		  newcarrylf = 1; /* don't expand LF again if it moves to the next block */
+		  
+		/* make space and insert CR */
+		memmove(&mess->data[i+1], &mess->data[i], size - (i + 1));
+		mess->data[i] = '\r';
+		
+		i++;
+	      }
+	  transfer->carrylf = newcarrylf;
+	  
+	}
+
+      return size + 4;
+    }
+}
+
+
+int do_tftp_script_run(void)
+{
+  struct tftp_transfer *transfer;
+
+  if ((transfer = daemon->tftp_done_trans))
+    {
+      daemon->tftp_done_trans = transfer->next;
+#ifdef HAVE_SCRIPT
+      queue_tftp(transfer->file->size, transfer->file->filename, &transfer->peer);
+#endif
+      free_transfer(transfer);
+      return 1;
+    }
+
+  return 0;
+}
+#endif
diff --git a/src/util.c b/src/util.c
new file mode 100755
index 0000000..2a1d448
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,701 @@
+/* dnsmasq is Copyright (c) 2000-2017 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, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
+   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.
+      
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* The SURF random number generator was taken from djbdns-1.05, by 
+   Daniel J Bernstein, which is public domain. */
+
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_BROKEN_RTC
+#include <sys/times.h>
+#endif
+
+#if defined(HAVE_LIBIDN2)
+#include <idn2.h>
+#elif defined(HAVE_IDN)
+#include <idna.h>
+#endif
+
+/* SURF random number generator */
+
+static u32 seed[32];
+static u32 in[12];
+static u32 out[8];
+static int outleft = 0;
+
+void rand_init()
+{
+  int fd = open(RANDFILE, O_RDONLY);
+  
+  if (fd == -1 ||
+      !read_write(fd, (unsigned char *)&seed, sizeof(seed), 1) ||
+      !read_write(fd, (unsigned char *)&in, sizeof(in), 1))
+    die(_("failed to seed the random number generator: %s"), NULL, EC_MISC);
+  
+  close(fd);
+}
+
+#define ROTATE(x,b) (((x) << (b)) | ((x) >> (32 - (b))))
+#define MUSH(i,b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x,b));
+
+static void surf(void)
+{
+  u32 t[12]; u32 x; u32 sum = 0;
+  int r; int i; int loop;
+
+  for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i];
+  for (i = 0;i < 8;++i) out[i] = seed[24 + i];
+  x = t[11];
+  for (loop = 0;loop < 2;++loop) {
+    for (r = 0;r < 16;++r) {
+      sum += 0x9e3779b9;
+      MUSH(0,5) MUSH(1,7) MUSH(2,9) MUSH(3,13)
+      MUSH(4,5) MUSH(5,7) MUSH(6,9) MUSH(7,13)
+      MUSH(8,5) MUSH(9,7) MUSH(10,9) MUSH(11,13)
+    }
+    for (i = 0;i < 8;++i) out[i] ^= t[i + 4];
+  }
+}
+
+unsigned short rand16(void)
+{
+  if (!outleft) 
+    {
+      if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
+      surf();
+      outleft = 8;
+    }
+  
+  return (unsigned short) out[--outleft];
+}
+
+u32 rand32(void)
+{
+ if (!outleft) 
+    {
+      if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
+      surf();
+      outleft = 8;
+    }
+  
+  return out[--outleft]; 
+}
+
+u64 rand64(void)
+{
+  static int outleft = 0;
+
+  if (outleft < 2)
+    {
+      if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
+      surf();
+      outleft = 8;
+    }
+  
+  outleft -= 2;
+
+  return (u64)out[outleft+1] + (((u64)out[outleft]) << 32);
+}
+
+/* returns 2 if names is OK but contains one or more underscores */
+static int check_name(char *in)
+{
+  /* remove trailing . 
+     also fail empty string and label > 63 chars */
+  size_t dotgap = 0, l = strlen(in);
+  char c;
+  int nowhite = 0;
+  int hasuscore = 0;
+  
+  if (l == 0 || l > MAXDNAME) return 0;
+  
+  if (in[l-1] == '.')
+    {
+      in[l-1] = 0;
+      nowhite = 1;
+    }
+
+  for (; (c = *in); in++)
+    {
+      if (c == '.')
+	dotgap = 0;
+      else if (++dotgap > MAXLABEL)
+	return 0;
+      else if (isascii((unsigned char)c) && iscntrl((unsigned char)c)) 
+	/* iscntrl only gives expected results for ascii */
+	return 0;
+#if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
+      else if (!isascii((unsigned char)c))
+	return 0;
+#endif
+      else if (c != ' ')
+	{
+	  nowhite = 1;
+	  if (c == '_')
+	    hasuscore = 1;
+	}
+    }
+
+  if (!nowhite)
+    return 0;
+
+  return hasuscore ? 2 : 1;
+}
+
+/* Hostnames have a more limited valid charset than domain names
+   so check for legal char a-z A-Z 0-9 - _ 
+   Note that this may receive a FQDN, so only check the first label 
+   for the tighter criteria. */
+int legal_hostname(char *name)
+{
+  char c;
+  int first;
+
+  if (!check_name(name))
+    return 0;
+
+  for (first = 1; (c = *name); name++, first = 0)
+    /* check for legal char a-z A-Z 0-9 - _ . */
+    {
+      if ((c >= 'A' && c <= 'Z') ||
+	  (c >= 'a' && c <= 'z') ||
+	  (c >= '0' && c <= '9'))
+	continue;
+
+      if (!first && (c == '-' || c == '_'))
+	continue;
+      
+      /* end of hostname part */
+      if (c == '.')
+	return 1;
+      
+      return 0;
+    }
+  
+  return 1;
+}
+  
+char *canonicalise(char *in, int *nomem)
+{
+  char *ret = NULL;
+  int rc;
+  
+  if (nomem)
+    *nomem = 0;
+  
+  if (!(rc = check_name(in)))
+    return NULL;
+  
+#if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
+  /* older libidn2 strips underscores, so don't do IDN processing
+     if the name has an underscore (check_name() returned 2) */
+  if (rc != 2)
+#endif
+#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
+    {
+#  ifdef HAVE_LIBIDN2
+      rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL);
+      if (rc == IDN2_DISALLOWED)
+	rc = idn2_to_ascii_lz(in, &ret, IDN2_TRANSITIONAL);
+#  else
+      rc = idna_to_ascii_lz(in, &ret, 0);
+#  endif
+      if (rc != IDNA_SUCCESS)
+	{
+	  if (ret)
+	    free(ret);
+	  
+	  if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR))
+	    {
+	      my_syslog(LOG_ERR, _("failed to allocate memory"));
+	      *nomem = 1;
+	    }
+	  
+	  return NULL;
+	}
+      
+      return ret;
+    }
+#endif
+  
+  if ((ret = whine_malloc(strlen(in)+1)))
+    strcpy(ret, in);
+  else if (nomem)
+    *nomem = 1;    
+
+  return ret;
+}
+
+unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit)
+{
+  int j;
+  
+  while (sval && *sval)
+    {
+      if (limit && p + 1 > (unsigned char*)limit)
+        return p;
+
+      unsigned char *cp = p++;
+      for (j = 0; *sval && (*sval != '.'); sval++, j++)
+	{
+          if (limit && p + 1 > (unsigned char*)limit)
+            return p;
+#ifdef HAVE_DNSSEC
+	  if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE)
+	    *p++ = (*(++sval))-1;
+	  else
+#endif		
+	    *p++ = *sval;
+	}
+      *cp  = j;
+      if (*sval)
+	sval++;
+    }
+  return p;
+}
+
+/* for use during startup */
+void *safe_malloc(size_t size)
+{
+  void *ret = calloc(1, size);
+  
+  if (!ret)
+    die(_("could not get memory"), NULL, EC_NOMEM);
+      
+  return ret;
+}    
+
+void safe_pipe(int *fd, int read_noblock)
+{
+  if (pipe(fd) == -1 || 
+      !fix_fd(fd[1]) ||
+      (read_noblock && !fix_fd(fd[0])))
+    die(_("cannot create pipe: %s"), NULL, EC_MISC);
+}
+
+void *whine_malloc(size_t size)
+{
+  void *ret = calloc(1, size);
+
+  if (!ret)
+    my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
+  
+  return ret;
+}
+
+int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2)
+{
+  if (s1->sa.sa_family == s2->sa.sa_family)
+    { 
+      if (s1->sa.sa_family == AF_INET &&
+	  s1->in.sin_port == s2->in.sin_port &&
+	  s1->in.sin_addr.s_addr == s2->in.sin_addr.s_addr)
+	return 1;
+#ifdef HAVE_IPV6      
+      if (s1->sa.sa_family == AF_INET6 &&
+	  s1->in6.sin6_port == s2->in6.sin6_port &&
+	  s1->in6.sin6_scope_id == s2->in6.sin6_scope_id &&
+	  IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr))
+	return 1;
+#endif
+    }
+  return 0;
+}
+
+int sa_len(union mysockaddr *addr)
+{
+#ifdef HAVE_SOCKADDR_SA_LEN
+  return addr->sa.sa_len;
+#else
+#ifdef HAVE_IPV6
+  if (addr->sa.sa_family == AF_INET6)
+    return sizeof(addr->in6);
+  else
+#endif
+    return sizeof(addr->in); 
+#endif
+}
+
+/* don't use strcasecmp and friends here - they may be messed up by LOCALE */
+int hostname_isequal(const char *a, const char *b)
+{
+  unsigned int c1, c2;
+  
+  do {
+    c1 = (unsigned char) *a++;
+    c2 = (unsigned char) *b++;
+    
+    if (c1 >= 'A' && c1 <= 'Z')
+      c1 += 'a' - 'A';
+    if (c2 >= 'A' && c2 <= 'Z')
+      c2 += 'a' - 'A';
+    
+    if (c1 != c2)
+      return 0;
+  } while (c1);
+  
+  return 1;
+}
+
+time_t dnsmasq_time(void)
+{
+#ifdef HAVE_BROKEN_RTC
+  struct tms dummy;
+  static long tps = 0;
+
+  if (tps == 0)
+    tps = sysconf(_SC_CLK_TCK);
+
+  return (time_t)(times(&dummy)/tps);
+#else
+  return time(NULL);
+#endif
+}
+
+int netmask_length(struct in_addr mask)
+{
+  int zero_count = 0;
+
+  while (0x0 == (mask.s_addr & 0x1) && zero_count < 32) 
+    {
+      mask.s_addr >>= 1;
+      zero_count++;
+    }
+  
+  return 32 - zero_count;
+}
+
+int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
+{
+  return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
+} 
+
+#ifdef HAVE_IPV6
+int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
+{
+  int pfbytes = prefixlen >> 3;
+  int pfbits = prefixlen & 7;
+
+  if (memcmp(&a->s6_addr, &b->s6_addr, pfbytes) != 0)
+    return 0;
+
+  if (pfbits == 0 ||
+      (a->s6_addr[pfbytes] >> (8 - pfbits) == b->s6_addr[pfbytes] >> (8 - pfbits)))
+    return 1;
+
+  return 0;
+}
+
+/* return least significant 64 bits if IPv6 address */
+u64 addr6part(struct in6_addr *addr)
+{
+  int i;
+  u64 ret = 0;
+
+  for (i = 8; i < 16; i++)
+    ret = (ret << 8) + addr->s6_addr[i];
+
+  return ret;
+}
+
+void setaddr6part(struct in6_addr *addr, u64 host)
+{
+  int i;
+
+  for (i = 15; i >= 8; i--)
+    {
+      addr->s6_addr[i] = host;
+      host = host >> 8;
+    }
+}
+
+#endif
+ 
+
+/* returns port number from address */
+int prettyprint_addr(union mysockaddr *addr, char *buf)
+{
+  int port = 0;
+  
+#ifdef HAVE_IPV6
+  if (addr->sa.sa_family == AF_INET)
+    {
+      inet_ntop(AF_INET, &addr->in.sin_addr, buf, ADDRSTRLEN);
+      port = ntohs(addr->in.sin_port);
+    }
+  else if (addr->sa.sa_family == AF_INET6)
+    {
+      char name[IF_NAMESIZE];
+      inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN);
+      if (addr->in6.sin6_scope_id != 0 &&
+	  if_indextoname(addr->in6.sin6_scope_id, name) &&
+	  strlen(buf) + strlen(name) + 2 <= ADDRSTRLEN)
+	{
+	  strcat(buf, "%");
+	  strcat(buf, name);
+	}
+      port = ntohs(addr->in6.sin6_port);
+    }
+#else
+  strcpy(buf, inet_ntoa(addr->in.sin_addr));
+  port = ntohs(addr->in.sin_port); 
+#endif
+  
+  return port;
+}
+
+void prettyprint_time(char *buf, unsigned int t)
+{
+  if (t == 0xffffffff)
+    sprintf(buf, _("infinite"));
+  else
+    {
+      unsigned int x, p = 0;
+       if ((x = t/86400))
+	p += sprintf(&buf[p], "%ud", x);
+       if ((x = (t/3600)%24))
+	p += sprintf(&buf[p], "%uh", x);
+      if ((x = (t/60)%60))
+	p += sprintf(&buf[p], "%um", x);
+      if ((x = t%60))
+	p += sprintf(&buf[p], "%us", x);
+    }
+}
+
+
+/* in may equal out, when maxlen may be -1 (No max len). 
+   Return -1 for extraneous no-hex chars found. */
+int parse_hex(char *in, unsigned char *out, int maxlen, 
+	      unsigned int *wildcard_mask, int *mac_type)
+{
+  int mask = 0, i = 0;
+  char *r;
+    
+  if (mac_type)
+    *mac_type = 0;
+  
+  while (maxlen == -1 || i < maxlen)
+    {
+      for (r = in; *r != 0 && *r != ':' && *r != '-' && *r != ' '; r++)
+	if (*r != '*' && !isxdigit((unsigned char)*r))
+	  return -1;
+      
+      if (*r == 0)
+	maxlen = i;
+      
+      if (r != in )
+	{
+	  if (*r == '-' && i == 0 && mac_type)
+	   {
+	      *r = 0;
+	      *mac_type = strtol(in, NULL, 16);
+	      mac_type = NULL;
+	   }
+	  else
+	    {
+	      *r = 0;
+	      if (strcmp(in, "*") == 0)
+		{
+		  mask = (mask << 1) | 1;
+		  i++;
+		}
+	      else
+		{
+		  int j, bytes = (1 + (r - in))/2;
+		  for (j = 0; j < bytes; j++)
+		    { 
+		      char sav = sav;
+		      if (j < bytes - 1)
+			{
+			  sav = in[(j+1)*2];
+			  in[(j+1)*2] = 0;
+			}
+		      /* checks above allow mix of hexdigit and *, which
+			 is illegal. */
+		      if (strchr(&in[j*2], '*'))
+			return -1;
+		      out[i] = strtol(&in[j*2], NULL, 16);
+		      mask = mask << 1;
+		      if (++i == maxlen)
+			break; 
+		      if (j < bytes - 1)
+			in[(j+1)*2] = sav;
+		    }
+		}
+	    }
+	}
+      in = r+1;
+    }
+  
+  if (wildcard_mask)
+    *wildcard_mask = mask;
+
+  return i;
+}
+
+/* return 0 for no match, or (no matched octets) + 1 */
+int memcmp_masked(unsigned char *a, unsigned char *b, int len, unsigned int mask)
+{
+  int i, count;
+  for (count = 1, i = len - 1; i >= 0; i--, mask = mask >> 1)
+    if (!(mask & 1))
+      {
+	if (a[i] == b[i])
+	  count++;
+	else
+	  return 0;
+      }
+  return count;
+}
+
+/* _note_ may copy buffer */
+int expand_buf(struct iovec *iov, size_t size)
+{
+  void *new;
+
+  if (size <= (size_t)iov->iov_len)
+    return 1;
+
+  if (!(new = whine_malloc(size)))
+    {
+      errno = ENOMEM;
+      return 0;
+    }
+
+  if (iov->iov_base)
+    {
+      memcpy(new, iov->iov_base, iov->iov_len);
+      free(iov->iov_base);
+    }
+
+  iov->iov_base = new;
+  iov->iov_len = size;
+
+  return 1;
+}
+
+char *print_mac(char *buff, unsigned char *mac, int len)
+{
+  char *p = buff;
+  int i;
+   
+  if (len == 0)
+    sprintf(p, "<null>");
+  else
+    for (i = 0; i < len; i++)
+      p += sprintf(p, "%.2x%s", mac[i], (i == len - 1) ? "" : ":");
+  
+  return buff;
+}
+
+/* rc is return from sendto and friends.
+   Return 1 if we should retry.
+   Set errno to zero if we succeeded. */
+int retry_send(ssize_t rc)
+{
+  static int retries = 0;
+  struct timespec waiter;
+  
+  if (rc != -1)
+    {
+      retries = 0;
+      errno = 0;
+      return 0;
+    }
+  
+  /* Linux kernels can return EAGAIN in perpetuity when calling
+     sendmsg() and the relevant interface has gone. Here we loop
+     retrying in EAGAIN for 1 second max, to avoid this hanging 
+     dnsmasq. */
+
+  if (errno == EAGAIN || errno == EWOULDBLOCK)
+     {
+       waiter.tv_sec = 0;
+       waiter.tv_nsec = 10000;
+       nanosleep(&waiter, NULL);
+       if (retries++ < 1000)
+	 return 1;
+     }
+  
+  retries = 0;
+  
+  if (errno == EINTR)
+    return 1;
+  
+  return 0;
+}
+
+int read_write(int fd, unsigned char *packet, int size, int rw)
+{
+  ssize_t n, done;
+  
+  for (done = 0; done < size; done += n)
+    {
+      do { 
+	if (rw)
+	  n = read(fd, &packet[done], (size_t)(size - done));
+	else
+	  n = write(fd, &packet[done], (size_t)(size - done));
+	
+	if (n == 0)
+	  return 0;
+	
+      } while (retry_send(n) || errno == ENOMEM || errno == ENOBUFS);
+
+      if (errno != 0)
+	return 0;
+    }
+     
+  return 1;
+}
+
+/* Basically match a string value against a wildcard pattern.  */
+int wildcard_match(const char* wildcard, const char* match)
+{
+  while (*wildcard && *match)
+    {
+      if (*wildcard == '*')
+        return 1;
+
+      if (*wildcard != *match)
+        return 0; 
+
+      ++wildcard;
+      ++match;
+    }
+
+  return *wildcard == *match;
+}
+
+/* The same but comparing a maximum of NUM characters, like strncmp.  */
+int wildcard_matchn(const char* wildcard, const char* match, int num)
+{
+  while (*wildcard && *match && num)
+    {
+      if (*wildcard == '*')
+        return 1;
+
+      if (*wildcard != *match)
+        return 0; 
+
+      ++wildcard;
+      ++match;
+      --num;
+    }
+
+  return (!num) || (*wildcard == *match);
+}
diff --git a/trust-anchors.conf b/trust-anchors.conf
new file mode 100644
index 0000000..6f807cf
--- /dev/null
+++ b/trust-anchors.conf
@@ -0,0 +1,10 @@
+# The root DNSSEC trust anchor, valid as at 10/02/2017
+
+# Note that this is a DS record (ie a hash of the root Zone Signing Key) 
+# If was downloaded from https://data.iana.org/root-anchors/root-anchors.xml
+
+trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
+trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D
+
+
+