Compare commits

...

166 Commits

Author SHA1 Message Date
Simon Kelley
74ea91531a Fix typo and format in CHANGELOG 2017-05-22 22:58:46 +01:00
Matthias Andree
9828ab115e Fix compiler warning. 2017-05-21 22:41:16 +01:00
Matthias Andree
f77700aa27 Fix compiler warning. 2017-05-21 22:36:09 +01:00
Simon Kelley
0fbd980639 Fix compiler warning. 2017-05-21 22:24:43 +01:00
Simon Kelley
43cdf1c3d0 Remove automatic IDN support when building i18n.
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
2017-05-21 22:12:44 +01:00
Simon Kelley
ff19b1a97d Fix &/&& confusion. 2017-05-21 21:15:32 +01:00
Conrad Kostecki
1835343acd Update German translation. 2017-05-12 15:16:02 +01:00
Simon Kelley
2aaea18f43 Add .gitattributes to substitute VERSION on export. 2017-05-12 13:14:17 +01:00
Simon Kelley
7ab78b937f Fix c7be0164ce 2017-05-11 20:33:21 +01:00
Simon Kelley
c7be0164ce Suppress DHCP ping checks when allocating on the loopback interface. 2017-05-10 22:21:53 +01:00
Petr Menšík
d203af4a02 Add optional support for libidn2 and therefore IDNA2008. 2017-05-10 21:41:57 +01:00
Simon Kelley
05f76dab89 Don't die() on failing to parse lease-script output. 2017-05-09 22:57:04 +01:00
Simon Kelley
bf05f8ff20 Fix crash introduced by 09f3b2cd9c. 2017-05-09 22:37:46 +01:00
Simon Kelley
09f3b2cd9c Fix case of DS queries to domains marked as not doing DNSSEC.
This was causing confusion: DNSSEC queries would be sent to
servers for domains that don't do DNSSEC, but because of that status
the answers would be treated as answers to ordinary queries,
sometimes resulting in a crash.
2017-05-09 01:34:02 +01:00
Simon Kelley
22827870fa Fix botch introduced by 561441320f 2017-05-08 21:39:04 +01:00
Vladislav Grishenko
4583dd9e42 Replace obsolete utime() usage with utimes().
This fixes build time warnings with POSIX.1-2008-aware c libraries.
2017-05-03 23:16:51 +01:00
Simon Kelley
561441320f Fix a couple of crashes on malformed config files.
Thanks to Stephan Zeisberg and
american fuzzy lop http://lcamtuf.coredump.cx/afl/
2017-05-03 22:54:09 +01:00
Simon Kelley
b2a9c571eb Add "known-othernet" DHCP tag. 2017-04-30 18:21:31 +01:00
Simon Kelley
efff74c1ae Tweak logging introduced in 3a8b0f6fcc 2017-04-28 23:01:23 +01:00
Simon Kelley
a9df0e30b0 Revert "Implement RFC-6842 (Client-ids in DHCP replies.)"
This reverts commit 88a77a78ad.

A least one client has been found which breaks with this change. Since
the use-case is not clear, I'm reverting the change, at least for now.
2017-04-28 22:44:24 +01:00
Simon Kelley
5ce3e76fbf DHCPv4: do ICMP-ping check in all cases other that current lease. 2017-04-28 22:14:20 +01:00
Vladislav Grishenko
6ec5f5c427 Extend --ra-param mtu: field to allow an interface name. 2017-04-24 22:34:45 +01:00
Vladislav Grishenko
5a7212c70e Make --rev-server work in the presence of --bogus-priv. 2017-04-24 22:21:04 +01:00
Petr Menšík
3a8b0f6fcc Improve error handling with shcp-script "init" mode. 2017-04-23 14:12:37 +01:00
Simon Kelley
a24c31e023 Debian: enable PIE and BINDNOW hardening in build. 2017-04-16 22:45:53 +01:00
Simon Kelley
f5a3679f1d Merge branch 'master' of ssh://thekelleys.org.uk/var/cache/git/dnsmasq 2017-04-16 22:27:51 +01:00
Simon Kelley
5ac813cb86 Bump Lua version to 5.2. 2017-04-16 20:47:11 +01:00
Simon Kelley
a93b02e321 Compile option string: show script-support independent of DHCP. 2017-04-16 20:38:22 +01:00
Petr Menšík
c77fb9d8f0 Capture and log STDOUT and STDERR output from dhcp-script. 2017-04-16 20:20:08 +01:00
Simon Kelley
facc18f2a8 Bump Debian standards version. 2017-04-11 18:52:36 +01:00
Simon Kelley
bc515b71ec Merge branch 'master' of ssh://thekelleys.org.uk/var/cache/git/dnsmasq 2017-04-11 18:49:59 +01:00
Simon Kelley
7bfa26399b FreeBSD compilation tweak. 2017-04-11 18:49:27 +01:00
Simon Kelley
461b7b43b4 Debian: readme typos. 2017-04-11 18:06:13 +01:00
Simon Kelley
b1cefa57f1 Debian: strip dhcp_release6 binary. 2017-04-11 15:55:26 +01:00
Simon Kelley
ce9a9704c6 Debian: add lsb-base dep. 2017-04-11 15:34:25 +01:00
Simon Kelley
93a9a55055 Debian changelog format fixup. 2017-04-11 15:21:30 +01:00
Simon Kelley
44eb875a5a Handle change in format of Debian /usr/share/dns/root.ds. 2017-04-11 15:13:09 +01:00
Floris Bos
bc87e609c2 Debian initscript tweak.
Dnsmasq's startup script seems to assume users always want to use
dnsmasq as local DNS resolver, and tells resolvconf to put
"nameserver 127.0.0.1" in /etc/resolv.conf
The problem with this is that if users just want to use dnsmasq
as DHCP server, and put port=0 in /etc/dnsmasq.conf to disable
the DNS functionality, they end up with broken name resolving.

Put a basic check in the startup script that skips resolvconf
configuration if a line starting with port=0 is in /etc/dnsmasq.conf
This doesn't cover all cases (e.g. configuration could also be in
different file in /etc/dnsmasq.d), but is better than current
situation.
2017-04-11 14:19:57 +01:00
David Flamand
005c46d6f5 Add mtu facility to --ra-param. 2017-04-11 11:49:54 +01:00
Floris Bos
503c609149 --dhcp-reply-delay option to workaround PXE client bugs.
Adds option to delay replying to DHCP packets by one or more seconds.
This provides a workaround for a PXE boot firmware implementation
that has a bug causing it to fail if it receives a (proxy) DHCP
reply instantly.

On Linux it looks up the exact receive time of the UDP packet with
the SIOCGSTAMP ioctl to prevent multiple delays if multiple packets
come in around the same time.
2017-04-09 23:07:13 +01:00
Floris Bos
60704f5e2e Add support for unique TFTP root per MAC.
It is currently only possible to let the TFTP server serve a different
folder depending on the client's IP address.
However it isn't always possible to predict what the client's
IP address will be, especially in situations in which we are not
responsible for handing them out (e.g. proxy dhcp setups).

Extend the current --tftp-unique-root parameter to support having a
separate folder per MAC address instead.
2017-04-09 22:22:49 +01:00
Kristian Evensen
4e7694d710 Allow binding to both source address and interface in server specs.
The current --server syntax allows for binding to interface or
address. However, in some (admittedly special) cases it is useful to
be able to specify both. This commit introduces the following syntax
to support binding to both interface and address:

--server X.X.X.X@IP@interface#port

Based on my tests, the syntax is backwards compatible with the current
@IP/interface#port. The code will fail if two interface names are given.

v1->v2:
* Add man page description of the extended server syntax (thanks Simon Kelley)

Signed-off-by: Kristian Evensen <kristian.evensen@gmail.com>
2017-03-22 21:32:50 +00:00
James Bottomley
e33b48700e When forwarding a query to a non-DNSSEC nameserver, don't verify the lack of DNSSEC.
The man page says that we don't do DNSSEC on forwarded domains, but if
you turn on dnssec_check_signatures this turns out to be untrue,
because we try to build up a DS chain to them.  Since forwarded domains
are usually used for split DNS to hidden domains, they're unlikely to
verify to the DNS root anyway, so the way to do DNSSEC for them (as the
manual says) is to provide a trust anchor for each forwarder.

The problem I've run into is a split DNS setup where I want DNSSEC to
work mostly, but one of the forwarding domains doesn't have an internal
DNSSEC capable resolver. Without this patch the entire domain goes
unresolvable because the DS record query to the internal resolver
returns a failure which is interpreted as the domain being BOGUS.

The fix is not to do the DS record chase for forwarded domains.
2017-03-17 21:44:10 +00:00
Petr Menšík
ad59f278c6 Fix man page re interface labels and add warning when used badly. 2017-03-17 17:22:19 +00:00
Bert Gijsbers
16f03e7139 Check for failure of "git describe" in get-version. 2017-03-06 23:07:32 +00:00
Olivier Gayot
dc99058d83 Improve error checking for --rev-server.
The rev-server directive only handles the following CIDR prefixes
properly: /8, /16, /24, /32.

Any other value was silently converted to /16 which could result in
unexpected behaviour.

This patch rejects any other value instead of making a silent
conversion.
2017-03-06 22:17:21 +00:00
Olivier Gayot
916959c188 Fix rev-server with /32 prefix.
[ excerpt from the man page ]
The rev-server directive provides a syntactic sugar to make specifying
address-to-name queries easier. For example
--rev-server=1.2.3.0/24,192.168.0.1 is exactly equivalent to
--server=/3.2.1.in-addr.arpa/192.168.0.1

It is not mentioned in the man page but the only prefixes that the
directive properly handles when dealing with IPv4 are /8, /16 and /24.
Specifying anything else as the same effect as specifying /16.

It is not a big deal for subnets on non-octet boundaries since they
cannot be represented using a single in-addr.arpa address. However, it
is unconvenient for /32 prefix while the analogous server directive
behaves as expected. E.g. the following server directive work
as expected:

    server=/42.10.168.192.in-addr.arpa/1.2.3.4

but the following does not:

    rev-server=192.168.10.42/32,1.2.3.4

and, in practice, the later behaves the same as:

    server=/168.192.in-addr.arpa/1.2.3.4

This strange behaviour is fixed by accepting /32 CIDR prefixes as a
valid value. Any other value will still be considered the same as /16.
2017-03-06 22:14:50 +00:00
Simon Kelley
864913c0f3 Man page typo. 2017-02-28 18:07:18 +00:00
Simon Kelley
13dee6f49e Compilation warning fixes. 2017-02-28 16:51:58 +00:00
Simon Kelley
62f9c0d470 Fix CNAME wildcard in auth-mode.
A domain can only have a CNAME if it has not other records.

Don't return a CNAME when there are records of other types on the name.
2017-02-19 23:07:01 +00:00
Simon Kelley
54bb3639d4 Update FAQ to fix a couple of dead links.
Thanks to Federico Bianchi for reporting this.
2017-02-19 22:13:36 +00:00
Simon Kelley
fca008d8d4 Make --bogus-priv apply to IPv6. 2017-02-19 18:50:41 +00:00
klemens
43517fcaf5 Spelling fixes. 2017-02-19 15:53:37 +00:00
Simon Kelley
88a77a78ad Implement RFC-6842 (Client-ids in DHCP replies.) 2017-02-11 17:02:02 +00:00
Hannu Nyman
3e2496fb16 Decrease the number of individual sites listed in log.
By default 30 first servers are listed individually to system log, and
then a count of the remaining items. With e.g. a NXDOMAIN based adblock
service, dnsmasq lists 30 unnecessary ad sites every time when dnsmasq
evaluates the list. But the actual nameservers in use are evaluated last
and are not displayed as they get included in the "remaining items" total.

Handle the "local addresses only" separately and list only a few of them.
Remove the "local addresses only" from the general count.
2017-02-11 13:44:08 +00:00
Simon Kelley
05da782f8f Add forthcoming 2017 root zone trust anchor to trust-anchors.conf. 2017-02-10 21:32:45 +00:00
Simon Kelley
361dfe5158 Improve connection handling when talking to TCP upsteam servers.
Specifically, be prepared to open a new connection when we
want to make multiple queries but the upstream server accepts
fewer queries per connection.
2017-02-10 21:12:30 +00:00
Baptiste Jonglez
68f6312d4b Stop treating SERVFAIL as a successful response from upstream servers.
This effectively reverts most of 51967f9807 ("SERVFAIL is an expected
error return, don't try all servers.") and 4ace25c5d6 ("Treat REFUSED (not
SERVFAIL) as an unsuccessful upstream response").

With the current behaviour, as soon as dnsmasq receives a SERVFAIL from an
upstream server, it stops trying to resolve the query and simply returns
SERVFAIL to the client.  With this commit, dnsmasq will instead try to
query other upstream servers upon receiving a SERVFAIL response.

According to RFC 1034 and 1035, the semantic of SERVFAIL is that of a
temporary error condition.  Recursive resolvers are expected to encounter
network or resources issues from time to time, and will respond with
SERVFAIL in this case.  Similarly, if a validating DNSSEC resolver [RFC
4033] encounters issues when checking signatures (unknown signing
algorithm, missing signatures, expired signatures because of a wrong
system clock, etc), it will respond with SERVFAIL.

Note that all those behaviours are entirely different from a negative
response, which would provide a definite indication that the requested
name does not exist.  In our case, if an upstream server responds with
SERVFAIL, another upstream server may well provide a positive answer for
the same query.

Thus, this commit will increase robustness whenever some upstream servers
encounter temporary issues or are misconfigured.

Quoting RFC 1034, Section 4.3.1. "Queries and responses":

    If recursive service is requested and available, the recursive response
    to a query will be one of the following:

       - The answer to the query, possibly preface by one or more CNAME
         RRs that specify aliases encountered on the way to an answer.

       - A name error indicating that the name does not exist.  This
         may include CNAME RRs that indicate that the original query
	  name was an alias for a name which does not exist.

       - A temporary error indication.

Here is Section 5.2.3. of RFC 1034, "Temporary failures":

    In a less than perfect world, all resolvers will occasionally be unable
    to resolve a particular request.  This condition can be caused by a
    resolver which becomes separated from the rest of the network due to a
    link failure or gateway problem, or less often by coincident failure or
    unavailability of all servers for a particular domain.

And finally, RFC 1035 specifies RRCODE 2 for this usage, which is now more
widely known as SERVFAIL (RFC 1035, Section 4.1.1. "Header section format"):

    RCODE           Response code - this 4 bit field is set as part of
                    responses.  The values have the following
                    interpretation:
                    (...)

                    2               Server failure - The name server was
                                    unable to process this query due to a
                                    problem with the name server.

For the DNSSEC-related usage of SERVFAIL, here is RFC 4033
Section 5. "Scope of the DNSSEC Document Set and Last Hop Issues":

    A validating resolver can determine the following 4 states:
    (...)

    Insecure: The validating resolver has a trust anchor, a chain of
       trust, and, at some delegation point, signed proof of the
       non-existence of a DS record.  This indicates that subsequent
       branches in the tree are provably insecure.  A validating resolver
       may have a local policy to mark parts of the domain space as
       insecure.

    Bogus: The validating resolver has a trust anchor and a secure
       delegation indicating that subsidiary data is signed, but the
       response fails to validate for some reason: missing signatures,
       expired signatures, signatures with unsupported algorithms, data
       missing that the relevant NSEC RR says should be present, and so
       forth.
    (...)

    This specification only defines how security-aware name servers can
    signal non-validating stub resolvers that data was found to be bogus
    (using RCODE=2, "Server Failure"; see [RFC4035]).

Notice the difference between a definite negative answer ("Insecure"
state), and an indefinite error condition ("Bogus" state).  The second
type of error may be specific to a recursive resolver, for instance
because its system clock has been incorrectly set, or because it does not
implement newer cryptographic primitives.  Another recursive resolver may
succeed for the same query.

There are other similar situations in which the specified behaviour is
similar to the one implemented by this commit.

For instance, RFC 2136 specifies the behaviour of a "requestor" that wants
to update a zone using the DNS UPDATE mechanism.  The requestor tries to
contact all authoritative name servers for the zone, with the following
behaviour specified in RFC 2136, Section 4:

    4.6. If a response is received whose RCODE is SERVFAIL or NOTIMP, or
    if no response is received within an implementation dependent timeout
    period, or if an ICMP error is received indicating that the server's
    port is unreachable, then the requestor will delete the unusable
    server from its internal name server list and try the next one,
    repeating until the name server list is empty.  If the requestor runs
    out of servers to try, an appropriate error will be returned to the
    requestor's caller.
2017-02-06 21:09:11 +00:00
Josh Soref
730c6745f0 Comprehensive spelling/typo fixes.
Thanks to Josh Soref for generating these fixes.
2017-02-06 16:14:04 +00:00
Simon Kelley
d42d4706bb Make --localise-queries apply to names from --interface-name. 2017-02-02 16:52:06 +00:00
Simon Kelley
0740e43e20 Fix rrfilter bug leading to malformed replies.
Bug tickled by Nominum upstream when DNSSEC enabled, due to
unusual order of RRs in reply from upstream server.
2017-01-26 18:02:54 +00:00
Simon Kelley
903df07bcb Detect and error loops in --cname configuration. 2017-01-19 17:22:00 +00:00
Simon Kelley
0ef1334d78 Tweak start-up logging 2017-01-15 16:42:39 +00:00
Reiter Wolfgang
5eb9dde09c Fix getsockname error return check. 2017-01-08 17:39:06 +00:00
Simon Kelley
ae3154aca9 Additional syntax check on MAC wildcards. 2017-01-01 22:59:46 +00:00
Simon Kelley
3ebe62d1b7 Merge branch 'master' of ssh://thekelleys.org.uk/var/cache/git/dnsmasq 2017-01-01 22:42:31 +00:00
ZHAO Yu
f89cae3ecf Add DNSMASQ_REQUESTED_OPTIONS env-var to lease change script. 2016-12-22 22:32:31 +00:00
Simon Kelley
09b768efa4 Bump TCP connection backlog from 5 to 32. 2016-12-22 22:16:58 +00:00
Simon Kelley
a1d973f987 Allow multiple CNAMEs in a single --cname= option. 2016-12-22 22:09:50 +00:00
Simon Kelley
0682b7795c Debian packaging update. 2016-12-14 17:59:45 +00:00
Simon Kelley
b637d7815d Allow wildcard CNAME records in authoritative zones. 2016-12-13 16:44:11 +00:00
Kevin Darbyshire-Bryant
7ac9ae1125 Compile time option NO_ID
Some consider it good practice to obscure software version numbers to
clients.  Compiling with -DNO_ID removes the *.bind info structure.
This includes: version, author, copyright, cachesize, cache insertions,
evictions, misses & hits, auth & servers.
2016-09-09 20:52:08 +01:00
Simon Kelley
c6af3a32f2 Support cross-builds in Debian packaging. 2016-08-31 22:38:48 +01:00
Simon Kelley
16800ea072 Fix crash introduced in 2675f20615 2016-08-30 23:07:06 +01:00
Simon Kelley
b5e33ae53a Log ipset errors. 2016-08-28 21:26:42 +01:00
Peter Wu
3c0c1111fe Improve --address and --ipset docs, fix --help output
Manual page: clarify that the --address and --ipset options take one or
more domains rather than just two. Clarify that --ipset puts addresses
in all ipsets, it is not a 1:1 mapping from addresses.

Also increase the width for options output in --help, some options were
truncated leading to confusing output. Almost all options and
descriptions are now within the 120 colums limit.
2016-08-28 20:53:09 +01:00
Beniamino Galvani
2675f20615 Handle binding upstream servers to an interface
(--server=1.2.3.4@eth0) when the named interface
is destroyed and recreated in the kernel.
2016-08-28 20:44:05 +01:00
Simon Kelley
e94ad0fa01 Suppress useless warning about DHCP packets of interfaces without addresses.
This only makes sense for interfaces which we're configured to listen on.
Thanks to Andrew Shadura for bug report.
2016-08-28 18:09:17 +01:00
Simon Kelley
396750cef5 Refactor openBSD pftables code to remove blatant copyright violation. 2016-08-13 22:34:11 +01:00
Simon Kelley
6c45519e18 2.76-3 debian release. 2016-08-13 21:49:17 +01:00
Simon Kelley
6d95099c56 Handle v4-mapped IPv6 addresses sanely for --synth-domain. 2016-08-11 23:38:54 +01:00
Simon Kelley
c8328ecde8 Bump auth zone serial when reloading /etc/hosts and friends. 2016-08-05 16:54:58 +01:00
Mathias Kresin
094bfaeb4f auth-zone: allow to exclude ip addresses from answer. 2016-07-24 14:15:22 +01:00
Simon Kelley
bf4e62c19e Compile-time check on buffer sizes for leasefile parsing code. 2016-07-22 21:37:59 +01:00
Simon Kelley
6b1c464d6d Don't reset packet length on transmission, in case of retransmission. 2016-07-22 20:59:16 +01:00
Simon Kelley
fa78573778 Zero packet buffers before building output, to reduce risk of information leakage. 2016-07-22 20:56:01 +01:00
Simon Kelley
cd2ddb9904 Debian systemd bugfix. 2016-07-16 22:23:49 +01:00
Simon Kelley
9bb3998da4 Merge 2.76-1.2 Debian NMU. 2016-07-16 22:06:01 +01:00
Simon Kelley
d6dce53e08 malloc(); memset() -> calloc() for efficiency. 2016-07-11 21:34:31 +01:00
Kevin Darbyshire-Bryant
06093a9a84 Fix problem with --dnssec-timestamp
whereby receipt of SIGHUP would erroneously engage timestamp checking.
2016-07-11 21:03:27 +01:00
Ivan Kokshaysky
1d07667ac7 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.
2016-07-11 18:36:05 +01:00
Simon Kelley
591ed1e905 Fix bad behaviour with some DHCP option arrangements.
The check that there's enough space to store the DHCP agent-id
at the end of the packet could succeed when it should fail
if the END option is in either of the oprion-overload areas.
That could overwrite legit options in the request and cause
bad behaviour. It's highly unlikely that any sane DHCP client
would trigger this bug, and it's never been seen, but this
fixes the problem.

Also fix off-by-one in bounds checking of option processing.
Worst case scenario on that is a read one byte beyond the
end off a buffer with a crafted packet, and maybe therefore
a SIGV crash if the memory after the buffer is not mapped.

Thanks to Timothy Becker for spotting these.
2016-07-11 18:18:42 +01:00
Kristjan Onu
907efeb2dc Manpage typo. 2016-07-10 22:37:57 +01:00
Simon Kelley
beea62cb66 Update .gitignore for change contrib/wrt -> contrib/lease-tools. 2016-07-10 22:13:57 +01:00
Simon Kelley
5874f3e922 Fix editing error on man page.
Thanks to Eric Westbrook for spotting this.
2016-07-10 22:12:08 +01:00
zeha@debian.org
04cb536f16 Merge 2.67-1.1 Debian NMU. 2016-07-06 22:30:10 +01:00
Simon Kelley
8ee8524016 Bump Debian version. 2016-07-06 22:23:22 +01:00
Simon Kelley
ce7845bf54 Check return of expand() always. 2016-07-06 21:42:27 +01:00
Simon Kelley
d55f81f5fd Zero newly malloc'ed memory. 2016-07-06 21:33:56 +01:00
Simon Kelley
294d36df47 Calculate length of TFTP error reply correctly. 2016-07-06 21:30:25 +01:00
Simon Kelley
f186bdcbc7 Fix debian changelog. 2016-05-18 15:51:54 +01:00
Jan Psota
ed1bd54b5c Update Polish translation.
Thanks to Jan Psota.
2016-05-18 15:16:29 +01:00
Simon Kelley
da2cad4b14 Doc about --pxe-service basename change into CHANGELOG. 2016-05-18 15:14:08 +01:00
Simon Kelley
0a4a04969d Final PXE tweak, and release-note to reflect changes. 2016-05-15 20:13:45 +01:00
Sergey Nechaev
45cb8dd9be Stricter command line args validation to dhcp_release6. 2016-05-14 21:36:15 +01:00
Simon Kelley
88b09aaddc Merge messages into translation files. 2016-05-14 20:56:02 +01:00
Simon Kelley
fe71bba356 Tweak UEFI workaround code. 2016-05-14 20:50:45 +01:00
Simon Kelley
cbc100fc81 Tweak CSAs affected by UEFI PXE workaround code. 2016-05-11 22:17:18 +01:00
Simon Kelley
68bea10bbf Fix error in PXE arch names and add ARM32 and ARM64. 2016-05-11 22:15:06 +01:00
Simon Kelley
8628cd603f Workaround for UEFI PXE boot problems. 2016-05-10 17:31:48 +01:00
Neil Jerram
ff325644c7 Fix for DHCP in transmission interface when --bridge-interface in use.
From f3d832b41f44c856003517c583fbd7af4dca722c Mon Sep 17 00:00:00 2001
From: Neil Jerram <Neil.Jerram@metaswitch.com>
Date: Fri, 8 Apr 2016 19:23:47 +0100
Subject: [PATCH] Fix DHCPv4 reply via --bridge-interface alias interface

Sending a DHCPv4 reply through a --bridge-interface alias interface
was inadvertently broken by

  commit 65c7212000
  Author: Lung-Pin Chang <changlp@cs.nctu.edu.tw>
  Date:   Thu Mar 19 23:22:21 2015 +0000

      dhcp: set outbound interface via cmsg in unicast reply

        If multiple routes to the same network exist, Linux blindly picks
        the first interface (route) based on destination address, which might not be
        the one we're actually offering leases. Rather than relying on this,
        always set the interface for outgoing unicast DHCP packets.

because in the aliasing case, iface_index is changed from the index of
the interface on which the packet was received, to be the interface
index of the 'bridge' interface (where the DHCP context is expected to
be defined, and so needs to be looked up).

For the cmsg code that the cited commit added, we need the original
iface_index; so this commit saves that off before the aliasing code
can change it, as rcvd_iface_index, and then uses rcvd_iface_index
instead of iface_index for the cmsg code.
2016-05-03 22:49:46 +01:00
Simon Kelley
b97026035e Limit number of upstream nameservers when logging configuration. 2016-05-03 22:34:06 +01:00
Simon Kelley
69cbf78bb6 Add contrib/lease-tools/dhcp_release6 2016-05-03 21:33:38 +01:00
Simon Kelley
c6cdf6bbee Move dhcp_release and dhcp_lease_time to contrib/lease_tools. 2016-05-03 21:14:14 +01:00
Simon Kelley
09217a1a87 Add --help to manpage . 2016-05-03 17:04:35 +01:00
Simon Kelley
332c41e2ff Debian init.d script fix. 2016-05-01 22:36:46 +01:00
Simon Kelley
2c0c36f54b Fix problem with IPv6 in new ARP-search code. 2016-05-01 20:57:08 +01:00
Simon Kelley
d6b749af91 Fix typo in SDBM hash function.
Thanks to Luis Carvalho for spotting the error.
2016-04-25 17:05:15 +01:00
Simon Kelley
14ffa0770b Fix init of per server EDNS UDP packet size. 2016-04-25 16:36:44 +01:00
Simon Kelley
87985855ad Remove pre-existing EDNS0_OPTION_NOMDEVICEID if MAC address unknown. 2016-04-25 15:33:30 +01:00
Simon Kelley
a2bc254bed Check return-code of inet_pton when parsing DHCPv4 options. 2016-04-21 22:41:31 +01:00
Simon Kelley
a7b27e84fa NULL pointer check. 2016-03-16 19:11:52 +00:00
Simon Kelley
529b030228 Tidy code. 2016-03-16 19:00:45 +00:00
Simon Kelley
4caa86dd7d Tidy. 2016-03-16 18:44:16 +00:00
Simon Kelley
e1abeeeec2 Fix memory leak in inotify code. 2016-03-16 18:12:35 +00:00
Simon Kelley
40205a053e Bound hash-iterations in DNSSEC NSEC3 checking. 2016-03-14 21:24:00 +00:00
Simon Kelley
b8ac466209 Tidy code. 2016-03-10 18:40:53 +00:00
Simon Kelley
d1377fa3c4 Account for TFTP packet headers in IPv6 correctly. 2016-03-04 21:32:21 +00:00
Simon Kelley
fa79466c2a Tighten syntax checking for dhcp-range and clarify man page. 2016-03-03 20:33:54 +00:00
Simon Kelley
a93bd4b016 Fix broken DNSMASQ_USER<x> envvars in script with more than one class. 2016-03-01 18:58:01 +00:00
Simon Kelley
407a1f3e95 Tidy parsing code. 2016-03-01 17:06:07 +00:00
Simon Kelley
4b6af5d53f Fix pointer declaration botch. 2016-03-01 17:00:26 +00:00
Simon Kelley
7aa3f9af66 format fix. 2016-03-01 16:32:30 +00:00
Simon Kelley
f7cf749943 Check return code from open() 2016-03-01 16:19:23 +00:00
Simon Kelley
aa300f7167 Fix typo in last commit. 2016-03-01 15:19:13 +00:00
Simon Kelley
c7f3bd2ac8 Replace incoming EDNS0_OPTION_NOMDEVICEID and EDNS0_OPTION_NOMCPEID options. 2016-02-28 21:48:34 +00:00
Simon Kelley
22fe2fd038 Fix --add-subnet when returning empty or default subnet. 2016-02-28 17:07:10 +00:00
Simon Kelley
7480aeffc8 Apply ceiling of lease length to TTL when --dhcp-ttl in use. 2016-02-26 21:58:20 +00:00
Simon Kelley
bec366b404 Add --tftp-mtu option. 2016-02-24 22:03:26 +00:00
Simon Kelley
e06e6e34bf Update CHANGELOG. 2016-02-24 21:26:16 +00:00
Simon Kelley
832e47beab Add --dhcp-ttl option. 2016-02-24 21:24:45 +00:00
Simon Kelley
df3d54f776 Add TTL parameter to --host-record and --cname. 2016-02-24 21:03:38 +00:00
Simon Kelley
22c0f4fe87 Fix previous commit. 2016-02-17 22:12:31 +00:00
Simon Kelley
9e4cf47ee8 Add --add-mac=text option. 2016-02-17 20:26:32 +00:00
Simon Kelley
fdc97e1383 Avoid divide-by-zero when dhcp-range is a whole /64 2016-02-13 17:47:17 +00:00
S L
a18bf3149a Avoid losing timer when deleting a RA context. 2016-02-12 17:36:20 +00:00
Simon Kelley
1566bacb2c Fix breakage in ARP code when IPV6 support not compiled in. 2016-02-05 14:48:25 +00:00
Simon Kelley
e6e751b066 Make names of ARP script actions consistent. 2016-02-01 17:59:07 +00:00
Andy Stormont
8de875f0fb Fix FTBFS on illumos 2016-02-01 12:07:57 +00:00
Chris Novakovic
4ace25c5d6 Treat REFUSED (not SERVFAIL) as an unsuccessful upstream response
Commit 51967f9807 began treating SERVFAIL
as a successful response from an upstream server (thus ignoring future
responses to the query from other upstream servers), but a typo in that
commit means that REFUSED responses are accidentally being treated as
successful instead of SERVFAIL responses.

This commit corrects this typo and provides the behaviour intended by
commit 51967f9: SERVFAIL responses are considered successful (and will
be sent back to the requester), while REFUSED responses are considered
unsuccessful (and dnsmasq will wait for responses from other upstream
servers that haven't responded yet).
2016-01-25 21:54:35 +00:00
Simon Kelley
1e5051228d Final form of configuration for EDNS0 MAC-address code. 2016-01-25 21:29:23 +00:00
Hans Dedecker
926332a764 Add --max-port config option. 2016-01-23 10:48:12 +00:00
Simon Kelley
d05dd58de1 Fix wrong reply to simple name when --domain-needed set and no servers configured.
Also return REFUSED and not SERVFAIL when out of memory.

Thanks to Allain Legacy for problem report.
2016-01-19 21:23:30 +00:00
Simon Kelley
f7443d76f7 Fix problems in last commit when DNSSEC not enabled. 2016-01-19 20:29:57 +00:00
Simon Kelley
f344dbc622 Complete DNSSEC server-selection code and set conntrack on DNSSEC queries. 2016-01-18 18:11:54 +00:00
Simon Kelley
f4d0c660ca Fix sporadic crash in find_mac() - hwlen must be zero for empty entries. 2016-01-18 12:51:08 +00:00
Simon Kelley
1801a29226 Fix botch in forward.c flags code.
Thanks to Matthias Anfree for spotting this.
2016-01-17 21:53:57 +00:00
Simon Kelley
92be34a407 Complete work to allow DNSSEC validation with private DNS servers. 2016-01-16 18:39:54 +00:00
Simon Kelley
bb58f63ce5 arp.c tidy up. 2016-01-14 19:23:10 +00:00
Simon Kelley
367341f745 Disable DNSSEC for server=/domain/.. servers unless trust-anchor provided. 2016-01-12 15:58:23 +00:00
André Glüpker
eddf365284 Fix bad cache-size calculation when hosts-file read fails. 2016-01-12 12:54:17 +00:00
Simon Kelley
a63b8b89e6 DNSSEC: Handle non-root trust anchors, and check we have a root trust anchor. 2016-01-12 11:28:58 +00:00
Simon Kelley
5757371d43 Inhibit DNSSEC validation when forwarding to private servers for a domain.
server=/example.com/<ip-of-server>

The rationale is that the chain-of-trust will not be complete to
private servers. If it was, it would not be necessary to access the
server direct.
2016-01-11 22:50:00 +00:00
Simon Kelley
b633de9413 Fix FTBFS when scripts excluded at compilation time. 2016-01-06 22:51:17 +00:00
Simon Kelley
c49778df4a Update copyright notices. Happy new year! 2016-01-06 18:52:33 +00:00
Simon Kelley
53a9173fc0 Handle building with script support enabled and DHCP disabled. 2016-01-06 17:59:13 +00:00
92 changed files with 8557 additions and 5875 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
VERSION export-subst

5
.gitignore vendored
View File

@@ -4,8 +4,9 @@ src/dnsmasq.pot
src/dnsmasq
src/dnsmasq_baseline
src/.copts_*
contrib/wrt/dhcp_lease_time
contrib/wrt/dhcp_release
contrib/lease-tools/dhcp_lease_time
contrib/lease-tools/dhcp_release
contrib/lease-tools/dhcp_release6
debian/base/
debian/daemon/
debian/files

693
CHANGELOG

File diff suppressed because it is too large Load Diff

View File

@@ -56,7 +56,7 @@ release 0.95 Major rewrite: remove calls to gethostbyname() and talk
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 embarrasing thinko in cache linked-list code.
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
@@ -78,7 +78,7 @@ release 0.98 Some enhancements and bug-fixes.
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 compliers with unsigned char.
(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
@@ -88,7 +88,7 @@ release 0.991 Added -b flag: when set causes dnsmasq to always answer
Fixed a bug which stopped dnsmasq working on a box with
two or more interfaces with the same IP address.
Fixed cacheing of CNAMEs. Previously, a CNAME which pointed
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.
@@ -191,7 +191,7 @@ release 1.1 Added --user argument to allow user to change to
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 suppored. Dnsmasq can
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.
@@ -214,7 +214,7 @@ release 1.3 Some versions of the Linux kernel return EINVAL rather
starting, rather than after the first query - principle
of least surprise applies here.
release 1.4 Fix a bug with DHPC lease parsing which broke in
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
@@ -258,7 +258,7 @@ 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 supplimentary groups.
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.)
@@ -297,7 +297,7 @@ release 1.9 Fixes to rpm .spec files.
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
embeded routers, and that's the point really. Thanks to
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
@@ -319,12 +319,12 @@ release 1.9 Fixes to rpm .spec files.
uClinux. Thanks to Matthew Natalier for uClinux stuff.
release 1.10 Log warnings if resolv.conf or dhcp.leases are not
accessable for any reason, as suggested by Hinrich Eilts.
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 instuctions into setup.html.
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
@@ -346,7 +346,7 @@ release 1.10 Log warnings if resolv.conf or dhcp.leases are not
Added -S option to directly specify upstream servers and
added ability to direct queries for specific domains to
specfic servers. Suggested by Jens Vonderheide.
specific servers. Suggested by Jens Vonderheide.
Upgraded random ID generation - patch from Rob Funk.
@@ -386,13 +386,13 @@ release 1.11 Actually implement the -R flag promised in the 1.10 man page.
names in /etc/hosts -suggestion from Phil Harman.
Always return a zero time-to-live for names derived from
DHCP which stops anthing else caching these
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 compliation on
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.
@@ -471,7 +471,7 @@ release 1.14 Fixed man page description of -b option which confused
/etc/resolv.conf.
(Thanks to Klaas Teschauer)
Check that recieved queries have only rfc1035-legal characters
Check that received queries have only rfc1035-legal characters
in them. This check is mainly to avoid bad strings being
sent to syslog.
@@ -549,7 +549,7 @@ release 1.16 Allow "/" characters in domain names - this fixes
release 1.17 Fixed crash with DHCP hostnames > 40 characters.
Fixed name-comparision routines to not depend on Locale,
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'.
@@ -574,7 +574,7 @@ release 1.18 Added round-robin DNS for names which have more than one
forwarded because -D is in effect, return NXDOMAIN not
an empty reply.
Add code to return the software version in repsonse to the
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.
@@ -635,7 +635,7 @@ release 2.0
dynamic allocation.
Allow dhcp-host options for the same host with different
IP adresses where the correct one will be selected for
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
@@ -674,7 +674,7 @@ release 2.1
Fix unaligned access warnings on BSD/Alpha.
Allow empty DHCP options, like so: dhpc-option=44
Allow empty DHCP options, like so: dhcp-option=44
Allow single-byte DHCP options like so: dhcp-option=20,1
@@ -745,7 +745,7 @@ release 2.3
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 desychronise lease
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
@@ -838,7 +838,7 @@ release 2.4
by Chad Skeeters.
Fixed bug in /etc/ethers parsing code triggered by tab
characters. Qudos to Dag Wieers for hepling to nail that
characters. Kudos to Dag Wieers for helping to nail that
one.
Added "bind-interfaces" option correctly.
@@ -975,7 +975,7 @@ release 2.8
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 agains vendor class
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
@@ -997,7 +997,7 @@ release 2.8
Add checks against DHCP clients which return zero-length
hostnames. This avoids the potential lease-loss problems
reffered to above. Also, if a client sends a hostname when
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.
@@ -1019,7 +1019,7 @@ release 2.9
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 prefered for the next query. This should
then becomes preferred for the next query. This should
improve reliability without generating significant extra
upstream load.
@@ -1027,7 +1027,7 @@ release 2.9
unqualified domains introduced in version 2.8
Allow fallback to "bind-interfaces" at runtime: Some
verions of *BSD seem to have enough stuff in the header
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.
@@ -1049,7 +1049,7 @@ release 2.9
first name found is now returned for reverse lookups,
rather than all of them.
Add back fatal errors when nonexistant
Add back fatal errors when nonexistent
interfaces or interface addresses are given but only in
"bind-interfaces" mode. Principle of least surprise applies.
@@ -1193,7 +1193,7 @@ version 2.14
version 2.15
Fixed NXDOMAIN/NODATA confusion for locally known
names. We now return a NODATA reponse for names which are
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
@@ -1229,7 +1229,7 @@ version 2.16
Set NONBLOCK on all listening sockets to workaround non-POSIX
compliance in Linux 2.4 and 2.6. This fixes rare hangs which
occured when corrupted packets were received. Thanks to
occurred when corrupted packets were received. Thanks to
Joris van Rantwijk for chasing that down.
Updated config.h for NetBSD. Thanks to Martin Lambers.
@@ -1297,7 +1297,7 @@ version 2.18
interfaces with more than one IPv6 address. Thanks to
Martin Pels for help with that.
Fix problems which occured when more than one dhcp-range
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.
@@ -1314,7 +1314,7 @@ version 2.19
Thanks to Richard Atterer for the bug report.
Check for under-length option fields in DHCP packets, a
zero length client-id, in particluar, could seriously
zero length client-id, in particular, could seriously
confuse dnsmasq 'till now. Thanks to Will Murname for help
with that.
@@ -1389,7 +1389,7 @@ version 2.21
recursive queries.
Fix DHCP address allocation problem when netid tags are in
use. Thanks to Will Murnane for the bug report and
use. Thanks to Will Murname for the bug report and
subsequent testing.
Add an additional data section to the reply for MX and SRV
@@ -1505,7 +1505,7 @@ version 2.23
from dnsmasq --version. Thanks to Dirk Schenkewitz for
the suggestion.
Fix pathalogical behaviour when a broken client keeps sending
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
@@ -1593,7 +1593,7 @@ version 2.24
than one dhcp-range is available. Thanks to Sorin Panca
for help chasing this down.
Added more explict error mesages to the hosts file and
Added more explicit error messages to the hosts file and
ethers file reading code. Markus Kaiserswerth suffered to
make this happen.
@@ -1617,7 +1617,7 @@ version 2.25
Fixed Suse spec file - thanks to Steven Springl.
Fixed DHCP bug when two distict subnets are on the same
Fixed DHCP bug when two distinct subnets are on the same
physical interface. Thanks to Pawel Zawora for finding
this and suggesting the fix.
@@ -1740,7 +1740,7 @@ version 2.28
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 occured in kernels at least as
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
@@ -1761,7 +1761,7 @@ version 2.28
Eric House and Eric Spakman for help in chasing this down.
Tolerate configuration screwups which lead to the DHCP
server attemping to allocate its own address to a
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.
@@ -2273,7 +2273,7 @@ version 2.40
this.
Use client-id as hash-seed for DHCP address allocation
with Firewire and Infiniband, as these don't supply an MAC
with Firewire and InfiniBand, as these don't supply an MAC
address.
Tweaked TFTP file-open code to make it behave sensibly
@@ -2307,7 +2307,7 @@ version 2.40
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 whould have been
situation, the whole name would have been
rejected. Thanks to Jima for the patch.
Handle EINTR returns from wait() correctly and reap
@@ -2319,7 +2319,7 @@ version 2.40
leases file and passed to the lease-change
script. Suggestion from Ben Voigt.
Re-run the lease chamge script with an "old" event for
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
@@ -2417,7 +2417,7 @@ version 2.41
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
whne one existed.) This fixes problems with the Sony Ericsson
when one existed.) This fixes problems with the Sony Ericsson
K610i phone. Thanks to Hakon Stordahl for finding and
fixing this.
@@ -2476,7 +2476,7 @@ version 2.42
Fix OS detection logic to cope with GNU/FreeBSD.
Fix unitialised variable in DBus code - thanks to Roy
Fix uninitialised variable in DBus code - thanks to Roy
Marples.
Fix network enumeration code to work on later NetBSD -

88
FAQ
View File

@@ -59,7 +59,7 @@ A: Yes, there is explicit support for *BSD and MacOS X and Solaris.
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
dosen't work: dnsmasq seems not to use the nameservers in the order
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
@@ -144,19 +144,19 @@ 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.]
Versign run the .com and .net top-level-domains. They have just
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 Versign which runs a web
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 Versign brokeness by run a command like
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 wierd one
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
@@ -180,7 +180,7 @@ A: There are a couple of configuration gotchas which have been
whilst the ISC one works.
The first thing to check is the broadcast address set for the
ethernet interface. This is normally the adddress on the connected
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
@@ -205,7 +205,7 @@ A: By default, none of the DHCP clients send the host-name when asking
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 lastest dhcpcd packages _do_ send
/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
@@ -240,7 +240,7 @@ 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 bizzare contraints and select the
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
@@ -252,10 +252,10 @@ A: Dnsmasq from v2.63 can operate in one of three different "networking
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 recieve all the packets sent to the server on
::). 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 recieved and
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.
@@ -276,7 +276,7 @@ A: Dnsmasq from v2.63 can operate in one of three different "networking
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 inferfaces. We will deal with these in order.
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
@@ -313,15 +313,25 @@ 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 subcribe to email alerts when
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: See http://www.isc.org/files/auth.html - that's
for the ISC daemon, but the same applies to dnsmasq.
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?
@@ -349,18 +359,64 @@ A: By default, the identity of a machine is determined by using 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 sumarily abandon a
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
@@ -488,7 +544,7 @@ 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
symtoms have beeen variously reported as continual DHCPINFORM
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

View File

@@ -1,4 +1,4 @@
# dnsmasq is Copyright (c) 2000-2015 Simon Kelley
# 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
@@ -55,10 +55,12 @@ dbus_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG)
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.1`
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.1`
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`
@@ -82,8 +84,8 @@ hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
all : $(BUILDDIR)
@cd $(BUILDDIR) && $(MAKE) \
top="$(top)" \
build_cflags="$(version) $(dbus_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
build_libs="$(dbus_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs)" \
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 :
@@ -106,8 +108,8 @@ all-i18n : $(BUILDDIR)
@cd $(BUILDDIR) && $(MAKE) \
top="$(top)" \
i18n=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
build_cflags="$(version) $(dbus_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags) `$(PKG_CONFIG) --cflags libidn`" \
build_libs="$(dbus_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) `$(PKG_CONFIG) --libs libidn`" \
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; \
@@ -123,7 +125,7 @@ merge :
echo -n msgmerge $(PO)/$$f && $(MSGMERGE) --no-wrap -U $(PO)/$$f $(BUILDDIR)/dnsmasq.pot; \
done
# Cannonicalise .po file.
# 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;
@@ -142,7 +144,7 @@ bloatcheck : $(BUILDDIR)/dnsmasq_baseline mostly_clean all
$(top)/bld/bloat-o-meter dnsmasq_baseline dnsmasq; \
size dnsmasq_baseline dnsmasq
# rules below are targets in recusive makes with cwd=$(BUILDDIR)
# rules below are targets in recursive makes with cwd=$(BUILDDIR)
$(copts_conf): $(hdrs)
@rm -f *.o .copts_*

View File

@@ -11,11 +11,18 @@
# 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 $1/.git ] || grep '^gitdir:' $1/.git >/dev/null 2>&1); then
cd $1; git describe | sed 's/^v//'
([ -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.
# unsubstituted VERSION, but no git available.
echo UNKNOWN
else
vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep ^v[0-9]`

View File

@@ -22,7 +22,7 @@ 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 dnsmaq, reboot or use the command:
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:

View File

@@ -1,9 +1,9 @@
This is a patch against SuSEfirewall2-3.1-206 (SuSE 9.x and older)
It fixes the depancy from the dns daemon name 'named'
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 allways 'named'
The SuSE people think the name of the dns server will always 'named'
--- /sbin/SuSEfirewall2.orig 2004-01-23 13:30:09.000000000 +0100

View File

@@ -13,10 +13,10 @@ 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
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,
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
@@ -40,7 +40,7 @@ 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
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.

View File

@@ -55,7 +55,7 @@ Index: src/dnsmasq.c
}
@@ -434,7 +433,7 @@
/* lose the setuid and setgid capbilities */
/* lose the setuid and setgid capabilities */
if (capset(hdr, data) == -1)
{
- send_event(err_pipe[1], EVENT_CAP_ERR, errno);

View File

@@ -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

View File

@@ -168,7 +168,7 @@ int main(int argc, char **argv)
*(p++) = 1;
*(p++) = DHCPINFORM;
/* Explicity request the lease time, it won't be sent otherwise:
/* Explicitly request the lease time, it won't be sent otherwise:
this is a dnsmasq extension, not standard. */
*(p++) = OPTION_REQUESTED_OPTIONS;
*(p++) = 1;

View File

@@ -117,7 +117,7 @@ static ssize_t netlink_recv(int fd)
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
/* 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)
{

View File

@@ -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>.

View File

@@ -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);
}

View File

@@ -3,7 +3,7 @@
# 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 seperated with a
# 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".

View File

@@ -1,6 +1,6 @@
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 adresses are searched for in the dnsmasq query log.
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

View File

@@ -5,10 +5,10 @@
# 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 ou more than the mones from reverse
# usually tell you more than the ones from reverse
# lookups.
#
# This has been tested on debian and asuswrt. Plese
# This has been tested on debian and asuswrt. Please
# report successful tests on other platforms.
#
# Author: Joachim Zobel <jz-2014@heute-morgen.de>

View File

@@ -2,7 +2,7 @@ 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 acceptible
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

View File

@@ -1,5 +1,5 @@
This is the README for the DNSmasq webmin module.
This is the README for the Dnsmasq webmin module.
Problems:
@@ -48,7 +48,7 @@ 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 usefull)
(rather the opposite - I'd be pleased someone found it useful)
Cheers,
Neil Fisher <neil@magnecor.com.au>

View File

@@ -1,6 +0,0 @@
CFLAGS?= -O2 -Wall -W
all: dhcp_release dhcp_lease_time
clean:
rm -f *~ *.o core dhcp_release dhcp_lease_time

View File

@@ -4,7 +4,7 @@ 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 fileystems read-only after boot,
*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:
@@ -62,7 +62,7 @@ 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
ammended, probably by changing it to read the output of
amended, probably by changing it to read the output of
`lease_update init` instead.

97
debian/changelog vendored
View File

@@ -1,21 +1,88 @@
dnsmasq (2.77-1) unstable; urgency=low
* New upstream.
* Don't register as a resolvconf source when config file
includes port=0 to disable DNS.
* Handle gratuitous format change in /usr/share/dns/root.ds
(closes: #858506) (closes: #860064)
* Add lsb-base dependancy.
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 11 Apr 2017 14:19:20 +0000
dnsmasq (2.76-5) unstable; urgency=medium
* Nail libnettle dependency to avoid ABI incompatibility.
(closes: #846642)
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 14 Dec 2016 17:58:10 +0000
dnsmasq (2.76-4.1) unstable; urgency=medium
* Non-maintainer upload.
* Add two upstream patches to fix binding to an interface being
destroyed and recreated. Closes: #834722.
+ 2675f2061525bc954be14988d64384b74aa7bf8b
+ 16800ea072dd0cdf14d951c4bb8d2808b3dfe53d
-- Vincent Bernat <bernat@debian.org> Sat, 26 Nov 2016 20:15:34 +0100
dnsmasq (2.76-4) unstable; urgency=medium
* Non-maintainer upload.
* Fix FTCBFS: Use triplet-prefixed tools. (closes: #836072)
-- Helmut Grohne <helmut@subdivi.de> Tue, 30 Aug 2016 13:59:12 +0200
dnsmasq (2.76-3) unstable; urgency=medium
* Bump auth zone serial on SIGHUP. (closes: #833733)
-- Simon Kelley <simon@thekelleys.org.uk> Sat, 13 Aug 2016 21:43:10 +0000
dnsmasq (2.76-2) unstable; urgency=medium
* Fix to systemd to fix failure to start with bridge interface.
(Closes: #831372)
-- Simon Kelley <simon@thekelleys.org.uk> Sat, 16 Jul 2016 22:09:10 +0000
dnsmasq (2.76-1.2) unstable; urgency=medium
* Non-maintainer upload.
* dnsmasq: Install marker file to determine package installed state,
for the benefit of the init script. (Closes: #819856)
-- Christian Hofstaedtler <zeha@debian.org> Sat, 16 Jul 2016 00:17:57 +0000
dnsmasq (2.76-1.1) unstable; urgency=medium
* Non-maintainer upload.
* Provide nss-lookup.target for systemd, without relying on insserv.
Patch from Michael Biebl <biebl@debian.org>. (Closes: #826242)
-- Christian Hofstaedtler <zeha@debian.org> Fri, 01 Jul 2016 13:41:11 +0000
dnsmasq (2.76-1) unstable; urgency=low
* New upstream. (closes: #798586)
* Use /run/dnsmasq directly, rather than relying on link from /var/run
to avoid problems before /var is mounted. (closes: #800351)
-- Simon Kelley <simon@thekelleys.org.uk> Thur, 10 Sep 2015 23:07:21 +0000
* Test for the existence of /usr/share/doc/dnsmasq rather then
/etc/dnsmasq.d/README in the daemon startup script. (closes: #819856)
* Add --help to manpage and mention dhcp6 in summary. (closes: #821226)
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 10 Sep 2015 23:07:21 +0000
dnsmasq (2.75-1) unstable; urgency=low
* New upstream. (closes: #794095)
-- Simon Kelley <simon@thekelleys.org.uk> Thur, 30 Jul 2015 20:58:31 +0000
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 30 Jul 2015 20:58:31 +0000
dnsmasq (2.74-1) unstable; urgency=low
* New upstream. (LP: #1468611)
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 15 Jul 2015 21:54:11 +0000
dnsmasq (2.73-2) unstable; urgency=low
@@ -42,7 +109,7 @@ dnsmasq (2.72-3) unstable; urgency=medium
work without it. (Closes: #769486, #776530)
- debian/init: when called with systemd-exec argument, let dnsmasq
go into the background, so Type=forking can detect when it is ready
* Remove line containing only whitespace in debian/contol.
* Remove line containing only whitespace in debian/control.
(closes: #777571)
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 11 Feb 2015 21:56:12 +0000
@@ -654,7 +721,7 @@ dnsmasq (2.26-1) unstable; urgency=high
dnsmasq (2.25-1) unstable; urgency=low
* Remove bashisms in postinst and prerm scripts.
* Remove misconcieved dependency on locales.
* Remove misconceived dependency on locales.
* Depend on adduser.
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 01 Dec 2005 21:02:12 +0000
@@ -676,7 +743,7 @@ dnsmasq (2.23-1) unstable; urgency=low
* Add support for DNSMASQ_EXCEPT in /etc/defaults/dnsmasq.
putting "lo" in this also disables resolvconf support.
* No longer delete pre-existing /etc/init.d symlinks. The
change in default runlevels which neccesitated this
change in default runlevels which necessitated this
is now ancient history and anyway the startup script now
behaves when called twice. (closes: #312111)
* Tightened config-file parser. (closes: #317030)
@@ -861,7 +928,7 @@ dnsmasq (2.6-3) unstable; urgency=low
* Removed reload command from start script and moved force-reload
to be equivalent to restart. This is needed to be policy compliant
since SIHGUP doesn't cause dnsmasq to reload its configuration file,
since SIGHUP doesn't cause dnsmasq to reload its configuration file,
only the /etc/hosts, /etc/resolv.conf etc. (closes: #244208)
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 18 Apr 2004 14:40:51 +0000
@@ -951,8 +1018,8 @@ dnsmasq (2.0-1) unstable; urgency=low
* New upstream: This removes the ability to read the
the leases file of ISC DHCP and replaces it with a built-in
DHCP server. Apologies in advance for breaking backwards
compatibilty, but this replaces a bit of a hack (the ISC stuff)
with a nicely engineered and much more apropriate solution.
compatibility, but this replaces a bit of a hack (the ISC stuff)
with a nicely engineered and much more appropriate solution.
Wearing my upstream-maintainer hat, I want to lose the hack now,
rather than have to support it into Sarge.
* New upstream closes some bugs since they become
@@ -978,7 +1045,7 @@ dnsmasq (1.18-1) unstable; urgency=low
* New upstream which does round-robin. (closes: #215460)
* Removed conflicts with other dns servers since it is now
possible to control exactly where dnsmasq listens on multi-homed
hosts, making co-existance with another nameserver
hosts, making co-existence with another nameserver
a viable proposition. (closes #176163)
* New upstream allows _ in hostnames and check for illegal
names in /etc/hosts. (closes: #218842)
@@ -1064,13 +1131,13 @@ dnsmasq (1.11-2) unstable; urgency=low
dnsmasq (1.11-1) unstable; urgency=low
* New uptream.
* New upstream.
-- Simon Kelley <simon@thekelleys.org.uk> Tues, 12 Jan 2003 22:25:17 -0100
dnsmasq (1.10-1) unstable; urgency=low
* New uptream.
* New upstream.
* Force service to stop in postinst before restarting. I don't
understand the circumstances under which it would still be running at
this point, but this is the correct fix anyway. (closes: #169718)
@@ -1082,7 +1149,7 @@ dnsmasq (1.10-1) unstable; urgency=low
dnsmasq (1.9-1) unstable; urgency=low
* New uptream.
* New upstream.
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 23 Sept 2002 21:35:07 -0100

4
debian/control vendored
View File

@@ -5,12 +5,12 @@ Build-depends: gettext, libnetfilter-conntrack-dev [linux-any],
libidn11-dev, libdbus-1-dev (>=0.61), libgmp-dev,
nettle-dev (>=2.4-3), libbsd-dev [!linux-any]
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
Standards-Version: 3.9.5
Standards-Version: 3.9.8
Package: dnsmasq
Architecture: all
Depends: netbase, dnsmasq-base(>= ${binary:Version}),
init-system-helpers (>= 1.18~)
init-system-helpers (>= 1.18~), lsb-base (>= 3.0-6)
Suggests: resolvconf
Conflicts: resolvconf (<<1.15)
Description: Small caching DNS proxy and DHCP/TFTP server

2
debian/copyright vendored
View File

@@ -1,4 +1,4 @@
dnsmasq is Copyright (c) 2000-2015 Simon Kelley
dnsmasq is Copyright (c) 2000-2016 Simon Kelley
It was downloaded from: http://www.thekelleys.org.uk/dnsmasq/

21
debian/init vendored
View File

@@ -8,7 +8,8 @@
# Description: DHCP and DNS server
### END INIT INFO
set +e # Don't exit on error status
# Don't exit on error status
set +e
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/dnsmasq
@@ -29,12 +30,11 @@ if [ -r /etc/default/locale ]; then
export LANG
fi
# /etc/dnsmasq.d/README is a non-conffile installed by the dnsmasq package.
# Should the dnsmasq package be removed, the following test ensures that
# the daemon is no longer started, even if the dnsmasq-base package is
# still in place.
test -e /etc/dnsmasq.d/README || exit 0
# The following test ensures the dnsmasq service is not started, when the
# package 'dnsmasq' is removed but not purged, even if the dnsmasq-base
# package is still in place.
test -e /usr/share/dnsmasq/installed-marker || exit 0
test -x $DAEMON || exit 0
# Provide skeleton LSB log functions for backports which don't have LSB functions.
@@ -111,7 +111,7 @@ DNSMASQ_OPTS="$DNSMASQ_OPTS --local-service"
ROOT_DS="/usr/share/dns/root.ds"
if [ -f $ROOT_DS ]; then
DNSMASQ_OPTS="$DNSMASQ_OPTS `sed -e s/". IN DS "/--trust-anchor=.,/ -e s/" "/,/g $ROOT_DS | tr '\n' ' '`"
DNSMASQ_OPTS="$DNSMASQ_OPTS `sed -e s/"^.*DS[\t ]"/--trust-anchor=.,/ -e s/" "/,/g $ROOT_DS | tr '\n' ' '`"
fi
start()
@@ -154,6 +154,11 @@ start_resolvconf()
[ $interface = lo ] && return
done
# Also skip this if DNS functionality is disabled in /etc/dnsmasq.conf
if grep -qs '^port=0' /etc/dnsmasq.conf; then
return
fi
if [ -x /sbin/resolvconf ] ; then
echo "nameserver 127.0.0.1" | /sbin/resolvconf -a lo.$NAME
fi

2
debian/installed-marker vendored Normal file
View File

@@ -0,0 +1,2 @@
# This file indicates dnsmasq (and not just dnsmasq-base) is installed.
# It is an implementation detail of the dnsmasq init script.

4
debian/readme vendored
View File

@@ -31,7 +31,7 @@ Notes on configuring dnsmasq as packaged for Debian.
as the first nameserver address in /etc/resolv.conf.
(6) In the absence of resolvconf, dns-nameservers lines in
/etc/network/interfaces are ignored. If you do do not use
/etc/network/interfaces are ignored. If you do not use
resolvconf, list 127.0.0.1 as the first nameserver address
in /etc/resolv.conf and configure your nameservers using
"server=<IP-address>" lines in /etc/dnsmasq.conf.
@@ -66,7 +66,7 @@ Notes on configuring dnsmasq as packaged for Debian.
combined with noi18n to be effective.
gitversion : set the version of the produced packages from the
git-derived versioning information on the source,
rather the the debian changelog.
rather than the debian changelog.
(9) Dnsmasq comes as three packages - dnsmasq-utils, dnsmasq-base and
dnsmasq. Dnsmasq-base provides the dnsmasq executable and

48
debian/rules vendored
View File

@@ -11,7 +11,7 @@
package=dnsmasq-base
dpkg_buildflags := DEB_BUILD_MAINT_OPTIONS="hardening=+all" dpkg-buildflags
dpkg_buildflags := DEB_BUILD_MAINT_OPTIONS="hardening=+all,+pie,+bindnow" dpkg-buildflags
CFLAGS = $(shell $(dpkg_buildflags) --get CFLAGS)
CFLAGS += $(shell $(dpkg_buildflags) --get CPPFLAGS)
@@ -24,8 +24,21 @@ DEB_COPTS = $(COPTS)
TARGET = install-i18n
DEB_HOST_ARCH_OS := $(shell dpkg-architecture -qDEB_HOST_ARCH_OS)
DEB_HOST_GNU_TYPE := $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
DEB_BUILD_GNU_TYPE := $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
BUILD_DATE := $(shell dpkg-parsechangelog --show-field Date)
ifeq ($(origin CC),default)
CC = $(DEB_HOST_GNU_TYPE)-gcc
endif
# Support non-cross-builds on systems without gnu-triplet-binaries for pkg-config.
ifeq ($(DEB_BUILD_GNU_TYPE),$(DEB_HOST_GNU_TYPE))
PKG_CONFIG=pkg-config
else
PKG_CONFIG=$(DEB_HOST_GNU_TYPE)-pkg-config
endif
# Force package version based on git tags.
ifneq (,$(filter gitversion,$(DEB_BUILD_OPTIONS)))
PACKAGE_VERSION = $(shell bld/get-version `pwd` | sed 's/test/~&/; s/[a-z]/~&/; s/-/./g; s/$$/-1/; s/^/-v/';)
@@ -35,6 +48,10 @@ ifeq (,$(filter nodbus,$(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_DBUS
endif
ifeq (,$(filter noidn, $(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_IDN
endif
ifeq (,$(filter noconntrack,$(DEB_BUILD_OPTIONS)))
ifeq ($(DEB_HOST_ARCH_OS),linux)
DEB_COPTS += -DHAVE_CONNTRACK
@@ -71,9 +88,6 @@ endif
ifneq (,$(filter noi18n,$(DEB_BUILD_OPTIONS)))
TARGET = install
ifeq (,$(filter noidn, $(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_IDN
endif
endif
ifneq (,$(filter uselua,$(DEB_BUILD_OPTIONS)))
@@ -93,7 +107,7 @@ clean:
$(checkdir)
rm -rf debian/daemon debian/base debian/utils debian/*~ debian/files debian/substvars debian/utils-substvars
make clean
make -C contrib/wrt clean
make -C contrib/lease-tools clean
binary-indep: checkroot
$(checkdir)
@@ -105,6 +119,7 @@ binary-indep: checkroot
-d debian/daemon/etc/dnsmasq.d \
-d debian/daemon/etc/resolvconf/update.d \
-d debian/daemon/usr/lib/resolvconf/dpkg-event.d \
-d debian/daemon/usr/share/dnsmasq \
-d debian/daemon/etc/default \
-d debian/daemon/lib/systemd/system \
-d debian/daemon/etc/insserv.conf.d
@@ -113,6 +128,7 @@ binary-indep: checkroot
install -m 755 debian/init debian/daemon/etc/init.d/dnsmasq
install -m 755 debian/resolvconf debian/daemon/etc/resolvconf/update.d/dnsmasq
install -m 755 debian/resolvconf-package debian/daemon/usr/lib/resolvconf/dpkg-event.d/dnsmasq
install -m 644 debian/installed-marker debian/daemon/usr/share/dnsmasq
install -m 644 debian/default debian/daemon/etc/default/dnsmasq
install -m 644 dnsmasq.conf.example debian/daemon/etc/dnsmasq.conf
install -m 644 debian/readme.dnsmasq.d debian/daemon/etc/dnsmasq.d/README
@@ -136,7 +152,7 @@ binary-arch: checkroot
-d debian/base/usr/share/doc/$(package)/examples \
-d debian/base/usr/share/$(package) \
-d debian/base/var/lib/misc
make $(TARGET) PREFIX=/usr DESTDIR=`pwd`/debian/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=gcc
make $(TARGET) PREFIX=/usr DESTDIR=`pwd`/debian/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
# Need to remove paypal links in Debian Package for policy reasons.
sed -e /\<H2\>Donations/Q -e /icon.png/d doc.html -e /favicon.ico/d >debian/base/usr/share/doc/$(package)/doc.html
@@ -168,7 +184,7 @@ endif
fi \
done
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
strip -R .note -R .comment debian/base/usr/sbin/dnsmasq
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/base/usr/sbin/dnsmasq
endif
cd debian/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps --warnings=1 debian/base/usr/sbin/dnsmasq
@@ -184,19 +200,23 @@ ifeq ($(DEB_HOST_ARCH_OS),linux)
-d debian/utils/usr/share/man/man1 \
-d debian/utils/usr/bin \
-d debian/utils/usr/share/doc/dnsmasq-utils
make -C contrib/wrt PREFIX=/usr DESTDIR=`pwd`/debian/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=gcc
install -m 755 contrib/wrt/dhcp_release debian/utils/usr/bin/dhcp_release
install -m 644 contrib/wrt/dhcp_release.1 debian/utils/usr/share/man/man1/dhcp_release.1
make -C contrib/lease-tools PREFIX=/usr DESTDIR=`pwd`/debian/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
install -m 755 contrib/lease-tools/dhcp_release debian/utils/usr/bin/dhcp_release
install -m 644 contrib/lease-tools/dhcp_release.1 debian/utils/usr/share/man/man1/dhcp_release.1
gzip -9n debian/utils/usr/share/man/man1/dhcp_release.1
install -m 755 contrib/wrt/dhcp_lease_time debian/utils/usr/bin/dhcp_lease_time
install -m 644 contrib/wrt/dhcp_lease_time.1 debian/utils/usr/share/man/man1/dhcp_lease_time.1
install -m 755 contrib/lease-tools/dhcp_release6 debian/utils/usr/bin/dhcp_release6
install -m 644 contrib/lease-tools/dhcp_release6.1 debian/utils/usr/share/man/man1/dhcp_release6.1
gzip -9n debian/utils/usr/share/man/man1/dhcp_release6.1
install -m 755 contrib/lease-tools/dhcp_lease_time debian/utils/usr/bin/dhcp_lease_time
install -m 644 contrib/lease-tools/dhcp_lease_time.1 debian/utils/usr/share/man/man1/dhcp_lease_time.1
install -m 644 debian/copyright debian/utils/usr/share/doc/dnsmasq-utils/copyright
install -m 644 debian/changelog debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
gzip -9n debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
gzip -9n debian/utils/usr/share/man/man1/dhcp_lease_time.1
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
strip -R .note -R .comment debian/utils/usr/bin/dhcp_release
strip -R .note -R .comment debian/utils/usr/bin/dhcp_lease_time
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/utils/usr/bin/dhcp_release
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/utils/usr/bin/dhcp_release6
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/utils/usr/bin/dhcp_lease_time
endif
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps -Tdebian/utils-substvars debian/utils/usr/bin/dhcp_release debian/utils/usr/bin/dhcp_lease_time

1
debian/shlibs.local vendored Normal file
View File

@@ -0,0 +1 @@
libnettle 6 libnettle6 (>= 3.3)

View File

@@ -1,6 +1,9 @@
[Unit]
Description=dnsmasq - A lightweight DHCP and caching DNS server
Requires=network.target
Wants=nss-lookup.target
Before=nss-lookup.target
After=network.target
[Service]
Type=forking
@@ -15,7 +18,7 @@ ExecStartPre=/usr/sbin/dnsmasq --test
ExecStart=/etc/init.d/dnsmasq systemd-exec
# The systemd-*-resolvconf functions configure (and deconfigure)
# resolvconf to work with the dnsmasq DNS server. They're called liek
# resolvconf to work with the dnsmasq DNS server. They're called like
# this to get correct error handling (ie don't start-resolvconf if the
# dnsmasq daemon fails to start.
ExecStartPost=/etc/init.d/dnsmasq systemd-start-resolvconf

View File

@@ -189,7 +189,7 @@
# 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 alogrithm.
# IPv6 address calculated using the SLAAC algorithm.
#dhcp-range=1234::, ra-names
# Do Router Advertisements, BUT NOT DHCP for this subnet.
@@ -210,7 +210,7 @@
#dhcp-range=1234::, ra-stateless, ra-names
# Do router advertisements for all subnets where we're doing DHCPv6
# Unless overriden by ra-stateless, ra-names, et al, the router
# 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.
@@ -251,7 +251,7 @@
# 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
# 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
@@ -288,7 +288,7 @@
# 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 obilgatory.
# 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
@@ -525,7 +525,7 @@
# (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 fasion. This facility can be used to
# 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

View File

@@ -18,7 +18,7 @@ Linux distributions and the ports systems of FreeBSD, OpenBSD and NetBSD. Dnsmas
<P>
The DNS subsystem provides a local DNS server for the network, with forwarding of all query types to upstream recursive DNS servers and
cacheing of common record types (A, AAAA, CNAME and PTR, also DNSKEY and DS when DNSSEC is enabled).
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.

View File

@@ -30,7 +30,7 @@ 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 uneeded functions to be omitted from the compiled binary.
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
@@ -42,6 +42,13 @@ the configuration file.
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
@@ -60,7 +67,7 @@ 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 the DHCP leases
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
@@ -68,6 +75,9 @@ 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
@@ -174,6 +184,13 @@ 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
@@ -186,12 +203,17 @@ or
options are given dnsmasq listens on all available interfaces except any
given in
.B \--except-interface
options. IP alias interfaces (eg "eth1:0") cannot be used with
.B --interface
options. On Linux, when
.B \--bind-interfaces
or
.B --except-interface
options, use --listen-address instead. A simple wildcard, consisting
of a trailing '*', can be used in
.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
@@ -205,7 +227,9 @@ and
.B --except-interface
options does not matter and that
.B --except-interface
options always override the others.
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
@@ -215,7 +239,7 @@ or
.B --listen-address
configuration, indeed
.B --auth-server
will overide these and provide a different DNS service on the
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,
@@ -225,7 +249,7 @@ addresses associated with the interface.
.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 is there are no --interface --except-interface,
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.
@@ -272,8 +296,8 @@ 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 which depend on the interface over which the query was
received. If a name in /etc/hosts has more than one address associated with
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
@@ -284,7 +308,8 @@ attached to. Currently this facility is limited to IPv4.
.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.
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
@@ -307,7 +332,7 @@ 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 \-B, --ignore-address=<ipaddr>
.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
@@ -405,7 +430,10 @@ 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. An empty domain specification,
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
@@ -414,7 +442,7 @@ address using a # character.
More than one -S flag is allowed, with
repeated domain or ipaddr parts as required.
More specific domains take precendence over less specific domains, so:
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,
@@ -439,14 +467,14 @@ 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 should be an ip-address, which should belong to the machine on which
dnsmasq is running otherwise this server line will be logged and then
ignored, or an interface name. 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.
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
@@ -460,28 +488,36 @@ but provides some syntactic sugar to make specifying address-to-name queries eas
is exactly equivalent to
.B --server=/3.2.1.in-addr.arpa/192.168.0.1
.TP
.B \-A, --address=/<domain>/[domain/][<ipaddr>]
.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 -A flags.
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 --server, with the
additional facility that /#/ matches any domain. Thus
--address=/#/1.2.3.4 will always return 1.2.3.4 for any query not
answered from /etc/hosts or DHCP and not sent to an upstream
nameserver by a more specific --server directive. As for --server,
one or more domains with no address returns a no-such-domain answer, so
--address=/example.com/ is equivalent to --server=/example.com/ and returns
NXDOMAIN for example.com and all its subdomains.
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 the specified domains
in the specified netfilter ip sets. Domains and subdomains are matched
in the same way as --address. These ip sets must already exist. See
ipset(8) for more details.
.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
@@ -519,7 +555,7 @@ 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>]
.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
@@ -536,6 +572,10 @@ 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,
@@ -549,7 +589,7 @@ Return a PTR DNS record.
.B --naptr-record=<name>,<order>,<preference>,<flags>,<service>,<regexp>[,<replacement>]
Return an NAPTR DNS record, as specified in RFC3403.
.TP
.B --cname=<cname>,<target>
.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
@@ -557,7 +597,13 @@ 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.
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
@@ -566,7 +612,7 @@ 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 a DNS record associating the name with the primary address on
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
@@ -576,7 +622,8 @@ 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.
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
@@ -591,10 +638,12 @@ 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
.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
@@ -602,7 +651,12 @@ subnet as the dnsmasq server. Note that the mechanism used to achieve this (an E
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.
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
@@ -654,7 +708,7 @@ 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 menas that all replies will be
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.
@@ -706,7 +760,7 @@ 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>].....]]
.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.
@@ -723,6 +777,10 @@ 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.
@@ -757,7 +815,7 @@ 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>]
.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>]
@@ -789,7 +847,7 @@ 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 mimimum
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
@@ -911,7 +969,7 @@ 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
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
@@ -963,6 +1021,8 @@ 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
@@ -1004,22 +1064,21 @@ 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 recieves a SIGHUP, or
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 --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 \-Z, --read-ethers
Read /etc/ethers for information about hosts for the DHCP server. The
@@ -1325,7 +1384,7 @@ 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, BC_EFI, Xscale_EFI and X86-64_EFI; an
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,
@@ -1334,8 +1393,9 @@ either from itself (
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 should not be added to
the basename. If an integer boot service type, rather than a basename
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.
@@ -1426,7 +1486,7 @@ 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-intialised. The enterprise-id is assigned by IANA, and the uid is a
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>
@@ -1494,6 +1554,8 @@ 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,
@@ -1517,8 +1579,8 @@ database.
All file descriptors are
closed except stdin, stdout and stderr which are open to /dev/null
(except in debug mode).
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
@@ -1533,11 +1595,11 @@ 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.
with an "old" event.
There are two further actions which may appear as the first argument
to the script, "init" and "tftp". More may be added in the future, so
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
@@ -1545,11 +1607,16 @@ 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 intialised once, when
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
@@ -1591,10 +1658,24 @@ table holds the tags
.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
.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
@@ -1695,9 +1776,9 @@ subnets with the mode keywords described in
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 serach list (DNSSL).
domain-search are used for the DNS server (RDNSS) and the domain search list (DNSSL).
.TP
.B --ra-param=<interface>,[high|low],[[<ra-interval>],<router lifetime>]
.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
@@ -1707,16 +1788,26 @@ The interval between router advertisements may be set (in seconds) with
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 three parameters may be set at once.
.B --ra-param=low,60,1200
(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 recieve TFTP 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
@@ -1729,12 +1820,16 @@ directory is only used for TFTP requests via that interface.
.B --tftp-no-fail
Do not abort startup if specified tftp root directories are inaccessible.
.TP
.B --tftp-unique-root
Add the IP address of the TFTP client as a path component on the end
of the TFTP-root (in standard dotted-quad format). Only valid if a
tftp-root is set and the directory exists. 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.
.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
@@ -1765,6 +1860,10 @@ 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
@@ -1800,7 +1899,7 @@ 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 recieves SIGHUP.
therein is updated when dnsmasq receives SIGHUP.
.SH CONFIG FILE
At startup, dnsmasq reads
.I /etc/dnsmasq.conf,
@@ -2136,7 +2235,12 @@ following data is used to populate the authoritative zone.
.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.
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
@@ -2149,7 +2253,7 @@ provided the address falls into one of the subnets specified in the
.PP
Addresses of DHCP leases, provided the address falls into one of the subnets specified in the
.B --auth-zone.
(If contructed DHCP ranges are is use, which depend on the address dynamically
(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

View File

@@ -1756,20 +1756,20 @@ 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>,[high|low],[[<intervalle d'annonce routeur>],<durée de vie route>]
.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.
.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 trois paramètres peuvent-être configurés en une fois :
.B --ra-param=low,60,1200
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>]]

906
po/de.po

File diff suppressed because it is too large Load Diff

891
po/es.po

File diff suppressed because it is too large Load Diff

1004
po/fi.po

File diff suppressed because it is too large Load Diff

880
po/fr.po

File diff suppressed because it is too large Load Diff

971
po/id.po

File diff suppressed because it is too large Load Diff

1004
po/it.po

File diff suppressed because it is too large Load Diff

963
po/no.po

File diff suppressed because it is too large Load Diff

892
po/pl.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

963
po/ro.po

File diff suppressed because it is too large Load Diff

View File

@@ -78,7 +78,7 @@ by modifying MODIFY_RESOLV_CONF_DYNAMICALLY="no" in <TT>/etc/sysconfig/network/c
<h3>Automatic DNS server configuration with DHCP.</h3>
You need to get your DHCP client to write the addresse(s) of the DNS
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
@@ -86,8 +86,8 @@ uses that to write a file suitable for dnsmasq.
<PRE>
echo -n >|/etc/dhcpc/resolv.conf
dnsservs=${DNS//,/ }
for serv in $dnsservs; do
dnsservers=${DNS//,/ }
for serv in $dnsservers; do
echo "nameserver $serv" >>/etc/dhcpc/resolv.conf
done
@@ -186,7 +186,7 @@ more than one nameserver just include as many
<H2>Local domains.</H2>
Sometimes people have local domains which they do not want forwarded
to upstream servers. This is accomodated by using server options
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

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -44,6 +44,11 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
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)
{
@@ -117,30 +122,36 @@ int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now)
/* If the database is less then INTERVAL old, look in there */
if (difftime(now, last) < INTERVAL)
for (arp = arps; arp; arp = arp->next)
{
if (addr->sa.sa_family == arp->family)
{
if (arp->addr.addr.addr4.s_addr != addr->in.sin_addr.s_addr)
continue;
}
{
/* 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
else
{
if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, &addr->in6.sin6_addr))
continue;
}
if (arp->family == AF_INET6 &&
!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, &addr->in6.sin6_addr))
continue;
#endif
/* Only accept poitive 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;
}
}
/* 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)
{
@@ -148,7 +159,7 @@ int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now)
last = now;
/* Mark all non-negative entries */
for (arp = arps, up = &arps; arp; arp = arp->next)
for (arp = arps; arp; arp = arp->next)
if (arp->status != ARP_EMPTY)
arp->status = ARP_MARK;
@@ -188,7 +199,8 @@ int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now)
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
@@ -208,8 +220,8 @@ int do_arp_script_run(void)
if (old)
{
#ifdef HAVE_SCRIPT
if (option_bool(OPT_DNS_CLIENT))
queue_arp(ACTION_ARP_OLD, old->hwaddr, old->hwlen, old->family, &old->addr);
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;
@@ -222,7 +234,7 @@ int do_arp_script_run(void)
if (arp->status == ARP_NEW)
{
#ifdef HAVE_SCRIPT
if (option_bool(OPT_DNS_CLIENT))
if (option_bool(OPT_SCRIPT_ARP))
queue_arp(ACTION_ARP, arp->hwaddr, arp->hwlen, arp->family, &arp->addr);
#endif
arp->status = ARP_FOUND;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -18,36 +18,53 @@
#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)
{
struct addrlist *subnet;
if (!zone->subnet)
return NULL;
return find_addrlist(zone->subnet, flag, addr_u);
}
for (subnet = zone->subnet; subnet; subnet = subnet->next)
{
if (!(subnet->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 - subnet->prefixlen));
if (is_same_net(addr, subnet->addr.addr.addr4, netmask))
return subnet;
}
#ifdef HAVE_IPV6
else if (is_same_net6(&(addr_u->addr.addr6), &subnet->addr.addr.addr6, subnet->prefixlen))
return subnet;
#endif
}
return NULL;
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)
{
/* No zones specified, no filter */
if (find_exclude(zone, flag, addr_u))
return 0;
/* No subnets specified, no filter */
if (!zone->subnet)
return 1;
@@ -99,7 +116,13 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
struct interface_name *intr;
struct naptr *na;
struct all_addr addr;
struct cname *a;
struct cname *a, *candidate;
unsigned int wclen;
/* Clear buffer beyond request to avoid risk of
information disclosure. */
memset(((char *)header) + qlen, 0,
(limit - ((char *)header)) - qlen);
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
return 0;
@@ -115,6 +138,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
{
unsigned short flag = 0;
int found = 0;
int cname_wildcard = 0;
/* save pointer to name for copying into answers */
nameoffset = p - (unsigned char *)header;
@@ -389,25 +413,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
}
}
for (a = daemon->cnames; a; a = a->next)
if (hostname_isequal(name, a->alias) )
{
log_query(F_CONFIG | F_CNAME, name, NULL, NULL);
strcpy(name, a->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;
}
if (!cut)
{
nxdomain = 0;
@@ -513,8 +518,62 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
} while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
}
if (!found)
log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);
/* 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);
}
}
@@ -806,7 +865,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
header->hb4 &= ~HB4_RA;
}
/* authoritive */
/* authoritative */
if (auth)
header->hb3 |= HB3_AA;
@@ -824,7 +883,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
/* 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);
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;
}

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -20,7 +20,9 @@
#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>
@@ -103,7 +105,7 @@ int arp_enumerate(void *parm, int (*callback)())
int iface_enumerate(int family, void *parm, int (*callback)())
{
struct ifaddrs *head, *addrs;
int errsav, fd = -1, ret = 0;
int errsave, fd = -1, ret = 0;
if (family == AF_UNSPEC)
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
@@ -235,11 +237,11 @@ int iface_enumerate(int family, void *parm, int (*callback)())
ret = 1;
err:
errsav = errno;
errsave = errno;
freeifaddrs(head);
if (fd != -1)
close(fd);
errno = errsav;
errno = errsave;
return ret;
}

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -774,10 +774,12 @@ static void add_hosts_cname(struct crec *target)
struct cname *a;
for (a = daemon->cnames; a; a = a->next)
if (hostname_isequal(cache_get_name(target), a->target) &&
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;
@@ -919,7 +921,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
if (!f)
{
my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
return 0;
return cache_size;
}
eatspace(f);
@@ -981,6 +983,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
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++;
}
@@ -988,6 +991,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
{
strcpy(cache->name.sname, canon);
cache->flags = flags;
cache->ttd = daemon->local_ttl;
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
name_count++;
}
@@ -1053,10 +1057,12 @@ void cache_reload(void)
/* 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 (hostname_isequal(a->target, intr->name) &&
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;
@@ -1071,6 +1077,7 @@ void cache_reload(void)
(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;
@@ -1095,6 +1102,7 @@ void cache_reload(void)
(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);
}
@@ -1103,6 +1111,7 @@ void cache_reload(void)
(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);
}
@@ -1170,7 +1179,8 @@ static void add_dhcp_cname(struct crec *target, time_t ttd)
struct cname *a;
for (a = daemon->cnames; a; a = a->next)
if (hostname_isequal(cache_get_name(target), a->target))
if (a->alias[1] != '*' &&
hostname_isequal(cache_get_name(target), a->target))
{
if ((aliasc = dhcp_spare))
dhcp_spare = dhcp_spare->next;
@@ -1283,6 +1293,7 @@ void cache_add_dhcp_entry(char *host_name, int prot,
}
#endif
#ifndef NO_ID
int cache_make_stat(struct txt_record *t)
{
static char *buff = NULL;
@@ -1378,6 +1389,7 @@ int cache_make_stat(struct txt_record *t)
*buff = len;
return 1;
}
#endif
/* There can be names in the cache containing control chars, don't
mess up logging or open security holes. */

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -18,13 +18,16 @@
#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 mininise fragmentation when storing DNSSEC keys */
#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 */
@@ -91,13 +94,13 @@ HAVE_DBUS
servers via DBus.
HAVE_IDN
define this if you want international domain name support.
NOTE: for backwards compatibility, IDN support is automatically
included when internationalisation support is built, using the
*-i18n makefile targets, even if HAVE_IDN is not explicitly set.
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 propogates conntrack marks from
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.
@@ -119,6 +122,8 @@ HAVE_LOOP
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
@@ -127,7 +132,7 @@ NO_SCRIPT
NO_LARGEFILE
NO_AUTH
NO_INOTIFY
these are avilable to explictly disable compile time options which would
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.
@@ -172,6 +177,7 @@ RESOLVFILE
/* #define HAVE_LUASCRIPT */
/* #define HAVE_DBUS */
/* #define HAVE_IDN */
/* #define HAVE_LIBIDN2 */
/* #define HAVE_CONNTRACK */
/* #define HAVE_DNSSEC */
@@ -228,7 +234,7 @@ HAVE_SOCKADDR_SA_LEN
defined if struct sockaddr has sa_len field (*BSD)
*/
/* Must preceed __linux__ since uClinux defines __linux__ too. */
/* Must precede __linux__ since uClinux defines __linux__ too. */
#if defined(__uClinux__)
#define HAVE_LINUX_NETWORK
#define HAVE_GETOPT_LONG
@@ -266,7 +272,7 @@ HAVE_SOCKADDR_SA_LEN
defined(__DragonFly__) || \
defined(__FreeBSD_kernel__)
#define HAVE_BSD_NETWORK
/* Later verions of FreeBSD have getopt_long() */
/* Later versions of FreeBSD have getopt_long() */
#if defined(optional_argument) && defined(required_argument)
# define HAVE_GETOPT_LONG
#endif
@@ -364,7 +370,7 @@ HAVE_SOCKADDR_SA_LEN
#endif
/* Define a string indicating which options are in use.
DNSMASQP_COMPILE_OPTS is only defined in dnsmasq.c */
DNSMASQ_COMPILE_OPTS is only defined in dnsmasq.c */
#ifdef DNSMASQ_COMPILE_OPTS
@@ -391,10 +397,14 @@ static char *compile_opts =
"no-"
#endif
"i18n "
#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
#if defined(HAVE_LIBIDN2)
"IDN2 "
#else
#if !defined(HAVE_IDN)
"no-"
#endif
"IDN "
#endif
"IDN "
#endif
#ifndef HAVE_DHCP
"no-"
#endif
@@ -404,14 +414,14 @@ static char *compile_opts =
"no-"
# endif
"DHCPv6 "
# if !defined(HAVE_SCRIPT)
#endif
#if !defined(HAVE_SCRIPT)
"no-scripts "
# else
# if !defined(HAVE_LUASCRIPT)
"no-"
# endif
"Lua "
#else
# if !defined(HAVE_LUASCRIPT)
"no-"
# endif
"Lua "
#endif
#ifndef HAVE_TFTP
"no-"
@@ -433,6 +443,9 @@ static char *compile_opts =
"no-"
#endif
"DNSSEC "
#ifdef NO_ID
"no-ID "
#endif
#ifndef HAVE_LOOP
"no-"
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -549,17 +549,16 @@ static DBusMessage *dbus_add_lease(DBusMessage* message)
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);
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,
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);

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -20,11 +20,11 @@
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(256);
daemon->dhcp_buff2 = safe_malloc(256);
daemon->dhcp_buff3 = safe_malloc(256);
/* 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,
@@ -855,14 +855,14 @@ void log_context(int family, struct dhcp_context *context)
if (context->flags & CONTEXT_RA_STATELESS)
{
if (context->flags & CONTEXT_TEMPLATE)
strncpy(daemon->dhcp_buff, context->template_interface, 256);
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, 256);
inet_ntop(family, end, daemon->dhcp_buff3, 256);
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") :

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -19,6 +19,10 @@
#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

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -67,9 +67,9 @@ static int make_fd(int port)
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 dnmsasq
/* 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 posible.
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))
@@ -145,11 +145,14 @@ void dhcp_packet(time_t now, int pxe_fd)
struct cmsghdr *cmptr;
struct iovec iov;
ssize_t sz;
int iface_index = 0, unicast_dest = 0, is_inform = 0;
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 {
@@ -176,6 +179,9 @@ void dhcp_packet(time_t now, int pxe_fd)
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)
@@ -217,9 +223,13 @@ void dhcp_packet(time_t now, int pxe_fd)
}
#endif
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
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);
@@ -230,6 +240,7 @@ void dhcp_packet(time_t now, int pxe_fd)
--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)
@@ -278,7 +289,8 @@ void dhcp_packet(time_t now, int pxe_fd)
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
else
{
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
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;
}
@@ -323,7 +335,7 @@ void dhcp_packet(time_t now, int pxe_fd)
/* We're relaying this request */
if (parm.relay_local.s_addr != 0 &&
relay_upstream4(parm.relay, (struct dhcp_packet *)daemon->dhcp_packet.iov_base, (size_t)sz, iface_index))
relay_upstream4(parm.relay, mess, (size_t)sz, iface_index))
return;
/* May have configured relay, but not DHCP server */
@@ -332,14 +344,14 @@ void dhcp_packet(time_t now, int pxe_fd)
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, &is_inform, pxe_fd, iface_addr);
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;
@@ -387,7 +399,7 @@ void dhcp_packet(time_t now, int pxe_fd)
msg.msg_controllen = sizeof(control_u);
cmptr = CMSG_FIRSTHDR(&msg);
pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
pkt->ipi_ifindex = iface_index;
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;
@@ -493,7 +505,7 @@ static int check_listen_addrs(struct in_addr local, int if_index, char *label,
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 superceded later for configured hosts or those coming via gateways. */
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)
@@ -593,7 +605,7 @@ struct dhcp_context *narrow_context(struct dhcp_context *context,
{
/* 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 correponding to that
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
@@ -635,9 +647,69 @@ struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct i
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)
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.
@@ -651,7 +723,11 @@ int address_allocate(struct dhcp_context *context,
/* 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 = 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)
@@ -689,69 +765,27 @@ int address_allocate(struct dhcp_context *context,
(!IN_CLASSC(ntohl(addr.s_addr)) ||
((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0))))
{
struct ping_result *r, *victim = NULL;
int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
((float)PING_WAIT)));
struct ping_result *r;
*addrp = addr;
/* 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)
{
/* 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)
break;
return 1;
}
}
if (!r)
{
if ((count < max) && !option_bool(OPT_NO_PING) && icmp_ping(addr))
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)
{
/* 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++;
}
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 = 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))

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -51,9 +51,9 @@ void dhcp6_init(void)
!set_ipv6pktinfo(fd))
die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
/* When bind-interfaces is set, there might be more than one dnmsasq
/* 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 posible.
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))
@@ -252,7 +252,7 @@ void dhcp6_packet(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)
{
/* Recieving a packet from a host does not populate the neighbour
/* 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. */
@@ -344,7 +344,7 @@ static int complete_context6(struct in6_addr *local, int prefix,
{
struct dhcp_context *tmp, **up;
/* use interface values only for contructed contexts */
/* use interface values only for constructed contexts */
if (!(context->flags & CONTEXT_CONSTRUCTED))
preferred = valid = 0xffffffff;
else if (flags & IFACE_DEPRECATED)
@@ -420,7 +420,7 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c
j = rand64();
else
for (j = iaid, i = 0; i < clid_len; i++)
j += clid[i] + (j << 6) + (j << 16) - j;
j = clid[i] + (j << 6) + (j << 16) - j;
for (pass = 0; pass <= plain_range ? 1 : 0; pass++)
for (c = context; c; c = c->current)
@@ -434,7 +434,16 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c
/* seed is largest extant lease addr in this context */
start = lease_find_max_addr6(c) + serial;
else
start = addr6part(&c->start6) + ((j + c->addr_epoch) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
{
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;
@@ -663,7 +672,7 @@ static int construct_worker(struct in6_addr *local, int prefix,
/* address went, now it's back */
log_context(AF_INET6, context);
/* fast RAs for a while */
ra_start_unsolicted(param->now, context);
ra_start_unsolicited(param->now, context);
param->newone = 1;
/* Add address to name again */
if (context->flags & CONTEXT_RA_NAME)
@@ -686,7 +695,7 @@ static int construct_worker(struct in6_addr *local, int prefix,
context->next = daemon->dhcp6;
daemon->dhcp6 = context;
ra_start_unsolicted(param->now, 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;
@@ -734,7 +743,7 @@ void dhcp_construct_contexts(time_t now)
/* maximum time is 2 hours, from RFC */
if (context->saved_valid > 7200) /* 2 hours */
context->saved_valid = 7200;
ra_start_unsolicted(now, context);
ra_start_unsolicited(now, context);
param.newone = 1; /* include deletion */
if (context->flags & CONTEXT_RA_NAME)

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -16,6 +16,7 @@
#define NAMESERVER_PORT 53
#define TFTP_PORT 69
#define MAX_PORT 65535u
#define IN6ADDRSZ 16
#define INADDRSZ 4

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -169,8 +169,16 @@ int main (int argc, char **argv)
if (option_bool(OPT_DNSSEC_VALID))
{
#ifdef HAVE_DNSSEC
if (!daemon->ds)
die(_("no trust anchors provided for DNSSEC"), NULL, EC_BADCONF);
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);
@@ -194,12 +202,12 @@ int main (int argc, char **argv)
#ifdef HAVE_SOLARIS_NETWORK
if (daemon->max_logs != 0)
die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
die(_("asynchronous logging is not available under Solaris"), NULL, EC_BADCONF);
#endif
#ifdef __ANDROID__
if (daemon->max_logs != 0)
die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
die(_("asynchronous logging is not available under Android"), NULL, EC_BADCONF);
#endif
#ifndef HAVE_AUTH
@@ -211,7 +219,13 @@ int main (int argc, char **argv)
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. */
@@ -246,10 +260,10 @@ int main (int argc, char **argv)
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 subsystrm relies on DHCP buffers, hence the last two
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_DNS_CLIENT))
daemon->relay6 || option_bool(OPT_TFTP) || option_bool(OPT_SCRIPT_ARP))
{
dhcp_common_init();
if (daemon->dhcp || daemon->doing_dhcp6)
@@ -500,7 +514,7 @@ int main (int argc, char **argv)
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 folowing code first deletes any existing file, and then opens it with the O_EXCL flag,
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.
@@ -547,16 +561,19 @@ int main (int argc, char **argv)
{
/* open stdout etc to /dev/null */
int nullfd = open("/dev/null", O_RDWR);
dup2(nullfd, STDOUT_FILENO);
dup2(nullfd, STDERR_FILENO);
dup2(nullfd, STDIN_FILENO);
close(nullfd);
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_DNS_CLIENT)) &&
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
@@ -566,7 +583,7 @@ int main (int argc, char **argv)
int bad_capabilities = 0;
gid_t dummy;
/* remove all supplimentary groups */
/* remove all supplementary groups */
if (gp &&
(setgroups(0, &dummy) == -1 ||
setgid(gp->gr_gid) == -1))
@@ -638,7 +655,7 @@ int main (int argc, char **argv)
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
data->inheritable = 0;
/* lose the setuid and setgid capbilities */
/* lose the setuid and setgid capabilities */
if (capset(hdr, data) == -1)
{
send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
@@ -697,10 +714,16 @@ int main (int argc, char **argv)
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);
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);
@@ -714,9 +737,6 @@ int main (int argc, char **argv)
}
#endif
if (option_bool(OPT_LOCAL_SERVICE))
my_syslog(LOG_INFO, _("DNS service limited to local subnets"));
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID))
{
@@ -733,7 +753,8 @@ int main (int argc, char **argv)
my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
if (option_bool(OPT_DNSSEC_TIME))
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)
@@ -750,6 +771,8 @@ int main (int argc, char **argv)
if (option_bool(OPT_NOWILD))
warn_bound_listeners();
else if (!option_bool(OPT_CLEVERBIND))
warn_wild_labels();
warn_int_names();
@@ -797,7 +820,7 @@ int main (int argc, char **argv)
my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device);
# endif
/* after dhcp_contruct_contexts */
/* after dhcp_construct_contexts */
if (daemon->dhcp || daemon->doing_dhcp6)
lease_find_interfaces(now);
#endif
@@ -919,7 +942,13 @@ int main (int argc, char **argv)
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
@@ -930,8 +959,11 @@ int main (int argc, char **argv)
poll_listen(daemon->helperfd, POLLOUT);
#else
/* need this for other side-effects */
# ifdef HAVE_DHCP
while (do_script_run(now));
while (do_arp_script_run(now));
# endif
while (do_arp_script_run());
# ifdef HAVE_TFTP
while (do_tftp_script_run());
@@ -1199,11 +1231,13 @@ static void async_event(int pipe, time_t now)
switch (ev.event)
{
case EVENT_RELOAD:
daemon->soa_sn++; /* Bump zone serial, as it may have changed. */
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
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"));
reset_option_bool(OPT_DNSSEC_TIME);
daemon->dnssec_no_time_check = 0;
}
#endif
/* fall through */
@@ -1268,6 +1302,7 @@ static void async_event(int pipe, time_t now)
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;
@@ -1281,12 +1316,19 @@ static void async_event(int pipe, time_t now)
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.
@@ -1312,7 +1354,7 @@ static void async_event(int pipe, time_t now)
if (daemon->tcp_pids[i] != 0)
kill(daemon->tcp_pids[i], SIGALRM);
#if defined(HAVE_SCRIPT)
#if defined(HAVE_SCRIPT) && defined(HAVE_DHCP)
/* handle pending lease transitions */
if (daemon->helperfd != -1)
{
@@ -1333,7 +1375,7 @@ static void async_event(int pipe, time_t now)
/* update timestamp file on TERM if time is considered valid */
if (daemon->back_to_the_future)
{
if (utime(daemon->timestamp_file, NULL) == -1)
if (utimes(daemon->timestamp_file, NULL) == -1)
my_syslog(LOG_ERR, _("failed to update mtime on %s: %s"), daemon->timestamp_file, strerror(errno));
}
#endif
@@ -1648,7 +1690,7 @@ static void check_dns_listeners(time_t now)
}
#ifndef NO_FORK
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to
/* Arrange for SIGALRM after CHILD_LIFETIME seconds to
terminate the process. */
if (!option_bool(OPT_DEBUG))
alarm(CHILD_LIFETIME);
@@ -1713,29 +1755,15 @@ int icmp_ping(struct in_addr addr)
{
/* Try and get an ICMP echo from a machine. */
/* Note that whilst in the three second wait, 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 fd, rc;
int fd;
struct sockaddr_in saddr;
struct {
struct ip ip;
struct icmp icmp;
} packet;
unsigned short id = rand16();
unsigned int i, j, timeout_count;
unsigned int i, j;
int gotreply = 0;
time_t start, now;
#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
if ((fd = make_icmp_sock()) == -1)
@@ -1765,14 +1793,46 @@ int icmp_ping(struct in_addr addr)
while (retry_send(sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
(struct sockaddr *)&saddr, sizeof(saddr))));
for (now = start = dnsmasq_time(), timeout_count = 0;
(difftime(now, start) < (float)PING_WAIT) && (timeout_count < PING_WAIT * 4);)
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);)
{
struct sockaddr_in faddr;
socklen_t len = sizeof(faddr);
poll_reset();
poll_listen(fd, POLLIN);
if (fd != -1)
poll_listen(fd, POLLIN);
set_dns_listeners(now);
set_log_writer();
@@ -1789,10 +1849,10 @@ int icmp_ping(struct in_addr addr)
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);
@@ -1802,27 +1862,26 @@ int icmp_ping(struct in_addr addr)
check_tftp_listeners(now);
#endif
if (poll_check(fd, POLLIN) &&
recvfrom(fd, &packet, sizeof(packet), 0,
(struct sockaddr *)&faddr, &len) == sizeof(packet) &&
saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
packet.icmp.icmp_type == ICMP_ECHOREPLY &&
packet.icmp.icmp_seq == 0 &&
packet.icmp.icmp_id == id)
{
gotreply = 1;
break;
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;
}
}
#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;
return 0;
}
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -14,7 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define COPYRIGHT "Copyright (c) 2000-2015 Simon Kelley"
#define COPYRIGHT "Copyright (c) 2000-2016 Simon Kelley"
#ifndef NO_LARGEFILE
/* Ensure we can use files >2GB (log files may grow this big) */
@@ -117,7 +117,6 @@ typedef unsigned long long u64;
#include <sys/uio.h>
#include <syslog.h>
#include <dirent.h>
#include <utime.h>
#ifndef HAVE_LINUX_NETWORK
# include <net/if_dl.h>
#endif
@@ -125,7 +124,7 @@ typedef unsigned long long u64;
#if defined(HAVE_LINUX_NETWORK)
#include <linux/capability.h>
/* There doesn't seem to be a universally-available
userpace header for these. */
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
@@ -145,30 +144,31 @@ 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_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
@@ -211,7 +211,7 @@ struct event_desc {
#define OPT_TFTP_SECURE 26
#define OPT_TFTP_NOBLOCK 27
#define OPT_LOG_OPTS 28
#define OPT_TFTP_APREF 29
#define OPT_TFTP_APREF_IP 29
#define OPT_NO_OVERRIDE 30
#define OPT_NO_REBIND 31
#define OPT_ADD_MAC 32
@@ -235,13 +235,17 @@ struct event_desc {
#define OPT_LOOP_DETECT 50
#define OPT_EXTRALOG 51
#define OPT_TFTP_NO_FAIL 52
#define OPT_DNS_CLIENT 53
#define OPT_LAST 54
#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_TFTP LOG_USER
#define MS_DHCP LOG_DAEMON
#define MS_SCRIPT LOG_MAIL
struct all_addr {
union {
@@ -284,6 +288,7 @@ struct naptr {
struct naptr *next;
};
#ifndef NO_ID
#define TXT_STAT_CACHESIZE 1
#define TXT_STAT_INSERTS 2
#define TXT_STAT_EVICTIONS 3
@@ -291,6 +296,7 @@ struct naptr {
#define TXT_STAT_HITS 5
#define TXT_STAT_AUTH 6
#define TXT_STAT_SERVERS 7
#endif
struct txt_record {
char *name;
@@ -306,8 +312,9 @@ struct ptr_record {
};
struct cname {
int ttl, flag;
char *alias, *target;
struct cname *next;
struct cname *next, *targetp;
};
struct ds_config {
@@ -337,11 +344,13 @@ struct auth_zone {
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;
@@ -477,11 +486,14 @@ union mysockaddr {
#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;
};
@@ -512,7 +524,7 @@ struct ipsets {
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;
int tftp_ok, dhcp_ok, mtu, done, warned, dad, dns_auth, index, multicast_done, found, label;
char *name;
struct irec *next;
};
@@ -635,7 +647,7 @@ struct frec {
#define ACTION_ADD 4
#define ACTION_TFTP 5
#define ACTION_ARP 6
#define ACTION_ARP_OLD 7
#define ACTION_ARP_DEL 7
#define LEASE_NEW 1 /* newly created */
#define LEASE_CHANGED 2 /* modified */
@@ -694,6 +706,12 @@ struct tag_if {
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];
@@ -780,7 +798,7 @@ struct pxe_service {
#define MATCH_REMOTE 4
#define MATCH_SUBSCRIBER 5
/* vendorclass, userclass, remote-id or cicuit-id */
/* vendorclass, userclass, remote-id or circuit-id */
struct dhcp_vendor {
int len, match_type;
unsigned int enterprise;
@@ -822,7 +840,8 @@ struct prefix_class {
struct ra_interface {
char *name;
int interval, lifetime, prio;
char *mtu_name;
int interval, lifetime, prio, mtu;
struct ra_interface *next;
};
@@ -949,8 +968,8 @@ extern struct daemon {
char *log_file; /* optional log file */
int max_logs; /* queue limit */
int cachesize, ftabsize;
int port, query_port, min_port;
unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, max_cache_ttl, auth_ttl;
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;
@@ -964,13 +983,14 @@ extern struct daemon {
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;
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;
@@ -987,6 +1007,7 @@ extern struct daemon {
#endif
#ifdef HAVE_DNSSEC
struct ds_config *ds;
int dnssec_no_time_check;
int back_to_the_future;
char *timestamp_file;
#endif
@@ -1073,7 +1094,9 @@ void cache_add_dhcp_entry(char *host_name, int prot, struct all_addr *host_addre
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);
@@ -1239,6 +1262,7 @@ int enumerate_interfaces(int reset);
void create_wildcard_listeners(void);
void create_bound_listeners(int die);
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_dns);
@@ -1267,9 +1291,11 @@ struct dhcp_context *address_available(struct dhcp_context *context,
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);
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);
@@ -1318,7 +1344,8 @@ void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data,
/* 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 *is_inform, int pxe_fd, struct in_addr fallback);
size_t sz, time_t now, int unicast_dest, int loopback,
int *is_inform, int pxe_fd, 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
@@ -1327,6 +1354,7 @@ unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
#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);
@@ -1465,6 +1493,7 @@ void log_relay(int family, struct dhcp_relay *relay);
/* 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);
@@ -1480,7 +1509,7 @@ void put_opt6_string(char *s);
void ra_init(time_t now);
void icmp6_packet(time_t now);
time_t periodic_ra(time_t now);
void ra_start_unsolicted(time_t now, struct dhcp_context *context);
void ra_start_unsolicited(time_t now, struct dhcp_context *context);
#endif
/* slaac.c */
@@ -1518,7 +1547,7 @@ int expand_workspace(unsigned char ***wkspc, int *szp, int new);
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);
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);

View File

@@ -1,5 +1,5 @@
/* dnssec.c is Copyright (c) 2012 Giovanni Bajo <rasky@develer.com>
and Copyright (c) 2012-2015 Simon Kelley
and Copyright (c) 2012-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
@@ -358,7 +358,7 @@ static int verify(struct blockdata *key_data, unsigned int key_len, unsigned cha
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 delcared as 2049 (allowing for the trailing zero)
The buffers are all declared as 2049 (allowing for the trailing zero)
for this reason.
*/
static int to_wire(char *name)
@@ -475,7 +475,7 @@ int setup_timestamp(void)
if (difftime(timestamp_time, time(0)) <= 0)
{
/* time already OK, update timestamp, and do key checking from the start. */
if (utime(daemon->timestamp_file, NULL) == -1)
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;
@@ -489,12 +489,14 @@ int setup_timestamp(void)
int fd = open(daemon->timestamp_file, O_WRONLY | O_CREAT | O_NONBLOCK | O_EXCL, 0666);
if (fd != -1)
{
struct utimbuf timbuf;
struct timeval tv[2];
close(fd);
timestamp_time = timbuf.actime = timbuf.modtime = 1420070400; /* 1-1-2015 */
if (utime(daemon->timestamp_file, &timbuf) == 0)
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;
}
}
@@ -519,18 +521,19 @@ static int check_date_range(u32 date_start, u32 date_end)
{
if (daemon->back_to_the_future == 0 && difftime(timestamp_time, curtime) <= 0)
{
if (utime(daemon->timestamp_file, NULL) != 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;
set_option_bool(OPT_DNSSEC_TIME);
daemon->dnssec_no_time_check = 0;
queue_event(EVENT_RELOAD); /* purge cache */
}
if (daemon->back_to_the_future == 0)
return 1;
}
else if (option_bool(OPT_DNSSEC_TIME))
else if (daemon->dnssec_no_time_check)
return 1;
/* We must explicitly check against wanted values, because of SERIAL_UNDEF */
@@ -669,7 +672,7 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
static unsigned char **rrset = NULL, **sigs = NULL;
/* Get pointers to RRset menbers and signature(s) for same.
/* 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)
@@ -1466,7 +1469,7 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
if (offset < p[1] && (p[offset+2] & mask) != 0)
return 0;
break; /* finshed checking */
break; /* finished checking */
}
rdlen -= p[1];
@@ -1624,7 +1627,7 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige
if (offset < p[1] && (p[offset+2] & mask) != 0)
return 0;
break; /* finshed checking */
break; /* finished checking */
}
rdlen -= p[1];
@@ -1697,7 +1700,15 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
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))
@@ -1783,7 +1794,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
}
while ((closest_encloser = strchr(closest_encloser, '.')));
if (!closest_encloser)
if (!closest_encloser || !next_closest)
return 0;
/* Look for NSEC3 that proves the non-existence of the next-closest encloser */
@@ -1873,10 +1884,27 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
*/
static int zone_status(char *name, int class, char *keyname, time_t now)
{
int name_start = strlen(name);
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]);
@@ -1884,7 +1912,7 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS)))
return STAT_NEED_DS;
/* F_DNSSECOK misused in DS cache records to non-existance of NS record.
/* 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
@@ -2102,7 +2130,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
/* 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 gennuine record doesn't exist. Check that here.
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. */

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -77,18 +77,31 @@ int is_name_synthetic(int flags, char *name, struct all_addr *addr)
*p = 0;
/* swap . or : for - */
for (p = tail; *p; p++)
if (*p == '-')
{
if (prot == AF_INET)
#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 = '.';
#ifdef HAVE_IPV6
else
*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)
@@ -169,8 +182,9 @@ int is_rev_synth(int flag, struct all_addr *addr, char *name)
inet_ntop(AF_INET6, &addr->addr.addr6, name+1, ADDRSTRLEN);
}
/* V4-mapped have periods.... */
for (p = name; *p; p++)
if (*p == ':')
if (*p == ':' || *p == '.')
*p = '-';
strncat(name, ".", MAXDNAME);

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -95,8 +95,10 @@ unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t
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)
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;
@@ -120,7 +122,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
if (set_do)
{
p -=2;
p -= 2;
flags |= 0x8000;
PUTSHORT(flags, p);
}
@@ -136,13 +138,36 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
return plen;
/* check if option already there */
for (i = 0; i + 4 < rdlen; i += len + 4)
for (i = 0; i + 4 < rdlen;)
{
GETSHORT(code, p);
GETSHORT(len, p);
/* malformed option, delete the whole OPT RR and start again. */
if (i + len > rdlen)
{
rdlen = 0;
is_last = 0;
break;
}
if (code == optno)
return plen;
p += len;
{
if (replace == 0)
return plen;
/* delete option if we're to replace it. */
p -= 4;
rdlen -= len + 4;
memcpy(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 */
@@ -190,7 +215,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
return plen; /* Too big */
/* Add new option */
if (optno != 0)
if (optno != 0 && replace != 2)
{
PUTSHORT(optno, p);
PUTSHORT(optlen, p);
@@ -203,7 +228,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
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);
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1, 0);
}
static unsigned char char64(unsigned char c)
@@ -221,23 +246,25 @@ static void encoder(unsigned char *in, char *out)
static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
{
int maclen;
int maclen, replace = 2; /* can't get mac address, just delete any incoming. */
unsigned char mac[DHCP_CHADDR_MAX];
char encode[8]; /* handle 6 byte MACs */
char encode[18]; /* handle 6 byte MACs */
if ((maclen = find_mac(l3, mac, 1, now)) == 6)
{
encoder(mac, encode);
encoder(mac+3, encode+4);
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, 8, 0);
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;
}
}
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);
return plen;
return add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, strlen(encode), 0, replace);
}
@@ -247,7 +274,7 @@ static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *lim
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);
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0);
return plen;
}
@@ -277,11 +304,14 @@ 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;
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)
if (source->sa.sa_family == AF_INET6 && daemon->add_subnet6)
{
opt->source_netmask = daemon->add_subnet6->mask;
if (daemon->add_subnet6->addr_used)
@@ -292,8 +322,9 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
else
addrp = &source->in6.sin6_addr;
}
else
#endif
if (source->sa.sa_family == AF_INET && daemon->add_subnet4)
{
opt->source_netmask = daemon->add_subnet4->mask;
if (daemon->add_subnet4->addr_used)
@@ -301,26 +332,26 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
sa_family = daemon->add_subnet4->addr.sa.sa_family;
addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
}
else
addrp = &source->in.sin_addr;
else
addrp = &source->in.sin_addr;
}
opt->scope_netmask = 0;
#ifdef HAVE_IPV6
opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
#else
opt->family = htons(1);
#endif
len = 0;
if (opt->source_netmask != 0)
if (addrp && opt->source_netmask != 0)
{
#ifdef HAVE_IPV6
opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
#else
opt->family = htons(1);
#endif
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;
}
@@ -332,7 +363,7 @@ static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned c
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);
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)
@@ -381,8 +412,12 @@ size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *l
if (option_bool(OPT_ADD_MAC))
plen = add_mac(header, plen, limit, source, now);
if (option_bool(OPT_DNS_CLIENT))
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))
{

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -106,8 +106,8 @@ int send_from(int fd, int nowild, char *packet, size_t len,
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)
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
@@ -120,8 +120,10 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp,
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 */
if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
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;
@@ -151,7 +153,7 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp,
hostname_isequal(matchstart, serv->domain) &&
(domainlen == 0 || namelen == domainlen || *(matchstart-1) == '.' ))
{
if (serv->flags & SERV_NO_REBIND)
if ((serv->flags & SERV_NO_REBIND) && norebind)
*norebind = 1;
else
{
@@ -175,7 +177,7 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp,
if (domainlen >= matchlen)
{
*type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND);
*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)
@@ -202,7 +204,7 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp,
}
}
if (flags == 0 && !(qtype & F_QUERY) &&
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;
@@ -233,12 +235,13 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
struct frec *forward, int ad_reqd, int do_bit)
{
char *domain = NULL;
int type = 0, norebind = 0;
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;
@@ -248,9 +251,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
(void)do_bit;
/* may be no servers available. */
if (!daemon->servers)
forward = NULL;
else if (forward || (hash && (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash))))
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.
@@ -315,6 +316,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
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);
@@ -324,9 +329,14 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (gotname)
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
if (!flags && !(forward = get_new_frec(now, NULL, 0)))
/* table full - server failure. */
flags = F_NEG;
#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)
{
@@ -406,7 +416,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
}
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID))
if (option_bool(OPT_DNSSEC_VALID) && do_dnssec)
{
size_t new = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
@@ -634,7 +644,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
return resize_packet(header, n, pheader, plen);
/* Complain loudly if the upstream server is non-recursive. */
if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR && ntohs(header->ancount) == 0 &&
if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR &&
server && !(server->flags & SERV_WARNED_RECURSIVE))
{
prettyprint_addr(&server->addr, daemon->namebuff);
@@ -800,9 +810,9 @@ void reply_query(int fd, int family, time_t now)
{
header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
if (forward->flags |= FREC_CHECKING_DISABLED)
if (forward->flags & FREC_CHECKING_DISABLED)
header->hb4 |= HB4_CD;
if (forward->flags |= FREC_AD_QUESTION)
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);
@@ -845,7 +855,8 @@ void reply_query(int fd, int family, time_t now)
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) != SERVFAIL)
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;
@@ -858,7 +869,8 @@ void reply_query(int fd, int family, time_t now)
no_cache_dnssec = 1;
#ifdef HAVE_DNSSEC
if (server && option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
if (server && (server->flags & SERV_DO_DNSSEC) &&
option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
{
int status = 0;
@@ -867,10 +879,10 @@ void reply_query(int fd, int family, time_t now)
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 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;
@@ -887,7 +899,7 @@ void reply_query(int fd, int family, time_t now)
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), NULL, NULL);
option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags & SERV_DO_DNSSEC), NULL, NULL);
}
/* Can't validate, as we're missing key data. Put this
@@ -912,11 +924,45 @@ void reply_query(int fd, int family, time_t now)
status = STAT_ABANDONED;
else
{
int fd;
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
@@ -971,6 +1017,15 @@ void reply_query(int fd, int family, time_t now)
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))));
@@ -984,7 +1039,7 @@ void reply_query(int fd, int family, time_t now)
if (!forward->dependent)
break;
/* validated subsdiary query, (and cached result)
/* 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);
@@ -1033,7 +1088,7 @@ void reply_query(int fd, int family, time_t now)
else
header->hb4 &= ~HB4_CD;
if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer,
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)))
{
@@ -1272,8 +1327,8 @@ void receive_query(struct listener *listen, time_t now)
{
struct irec *iface;
/* get the netmask of the interface whch has the address we were sent to.
This is no neccessarily the interface we arrived on. */
/* 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 &&
@@ -1394,20 +1449,25 @@ void receive_query(struct listener *listen, time_t now)
}
#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 *keycount)
int class, char *name, char *keyname, struct server *server,
int have_mark, unsigned int mark, int *keycount)
{
/* Recurse up the key heirarchy */
int new_status;
unsigned char *packet = NULL;
size_t m;
unsigned char *payload = NULL;
struct dns_header *new_header = NULL;
u16 *length = NULL;
unsigned char c1, c2;
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;
@@ -1416,7 +1476,8 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
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), NULL, NULL);
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;
@@ -1441,24 +1502,88 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, server->edns_pktsz);
*length = htons(m);
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))
/* 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;
}
m = (c1 << 8) | c2;
new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, keycount);
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);
@@ -1468,7 +1593,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
/* The daemon forks before calling this: it should deal with one connection,
blocking as neccessary, and then return. Note, need to be a bit careful
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,
@@ -1497,10 +1622,31 @@ unsigned char *tcp_request(int confd, time_t now,
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))
{
@@ -1626,7 +1772,7 @@ unsigned char *tcp_request(int confd, time_t now,
{
unsigned int flags = 0;
struct all_addr *addrp = NULL;
int type = 0;
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);
@@ -1639,6 +1785,8 @@ unsigned char *tcp_request(int confd, time_t now,
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
@@ -1657,7 +1805,7 @@ unsigned char *tcp_request(int confd, time_t now,
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 subtley ensures that consecutive queries on this connection
Note that this code subtly ensures that consecutive queries on this connection
which can go to the same server, do so. */
while (1)
{
@@ -1677,7 +1825,8 @@ unsigned char *tcp_request(int confd, time_t now,
(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)
@@ -1685,20 +1834,8 @@ unsigned char *tcp_request(int confd, time_t now,
#ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing connection. */
if (option_bool(OPT_CONNTRACK))
{
unsigned int mark;
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;
if (get_incoming_mark(&peer_addr, &local, 1, &mark))
setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
}
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) ||
@@ -1709,25 +1846,27 @@ unsigned char *tcp_request(int confd, time_t now,
continue;
}
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID))
{
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
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 */
@@ -1741,9 +1880,17 @@ unsigned char *tcp_request(int confd, time_t now,
{
close(last_server->tcpfd);
last_server->tcpfd = -1;
continue;
}
/* 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)
@@ -1756,10 +1903,11 @@ unsigned char *tcp_request(int confd, time_t now,
#endif
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled)
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, &keycount);
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)
@@ -1930,6 +2078,8 @@ static void free_frec(struct frec *f)
#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
@@ -1976,7 +2126,7 @@ struct frec *get_new_frec(time_t now, int *wait, int force)
/* can't find empty one, use oldest if there is one
and it's older than timeout */
if (oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
if (!force && oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
{
/* keep stuff for twice timeout if we can by allocating a new
record instead */
@@ -2016,7 +2166,7 @@ struct frec *get_new_frec(time_t now, int *wait, int force)
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)
{

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -14,11 +14,12 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include "dnsmasq.h"
#ifdef HAVE_SCRIPT
/* This file has code to fork a helper process which recieves data via a pipe
/* 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.
@@ -135,7 +136,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
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)
{
@@ -189,6 +190,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
unsigned char *buf = (unsigned char *)daemon->namebuff;
unsigned char *end, *extradata, *alloc_buff = NULL;
int is6, err = 0;
int pipeout[2];
free(alloc_buff);
@@ -221,12 +223,12 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
}
else if (data.action == ACTION_ARP)
{
action_str = "arp";
action_str = "arp-add";
is6 = (data.flags != AF_INET);
}
else if (data.action == ACTION_ARP_OLD)
else if (data.action == ACTION_ARP_DEL)
{
action_str = "arp-old";
action_str = "arp-del";
is6 = (data.flags != AF_INET);
data.action = ACTION_ARP;
}
@@ -300,7 +302,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
if (!is6)
inet_ntop(AF_INET, &data.addr, daemon->addrbuff, ADDRSTRLEN);
#ifdef HAVE_DHCP6
#ifdef HAVE_IPV6
else
inet_ntop(AF_INET6, &data.addr6, daemon->addrbuff, ADDRSTRLEN);
#endif
@@ -472,16 +474,54 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
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)
continue;
{
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)
{
@@ -504,6 +544,15 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
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)
{
@@ -556,6 +605,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
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);
@@ -579,7 +629,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
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);

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -54,7 +54,10 @@ static char *my_readlink(char *path)
{
/* Not link or doesn't exist. */
if (errno == EINVAL || errno == ENOENT)
return NULL;
{
free(buf);
return NULL;
}
else
die(_("cannot access path %s: %s"), path, EC_MISC);
}
@@ -101,7 +104,7 @@ void inotify_dnsmasq_init()
strcpy(path, res->name);
/* Follow symlinks until we reach a non-symlink, or a non-existant file. */
/* Follow symlinks until we reach a non-symlink, or a non-existent file. */
while ((new_path = my_readlink(path)))
{
if (links-- == 0)
@@ -200,6 +203,8 @@ void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revh
free(path);
}
}
closedir(dir_stream);
}
}
@@ -255,7 +260,7 @@ int inotify_check(time_t now)
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->doing_dhcp6)
{
/* Propogate the consequences of loading a new dhcp-host */
/* Propagate the consequences of loading a new dhcp-host */
dhcp_update_configs(daemon->dhcp_conf);
lease_update_from_configs();
lease_update_file(now);
@@ -268,7 +273,7 @@ int inotify_check(time_t now)
{
if (option_read_dynfile(path, AH_DHCP_HST))
{
/* Propogate the consequences of loading a new dhcp-host */
/* Propagate the consequences of loading a new dhcp-host */
dhcp_update_configs(daemon->dhcp_conf);
lease_update_from_configs();
lease_update_file(now);

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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

View File

@@ -211,7 +211,7 @@ static int old_add_to_ipset(const char *setname, const struct all_addr *ipaddr,
int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags, int remove)
{
int af = AF_INET;
int ret = 0, af = AF_INET;
#ifdef HAVE_IPV6
if (flags & F_IPV6)
@@ -219,11 +219,20 @@ int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags,
af = AF_INET6;
/* old method only supports IPv4 */
if (old_kernel)
return -1;
{
errno = EAFNOSUPPORT ;
ret = -1;
}
}
#endif
return old_kernel ? old_add_to_ipset(setname, ipaddr, remove) : new_add_to_ipset(setname, ipaddr, af, remove);
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

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -21,21 +21,126 @@
static struct dhcp_lease *leases = NULL, *old_leases = NULL;
static int dns_dirty, file_dirty, leases_left;
void lease_init(time_t now)
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",
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
set without a script, we just do without any
lease database. */
#ifdef HAVE_SCRIPT
if (daemon->lease_change_command)
@@ -56,99 +161,24 @@ void lease_init(time_t now)
{
/* 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);
}
/* client-id max length is 255 which is 255*2 digits + 254 colons
borrow DNS packet buffer which is always larger than 1000 bytes */
if (leasestream)
while (fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2) == 2)
{
#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);
daemon->duid = safe_malloc(daemon->duid_len);
memcpy(daemon->duid, daemon->dhcp_buff2, daemon->duid_len);
continue;
}
#endif
{
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);
ei = atol(daemon->dhcp_buff3);
if (fscanf(leasestream, " %64s %255s %764s",
daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3)
break;
clid_len = 0;
if (strcmp(daemon->packet, "*") != 0)
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
if (inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4) &&
(lease = lease4_allocate(addr.addr.addr4)))
{
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
/* For backwards compatibility, no explict MAC address type means ether. */
if (hw_type == 0 && hw_len != 0)
hw_type = ARPHRD_ETHER;
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, get_domain(lease->addr), NULL);
}
#ifdef HAVE_DHCP6
else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6))
{
char *s = daemon->dhcp_buff2;
int lease_type = LEASE_NA;
int iaid;
if (s[0] == 'T')
{
lease_type = LEASE_TA;
s++;
}
iaid = strtoul(s, NULL, 10);
if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
{
lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, 0, clid_len, now, 0);
lease_set_iaid(lease, iaid);
if (strcmp(daemon->dhcp_buff, "*") != 0)
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL);
}
}
#endif
else
break;
if (!lease)
die (_("too many stored leases"), NULL, EC_MISC);
#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);
}
if (ferror(leasestream))
die(_("failed to read lease file %s: %s"), daemon->lease_file, EC_FILE);
}
#ifdef HAVE_SCRIPT
if (!daemon->lease_stream)
@@ -162,6 +192,7 @@ void lease_init(time_t now)
errno = ENOENT;
else if (WEXITSTATUS(rc) == 126)
errno = EACCES;
die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command, EC_FILE);
}
@@ -406,7 +437,7 @@ void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *inte
void lease_update_slaac(time_t now)
{
/* Called when we contruct a new RA-names context, to add putative
/* Called when we construct a new RA-names context, to add putative
new SLAAC addresses to existing leases. */
struct dhcp_lease *lease;
@@ -776,7 +807,7 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
{
exp = now + (time_t)len;
/* Check for 2038 overflow. Make the lease
inifinite in that case, as the least disruptive
infinite in that case, as the least disruptive
thing we can do. */
if (difftime(exp, now) <= 0.0)
exp = 0;
@@ -1110,18 +1141,22 @@ int do_script_run(time_t now)
}
#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;
/* check for embeded NULLs */
for (i = 0; i < len; i++)
if (data[i] == 0)
{
len = i;
break;
}
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;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -154,7 +154,7 @@ static void log_write(void)
while (entries)
{
/* The data in the payoad is written with a terminating zero character
/* 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
@@ -288,7 +288,9 @@ void my_syslog(int priority, const char *format, ...)
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
@@ -436,7 +438,7 @@ void check_log_writer(int force)
void flush_log(void)
{
/* write until queue empty, but don't loop forever if there's
no connection to the syslog in existance */
no connection to the syslog in existence */
while (log_fd != -1)
{
struct timespec waiter;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -73,7 +73,7 @@ void netlink_init(void)
}
if (daemon->netlinkfd == -1 ||
getsockname(daemon->netlinkfd, (struct sockaddr *)&addr, &slen) == 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() */
@@ -188,11 +188,17 @@ int iface_enumerate(int family, void *parm, int (*callback)())
}
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
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)

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -178,7 +178,7 @@ int iface_check(int family, struct all_addr *addr, char *name, int *auth)
}
/* Fix for problem that the kernel sometimes reports the loopback inerface as the
/* 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
@@ -244,6 +244,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
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
@@ -264,6 +265,8 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
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))
@@ -482,6 +485,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
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);
@@ -532,13 +536,14 @@ static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
{
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 = broadcast; /* warning */
addr.in.sin_addr = local;
addr.in.sin_port = htons(daemon->port);
@@ -643,7 +648,7 @@ int enumerate_interfaces(int reset)
/* 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 re-entrancy, hence it's here. It also means there's a possibility,
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;
@@ -698,7 +703,7 @@ static int make_sock(union mysockaddr *addr, int type, int dienow)
if ((fd = socket(family, type, 0)) == -1)
{
int port, errsav;
int port, errsave;
char *s;
/* No error if the kernel just doesn't support this IP flavour */
@@ -708,7 +713,7 @@ static int make_sock(union mysockaddr *addr, int type, int dienow)
return -1;
err:
errsav = errno;
errsave = errno;
port = prettyprint_addr(addr, daemon->addrbuff);
if (!option_bool(OPT_NOWILD) && !option_bool(OPT_CLEVERBIND))
sprintf(daemon->addrbuff, "port %d", port);
@@ -717,7 +722,7 @@ static int make_sock(union mysockaddr *addr, int type, int dienow)
if (fd != -1)
close (fd);
errno = errsav;
errno = errsave;
if (dienow)
{
@@ -745,7 +750,7 @@ static int make_sock(union mysockaddr *addr, int type, int dienow)
if (type == SOCK_STREAM)
{
if (listen(fd, 5) == -1)
if (listen(fd, TCP_BACKLOG) == -1)
goto err;
}
else if (family == AF_INET)
@@ -809,10 +814,11 @@ int tcp_interface(int fd, int af)
int opt = 1;
struct cmsghdr *cmptr;
struct msghdr msg;
socklen_t len;
/* use mshdr do that the CMSDG_* macros are available */
/* use mshdr so that the CMSDG_* macros are available */
msg.msg_control = daemon->packet;
msg.msg_controllen = daemon->packet_buff_sz;
msg.msg_controllen = len = daemon->packet_buff_sz;
/* we overwrote the buffer... */
daemon->srv_save = NULL;
@@ -820,18 +826,21 @@ int tcp_interface(int fd, int af)
if (af == AF_INET)
{
if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) != -1 &&
getsockopt(fd, IPPROTO_IP, IP_PKTOPTIONS, msg.msg_control, (socklen_t *)&msg.msg_controllen) != -1)
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;
}
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
@@ -849,9 +858,10 @@ int tcp_interface(int fd, int af)
#endif
if (set_ipv6pktinfo(fd) &&
getsockopt(fd, IPPROTO_IPV6, PKTOPTIONS, msg.msg_control, (socklen_t *)&msg.msg_controllen) != -1)
getsockopt(fd, IPPROTO_IPV6, PKTOPTIONS, msg.msg_control, &len) != -1)
{
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
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 {
@@ -1028,6 +1038,15 @@ void warn_bound_listeners(void)
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;
@@ -1119,7 +1138,7 @@ int random_sock(int family)
if ((fd = socket(family, SOCK_DGRAM, 0)) != -1)
{
union mysockaddr addr;
unsigned int ports_avail = 65536u - (unsigned short)daemon->min_port;
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));
@@ -1132,8 +1151,8 @@ int random_sock(int family)
{
unsigned short port = rand16();
if (daemon->min_port != 0)
port = htons(daemon->min_port + (port % ((unsigned short)ports_avail)));
if (daemon->min_port != 0 || daemon->max_port != MAX_PORT)
port = htons(daemon->min_port + (port % ((unsigned short)ports_avail)));
if (family == AF_INET)
{
@@ -1198,6 +1217,7 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
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
@@ -1218,11 +1238,15 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
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)
strcmp(intname, sfd->interface) == 0 &&
ifindex == sfd->ifindex)
return sfd;
/* need to make a new one. */
@@ -1244,11 +1268,13 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
errno = errsave;
return NULL;
}
strcpy(sfd->interface, intname);
sfd->source_addr = *addr;
sfd->next = daemon->sfds;
sfd->ifindex = ifindex;
daemon->sfds = sfd;
return sfd;
}
@@ -1403,7 +1429,6 @@ void add_update_server(int flags,
serv->domain = domain_str;
serv->next = next;
serv->queries = serv->failed_queries = 0;
serv->edns_pktsz = daemon->edns_pktsz;
#ifdef HAVE_LOOP
serv->uid = rand32();
#endif
@@ -1424,18 +1449,58 @@ void check_servers(void)
{
struct irec *iface;
struct server *serv;
int port = 0;
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 (serv = daemon->servers; serv; serv = serv->next)
{
if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
{
port = prettyprint_addr(&serv->addr, daemon->namebuff);
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)
@@ -1465,13 +1530,23 @@ void check_servers(void)
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;
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)
@@ -1480,11 +1555,15 @@ void check_servers(void)
s1 = _("domain"), s2 = serv->domain;
if (serv->flags & SERV_NO_ADDR)
my_syslog(LOG_INFO, _("using local addresses only for %s %s"), s1, s2);
{
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"), daemon->namebuff, port, s1, s2);
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)
@@ -1496,7 +1575,26 @@ void check_servers(void)
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();
}

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -154,8 +154,13 @@ struct myoption {
#define LOPT_HOST_INOTIFY 342
#define LOPT_DNSSEC_STAMP 343
#define LOPT_TFTP_NO_FAIL 344
#define LOPT_DNS_CLIENT_ID 355
#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
@@ -238,9 +243,10 @@ static const struct myoption opts[] =
{ "enable-tftp", 2, 0, LOPT_TFTP },
{ "tftp-secure", 0, 0, LOPT_SECURE },
{ "tftp-no-fail", 0, 0, LOPT_TFTP_NO_FAIL },
{ "tftp-unique-root", 0, 0, LOPT_APREF },
{ "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 },
@@ -271,6 +277,7 @@ static const struct myoption opts[] =
{ "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 },
@@ -280,9 +287,9 @@ static const struct myoption opts[] =
{ "dhcp-proxy", 2, 0, LOPT_PROXY },
{ "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES },
{ "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND },
{ "add-mac", 0, 0, LOPT_ADD_MAC },
{ "add-mac", 2, 0, LOPT_ADD_MAC },
{ "add-subnet", 2, 0, LOPT_ADD_SBNET },
{ "add-dns-client", 2, 0 , LOPT_DNS_CLIENT_ID },
{ "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 },
@@ -315,6 +322,9 @@ static const struct myoption opts[] =
{ "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 }
};
@@ -394,7 +404,7 @@ static struct {
{ '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 for known DHCP options."), 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 },
@@ -412,8 +422,9 @@ static struct {
{ '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, "<facilty>|<file>", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), 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 },
@@ -421,10 +432,11 @@ static struct {
{ 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, OPT_TFTP_APREF, NULL, gettext_noop("Add client IP address to tftp-root."), 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 conncurrent TFTP transfers (defaults to %s)."), "#" },
{ 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 },
@@ -438,33 +450,34 @@ static struct {
{ 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>[,<interface>]", gettext_noop("Relay DHCP requests to a remote server"), NULL},
{ LOPT_CNAME, ARG_DUP, "<alias>,<target>", gettext_noop("Specify alias name for LOCAL DNS name."), 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, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), 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_DNS_CLIENT_ID, ARG_ONE, "<proxyname>", gettext_noop("Add client identification 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>", gettext_noop("Specify host (A/AAAA and PTR) records"), 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 authoritive zone information"), 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>/<ipset>[,<ipset>...]", gettext_noop("Specify ipsets to which matching domains should be added"), 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 },
@@ -475,17 +488,19 @@ static struct {
#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, "<interface>,[high,|low,]<interval>[,<lifetime>]", gettext_noop("Set priority, resend-interval and router-lifetime"), NULL },
{ 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_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 metacharaters in quoted strings by mapping them into the ASCII control
/* 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.
@@ -645,7 +660,8 @@ static int atoi_check8(char *a, int *res)
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));
@@ -658,13 +674,14 @@ static void add_txt(char *name, char *txt, int stat)
*(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)
{
@@ -709,7 +726,7 @@ static void do_usage(void)
sprintf(buff, " ");
sprintf(buff+4, "--%s%s%s", opts[j].name, eq, desc);
printf("%-40.40s", buff);
printf("%-55.55s", buff);
if (usage[i].arg)
{
@@ -743,6 +760,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
{
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;
@@ -768,6 +786,19 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
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);
@@ -786,6 +817,9 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
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
@@ -818,7 +852,10 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
if (inet_pton(AF_INET6, source, &source_addr->in6.sin6_addr) == 0)
{
#if defined(SO_BINDTODEVICE)
source_addr->in6.sin6_addr = in6addr_any;
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");
@@ -836,19 +873,31 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
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) >> 8;
in_addr_t a = ntohl(addr.s_addr);
char *p;
memset(serv, 0, sizeof(struct server));
p = serv->domain = opt_malloc(25); /* strlen("xxx.yyy.zzz.in-addr.arpa")+1 */
if (msize == 24)
p += sprintf(p, "%d.", a & 0xff);
a = a >> 8;
if (msize != 8)
p += sprintf(p, "%d.", a & 0xff);
a = a >> 8;
p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
p = serv->domain = opt_malloc(29); /* strlen("xxx.yyy.zzz.ttt.in-addr.arpa")+1 */
switch (msize)
{
case 32:
p += sprintf(p, "%d.", 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;
@@ -1187,7 +1236,8 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
cp = comma;
comma = split(cp);
slash = split_chr(cp, '/');
inet_pton(AF_INET, cp, &in);
if (!inet_pton(AF_INET, cp, &in))
ret_err(_("bad IPv4 address"));
if (!slash)
{
memcpy(op, &in, INADDRSZ);
@@ -1635,12 +1685,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
daemon->add_subnet4 = new;
new = opt_malloc(sizeof(struct mysubnet));
if (comma)
{
if ((end = split_chr(comma, '/')))
{
/* has subnet+len */
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);
@@ -1653,8 +1703,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (!atoi_check(comma, &new->mask))
ret_err(gen_err);
}
}
daemon->add_subnet6 = new;
daemon->add_subnet6 = new;
}
}
break;
@@ -1892,6 +1943,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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;
@@ -1899,6 +1951,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
while ((arg = comma))
{
int prefixlen = 0;
int is_exclude = 0;
char *prefix;
struct addrlist *subnet = NULL;
struct all_addr addr;
@@ -1909,6 +1962,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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));
@@ -1946,8 +2005,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (subnet)
{
subnet->addr = addr;
subnet->next = new->subnet;
new->subnet = subnet;
if (is_exclude)
{
subnet->next = new->exclude;
new->exclude = subnet;
}
else
{
subnet->next = new->subnet;
new->subnet = subnet;
}
}
}
break;
@@ -1977,11 +2045,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
comma = split(arg);
daemon->soa_retry = (u32)atoi(arg);
if (comma)
{
arg = comma;
comma = split(arg);
daemon->soa_expiry = (u32)atoi(arg);
}
daemon->soa_expiry = (u32)atoi(comma);
}
}
}
@@ -2038,6 +2102,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
/* 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>/ */
@@ -2153,12 +2220,26 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
break;
case LOPT_DNS_CLIENT_ID: /* --add-dns-client */
set_option_bool(OPT_DNS_CLIENT);
if (arg)
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;
@@ -2395,7 +2476,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
ret_err(gen_err);
if (inet_pton(AF_INET, arg, &addr4))
serv = add_rev4(addr4, size);
{
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);
@@ -2512,6 +2597,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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);
@@ -2555,6 +2645,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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))
@@ -2573,6 +2664,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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;
@@ -2591,6 +2687,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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)
@@ -2619,6 +2720,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
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 */
@@ -2733,13 +2843,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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;
if (k >= 4 && strchr(a[3], '.') &&
(inet_pton(AF_INET, a[3], &new->broadcast) > 0))
{
new->flags |= CONTEXT_BRDCAST;
leasepos = 4;
}
}
}
#ifdef HAVE_DHCP6
@@ -2829,6 +2940,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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)
@@ -2923,7 +3037,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
if (len == -1)
ret_err(_("bad hex constant"));
else if ((new->clid = opt_malloc(len)))
{
@@ -3207,11 +3320,43 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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 */
@@ -3255,7 +3400,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
{
struct pxe_service *new = opt_malloc(sizeof(struct pxe_service));
char *CSA[] = { "x86PC", "PC98", "IA64_EFI", "Alpha", "Arc_x86", "Intel_Lean_Client",
"IA32_EFI", "BC_EFI", "Xscale_EFI", "x86-64_EFI", NULL };
"IA32_EFI", "x86-64_EFI", "Xscale_EFI", "BC_EFI",
"ARM32_EFI", "ARM64_EFI", NULL };
static int boottype = 32768;
new->netid = NULL;
@@ -3560,7 +3706,21 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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')
@@ -3572,6 +3732,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int 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;
@@ -3616,8 +3777,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
(!(inet_pton(AF_INET, a[1], &new->out) > 0)))
option = '?';
if (k == 3)
inet_pton(AF_INET, a[2], &new->mask);
if (k == 3 && !inet_pton(AF_INET, a[2], &new->mask))
option = '?';
if (dash &&
(!(inet_pton(AF_INET, dash, &new->end) > 0) ||
@@ -3667,27 +3828,41 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case LOPT_CNAME: /* --cname */
{
struct cname *new;
char *alias;
char *target;
char *alias, *target, *last, *pen;
int ttl = -1;
if (!(comma = split(arg)))
ret_err(gen_err);
alias = canonicalise_opt(arg);
target = canonicalise_opt(comma);
if (!alias || !target)
ret_err(_("bad CNAME"));
else
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, arg))
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;
@@ -3753,7 +3928,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case LOPT_RR: /* dns-rr */
{
struct txt_record *new;
size_t len = len;
size_t len = 0;
char *data;
int val;
@@ -3861,13 +4036,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (!atoi_check16(arg, &priority))
ret_err(_("invalid priority"));
if (comma)
{
arg = comma;
comma = split(arg);
if (!atoi_check16(arg, &weight))
ret_err(_("invalid weight"));
}
if (comma && !atoi_check16(comma, &weight))
ret_err(_("invalid weight"));
}
}
}
@@ -3888,14 +4058,22 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
{
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;
if (inet_pton(AF_INET, arg, &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))
@@ -4012,7 +4190,7 @@ static void read_file(char *file, FILE *f, int hard_opt)
{
int white, i;
volatile int option = (hard_opt == LOPT_REV_SERV) ? 0 : hard_opt;
char *errmess, *p, *arg = NULL, *start;
char *errmess, *p, *arg, *start;
size_t len;
/* Memory allocation failure longjmps here if mem_recover == 1 */
@@ -4023,6 +4201,7 @@ static void read_file(char *file, FILE *f, int hard_opt)
mem_recover = 1;
}
arg = NULL;
lineno++;
errmess = NULL;
@@ -4462,7 +4641,9 @@ void read_opts(int argc, char **argv, char *compile_opts)
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);
@@ -4475,6 +4656,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
add_txt("auth.bind", NULL, TXT_STAT_AUTH);
#endif
add_txt("servers.bind", NULL, TXT_STAT_SERVERS);
#endif
while (1)
{
@@ -4561,21 +4743,68 @@ void read_opts(int argc, char **argv, char *compile_opts)
{
struct server *tmp;
for (tmp = daemon->servers; tmp; tmp = tmp->next)
{
tmp->edns_pktsz = daemon->edns_pktsz;
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);
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);
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;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -29,9 +29,19 @@ void end_opt6(int container)
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;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -28,11 +28,12 @@
struct ra_param {
time_t now;
int ind, managed, other, found_context, first, adv_router;
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 {
@@ -81,7 +82,7 @@ void ra_init(time_t now)
/* 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 recieve ping replies */
/* 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;
@@ -111,10 +112,10 @@ void ra_init(time_t now)
daemon->icmp6fd = fd;
if (daemon->doing_ra)
ra_start_unsolicted(now, NULL);
ra_start_unsolicited(now, NULL);
}
void ra_start_unsolicted(time_t now, struct dhcp_context *context)
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.
@@ -242,7 +243,7 @@ static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_ad
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;
int done_dns = 0, old_prefix = 0, mtu = 0;
unsigned int min_pref_time;
#ifdef HAVE_LINUX_NETWORK
FILE *f;
@@ -251,7 +252,7 @@ static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_ad
parm.ind = iface;
parm.managed = 0;
parm.other = 0;
parm.found_context = 0;
parm.found_context = NULL;
parm.adv_router = 0;
parm.if_name = iface_name;
parm.first = 1;
@@ -260,8 +261,10 @@ static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_ad
parm.adv_interval = calc_interval(ra_param);
parm.prio = calc_prio(ra_param);
save_counter(0);
ra = expand(sizeof(struct ra_packet));
reset_counter();
if (!(ra = expand(sizeof(struct ra_packet))))
return;
ra->type = ND_ROUTER_ADVERT;
ra->code = 0;
@@ -308,8 +311,14 @@ static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_ad
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);
}
@@ -390,22 +399,32 @@ static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_ad
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 necessarilly the same as the IPv4 MTU
/* Note that IPv6 MTU is not neccessarily the same as the IPv4 MTU
available from SIOCGIFMTU */
sprintf(daemon->namebuff, "/proc/sys/net/ipv6/conf/%s/mtu", iface_name);
if ((f = fopen(daemon->namebuff, "r")))
if (mtu == 0)
{
if (fgets(daemon->namebuff, MAXDNAME, f))
{
put_opt6_char(ICMP6_OPT_MTU);
put_opt6_char(1);
put_opt6_short(0);
put_opt6_long(atoi(daemon->namebuff));
}
fclose(f);
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);
@@ -519,7 +538,7 @@ static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_ad
}
while (retry_send(sendto(daemon->icmp6fd, daemon->outpacket.iov_base,
save_counter(0), 0, (struct sockaddr *)&addr,
save_counter(-1), 0, (struct sockaddr *)&addr,
sizeof(addr))));
}
@@ -636,8 +655,10 @@ static int add_prefixes(struct in6_addr *local, int prefix,
off_link = (context->flags & CONTEXT_RA_OFF_LINK);
}
param->first = 0;
param->found_context = 1;
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 */
@@ -769,7 +790,7 @@ time_t periodic_ra(time_t now)
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 satistfy it. */
ever be able to send ra's and satisfy it. */
context->ra_time = 0;
if (param.iface != 0 &&

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -176,7 +176,7 @@ int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
if (hostname_isequal(lastchunk, "arpa") && hostname_isequal(penchunk, "in-addr"))
{
/* IP v4 */
/* address arives as a name of the form
/* 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. */
@@ -206,7 +206,7 @@ int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
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 reprentations are obsolete and
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.
*/
@@ -336,7 +336,7 @@ unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *h
}
/* CRC the question section. This is used to safely detect query
retransmision and to detect answers to questions we didn't ask, which
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
@@ -426,6 +426,19 @@ int private_net(struct in_addr addr, int ban_localhost)
((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;
@@ -896,9 +909,7 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
header->nscount = htons(0);
header->arcount = htons(0);
header->ancount = htons(0); /* no answers unless changed below */
if (flags == F_NEG)
SET_RCODE(header, SERVFAIL); /* couldn't get memory */
else if (flags == F_NOERR)
if (flags == F_NOERR)
SET_RCODE(header, NOERROR); /* empty domain */
else if (flags == F_NXDOMAIN)
SET_RCODE(header, NXDOMAIN);
@@ -1169,12 +1180,24 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
static unsigned long crec_ttl(struct crec *crecp, time_t now)
{
/* Return 0 ttl for DHCP entries, which might change
before the lease expires. */
before the lease expires, unless configured otherwise. */
if (crecp->flags & (F_IMMORTAL | F_DHCP))
return daemon->local_ttl;
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;
}
/* Return the Max TTL value if it is lower then the actual 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
@@ -1199,6 +1222,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
struct mx_srv_record *rec;
size_t len;
/* Clear buffer beyond request to avoid risk of
information disclosure. */
memset(((char *)header) + qlen, 0,
(limit - ((char *)header)) - qlen);
if (ntohs(header->ancount) != 0 ||
ntohs(header->nscount) != 0 ||
@@ -1254,6 +1282,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
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)
{
@@ -1261,7 +1290,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
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))
@@ -1424,20 +1453,48 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
anscount++;
}
}
else if (is_arpa == F_IPV4 &&
option_bool(OPT_BOGUSPRIV) &&
private_net(addr.addr.addr4, 1))
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))))
{
/* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
ans = 1;
sec_data = 0;
nxdomain = 1;
if (!dryrun)
log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
name, &addr, NULL);
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;
@@ -1500,9 +1557,24 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (intr)
{
struct addrlist *addrlist;
int gotit = 0;
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))
@@ -1512,6 +1584,10 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
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;
@@ -1541,7 +1617,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
{
int localise = 0;
/* See if a putative address is on the network from which we recieved
/* 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)
{
@@ -1817,7 +1893,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
/* set RA flag */
header->hb4 |= HB4_RA;
/* authoritive - only hosts and DHCP derived names. */
/* authoritative - only hosts and DHCP derived names. */
if (auth)
header->hb3 |= HB3_AA;
@@ -1837,7 +1913,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
/* 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);
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;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -63,10 +63,12 @@ static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char
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 *is_inform, int pxe, struct in_addr fallback)
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;
@@ -186,7 +188,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
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_find(mess, sz, OPTION_END, 0);
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;
@@ -364,7 +367,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
/* 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, existance of the option is enough. This code handles
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)
{
@@ -380,7 +383,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
{
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 <= (option_len(opt))) &&
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)
{
@@ -485,6 +488,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
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)
{
@@ -566,7 +576,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
lease_prune(lease, now);
lease = NULL;
}
if (!address_allocate(context, &mess->yiaddr, mess->chaddr, mess->hlen, tagif_netid, now))
if (!address_allocate(context, &mess->yiaddr, mess->chaddr, mess->hlen, tagif_netid, now, loopback))
message = _("no address available");
}
else
@@ -824,7 +834,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else
mess->siaddr = context->local;
snprintf((char *)mess->file, sizeof(mess->file), "%s.%d", service->basename, layer);
if (strchr(service->basename, '.'))
snprintf((char *)mess->file, sizeof(mess->file),
"%s.%d", service->basename, layer);
else
snprintf((char *)mess->file, sizeof(mess->file),
"%s", service->basename);
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);
@@ -851,6 +867,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
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) &&
@@ -860,7 +877,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (tmp)
{
struct dhcp_boot *boot;
int redirect4011 = 0;
if (tmp->netid.net)
{
tmp->netid.next = netid;
@@ -878,10 +896,21 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
clear_packet(mess, end);
/* Provide the bootfile here, for gPXE, and in case we have no menu items
and set discovery_control = 8 */
if (boot)
/* 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)
@@ -896,10 +925,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));
pxe_misc(mess, end, uuid);
prune_vendor_opts(tagif_netid);
do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
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);
}
}
@@ -1008,6 +1040,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
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 if (!do_icmp_ping(now, config->addr, 0, loopback))
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by another host"), addrs);
else
conf = config->addr;
}
@@ -1020,11 +1054,11 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
!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))
!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))
else if (!address_allocate(context, &mess->yiaddr, emac, emac_len, tagif_netid, now, loopback))
message = _("no address available");
}
@@ -1040,7 +1074,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
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));
@@ -1286,6 +1320,24 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
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);
@@ -1308,7 +1360,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
/* 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, 0);
lease_add_extradata(lease, ucp, len, -1);
}
}
#endif
@@ -1589,7 +1641,7 @@ static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt
{
while (1)
{
if (p > end)
if (p >= end)
return NULL;
else if (*p == OPTION_END)
return opt == OPTION_END ? p : NULL;
@@ -1975,6 +2027,56 @@ static int prune_vendor_opts(struct dhcp_netid *netid)
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
@@ -2509,7 +2611,8 @@ static void do_options(struct dhcp_context *context,
if (context && pxe_arch != -1)
{
pxe_misc(mess, end, uuid);
config_opts = pxe_opts(pxe_arch, tagif, context->local, now);
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)) &&
@@ -2528,6 +2631,29 @@ static void do_options(struct dhcp_context *context,
}
}
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

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -89,7 +89,7 @@ unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *if
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
vendor->netid.next = &vendor->netid;
save_counter(0);
reset_counter();
state.context = context;
state.interface = interface;
state.iface_name = iface_name;
@@ -118,7 +118,7 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
void *opt;
struct dhcp_vendor *vendor;
/* if not an encaplsulated relayed message, just do the stuff */
/* 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
@@ -262,7 +262,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
state->hostname_auth = 0;
state->hostname = NULL;
state->client_hostname = NULL;
state->fqdn_flags = 0x01; /* default to send if we recieve no FQDN option */
state->fqdn_flags = 0x01; /* default to send if we receive no FQDN option */
#ifdef OPTION6_PREFIX_CLASS
state->send_prefix_class = NULL;
#endif
@@ -381,7 +381,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
/* 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, existance of the option is enough. This code handles
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)
{
@@ -526,7 +526,14 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
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))
@@ -1273,7 +1280,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
}
/* We must anwser with 'success' in global section anyway */
/* We must answer with 'success' in global section anyway */
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6SUCCESS);
put_opt6_string(_("success"));
@@ -1387,7 +1394,7 @@ static struct dhcp_netid *add_options(struct state *state, int do_refresh)
unsigned int lease_time = 0xffffffff;
/* Find the smallest lease tie of all contexts,
subjext to the RFC-4242 stipulation that this must not
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)
@@ -1975,7 +1982,7 @@ static void log6_packet(struct state *state, char *type, struct in6_addr *addr,
if (addr)
{
inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, 255);
inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, DHCP_BUFF_SZ - 1);
strcat(daemon->dhcp_buff2, " ");
}
else
@@ -2084,7 +2091,7 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
if (hopcount > 32)
return;
save_counter(0);
reset_counter();
if ((header = put_opt6(NULL, 34)))
{
@@ -2127,7 +2134,7 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
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(0), &to, &from, 0);
send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0);
if (option_bool(OPT_LOG_OPTS))
{
@@ -2161,7 +2168,7 @@ unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival
(!relay->interface || wildcard_match(relay->interface, arrival_interface)))
break;
save_counter(0);
reset_counter();
if (relay)
{

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -173,7 +173,7 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
GETSHORT(qclass, p);
/* First pass, find pointers to start and end of all the records we wish to elide:
records added for DNSSEC, unless explicity queried for */
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++)
@@ -239,7 +239,15 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
if (!check_rrs(p, header, plen, 0, rrs, rr_found))
return plen;
/* Third pass, elide records */
/* 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];
@@ -254,14 +262,6 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
header->nscount = htons(ntohs(header->nscount) - chop_ns);
header->arcount = htons(ntohs(header->arcount) - chop_ar);
/* Fourth pass, fix up pointers in the remaining 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);
return plen;
}
@@ -323,12 +323,12 @@ int expand_workspace(unsigned char ***wkspc, int *szp, int new)
new += 5;
if (!(p = whine_malloc(new * sizeof(unsigned char **))))
if (!(p = whine_malloc(new * sizeof(unsigned char *))))
return 0;
if (old != 0 && *wkspc)
{
memcpy(p, *wkspc, old * sizeof(unsigned char **));
memcpy(p, *wkspc, old * sizeof(unsigned char *));
free(*wkspc);
}

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -94,7 +94,7 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
slaac->backoff = 1;
slaac->addr = addr;
/* Do RA's to prod it */
ra_start_unsolicted(now, context);
ra_start_unsolicited(now, context);
}
if (slaac)
@@ -146,8 +146,11 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
struct ping_packet *ping;
struct sockaddr_in6 addr;
save_counter(0);
ping = expand(sizeof(struct ping_packet));
reset_counter();
if (!(ping = expand(sizeof(struct ping_packet))))
continue;
ping->type = ICMP6_ECHO_REQUEST;
ping->code = 0;
ping->identifier = ping_id;
@@ -161,7 +164,7 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
addr.sin6_port = htons(IPPROTO_ICMPV6);
addr.sin6_addr = slaac->addr;
if (sendto(daemon->icmp6fd, daemon->outpacket.iov_base, save_counter(0), 0,
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 */

View File

@@ -20,9 +20,7 @@
#if defined(HAVE_IPSET) && defined(HAVE_BSD_NETWORK)
#ifndef __FreeBSD__
#include <string.h>
#endif
#include <sys/types.h>
#include <sys/ioctl.h>
@@ -53,52 +51,6 @@ static char *pfr_strerror(int errnum)
}
}
static int pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
{
struct pfioc_table io;
if (size < 0 || (size && tbl == NULL))
{
errno = EINVAL;
return (-1);
}
bzero(&io, sizeof io);
io.pfrio_flags = flags;
io.pfrio_buffer = tbl;
io.pfrio_esize = sizeof(*tbl);
io.pfrio_size = size;
if (ioctl(dev, DIOCRADDTABLES, &io))
return (-1);
if (nadd != NULL)
*nadd = io.pfrio_nadd;
return (0);
}
static int fill_addr(const struct all_addr *ipaddr, int flags, struct pfr_addr* addr) {
if ( !addr || !ipaddr)
{
my_syslog(LOG_ERR, _("error: fill_addr missused"));
return -1;
}
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;
}
return 1;
}
/*****************************************************************************/
void ipset_init(void)
{
@@ -111,14 +63,13 @@ void ipset_init(void)
}
int add_to_ipset(const char *setname, const struct all_addr *ipaddr,
int flags, int remove)
int flags, int remove)
{
struct pfr_addr addr;
struct pfioc_table io;
struct pfr_table table;
int n = 0, rc = 0;
if ( dev == -1 )
if (dev == -1)
{
my_syslog(LOG_ERR, _("warning: no opened pf devices %s"), pf_device);
return -1;
@@ -126,31 +77,52 @@ int add_to_ipset(const char *setname, const struct all_addr *ipaddr,
bzero(&table, sizeof(struct pfr_table));
table.pfrt_flags |= PFR_TFLAG_PERSIST;
if ( strlen(setname) >= PF_TABLE_NAME_SIZE )
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))
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;
}
if ((rc = pfr_add_tables(&table, 1, &n, 0)))
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, _("warning: pfr_add_tables: %s(%d)"),
pfr_strerror(errno),rc);
my_syslog(LOG_WARNING, _("IPset: error:%s"), pfr_strerror(errno));
return -1;
}
table.pfrt_flags &= ~PFR_TFLAG_PERSIST;
if (n)
my_syslog(LOG_INFO, _("info: table created"));
fill_addr(ipaddr,flags,&addr);
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;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -103,8 +103,10 @@ void tftp_request(struct listener *listen, time_t now)
if (listen->iface)
{
addr = listen->iface->addr;
mtu = listen->iface->mtu;
name = listen->iface->name;
mtu = listen->iface->mtu;
if (daemon->tftp_mtu != 0 && daemon->tftp_mtu < mtu)
mtu = daemon->tftp_mtu;
}
else
{
@@ -234,9 +236,17 @@ void tftp_request(struct listener *listen, time_t now)
strncpy(ifr.ifr_name, name, IF_NAMESIZE);
if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
mtu = ifr.ifr_mtu;
{
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 */
@@ -336,14 +346,15 @@ void tftp_request(struct listener *listen, time_t now)
{
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;
/* 32 bytes for IP, UDP and TFTP headers */
if (mtu != 0 && transfer->blocksize > (unsigned)mtu - 32)
transfer->blocksize = (unsigned)mtu - 32;
if (mtu != 0 && transfer->blocksize > (unsigned)mtu - overhead)
transfer->blocksize = (unsigned)mtu - overhead;
transfer->opt_blocksize = 1;
transfer->block = 0;
}
@@ -371,7 +382,7 @@ void tftp_request(struct listener *listen, time_t now)
if (prefix[strlen(prefix)-1] != '/')
strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
if (option_bool(OPT_TFTP_APREF))
if (option_bool(OPT_TFTP_APREF_IP))
{
size_t oldlen = strlen(daemon->namebuff);
struct stat statbuf;
@@ -383,7 +394,40 @@ void tftp_request(struct listener *listen, time_t now)
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] == '/')
{
@@ -396,7 +440,7 @@ void tftp_request(struct listener *listen, time_t now)
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)))
{
@@ -459,7 +503,7 @@ static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix)
else if (option_bool(OPT_TFTP_SECURE) && uid != statbuf.st_uid)
goto perm;
/* If we're doing many tranfers from the same file, only
/* 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
@@ -641,20 +685,24 @@ static void sanitise(char *buf)
}
#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 ret = 4;
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);
ret += (snprintf(mess->message, 500, message, file, errstr) + 1);
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;
@@ -670,6 +718,8 @@ static ssize_t tftp_err_oops(char *packet, char *file)
/* 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 */

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
/* 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
@@ -24,7 +24,9 @@
#include <sys/times.h>
#endif
#if defined(LOCALEDIR) || defined(HAVE_IDN)
#if defined(HAVE_LIBIDN2)
#include <idn2.h>
#elif defined(HAVE_IDN)
#include <idna.h>
#endif
@@ -134,7 +136,7 @@ static int check_name(char *in)
else if (isascii((unsigned char)c) && iscntrl((unsigned char)c))
/* iscntrl only gives expected results for ascii */
return 0;
#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
#if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
else if (!isascii((unsigned char)c))
return 0;
#endif
@@ -184,7 +186,7 @@ int legal_hostname(char *name)
char *canonicalise(char *in, int *nomem)
{
char *ret = NULL;
#if defined(LOCALEDIR) || defined(HAVE_IDN)
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
int rc;
#endif
@@ -194,8 +196,15 @@ char *canonicalise(char *in, int *nomem)
if (!check_name(in))
return NULL;
#if defined(LOCALEDIR) || defined(HAVE_IDN)
if ((rc = idna_to_ascii_lz(in, &ret, 0)) != IDNA_SUCCESS)
#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);
@@ -244,11 +253,11 @@ unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
/* for use during startup */
void *safe_malloc(size_t size)
{
void *ret = malloc(size);
void *ret = calloc(1, size);
if (!ret)
die(_("could not get memory"), NULL, EC_NOMEM);
return ret;
}
@@ -262,11 +271,11 @@ void safe_pipe(int *fd, int read_noblock)
void *whine_malloc(size_t size)
{
void *ret = malloc(size);
void *ret = calloc(1, size);
if (!ret)
my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
return ret;
}
@@ -323,7 +332,7 @@ int hostname_isequal(const char *a, const char *b)
return 1;
}
time_t dnsmasq_time(void)
{
#ifdef HAVE_BROKEN_RTC
@@ -373,7 +382,7 @@ int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
return 0;
}
/* return least signigicant 64 bits if IPv6 address */
/* return least significant 64 bits if IPv6 address */
u64 addr6part(struct in6_addr *addr)
{
int i;
@@ -497,9 +506,14 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
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;
i++;
if (++i == maxlen)
break;
if (j < bytes - 1)
in[(j+1)*2] = sav;
}

View File

@@ -1,9 +1,10 @@
# The root DNSSEC trust anchor, valid as at 30/01/2014
# 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