Compare commits
185 Commits
v2.63test3
...
v2.67test2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
797a7afba4 | ||
|
|
4b5ea12e90 | ||
|
|
2b6390fdc9 | ||
|
|
bd08ae67f9 | ||
|
|
4582c0efe7 | ||
|
|
834f36fe6d | ||
|
|
6f130def07 | ||
|
|
3931a7bd85 | ||
|
|
d9ee9c0872 | ||
|
|
0b0a73c1c9 | ||
|
|
81925ab73a | ||
|
|
9de1aa9b7f | ||
|
|
6f9aaa93e9 | ||
|
|
7e5664bdbc | ||
|
|
83f28bef6c | ||
|
|
96c727fda6 | ||
|
|
49dc570a72 | ||
|
|
cd1e04a234 | ||
|
|
27cb314e54 | ||
|
|
56a1142f03 | ||
|
|
5b37aa8c19 | ||
|
|
8ac9787350 | ||
|
|
9f9bd08af8 | ||
|
|
4c985dac39 | ||
|
|
3d77c0460d | ||
|
|
3ddad24608 | ||
|
|
6e37ab595c | ||
|
|
a1a79edaea | ||
|
|
49333cbdbe | ||
|
|
de92b479d9 | ||
|
|
0f128eb58c | ||
|
|
c630924d66 | ||
|
|
ff59fc82b3 | ||
|
|
52a1ae72f0 | ||
|
|
3a654c506f | ||
|
|
2763d4b51a | ||
|
|
e28836bf45 | ||
|
|
a6ebfacf7b | ||
|
|
c7961075c4 | ||
|
|
ab6ede7e04 | ||
|
|
b3538f1100 | ||
|
|
3b323bda58 | ||
|
|
13d86c7372 | ||
|
|
208fb610a6 | ||
|
|
4038ae2005 | ||
|
|
dd1721c799 | ||
|
|
a21e27bc99 | ||
|
|
b0ff858e78 | ||
|
|
54dae552b1 | ||
|
|
25c4198f7c | ||
|
|
4ead40cf67 | ||
|
|
04a0612e8a | ||
|
|
aa608c84b4 | ||
|
|
38365ff040 | ||
|
|
9c4270bcd9 | ||
|
|
46b066565e | ||
|
|
4dc9c657ad | ||
|
|
39595cfe31 | ||
|
|
ffa3d7d6a2 | ||
|
|
aa67fe7a8c | ||
|
|
bb2509fd2c | ||
|
|
61744359de | ||
|
|
095f62551f | ||
|
|
e25db1f273 | ||
|
|
79cb46c0e9 | ||
|
|
22ce550e53 | ||
|
|
30393100c1 | ||
|
|
459380965a | ||
|
|
21bac1bccd | ||
|
|
b1a1b6def5 | ||
|
|
baeb3adf21 | ||
|
|
39f6a04ca4 | ||
|
|
37c9ccebd1 | ||
|
|
71c73ac17c | ||
|
|
c6cb7407b3 | ||
|
|
333b2ceb97 | ||
|
|
b456b9fdfe | ||
|
|
34d0a36a1d | ||
|
|
355736f36f | ||
|
|
771287be11 | ||
|
|
dc9476b670 | ||
|
|
1e14cc0f48 | ||
|
|
55b548ae2b | ||
|
|
3b43646a08 | ||
|
|
3bc0d932d0 | ||
|
|
60225f4e75 | ||
|
|
1962446269 | ||
|
|
be37986a0f | ||
|
|
d7346a1e8c | ||
|
|
87d346f6a7 | ||
|
|
f0dd7f807d | ||
|
|
0c0502426f | ||
|
|
7f035f58c6 | ||
|
|
81e84f8dac | ||
|
|
55b42f6de3 | ||
|
|
ed8b68ad06 | ||
|
|
bad7b875eb | ||
|
|
5d162f20a9 | ||
|
|
9d29949440 | ||
|
|
1b75c1e61f | ||
|
|
293fd0f700 | ||
|
|
c1be917782 | ||
|
|
bb86e858b6 | ||
|
|
8445f5d2e2 | ||
|
|
72c9c3b11b | ||
|
|
6e3dba3fde | ||
|
|
7558ecd9ac | ||
|
|
1f776932a1 | ||
|
|
4820dce97a | ||
|
|
f8abe0c566 | ||
|
|
9def963c65 | ||
|
|
990123a937 | ||
|
|
1d6c639310 | ||
|
|
429798fd08 | ||
|
|
b5a8dd1dec | ||
|
|
95a0bd3701 | ||
|
|
8ff556739e | ||
|
|
496787677e | ||
|
|
e1ff419cf9 | ||
|
|
ee86ce68fc | ||
|
|
b75e936372 | ||
|
|
aa79235194 | ||
|
|
7c305be1bd | ||
|
|
f7fe362721 | ||
|
|
36bec089f7 | ||
|
|
45dd1fece4 | ||
|
|
29d28dda95 | ||
|
|
421594f83d | ||
|
|
d89fb4ed4f | ||
|
|
295a54eed3 | ||
|
|
5c0bd5b112 | ||
|
|
86e3b9a026 | ||
|
|
2f38141f43 | ||
|
|
8273ea5a19 | ||
|
|
4f7b304f53 | ||
|
|
8e4b87918f | ||
|
|
83b2198e86 | ||
|
|
d1a5975f9b | ||
|
|
52002051ad | ||
|
|
b191a77901 | ||
|
|
23780dd577 | ||
|
|
d1e9a582ad | ||
|
|
819ff4dd0f | ||
|
|
de604c18a0 | ||
|
|
be6cfb42ab | ||
|
|
2022310f95 | ||
|
|
657ed09693 | ||
|
|
c99df938d7 | ||
|
|
cf568a3726 | ||
|
|
e4807d8bb2 | ||
|
|
35239a302a | ||
|
|
db3946c358 | ||
|
|
0d28af84d0 | ||
|
|
42698cb7ab | ||
|
|
1d860415f2 | ||
|
|
289a253569 | ||
|
|
faafb3f7b7 | ||
|
|
2b127a1eab | ||
|
|
dfb23b3f77 | ||
|
|
b269221c00 | ||
|
|
8b46061e73 | ||
|
|
4d0f5b4c44 | ||
|
|
1dedeb87cc | ||
|
|
79cfefd856 | ||
|
|
0c0d4793ac | ||
|
|
12d71ed28c | ||
|
|
9fed0f71c2 | ||
|
|
2e34ac1403 | ||
|
|
bc54ae392b | ||
|
|
00acd06340 | ||
|
|
476e4a03c1 | ||
|
|
5f11b3e5e0 | ||
|
|
3169daad46 | ||
|
|
fd05f12790 | ||
|
|
ad094275b0 | ||
|
|
c740e4f342 | ||
|
|
132255b5da | ||
|
|
c4c0488ac6 | ||
|
|
a2ce6fcc91 | ||
|
|
12090548d2 | ||
|
|
8223cb15e7 | ||
|
|
4ba9b38cc5 | ||
|
|
42243214b5 | ||
|
|
23245c0cb2 | ||
|
|
b271446f82 |
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
src/*.o
|
||||
src/*.mo
|
||||
src/dnsmasq.pot
|
||||
src/dnsmasq
|
||||
src/.configured
|
||||
contrib/wrt/dhcp_lease_time
|
||||
contrib/wrt/dhcp_release
|
||||
debian/base/
|
||||
debian/daemon/
|
||||
debian/files
|
||||
debian/substvars
|
||||
debian/utils-substvars
|
||||
debian/utils/
|
||||
180
CHANGELOG
180
CHANGELOG
@@ -1,3 +1,159 @@
|
||||
version 2.67
|
||||
Fix crash if upstream server returns SERVFAIL when
|
||||
--conntrack in use. Thanks to Giacomo Tazzari for finding
|
||||
this and supplying the patch.
|
||||
|
||||
|
||||
version 2.66
|
||||
Add the ability to act as an authoritative DNS
|
||||
server. Dnsmasq can now answer queries from the wider 'net
|
||||
with local data, as long as the correct NS records are set
|
||||
up. Only local data is provided, to avoid creating an open
|
||||
DNS relay. Zone transfer is supported, to allow secondary
|
||||
servers to be configured.
|
||||
|
||||
Add "constructed DHCP ranges" for DHCPv6. This is intended
|
||||
for IPv6 routers which get prefixes dynamically via prefix
|
||||
delegation. With suitable configuration, stateful DHCPv6
|
||||
and RA can happen automatically as prefixes are delegated
|
||||
and then deprecated, without having to re-write the
|
||||
dnsmasq configuration file or restart the daemon. Thanks to
|
||||
Steven Barth for extensive testing and development work on
|
||||
this idea.
|
||||
|
||||
Fix crash on startup on Solaris 11. Regression probably
|
||||
introduced in 2.61. Thanks to Geoff Johnstone for the
|
||||
patch.
|
||||
|
||||
Add code to make behaviour for TCP DNS requests that same
|
||||
as for UDP requests, when a request arrives for an allowed
|
||||
address, but via a banned interface. This change is only
|
||||
active on Linux, since the relevant API is missing (AFAIK)
|
||||
on other platforms. Many thanks to Tomas Hozza for
|
||||
spotting the problem, and doing invaluable discovery of
|
||||
the obscure and undocumented API required for the solution.
|
||||
|
||||
Don't send the default DHCP option advertising dnsmasq as
|
||||
the local DNS server if dnsmasq is configured to not act
|
||||
as DNS server, or it's configured to a non-standard port.
|
||||
|
||||
Add DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBCRIBER_ID,
|
||||
DNSMASQ_REMOTE_ID variables to the environment of the
|
||||
lease-change script (and the corresponding Lua). These hold
|
||||
information inserted into the DHCP request by a DHCP relay
|
||||
agent. Thanks to Lakefield Communications for providing a
|
||||
bounty for this addition.
|
||||
|
||||
Fixed crash, introduced in 2.64, whilst handling DHCPv6
|
||||
information-requests with some common configurations.
|
||||
Thanks to Robert M. Albrecht for the bug report and
|
||||
chasing the problem.
|
||||
|
||||
Add --ipset option. Thanks to Jason A. Donenfeld for the
|
||||
patch.
|
||||
|
||||
Don't erroneously reject some option names in --dhcp-match
|
||||
options. Thanks to Benedikt Hochstrasser for the bug report.
|
||||
|
||||
Allow a trailing '*' wildcard in all interface-name
|
||||
configurations. Thanks to Christian Parpart for the patch.
|
||||
|
||||
Handle the situation where libc headers define
|
||||
SO_REUSEPORT, but the kernel in use doesn't, to cope with
|
||||
the introduction of this option to Linux. Thanks to Rich
|
||||
Felker for the bug report.
|
||||
|
||||
Update Polish translation. Thanks to Jan Psota.
|
||||
|
||||
Fix crash if the configured DHCP lease limit is
|
||||
reached. Regression occurred in 2.61. Thanks to Tsachi for
|
||||
the bug report.
|
||||
|
||||
Update the French translation. Thanks to Gildas le Nadan.
|
||||
|
||||
|
||||
version 2.65
|
||||
Fix regression which broke forwarding of queries sent via
|
||||
TCP which are not for A and AAAA and which were directed to
|
||||
non-default servers. Thanks to Niax for the bug report.
|
||||
|
||||
Fix failure to build with DHCP support excluded. Thanks to
|
||||
Gustavo Zacarias for the patch.
|
||||
|
||||
Fix nasty regression in 2.64 which completely broke cacheing.
|
||||
|
||||
|
||||
version 2.64
|
||||
Handle DHCP FQDN options with all flag bits zero and
|
||||
--dhcp-client-update set. Thanks to Bernd Krumbroeck for
|
||||
spotting the problem.
|
||||
|
||||
Finesse the check for /etc/hosts names which conflict with
|
||||
DHCP names. Previously a name/address pair in /etc/hosts
|
||||
which didn't match the name/address of a DHCP lease would
|
||||
generate a warning. Now that only happesn if there is not
|
||||
also a match. This allows multiple addresses for a name in
|
||||
/etc/hosts with one of them assigned via DHCP.
|
||||
|
||||
Fix broken vendor-option processing for BOOTP. Thanks to
|
||||
Hans-Joachim Baader for the bug report.
|
||||
|
||||
Don't report spurious netlink errors, regression in
|
||||
2.63. Thanks to Vladislav Grishenko for the patch.
|
||||
|
||||
Flag DHCP or DHCPv6 in starup logging. Thanks to
|
||||
Vladislav Grishenko for the patch.
|
||||
|
||||
Add SetServersEx method in DBus interface. Thanks to Dan
|
||||
Williams for the patch.
|
||||
|
||||
Add SetDomainServers method in DBus interface. Thanks to
|
||||
Roy Marples for the patch.
|
||||
|
||||
Fix build with later Lua libraries. Thansk to Cristian
|
||||
Rodriguez for the patch.
|
||||
|
||||
Add --max-cache-ttl option. Thanks to Dennis Kaarsemaker
|
||||
for the patch.
|
||||
|
||||
Fix breakage of --host-record parsing, resulting in
|
||||
infinte loop at startup. Regression in 2.63. Thanks to
|
||||
Haim Gelfenbeyn for spotting this.
|
||||
|
||||
Set SO_REUSEADDRESS and SO_V6ONLY options on the DHCPv6
|
||||
socket, this allows multiple instances of dnsmasq on a
|
||||
single machine, in the same way as for DHCPv4. Thanks to
|
||||
Gene Czarcinski and Vladislav Grishenko for work on this.
|
||||
|
||||
Fix DHCPv6 to do access control correctly when it's
|
||||
configured with --listen-address. Thanks to
|
||||
Gene Czarcinski for sorting this out.
|
||||
|
||||
Add a "wildcard" dhcp-range which works for any IPv6
|
||||
subnet, --dhcp-range=::,static Useful for Stateless
|
||||
DHCPv6. Thanks to Vladislav Grishenko for the patch.
|
||||
|
||||
Don't include lease-time in DHCPACK replies to DHCPINFORM
|
||||
queries, since RFC-2131 says we shouldn't. Thanks to
|
||||
Wouter Ibens for pointing this out.
|
||||
|
||||
Makefile tweak to do dependency checking on header files.
|
||||
Thanks to Johan Peeters for the patch.
|
||||
|
||||
Check interface for outgoing unsolicited router
|
||||
advertisements, rather than relying on interface address
|
||||
configuration. Thanks to Gene Czarinski for the patch.
|
||||
|
||||
Handle better attempts to transmit on interfaces which are
|
||||
still doing DAD, and specifically do not just transmit
|
||||
without setting source address and interface, since this
|
||||
can cause very puzzling effects when a router
|
||||
advertisement goes astray. Thanks again to Gene Czarinski.
|
||||
|
||||
Get RA timers right when there is more than one
|
||||
dhcp-range on a subnet.
|
||||
|
||||
|
||||
version 2.63
|
||||
Do duplicate dhcp-host address check in --test mode.
|
||||
|
||||
@@ -27,7 +183,26 @@ version 2.63
|
||||
Fix regression in 2.61 which broke caching of CNAME
|
||||
chains. Thanks to Atul Gupta for the bug report.
|
||||
|
||||
Allow the target of a --cname flag to be anothe --cname.
|
||||
Allow the target of a --cname flag to be another --cname.
|
||||
|
||||
Teach DHCPv6 about the RFC 4242 information-refresh-time
|
||||
option, and add parsing if the minutes, hours and days
|
||||
format for options. Thanks to Francois-Xavier Le Bail for
|
||||
the suggestion.
|
||||
|
||||
Allow "w" (for week) as multiplier in lease times, as well
|
||||
as seconds, minutes, hours and days. Álvaro Gámez Machado
|
||||
spotted the ommission.
|
||||
|
||||
Update French translation. Thanks to Gildas Le Nadan.
|
||||
|
||||
Allow a DBus service name to be given with --enable-dbus
|
||||
which overrides the default,
|
||||
uk.org.thekelleys.dnsmasq. Thanks to Mathieu
|
||||
Trudel-Lapierre for the patch.
|
||||
|
||||
Set the "prefix on-link" bit in Router
|
||||
Advertisements. Thanks to Gui Iribarren for the patch.
|
||||
|
||||
|
||||
version 2.62
|
||||
@@ -54,7 +229,6 @@ version 2.62
|
||||
two addresses in the same network. Thanks to Jim Bos for
|
||||
his help nailing this.
|
||||
|
||||
|
||||
version 2.61
|
||||
Re-write interface discovery code on *BSD to use
|
||||
getifaddrs. This is more portable, more straightforward,
|
||||
@@ -341,7 +515,7 @@ version 2.58
|
||||
|
||||
Fix regression in TFTP server on *BSD platforms introduced
|
||||
in version 2.56, due to confusion with sockaddr
|
||||
length. Many thanks to Loïc Pefferkorn for finding this.
|
||||
length. Many thanks to Loic Pefferkorn for finding this.
|
||||
|
||||
Support scope-ids in IPv6 addresses of nameservers from
|
||||
/etc/resolv.conf and in --server options. Eg
|
||||
|
||||
109
FAQ
109
FAQ
@@ -22,7 +22,7 @@ A: The high ports that dnsmasq opens are for replies from the upstream
|
||||
now uses a new, randomly selected, port for each query. The old
|
||||
default behaviour (use one port allocated by the OS) is available by
|
||||
setting --query-port=0, and setting the query port to a positive
|
||||
value is still works. You should think hard and know what you are
|
||||
value still works. You should think hard and know what you are
|
||||
doing before using either of these options.
|
||||
|
||||
Q: Why doesn't dnsmasq support DNS queries over TCP? Don't the RFC's specify
|
||||
@@ -112,7 +112,7 @@ A: Resolver code sometime does strange things when given names without
|
||||
hostname will fix things. (ie "ping myhost" fails, but "ping
|
||||
myhost." works. The solution is to make sure that all your hosts
|
||||
have a domain set ("domain" in resolv.conf, or set a domain in
|
||||
your DHCP server, see below fr Windows XP and Mac OS X).
|
||||
your DHCP server, see below for Windows XP and Mac OS X).
|
||||
Any domain will do, but "localnet" is traditional. Now when you
|
||||
resolve "myhost" the resolver will attempt to look up
|
||||
"myhost.localnet" so you need to have dnsmasq reply to that name.
|
||||
@@ -236,53 +236,70 @@ Q: What network types are supported by the DHCP server?
|
||||
A: Ethernet (and 802.11 wireless) are supported on all platforms. On
|
||||
Linux all network types (including FireWire) are supported.
|
||||
|
||||
Q: What is this strange "bind-interface" option?
|
||||
Q: What are these strange "bind-interface" and "bind-dynamic" options?
|
||||
|
||||
A: The DNS spec says that the reply to a DNS query must come from the
|
||||
same address it was sent to. The traditional way to write an UDP
|
||||
server to do this is to find all of the addresses belonging to the
|
||||
machine (ie all the interfaces on the machine) and then create a
|
||||
socket for each interface which is bound to the address of the
|
||||
interface. Then when a packet is sent to address A, it is received
|
||||
on the socket bound to address A and when the reply is also sent
|
||||
via that socket, the source address is set to A by the kernel and
|
||||
everything works. This is the how dnsmasq works when
|
||||
"bind-interfaces" is set, with the obvious extension that is misses
|
||||
out creating sockets for some interfaces depending on the
|
||||
--interface, --address and --except-interface flags. The
|
||||
disadvantage of this approach is that it breaks if interfaces don't
|
||||
exist or are not configured when the daemon starts and does the
|
||||
socket creation step. In a hotplug-aware world this is a real
|
||||
problem.
|
||||
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
|
||||
mode which best fits the requirements of a particular installation.
|
||||
The origin of these are deficiencies in the Unix networking
|
||||
model and APIs and each mode has different advantages and
|
||||
problems. Just to add to the confusion, not all modes are available on
|
||||
all platforms (due the to lack of supporting network APIs).To further
|
||||
add to the confusion, the rules for the DHCP subsystem on dnsmasq are
|
||||
different to the rules for the DNS and TFTP subsystems.
|
||||
|
||||
The alternative approach is to have only one socket, which is bound
|
||||
to the correct port and the wildcard IP address (0.0.0.0). That
|
||||
socket will receive _all_ packets sent to port 53, no matter what
|
||||
destination address they have. This solves the problem of
|
||||
interfaces which are created or reconfigured after daemon
|
||||
start-up. To make this work is more complicated because of the
|
||||
"reply source address" problem. When a UDP packet is sent by a
|
||||
socket bound to 0.0.0.0 its source address will be set to the
|
||||
address of one of the machine's interfaces, but which one is not
|
||||
determined and can vary depending on the OS being run. To get round
|
||||
this it is neccessary to use a scary advanced API to determine the
|
||||
address to which a query was sent, and force that to be the source
|
||||
address in the reply. For IPv4 this stuff in non-portable and quite
|
||||
often not even available (It's different between FreeBSD 5.x and
|
||||
Linux, for instance, and FreeBSD 4.x, Linux 2.0.x and OpenBSD don't
|
||||
have it at all.) Hence "bind-interfaces" has to always be available
|
||||
as a fall back. For IPv6 the API is standard and universally
|
||||
available.
|
||||
The three modes are "wildcard", "bind-interfaces" and "bind-dynamic".
|
||||
|
||||
It could be argued that if the --interface or --address flags are
|
||||
used then binding interfaces is more appropriate, but using
|
||||
wildcard binding means that dnsmasq will quite happily start up
|
||||
after being told to use interfaces which don't exist, but which are
|
||||
created later. Wildcard binding breaks the scenario when dnsmasq is
|
||||
listening on one interface and another server (most probably BIND)
|
||||
is listening on another. It's not possible for BIND to bind to an
|
||||
(address,port) pair when dnsmasq has bound (wildcard,port), hence
|
||||
the ability to explicitly turn off wildcard binding.
|
||||
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
|
||||
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
|
||||
the address to which it was sent, and applies the configured
|
||||
rules. Wildcard mode is the default if neither of the other modes are
|
||||
specified.
|
||||
|
||||
In "bind-interfaces" mode, dnsmasq runs through all the network
|
||||
interfaces available when it starts, finds the set of IP addresses on
|
||||
those interfaces, filters that set using the access control
|
||||
configuration, and then binds the set of IP addresses. Only packets
|
||||
sent to the allowed addresses are delivered by the kernel to dnsmasq.
|
||||
|
||||
In "bind-dynamic" mode, access control filtering is done both by
|
||||
binding individual IP addresses, as for bind-interfaces, and by
|
||||
inspecting individual packets on arrival as for wildcard mode. In
|
||||
addition, dnsmasq notices when new interfaces appear or new addresses
|
||||
appear on existing interfaces, and the resulting IP addresses are
|
||||
bound automatically without having to restart dnsmasq.
|
||||
|
||||
The mode chosen has four different effects: co-existence with other
|
||||
servers, semantics of --interface access control, effect of new
|
||||
interfaces, and legality of --interface specifications for
|
||||
non-existent inferfaces. We will deal with these in order.
|
||||
|
||||
A dnsmasq instance running in wildcard mode precludes a machine from
|
||||
running a second instance of dnsmasq or any other DNS, TFTP or DHCP
|
||||
server. Attempts to do so will fail with an "address in use" error.
|
||||
Dnsmasq running in --bind-interfaces or bind-dynamic mode allow other
|
||||
instances of dnsmasq or other servers, as long as no two servers are
|
||||
configured to listen on the same interface address.
|
||||
|
||||
The semantics of --interface varies subtly between wildcard or
|
||||
bind-dynamic mode and bind-interfaces mode. The situation where this
|
||||
matters is a request which arrives via one interface (A), but with a
|
||||
destination address of a second interface (B) and when dnsmasq is
|
||||
configured to listen only on B. In wildcard or bind-dynamic mode, such
|
||||
a request will be ignored, in bind-interfaces mode, it will be
|
||||
accepted.
|
||||
|
||||
The creation of new network interfaces after dnsmasq starts is ignored
|
||||
by dnsmasq when in --bind-interfaces mode. In wildcard or bind-dynamic
|
||||
mode, such interfaces are handled normally.
|
||||
|
||||
A --interface specification for a non-existent interface is a fatal
|
||||
error at start-up when in --bind-interfaces mode, by just generates a
|
||||
warning in wildcard or bind-dynamic mode.
|
||||
|
||||
Q: Why doesn't Kerberos work/why can't I get sensible answers to
|
||||
queries for SRV records.
|
||||
|
||||
15
Makefile
15
Makefile
@@ -1,4 +1,4 @@
|
||||
# dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
# dnsmasq is Copyright (c) 2000-2013 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
|
||||
@@ -65,7 +65,7 @@ version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
|
||||
objs = cache.o rfc1035.o util.o option.o forward.o network.o \
|
||||
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
|
||||
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
|
||||
dhcp-common.o outpacket.o radv.o slaac.o
|
||||
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o
|
||||
|
||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
dns-protocol.h radv-protocol.h
|
||||
@@ -79,7 +79,8 @@ all : $(BUILDDIR)
|
||||
|
||||
clean :
|
||||
rm -f *~ $(BUILDDIR)/*.mo contrib/*/*~ */*~ $(BUILDDIR)/*.pot
|
||||
rm -f $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq core */core
|
||||
rm -f $(BUILDDIR)/.configured $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq
|
||||
rm -rf core */core
|
||||
|
||||
install : all install-common
|
||||
|
||||
@@ -113,7 +114,11 @@ $(BUILDDIR):
|
||||
mkdir -p $(BUILDDIR)
|
||||
|
||||
|
||||
# rules below are targets in recusive makes with cwd=$(SRC)
|
||||
# rules below are targets in recusive makes with cwd=$(BUILDDIR)
|
||||
|
||||
.configured: $(hdrs)
|
||||
@rm -f *.o
|
||||
@touch $@
|
||||
|
||||
$(objs:.o=.c) $(hdrs):
|
||||
ln -s $(top)/$(SRC)/$@ .
|
||||
@@ -121,7 +126,7 @@ $(objs:.o=.c) $(hdrs):
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $(COPTS) $(i18n) $(build_cflags) $(RPM_OPT_FLAGS) -c $<
|
||||
|
||||
dnsmasq : $(hdrs) $(objs)
|
||||
dnsmasq : .configured $(hdrs) $(objs)
|
||||
$(CC) $(LDFLAGS) -o $@ $(objs) $(build_libs) $(LIBS)
|
||||
|
||||
dnsmasq.pot : $(objs:.o=.c) $(hdrs)
|
||||
|
||||
@@ -8,7 +8,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
||||
netlink.c network.c option.c rfc1035.c \
|
||||
rfc2131.c tftp.c util.c conntrack.c \
|
||||
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
|
||||
radv.c slaac.c
|
||||
radv.c slaac.c auth.c ipset.c
|
||||
|
||||
LOCAL_MODULE := dnsmasq
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
# which has a set of references substituted into it by git.
|
||||
# If we can find one which matches $v[0-9].* then we assume it's
|
||||
# a version-number tag, else we just use the whole string.
|
||||
# If there is more than one v[0-9].* tag, sort them and use the
|
||||
# first. This favours, eg v2.63 over 2.63rc6.
|
||||
|
||||
if which git >/dev/null 2>&1 && [ -d $1/.git ]; then
|
||||
cd $1; git describe
|
||||
@@ -15,10 +17,10 @@ elif grep '\$Format:%d\$' $1/VERSION >/dev/null 2>&1; then
|
||||
# unsubstituted VERSION, but no git available.
|
||||
echo UNKNOWN
|
||||
else
|
||||
vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep $v[0-9]`
|
||||
vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep ^v[0-9]`
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "${vers}" | head -n 1 | sed 's/^v//'
|
||||
echo "${vers}" | sort | head -n 1 | sed 's/^v//'
|
||||
else
|
||||
cat $1/VERSION
|
||||
fi
|
||||
|
||||
43
contrib/dbus-test/dbus-test.py
Executable file
43
contrib/dbus-test/dbus-test.py
Executable file
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/python
|
||||
import dbus
|
||||
|
||||
bus = dbus.SystemBus()
|
||||
p = bus.get_object("uk.org.thekelleys.dnsmasq", "/uk/org/thekelleys/dnsmasq")
|
||||
l = dbus.Interface(p, dbus_interface="uk.org.thekelleys.dnsmasq")
|
||||
|
||||
# The new more flexible SetServersEx method
|
||||
array = dbus.Array()
|
||||
array.append(["1.2.3.5"])
|
||||
array.append(["1.2.3.4#664", "foobar.com"])
|
||||
array.append(["1003:1234:abcd::1%eth0", "eng.mycorp.com", "lab.mycorp.com"])
|
||||
print l.SetServersEx(array)
|
||||
|
||||
# Must create a new object for dnsmasq as the introspection gives the wrong
|
||||
# signature for SetServers (av) while the code only expects a bunch of arguments
|
||||
# instead of an array of variants
|
||||
p = bus.get_object("uk.org.thekelleys.dnsmasq", "/uk/org/thekelleys/dnsmasq", introspect=False)
|
||||
l = dbus.Interface(p, dbus_interface="uk.org.thekelleys.dnsmasq")
|
||||
|
||||
# The previous method; all addresses in machine byte order
|
||||
print l.SetServers(dbus.UInt32(16909060), # 1.2.3.5
|
||||
dbus.UInt32(16909061), # 1.2.3.4
|
||||
"foobar.com",
|
||||
dbus.Byte(0x10), # 1003:1234:abcd::1
|
||||
dbus.Byte(0x03),
|
||||
dbus.Byte(0x12),
|
||||
dbus.Byte(0x34),
|
||||
dbus.Byte(0xab),
|
||||
dbus.Byte(0xcd),
|
||||
dbus.Byte(0x00),
|
||||
dbus.Byte(0x00),
|
||||
dbus.Byte(0x00),
|
||||
dbus.Byte(0x00),
|
||||
dbus.Byte(0x00),
|
||||
dbus.Byte(0x00),
|
||||
dbus.Byte(0x00),
|
||||
dbus.Byte(0x00),
|
||||
dbus.Byte(0x00),
|
||||
dbus.Byte(0x01),
|
||||
"eng.mycorp.com",
|
||||
"lab.mycorp.com")
|
||||
|
||||
@@ -255,10 +255,6 @@ int main(int argc, char **argv)
|
||||
struct ifreq ifr;
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
int nl = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
struct iovec iov;
|
||||
|
||||
iov.iov_len = 200;
|
||||
iov.iov_base = malloc(iov.iov_len);
|
||||
|
||||
if (argc < 4 || argc > 5)
|
||||
{
|
||||
|
||||
@@ -19,7 +19,8 @@ and avoids startup races with the provider of nameserver information.
|
||||
|
||||
|
||||
Dnsmasq provides one service on the DBus: uk.org.thekelleys.dnsmasq
|
||||
and a single object: /uk/org/thekelleys/dnsmasq
|
||||
and a single object: /uk/org/thekelleys/dnsmasq
|
||||
The name of the service may be changed by giving an argument to --enable-dbus.
|
||||
|
||||
1. METHODS
|
||||
----------
|
||||
@@ -94,6 +95,65 @@ Each call to SetServers completely replaces the set of servers
|
||||
specified by via the DBus, but it leaves any servers specified via the
|
||||
command line or /etc/dnsmasq.conf or /etc/resolv.conf alone.
|
||||
|
||||
SetServersEx
|
||||
------------
|
||||
|
||||
This function is more flexible and the SetServers function, in that it can
|
||||
handle address scoping, port numbers, and is easier for clients to use.
|
||||
|
||||
Returns nothing. Takes a set of arguments representing the new
|
||||
upstream DNS servers to be used by dnsmasq. All addresses (both IPv4 and IPv6)
|
||||
are represented as STRINGS. Each server address may be followed by one or more
|
||||
STRINGS, which are the domains for which the preceding server should be used.
|
||||
|
||||
This function takes an array of STRING arrays, where each inner array represents
|
||||
a set of DNS servers and domains for which those servers may be used. Each
|
||||
string represents a list of upstream DNS servers first, and domains second.
|
||||
Mixing of domains and servers within a the string array is not allowed.
|
||||
|
||||
Examples.
|
||||
|
||||
[
|
||||
["1.2.3.4", "foobar.com"],
|
||||
["1003:1234:abcd::1%eth0", "eng.mycorp.com", "lab.mycorp.com"]
|
||||
]
|
||||
|
||||
is equivalent to
|
||||
|
||||
--server=/foobar.com/1.2.3.4 \
|
||||
--server=/eng.mycorp.com/lab.mycorp.com/1003:1234:abcd::1%eth0
|
||||
|
||||
An IPv4 address of 0.0.0.0 is interpreted as "no address, local only",
|
||||
so
|
||||
|
||||
[ ["0.0.0.0", "local.domain"] ]
|
||||
|
||||
is equivalent to
|
||||
|
||||
--local=/local.domain/
|
||||
|
||||
|
||||
Each call to SetServersEx completely replaces the set of servers
|
||||
specified by via the DBus, but it leaves any servers specified via the
|
||||
command line or /etc/dnsmasq.conf or /etc/resolv.conf alone.
|
||||
|
||||
|
||||
SetDomainServers
|
||||
----------------
|
||||
|
||||
Yes another variation for setting DNS servers, with the capability of
|
||||
SetServersEx, but without using arrays of arrays, which are not
|
||||
sendable with dbus-send. The arguments are an array of strings which
|
||||
are identical to the equivalent arguments --server, so the example
|
||||
for SetServersEx is represented as
|
||||
|
||||
[
|
||||
"/foobar.com/1.2.3.4"
|
||||
"/eng.mycorp.com/lab.mycorp.com/1003:1234:abcd::1%eth0"
|
||||
]
|
||||
|
||||
|
||||
|
||||
2. SIGNALS
|
||||
----------
|
||||
|
||||
|
||||
48
debian/changelog
vendored
48
debian/changelog
vendored
@@ -1,6 +1,54 @@
|
||||
dnsmasq (2.67-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 19 Apr 2013 10:23:31 +0000
|
||||
|
||||
dnsmasq (2.66-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* Add support for noipset in DEB_BUILD_OPTIONS.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 22 Feb 2013 21:52:13 +0000
|
||||
|
||||
dnsmasq (2.65-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 14 Dec 2012 11:34:12 +0000
|
||||
|
||||
dnsmasq (2.64-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 21 Sep 2012 17:17:22 +0000
|
||||
|
||||
dnsmasq (2.63-4) unstable; urgency=low
|
||||
|
||||
* Make pid-file creation immune to symlink attacks. (closes: #686484)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 21 Sep 2012 17:16:34 +0000
|
||||
|
||||
dnsmasq (2.63-3) unstable; urgency=low
|
||||
|
||||
* Move adduser dependency to dnsmasq-base. (closes: #686694)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 4 Sep 2012 21:44:15 +0000
|
||||
|
||||
dnsmasq (2.63-2) unstable; urgency=low
|
||||
|
||||
* Fix version script to report correct version.
|
||||
* Unbotch move of dbus config file by using correct versions in
|
||||
Replaces: and Breaks: lines. (closes: #685204)
|
||||
* Create dnsmasq user in dnsmasq-base so that Dbus doesn't complain if
|
||||
only dnsmasq-base is installed. (closes: #685987)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 28 Aug 2012 16:18:35 +0000
|
||||
|
||||
dnsmasq (2.63-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* Move /etc/dbus-1/system.d/dnsmasq.conf from dnsmasq to dnsmasq-base.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 11 Jun 2012 21:55:35 +0000
|
||||
|
||||
|
||||
1
debian/conffiles
vendored
1
debian/conffiles
vendored
@@ -2,5 +2,4 @@
|
||||
/etc/default/dnsmasq
|
||||
/etc/dnsmasq.conf
|
||||
/etc/resolvconf/update.d/dnsmasq
|
||||
/etc/dbus-1/system.d/dnsmasq.conf
|
||||
/etc/insserv.conf.d/dnsmasq
|
||||
|
||||
7
debian/control
vendored
7
debian/control
vendored
@@ -7,7 +7,7 @@ Standards-Version: 3.9.3
|
||||
|
||||
Package: dnsmasq
|
||||
Architecture: all
|
||||
Depends: netbase, adduser, dnsmasq-base(>= ${source:Version})
|
||||
Depends: netbase, dnsmasq-base(>= ${source:Version})
|
||||
Suggests: resolvconf
|
||||
Conflicts: resolvconf (<<1.15)
|
||||
Description: Small caching DNS proxy and DHCP/TFTP server
|
||||
@@ -22,8 +22,9 @@ Description: Small caching DNS proxy and DHCP/TFTP server
|
||||
|
||||
Package: dnsmasq-base
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}
|
||||
Conflicts: dnsmasq (<<2.41)
|
||||
Depends: adduser, ${shlibs:Depends}
|
||||
Breaks: dnsmasq (<< 2.63-1~)
|
||||
Replaces: dnsmasq (<< 2.63-1~)
|
||||
Description: Small caching DNS proxy and DHCP/TFTP server
|
||||
This package contains the dnsmasq executable and documentation, but
|
||||
not the infrastructure required to run it as a system daemon. For
|
||||
|
||||
2
debian/copyright
vendored
2
debian/copyright
vendored
@@ -1,4 +1,4 @@
|
||||
dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
dnsmasq is Copyright (c) 2000-2013 Simon Kelley
|
||||
|
||||
It was downloaded from: http://www.thekelleys.org.uk/dnsmasq/
|
||||
|
||||
|
||||
1
debian/dnsmasq-base.conffiles
vendored
Normal file
1
debian/dnsmasq-base.conffiles
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/etc/dbus-1/system.d/dnsmasq.conf
|
||||
24
debian/dnsmasq-base.postinst
vendored
Normal file
24
debian/dnsmasq-base.postinst
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# Create the dnsmasq user in dnsmasq-base, so that Dbus doesn't complain.
|
||||
|
||||
# create a user to run as (code stolen from dovecot-common)
|
||||
if [ "$1" = "configure" ]; then
|
||||
if [ -z "`id -u dnsmasq 2> /dev/null`" ]; then
|
||||
adduser --system --home /var/lib/misc --gecos "dnsmasq" \
|
||||
--no-create-home --disabled-password \
|
||||
--quiet dnsmasq || true
|
||||
fi
|
||||
|
||||
# Make the directory where we keep the pid file - this
|
||||
# has to be owned by "dnsmasq" so that the file can be unlinked.
|
||||
# This is only actually used by the dnsmasq binary package, not
|
||||
# dnsmasq-base, but it's much easier to create it here so that
|
||||
# we don't have synchronisation issues with the creation of the
|
||||
# dnsmasq user.
|
||||
if [ ! -d /var/run/dnsmasq ]; then
|
||||
mkdir /var/run/dnsmasq
|
||||
chown dnsmasq:nogroup /var/run/dnsmasq
|
||||
fi
|
||||
fi
|
||||
11
debian/dnsmasq-base.postrm
vendored
Normal file
11
debian/dnsmasq-base.postrm
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
if [ purge = "$1" ]; then
|
||||
if [ -x "$(command -v deluser)" ]; then
|
||||
deluser --quiet --system dnsmasq > /dev/null || true
|
||||
else
|
||||
echo >&2 "not removing dnsmasq system account because deluser command was not found"
|
||||
fi
|
||||
rm -rf /var/run/dnsmasq
|
||||
fi
|
||||
27
debian/postinst
vendored
27
debian/postinst
vendored
@@ -1,27 +1,6 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# create a user to run as (code stolen from dovecot-common)
|
||||
if [ "$1" = "configure" ]; then
|
||||
if [ -z "`id -u dnsmasq 2> /dev/null`" ]; then
|
||||
adduser --system --home /var/lib/misc --gecos "dnsmasq" \
|
||||
--no-create-home --disabled-password \
|
||||
--quiet dnsmasq || true
|
||||
fi
|
||||
|
||||
# Make the directory where we keep the pid file - this
|
||||
# has to be owned by "dnsmasq" do that the file can be unlinked.
|
||||
if [ ! -d /var/run/dnsmasq ]; then
|
||||
mkdir /var/run/dnsmasq
|
||||
chown dnsmasq:nogroup /var/run/dnsmasq
|
||||
fi
|
||||
|
||||
# handle new location of pidfile during an upgrade
|
||||
if [ -e /var/run/dnsmasq.pid ]; then
|
||||
mv /var/run/dnsmasq.pid /var/run/dnsmasq
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -x /etc/init.d/dnsmasq ]; then
|
||||
update-rc.d dnsmasq defaults 15 85 >/dev/null
|
||||
|
||||
@@ -40,10 +19,4 @@ if [ -x /etc/init.d/dnsmasq ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# dpkg can botch the change of /usr/share/doc/dnsmasq from
|
||||
# directory to symlink. Fix up here.
|
||||
if [ ! -h /usr/share/doc/dnsmasq ] && { rmdir /usr/share/doc/dnsmasq; }; then
|
||||
cd /usr/share/doc/
|
||||
ln -s /usr/share/doc/dnsmasq-base dnsmasq
|
||||
fi
|
||||
|
||||
|
||||
6
debian/postrm
vendored
6
debian/postrm
vendored
@@ -3,10 +3,4 @@ set -e
|
||||
|
||||
if [ purge = "$1" ]; then
|
||||
update-rc.d dnsmasq remove >/dev/null
|
||||
if [ -x "$(command -v deluser)" ]; then
|
||||
deluser --quiet --system dnsmasq > /dev/null || true
|
||||
else
|
||||
echo >&2 "not removing dnsmasq system account because deluser command was not found"
|
||||
fi
|
||||
rm -rf /var/run/dnsmasq
|
||||
fi
|
||||
|
||||
1
debian/readme
vendored
1
debian/readme
vendored
@@ -59,6 +59,7 @@ Notes on configuring dnsmasq as packaged for Debian.
|
||||
noipv6 : omit IPv6 support.
|
||||
nodbus : omit DBus support.
|
||||
noconntrack : omit connection tracking support.
|
||||
noipset : omit IPset support.
|
||||
nortc : compile alternate mode suitable for systems without an RTC.
|
||||
noi18n : omit translations and internationalisation support.
|
||||
noidn : omit international domain name support, must be
|
||||
|
||||
11
debian/rules
vendored
11
debian/rules
vendored
@@ -33,6 +33,10 @@ ifeq ($(DEB_BUILD_ARCH_OS),linux)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(filter noipset,$(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DNO_IPSET
|
||||
endif
|
||||
|
||||
ifneq (,$(filter nodhcp6,$(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DNO_DHCP6
|
||||
endif
|
||||
@@ -85,7 +89,6 @@ binary-indep: checkroot
|
||||
-d debian/daemon/etc/resolvconf/update.d \
|
||||
-d debian/daemon/usr/lib/resolvconf/dpkg-event.d \
|
||||
-d debian/daemon/etc/default \
|
||||
-d debian/daemon/etc/dbus-1/system.d \
|
||||
-d debian/daemon/lib/systemd/system \
|
||||
-d debian/daemon/etc/insserv.conf.d
|
||||
install -m 644 debian/conffiles debian/daemon/DEBIAN
|
||||
@@ -96,7 +99,6 @@ binary-indep: checkroot
|
||||
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
|
||||
install -m 644 debian/dbus.conf debian/daemon/etc/dbus-1/system.d/dnsmasq.conf
|
||||
install -m 644 debian/systemd.service debian/daemon/lib/systemd/system/dnsmasq.service
|
||||
install -m 644 debian/insserv debian/daemon/etc/insserv.conf.d/dnsmasq
|
||||
ln -s $(package) debian/daemon/usr/share/doc/dnsmasq
|
||||
@@ -111,6 +113,7 @@ binary-arch: checkroot
|
||||
rm -rf debian/base
|
||||
install -m 755 \
|
||||
-d debian/base/DEBIAN \
|
||||
-d debian/base/etc/dbus-1/system.d \
|
||||
-d debian/base/usr/share/doc/$(package) \
|
||||
-d debian/base/usr/share/doc/$(package)/examples \
|
||||
-d debian/base/var/run \
|
||||
@@ -129,10 +132,14 @@ ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||
install -m 644 dbus/DBus-interface debian/base/usr/share/doc/$(package)/.
|
||||
gzip -9 debian/base/usr/share/doc/$(package)/DBus-interface
|
||||
endif
|
||||
install -m 644 debian/dnsmasq-base.conffiles debian/base/DEBIAN/conffiles
|
||||
install -m 755 debian/dnsmasq-base.postinst debian/base/DEBIAN/postinst
|
||||
install -m 755 debian/dnsmasq-base.postrm debian/base/DEBIAN/postrm
|
||||
install -m 644 debian/changelog debian/base/usr/share/doc/$(package)/changelog.Debian
|
||||
gzip -9 debian/base/usr/share/doc/$(package)/changelog.Debian
|
||||
install -m 644 debian/readme debian/base/usr/share/doc/$(package)/README.Debian
|
||||
install -m 644 debian/copyright debian/base/usr/share/doc/$(package)/copyright
|
||||
install -m 644 debian/dbus.conf debian/base/etc/dbus-1/system.d/dnsmasq.conf
|
||||
gzip -9 debian/base/usr/share/man/man8/dnsmasq.8
|
||||
for f in debian/base/usr/share/man/*; do \
|
||||
if [ -f $$f/man8/dnsmasq.8 ]; then \
|
||||
|
||||
@@ -69,6 +69,10 @@
|
||||
# --address (and --server) work with IPv6 addresses too.
|
||||
#address=/www.thekelleys.org.uk/fe80::20d:60ff:fe36:f83
|
||||
|
||||
# Add the IPs of all queries to yahoo.com, google.com, and their
|
||||
# subdomains to the vpn and search ipsets:
|
||||
#ipset=/yahoo.com/google.com/vpn,search
|
||||
|
||||
# You can control how dnsmasq talks to a server: this forces
|
||||
# queries to 10.1.2.3 to be routed via eth1
|
||||
# server=10.1.2.3@eth1
|
||||
@@ -326,6 +330,9 @@
|
||||
# dnsmasq and another.
|
||||
#dhcp-option=option6:dns-server,[::],[1234::88]
|
||||
|
||||
# Ask client to poll for option changes every six hours. (RFC4242)
|
||||
#dhcp-option=option6:information-refresh-time,6h
|
||||
|
||||
# Set the NTP time server address to be the same machine as
|
||||
# is running dnsmasq
|
||||
#dhcp-option=42,0.0.0.0
|
||||
@@ -477,7 +484,7 @@
|
||||
#tftp-no-blocksize
|
||||
|
||||
# Set the boot file name only when the "red" tag is set.
|
||||
#dhcp-boot=net:red,pxelinux.red-net
|
||||
#dhcp-boot=tag:red,pxelinux.red-net
|
||||
|
||||
# An example of dhcp-boot with an external TFTP server: the name and IP
|
||||
# address of the server are given after the filename.
|
||||
@@ -618,6 +625,6 @@
|
||||
# Log lots of extra information about DHCP transactions.
|
||||
#log-dhcp
|
||||
|
||||
# Include a another lot of configuration options.
|
||||
# Include another lot of configuration options.
|
||||
#conf-file=/etc/dnsmasq.more.conf
|
||||
#conf-dir=/etc/dnsmasq.d
|
||||
|
||||
278
man/dnsmasq.8
278
man/dnsmasq.8
@@ -6,24 +6,28 @@ dnsmasq \- A lightweight DHCP and caching DNS server.
|
||||
.I [OPTION]...
|
||||
.SH "DESCRIPTION"
|
||||
.BR dnsmasq
|
||||
is a lightweight DNS, TFTP and DHCP server. It is intended to provide
|
||||
is a lightweight DNS, TFTP, PXE, router advertisement and DHCP server. It is intended to provide
|
||||
coupled DNS and DHCP service to a LAN.
|
||||
.PP
|
||||
Dnsmasq accepts DNS queries and either answers them from a small, local,
|
||||
cache or forwards them to a real, recursive, DNS server. It loads the
|
||||
contents of /etc/hosts so that local hostnames
|
||||
which do not appear in the global DNS can be resolved and also answers
|
||||
DNS queries for DHCP configured hosts.
|
||||
DNS queries for DHCP configured hosts. It can also act as the authoritative DNS server for one or more domains, allowing local names to appear in the global DNS.
|
||||
.PP
|
||||
The dnsmasq DHCP server supports static address assignments and multiple
|
||||
networks. It automatically
|
||||
sends a sensible default set of DHCP options, and can be configured to
|
||||
send any desired set of DHCP options, including vendor-encapsulated
|
||||
options. It includes a secure, read-only,
|
||||
TFTP server to allow net/PXE boot of DHCP hosts and also supports BOOTP.
|
||||
TFTP server to allow net/PXE boot of DHCP hosts and also supports BOOTP. The PXE support is full featured, and includes a proxy mode which supplies PXE information to clients whilst DHCP address allocation is done by another server.
|
||||
.PP
|
||||
Dnsmasq
|
||||
supports IPv6 for all functions and a minimal router-advertisement daemon.
|
||||
The dnsmasq DHCPv6 server provides the same set of features as the
|
||||
DHCPv4 server, and in addition, it includes router advertisements and
|
||||
a neat feature which allows nameing for clients which use DHCPv4 and
|
||||
stateless autoconfiguration only for IPv6 configuration. There is support for doing address allocation (both DHCPv6 and RA) from subnets which are dynamically delegated via DHCPv6 prefix delegation.
|
||||
.PP
|
||||
Dnsmasq is coded with small embedded systems in mind. It aims for the smallest possible memory footprint compatible with the supported functions, and allows uneeded 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
|
||||
@@ -71,6 +75,12 @@ maximum TTL will be given to clients instead of the true TTL value if it is
|
||||
lower. The true TTL value is however kept in the cache to avoid flooding
|
||||
the upstream DNS servers.
|
||||
.TP
|
||||
.B --max-cache-ttl=<time>
|
||||
Set a maximum TTL value for entries in the cache.
|
||||
.TP
|
||||
.B --auth-ttl=<time>
|
||||
Set the TTL value returned in answers from the authoritative server.
|
||||
.TP
|
||||
.B \-k, --keep-in-foreground
|
||||
Do not go into the background at startup but otherwise run as
|
||||
normal. This is intended for use when dnsmasq is run under daemontools
|
||||
@@ -80,7 +90,9 @@ or launchd.
|
||||
Debug mode: don't fork to the background, don't write a pid file,
|
||||
don't change user id, generate a complete cache dump on receipt on
|
||||
SIGUSR1, log to stderr as well as syslog, don't fork new processes
|
||||
to handle TCP queries.
|
||||
to handle TCP queries. Note that this option is for use in debugging
|
||||
only, to stop dnsmasq daemonising in production, use
|
||||
.B -k.
|
||||
.TP
|
||||
.B \-q, --log-queries
|
||||
Log the results of DNS queries handled by dnsmasq. Enable a full cache dump on receipt of SIGUSR1.
|
||||
@@ -162,7 +174,12 @@ options. IP alias interfaces (eg "eth1:0") cannot be used with
|
||||
.B --interface
|
||||
or
|
||||
.B --except-interface
|
||||
options, use --listen-address instead.
|
||||
options, use --listen-address instead. A simple wildcard, consisting
|
||||
of a trailing '*', can be used in
|
||||
.B \--interface
|
||||
and
|
||||
.B \--except-interface
|
||||
options.
|
||||
.TP
|
||||
.B \-I, --except-interface=<interface name>
|
||||
Do not listen on the specified interface. Note that the order of
|
||||
@@ -173,6 +190,16 @@ and
|
||||
options does not matter and that
|
||||
.B --except-interface
|
||||
options always override the others.
|
||||
.TP
|
||||
.B --auth-server=<domain>,<interface>|<ip-address>
|
||||
Enable DNS authoritative mode for queries arriving at an interface or address. Note that the interface or address
|
||||
need not be mentioned in
|
||||
.B --interface
|
||||
or
|
||||
.B --listen-address
|
||||
configuration, indeed
|
||||
.B --auth-server
|
||||
will overide 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.
|
||||
.TP
|
||||
.B \-2, --no-dhcp-interface=<interface name>
|
||||
Do not provide DHCP or TFTP on the specified interface, but do provide DNS service.
|
||||
@@ -207,12 +234,12 @@ dnsmasq which provide DHCP service to run in the same machine.
|
||||
.B --bind-dynamic
|
||||
Enable a network mode which is a hybrid between
|
||||
.B --bind-interfaces
|
||||
and the default. Dnsmasq binds the address of indivdual interfaces,
|
||||
and the default. Dnsmasq binds the address of individual interfaces,
|
||||
allowing multiple dnsmasq instances, but if new interfaces or
|
||||
addresses appear, it automatically listens on those (subject to any
|
||||
access-control configuration). This makes dynamically created
|
||||
interfaces work in the same way as the default. Implementing this
|
||||
option requires non-standard networking APIs and it is only availble
|
||||
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
|
||||
@@ -271,11 +298,13 @@ time is the one used.
|
||||
Don't read /etc/resolv.conf. Get upstream servers only from the command
|
||||
line or the dnsmasq configuration file.
|
||||
.TP
|
||||
.B \-1, --enable-dbus
|
||||
.B \-1, --enable-dbus[=<service-name>]
|
||||
Allow dnsmasq configuration to be updated via DBus method calls. The
|
||||
configuration which can be changed is upstream DNS servers (and
|
||||
corresponding domains) and cache clear. Requires that dnsmasq has
|
||||
been built with DBus support.
|
||||
been built with DBus support. If the service name is given, dnsmasq
|
||||
provides service at that name, rather than the default which is
|
||||
.B uk.org.thekelleys.dnsmasq
|
||||
.TP
|
||||
.B \-o, --strict-order
|
||||
By default, dnsmasq will send queries to any of the upstream servers
|
||||
@@ -391,6 +420,12 @@ additional facility that /#/ matches any domain. Thus
|
||||
answered from /etc/hosts or DHCP and not sent to an upstream
|
||||
nameserver by a more specific --server directive.
|
||||
.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.
|
||||
.TP
|
||||
.B \-m, --mx-host=<mx name>[[,<hostname>],<preference>]
|
||||
Return an MX record named <mx name> pointing to the given hostname (if
|
||||
given), or
|
||||
@@ -470,7 +505,7 @@ is permissable to have more than one cname pointing to the same target.
|
||||
.B --dns-rr=<name>,<RR-number>,[<hex data>]
|
||||
Return an arbitrary DNS Resource Record. The number is the type of the
|
||||
record (which is always in the C_IN class). The value of the record is
|
||||
given by the hex data, which may be of the for 01:23:45 or 01 23 45 or
|
||||
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>
|
||||
@@ -521,6 +556,30 @@ If you use the first DNSSEC mode, validating resolvers in clients,
|
||||
this option is not required. Dnsmasq always returns all the data
|
||||
needed for a client to do validation itself.
|
||||
.TP
|
||||
.B --auth-zone=<domain>[,<subnet>[,<subnet>.....]]
|
||||
Define a DNS zone for which dnsmasq acts as authoritative server. Locally defined DNS records which are in the domain
|
||||
will be served, except that A and AAAA records must be in one of the
|
||||
specified subnets, or in a subnet corresponding to a contructed DHCP
|
||||
range. The subnet(s) are also used to define in-addr.arpa and
|
||||
ipv6.arpa domains which are served for reverse-DNS queries. For IPv4
|
||||
subnets, the prefix length is limited to the values 8, 16 or 24.
|
||||
.TP
|
||||
.B --auth-soa=<serial>[,<hostmaster>[,<refresh>[,<retry>[,<expiry>]]]]
|
||||
Specify fields in the SOA record associated with authoritative
|
||||
zones. Note that this is optional, all the values are set to sane defaults.
|
||||
.TP
|
||||
.B --auth-sec-servers=<domain>[,<domain>[,<domain>...]]
|
||||
Specify any secondary servers for a zone for which dnsmasq is
|
||||
authoritative. These servers must be configured to get zone data from
|
||||
dnsmasq by zone transfer, and answer queries for the same
|
||||
authoritative zones as dnsmasq.
|
||||
.TP
|
||||
.B --auth-peer=<ip-address>[,<ip-address>[,<ip-address>...]]
|
||||
Specify the addresses of secondary servers which are allowed to
|
||||
initiate zone transfer (AXFR) requests for zones for which dnsmasq is
|
||||
authoritative. If this option is not given, then AXFR requests will be
|
||||
accepted from any secondary.
|
||||
.TP
|
||||
.B --conntrack
|
||||
Read the Linux connection track mark associated with incoming DNS
|
||||
queries and set the same mark value on upstream traffic used to answer
|
||||
@@ -531,9 +590,9 @@ 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>][,<mode>][,<prefix-len>][,<lease time>]
|
||||
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-IPv6addr>[,<end-IPv6addr>|constructor:<interface>][,<mode>][,<prefix-len>][,<lease time>]
|
||||
|
||||
Enable the DHCP server. Addresses will be given out from the range
|
||||
<start-addr> to <end-addr> and from statically defined addresses given
|
||||
@@ -565,6 +624,14 @@ given, this defaults to 64. Unlike the IPv4 case, the prefix length is not
|
||||
automatically derived from the interface configuration. The mimimum
|
||||
size of the prefix length is 64.
|
||||
|
||||
IPv6 (only) supports another type of range. In this, the start address and optional end address contain only the network part (ie ::1) and they are followed by
|
||||
.B constructor:<interface>.
|
||||
This forms a template which describes how to create ranges, based on the addresses assigned to the interface. For instance
|
||||
|
||||
.B --dhcp-range=::1,::400,constructor:eth0
|
||||
|
||||
will look for addresses of the form <network>::1 on eth0 and then create a range from <network>::1 to <network>::400. If the interface is assigned more than one network, then the corresponding ranges will be automatically created, and then deprecated and finally removed again as the address is deprecated and then deleted. The interface name may have a final "*" wildcard.
|
||||
|
||||
The optional
|
||||
.B set:<tag>
|
||||
sets an alphanumeric label which marks this network so that
|
||||
@@ -579,7 +646,11 @@ which tells dnsmasq to enable DHCP for the network specified, but not
|
||||
to dynamically allocate IP addresses: only hosts which have static
|
||||
addresses given via
|
||||
.B dhcp-host
|
||||
or from /etc/ethers will be served.
|
||||
or from /etc/ethers will be served. A static-only subnet with address
|
||||
all zeros may be used as a "catch-all" address to enable replies to all
|
||||
Information-request packets on a subnet which is provided with
|
||||
stateless DHCPv6, ie
|
||||
.B --dhcp=range=::,static
|
||||
|
||||
For IPv4, the <mode> may be
|
||||
.B proxy
|
||||
@@ -661,7 +732,13 @@ A single
|
||||
.B dhcp-host
|
||||
may contain an IPv4 address or an IPv6 address, or both. IPv6 addresses must be bracketed by square brackets thus:
|
||||
.B --dhcp-host=laptop,[1234::56]
|
||||
Note that in IPv6 DHCP, the hardware address is not normally available, so a client must be identified by client-id (called client DUID in IPv6-land) or hostname.
|
||||
IPv6 addresses may contain only the host-identifier part:
|
||||
.B --dhcp-host=laptop,[::56]
|
||||
in which case they act as wildcards in constructed dhcp ranges, with
|
||||
the appropriate network part inserted.
|
||||
Note that in IPv6 DHCP, the hardware address is not normally
|
||||
available, so a client must be identified by client-id (called client
|
||||
DUID in IPv6-land) or hostname.
|
||||
|
||||
The special option id:* means "ignore any client-id
|
||||
and use MAC addresses only." This is useful when a client presents a client-id sometimes
|
||||
@@ -1060,12 +1137,13 @@ create thousands of leases and use lots of memory in the dnsmasq
|
||||
process.
|
||||
.TP
|
||||
.B \-K, --dhcp-authoritative
|
||||
(IPv4 only) Should be set when dnsmasq is definitely the only DHCP server on a network.
|
||||
It changes the behaviour from strict RFC compliance so that DHCP requests on
|
||||
Should be set when dnsmasq is definitely the only DHCP server on a network.
|
||||
For DHCPv4, it changes the behaviour from strict RFC compliance so that DHCP requests on
|
||||
unknown leases from unknown hosts are not ignored. This allows new hosts
|
||||
to get a lease without a tedious timeout under all circumstances. It also
|
||||
allows dnsmasq to rebuild its lease database without each client needing to
|
||||
reacquire a lease, if the database is lost.
|
||||
reacquire a lease, if the database is lost. For DHCPv6 it sets the
|
||||
priority in replies to 255 (the maximum) instead of 0 (the minimum).
|
||||
.TP
|
||||
.B --dhcp-alternate-port[=<server port>[,<client port>]]
|
||||
(IPv4 only) Change the ports used for DHCP from the default. If this option is
|
||||
@@ -1167,6 +1245,9 @@ For IPv4 only:
|
||||
|
||||
DNSMASQ_CLIENT_ID if the host provided a client-id.
|
||||
|
||||
DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBSCRIBER_ID, DNSMASQ_REMOTE_ID if a
|
||||
DHCP relay-agent added any of these options.
|
||||
|
||||
If the client provides vendor-class, DNSMASQ_VENDOR_CLASS.
|
||||
|
||||
For IPv6 only:
|
||||
@@ -1637,6 +1718,165 @@ parameter in a BOOTP request is used as a tag,
|
||||
as is the tag "bootp", allowing some control over the options returned to
|
||||
different classes of hosts.
|
||||
|
||||
.SH AUTHORITATIVE CONFIGURATION
|
||||
.PP
|
||||
Configuring dnsmasq to act as an authoritative DNS server is
|
||||
complicated by the fact that it involves configuration of external DNS
|
||||
servers to provide delegation. We will walk through three scenarios of
|
||||
increasing complexity. Prerequisites for all of these scenarios
|
||||
are a globally accessible IP address, an A or AAAA record pointing to that address,
|
||||
and an external DNS server capable of doing delegation of the zone in
|
||||
question. For the first part of this explanation, we will call the A (or AAAA) record
|
||||
for the globally accessible address server.example.com, and the zone
|
||||
for which dnsmasq is authoritative our.zone.com.
|
||||
|
||||
The simplest configuration consists of two lines of dnsmasq configuration; something like
|
||||
|
||||
.nf
|
||||
.B auth-server=server.example.com,eth0
|
||||
.B auth-zone=our.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
and two records in the external DNS
|
||||
|
||||
.nf
|
||||
server.example.com A 192.0.43.10
|
||||
our.zone.com NS server.example.com
|
||||
.fi
|
||||
|
||||
eth0 is the external network interface on which dnsmasq is listening,
|
||||
and has (globally accessible) address 192.0.43.10.
|
||||
|
||||
Note that the external IP address may well be dynamic (ie assigned
|
||||
from an ISP by DHCP or PPP) If so, the A record must be linked to this
|
||||
dynamic assignment by one of the usual dynamic-DNS systems.
|
||||
|
||||
A more complex, but practically useful configuration has the address
|
||||
record for the globally accessible IP address residing in the
|
||||
authoritative zone which dnsmasq is serving, typically at the root. Now
|
||||
we have
|
||||
|
||||
.nf
|
||||
.B auth-server=our.zone.com,eth0
|
||||
.B auth-zone=our.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
.nf
|
||||
our.zone.com A 1.2.3.4
|
||||
our.zone.com NS our.zone.com
|
||||
.fi
|
||||
|
||||
The A record for our.zone.com has now become a glue record, it solves
|
||||
the chicken-and-egg problem of finding the IP address of the
|
||||
nameserver for our.zone.com when the A record is within that
|
||||
zone. Note that this is the only role of this record: as dnsmasq is
|
||||
now authoritative from our.zone.com it too must provide this
|
||||
record. If the external address is static, this can be done with an
|
||||
.B /etc/hosts
|
||||
entry or
|
||||
.B --host-record.
|
||||
|
||||
.nf
|
||||
.B auth-server=our.zone.com,eth0
|
||||
.B host-record=our.zone.com,1.2.3.4
|
||||
.B auth-zone=our.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
If the external address is dynamic, the address
|
||||
associated with our.zone.com must be derived from the address of the
|
||||
relevant interface. This is done using
|
||||
.B interface-name
|
||||
Something like:
|
||||
|
||||
.nf
|
||||
.B auth-server=our.zone.com,eth0
|
||||
.B interface-name=our.zone.com,eth0
|
||||
.B auth-zone=our.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
Our final configuration builds on that above, but also adds a
|
||||
secondary DNS server. This is another DNS server which learns the DNS data
|
||||
for the zone by doing zones transfer, and acts as a backup should
|
||||
the primary server become inaccessible. The configuration of the
|
||||
secondary is beyond the scope of this man-page, but the extra
|
||||
configuration of dnsmasq is simple:
|
||||
|
||||
.nf
|
||||
.B auth-sec-servers=secondary.myisp.com
|
||||
.fi
|
||||
|
||||
and
|
||||
|
||||
.nf
|
||||
our.zone.com NS secondary.myisp.com
|
||||
.fi
|
||||
|
||||
Adding auth-sec-servers enables zone transfer in dnsmasq, to allow the
|
||||
secondary to collect the DNS data. If you wish to restrict this data
|
||||
to particular hosts then
|
||||
|
||||
.nf
|
||||
.B auth-peer=<IP address of secondary>
|
||||
.fi
|
||||
|
||||
will do so.
|
||||
|
||||
Dnsmasq acts as an authoritative server for in-addr.arpa and
|
||||
ipv6.arpa domains associated with the subnets given in auth-zone
|
||||
declarations, so reverse (address to name) lookups can be simply
|
||||
configured with a suitable NS record, for instance in this example,
|
||||
where we allow 1.2.3.0/24 addresses.
|
||||
|
||||
.nf
|
||||
3.2.1.in-addr.arpa NS our.zone.com
|
||||
.fi
|
||||
|
||||
Note that at present, reverse (in-addr.arpa and ip6.arpa) zones are
|
||||
not available in zone transfers, so there is no point arranging
|
||||
secondary servers for reverse lookups.
|
||||
|
||||
.PP
|
||||
When dnsmasq is configured to act as an authoritative server, the
|
||||
following data is used to populate the authoritative zone.
|
||||
.PP
|
||||
.B --mx-host, --srv-host, --dns-rr, --txt-record, --naptr-record
|
||||
, as long as the record names are in the authoritative domain.
|
||||
.PP
|
||||
.B --cname
|
||||
as long as the record name is in the authoritative domain. If the
|
||||
target of the CNAME is unqualified, then it is qualified with the
|
||||
authoritative zone name.
|
||||
.PP
|
||||
IPv4 and IPv6 addresses from /etc/hosts (and
|
||||
.B --addn-hosts
|
||||
) and
|
||||
.B --host-record
|
||||
provided the address falls into one of the subnets specified in the
|
||||
.B --auth-zone.
|
||||
.PP
|
||||
Addresses specified by
|
||||
.B --interface-name.
|
||||
In this case, the address is not contrained to a subnet from
|
||||
.B --auth-zone.
|
||||
|
||||
.PP
|
||||
Addresses of DHCP leases, provided the address falls into one of the subnets specified in the
|
||||
.B --auth-zone
|
||||
OR a constructed DHCP range. In the default mode, where a DHCP lease
|
||||
has an unqualified name, and possibly a qualified name constructed
|
||||
using
|
||||
.B --domain
|
||||
then the name in the authoritative zone is constructed from the
|
||||
unqualified name and the zone's domain. This may or may not equal
|
||||
that specified by
|
||||
.B --domain.
|
||||
If
|
||||
.B --dhcp-fqdn
|
||||
is set, then the fully qualified names associated with DHCP leases are
|
||||
used, and must match the zone's domain.
|
||||
|
||||
|
||||
|
||||
.SH EXIT CODES
|
||||
.PP
|
||||
0 - Dnsmasq successfully forked into the background, or terminated
|
||||
|
||||
392
man/fr/dnsmasq.8
392
man/fr/dnsmasq.8
@@ -6,24 +6,40 @@ Dnsmasq \- Un serveur DHCP et cache DNS poids-plume.
|
||||
.I [OPTION]...
|
||||
.SH "DESCRIPTION"
|
||||
.BR dnsmasq
|
||||
est un serveur DHCP et DNS à faible empreinte mémoire. Il offre à la fois les
|
||||
services DNS et DHCP pour un réseau local (LAN).
|
||||
est un serveur à faible empreinte mémoire faisant DNS, TFTP, PXE, annonces de
|
||||
routeurs et DHCP. Il offre à la fois les services DNS et DHCP pour un réseau
|
||||
local (LAN).
|
||||
.PP
|
||||
Dnsmasq accepte les requêtes DNS et y réponds soit en utilisant un petit cache
|
||||
local, soit en effectuant une requête à un serveur DNS récursif externe (par
|
||||
exemple celui de votre fournisseur d'accès internet). Il charge le contenu du
|
||||
fichier /etc/hosts afin que les noms locaux n'apparaissant pas dans les DNS
|
||||
globaux soient tout de même résolus, et assure également la résolution de nom
|
||||
pour les hôtes présents dans le service DHCP.
|
||||
pour les hôtes présents dans le service DHCP. Il peut aussi agir en temps que
|
||||
serveur DNS faisant autorité pour un ou plusieurs domaines, permettant à des
|
||||
noms locaux d'apparaitre dans le DNS global.
|
||||
.PP
|
||||
Le serveur DHCP Dnsmasq DHCP supporte les définitions d'adresses statiques et les
|
||||
réseaux multiples. Il envoie par défaut un jeu raisonnable de paramètres DHCP, et
|
||||
peut être configuré pour envoyer n'importe quel option DHCP.
|
||||
réseaux multiples. Il fournit par défaut un jeu raisonnable de paramètres DHCP,
|
||||
et peut être configuré pour fournir n'importe quelle option DHCP.
|
||||
Il inclut un serveur TFTP sécurisé en lecture seule permettant le démarrage via
|
||||
le réseau/PXE de clients DHCP et supporte également le protocole BOOTP.
|
||||
le réseau/PXE de clients DHCP et supporte également le protocole BOOTP. Le
|
||||
support PXE est complet, et comprend un mode proxy permettant de fournir des
|
||||
informations PXE aux clients alors que l'allocation DHCP est effectuée par un
|
||||
autre serveur.
|
||||
.PP
|
||||
Dnsmasq supporte IPv6 et contient un démon minimaliste capable de faire des
|
||||
annonces routeurs ("router-advertisements").
|
||||
Le serveur DHCPv6 de dnsmasq possède non seulement les mêmes fonctionalités
|
||||
que le serveur DHCPv4, mais aussi le support des annonces de routeurs ainsi
|
||||
qu'une fonctionalité permettant l'addition de ressources AAAA pour des
|
||||
clients utilisant DHCPv4 et la configuration IPv6 sans état (stateless
|
||||
autoconfiguration).
|
||||
Il inclut le support d'allocations d'adresses (à la fois en DHCPv6 et en
|
||||
annonces de routeurs - RA) pour des sous-réseaux dynamiquement délégués via
|
||||
une délégation de préfixe DHCPv6.
|
||||
.PP
|
||||
Dnsmasq est developpé pour de petits systèmes embarqués. It tends à avoir
|
||||
l'empreinte mémoire la plus faible possible pour les fonctions supportées,
|
||||
et permet d'exclure les fonctions inutiles du binaire compilé.
|
||||
.SH OPTIONS
|
||||
Notes : Il est possible d'utiliser des options sans leur donner de paramètre.
|
||||
Dans ce cas, la fonction correspondante sera désactivée. Par exemple
|
||||
@@ -76,9 +92,16 @@ l'absence d'enregistrement SOA.
|
||||
.TP
|
||||
.B --max-ttl=<durée>
|
||||
Définie la valeur de TTL maximum qui sera fournie aux clients. La valeur maximum
|
||||
de TTL spécifiée sera fournie aux clients en remplacement de la vraie valeur de TTL
|
||||
si cette dernière est supérieure. La valeur réelle de TTL est cependant conservée dans
|
||||
le cache afin d'éviter de saturer les serveurs DNS en amont.
|
||||
de TTL spécifiée sera fournie aux clients en remplacement de la vraie valeur de
|
||||
TTL si cette dernière est supérieure. La valeur réelle de TTL est cependant
|
||||
conservée dans le cache afin d'éviter de saturer les serveurs DNS en amont.
|
||||
.TP
|
||||
.B --max-cache-ttl=<durée>
|
||||
Définie la valeur de TTL maximum pour les entrées dans le cache
|
||||
.TP
|
||||
.B --auth-ttl=<durée>
|
||||
Définie la valeur de TTL retournée pour les réponses du serveur faisant
|
||||
autorité.
|
||||
.TP
|
||||
.B \-k, --keep-in-foreground
|
||||
Ne pas aller en tâche de fond au lancement, mais en dehors de cela, fonctionner
|
||||
@@ -90,7 +113,10 @@ Mode debug (déverminage) : ne pas aller en tâche de fond, ne pas écrire de
|
||||
fichier pid, ne pas changer d'identifiant utilisateur, générer un état complet
|
||||
du cache lors de la réception d'un signal SIGUSR1, envoyer les logs sur la
|
||||
sortie standard d'erreur ("stderr") de même que dans le syslog, ne pas créer de
|
||||
processus fils pour traiter les requêtes TCP.
|
||||
processus fils pour traiter les requêtes TCP. A noter que cette option est à
|
||||
user pour du déverminage seulement : pour empêcher dnsmasq se fonctionner en
|
||||
mode démon en production, utiliser
|
||||
.B -k.
|
||||
.TP
|
||||
.B \-q, --log-queries
|
||||
Enregistrer les résultats des requêtes DNS traitées par Dnsmasq dans un fichier
|
||||
@@ -185,7 +211,11 @@ ni
|
||||
.B \--except-interface.
|
||||
Utiliser l'option
|
||||
.B --listen-address
|
||||
à la place.
|
||||
à la place. Un simple joker, consistant d'un '*' final, peut-être utilisé dans
|
||||
les options
|
||||
.B \--interface
|
||||
et
|
||||
.B \--except-interface
|
||||
.TP
|
||||
.B \-I, --except-interface=<interface name>
|
||||
Ne pas écouter sur l'interface spécifiée. Notez que l'ordre dans lesquelles les
|
||||
@@ -198,6 +228,21 @@ et
|
||||
sont fournies n'importe pas, et que l'option
|
||||
.B --except-interface
|
||||
l'emporte toujours sur les autres.
|
||||
.TP
|
||||
.B --auth-server=<domaine>,<interface>|<addresse IP>
|
||||
Active le mode DNS faisant autorité pour les requêtes arrivant sur cette
|
||||
interface ou sur cette adresse. Noter que l'interface ou l'adresse n'ont
|
||||
pas besoin d'être mentionées ni dans
|
||||
.B --interface
|
||||
ni dans
|
||||
.B --listen-address
|
||||
En effet,
|
||||
.B --auth-server
|
||||
va passer outre ceux-ci et fournir un service DNS différent sur l'interface
|
||||
spécifiée. La valeur de <domaine> est l'enregistrement de type "colle"
|
||||
("glue record"). Il doit correspondre dans le service DNS global avec un
|
||||
enregistrement de type A et/ou AAAA pointant sur l'adresse sur laquelle dnsmasq
|
||||
écoute pour le mode DNS faisant autorité.
|
||||
.TP
|
||||
.B \-2, --no-dhcp-interface=<nom d'interface>
|
||||
Ne pas fournir de service DHCP sur l'interface spécifiée, mais fournir tout de
|
||||
@@ -232,6 +277,18 @@ autre serveur de nom (ou une autre instance de Dnsmasq) tourne sur la même
|
||||
machine. Utiliser cette option permet également d'avoir plusieurs instances de
|
||||
Dnsmasq fournissant un service DHCP sur la même machine.
|
||||
.TP
|
||||
.B --bind-dynamic
|
||||
Autorise un mode réseau intermédiaire entre
|
||||
.B --bind-interfaces
|
||||
et le mode par défaut. Dnsmasq s'associe à une seule interface, ce qui permet
|
||||
plusieurs instances de dnsmasq, mais si une interface ou adresse apparaissent,
|
||||
il se mettra automatiquement à écouter sur celles-ci (les règles de contrôle
|
||||
d'accès s'appliquent).
|
||||
De fait, les interfaces créées dynamiquement fonctionnent de la même façon que
|
||||
dans le comportement par défaut. Ce fonctionnement nécessite des APIs réseau
|
||||
non standard et n'est disponible que sous Linux. Sur les autres plateformes,
|
||||
le fonctionnement est celui du mode --bind-interfaces.
|
||||
.TP
|
||||
.B \-y, --localise-queries
|
||||
Retourne des réponses aux requêtes DNS dépendantes de l'interface sur laquelle
|
||||
la requête a été reçue, à partir du fichier /etc/hosts. Si un nom dans
|
||||
@@ -300,11 +357,14 @@ Ne pas lire le contenu du fichier /etc/resolv.conf. N'obtenir l'adresse des
|
||||
serveurs de nom amont que depuis la ligne de commande ou le fichier de
|
||||
configuration de Dnsmasq.
|
||||
.TP
|
||||
.B \-1, --enable-dbus
|
||||
.B \-1, --enable-dbus[=<nom de service>]
|
||||
Autoriser la mise à jour de la configuration de Dnsmasq par le biais d'appel de
|
||||
méthodes DBus. Il est possible par ce biais de mettre à jour l'adresse de
|
||||
serveurs DNS amont (et les domaines correspondants) et de vider le cache. Cette
|
||||
option nécessite que Dnsmasq soit compilé avec le support DBus.
|
||||
option nécessite que Dnsmasq soit compilé avec le support DBus. Si un nom de
|
||||
service est fourni, dnsmasq fourni un service à ce nom, plutôt qu'avec la
|
||||
valeur par défaut :
|
||||
.B uk.org.thekelleys.dnsmasq
|
||||
.TP
|
||||
.B \-o, --strict-order
|
||||
Par défaut, Dnsmasq envoie les requêtes à n'importe lequel des serveurs amonts
|
||||
@@ -443,6 +503,12 @@ n'ayant de réponse ni dans /etc/hosts, ni dans les baux DHCP, et n'étant pas
|
||||
transmise à un serveur spécifique par le biais d'une directive
|
||||
.B --server.
|
||||
.TP
|
||||
.B --ipset=/<domaine>/[domaine/]<ipset>[,<ipset>]
|
||||
Obtient les adresses IP des domaines spécifiés et les place dans les groupes
|
||||
d'IP netfilter (ipset) indiqués. Domaines et sous-domaines sont résolus de la
|
||||
même façon que pour --address. Ces groupes d'IP doivent déjà exister. Voir
|
||||
ipset(8) pour plus de détails.
|
||||
.TP
|
||||
.B \-m, --mx-host=<nom de l'hôte>[[,<nom du MX>],<préference>]
|
||||
Spécifie un enregistrement de type MX pour <nom de l'hôte> retournant le nom
|
||||
donné dans <nom du MX> (s'il est présent), ou sinon le nom spécifié dans
|
||||
@@ -532,9 +598,17 @@ Retourne un enregistrement de type NAPTR, tel que spécifié dans le RFC3403.
|
||||
Retourne un enregistrement de type CNAME qui indique que <cname> est en
|
||||
réalité <cible>. Il existe des contraintes significatives sur la valeur
|
||||
de cible; il doit s'agir d'un nom DNS qui est connu de dnsmasq via /etc/hosts
|
||||
(ou un fichier hôtes additionnel) ou via DHCP. Si une cible ne satisfait
|
||||
pas ces critères, le CNAME est ignoré. Le CNAME doit être unique, mais
|
||||
il est autorisé d'avoir plus d'un CNAME pointant vers la même cible.
|
||||
(ou un fichier hôtes additionnel), ou via DHCP, ou par un autre
|
||||
.B --cname.
|
||||
Si une cible ne satisfait pas ces critères, le CNAME est ignoré. Le CNAME
|
||||
doit être unique, mais il est autorisé d'avoir plus d'un CNAME pointant
|
||||
vers la même cible.
|
||||
.TP
|
||||
.B --dns-rr=<nom>,<numéro-RR>,[<données hexadécimales>]
|
||||
Retourne un enregistrement DNS arbitraire. Le numéro correspond au type
|
||||
d'enregistrement (qui est toujours de la classe C_IN). La valeur de
|
||||
l'enregistrement est donnée dans les données hexadécimales, qui peuvent
|
||||
être de la forme 01:23:45, 01 23 45,+012345 ou n'importe quelle combinaison.
|
||||
.TP
|
||||
.B --interface-name=<nom>,<interface>
|
||||
Définit un entregistrement DNS associant le nom avec l'adresse primaire sur
|
||||
@@ -591,6 +665,34 @@ Si vous utilisez le premier mode DNSSEC, la validation par le resolveur des
|
||||
clients, cette option n'est pas requise. Dnsmasq retourne toujours toutes les
|
||||
données nécessaires par un client pour effectuer la validation lui-même.
|
||||
.TP
|
||||
.B --auth-zone=<domaine>[,<sous-réseau>[,<sous-réseau>.....]]
|
||||
Définie une zone DNS pour laquelle dnsmasq agit en temps que serveur faisant
|
||||
autorité. Les enregistrements DNS définis localement et correspondant à ce
|
||||
domaine seront fournis, à ceci près que les enregistrements A et AAAA doivent
|
||||
se situer dans l'un des sous-réseaux précisés si ceux-ci sont définis, ou dans
|
||||
un réseau correspondant à une plage DHCP. Le ou les sous-réseaux sont également
|
||||
utilisé pour définir les domaines in-addr.arpa et ipv6.arpa servant à
|
||||
l'interrogation DNS inverse. Dans le cas d'IPv4, la longueur du masque de
|
||||
réseau doit être de 8, 16 ou 24.
|
||||
.TP
|
||||
.B --auth-soa=<numéro de série>[,<mainteneur de zone (hostmaster)>[,<rafraichissement>[,<nombre de réessais>[,<expiration>]]]]
|
||||
Spécifie les champs de l'enregistrement de type SOA (Start Of Authority)
|
||||
associé à une zone pour laquelle le serveur fait autorité. A noter que cela est
|
||||
optionnel, les valeurs par défaut devant convenir à la majorité des cas.
|
||||
.TP
|
||||
.B --auth-sec-servers=<domaine>[,<domaine>[,<domaine>...]]
|
||||
Spécifie un ou plusieurs serveur de nom secondaires pour une zone pour
|
||||
laquelle dnsmasq fait autorité. Ces serveurs doivent-être configurés pour
|
||||
récupérer auprès de dnsmasq les informations liées à la zone au travers d'un
|
||||
transfert de zone, et répondre aux requêtes pour toutes les zones pour
|
||||
lesquelles dnsmasq fait autorité.
|
||||
.TP
|
||||
.B --auth-peer=<adresse IP>[,<adresse IP>[,<adresse IP>...]]
|
||||
Spécifie la ou les adresses de serveurs secondaires autorisés à initier des
|
||||
requêtes de transfert de zone (AXFR) pour les zones pour lesquelles
|
||||
dnsmasq fait autorité. Si cette option n'est pas fournie, les requêtes AXFR
|
||||
seront acceptées pour tous les serveurs secondaires.
|
||||
.TP
|
||||
.B --conntrack
|
||||
Lis le marquage de suivi de connexion Linux associé aux requêtes DNS entrantes
|
||||
et positionne la même marque au trafic amont utilisé pour répondre à ces
|
||||
@@ -601,9 +703,10 @@ avec le support conntrack, le noyau doit également inclure conntrack et être
|
||||
configuré pour cela. Cette option ne peut pas être combinée avec
|
||||
--query-port.
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[interface:<interface>,][tag:<label>[,tag:<label>],][set:<label>],]<adresse de début>[,<adresse de fin>][,<mode>][,<masque de réseau>[,<broadcast>]][,<durée de bail>]
|
||||
.B \-F, --dhcp-range=[tag:<label>[,tag:<label>],][set:<label>],]<adresse de début>[,<adresse de fin>][,<mode>][,<masque de réseau>[,<broadcast>]][,<durée de bail>]
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[interface:<interface>,][tag:<label>[,tag:<label>],][set:<label>],]<addresse IPv6 de début>[,<adresse IPv6 de fin>][,<mode>][,<longueur de préfixe>][,<durée de bail>]
|
||||
.B \-F, --dhcp-range=[tag:<label>[,tag:<label>],][set:<label>],]<addresse IPv6 de début>[,<adresse IPv6 de fin>|constructor:<interface>][,<mode>][,<longueur de préfixe>][,<durée de bail>]
|
||||
|
||||
Active le serveur DHCP. Les adresses seront données dans la plage comprise entre
|
||||
<adresse de début> et <adresse de fin> et à partir des adresses définies
|
||||
statiquement dans l'option
|
||||
@@ -643,6 +746,22 @@ d'IPv4, la longueur de préfixe n'est pas automatiquement déduite de la
|
||||
configuration de l'interface. La taille minimale pour la longueur de préfixe
|
||||
est 64.
|
||||
|
||||
Pour IPv6 (et IPv6 uniquement), il est possible de définir les plages d'une
|
||||
autre façon. Dans ce cas, l'adresse de départ et l'adresse de fin optionnelle
|
||||
contiennent uniquement la partie réseau (par exemple ::1) et sont suivies par
|
||||
.B constructor:<interface>.
|
||||
Cela forme un modèle décrivant comment construire la plage, à partir des
|
||||
adresses assignées à l'interface. Par exemple
|
||||
|
||||
.B --dhcp-range=::1,::400,constructor:eth0
|
||||
|
||||
provoque la recherche d'adresses de la forme <réseau>::1 sur eth0 et crée une
|
||||
plage allant de <réseau>::1 à <réseau>:400. Si une interface est assignée à
|
||||
plus d'un réseau, les plages correspondantes seront automatiquement créées,
|
||||
rendues obsolètes puis supprimées lorsque l'adress est rendue obsolète puis
|
||||
supprimée. Le nom de l'interface peut être spécifié avec un caractère joker '*'
|
||||
final.
|
||||
|
||||
L'identifiant de label optionnel
|
||||
.B set:<label>
|
||||
fournie une étiquette alphanumérique qui identifie ce réseau, afin de permettre
|
||||
@@ -657,7 +776,13 @@ Le mot clef optionnel <mode> peut être égal à
|
||||
spécifié, mais de ne pas activer l'allocation dynamique d'adresses IP : Seuls
|
||||
les hôtes possédant des adresses IP statiques fournies via
|
||||
.B dhcp-host
|
||||
ou présentes dans le fichier /etc/ethers seront alors servis par le DHCP.
|
||||
ou présentes dans le fichier /etc/ethers seront alors servis par le DHCP. Il est
|
||||
possible d'activer un mode "fourre-tout" en définissant un réseau statique
|
||||
comportant uniquement des zéros, c'est à dire :
|
||||
.B --dhcp=range=::,static
|
||||
Cela permet de retourner des réponses à tous les paquets de type
|
||||
Information-request (requête d'information) en mode DHCPv6 sans état sur le
|
||||
sous-réseau configuré.
|
||||
|
||||
Pour IPv4, le <mode> peut est égal à
|
||||
.B proxy
|
||||
@@ -705,8 +830,6 @@ peut-être combiné avec
|
||||
et
|
||||
.B slaac.
|
||||
|
||||
La section interface:<nom d'interface> n'est normalement pas utilisée. Se
|
||||
référer aux indications de la section NOTES pour plus de détail à ce sujet.
|
||||
.TP
|
||||
.B \-G, --dhcp-host=[<adresse matérielle>][,id:<identifiant client>|*][,set:<label>][,<adresse IP>][,<nom d'hôte>][,<durée de bail>][,ignore]
|
||||
Spécifie les paramètres DHCP relatifs à un hôte. Cela permet à une machine
|
||||
@@ -744,6 +867,10 @@ Un seul
|
||||
peut contenir une adresse IPv4, une adresse IPv6, ou les deux en même temps.
|
||||
Les adresses IPv6 doivent-être mises entre crochets comme suit :
|
||||
.B --dhcp-host=laptop,[1234::56]
|
||||
Les adresses IPv6 peuvent ne contenir que la partie identifiant de client :
|
||||
.B --dhcp-host=laptop,[::56]
|
||||
Dans ce cas, lorsque des plages dhcp sont définies automatiquement par le biais
|
||||
de constructeurs, la partie réseau correspondante est rajoutée à l'adresse.
|
||||
A noter que pour le DHCP IPv6, l'adresse matérielle n'est en principe pas
|
||||
disponible, aussi un client doit-être identifié par un identifiant de client
|
||||
(appellé "DUID client") ou un nom d'hôte.
|
||||
@@ -1186,14 +1313,16 @@ créant des milliers de baux et utilisant beaucoup de mémoire dans le processus
|
||||
Dnsmasq.
|
||||
.TP
|
||||
.B \-K, --dhcp-authoritative
|
||||
(IPv4 seulement) Cette option doit être donnée lorsque Dnsmasq est le seul
|
||||
serveur DHCP sur le réseau. Cela change le comportement par défaut qui est
|
||||
Doit être spécifié lorsque dnsmasq est réellement le seul serveur DHCP
|
||||
sur le réseau. Pour DHCPv4, cela change le comportement par défaut qui est
|
||||
celui d'un strict respect des RFC, afin que les requêtes DHCP pour des baux
|
||||
inconnus par des hôtes inconnus ne soient pas ignorées. Cela permet à de
|
||||
nouveaux hôtes d'obtenir des baux sans tenir compte de fastidieuses
|
||||
temporisations ("timeout"). Cela permet également à Dnsmasq de reconstruire
|
||||
sa base de données contenant les baux sans que les clients n'aient besoin de
|
||||
redemander un bail, si celle-ci est perdue.
|
||||
Dans le cas de DHCPv6, cela positionne la priorité des réponses à 255 (le
|
||||
maximum) au lieu de 0 (le minimum).
|
||||
.TP
|
||||
.B --dhcp-alternate-port[=<port serveur>[,<port client>]]
|
||||
(IPv4 seulement) Change les ports utilisés par défaut pour le DHCP. Si cette
|
||||
@@ -1301,6 +1430,9 @@ Pour IPv4 seulement :
|
||||
|
||||
DNSMASQ_CLIENT_ID, si l'hôte a fourni un identifiant de client.
|
||||
|
||||
DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBSCRIBER_ID, DNSMASQ_REMOTE_ID si un relai DHCP a
|
||||
rajouté l'une de ces options.
|
||||
|
||||
Si le client fournit une information de classe de vendeur, DNSMASQ_VENDOR_CLASS.
|
||||
|
||||
Pour IPv6 seulement :
|
||||
@@ -1517,12 +1649,11 @@ 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 --enable-tftp[=<interface>]
|
||||
.B --enable-tftp
|
||||
Active la fonction serveur TFTP. Celui-ci est de manière délibérée limité aux
|
||||
fonctions nécessaires au démarrage par le réseau ("net-boot") d'un client. Seul
|
||||
un accès en lecture est possible; les extensions tsize et blksize sont supportées
|
||||
(tsize est seulement supporté en mode octet). Voir dans la section NOTES les
|
||||
informations relatives à la spécification de l'interface.
|
||||
(tsize est seulement supporté en mode octet).
|
||||
.TP
|
||||
.B --tftp-root=<répertoire>[,<interface>]
|
||||
Les fichiers à fournir dans les transferts TFTP seront cherchés en prenant le
|
||||
@@ -1560,6 +1691,13 @@ Sans cela, en effet, l'accès de tous les fichiers du serveur pour lequel le
|
||||
droit de lecture pour tout le monde est positionné ("world-readable") devient
|
||||
possible par n'importe quel hôte sur le réseau.
|
||||
.TP
|
||||
.B --tftp-lowercase
|
||||
Converti les noms de fichiers des requêtes TFTP en minuscules. Cela est utile
|
||||
pour les requêtes effectuées depuis les machines Windows, dont les systèmes
|
||||
de fichiers sont insensibles à la casse et pour lesquels la détermination
|
||||
de la casse est parfois un peu aléatoire. A noter que le serveur tftp de
|
||||
dnsmasq converti systématiquement les "\\" en "/" dans les noms de fichiers.
|
||||
.TP
|
||||
.B --tftp-max=<connexions>
|
||||
Définit le nombre maximum de connexions TFTP simultanées autorisées. La valeur
|
||||
par défaut est de 50. Lorsqu'un grand nombre de connexions TFTP est spécifié,
|
||||
@@ -1823,50 +1961,166 @@ supprime la nécessité des associations statiques). Le paramètre
|
||||
que le label "bootp", permettant un certain contrôle sur les options retournées
|
||||
aux différentes classes d'hôtes.
|
||||
|
||||
Il est possible de spécifier un nom d'interface à
|
||||
.B dhcp-range
|
||||
sous la forme "interface:<nom d'interface>". La sémantique est comme suit :
|
||||
Pour le DHCP, s'il existe une autre valeur de dhcp-range pour laquelle
|
||||
_aucun_ nom d'interface n'est donné, alors le nom d'interface est ignoré
|
||||
et dnsmasq se comporte comme si la partie spécifiant l'interface n'existait
|
||||
pas, sinon le service DHCP n'est fourni qu'aux interfaces mentionnées dans
|
||||
les déclarations dhcp-range. Pour le DNS, si il n'y a pas d'option
|
||||
.B --interface
|
||||
ou
|
||||
.B --listen-address
|
||||
, alors le comportement n'est pas impacté par la spécification d'interface. Si
|
||||
l'une ou l'autre de ces options est présente, alors les interfaces mentionnées
|
||||
dans les plages d'adresses dhcp-range sont rajoutées à la liste de celles
|
||||
où le service DNS est assuré.
|
||||
|
||||
De manière similaire,
|
||||
.B enable-tftp
|
||||
peut prendre un nom d'interface, ce qui active le TFTP pour cette seule
|
||||
interface, en ignorant les options
|
||||
.B --interface
|
||||
ou
|
||||
.B --listen-address
|
||||
De plus,
|
||||
.B --tftp-secure
|
||||
,
|
||||
.B --tftp-unique-root
|
||||
.SH CONFIGURATION EN TEMPS QUE SERVEUR FAISANT AUTORITÉ
|
||||
.PP
|
||||
Configurer dnsmasq pour agir en temps que serveur DNS faisant autorité est
|
||||
compliqué par le fait que cela implique la configuration de serveurs DNS
|
||||
externes pour mettre en place la délégation. Seront présentés ci-dessous trois
|
||||
scénarios de complexité croissante. Le pré-requis pour chacun de ces scénarios
|
||||
est l'existence d'une adresse IP globalement disponible, d'un enregistrement de
|
||||
type A ou AAAA pointant vers cette adresse, ainsi que d'un serveur DNS externe
|
||||
capable d'effectuer la délégation de la zone en question. Pour la première
|
||||
partie de ces explications, nous allons appeller serveur.exemple.com
|
||||
l'enregistrement A (ou AAAA) de l'adresse globalement accessible, et
|
||||
notre.zone.com la zone pour laquelle dnsmasq fait autorité.
|
||||
|
||||
La configuration la plus simple consiste en deux lignes de configuration,
|
||||
sous la forme :
|
||||
.nf
|
||||
.B auth-server=serveur.exemple.com,eth0
|
||||
.B auth-zone=notre.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
ainsi que deux enregistrements dans le DNS externe :
|
||||
|
||||
.nf
|
||||
serveur.exemple.com A 192.0.43.10
|
||||
notre.zone.com NS serveur.exemple.com
|
||||
.fi
|
||||
|
||||
eth0 est l'interface réseau externe sur laquelle dnsmasq écoute, dont l'adresse
|
||||
IP (globalement accessible) est 192.0.43.10.
|
||||
|
||||
A noter que l'adresse IP externe peut parfaitement être dynamique (par exemple
|
||||
attribuée par un FAI via DHCP ou PPP). Dans ce cas, l'enregistrement de type A
|
||||
doit être lié à cet enregistrement dynamique par l'une ou l'autre des techniques
|
||||
habituelles de système DNS dynamique.
|
||||
|
||||
Un exemple plus complexe mais en pratique plus utile correspond au cas où
|
||||
l'adresse IP globalement accessible se trouve dans la zone pour laquelle
|
||||
dnsmasq fait autorité, le plus souvent à la racine. Dans ce cas nous avons :
|
||||
|
||||
.nf
|
||||
.B auth-server=notre.zone.com,eth0
|
||||
.B auth-zone=notre.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
.nf
|
||||
notre.zone.com A 1.2.3.4
|
||||
notre.zone.com NS our.zone.com
|
||||
.fi
|
||||
|
||||
L'enregistrement A pour notre.zone.com est dorénavant un enregistrement "colle"
|
||||
qui résoud le problème de poule et d'oeuf consistant à trouver l'adresse IP
|
||||
du serveur de nom pour notre.zone.com lorsque l'enregistrement se trouve dans
|
||||
la zone en question. Il s'agit du seul rôle de cet enregistrement : comme dnsmasq
|
||||
fait désormais autorité pour notre.zone.com, il doit également fournir cet
|
||||
enregistrement. Si l'adresse externe est statique, cela peut-être réalisé par
|
||||
le biais d'une entrée dans
|
||||
.B /etc/hosts
|
||||
ou via un
|
||||
.B --host-record.
|
||||
|
||||
.nf
|
||||
.B auth-server=notre.zone.com,eth0
|
||||
.B host-record=notre.zone.com,1.2.3.4
|
||||
.B auth-zone=notre.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
Si l'adresse externe est dynamique, l'adresse associée à notre.zone.com doit
|
||||
être dérivée de l'interface correspondante. Cela peut être fait en utilisant
|
||||
.B interface-name
|
||||
Sous la forme :
|
||||
|
||||
.nf
|
||||
.B auth-server=notre.zone.com,eth0
|
||||
.B interface-name=notre.zone.com,eth0
|
||||
.B auth-zone=notre.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
La configuration finale rajoute à cette base un serveur DNS secondaire. Il
|
||||
s'agit d'un autre serveur DNS qui apprend les données DNS de la zone en
|
||||
effectuant un transfert de zone, et qui joue le rôle de serveur de secours
|
||||
au cas où le serveur principal devenait inaccessible. La configuration
|
||||
de ce serveur secondaire sort du cadre de cette page de manuel. Les éléments
|
||||
de configuration à rajouter dans dnsmasq sont les simples :
|
||||
|
||||
.nf
|
||||
.B auth-sec-servers=secondaire.monfai.com
|
||||
.fi
|
||||
|
||||
et
|
||||
.B --tftp-no-blocksize
|
||||
sont ignorées pour les requêtes sur de telles interfaces. (une directive
|
||||
.B --tftp-root
|
||||
donnant le chemin de la racine et une interface doit-être fournie).
|
||||
|
||||
Ces règles peuvent paraître étrange à première vue, mais elles permettent
|
||||
d'ajouter à la configuration de dnsmasq des lignes de configuration de la
|
||||
forme "dhcp-range=interface:virt0,192.168.0.4,192.168.0.200" afin de fournir
|
||||
un service DHCP et DNS sur cette interface, sans pour autant affecter les
|
||||
services fournis sur d'autres interfaces, malgré l'absence de paramètres
|
||||
"interface=<interface>" sur les autres lignes de configuration.
|
||||
"enable-tftp=virt0" et "tftp-root=<root>,virt0" effectuent la même chose pour
|
||||
TFTP.
|
||||
L'idée de tout cela est de permettre l'addition de telles lignes
|
||||
automatiquement par libvirt ou un système équivalent, sans perturbation
|
||||
d'une configuration manuelle existant par ailleurs.
|
||||
.nf
|
||||
notre.zone.com NS secondaire.monfai.com
|
||||
.fi
|
||||
|
||||
L'addition d'une option auth-sec-servers active les transferts de zone dans
|
||||
dnsmasq, ce qui permet au serveur secondaire de venir collecter les données
|
||||
DNS. Si vous souhaitez restreindre l'accès à ces données à des hôtes
|
||||
spécifiques, vous pouvez le faire via :
|
||||
|
||||
.nf
|
||||
.B auth-peer=<adresse IP du serveur secondaire>
|
||||
.fi
|
||||
|
||||
Dnsmasq joue le rôle de serveur faisant autorité pour les domaines in-addr.arpa
|
||||
et ipv6.arpa associés aux sous-réseaux définis dans la déclaration de zone
|
||||
auth-zone, ce qui fait que les requêtes DNS inversées (de l'adresse vers
|
||||
le nom) peuvent-simplement être configurées avec un enregistrement NS
|
||||
adéquat. Par exemple, comme nous définissons plus haut les adresses
|
||||
1.2.3.0/24 :
|
||||
.nf
|
||||
3.2.1.in-addr.arpa NS notre.zone.com
|
||||
.fi
|
||||
|
||||
Veuillez noter que pour l'instant, les zones inverses ne sont pas
|
||||
disponibles dans les transferts de zone, donc il est inutile de configurer
|
||||
de serveur secondaire pour la résolution inverse.
|
||||
|
||||
.PP
|
||||
Lorsque dnsmasq est configuré en temps que serveur faisant autorité,
|
||||
les données suivantes sont utilisées pour peupler la zone considérée :
|
||||
.PP
|
||||
.B --mx-host, --srv-host, --dns-rr, --txt-record, --naptr-record
|
||||
, pour autant que les noms des enregistrements se trouvent dans la zone en
|
||||
question.
|
||||
.PP
|
||||
.B --cname
|
||||
pour peu que le nom soit dans le domaine. Si la cible du CNAME n'est
|
||||
pas pleinement qualifiée, alors elle est qualifiée avec le nom de la
|
||||
zone pour laquelle le serveur fait autorité.
|
||||
.PP
|
||||
Les adresses IPv4 et IPv6 extraites de /etc/hosts (et
|
||||
.B --addn-hosts
|
||||
) ainsi que les options
|
||||
.B --host-record
|
||||
fournissant des adresses situées dans l'un des sous-réseaux spécifiés dans
|
||||
.B --auth-zone.
|
||||
.PP
|
||||
Adresses spécifiées par
|
||||
.B --interface-name.
|
||||
Dans ce cas, l'adresse n'est pas limitée à l'un des sous-réseaux donné dans
|
||||
.B --auth-zone.
|
||||
|
||||
.PP
|
||||
Les adresses de baux DHCP, si l'adresse est située dans l'un des sous-réseaux de
|
||||
.B --auth-zone
|
||||
OU dans une plage DHCP construite. Dans le mode par défaut, où le bail
|
||||
DHCP a un nom non qualifié, et éventuellement pour un nom qualifié construit
|
||||
via
|
||||
.B --domain
|
||||
, alors le nom dans la zone faisant autorité est construit à partir du nom
|
||||
non qualifié et du nom de domaine de la zone. Cela peut on non être égal
|
||||
celui fourni par
|
||||
.B --domain.
|
||||
Si l'option
|
||||
.B --dhcp-fqdn
|
||||
est fournie, alors les noms pleinemenet qualifiés associés aux baux DHCP
|
||||
sont utilisés, dès lors qu'ils correspondent au nom de domaine associé
|
||||
à la zone.
|
||||
|
||||
|
||||
.SH CODES DE SORTIE
|
||||
.PP
|
||||
|
||||
1005
po/pt_BR.po
1005
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
756
src/auth.c
Normal file
756
src/auth.c
Normal file
@@ -0,0 +1,756 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_AUTH
|
||||
|
||||
static struct subnet *filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u)
|
||||
{
|
||||
struct subnet *subnet;
|
||||
|
||||
for (subnet = zone->subnet; subnet; subnet = subnet->next)
|
||||
{
|
||||
if (subnet->is6 && (flag & F_IPV4))
|
||||
continue;
|
||||
|
||||
if (!subnet->is6)
|
||||
{
|
||||
struct in_addr addr = addr_u->addr.addr4;
|
||||
struct in_addr mask;
|
||||
|
||||
mask.s_addr = htonl(~((1 << (32 - subnet->prefixlen)) - 1));
|
||||
|
||||
if (is_same_net(addr, subnet->addr4, mask))
|
||||
return subnet;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (is_same_net6(&(addr_u->addr.addr6), &subnet->addr6, subnet->prefixlen))
|
||||
return subnet;
|
||||
#endif
|
||||
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int filter_constructed_dhcp(struct auth_zone *zone, int flag, struct all_addr *addr_u)
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
struct dhcp_context *context;
|
||||
|
||||
if (flag & F_IPV6)
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_CONSTRUCTED) &&
|
||||
is_same_net6(&(addr_u->addr.addr6), &context->start6, context->prefix))
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
return filter_zone(zone, flag, addr_u) != NULL;
|
||||
}
|
||||
|
||||
static int in_zone(struct auth_zone *zone, char *name, char **cut)
|
||||
{
|
||||
size_t namelen = strlen(name);
|
||||
size_t domainlen = strlen(zone->domain);
|
||||
|
||||
if (cut)
|
||||
*cut = NULL;
|
||||
|
||||
if (namelen >= domainlen &&
|
||||
hostname_isequal(zone->domain, &name[namelen - domainlen]))
|
||||
{
|
||||
|
||||
if (namelen == domainlen)
|
||||
return 1;
|
||||
|
||||
if (name[namelen - domainlen - 1] == '.')
|
||||
{
|
||||
if (cut)
|
||||
*cut = &name[namelen - domainlen - 1];
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr)
|
||||
{
|
||||
char *name = daemon->namebuff;
|
||||
unsigned char *p, *ansp;
|
||||
int qtype, qclass;
|
||||
int nameoffset, axfroffset = 0;
|
||||
int q, anscount = 0, authcount = 0;
|
||||
struct crec *crecp;
|
||||
int auth = 1, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0;
|
||||
struct auth_zone *zone = NULL;
|
||||
struct subnet *subnet = NULL;
|
||||
char *cut;
|
||||
struct mx_srv_record *rec, *move, **up;
|
||||
struct txt_record *txt;
|
||||
struct interface_name *intr;
|
||||
struct naptr *na;
|
||||
struct all_addr addr;
|
||||
struct cname *a;
|
||||
|
||||
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
|
||||
return 0;
|
||||
|
||||
/* determine end of question section (we put answers there) */
|
||||
if (!(ansp = skip_questions(header, qlen)))
|
||||
return 0; /* bad packet */
|
||||
|
||||
/* now process each question, answers go in RRs after the question */
|
||||
p = (unsigned char *)(header+1);
|
||||
|
||||
for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
{
|
||||
unsigned short flag = 0;
|
||||
int found = 0;
|
||||
|
||||
/* save pointer to name for copying into answers */
|
||||
nameoffset = p - (unsigned char *)header;
|
||||
|
||||
/* now extract name as .-concatenated string into name */
|
||||
if (!extract_name(header, qlen, &p, name, 1, 4))
|
||||
return 0; /* bad packet */
|
||||
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
|
||||
if (qclass != C_IN)
|
||||
{
|
||||
auth = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (qtype == T_PTR)
|
||||
{
|
||||
if (!(flag = in_arpa_name_2_addr(name, &addr)))
|
||||
continue;
|
||||
|
||||
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
||||
if ((subnet = filter_zone(zone, flag, &addr)))
|
||||
break;
|
||||
|
||||
if (!zone)
|
||||
{
|
||||
auth = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flag == F_IPV4)
|
||||
{
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
{
|
||||
if (addr.addr.addr4.s_addr == get_ifaddr(intr->intr).s_addr)
|
||||
break;
|
||||
else
|
||||
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
|
||||
intr = intr->next;
|
||||
}
|
||||
|
||||
if (intr)
|
||||
{
|
||||
if (in_zone(zone, intr->name, NULL))
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
T_PTR, C_IN, "d", intr->name))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((crecp = cache_find_by_addr(NULL, &addr, now, flag)))
|
||||
do {
|
||||
strcpy(name, cache_get_name(crecp));
|
||||
|
||||
if (crecp->flags & F_DHCP && !option_bool(OPT_DHCP_FQDN))
|
||||
{
|
||||
char *p = strchr(name, '.');
|
||||
if (p)
|
||||
*p = 0; /* must be bare name */
|
||||
|
||||
/* add external domain */
|
||||
strcat(name, ".");
|
||||
strcat(name, zone->domain);
|
||||
log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
T_PTR, C_IN, "d", name))
|
||||
anscount++;
|
||||
}
|
||||
else if (crecp->flags & (F_DHCP | F_HOSTS) && in_zone(zone, name, NULL))
|
||||
{
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
T_PTR, C_IN, "d", name))
|
||||
anscount++;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
} while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
|
||||
|
||||
if (!found)
|
||||
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | F_AUTH, NULL, &addr, NULL);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
cname_restart:
|
||||
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
||||
if (in_zone(zone, name, &cut))
|
||||
break;
|
||||
|
||||
if (!zone)
|
||||
{
|
||||
auth = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (rec = daemon->mxnames; rec; rec = rec->next)
|
||||
if (!rec->issrv && hostname_isequal(name, rec->name))
|
||||
{
|
||||
nxdomain = 0;
|
||||
|
||||
if (qtype == T_MX)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_MX, C_IN, "sd", rec->weight, rec->target))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next)
|
||||
if (rec->issrv && hostname_isequal(name, rec->name))
|
||||
{
|
||||
nxdomain = 0;
|
||||
|
||||
if (qtype == T_SRV)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_SRV, C_IN, "sssd",
|
||||
rec->priority, rec->weight, rec->srvport, rec->target))
|
||||
|
||||
anscount++;
|
||||
}
|
||||
|
||||
/* unlink first SRV record found */
|
||||
if (!move)
|
||||
{
|
||||
move = rec;
|
||||
*up = rec->next;
|
||||
}
|
||||
else
|
||||
up = &rec->next;
|
||||
}
|
||||
else
|
||||
up = &rec->next;
|
||||
|
||||
/* put first SRV record back at the end. */
|
||||
if (move)
|
||||
{
|
||||
*up = move;
|
||||
move->next = NULL;
|
||||
}
|
||||
|
||||
for (txt = daemon->rr; txt; txt = txt->next)
|
||||
if (hostname_isequal(name, txt->name))
|
||||
{
|
||||
nxdomain = 0;
|
||||
if (txt->class == qtype)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, txt->class, C_IN, "t", txt->len, txt->txt))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
for (txt = daemon->txt; txt; txt = txt->next)
|
||||
if (txt->class == C_IN && hostname_isequal(name, txt->name))
|
||||
{
|
||||
nxdomain = 0;
|
||||
if (qtype == T_TXT)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_TXT, C_IN, "t", txt->len, txt->txt))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
for (na = daemon->naptr; na; na = na->next)
|
||||
if (hostname_isequal(name, na->name))
|
||||
{
|
||||
nxdomain = 0;
|
||||
if (qtype == T_NAPTR)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_NAPTR, C_IN, "sszzzd",
|
||||
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
if (hostname_isequal(name, intr->name))
|
||||
{
|
||||
nxdomain = 0;
|
||||
if (qtype == T_A && (addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr != (in_addr_t) -1)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_A, C_IN, "4", &addr))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
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, NULL,
|
||||
T_CNAME, C_IN, "d", name))
|
||||
anscount++;
|
||||
|
||||
goto cname_restart;
|
||||
}
|
||||
|
||||
if (qtype == T_A)
|
||||
flag = F_IPV4;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (qtype == T_AAAA)
|
||||
flag = F_IPV6;
|
||||
#endif
|
||||
|
||||
if (!cut)
|
||||
{
|
||||
nxdomain = 0;
|
||||
|
||||
if (qtype == T_SOA)
|
||||
{
|
||||
soa = 1; /* inhibits auth section */
|
||||
found = 1;
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
|
||||
}
|
||||
else if (qtype == T_AXFR)
|
||||
{
|
||||
struct iname *peers;
|
||||
|
||||
if (peer_addr->sa.sa_family == AF_INET)
|
||||
peer_addr->in.sin_port = 0;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
peer_addr->in6.sin6_port = 0;
|
||||
#endif
|
||||
|
||||
for (peers = daemon->auth_peers; peers; peers = peers->next)
|
||||
if (sockaddr_isequal(peer_addr, &peers->addr))
|
||||
break;
|
||||
|
||||
/* Refuse all AXFR unless --auth-sec-servers is set */
|
||||
if ((!peers && daemon->auth_peers) || !daemon->secondary_forward_server)
|
||||
{
|
||||
if (peer_addr->sa.sa_family == AF_INET)
|
||||
inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
#endif
|
||||
|
||||
my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
soa = 1; /* inhibits auth section */
|
||||
ns = 1; /* ensure we include NS records! */
|
||||
axfr = 1;
|
||||
found = 1;
|
||||
axfroffset = nameoffset;
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>");
|
||||
}
|
||||
else if (qtype == T_NS)
|
||||
{
|
||||
ns = 1; /* inhibits auth section */
|
||||
found = 1;
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");
|
||||
}
|
||||
}
|
||||
|
||||
if (!option_bool(OPT_DHCP_FQDN) && cut)
|
||||
{
|
||||
*cut = 0; /* remove domain part */
|
||||
|
||||
if (!strchr(name, '.') && (crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
|
||||
{
|
||||
if (crecp->flags & F_DHCP)
|
||||
do
|
||||
{
|
||||
nxdomain = 0;
|
||||
if ((crecp->flags & flag) &&
|
||||
(filter_constructed_dhcp(zone, flag, &(crecp->addr.addr))))
|
||||
{
|
||||
*cut = '.'; /* restore domain part */
|
||||
log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
|
||||
*cut = 0; /* remove domain part */
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
qtype == T_A ? "4" : "6", &crecp->addr))
|
||||
anscount++;
|
||||
}
|
||||
} while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
|
||||
}
|
||||
|
||||
*cut = '.'; /* restore domain part */
|
||||
}
|
||||
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
|
||||
{
|
||||
if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
|
||||
do
|
||||
{
|
||||
nxdomain = 0;
|
||||
if ((crecp->flags & flag) && filter_constructed_dhcp(zone, flag, &(crecp->addr.addr)))
|
||||
{
|
||||
log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
qtype == T_A ? "4" : "6", &crecp->addr))
|
||||
anscount++;
|
||||
}
|
||||
} while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
|
||||
}
|
||||
|
||||
if (!found)
|
||||
log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);
|
||||
|
||||
}
|
||||
|
||||
/* Add auth section */
|
||||
if (auth && zone)
|
||||
{
|
||||
char *authname;
|
||||
int newoffset, offset = 0;
|
||||
|
||||
if (!subnet)
|
||||
authname = zone->domain;
|
||||
else
|
||||
{
|
||||
/* handle NS and SOA for PTR records */
|
||||
|
||||
authname = name;
|
||||
|
||||
if (!subnet->is6)
|
||||
{
|
||||
in_addr_t a = ntohl(subnet->addr4.s_addr) >> 8;
|
||||
char *p = name;
|
||||
|
||||
if (subnet->prefixlen == 24)
|
||||
p += sprintf(p, "%d.", a & 0xff);
|
||||
a = a >> 8;
|
||||
if (subnet->prefixlen != 8)
|
||||
p += sprintf(p, "%d.", a & 0xff);
|
||||
a = a >> 8;
|
||||
p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
|
||||
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
char *p = name;
|
||||
int i;
|
||||
|
||||
for (i = subnet->prefixlen-1; i >= 0; i -= 4)
|
||||
{
|
||||
int dig = ((unsigned char *)&subnet->addr6)[i>>3];
|
||||
p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
|
||||
}
|
||||
p += sprintf(p, "ip6.arpa");
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* handle NS and SOA in auth section or for explicit queries */
|
||||
newoffset = ansp - (unsigned char *)header;
|
||||
if (((anscount == 0 && !ns) || soa) &&
|
||||
add_resource_record(header, limit, &trunc, 0, &ansp,
|
||||
daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
|
||||
authname, daemon->authserver, daemon->hostmaster,
|
||||
daemon->soa_sn, daemon->soa_refresh,
|
||||
daemon->soa_retry, daemon->soa_expiry,
|
||||
daemon->auth_ttl))
|
||||
{
|
||||
offset = newoffset;
|
||||
if (soa)
|
||||
anscount++;
|
||||
else
|
||||
authcount++;
|
||||
}
|
||||
|
||||
if (anscount != 0 || ns)
|
||||
{
|
||||
struct name_list *secondary;
|
||||
|
||||
newoffset = ansp - (unsigned char *)header;
|
||||
if (add_resource_record(header, limit, &trunc, -offset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
|
||||
{
|
||||
if (offset == 0)
|
||||
offset = newoffset;
|
||||
if (ns)
|
||||
anscount++;
|
||||
else
|
||||
authcount++;
|
||||
}
|
||||
|
||||
if (!subnet)
|
||||
for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next)
|
||||
if (add_resource_record(header, limit, &trunc, offset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name))
|
||||
{
|
||||
if (ns)
|
||||
anscount++;
|
||||
else
|
||||
authcount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (axfr)
|
||||
{
|
||||
for (rec = daemon->mxnames; rec; rec = rec->next)
|
||||
if (in_zone(zone, rec->name, &cut))
|
||||
{
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
|
||||
if (rec->issrv)
|
||||
{
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_SRV, C_IN, "sssd", cut ? rec->name : NULL,
|
||||
rec->priority, rec->weight, rec->srvport, rec->target))
|
||||
|
||||
anscount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_MX, C_IN, "sd", cut ? rec->name : NULL, rec->weight, rec->target))
|
||||
anscount++;
|
||||
}
|
||||
|
||||
/* restore config data */
|
||||
if (cut)
|
||||
*cut = '.';
|
||||
}
|
||||
|
||||
for (txt = daemon->rr; txt; txt = txt->next)
|
||||
if (in_zone(zone, txt->name, &cut))
|
||||
{
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
|
||||
NULL, txt->class, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
|
||||
anscount++;
|
||||
|
||||
/* restore config data */
|
||||
if (cut)
|
||||
*cut = '.';
|
||||
}
|
||||
|
||||
for (txt = daemon->txt; txt; txt = txt->next)
|
||||
if (txt->class == C_IN && in_zone(zone, txt->name, &cut))
|
||||
{
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_TXT, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
|
||||
anscount++;
|
||||
|
||||
/* restore config data */
|
||||
if (cut)
|
||||
*cut = '.';
|
||||
}
|
||||
|
||||
for (na = daemon->naptr; na; na = na->next)
|
||||
if (in_zone(zone, na->name, &cut))
|
||||
{
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_NAPTR, C_IN, "sszzzd", cut ? na->name : NULL,
|
||||
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
|
||||
anscount++;
|
||||
|
||||
/* restore config data */
|
||||
if (cut)
|
||||
*cut = '.';
|
||||
}
|
||||
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
if (in_zone(zone, intr->name, &cut) && (addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr != (in_addr_t) -1)
|
||||
{
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addr))
|
||||
anscount++;
|
||||
|
||||
/* restore config data */
|
||||
if (cut)
|
||||
*cut = '.';
|
||||
}
|
||||
|
||||
for (a = daemon->cnames; a; a = a->next)
|
||||
if (in_zone(zone, a->alias, &cut))
|
||||
{
|
||||
strcpy(name, a->target);
|
||||
if (!strchr(name, '.'))
|
||||
{
|
||||
strcat(name, ".");
|
||||
strcat(name, zone->domain);
|
||||
}
|
||||
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
T_CNAME, C_IN, "d", cut ? a->alias : NULL, name))
|
||||
anscount++;
|
||||
}
|
||||
|
||||
cache_enumerate(1);
|
||||
while ((crecp = cache_enumerate(0)))
|
||||
{
|
||||
if ((crecp->flags & (F_IPV4 | F_IPV6)) &&
|
||||
!(crecp->flags & (F_NEG | F_NXDOMAIN)) &&
|
||||
(crecp->flags & F_FORWARD))
|
||||
{
|
||||
if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN))
|
||||
{
|
||||
char *cache_name = cache_get_name(crecp);
|
||||
if (!strchr(cache_name, '.') && filter_constructed_dhcp(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))
|
||||
{
|
||||
qtype = T_A;
|
||||
#ifdef HAVE_IPV6
|
||||
if (crecp->flags & F_IPV6)
|
||||
qtype = T_AAAA;
|
||||
#endif
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
(crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
|
||||
{
|
||||
strcpy(name, cache_get_name(crecp));
|
||||
if (in_zone(zone, name, &cut) && filter_constructed_dhcp(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))
|
||||
{
|
||||
qtype = T_A;
|
||||
#ifdef HAVE_IPV6
|
||||
if (crecp->flags & F_IPV6)
|
||||
qtype = T_AAAA;
|
||||
#endif
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
(crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* repeat SOA as last record */
|
||||
if (add_resource_record(header, limit, &trunc, axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
|
||||
daemon->authserver, daemon->hostmaster,
|
||||
daemon->soa_sn, daemon->soa_refresh,
|
||||
daemon->soa_retry, daemon->soa_expiry,
|
||||
daemon->auth_ttl))
|
||||
anscount++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* done all questions, set up header and return length of result */
|
||||
/* clear authoritative and truncated flags, set QR flag */
|
||||
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
|
||||
/* clear RA flag */
|
||||
header->hb4 &= ~HB4_RA;
|
||||
|
||||
/* authoritive */
|
||||
if (auth)
|
||||
header->hb3 |= HB3_AA;
|
||||
|
||||
/* truncation */
|
||||
if (trunc)
|
||||
header->hb3 |= HB3_TC;
|
||||
|
||||
if (anscount == 0 && auth && nxdomain)
|
||||
SET_RCODE(header, NXDOMAIN);
|
||||
else
|
||||
SET_RCODE(header, NOERROR); /* no error */
|
||||
header->ancount = htons(anscount);
|
||||
header->nscount = htons(authcount);
|
||||
header->arcount = htons(0);
|
||||
return ansp - (unsigned char *)header;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
13
src/bpf.c
13
src/bpf.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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,6 +20,7 @@
|
||||
#include <ifaddrs.h>
|
||||
|
||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if_dl.h>
|
||||
@@ -110,7 +111,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
{
|
||||
int iface_index = if_nametoindex(addrs->ifa_name);
|
||||
|
||||
if (iface_index == 0)
|
||||
if (iface_index == 0 || !addrs->ifa_addr || !addrs->ifa_netmask)
|
||||
continue;
|
||||
|
||||
if (family == AF_INET)
|
||||
@@ -118,7 +119,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
struct in_addr addr, netmask, broadcast;
|
||||
addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
|
||||
netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
|
||||
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
|
||||
if (addrs->ifa_broadaddr)
|
||||
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
|
||||
else
|
||||
broadcast.s_addr = 0;
|
||||
if (!((*callback)(addr, iface_index, netmask, broadcast, parm)))
|
||||
goto err;
|
||||
}
|
||||
@@ -146,7 +150,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
addr->s6_addr[3] = 0;
|
||||
}
|
||||
|
||||
if (!((*callback)(addr, prefix, scope_id, iface_index, 0, parm)))
|
||||
/* preferred and valid times == forever until we known how to dtermine them. */
|
||||
if (!((*callback)(addr, prefix, scope_id, iface_index, 0, -1, -1, parm)))
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
98
src/cache.c
98
src/cache.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
@@ -235,6 +235,29 @@ char *cache_get_name(struct crec *crecp)
|
||||
return crecp->name.sname;
|
||||
}
|
||||
|
||||
struct crec *cache_enumerate(int init)
|
||||
{
|
||||
static int bucket;
|
||||
static struct crec *cache;
|
||||
|
||||
if (init)
|
||||
{
|
||||
bucket = 0;
|
||||
cache = NULL;
|
||||
}
|
||||
else if (cache && cache->hash_next)
|
||||
cache = cache->hash_next;
|
||||
else
|
||||
{
|
||||
cache = NULL;
|
||||
while (bucket < hash_size)
|
||||
if ((cache = hash_table[bucket++]))
|
||||
break;
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
static int is_outdated_cname_pointer(struct crec *crecp)
|
||||
{
|
||||
if (!(crecp->flags & F_CNAME))
|
||||
@@ -371,6 +394,9 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
int freed_all = flags & F_REVERSE;
|
||||
int free_avail = 0;
|
||||
|
||||
if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
|
||||
ttl = daemon->max_cache_ttl;
|
||||
|
||||
/* Don't log keys */
|
||||
if (flags & (F_IPV4 | F_IPV6))
|
||||
log_query(flags | F_UPSTREAM, name, addr, NULL);
|
||||
@@ -1042,7 +1068,7 @@ static void add_dhcp_cname(struct crec *target, time_t ttd)
|
||||
void cache_add_dhcp_entry(char *host_name, int prot,
|
||||
struct all_addr *host_address, time_t ttd)
|
||||
{
|
||||
struct crec *crec = NULL;
|
||||
struct crec *crec = NULL, *fail_crec = NULL;
|
||||
unsigned short flags = F_IPV4;
|
||||
int in_hosts = 0;
|
||||
size_t addrlen = sizeof(struct in_addr);
|
||||
@@ -1055,28 +1081,21 @@ void cache_add_dhcp_entry(char *host_name, int prot,
|
||||
}
|
||||
#endif
|
||||
|
||||
inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
|
||||
|
||||
while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
|
||||
{
|
||||
/* check all addresses associated with name */
|
||||
if (crec->flags & F_HOSTS)
|
||||
{
|
||||
/* if in hosts, don't need DHCP record */
|
||||
in_hosts = 1;
|
||||
|
||||
inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
|
||||
if (crec->flags & F_CNAME)
|
||||
my_syslog(MS_DHCP | LOG_WARNING,
|
||||
_("%s is a CNAME, not giving it to the DHCP lease of %s"),
|
||||
host_name, daemon->addrbuff);
|
||||
else if (memcmp(&crec->addr.addr, host_address, addrlen) != 0)
|
||||
{
|
||||
inet_ntop(prot, &crec->addr.addr, daemon->namebuff, MAXDNAME);
|
||||
my_syslog(MS_DHCP | LOG_WARNING,
|
||||
_("not giving name %s to the DHCP lease of %s because "
|
||||
"the name exists in %s with address %s"),
|
||||
host_name, daemon->addrbuff,
|
||||
record_source(crec->uid), daemon->namebuff);
|
||||
}
|
||||
else if (memcmp(&crec->addr.addr, host_address, addrlen) == 0)
|
||||
in_hosts = 1;
|
||||
else
|
||||
fail_crec = crec;
|
||||
}
|
||||
else if (!(crec->flags & F_DHCP))
|
||||
{
|
||||
@@ -1086,21 +1105,34 @@ void cache_add_dhcp_entry(char *host_name, int prot,
|
||||
}
|
||||
}
|
||||
|
||||
if (in_hosts)
|
||||
/* if in hosts, don't need DHCP record */
|
||||
if (in_hosts)
|
||||
return;
|
||||
|
||||
if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
|
||||
{
|
||||
if (crec->flags & F_NEG)
|
||||
{
|
||||
flags |= F_REVERSE;
|
||||
cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
|
||||
}
|
||||
}
|
||||
else
|
||||
flags |= F_REVERSE;
|
||||
|
||||
if ((crec = dhcp_spare))
|
||||
|
||||
/* Name in hosts, address doesn't match */
|
||||
if (fail_crec)
|
||||
{
|
||||
inet_ntop(prot, &fail_crec->addr.addr, daemon->namebuff, MAXDNAME);
|
||||
my_syslog(MS_DHCP | LOG_WARNING,
|
||||
_("not giving name %s to the DHCP lease of %s because "
|
||||
"the name exists in %s with address %s"),
|
||||
host_name, daemon->addrbuff,
|
||||
record_source(fail_crec->uid), daemon->namebuff);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
|
||||
{
|
||||
if (crec->flags & F_NEG)
|
||||
{
|
||||
flags |= F_REVERSE;
|
||||
cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
|
||||
}
|
||||
}
|
||||
else
|
||||
flags |= F_REVERSE;
|
||||
|
||||
if ((crec = dhcp_spare))
|
||||
dhcp_spare = dhcp_spare->next;
|
||||
else /* need new one */
|
||||
crec = whine_malloc(sizeof(struct crec));
|
||||
@@ -1239,14 +1271,14 @@ char *record_source(int index)
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
void querystr(char *str, unsigned short type)
|
||||
void querystr(char *desc, char *str, unsigned short type)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
sprintf(str, "query[type=%d]", type);
|
||||
sprintf(str, "%s[type=%d]", desc, type);
|
||||
for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
|
||||
if (typestr[i].type == type)
|
||||
sprintf(str,"query[%s]", typestr[i].name);
|
||||
sprintf(str,"%s[%s]", desc, typestr[i].name);
|
||||
}
|
||||
|
||||
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||
@@ -1307,6 +1339,8 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||
source = arg;
|
||||
else if (flags & F_UPSTREAM)
|
||||
source = "reply";
|
||||
else if (flags & F_AUTH)
|
||||
source = "auth";
|
||||
else if (flags & F_SERVER)
|
||||
{
|
||||
source = "forwarded";
|
||||
|
||||
41
src/config.h
41
src/config.h
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
@@ -40,9 +40,14 @@
|
||||
#define LOG_MAX 5 /* log-queue length */
|
||||
#define RANDFILE "/dev/urandom"
|
||||
#define EDNS0_OPTION_MAC 5 /* dyndns.org temporary assignment */
|
||||
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* DBUS interface specifics */
|
||||
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* Default - may be overridden by config */
|
||||
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
|
||||
|
||||
#define AUTH_TTL 600 /* default TTL for auth DNS */
|
||||
#define SOA_REFRESH 1200 /* SOA refresh default */
|
||||
#define SOA_RETRY 180 /* SOA retry default */
|
||||
#define SOA_EXPIRY 1209600 /* SOA expiry default */
|
||||
#define RA_INTERVAL 600 /* Send unsolicited RA's this often when not provoked. */
|
||||
|
||||
/* compile-time options: uncomment below to enable or do eg.
|
||||
make COPTS=-DHAVE_BROKEN_RTC
|
||||
|
||||
@@ -92,12 +97,22 @@ HAVE_CONNTRACK
|
||||
a build-dependency on libnetfilter_conntrack, but the resulting binary will
|
||||
still run happily on a kernel without conntrack support.
|
||||
|
||||
HAVE_IPSET
|
||||
define this to include the ability to selectively add resolved ip addresses
|
||||
to given ipsets.
|
||||
|
||||
HAVE_AUTH
|
||||
define this to include the facility to act as an authoritative DNS
|
||||
server for one or more zones.
|
||||
|
||||
|
||||
NO_IPV6
|
||||
NO_TFTP
|
||||
NO_DHCP
|
||||
NO_DHCP6
|
||||
NO_SCRIPT
|
||||
NO_LARGEFILE
|
||||
NO_AUTH
|
||||
these are avilable to explictly 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
|
||||
@@ -119,6 +134,8 @@ RESOLVFILE
|
||||
#define HAVE_DHCP6
|
||||
#define HAVE_TFTP
|
||||
#define HAVE_SCRIPT
|
||||
#define HAVE_AUTH
|
||||
#define HAVE_IPSET
|
||||
/* #define HAVE_LUASCRIPT */
|
||||
/* #define HAVE_BROKEN_RTC */
|
||||
/* #define HAVE_DBUS */
|
||||
@@ -126,7 +143,6 @@ RESOLVFILE
|
||||
/* #define HAVE_CONNTRACK */
|
||||
|
||||
|
||||
|
||||
/* Default locations for important system files. */
|
||||
|
||||
#ifndef LEASEFILE
|
||||
@@ -307,6 +323,13 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#define HAVE_SCRIPT
|
||||
#endif
|
||||
|
||||
#ifdef NO_AUTH
|
||||
#undef HAVE_AUTH
|
||||
#endif
|
||||
|
||||
#if defined(NO_IPSET) || !defined(HAVE_LINUX_NETWORK)
|
||||
#undef HAVE_IPSET
|
||||
#endif
|
||||
|
||||
/* Define a string indicating which options are in use.
|
||||
DNSMASQP_COMPILE_OPTS is only defined in dnsmasq.c */
|
||||
@@ -365,7 +388,15 @@ static char *compile_opts =
|
||||
#ifndef HAVE_CONNTRACK
|
||||
"no-"
|
||||
#endif
|
||||
"conntrack";
|
||||
"conntrack "
|
||||
#ifndef HAVE_IPSET
|
||||
"no-"
|
||||
#endif
|
||||
"ipset "
|
||||
#ifndef HAVE_AUTH
|
||||
"no-"
|
||||
#endif
|
||||
"auth";
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
|
||||
445
src/dbus.c
445
src/dbus.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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,7 @@
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
|
||||
const char* introspection_xml =
|
||||
const char* introspection_xml_template =
|
||||
"<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
|
||||
"\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
|
||||
"<node name=\"" DNSMASQ_PATH "\">\n"
|
||||
@@ -29,7 +29,7 @@ const char* introspection_xml =
|
||||
" <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
|
||||
" </method>\n"
|
||||
" </interface>\n"
|
||||
" <interface name=\"" DNSMASQ_SERVICE "\">\n"
|
||||
" <interface name=\"%s\">\n"
|
||||
" <method name=\"ClearCache\">\n"
|
||||
" </method>\n"
|
||||
" <method name=\"GetVersion\">\n"
|
||||
@@ -38,6 +38,12 @@ const char* introspection_xml =
|
||||
" <method name=\"SetServers\">\n"
|
||||
" <arg name=\"servers\" direction=\"in\" type=\"av\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"SetDomainServers\">\n"
|
||||
" <arg name=\"servers\" direction=\"in\" type=\"as\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"SetServersEx\">\n"
|
||||
" <arg name=\"servers\" direction=\"in\" type=\"aas\"/>\n"
|
||||
" </method>\n"
|
||||
" <signal name=\"DhcpLeaseAdded\">\n"
|
||||
" <arg name=\"ipaddr\" type=\"s\"/>\n"
|
||||
" <arg name=\"hwaddr\" type=\"s\"/>\n"
|
||||
@@ -56,6 +62,8 @@ const char* introspection_xml =
|
||||
" </interface>\n"
|
||||
"</node>\n";
|
||||
|
||||
static char *introspection_xml = NULL;
|
||||
|
||||
struct watch {
|
||||
DBusWatch *watch;
|
||||
struct watch *next;
|
||||
@@ -83,34 +91,135 @@ static dbus_bool_t add_watch(DBusWatch *watch, void *data)
|
||||
|
||||
static void remove_watch(DBusWatch *watch, void *data)
|
||||
{
|
||||
struct watch **up, *w;
|
||||
struct watch **up, *w, *tmp;
|
||||
|
||||
for (up = &(daemon->watches), w = daemon->watches; w; w = w->next)
|
||||
if (w->watch == watch)
|
||||
{
|
||||
*up = w->next;
|
||||
free(w);
|
||||
}
|
||||
else
|
||||
up = &(w->next);
|
||||
for (up = &(daemon->watches), w = daemon->watches; w; w = tmp)
|
||||
{
|
||||
tmp = w->next;
|
||||
if (w->watch == watch)
|
||||
{
|
||||
*up = tmp;
|
||||
free(w);
|
||||
}
|
||||
else
|
||||
up = &(w->next);
|
||||
}
|
||||
|
||||
w = data; /* no warning */
|
||||
}
|
||||
|
||||
static void dbus_read_servers(DBusMessage *message)
|
||||
static void add_update_server(union mysockaddr *addr,
|
||||
union mysockaddr *source_addr,
|
||||
const char *interface,
|
||||
const char *domain)
|
||||
{
|
||||
struct server *serv;
|
||||
|
||||
/* See if there is a suitable candidate, and unmark */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if ((serv->flags & SERV_FROM_DBUS) &&
|
||||
(serv->flags & SERV_MARK))
|
||||
{
|
||||
if (domain)
|
||||
{
|
||||
if (!(serv->flags & SERV_HAS_DOMAIN) || !hostname_isequal(domain, serv->domain))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (serv->flags & SERV_HAS_DOMAIN)
|
||||
continue;
|
||||
}
|
||||
|
||||
serv->flags &= ~SERV_MARK;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!serv && (serv = whine_malloc(sizeof (struct server))))
|
||||
{
|
||||
/* Not found, create a new one. */
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
|
||||
if (domain && !(serv->domain = whine_malloc(strlen(domain)+1)))
|
||||
{
|
||||
free(serv);
|
||||
serv = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = serv;
|
||||
serv->flags = SERV_FROM_DBUS;
|
||||
if (domain)
|
||||
{
|
||||
strcpy(serv->domain, domain);
|
||||
serv->flags |= SERV_HAS_DOMAIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (serv)
|
||||
{
|
||||
if (interface)
|
||||
strcpy(serv->interface, interface);
|
||||
else
|
||||
serv->interface[0] = 0;
|
||||
|
||||
if (source_addr->in.sin_family == AF_INET &&
|
||||
addr->in.sin_addr.s_addr == 0 &&
|
||||
serv->domain)
|
||||
serv->flags |= SERV_NO_ADDR;
|
||||
else
|
||||
{
|
||||
serv->flags &= ~SERV_NO_ADDR;
|
||||
serv->addr = *addr;
|
||||
serv->source_addr = *source_addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void mark_dbus(void)
|
||||
{
|
||||
struct server *serv;
|
||||
|
||||
/* mark everything from DBUS */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (serv->flags & SERV_FROM_DBUS)
|
||||
serv->flags |= SERV_MARK;
|
||||
}
|
||||
|
||||
static void cleanup_dbus()
|
||||
{
|
||||
struct server *serv, *tmp, **up;
|
||||
|
||||
/* unlink and free anything still marked. */
|
||||
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
|
||||
{
|
||||
tmp = serv->next;
|
||||
if (serv->flags & SERV_MARK)
|
||||
{
|
||||
server_gone(serv);
|
||||
*up = serv->next;
|
||||
if (serv->domain)
|
||||
free(serv->domain);
|
||||
free(serv);
|
||||
}
|
||||
else
|
||||
up = &serv->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void dbus_read_servers(DBusMessage *message)
|
||||
{
|
||||
DBusMessageIter iter;
|
||||
union mysockaddr addr, source_addr;
|
||||
char *domain;
|
||||
|
||||
dbus_message_iter_init(message, &iter);
|
||||
|
||||
/* mark everything from DBUS */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (serv->flags & SERV_FROM_DBUS)
|
||||
serv->flags |= SERV_MARK;
|
||||
|
||||
|
||||
mark_dbus();
|
||||
|
||||
while (1)
|
||||
{
|
||||
int skip = 0;
|
||||
@@ -169,6 +278,7 @@ static void dbus_read_servers(DBusMessage *message)
|
||||
/* At the end */
|
||||
break;
|
||||
|
||||
/* process each domain */
|
||||
do {
|
||||
if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING)
|
||||
{
|
||||
@@ -179,83 +289,187 @@ static void dbus_read_servers(DBusMessage *message)
|
||||
domain = NULL;
|
||||
|
||||
if (!skip)
|
||||
{
|
||||
/* See if this is already there, and unmark */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if ((serv->flags & SERV_FROM_DBUS) &&
|
||||
(serv->flags & SERV_MARK))
|
||||
{
|
||||
if (!(serv->flags & SERV_HAS_DOMAIN) && !domain)
|
||||
{
|
||||
serv->flags &= ~SERV_MARK;
|
||||
break;
|
||||
}
|
||||
if ((serv->flags & SERV_HAS_DOMAIN) &&
|
||||
domain &&
|
||||
hostname_isequal(domain, serv->domain))
|
||||
{
|
||||
serv->flags &= ~SERV_MARK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!serv && (serv = whine_malloc(sizeof (struct server))))
|
||||
{
|
||||
/* Not found, create a new one. */
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
|
||||
if (domain)
|
||||
serv->domain = whine_malloc(strlen(domain)+1);
|
||||
|
||||
if (domain && !serv->domain)
|
||||
{
|
||||
free(serv);
|
||||
serv = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = serv;
|
||||
serv->flags = SERV_FROM_DBUS;
|
||||
if (domain)
|
||||
{
|
||||
strcpy(serv->domain, domain);
|
||||
serv->flags |= SERV_HAS_DOMAIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (serv)
|
||||
{
|
||||
if (source_addr.in.sin_family == AF_INET &&
|
||||
addr.in.sin_addr.s_addr == 0 &&
|
||||
serv->domain)
|
||||
serv->flags |= SERV_NO_ADDR;
|
||||
else
|
||||
{
|
||||
serv->flags &= ~SERV_NO_ADDR;
|
||||
serv->addr = addr;
|
||||
serv->source_addr = source_addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
|
||||
add_update_server(&addr, &source_addr, NULL, domain);
|
||||
|
||||
} while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
|
||||
}
|
||||
|
||||
|
||||
/* unlink and free anything still marked. */
|
||||
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
|
||||
cleanup_dbus();
|
||||
}
|
||||
|
||||
static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
{
|
||||
DBusMessageIter iter, array_iter, string_iter;
|
||||
DBusMessage *error = NULL;
|
||||
const char *addr_err;
|
||||
char *dup = NULL;
|
||||
|
||||
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
|
||||
|
||||
if (!dbus_message_iter_init(message, &iter))
|
||||
{
|
||||
tmp = serv->next;
|
||||
if (serv->flags & SERV_MARK)
|
||||
{
|
||||
server_gone(serv);
|
||||
*up = serv->next;
|
||||
free(serv);
|
||||
}
|
||||
else
|
||||
up = &serv->next;
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Failed to initialize dbus message iter");
|
||||
}
|
||||
|
||||
/* check that the message contains an array of arrays */
|
||||
if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
|
||||
(dbus_message_iter_get_element_type(&iter) != (strings ? DBUS_TYPE_STRING : DBUS_TYPE_ARRAY)))
|
||||
{
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
strings ? "Expected array of string" : "Expected array of string arrays");
|
||||
}
|
||||
|
||||
mark_dbus();
|
||||
|
||||
/* array_iter points to each "as" element in the outer array */
|
||||
dbus_message_iter_recurse(&iter, &array_iter);
|
||||
while (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID)
|
||||
{
|
||||
const char *str = NULL;
|
||||
union mysockaddr addr, source_addr;
|
||||
char interface[IF_NAMESIZE];
|
||||
char *str_addr, *str_domain = NULL;
|
||||
|
||||
if (strings)
|
||||
{
|
||||
dbus_message_iter_get_basic(&array_iter, &str);
|
||||
if (!str || !strlen (str))
|
||||
{
|
||||
error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Empty string");
|
||||
break;
|
||||
}
|
||||
|
||||
/* dup the string because it gets modified during parsing */
|
||||
if (dup)
|
||||
free(dup);
|
||||
if (!(dup = str_domain = whine_malloc(strlen(str)+1)))
|
||||
break;
|
||||
|
||||
strcpy(str_domain, str);
|
||||
|
||||
/* point to address part of old string for error message */
|
||||
if ((str_addr = strrchr(str, '/')))
|
||||
str = str_addr+1;
|
||||
|
||||
if ((str_addr = strrchr(str_domain, '/')))
|
||||
{
|
||||
if (*str_domain != '/' || str_addr == str_domain)
|
||||
{
|
||||
error = dbus_message_new_error_printf(message,
|
||||
DBUS_ERROR_INVALID_ARGS,
|
||||
"No domain terminator '%s'",
|
||||
str);
|
||||
break;
|
||||
}
|
||||
*str_addr++ = 0;
|
||||
str_domain++;
|
||||
}
|
||||
else
|
||||
{
|
||||
str_addr = str_domain;
|
||||
str_domain = NULL;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* check the types of the struct and its elements */
|
||||
if ((dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY) ||
|
||||
(dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_STRING))
|
||||
{
|
||||
error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected inner array of strings");
|
||||
break;
|
||||
}
|
||||
|
||||
/* string_iter points to each "s" element in the inner array */
|
||||
dbus_message_iter_recurse(&array_iter, &string_iter);
|
||||
if (dbus_message_iter_get_arg_type(&string_iter) != DBUS_TYPE_STRING)
|
||||
{
|
||||
/* no IP address given */
|
||||
error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected IP address");
|
||||
break;
|
||||
}
|
||||
|
||||
dbus_message_iter_get_basic(&string_iter, &str);
|
||||
if (!str || !strlen (str))
|
||||
{
|
||||
error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Empty IP address");
|
||||
break;
|
||||
}
|
||||
|
||||
/* dup the string because it gets modified during parsing */
|
||||
if (dup)
|
||||
free(dup);
|
||||
if (!(dup = str_addr = whine_malloc(strlen(str)+1)))
|
||||
break;
|
||||
|
||||
strcpy(str_addr, str);
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
memset(&source_addr, 0, sizeof(source_addr));
|
||||
memset(&interface, 0, sizeof(interface));
|
||||
|
||||
/* parse the IP address */
|
||||
addr_err = parse_server(str_addr, &addr, &source_addr, (char *) &interface, NULL);
|
||||
|
||||
if (addr_err)
|
||||
{
|
||||
error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid IP address '%s': %s",
|
||||
str, addr_err);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strings)
|
||||
{
|
||||
char *p;
|
||||
|
||||
do {
|
||||
if (str_domain)
|
||||
{
|
||||
if ((p = strchr(str_domain, '/')))
|
||||
*p++ = 0;
|
||||
}
|
||||
else
|
||||
p = NULL;
|
||||
|
||||
add_update_server(&addr, &source_addr, interface, str_domain);
|
||||
} while ((str_domain = p));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* jump past the address to the domain list (if any) */
|
||||
dbus_message_iter_next (&string_iter);
|
||||
|
||||
/* parse domains and add each server/domain pair to the list */
|
||||
do {
|
||||
str = NULL;
|
||||
if (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING)
|
||||
dbus_message_iter_get_basic(&string_iter, &str);
|
||||
dbus_message_iter_next (&string_iter);
|
||||
|
||||
add_update_server(&addr, &source_addr, interface, str);
|
||||
} while (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING);
|
||||
}
|
||||
|
||||
/* jump to next element in outer array */
|
||||
dbus_message_iter_next(&array_iter);
|
||||
}
|
||||
|
||||
cleanup_dbus();
|
||||
|
||||
if (dup)
|
||||
free(dup);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
@@ -263,23 +477,27 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
void *user_data)
|
||||
{
|
||||
char *method = (char *)dbus_message_get_member(message);
|
||||
|
||||
DBusMessage *reply = NULL;
|
||||
|
||||
if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(message);
|
||||
|
||||
dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection_xml, DBUS_TYPE_INVALID);
|
||||
dbus_connection_send (connection, reply, NULL);
|
||||
dbus_message_unref (reply);
|
||||
/* string length: "%s" provides space for termination zero */
|
||||
if (!introspection_xml &&
|
||||
(introspection_xml = whine_malloc(strlen(introspection_xml_template) + strlen(daemon->dbus_name))))
|
||||
sprintf(introspection_xml, introspection_xml_template, daemon->dbus_name);
|
||||
|
||||
if (introspection_xml)
|
||||
{
|
||||
reply = dbus_message_new_method_return(message);
|
||||
dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection_xml, DBUS_TYPE_INVALID);
|
||||
}
|
||||
}
|
||||
else if (strcmp(method, "GetVersion") == 0)
|
||||
{
|
||||
char *v = VERSION;
|
||||
DBusMessage *reply = dbus_message_new_method_return(message);
|
||||
reply = dbus_message_new_method_return(message);
|
||||
|
||||
dbus_message_append_args(reply, DBUS_TYPE_STRING, &v, DBUS_TYPE_INVALID);
|
||||
dbus_connection_send (connection, reply, NULL);
|
||||
dbus_message_unref (reply);
|
||||
}
|
||||
else if (strcmp(method, "SetServers") == 0)
|
||||
{
|
||||
@@ -287,6 +505,16 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
dbus_read_servers(message);
|
||||
check_servers();
|
||||
}
|
||||
else if (strcmp(method, "SetServersEx") == 0)
|
||||
{
|
||||
reply = dbus_read_servers_ex(message, 0);
|
||||
check_servers();
|
||||
}
|
||||
else if (strcmp(method, "SetDomainServers") == 0)
|
||||
{
|
||||
reply = dbus_read_servers_ex(message, 1);
|
||||
check_servers();
|
||||
}
|
||||
else if (strcmp(method, "ClearCache") == 0)
|
||||
clear_cache_and_reload(dnsmasq_time());
|
||||
else
|
||||
@@ -294,8 +522,17 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
|
||||
method = user_data; /* no warning */
|
||||
|
||||
/* If no reply or no error, return nothing */
|
||||
if (!reply)
|
||||
reply = dbus_message_new_method_return(message);
|
||||
|
||||
if (reply)
|
||||
{
|
||||
dbus_connection_send (connection, reply, NULL);
|
||||
dbus_message_unref (reply);
|
||||
}
|
||||
|
||||
return (DBUS_HANDLER_RESULT_HANDLED);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -315,7 +552,7 @@ char *dbus_init(void)
|
||||
dbus_connection_set_watch_functions(connection, add_watch, remove_watch,
|
||||
NULL, NULL, NULL);
|
||||
dbus_error_init (&dbus_error);
|
||||
dbus_bus_request_name (connection, DNSMASQ_SERVICE, 0, &dbus_error);
|
||||
dbus_bus_request_name (connection, daemon->dbus_name, 0, &dbus_error);
|
||||
if (dbus_error_is_set (&dbus_error))
|
||||
return (char *)dbus_error.message;
|
||||
|
||||
@@ -325,7 +562,7 @@ char *dbus_init(void)
|
||||
|
||||
daemon->dbus = connection;
|
||||
|
||||
if ((message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, "Up")))
|
||||
if ((message = dbus_message_new_signal(DNSMASQ_PATH, daemon->dbus_name, "Up")))
|
||||
{
|
||||
dbus_connection_send(connection, message, NULL);
|
||||
dbus_message_unref(message);
|
||||
@@ -430,7 +667,7 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
|
||||
else
|
||||
return;
|
||||
|
||||
if (!(message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, action_str)))
|
||||
if (!(message = dbus_message_new_signal(DNSMASQ_PATH, daemon->dbus_name, action_str)))
|
||||
return;
|
||||
|
||||
dbus_message_iter_init_append(message, &args);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
@@ -91,6 +91,7 @@ struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *con
|
||||
{
|
||||
struct dhcp_netid *tagif = run_tag_if(tags);
|
||||
struct dhcp_opt *opt;
|
||||
struct dhcp_opt *tmp;
|
||||
|
||||
/* flag options which are valid with the current tag set (sans context tags) */
|
||||
for (opt = opts; opt; opt = opt->next)
|
||||
@@ -135,7 +136,6 @@ struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *con
|
||||
for (opt = opts; opt; opt = opt->next)
|
||||
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
|
||||
{
|
||||
struct dhcp_opt *tmp;
|
||||
for (tmp = opts; tmp; tmp = tmp->next)
|
||||
if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
|
||||
break;
|
||||
@@ -145,6 +145,13 @@ struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *con
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt);
|
||||
}
|
||||
|
||||
/* Finally, eliminate duplicate options later in the chain, and therefore earlier in the config file. */
|
||||
for (opt = opts; opt; opt = opt->next)
|
||||
if (opt->flags & DHOPT_TAGOK)
|
||||
for (tmp = opt->next; tmp; tmp = tmp->next)
|
||||
if (tmp->opt == opt->opt)
|
||||
tmp->flags &= ~DHOPT_TAGOK;
|
||||
|
||||
return tagif;
|
||||
}
|
||||
|
||||
@@ -255,7 +262,7 @@ void dhcp_update_configs(struct dhcp_config *configs)
|
||||
in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
|
||||
restore the status-quo ante first. */
|
||||
|
||||
struct dhcp_config *config;
|
||||
struct dhcp_config *config, *conf_tmp;
|
||||
struct crec *crec;
|
||||
int prot = AF_INET;
|
||||
|
||||
@@ -297,7 +304,8 @@ void dhcp_update_configs(struct dhcp_config *configs)
|
||||
config->hostname, daemon->addrbuff);
|
||||
}
|
||||
|
||||
if (prot == AF_INET && !config_find_by_address(configs, crec->addr.addr.addr.addr4))
|
||||
if (prot == AF_INET &&
|
||||
(!(conf_tmp = config_find_by_address(configs, crec->addr.addr.addr.addr4)) || conf_tmp == config))
|
||||
{
|
||||
config->addr = crec->addr.addr.addr.addr4;
|
||||
config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
|
||||
@@ -305,7 +313,8 @@ void dhcp_update_configs(struct dhcp_config *configs)
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (prot == AF_INET6 && !config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0))
|
||||
if (prot == AF_INET6 &&
|
||||
(!(conf_tmp = config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0)) || conf_tmp == config))
|
||||
{
|
||||
memcpy(&config->addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ);
|
||||
config->flags |= CONFIG_ADDR6 | CONFIG_ADDR_HOSTS;
|
||||
@@ -331,83 +340,6 @@ void dhcp_update_configs(struct dhcp_config *configs)
|
||||
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
static int join_multicast_worker(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam)
|
||||
{
|
||||
char ifrn_name[IFNAMSIZ];
|
||||
struct ipv6_mreq mreq;
|
||||
int fd, i, max = *((int *)vparam);
|
||||
struct iname *tmp;
|
||||
|
||||
(void)prefix;
|
||||
(void)scope;
|
||||
(void)dad;
|
||||
|
||||
/* record which interfaces we join on, so that we do it at most one per
|
||||
interface, even when they have multiple addresses. Use outpacket
|
||||
as an array of int, since it's always allocated here and easy
|
||||
to expand for theoretical vast numbers of interfaces. */
|
||||
for (i = 0; i < max; i++)
|
||||
if (if_index == ((int *)daemon->outpacket.iov_base)[i])
|
||||
return 1;
|
||||
|
||||
if ((fd = socket(PF_INET6, SOCK_DGRAM, 0)) == -1)
|
||||
return 0;
|
||||
|
||||
if (!indextoname(fd, if_index, ifrn_name))
|
||||
{
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
/* Are we doing DHCP on this interface? */
|
||||
if (!iface_check(AF_INET6, (struct all_addr *)local, ifrn_name))
|
||||
return 1;
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifrn_name) == 0))
|
||||
return 1;
|
||||
|
||||
mreq.ipv6mr_interface = if_index;
|
||||
|
||||
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
|
||||
|
||||
if (daemon->dhcp6 &&
|
||||
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||
return 0;
|
||||
|
||||
inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
|
||||
|
||||
if (daemon->dhcp6 &&
|
||||
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||
return 0;
|
||||
|
||||
inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
|
||||
|
||||
if (daemon->ra_contexts &&
|
||||
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||
return 0;
|
||||
|
||||
expand_buf(&daemon->outpacket, (max+1) * sizeof(int));
|
||||
((int *)daemon->outpacket.iov_base)[max++] = if_index;
|
||||
|
||||
*((int *)vparam) = max;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void join_multicast(void)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
if (!iface_enumerate(AF_INET6, &count, join_multicast_worker))
|
||||
die(_("failed to join DHCPv6 multicast group: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
void bindtodevice(int fd)
|
||||
{
|
||||
@@ -418,7 +350,7 @@ void bindtodevice(int fd)
|
||||
SO_BINDTODEVICE is only available Linux. */
|
||||
|
||||
struct irec *iface, *found;
|
||||
|
||||
|
||||
for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->dhcp_ok)
|
||||
{
|
||||
@@ -433,14 +365,14 @@ void bindtodevice(int fd)
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
strcpy(ifr.ifr_name, found->name);
|
||||
/* only allowed by root. */
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 &&
|
||||
errno != EPERM)
|
||||
die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
{
|
||||
struct ifreq ifr;
|
||||
strcpy(ifr.ifr_name, found->name);
|
||||
/* only allowed by root. */
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 &&
|
||||
errno != EPERM)
|
||||
die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -487,15 +419,15 @@ static const struct opttab_t {
|
||||
{ "x-windows-fs", 48, OT_ADDR_LIST },
|
||||
{ "x-windows-dm", 49, OT_ADDR_LIST },
|
||||
{ "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
|
||||
{ "lease-time", 51, OT_INTERNAL | OT_DEC },
|
||||
{ "lease-time", 51, OT_INTERNAL | OT_TIME },
|
||||
{ "option-overload", 52, OT_INTERNAL },
|
||||
{ "message-type", 53, OT_INTERNAL | OT_DEC },
|
||||
{ "server-identifier", 54, OT_INTERNAL | OT_ADDR_LIST },
|
||||
{ "parameter-request", 55, OT_INTERNAL },
|
||||
{ "message", 56, OT_INTERNAL },
|
||||
{ "max-message-size", 57, OT_INTERNAL },
|
||||
{ "T1", 58, OT_INTERNAL | OT_DEC},
|
||||
{ "T2", 59, OT_INTERNAL | OT_DEC},
|
||||
{ "T1", 58, OT_INTERNAL | OT_TIME},
|
||||
{ "T2", 59, OT_INTERNAL | OT_TIME},
|
||||
{ "vendor-class", 60, 0 },
|
||||
{ "client-id", 61, OT_INTERNAL },
|
||||
{ "nis+-domain", 64, OT_NAME },
|
||||
@@ -546,6 +478,7 @@ static const struct opttab_t opttab6[] = {
|
||||
{ "nis-domain", 29, OT_RFC1035_NAME },
|
||||
{ "nis+-domain", 30, OT_RFC1035_NAME },
|
||||
{ "sntp-server", 31, OT_ADDR_LIST },
|
||||
{ "information-refresh-time", 32, OT_TIME },
|
||||
{ "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
|
||||
{ "ntp-server", 56, OT_ADDR_LIST },
|
||||
{ "bootfile-url", 59, OT_NAME },
|
||||
@@ -579,7 +512,7 @@ void display_opts6(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
u16 lookup_dhcp_opt(int prot, char *name)
|
||||
int lookup_dhcp_opt(int prot, char *name)
|
||||
{
|
||||
const struct opttab_t *t;
|
||||
int i;
|
||||
@@ -592,14 +525,13 @@ u16 lookup_dhcp_opt(int prot, char *name)
|
||||
t = opttab;
|
||||
|
||||
for (i = 0; t[i].name; i++)
|
||||
if (!(t[i].size & OT_INTERNAL) &&
|
||||
strcasecmp(t[i].name, name) == 0)
|
||||
if (strcasecmp(t[i].name, name) == 0)
|
||||
return t[i].val;
|
||||
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
u16 lookup_dhcp_len(int prot, u16 val)
|
||||
int lookup_dhcp_len(int prot, int val)
|
||||
{
|
||||
const struct opttab_t *t;
|
||||
int i;
|
||||
@@ -613,14 +545,9 @@ u16 lookup_dhcp_len(int prot, u16 val)
|
||||
|
||||
for (i = 0; t[i].name; i++)
|
||||
if (val == t[i].val)
|
||||
{
|
||||
if (t[i].size & OT_INTERNAL)
|
||||
return 0;
|
||||
|
||||
return t[i].size & ~OT_DEC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return t[i].size & ~OT_DEC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
|
||||
@@ -710,14 +637,17 @@ char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if ((ot[o].size & OT_DEC) && opt_len != 0)
|
||||
else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
|
||||
{
|
||||
unsigned int dec = 0;
|
||||
|
||||
for (i = 0; i < opt_len; i++)
|
||||
dec = (dec << 8) | val[i];
|
||||
|
||||
sprintf(buf, "%u", dec);
|
||||
if (ot[o].size & OT_TIME)
|
||||
prettyprint_time(buf, dec);
|
||||
else
|
||||
sprintf(buf, "%u", dec);
|
||||
}
|
||||
else
|
||||
nodecode = 1;
|
||||
@@ -744,4 +674,82 @@ char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len,
|
||||
|
||||
}
|
||||
|
||||
void log_context(int family, struct dhcp_context *context)
|
||||
{
|
||||
/* Cannot use dhcp_buff* for RA contexts */
|
||||
|
||||
void *start = &context->start;
|
||||
void *end = &context->end;
|
||||
char *template = "", *p = daemon->namebuff;
|
||||
|
||||
*p = 0;
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (family == AF_INET6)
|
||||
{
|
||||
struct in6_addr subnet = context->start6;
|
||||
if (!(context->flags & CONTEXT_TEMPLATE))
|
||||
setaddr6part(&subnet, 0);
|
||||
inet_ntop(AF_INET6, &subnet, daemon->addrbuff, ADDRSTRLEN);
|
||||
start = &context->start6;
|
||||
end = &context->end6;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
|
||||
strcpy(daemon->namebuff, _(", prefix deprecated"));
|
||||
else
|
||||
{
|
||||
p += sprintf(p, _(", lease time "));
|
||||
prettyprint_time(p, context->lease_time);
|
||||
p += strlen(p);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (context->flags & CONTEXT_CONSTRUCTED)
|
||||
{
|
||||
char ifrn_name[IFNAMSIZ];
|
||||
|
||||
template = p;
|
||||
p += sprintf(p, ", ");
|
||||
|
||||
if (indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, context->if_index, ifrn_name))
|
||||
sprintf(p, "constructed for %s", ifrn_name);
|
||||
}
|
||||
else if (context->flags & CONTEXT_TEMPLATE)
|
||||
{
|
||||
template = p;
|
||||
p += sprintf(p, ", ");
|
||||
|
||||
sprintf(p, "template for %s", context->template_interface);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((context->flags & CONTEXT_DHCP) || family == AF_INET)
|
||||
{
|
||||
inet_ntop(family, start, daemon->dhcp_buff, 256);
|
||||
inet_ntop(family, end, daemon->dhcp_buff3, 256);
|
||||
my_syslog(MS_DHCP | LOG_INFO,
|
||||
(context->flags & CONTEXT_RA_STATELESS) ?
|
||||
_("%s stateless on %s%.0s%.0s%s") :
|
||||
(context->flags & CONTEXT_STATIC) ?
|
||||
_("%s, static leases only on %.0s%s%s%.0s") :
|
||||
(context->flags & CONTEXT_PROXY) ?
|
||||
_("%s, proxy on subnet %.0s%s%.0s%.0s") :
|
||||
_("%s, IP range %s -- %s%s%.0s"),
|
||||
(family != AF_INET) ? "DHCPv6" : "DHCP",
|
||||
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (context->flags & CONTEXT_RA_NAME)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
|
||||
|
||||
if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
|
||||
22
src/dhcp.c
22
src/dhcp.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
@@ -65,14 +65,22 @@ static int make_fd(int port)
|
||||
|
||||
/* When bind-interfaces is set, there might be more than one dnmsasq
|
||||
instance binding port 67. That's OK if they serve different networks.
|
||||
Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
|
||||
Need to set REUSEADDR|REUSEPORT to make this posible.
|
||||
Handle the case that REUSEPORT is defined, but the kernel doesn't
|
||||
support it. This handles the introduction of REUSEPORT on Linux. */
|
||||
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
|
||||
{
|
||||
int rc = -1, porterr = 0;
|
||||
|
||||
#ifdef SO_REUSEPORT
|
||||
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
|
||||
#else
|
||||
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
|
||||
if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
|
||||
errno != ENOPROTOOPT)
|
||||
porterr = 1;
|
||||
#endif
|
||||
|
||||
if (rc == -1 && !porterr)
|
||||
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
|
||||
|
||||
if (rc == -1)
|
||||
die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
@@ -252,7 +260,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
}
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
/* unlinked contexts are marked by context->current == context */
|
||||
@@ -262,7 +270,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
parm.current = NULL;
|
||||
parm.ind = iface_index;
|
||||
|
||||
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name))
|
||||
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name, NULL))
|
||||
{
|
||||
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
|
||||
for a secondary */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
@@ -59,6 +59,11 @@
|
||||
#define OPTION6_SUBSCRIBER_ID 38
|
||||
#define OPTION6_FQDN 39
|
||||
|
||||
/* replace this with the real number when allocated.
|
||||
defining this also enables the relevant code. */
|
||||
/* #define OPTION6_PREFIX_CLASS 99 */
|
||||
|
||||
|
||||
#define DHCP6SUCCESS 0
|
||||
#define DHCP6UNSPEC 1
|
||||
#define DHCP6NOADDRS 2
|
||||
|
||||
358
src/dhcp6.c
358
src/dhcp6.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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,11 +21,12 @@
|
||||
struct iface_param {
|
||||
struct dhcp_context *current;
|
||||
struct in6_addr fallback;
|
||||
int ind;
|
||||
int ind, addr_match;
|
||||
};
|
||||
|
||||
static int complete_context6(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam);
|
||||
int scope, int if_index, int flags,
|
||||
unsigned int preferred, unsigned int valid, void *vparam);
|
||||
|
||||
static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm);
|
||||
|
||||
@@ -36,15 +37,39 @@ void dhcp6_init(void)
|
||||
#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
|
||||
int class = IPTOS_CLASS_CS6;
|
||||
#endif
|
||||
|
||||
int oneopt = 1;
|
||||
|
||||
if ((fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1 ||
|
||||
#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
|
||||
setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
|
||||
#endif
|
||||
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &oneopt, sizeof(oneopt)) == -1 ||
|
||||
!fix_fd(fd) ||
|
||||
!set_ipv6pktinfo(fd))
|
||||
die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
|
||||
|
||||
/* When bind-interfaces is set, there might be more than one dnmsasq
|
||||
instance binding port 547. That's OK if they serve different networks.
|
||||
Need to set REUSEADDR|REUSEPORT to make this posible.
|
||||
Handle the case that REUSEPORT is defined, but the kernel doesn't
|
||||
support it. This handles the introduction of REUSEPORT on Linux. */
|
||||
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
|
||||
{
|
||||
int rc = -1, porterr = 0;
|
||||
|
||||
#ifdef SO_REUSEPORT
|
||||
if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
|
||||
errno != ENOPROTOOPT)
|
||||
porterr = 1;
|
||||
#endif
|
||||
|
||||
if (rc == -1 && !porterr)
|
||||
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
|
||||
|
||||
if (rc == -1)
|
||||
die(_("failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
saddr.sin6_len = sizeof(struct sockaddr_in6);
|
||||
@@ -71,7 +96,6 @@ void dhcp6_packet(time_t now)
|
||||
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||
} control_u;
|
||||
struct sockaddr_in6 from;
|
||||
struct all_addr dest;
|
||||
ssize_t sz;
|
||||
struct ifreq ifr;
|
||||
struct iname *tmp;
|
||||
@@ -98,33 +122,52 @@ void dhcp6_packet(time_t now)
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
|
||||
if_index = p.p->ipi6_ifindex;
|
||||
dest.addr.addr6 = p.p->ipi6_addr;
|
||||
}
|
||||
|
||||
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
if (!iface_check(AF_INET6, (struct all_addr *)&dest, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
/* unlinked contexts are marked by context->current == context */
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
{
|
||||
context->current = context;
|
||||
memset(&context->local6, 0, IN6ADDRSZ);
|
||||
}
|
||||
|
||||
parm.current = NULL;
|
||||
parm.ind = if_index;
|
||||
parm.addr_match = 0;
|
||||
memset(&parm.fallback, 0, IN6ADDRSZ);
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
|
||||
{
|
||||
/* wildcard context for DHCP-stateless only */
|
||||
parm.current = context;
|
||||
context->current = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unlinked contexts are marked by context->current == context */
|
||||
context->current = context;
|
||||
memset(&context->local6, 0, IN6ADDRSZ);
|
||||
}
|
||||
|
||||
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
|
||||
return;
|
||||
|
||||
if (daemon->if_names || daemon->if_addrs)
|
||||
{
|
||||
|
||||
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
break;
|
||||
|
||||
if (!tmp && !parm.addr_match)
|
||||
return;
|
||||
}
|
||||
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
|
||||
port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
|
||||
@@ -147,19 +190,27 @@ void dhcp6_packet(time_t now)
|
||||
}
|
||||
|
||||
static int complete_context6(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam)
|
||||
int scope, int if_index, int flags, unsigned int preferred,
|
||||
unsigned int valid, void *vparam)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
struct iface_param *param = vparam;
|
||||
|
||||
struct iname *tmp;
|
||||
|
||||
(void)scope; /* warning */
|
||||
(void)dad;
|
||||
|
||||
if (if_index == param->ind &&
|
||||
!IN6_IS_ADDR_LOOPBACK(local) &&
|
||||
!IN6_IS_ADDR_LINKLOCAL(local) &&
|
||||
!IN6_IS_ADDR_MULTICAST(local))
|
||||
{
|
||||
/* if we have --listen-address config, see if the
|
||||
arrival interface has a matching address. */
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
if (tmp->addr.sa.sa_family == AF_INET6 &&
|
||||
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
|
||||
param->addr_match = 1;
|
||||
|
||||
/* Determine a globally address on the arrival interface, even
|
||||
if we have no matching dhcp-context, because we're only
|
||||
allocating on remote subnets via relays. This
|
||||
@@ -168,16 +219,40 @@ static int complete_context6(struct in6_addr *local, int prefix,
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
{
|
||||
if (prefix == context->prefix &&
|
||||
if ((context->flags & CONTEXT_DHCP) &&
|
||||
!(context->flags & CONTEXT_TEMPLATE) &&
|
||||
prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
{
|
||||
|
||||
|
||||
/* link it onto the current chain if we've not seen it before */
|
||||
if (context->current == context)
|
||||
{
|
||||
context->current = param->current;
|
||||
param->current = context;
|
||||
struct dhcp_context *tmp, **up;
|
||||
|
||||
/* use interface values only for contructed contexts */
|
||||
if (!(context->flags & CONTEXT_CONSTRUCTED))
|
||||
preferred = valid = 0xffffffff;
|
||||
else if (flags & IFACE_DEPRECATED)
|
||||
preferred = 0;
|
||||
|
||||
if (context->flags & CONTEXT_DEPRECATE)
|
||||
preferred = 0;
|
||||
|
||||
/* order chain, longest preferred time first */
|
||||
for (up = ¶m->current, tmp = param->current; tmp; tmp = tmp->current)
|
||||
if (tmp->preferred <= preferred)
|
||||
break;
|
||||
else
|
||||
up = &tmp->current;
|
||||
|
||||
context->current = *up;
|
||||
*up = context;
|
||||
context->local6 = *local;
|
||||
context->preferred = preferred;
|
||||
context->valid = valid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -198,8 +273,8 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
|
||||
int serial, struct dhcp_netid *netids, struct in6_addr *ans)
|
||||
struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
|
||||
int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans)
|
||||
{
|
||||
/* Find a free address: exclude anything in use and anything allocated to
|
||||
a particular hwaddr/clientid/hostname in our configuration.
|
||||
@@ -216,12 +291,12 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
|
||||
|
||||
/* hash hwaddr: use the SDBM hashing algorithm. This works
|
||||
for MAC addresses, let's see how it manages with client-ids! */
|
||||
for (j = 0, i = 0; i < clid_len; i++)
|
||||
for (j = iaid, i = 0; i < clid_len; i++)
|
||||
j += clid[i] + (j << 6) + (j << 16) - j;
|
||||
|
||||
for (pass = 0; pass <= 1; pass++)
|
||||
for (pass = 0; pass <= plain_range ? 1 : 0; pass++)
|
||||
for (c = context; c; c = c->current)
|
||||
if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS))
|
||||
if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS | CONTEXT_USED))
|
||||
continue;
|
||||
else if (!match_netid(c->filter, netids, pass))
|
||||
continue;
|
||||
@@ -231,7 +306,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
|
||||
/* 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 + serial) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
|
||||
start = addr6part(&c->start6) + ((j + c->addr_epoch) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
|
||||
|
||||
/* iterate until we find a free address. */
|
||||
addr = start;
|
||||
@@ -248,7 +323,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
|
||||
{
|
||||
*ans = c->start6;
|
||||
setaddr6part (ans, addr);
|
||||
return 1;
|
||||
return c;
|
||||
}
|
||||
|
||||
addr++;
|
||||
@@ -258,13 +333,15 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
|
||||
|
||||
} while (addr != start);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* can dynamically allocate addr */
|
||||
struct dhcp_context *address6_available(struct dhcp_context *context,
|
||||
struct in6_addr *taddr,
|
||||
struct dhcp_netid *netids)
|
||||
struct dhcp_netid *netids,
|
||||
int plain_range)
|
||||
{
|
||||
u64 start, end, addr = addr6part(taddr);
|
||||
struct dhcp_context *tmp;
|
||||
@@ -279,60 +356,61 @@ struct dhcp_context *address6_available(struct dhcp_context *context,
|
||||
is_same_net6(&tmp->end6, taddr, tmp->prefix) &&
|
||||
addr >= start &&
|
||||
addr <= end &&
|
||||
match_netid(tmp->filter, netids, 1))
|
||||
match_netid(tmp->filter, netids, plain_range))
|
||||
return tmp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dhcp_context *narrow_context6(struct dhcp_context *context,
|
||||
struct in6_addr *taddr,
|
||||
struct dhcp_netid *netids)
|
||||
/* address OK if configured */
|
||||
struct dhcp_context *address6_valid(struct dhcp_context *context,
|
||||
struct in6_addr *taddr,
|
||||
struct dhcp_netid *netids,
|
||||
int plain_range)
|
||||
{
|
||||
/* 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
|
||||
address. Note that none may fit, if the address came a dhcp-host and is outside
|
||||
any dhcp-range. In that case we return a static range if possible, or failing that,
|
||||
any context on the correct subnet. (If there's more than one, this is a dodgy
|
||||
configuration: maybe there should be a warning.) */
|
||||
|
||||
struct dhcp_context *tmp;
|
||||
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if (is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
|
||||
match_netid(tmp->filter, netids, plain_range))
|
||||
return tmp;
|
||||
|
||||
if (!(tmp = address6_available(context, taddr, netids)))
|
||||
{
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if (match_netid(tmp->filter, netids, 1) &&
|
||||
is_same_net6(taddr, &tmp->start6, tmp->prefix) &&
|
||||
(tmp->flags & CONTEXT_STATIC))
|
||||
break;
|
||||
|
||||
if (!tmp)
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if (match_netid(tmp->filter, netids, 1) &&
|
||||
is_same_net6(taddr, &tmp->start6, tmp->prefix) &&
|
||||
!(tmp->flags & CONTEXT_PROXY))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Only one context allowed now */
|
||||
if (tmp)
|
||||
tmp->current = NULL;
|
||||
|
||||
return tmp;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int is_addr_in_context6(struct dhcp_context *context, struct dhcp_config *config)
|
||||
int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr)
|
||||
{
|
||||
if (!context) /* called via find_config() from lease_update_from_configs() */
|
||||
return 1;
|
||||
if (!(config->flags & CONFIG_ADDR6))
|
||||
if (!config || !(config->flags & CONFIG_ADDR6))
|
||||
return 0;
|
||||
|
||||
if ((config->flags & CONFIG_WILDCARD) && context->prefix == 64)
|
||||
{
|
||||
*addr = context->start6;
|
||||
setaddr6part(addr, addr6part(&config->addr6));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (is_same_net6(&context->start6, &config->addr6, context->prefix))
|
||||
{
|
||||
*addr = config->addr6;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_config_in_context6(struct dhcp_context *context, struct dhcp_config *config)
|
||||
{
|
||||
if (!(config->flags & CONFIG_ADDR6) ||
|
||||
(config->flags & CONFIG_WILDCARD))
|
||||
|
||||
return 1;
|
||||
|
||||
for (; context; context = context->current)
|
||||
if (is_same_net6(&config->addr6, &context->start6, context->prefix))
|
||||
return 1;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -350,7 +428,7 @@ struct dhcp_config *find_config6(struct dhcp_config *configs,
|
||||
{
|
||||
if (config->clid_len == duid_len &&
|
||||
memcmp(config->clid, duid, duid_len) == 0 &&
|
||||
is_addr_in_context6(context, config))
|
||||
is_config_in_context6(context, config))
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -358,7 +436,7 @@ struct dhcp_config *find_config6(struct dhcp_config *configs,
|
||||
for (config = configs; config; config = config->next)
|
||||
if ((config->flags & CONFIG_NAME) &&
|
||||
hostname_isequal(config->hostname, hostname) &&
|
||||
is_addr_in_context6(context, config))
|
||||
is_config_in_context6(context, config))
|
||||
return config;
|
||||
|
||||
return NULL;
|
||||
@@ -418,6 +496,140 @@ static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, vo
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct cparam {
|
||||
time_t now;
|
||||
int newone, newname;
|
||||
};
|
||||
|
||||
static int construct_worker(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int flags,
|
||||
int preferred, int valid, void *vparam)
|
||||
{
|
||||
char ifrn_name[IFNAMSIZ];
|
||||
struct in6_addr start6, end6;
|
||||
struct dhcp_context *template, *context;
|
||||
|
||||
(void)scope;
|
||||
(void)flags;
|
||||
(void)valid;
|
||||
(void)preferred;
|
||||
|
||||
struct cparam *param = vparam;
|
||||
|
||||
if (IN6_IS_ADDR_LOOPBACK(local) ||
|
||||
IN6_IS_ADDR_LINKLOCAL(local) ||
|
||||
IN6_IS_ADDR_MULTICAST(local))
|
||||
return 1;
|
||||
|
||||
if (!indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, if_index, ifrn_name))
|
||||
return 0;
|
||||
|
||||
for (template = daemon->dhcp6; template; template = template->next)
|
||||
if (!(template->flags & CONTEXT_TEMPLATE))
|
||||
{
|
||||
/* non-template entries, just fill in interface and local addresses */
|
||||
if (prefix == template->prefix &&
|
||||
is_same_net6(local, &template->start6, prefix) &&
|
||||
is_same_net6(local, &template->end6, prefix))
|
||||
{
|
||||
template->if_index = if_index;
|
||||
template->local6 = *local;
|
||||
}
|
||||
|
||||
}
|
||||
else if (addr6part(local) == addr6part(&template->start6) && wildcard_match(template->template_interface, ifrn_name))
|
||||
{
|
||||
start6 = *local;
|
||||
setaddr6part(&start6, addr6part(&template->start6));
|
||||
end6 = *local;
|
||||
setaddr6part(&end6, addr6part(&template->end6));
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_CONSTRUCTED) &&
|
||||
IN6_ARE_ADDR_EQUAL(&start6, &context->start6) &&
|
||||
IN6_ARE_ADDR_EQUAL(&end6, &context->end6))
|
||||
{
|
||||
context->flags &= ~CONTEXT_GC;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!context && (context = whine_malloc(sizeof (struct dhcp_context))))
|
||||
{
|
||||
*context = *template;
|
||||
context->start6 = start6;
|
||||
context->end6 = end6;
|
||||
context->flags &= ~CONTEXT_TEMPLATE;
|
||||
context->flags |= CONTEXT_CONSTRUCTED;
|
||||
context->if_index = if_index;
|
||||
context->local6 = *local;
|
||||
|
||||
context->next = daemon->dhcp6;
|
||||
daemon->dhcp6 = context;
|
||||
|
||||
ra_start_unsolicted(param->now, context);
|
||||
/* we created a new one, need to call
|
||||
lease_update_file to get periodic functions called */
|
||||
param->newone = 1;
|
||||
|
||||
/* Will need to add new putative SLAAC addresses to existing leases */
|
||||
if (context->flags & CONTEXT_RA_NAME)
|
||||
param->newname = 1;
|
||||
|
||||
log_context(AF_INET6, context);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dhcp_construct_contexts(time_t now)
|
||||
{
|
||||
struct dhcp_context *tmp, *context, **up;
|
||||
struct cparam param;
|
||||
param.newone = 0;
|
||||
param.newname = 0;
|
||||
param.now = now;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
{
|
||||
context->if_index = 0;
|
||||
if (context->flags & CONTEXT_CONSTRUCTED)
|
||||
context->flags |= CONTEXT_GC;
|
||||
}
|
||||
|
||||
iface_enumerate(AF_INET6, ¶m, construct_worker);
|
||||
|
||||
for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
|
||||
{
|
||||
tmp = context->next;
|
||||
|
||||
if (context->flags & CONTEXT_GC)
|
||||
{
|
||||
*up = context->next;
|
||||
param.newone = 1; /* include deletion */
|
||||
if (context->flags & CONTEXT_RA_NAME)
|
||||
param.newname = 1;
|
||||
free(context);
|
||||
}
|
||||
else
|
||||
up = &context->next;
|
||||
}
|
||||
|
||||
if (param.newone)
|
||||
{
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
{
|
||||
if (param.newname)
|
||||
lease_update_slaac(now);
|
||||
lease_update_file(now);
|
||||
}
|
||||
else
|
||||
/* Not doing DHCP, so no lease system, manage alarms for ra only */
|
||||
send_alarm(periodic_ra(now), now);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
@@ -52,6 +52,7 @@
|
||||
#define T_OPT 41
|
||||
#define T_TKEY 249
|
||||
#define T_TSIG 250
|
||||
#define T_AXFR 252
|
||||
#define T_MAILB 253
|
||||
#define T_ANY 255
|
||||
|
||||
|
||||
357
src/dnsmasq.c
357
src/dnsmasq.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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,6 +51,7 @@ int main (int argc, char **argv)
|
||||
cap_user_header_t hdr = NULL;
|
||||
cap_user_data_t data = NULL;
|
||||
#endif
|
||||
struct dhcp_context *context;
|
||||
|
||||
#ifdef LOCALEDIR
|
||||
setlocale(LC_ALL, "");
|
||||
@@ -84,6 +85,7 @@ int main (int argc, char **argv)
|
||||
|
||||
daemon->addrbuff = safe_malloc(ADDRSTRLEN);
|
||||
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (!daemon->lease_file)
|
||||
{
|
||||
@@ -147,69 +149,82 @@ int main (int argc, char **argv)
|
||||
die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_AUTH
|
||||
if (daemon->authserver)
|
||||
die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
rand_init();
|
||||
|
||||
now = dnsmasq_time();
|
||||
|
||||
/* Create a serial at startup if not configured. */
|
||||
if (daemon->authinterface && daemon->soa_sn == 0)
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
die(_("zone serial must be configured in --auth-soa"), NULL, EC_BADCONF);
|
||||
#else
|
||||
daemon->soa_sn = now;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->dhcp6)
|
||||
{
|
||||
{
|
||||
|
||||
# ifdef HAVE_DHCP6
|
||||
if (daemon->dhcp6)
|
||||
{
|
||||
daemon->doing_ra = option_bool(OPT_RA);
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
{
|
||||
if (context->flags & CONTEXT_DHCP)
|
||||
daemon->doing_dhcp6 = 1;
|
||||
if (context->flags & CONTEXT_RA)
|
||||
daemon->doing_ra = 1;
|
||||
#ifndef HAVE_LINUX_NETWORK
|
||||
if (context->flags & CONTEXT_TEMPLATE)
|
||||
die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
/* Note that order matters here, we must call lease_init before
|
||||
creating any file descriptors which shouldn't be leaked
|
||||
to the lease-script init process. We need to call common_init
|
||||
before lease_init to allocate buffers it uses.*/
|
||||
dhcp_common_init();
|
||||
lease_init(now);
|
||||
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
{
|
||||
dhcp_common_init();
|
||||
lease_init(now);
|
||||
}
|
||||
|
||||
if (daemon->dhcp)
|
||||
dhcp_init();
|
||||
}
|
||||
|
||||
|
||||
# ifdef HAVE_DHCP6
|
||||
/* Start RA subsystem if --enable-ra OR dhcp-range=<subnet>, ra-only */
|
||||
if (daemon->ra_contexts || option_bool(OPT_RA))
|
||||
{
|
||||
/* link the DHCP6 contexts to the ra-only ones so we can traverse them all
|
||||
from ->ra_contexts, but only the non-ra-onlies from ->dhcp6 */
|
||||
struct dhcp_context *context;
|
||||
if (daemon->doing_ra)
|
||||
ra_init(now);
|
||||
|
||||
if (!daemon->ra_contexts)
|
||||
daemon->ra_contexts = daemon->dhcp6;
|
||||
else
|
||||
{
|
||||
for (context = daemon->ra_contexts; context->next; context = context->next);
|
||||
context->next = daemon->dhcp6;
|
||||
}
|
||||
ra_init(now);
|
||||
if (daemon->doing_dhcp6)
|
||||
dhcp6_init();
|
||||
# endif
|
||||
}
|
||||
|
||||
if (daemon->dhcp6)
|
||||
dhcp6_init();
|
||||
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IPSET
|
||||
if (daemon->ipsets)
|
||||
ipset_init();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* After lease_init */
|
||||
netlink_init();
|
||||
|
||||
|
||||
if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
|
||||
die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
/* after netlink_init */
|
||||
if (daemon->ra_contexts || daemon->dhcp6)
|
||||
join_multicast();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
/* after netlink_init */
|
||||
if (daemon->dhcp || daemon->dhcp6)
|
||||
lease_find_interfaces(now);
|
||||
#endif
|
||||
|
||||
if (!enumerate_interfaces())
|
||||
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
|
||||
|
||||
@@ -239,6 +254,12 @@ int main (int argc, char **argv)
|
||||
}
|
||||
else
|
||||
create_wildcard_listeners();
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
/* after enumerate_interfaces() */
|
||||
if (daemon->doing_dhcp6 || daemon->doing_ra)
|
||||
join_multicast(1);
|
||||
#endif
|
||||
|
||||
if (daemon->port != 0)
|
||||
cache_init();
|
||||
@@ -383,15 +404,48 @@ int main (int argc, char **argv)
|
||||
/* write pidfile _after_ forking ! */
|
||||
if (daemon->runfile)
|
||||
{
|
||||
FILE *pidfile;
|
||||
int fd, err = 0;
|
||||
|
||||
sprintf(daemon->namebuff, "%d\n", (int) getpid());
|
||||
|
||||
/* Explanation: Some installations of dnsmasq (eg Debian/Ubuntu) locate the pid-file
|
||||
in a directory which is writable by the non-privileged user that dnsmasq runs as. This
|
||||
allows the daemon to delete the file as part of its shutdown. This is a security hole to the
|
||||
extent that an attacker running as the unprivileged user could replace the pidfile with a
|
||||
symlink, and have the target of that symlink overwritten as root next time dnsmasq starts.
|
||||
|
||||
The folowing code first deletes any existing file, and then opens it with the O_EXCL flag,
|
||||
ensuring that the open() fails should there be any existing file (because the unlink() failed,
|
||||
or an attacker exploited the race between unlink() and open()). This ensures that no symlink
|
||||
attack can succeed.
|
||||
|
||||
Any compromise of the non-privileged user still theoretically allows the pid-file to be
|
||||
replaced whilst dnsmasq is running. The worst that could allow is that the usual
|
||||
"shutdown dnsmasq" shell command could be tricked into stopping any other process.
|
||||
|
||||
Note that if dnsmasq is started as non-root (eg for testing) it silently ignores
|
||||
failure to write the pid-file.
|
||||
*/
|
||||
|
||||
unlink(daemon->runfile);
|
||||
|
||||
/* only complain if started as root */
|
||||
if ((pidfile = fopen(daemon->runfile, "w")))
|
||||
if ((fd = open(daemon->runfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)) == -1)
|
||||
{
|
||||
fprintf(pidfile, "%d\n", (int) getpid());
|
||||
fclose(pidfile);
|
||||
/* only complain if started as root */
|
||||
if (getuid() == 0)
|
||||
err = 1;
|
||||
}
|
||||
else if (getuid() == 0)
|
||||
else
|
||||
{
|
||||
if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
|
||||
err = 1;
|
||||
|
||||
while (!err && close(fd) == -1)
|
||||
if (!retry_send())
|
||||
err = 1;
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
|
||||
_exit(0);
|
||||
@@ -581,91 +635,27 @@ int main (int argc, char **argv)
|
||||
|
||||
if (daemon->max_logs != 0)
|
||||
my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
|
||||
|
||||
if (daemon->ra_contexts)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
|
||||
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->dhcp6 || daemon->ra_contexts)
|
||||
{
|
||||
struct dhcp_context *dhcp_tmp;
|
||||
int family = AF_INET;
|
||||
dhcp_tmp = daemon->dhcp;
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
again:
|
||||
#endif
|
||||
for (; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
|
||||
{
|
||||
void *start = &dhcp_tmp->start;
|
||||
void *end = &dhcp_tmp->end;
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (family == AF_INET6)
|
||||
{
|
||||
start = &dhcp_tmp->start6;
|
||||
end = &dhcp_tmp->end6;
|
||||
struct in6_addr subnet = dhcp_tmp->start6;
|
||||
setaddr6part(&subnet, 0);
|
||||
inet_ntop(AF_INET6, &subnet, daemon->addrbuff, 256);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (family != AF_INET && (dhcp_tmp->flags & CONTEXT_DEPRECATE))
|
||||
strcpy(daemon->namebuff, _("prefix deprecated"));
|
||||
else
|
||||
{
|
||||
char *p = daemon->namebuff;
|
||||
p += sprintf(p, _("lease time "));
|
||||
prettyprint_time(p, dhcp_tmp->lease_time);
|
||||
}
|
||||
|
||||
if (daemon->dhcp_buff)
|
||||
inet_ntop(family, start, daemon->dhcp_buff, 256);
|
||||
if (daemon->dhcp_buff3)
|
||||
inet_ntop(family, end, daemon->dhcp_buff3, 256);
|
||||
if ((dhcp_tmp->flags & CONTEXT_DHCP) || family == AF_INET)
|
||||
my_syslog(MS_DHCP | LOG_INFO,
|
||||
(dhcp_tmp->flags & CONTEXT_RA_STATELESS) ?
|
||||
_("stateless DHCPv6 on %s%.0s%.0s") :
|
||||
(dhcp_tmp->flags & CONTEXT_STATIC) ?
|
||||
_("DHCP, static leases only on %.0s%s, %s") :
|
||||
(dhcp_tmp->flags & CONTEXT_PROXY) ?
|
||||
_("DHCP, proxy on subnet %.0s%s%.0s") :
|
||||
_("DHCP, IP range %s -- %s, %s"),
|
||||
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff);
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
log_context(AF_INET, context);
|
||||
|
||||
if (dhcp_tmp->flags & CONTEXT_RA_NAME)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s"),
|
||||
daemon->addrbuff);
|
||||
if (dhcp_tmp->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS))
|
||||
{
|
||||
if (!(dhcp_tmp->flags & CONTEXT_DEPRECATE))
|
||||
{
|
||||
char *p = daemon->namebuff;
|
||||
p += sprintf(p, _("prefix valid "));
|
||||
prettyprint_time(p, dhcp_tmp->lease_time > 7200 ? dhcp_tmp->lease_time : 7200);
|
||||
}
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("SLAAC on %s %s"),
|
||||
daemon->addrbuff, daemon->namebuff);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (family == AF_INET)
|
||||
{
|
||||
family = AF_INET6;
|
||||
if (daemon->ra_contexts)
|
||||
dhcp_tmp = daemon->ra_contexts;
|
||||
else
|
||||
dhcp_tmp = daemon->dhcp6;
|
||||
goto again;
|
||||
}
|
||||
#endif
|
||||
# ifdef HAVE_DHCP6
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
log_context(AF_INET6, context);
|
||||
|
||||
}
|
||||
#endif
|
||||
if (daemon->doing_dhcp6 || daemon->doing_ra)
|
||||
dhcp_construct_contexts(now);
|
||||
|
||||
if (option_bool(OPT_RA))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
|
||||
# endif
|
||||
|
||||
/* after dhcp_contruct_contexts */
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
lease_find_interfaces(now);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if (option_bool(OPT_TFTP))
|
||||
@@ -772,13 +762,13 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->dhcp6)
|
||||
if (daemon->doing_dhcp6)
|
||||
{
|
||||
FD_SET(daemon->dhcp6fd, &rset);
|
||||
bump_maxfd(daemon->dhcp6fd, &maxfd);
|
||||
}
|
||||
|
||||
if (daemon->ra_contexts)
|
||||
if (daemon->doing_ra)
|
||||
{
|
||||
FD_SET(daemon->icmp6fd, &rset);
|
||||
bump_maxfd(daemon->icmp6fd, &maxfd);
|
||||
@@ -842,7 +832,7 @@ int main (int argc, char **argv)
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
if (FD_ISSET(daemon->netlinkfd, &rset))
|
||||
netlink_multicast();
|
||||
netlink_multicast(now);
|
||||
#endif
|
||||
|
||||
/* Check for changes to resolv files once per second max. */
|
||||
@@ -890,11 +880,11 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->dhcp6 && FD_ISSET(daemon->dhcp6fd, &rset))
|
||||
if (daemon->doing_dhcp6 && FD_ISSET(daemon->dhcp6fd, &rset))
|
||||
dhcp6_packet(now);
|
||||
|
||||
if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
|
||||
icmp6_packet();
|
||||
if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
|
||||
icmp6_packet(now);
|
||||
#endif
|
||||
|
||||
# ifdef HAVE_SCRIPT
|
||||
@@ -1074,13 +1064,13 @@ static void async_event(int pipe, time_t now)
|
||||
|
||||
case EVENT_ALARM:
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->dhcp6)
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
{
|
||||
lease_prune(NULL, now);
|
||||
lease_update_file(now);
|
||||
}
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (daemon->ra_contexts)
|
||||
else if (daemon->doing_ra)
|
||||
/* Not doing DHCP, so no lease system, manage alarms for ra only */
|
||||
send_alarm(periodic_ra(now), now);
|
||||
#endif
|
||||
@@ -1237,7 +1227,7 @@ void clear_cache_and_reload(time_t now)
|
||||
cache_reload();
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->dhcp6)
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
{
|
||||
if (option_bool(OPT_ETHERS))
|
||||
dhcp_read_ethers();
|
||||
@@ -1248,7 +1238,7 @@ void clear_cache_and_reload(time_t now)
|
||||
lease_update_dns(1);
|
||||
}
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (daemon->ra_contexts)
|
||||
else if (daemon->doing_ra)
|
||||
/* Not doing DHCP, so no lease system, manage
|
||||
alarms for ra only */
|
||||
send_alarm(periodic_ra(now), now);
|
||||
@@ -1352,7 +1342,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
|
||||
if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
|
||||
{
|
||||
int confd;
|
||||
int confd, client_ok = 1;
|
||||
struct irec *iface = NULL;
|
||||
pid_t p;
|
||||
union mysockaddr tcp_addr;
|
||||
@@ -1360,28 +1350,66 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
|
||||
while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
|
||||
|
||||
if (confd == -1 ||
|
||||
getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
|
||||
if (confd == -1)
|
||||
continue;
|
||||
|
||||
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
|
||||
iface = listener->iface; /* May be NULL */
|
||||
else
|
||||
|
||||
if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
|
||||
{
|
||||
/* Check for allowed interfaces when binding the wildcard address:
|
||||
we do this by looking for an interface with the same address as
|
||||
the local address of the TCP connection, then looking to see if that's
|
||||
an allowed interface. As a side effect, we get the netmask of the
|
||||
interface too, for localisation. */
|
||||
|
||||
/* interface may be new since startup */
|
||||
if (enumerate_interfaces())
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&iface->addr, &tcp_addr))
|
||||
break;
|
||||
close(confd);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!iface && !(option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND)))
|
||||
|
||||
if (option_bool(OPT_NOWILD))
|
||||
iface = listener->iface; /* May be NULL */
|
||||
else
|
||||
{
|
||||
int if_index;
|
||||
char intr_name[IF_NAMESIZE];
|
||||
|
||||
/* In full wildcard mode, need to refresh interface list.
|
||||
This happens automagically in CLEVERBIND */
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces();
|
||||
|
||||
/* if we can find the arrival interface, check it's one that's allowed */
|
||||
if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
|
||||
indextoname(listener->tcpfd, if_index, intr_name))
|
||||
{
|
||||
struct all_addr addr;
|
||||
addr.addr.addr4 = tcp_addr.in.sin_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
if (tcp_addr.sa.sa_family == AF_INET6)
|
||||
addr.addr.addr6 = tcp_addr.in6.sin6_addr;
|
||||
#endif
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->index == if_index)
|
||||
break;
|
||||
|
||||
if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
|
||||
client_ok = 0;
|
||||
}
|
||||
|
||||
if (option_bool(OPT_CLEVERBIND))
|
||||
iface = listener->iface; /* May be NULL */
|
||||
else
|
||||
{
|
||||
/* Check for allowed interfaces when binding the wildcard address:
|
||||
we do this by looking for an interface with the same address as
|
||||
the local address of the TCP connection, then looking to see if that's
|
||||
an allowed interface. As a side effect, we get the netmask of the
|
||||
interface too, for localisation. */
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&iface->addr, &tcp_addr))
|
||||
break;
|
||||
|
||||
if (!iface)
|
||||
client_ok = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!client_ok)
|
||||
{
|
||||
shutdown(confd, SHUT_RDWR);
|
||||
close(confd);
|
||||
@@ -1408,11 +1436,18 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
struct server *s;
|
||||
int flags;
|
||||
struct in_addr netmask;
|
||||
int auth_dns;
|
||||
|
||||
if (iface)
|
||||
netmask = iface->netmask;
|
||||
{
|
||||
netmask = iface->netmask;
|
||||
auth_dns = iface->dns_auth;
|
||||
}
|
||||
else
|
||||
netmask.s_addr = 0;
|
||||
{
|
||||
netmask.s_addr = 0;
|
||||
auth_dns = 0;
|
||||
}
|
||||
|
||||
#ifndef NO_FORK
|
||||
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to
|
||||
@@ -1431,7 +1466,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
||||
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
|
||||
buff = tcp_request(confd, now, &tcp_addr, netmask);
|
||||
buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
|
||||
|
||||
shutdown(confd, SHUT_RDWR);
|
||||
close(confd);
|
||||
@@ -1544,7 +1579,7 @@ int icmp_ping(struct in_addr addr)
|
||||
set_log_writer(&wset, &maxfd);
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->ra_contexts)
|
||||
if (daemon->doing_ra)
|
||||
{
|
||||
FD_SET(daemon->icmp6fd, &rset);
|
||||
bump_maxfd(daemon->icmp6fd, &maxfd);
|
||||
@@ -1563,8 +1598,8 @@ int icmp_ping(struct in_addr addr)
|
||||
check_dns_listeners(&rset, now);
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
|
||||
icmp6_packet();
|
||||
if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
|
||||
icmp6_packet(now);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
|
||||
144
src/dnsmasq.h
144
src/dnsmasq.h
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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-2012 Simon Kelley"
|
||||
#define COPYRIGHT "Copyright (c) 2000-2013 Simon Kelley"
|
||||
|
||||
#ifndef NO_LARGEFILE
|
||||
/* Ensure we can use files >2GB (log files may grow this big) */
|
||||
@@ -278,6 +278,20 @@ struct cname {
|
||||
struct cname *next;
|
||||
};
|
||||
|
||||
struct auth_zone {
|
||||
char *domain;
|
||||
struct subnet {
|
||||
int is6, prefixlen;
|
||||
struct in_addr addr4;
|
||||
#ifdef HAVE_IPV6
|
||||
struct in6_addr addr6;
|
||||
#endif
|
||||
struct subnet *next;
|
||||
} *subnet;
|
||||
struct auth_zone *next;
|
||||
};
|
||||
|
||||
|
||||
struct host_record {
|
||||
struct name_list {
|
||||
char *name;
|
||||
@@ -357,6 +371,8 @@ struct crec {
|
||||
#define F_SERVER (1u<<18)
|
||||
#define F_QUERY (1u<<19)
|
||||
#define F_NOERR (1u<<20)
|
||||
#define F_AUTH (1u<<21)
|
||||
|
||||
/* composites */
|
||||
#define F_TYPE (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS) /* Only one may be set */
|
||||
|
||||
@@ -373,6 +389,11 @@ union mysockaddr {
|
||||
#endif
|
||||
};
|
||||
|
||||
/* bits in flag param to IPv6 callbacks from iface_enumerate() */
|
||||
#define IFACE_TENTATIVE 1
|
||||
#define IFACE_DEPRECATED 2
|
||||
|
||||
|
||||
#define SERV_FROM_RESOLV 1 /* 1 for servers from resolv, 0 for command line. */
|
||||
#define SERV_NO_ADDR 2 /* no server, this domain is local only */
|
||||
#define SERV_LITERAL_ADDRESS 4 /* addr is the answer, not the server */
|
||||
@@ -409,11 +430,17 @@ struct server {
|
||||
struct server *next;
|
||||
};
|
||||
|
||||
struct ipsets {
|
||||
char **sets;
|
||||
char *domain;
|
||||
struct ipsets *next;
|
||||
};
|
||||
|
||||
struct irec {
|
||||
union mysockaddr addr;
|
||||
struct in_addr netmask; /* only valid for IPv4 */
|
||||
int tftp_ok, dhcp_ok, mtu, done, dad;
|
||||
char *name;
|
||||
int tftp_ok, dhcp_ok, mtu, done, dad, dns_auth, index, multicast_done;
|
||||
char *name;
|
||||
struct irec *next;
|
||||
};
|
||||
|
||||
@@ -475,7 +502,7 @@ struct frec {
|
||||
#define OT_NAME 0x1000
|
||||
#define OT_CSTRING 0x0800
|
||||
#define OT_DEC 0x0400
|
||||
|
||||
#define OT_TIME 0x0200
|
||||
|
||||
/* actions in the daemon->helper RPC */
|
||||
#define ACTION_DEL 1
|
||||
@@ -516,6 +543,7 @@ struct dhcp_lease {
|
||||
int backoff; /* zero -> confirmed */
|
||||
struct slaac_address *next;
|
||||
} *slaac_address;
|
||||
int vendorclass_count;
|
||||
#endif
|
||||
struct dhcp_lease *next;
|
||||
};
|
||||
@@ -572,6 +600,7 @@ struct dhcp_config {
|
||||
#define CONFIG_DECLINED 1024 /* address declined by client */
|
||||
#define CONFIG_BANK 2048 /* from dhcp hosts file */
|
||||
#define CONFIG_ADDR6 4096
|
||||
#define CONFIG_WILDCARD 8192
|
||||
|
||||
struct dhcp_opt {
|
||||
int opt, len, flags;
|
||||
@@ -651,7 +680,15 @@ struct cond_domain {
|
||||
#endif
|
||||
int is6;
|
||||
struct cond_domain *next;
|
||||
};
|
||||
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
struct prefix_class {
|
||||
int class;
|
||||
struct dhcp_netid tag;
|
||||
struct prefix_class *next;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct dhcp_context {
|
||||
unsigned int lease_time, addr_epoch;
|
||||
@@ -662,7 +699,9 @@ struct dhcp_context {
|
||||
struct in6_addr start6, end6; /* range of available addresses */
|
||||
struct in6_addr local6;
|
||||
int prefix, if_index;
|
||||
time_t ra_time;
|
||||
unsigned int valid, preferred;
|
||||
time_t ra_time, ra_short_period_start;
|
||||
char *template_interface;
|
||||
#endif
|
||||
int flags;
|
||||
struct dhcp_netid netid, *filter;
|
||||
@@ -679,6 +718,12 @@ struct dhcp_context {
|
||||
#define CONTEXT_RA_STATELESS 128
|
||||
#define CONTEXT_DHCP 256
|
||||
#define CONTEXT_DEPRECATE 512
|
||||
#define CONTEXT_TEMPLATE 1024 /* create contexts using addresses */
|
||||
#define CONTEXT_CONSTRUCTED 2048
|
||||
#define CONTEXT_GC 4096
|
||||
#define CONTEXT_RA 8192
|
||||
#define CONTEXT_CONF_USED 16384
|
||||
#define CONTEXT_USED 32768
|
||||
|
||||
struct ping_result {
|
||||
struct in_addr addr;
|
||||
@@ -733,27 +778,32 @@ extern struct daemon {
|
||||
struct ptr_record *ptr;
|
||||
struct host_record *host_records, *host_records_tail;
|
||||
struct cname *cnames;
|
||||
struct auth_zone *auth_zones;
|
||||
struct interface_name *int_names;
|
||||
char *mxtarget;
|
||||
char *lease_file;
|
||||
char *username, *groupname, *scriptuser;
|
||||
char *luascript;
|
||||
char *authserver, *hostmaster;
|
||||
struct iname *authinterface;
|
||||
struct name_list *secondary_forward_server;
|
||||
int group_set, osport;
|
||||
char *domain_suffix;
|
||||
struct cond_domain *cond_domain;
|
||||
char *runfile;
|
||||
char *lease_change_command;
|
||||
struct iname *if_names, *if_addrs, *if_except, *dhcp_except;
|
||||
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers;
|
||||
struct bogus_addr *bogus_addr;
|
||||
struct server *servers;
|
||||
struct ipsets *ipsets;
|
||||
int log_fac; /* log facility */
|
||||
char *log_file; /* optional log file */
|
||||
int max_logs; /* queue limit */
|
||||
int cachesize, ftabsize;
|
||||
int port, query_port, min_port;
|
||||
unsigned long local_ttl, neg_ttl, max_ttl;
|
||||
unsigned long local_ttl, neg_ttl, max_ttl, max_cache_ttl, auth_ttl;
|
||||
struct hostsfile *addn_hosts;
|
||||
struct dhcp_context *dhcp, *dhcp6, *ra_contexts;
|
||||
struct dhcp_context *dhcp, *dhcp6;
|
||||
struct dhcp_config *dhcp_conf;
|
||||
struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6;
|
||||
struct dhcp_vendor *dhcp_vendors;
|
||||
@@ -764,6 +814,7 @@ extern struct daemon {
|
||||
struct addr_list *override_relays;
|
||||
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;
|
||||
@@ -777,6 +828,11 @@ extern struct daemon {
|
||||
struct tftp_prefix *if_prefix; /* per-interface TFTP prefixes */
|
||||
unsigned int duid_enterprise, duid_config_len;
|
||||
unsigned char *duid_config;
|
||||
char *dbus_name;
|
||||
unsigned long soa_sn, soa_refresh, soa_retry, soa_expiry;
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
struct prefix_class *prefix_classes;
|
||||
#endif
|
||||
|
||||
/* globally used stuff for DNS */
|
||||
char *packet; /* packet buffer */
|
||||
@@ -834,7 +890,7 @@ extern struct daemon {
|
||||
void cache_init(void);
|
||||
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg);
|
||||
char *record_source(int index);
|
||||
void querystr(char *str, unsigned short type);
|
||||
void querystr(char *desc, char *str, unsigned short type);
|
||||
struct crec *cache_find_by_addr(struct crec *crecp,
|
||||
struct all_addr *addr, time_t now,
|
||||
unsigned short prot);
|
||||
@@ -850,6 +906,7 @@ struct in_addr a_record_from_hosts(char *name, time_t now);
|
||||
void cache_unhash_dhcp(void);
|
||||
void dump_cache(time_t now);
|
||||
char *cache_get_name(struct crec *crecp);
|
||||
struct crec *cache_enumerate(int init);
|
||||
char *get_domain(struct in_addr addr);
|
||||
#ifdef HAVE_IPV6
|
||||
char *get_domain6(struct in6_addr *addr);
|
||||
@@ -866,7 +923,8 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
|
||||
struct all_addr *addrp, unsigned int flags,
|
||||
unsigned long local_ttl);
|
||||
int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff,
|
||||
time_t now, int is_sign, int checkrebind, int checking_disabled);
|
||||
time_t now, char **ipsets, int is_sign, int checkrebind,
|
||||
int checking_disabled);
|
||||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask, time_t now);
|
||||
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||
@@ -878,6 +936,18 @@ unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
|
||||
size_t resize_packet(struct dns_header *header, size_t plen,
|
||||
unsigned char *pheader, size_t hlen);
|
||||
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
|
||||
int add_resource_record(struct dns_header *header, char *limit, int *truncp,
|
||||
int nameoffset, unsigned char **pp, unsigned long ttl,
|
||||
int *offset, unsigned short type, unsigned short class, char *format, ...);
|
||||
unsigned char *skip_questions(struct dns_header *header, size_t plen);
|
||||
int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
char *name, int isExtract, int extrabytes);
|
||||
int in_arpa_name_2_addr(char *namein, struct all_addr *addrp);
|
||||
|
||||
/* auth.c */
|
||||
#ifdef HAVE_AUTH
|
||||
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr);
|
||||
#endif
|
||||
|
||||
/* util.c */
|
||||
void rand_init(void);
|
||||
@@ -890,7 +960,7 @@ void safe_pipe(int *fd, int read_noblock);
|
||||
void *whine_malloc(size_t size);
|
||||
int sa_len(union mysockaddr *addr);
|
||||
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
|
||||
int hostname_isequal(char *a, char *b);
|
||||
int hostname_isequal(const char *a, const char *b);
|
||||
time_t dnsmasq_time(void);
|
||||
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -910,6 +980,8 @@ char *print_mac(char *buff, unsigned char *mac, int len);
|
||||
void bump_maxfd(int fd, int *max);
|
||||
int read_write(int fd, unsigned char *packet, int size, int rw);
|
||||
|
||||
int wildcard_match(const char* wildcard, const char* match);
|
||||
|
||||
/* log.c */
|
||||
void die(char *message, char *arg1, int exit_code);
|
||||
int log_start(struct passwd *ent_pw, int errfd);
|
||||
@@ -927,12 +999,14 @@ void reread_dhcp(void);
|
||||
void set_option_bool(unsigned int opt);
|
||||
void reset_option_bool(unsigned int opt);
|
||||
struct hostsfile *expand_filelist(struct hostsfile *list);
|
||||
char *parse_server(char *arg, union mysockaddr *addr,
|
||||
union mysockaddr *source_addr, char *interface, int *flags);
|
||||
|
||||
/* forward.c */
|
||||
void reply_query(int fd, int family, time_t now);
|
||||
void receive_query(struct listener *listen, time_t now);
|
||||
unsigned char *tcp_request(int confd, time_t now,
|
||||
union mysockaddr *local_addr, struct in_addr netmask);
|
||||
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns);
|
||||
void server_gone(struct server *server);
|
||||
struct frec *get_new_frec(time_t now, int *wait);
|
||||
int send_from(int fd, int nowild, char *packet, size_t len,
|
||||
@@ -950,12 +1024,17 @@ int enumerate_interfaces();
|
||||
void create_wildcard_listeners(void);
|
||||
void create_bound_listeners(int die);
|
||||
int is_dad_listeners(void);
|
||||
int iface_check(int family, struct all_addr *addr, char *name);
|
||||
int iface_check(int family, struct all_addr *addr, char *name, int *auth_dns);
|
||||
int loopback_exception(int fd, int family, struct all_addr *addr, char *name);
|
||||
int fix_fd(int fd);
|
||||
int tcp_interface(int fd, int af);
|
||||
struct in_addr get_ifaddr(char *intr);
|
||||
#ifdef HAVE_IPV6
|
||||
int set_ipv6pktinfo(int fd);
|
||||
#endif
|
||||
#ifdef HAVE_DHCP6
|
||||
void join_multicast(int dienow);
|
||||
#endif
|
||||
|
||||
/* dhcp.c */
|
||||
#ifdef HAVE_DHCP
|
||||
@@ -991,9 +1070,12 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr);
|
||||
struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type);
|
||||
struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
|
||||
int lease_type, int iaid, struct in6_addr *addr);
|
||||
void lease6_reset(void);
|
||||
struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid);
|
||||
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr);
|
||||
u64 lease_find_max_addr6(struct dhcp_context *context);
|
||||
void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface);
|
||||
void lease_update_slaac(time_t now);
|
||||
#endif
|
||||
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||
unsigned char *clid, int hw_len, int hw_type, int clid_len, time_t now, int force);
|
||||
@@ -1036,7 +1118,7 @@ void poll_resolv(int force, int do_reload, time_t now);
|
||||
/* netlink.c */
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
void netlink_init(void);
|
||||
void netlink_multicast(void);
|
||||
void netlink_multicast(time_t now);
|
||||
#endif
|
||||
|
||||
/* bpf.c */
|
||||
@@ -1059,6 +1141,12 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* ipset.c */
|
||||
#ifdef HAVE_IPSET
|
||||
void ipset_init(void);
|
||||
int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags, int remove);
|
||||
#endif
|
||||
|
||||
/* helper.c */
|
||||
#if defined(HAVE_SCRIPT)
|
||||
int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd);
|
||||
@@ -1088,14 +1176,17 @@ int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
|
||||
#ifdef HAVE_DHCP6
|
||||
void dhcp6_init(void);
|
||||
void dhcp6_packet(time_t now);
|
||||
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
|
||||
int serial, struct dhcp_netid *netids, struct in6_addr *ans);
|
||||
struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
|
||||
int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans);
|
||||
int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr);
|
||||
struct dhcp_context *address6_available(struct dhcp_context *context,
|
||||
struct in6_addr *taddr,
|
||||
struct dhcp_netid *netids);
|
||||
struct dhcp_context *narrow_context6(struct dhcp_context *context,
|
||||
struct in6_addr *taddr,
|
||||
struct dhcp_netid *netids);
|
||||
struct dhcp_netid *netids,
|
||||
int plain_range);
|
||||
struct dhcp_context *address6_valid(struct dhcp_context *context,
|
||||
struct in6_addr *taddr,
|
||||
struct dhcp_netid *netids,
|
||||
int plain_range);
|
||||
struct dhcp_config *find_config6(struct dhcp_config *configs,
|
||||
struct dhcp_context *context,
|
||||
unsigned char *duid, int duid_len,
|
||||
@@ -1103,6 +1194,7 @@ struct dhcp_config *find_config6(struct dhcp_config *configs,
|
||||
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net,
|
||||
int prefix, u64 addr);
|
||||
void make_duid(time_t now);
|
||||
void dhcp_construct_contexts(time_t now);
|
||||
#endif
|
||||
|
||||
/* rfc3315.c */
|
||||
@@ -1124,8 +1216,8 @@ void log_tags(struct dhcp_netid *netid, u32 xid);
|
||||
int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
|
||||
void dhcp_update_configs(struct dhcp_config *configs);
|
||||
void display_opts(void);
|
||||
u16 lookup_dhcp_opt(int prot, char *name);
|
||||
u16 lookup_dhcp_len(int prot, u16 val);
|
||||
int lookup_dhcp_opt(int prot, char *name);
|
||||
int lookup_dhcp_len(int prot, int val);
|
||||
char *option_string(int prot, unsigned int opt, unsigned char *val,
|
||||
int opt_len, char *buf, int buf_len);
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
@@ -1133,8 +1225,8 @@ void bindtodevice(int fd);
|
||||
#endif
|
||||
# ifdef HAVE_DHCP6
|
||||
void display_opts6(void);
|
||||
void join_multicast(void);
|
||||
# endif
|
||||
void log_context(int family, struct dhcp_context *context);
|
||||
#endif
|
||||
|
||||
/* outpacket.c */
|
||||
@@ -1153,16 +1245,14 @@ void put_opt6_string(char *s);
|
||||
/* radv.c */
|
||||
#ifdef HAVE_DHCP6
|
||||
void ra_init(time_t now);
|
||||
void icmp6_packet(void);
|
||||
void icmp6_packet(time_t now);
|
||||
time_t periodic_ra(time_t now);
|
||||
void ra_start_unsolicted(time_t now, struct dhcp_context *context);
|
||||
#endif
|
||||
|
||||
/* slaac.c */
|
||||
#ifdef HAVE_DHCP6
|
||||
void build_subnet_map(void);
|
||||
void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force);
|
||||
time_t periodic_slaac(time_t now, struct dhcp_lease *leases);
|
||||
void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface, struct dhcp_lease *leases);
|
||||
void schedule_subnet_map(void);
|
||||
#endif
|
||||
|
||||
382
src/forward.c
382
src/forward.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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,26 +95,19 @@ int send_from(int fd, int nowild, char *packet, size_t len,
|
||||
#endif
|
||||
}
|
||||
|
||||
retry:
|
||||
if (sendmsg(fd, &msg, 0) == -1)
|
||||
while (sendmsg(fd, &msg, 0) == -1)
|
||||
{
|
||||
/* certain Linux kernels seem to object to setting the source address in the IPv6 stack
|
||||
by returning EINVAL from sendmsg. In that case, try again without setting the
|
||||
source address, since it will nearly alway be correct anyway. IPv6 stinks. */
|
||||
if (errno == EINVAL && msg.msg_controllen)
|
||||
{
|
||||
msg.msg_controllen = 0;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (retry_send())
|
||||
goto retry;
|
||||
continue;
|
||||
|
||||
/* If interface is still in DAD, EINVAL results - ignore that. */
|
||||
if (errno == EINVAL)
|
||||
break;
|
||||
|
||||
my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -335,8 +328,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
struct server *firstsentto = start;
|
||||
int forwarded = 0;
|
||||
|
||||
if (udpaddr && option_bool(OPT_ADD_MAC))
|
||||
plen = add_mac(header, plen, ((char *) header) + PACKETSZ, udpaddr);
|
||||
if (option_bool(OPT_ADD_MAC))
|
||||
plen = add_mac(header, plen, ((char *) header) + PACKETSZ, &forward->source);
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -379,7 +372,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
if (option_bool(OPT_CONNTRACK))
|
||||
{
|
||||
unsigned int mark;
|
||||
if (get_incoming_mark(udpaddr, dst_addr, 0, &mark))
|
||||
if (get_incoming_mark(&forward->source, &forward->dest, 0, &mark))
|
||||
setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||
}
|
||||
#endif
|
||||
@@ -446,9 +439,28 @@ static size_t process_reply(struct dns_header *header, time_t now,
|
||||
struct server *server, size_t n, int check_rebind, int checking_disabled)
|
||||
{
|
||||
unsigned char *pheader, *sizep;
|
||||
char **sets = 0;
|
||||
int munged = 0, is_sign;
|
||||
size_t plen;
|
||||
|
||||
#ifdef HAVE_IPSET
|
||||
/* Similar algorithm to search_servers. */
|
||||
struct ipsets *ipset_pos;
|
||||
unsigned int namelen = strlen(daemon->namebuff);
|
||||
unsigned int matchlen = 0;
|
||||
for (ipset_pos = daemon->ipsets; ipset_pos; ipset_pos = ipset_pos->next)
|
||||
{
|
||||
unsigned int domainlen = strlen(ipset_pos->domain);
|
||||
char *matchstart = daemon->namebuff + namelen - domainlen;
|
||||
if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
|
||||
(domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
|
||||
domainlen >= matchlen) {
|
||||
matchlen = domainlen;
|
||||
sets = ipset_pos->sets;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If upstream is advertising a larger UDP packet size
|
||||
than we allow, trim it so that we don't get overlarge
|
||||
requests for the client. We can't do this for signed packets. */
|
||||
@@ -501,7 +513,7 @@ static size_t process_reply(struct dns_header *header, time_t now,
|
||||
SET_RCODE(header, NOERROR);
|
||||
}
|
||||
|
||||
if (extract_addresses(header, n, daemon->namebuff, now, is_sign, check_rebind, checking_disabled))
|
||||
if (extract_addresses(header, n, daemon->namebuff, now, sets, is_sign, check_rebind, checking_disabled))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
|
||||
munged = 1;
|
||||
@@ -642,6 +654,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
size_t m;
|
||||
ssize_t n;
|
||||
int if_index = 0;
|
||||
int auth_dns = 0;
|
||||
struct iovec iov[1];
|
||||
struct msghdr msg;
|
||||
struct cmsghdr *cmptr;
|
||||
@@ -664,17 +677,20 @@ void receive_query(struct listener *listen, time_t now)
|
||||
/* packet buffer overwritten */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
if (listen->iface && listen->family == AF_INET && option_bool(OPT_NOWILD))
|
||||
dst_addr_4.s_addr = 0;
|
||||
netmask.s_addr = 0;
|
||||
|
||||
if (option_bool(OPT_NOWILD) && listen->iface)
|
||||
{
|
||||
dst_addr_4 = listen->iface->addr.in.sin_addr;
|
||||
netmask = listen->iface->netmask;
|
||||
auth_dns = listen->iface->dns_auth;
|
||||
|
||||
if (listen->family == AF_INET)
|
||||
{
|
||||
dst_addr_4 = listen->iface->addr.in.sin_addr;
|
||||
netmask = listen->iface->netmask;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dst_addr_4.s_addr = 0;
|
||||
netmask.s_addr = 0;
|
||||
}
|
||||
|
||||
|
||||
iov[0].iov_base = daemon->packet;
|
||||
iov[0].iov_len = daemon->edns_pktsz;
|
||||
|
||||
@@ -766,10 +782,17 @@ void receive_query(struct listener *listen, time_t now)
|
||||
|
||||
/* enforce available interface configuration */
|
||||
|
||||
if (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
|
||||
!iface_check(listen->family, &dst_addr, ifr.ifr_name))
|
||||
if (!indextoname(listen->fd, if_index, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
if (!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns))
|
||||
{
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces();
|
||||
if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name))
|
||||
return;
|
||||
}
|
||||
|
||||
if (listen->family == AF_INET && option_bool(OPT_LOCALISE))
|
||||
{
|
||||
struct irec *iface;
|
||||
@@ -783,7 +806,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
break;
|
||||
|
||||
/* interface may be new */
|
||||
if (!iface)
|
||||
if (!iface && !option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces();
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
@@ -803,7 +826,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
{
|
||||
char types[20];
|
||||
|
||||
querystr(types, type);
|
||||
querystr(auth_dns ? "auth" : "query", types, type);
|
||||
|
||||
if (listen->family == AF_INET)
|
||||
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||
@@ -815,19 +838,32 @@ void receive_query(struct listener *listen, time_t now)
|
||||
#endif
|
||||
}
|
||||
|
||||
m = answer_request (header, ((char *) header) + PACKETSZ, (size_t)n,
|
||||
dst_addr_4, netmask, now);
|
||||
if (m >= 1)
|
||||
#ifdef HAVE_AUTH
|
||||
if (auth_dns)
|
||||
{
|
||||
send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
|
||||
(char *)header, m, &source_addr, &dst_addr, if_index);
|
||||
daemon->local_answer++;
|
||||
m = answer_auth(header, ((char *) header) + PACKETSZ, (size_t)n, now, &source_addr);
|
||||
if (m >= 1)
|
||||
send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
|
||||
(char *)header, m, &source_addr, &dst_addr, if_index);
|
||||
}
|
||||
else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
|
||||
header, (size_t)n, now, NULL))
|
||||
daemon->queries_forwarded++;
|
||||
else
|
||||
daemon->local_answer++;
|
||||
#endif
|
||||
{
|
||||
m = answer_request(header, ((char *) header) + PACKETSZ, (size_t)n,
|
||||
dst_addr_4, netmask, now);
|
||||
|
||||
if (m >= 1)
|
||||
{
|
||||
send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
|
||||
(char *)header, m, &source_addr, &dst_addr, if_index);
|
||||
daemon->local_answer++;
|
||||
}
|
||||
else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
|
||||
header, (size_t)n, now, NULL))
|
||||
daemon->queries_forwarded++;
|
||||
else
|
||||
daemon->local_answer++;
|
||||
}
|
||||
}
|
||||
|
||||
/* The daemon forks before calling this: it should deal with one connection,
|
||||
@@ -835,17 +871,21 @@ void receive_query(struct listener *listen, time_t now)
|
||||
about resources for debug mode, when the fork is suppressed: that's
|
||||
done by the caller. */
|
||||
unsigned char *tcp_request(int confd, time_t now,
|
||||
union mysockaddr *local_addr, struct in_addr netmask)
|
||||
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
|
||||
{
|
||||
size_t size = 0;
|
||||
int norebind = 0;
|
||||
int checking_disabled;
|
||||
size_t m;
|
||||
unsigned short qtype, gotname;
|
||||
unsigned short qtype;
|
||||
unsigned int gotname;
|
||||
unsigned char c1, c2;
|
||||
/* Max TCP packet + slop */
|
||||
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ);
|
||||
struct dns_header *header;
|
||||
/* Max TCP packet + slop + size */
|
||||
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
|
||||
unsigned char *payload = &packet[2];
|
||||
/* largest field in header is 16-bits, so this is still sufficiently aligned */
|
||||
struct dns_header *header = (struct dns_header *)payload;
|
||||
u16 *length = (u16 *)packet;
|
||||
struct server *last_server;
|
||||
struct in_addr dst_addr_4;
|
||||
union mysockaddr peer_addr;
|
||||
@@ -859,14 +899,12 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
if (!packet ||
|
||||
!read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
|
||||
!(size = c1 << 8 | c2) ||
|
||||
!read_write(confd, packet, size, 1))
|
||||
!read_write(confd, payload, size, 1))
|
||||
return packet;
|
||||
|
||||
if (size < (int)sizeof(struct dns_header))
|
||||
continue;
|
||||
|
||||
header = (struct dns_header *)packet;
|
||||
|
||||
/* save state of "cd" flag in query */
|
||||
checking_disabled = header->hb4 & HB4_CD;
|
||||
|
||||
@@ -877,7 +915,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
{
|
||||
char types[20];
|
||||
|
||||
querystr(types, qtype);
|
||||
querystr(auth_dns ? "auth" : "query", types, qtype);
|
||||
|
||||
if (peer_addr.sa.sa_family == AF_INET)
|
||||
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||
@@ -894,144 +932,146 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
else
|
||||
dst_addr_4.s_addr = 0;
|
||||
|
||||
/* m > 0 if answered from cache */
|
||||
m = answer_request(header, ((char *) header) + 65536, (unsigned int)size,
|
||||
dst_addr_4, netmask, now);
|
||||
|
||||
/* Do this by steam now we're not in the select() loop */
|
||||
check_log_writer(NULL);
|
||||
|
||||
if (m == 0)
|
||||
#ifdef HAVE_AUTH
|
||||
if (auth_dns)
|
||||
m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
unsigned int flags = 0;
|
||||
struct all_addr *addrp = NULL;
|
||||
int type = 0;
|
||||
char *domain = NULL;
|
||||
|
||||
if (option_bool(OPT_ADD_MAC))
|
||||
size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
|
||||
|
||||
if (gotname)
|
||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
||||
/* m > 0 if answered from cache */
|
||||
m = answer_request(header, ((char *) header) + 65536, (size_t)size,
|
||||
dst_addr_4, netmask, now);
|
||||
|
||||
if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
|
||||
last_server = daemon->servers;
|
||||
else
|
||||
last_server = daemon->last_server;
|
||||
|
||||
if (!flags && last_server)
|
||||
/* Do this by steam now we're not in the select() loop */
|
||||
check_log_writer(NULL);
|
||||
|
||||
if (m == 0)
|
||||
{
|
||||
struct server *firstsendto = NULL;
|
||||
unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);
|
||||
|
||||
/* Loop round available servers until we succeed in connecting to one.
|
||||
Note that this code subtley ensures that consecutive queries on this connection
|
||||
which can go to the same server, do so. */
|
||||
while (1)
|
||||
{
|
||||
if (!firstsendto)
|
||||
firstsendto = last_server;
|
||||
else
|
||||
{
|
||||
if (!(last_server = last_server->next))
|
||||
last_server = daemon->servers;
|
||||
|
||||
if (last_server == firstsendto)
|
||||
break;
|
||||
}
|
||||
unsigned int flags = 0;
|
||||
struct all_addr *addrp = NULL;
|
||||
int type = 0;
|
||||
char *domain = NULL;
|
||||
|
||||
/* server for wrong domain */
|
||||
if (type != (last_server->flags & SERV_TYPE) ||
|
||||
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
|
||||
continue;
|
||||
|
||||
if (last_server->tcpfd == -1)
|
||||
if (option_bool(OPT_ADD_MAC))
|
||||
size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
|
||||
|
||||
if (gotname)
|
||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
||||
|
||||
if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
|
||||
last_server = daemon->servers;
|
||||
else
|
||||
last_server = daemon->last_server;
|
||||
|
||||
if (!flags && last_server)
|
||||
{
|
||||
struct server *firstsendto = NULL;
|
||||
unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);
|
||||
|
||||
/* Loop round available servers until we succeed in connecting to one.
|
||||
Note that this code subtley ensures that consecutive queries on this connection
|
||||
which can go to the same server, do so. */
|
||||
while (1)
|
||||
{
|
||||
if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
|
||||
if (!firstsendto)
|
||||
firstsendto = last_server;
|
||||
else
|
||||
{
|
||||
if (!(last_server = last_server->next))
|
||||
last_server = daemon->servers;
|
||||
|
||||
if (last_server == firstsendto)
|
||||
break;
|
||||
}
|
||||
|
||||
/* server for wrong domain */
|
||||
if (type != (last_server->flags & SERV_TYPE) ||
|
||||
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
|
||||
continue;
|
||||
|
||||
if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
|
||||
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
|
||||
if (last_server->tcpfd == -1)
|
||||
{
|
||||
if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
|
||||
continue;
|
||||
|
||||
if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
|
||||
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
|
||||
{
|
||||
close(last_server->tcpfd);
|
||||
last_server->tcpfd = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
#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));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
*length = htons(size);
|
||||
|
||||
if (!read_write(last_server->tcpfd, packet, size + sizeof(u16), 0) ||
|
||||
!read_write(last_server->tcpfd, &c1, 1, 1) ||
|
||||
!read_write(last_server->tcpfd, &c2, 1, 1))
|
||||
{
|
||||
close(last_server->tcpfd);
|
||||
last_server->tcpfd = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
#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));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
c1 = size >> 8;
|
||||
c2 = size;
|
||||
|
||||
if (!read_write(last_server->tcpfd, &c1, 1, 0) ||
|
||||
!read_write(last_server->tcpfd, &c2, 1, 0) ||
|
||||
!read_write(last_server->tcpfd, packet, size, 0) ||
|
||||
!read_write(last_server->tcpfd, &c1, 1, 1) ||
|
||||
!read_write(last_server->tcpfd, &c2, 1, 1))
|
||||
{
|
||||
close(last_server->tcpfd);
|
||||
last_server->tcpfd = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
m = (c1 << 8) | c2;
|
||||
if (!read_write(last_server->tcpfd, packet, m, 1))
|
||||
return packet;
|
||||
|
||||
if (!gotname)
|
||||
strcpy(daemon->namebuff, "query");
|
||||
if (last_server->addr.sa.sa_family == AF_INET)
|
||||
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&last_server->addr.in.sin_addr, NULL);
|
||||
}
|
||||
|
||||
m = (c1 << 8) | c2;
|
||||
if (!read_write(last_server->tcpfd, payload, m, 1))
|
||||
return packet;
|
||||
|
||||
if (!gotname)
|
||||
strcpy(daemon->namebuff, "query");
|
||||
if (last_server->addr.sa.sa_family == AF_INET)
|
||||
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&last_server->addr.in.sin_addr, NULL);
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&last_server->addr.in6.sin6_addr, NULL);
|
||||
else
|
||||
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&last_server->addr.in6.sin6_addr, NULL);
|
||||
#endif
|
||||
|
||||
/* There's no point in updating the cache, since this process will exit and
|
||||
lose the information after a few queries. We make this call for the alias and
|
||||
bogus-nxdomain side-effects. */
|
||||
/* If the crc of the question section doesn't match the crc we sent, then
|
||||
someone might be attempting to insert bogus values into the cache by
|
||||
sending replies containing questions and bogus answers. */
|
||||
if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff))
|
||||
m = process_reply(header, now, last_server, (unsigned int)m,
|
||||
option_bool(OPT_NO_REBIND) && !norebind, checking_disabled);
|
||||
|
||||
break;
|
||||
|
||||
/* There's no point in updating the cache, since this process will exit and
|
||||
lose the information after a few queries. We make this call for the alias and
|
||||
bogus-nxdomain side-effects. */
|
||||
/* If the crc of the question section doesn't match the crc we sent, then
|
||||
someone might be attempting to insert bogus values into the cache by
|
||||
sending replies containing questions and bogus answers. */
|
||||
if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff))
|
||||
m = process_reply(header, now, last_server, (unsigned int)m,
|
||||
option_bool(OPT_NO_REBIND) && !norebind, checking_disabled);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* In case of local answer or no connections made. */
|
||||
if (m == 0)
|
||||
m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
|
||||
}
|
||||
|
||||
/* In case of local answer or no connections made. */
|
||||
if (m == 0)
|
||||
m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
|
||||
}
|
||||
|
||||
|
||||
check_log_writer(NULL);
|
||||
|
||||
c1 = m>>8;
|
||||
c2 = m;
|
||||
if (!read_write(confd, &c1, 1, 0) ||
|
||||
!read_write(confd, &c2, 1, 0) ||
|
||||
!read_write(confd, packet, m, 0))
|
||||
*length = htons(m);
|
||||
|
||||
if (m == 0 || !read_write(confd, packet, m + sizeof(u16), 0))
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
34
src/helper.c
34
src/helper.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
@@ -34,10 +34,15 @@ static void my_setenv(const char *name, const char *value, int *error);
|
||||
static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err);
|
||||
|
||||
#ifdef HAVE_LUASCRIPT
|
||||
#define LUA_COMPAT_ALL
|
||||
#include <lua.h>
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
#ifndef lua_open
|
||||
#define lua_open() luaL_newstate()
|
||||
#endif
|
||||
|
||||
lua_State *lua;
|
||||
|
||||
static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field);
|
||||
@@ -224,13 +229,6 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
}
|
||||
}
|
||||
|
||||
/* expiry or length into dhcp_buff2 */
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
sprintf(daemon->dhcp_buff2, "%u", data.length);
|
||||
#else
|
||||
sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
|
||||
#endif
|
||||
|
||||
/* supplied data may just exceed normal buffer (unlikely) */
|
||||
if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME &&
|
||||
!(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len)))
|
||||
@@ -392,6 +390,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
buf = grab_extradata_lua(buf, end, "cpewan_oui");
|
||||
buf = grab_extradata_lua(buf, end, "cpewan_serial");
|
||||
buf = grab_extradata_lua(buf, end, "cpewan_class");
|
||||
buf = grab_extradata_lua(buf, end, "circuit_id");
|
||||
buf = grab_extradata_lua(buf, end, "subscriber_id");
|
||||
buf = grab_extradata_lua(buf, end, "remote_id");
|
||||
}
|
||||
|
||||
buf = grab_extradata_lua(buf, end, "tags");
|
||||
@@ -488,8 +489,10 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
my_setenv("DNSMASQ_INTERFACE", data.interface, &err);
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
sprintf(daemon->dhcp_buff2, "%u", data.length);
|
||||
my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
|
||||
#else
|
||||
sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
|
||||
my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
|
||||
#endif
|
||||
|
||||
@@ -523,10 +526,13 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_CIRCUIT_ID", &err);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_SUBSCRIBER_ID", &err);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_REMOTE_ID", &err);
|
||||
}
|
||||
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
|
||||
|
||||
|
||||
if (is6)
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
|
||||
else if (data.giaddr.s_addr != 0)
|
||||
@@ -649,8 +655,9 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
|
||||
unsigned char *p;
|
||||
unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
|
||||
int fd = daemon->dhcpfd;
|
||||
#ifdef HAVE_DHCP6
|
||||
int is6 = !!(lease->flags & (LEASE_TA | LEASE_NA));
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (!daemon->dhcp)
|
||||
fd = daemon->dhcp6fd;
|
||||
#endif
|
||||
@@ -670,7 +677,12 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
|
||||
|
||||
buf->action = action;
|
||||
buf->flags = lease->flags;
|
||||
buf->hwaddr_len = lease->hwaddr_len;
|
||||
#ifdef HAVE_DHCP6
|
||||
if (is6)
|
||||
buf->hwaddr_len = lease->vendorclass_count;
|
||||
else
|
||||
#endif
|
||||
buf->hwaddr_len = lease->hwaddr_len;
|
||||
buf->hwaddr_type = lease->hwaddr_type;
|
||||
buf->clid_len = clid_len;
|
||||
buf->ed_len = ed_len;
|
||||
|
||||
205
src/ipset.c
Normal file
205
src/ipset.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/* ipset.c is Copyright (c) 2013 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_IPSET
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#ifndef NFNL_SUBSYS_IPSET
|
||||
#define NFNL_SUBSYS_IPSET 6
|
||||
#define IPSET_ATTR_DATA 7
|
||||
#define IPSET_ATTR_IP 1
|
||||
#define IPSET_ATTR_IPADDR_IPV4 1
|
||||
#define IPSET_ATTR_IPADDR_IPV6 2
|
||||
#define IPSET_ATTR_PROTOCOL 1
|
||||
#define IPSET_ATTR_SETNAME 2
|
||||
#define IPSET_CMD_ADD 9
|
||||
#define IPSET_CMD_DEL 10
|
||||
#define IPSET_MAXNAMELEN 32
|
||||
#define IPSET_PROTOCOL 6
|
||||
#else
|
||||
#include <linux/netfilter/ipset/ip_set.h>
|
||||
#endif
|
||||
|
||||
/* data structure size in here is fixed */
|
||||
#define BUFF_SZ 256
|
||||
|
||||
#define NL_ALIGN(len) (((len)+3) & ~(3))
|
||||
static const struct sockaddr_nl snl = { .nl_family = AF_NETLINK };
|
||||
static int ipset_sock, old_kernel;
|
||||
static char *buffer;
|
||||
|
||||
static inline void add_attr(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data)
|
||||
{
|
||||
struct nlattr *attr = (void *)nlh + NL_ALIGN(nlh->nlmsg_len);
|
||||
uint16_t payload_len = NL_ALIGN(sizeof(struct nlattr)) + len;
|
||||
attr->nla_type = type;
|
||||
attr->nla_len = payload_len;
|
||||
memcpy((void *)attr + NL_ALIGN(sizeof(struct nlattr)), data, len);
|
||||
nlh->nlmsg_len += NL_ALIGN(payload_len);
|
||||
}
|
||||
|
||||
void ipset_init(void)
|
||||
{
|
||||
struct utsname utsname;
|
||||
int version;
|
||||
char *split;
|
||||
|
||||
if (uname(&utsname) < 0)
|
||||
die(_("failed to find kernel version: %s"), NULL, EC_MISC);
|
||||
|
||||
split = strtok(utsname.release, ".");
|
||||
version = (split ? atoi(split) : 0);
|
||||
split = strtok(NULL, ".");
|
||||
version = version * 256 + (split ? atoi(split) : 0);
|
||||
split = strtok(NULL, ".");
|
||||
version = version * 256 + (split ? atoi(split) : 0);
|
||||
old_kernel = (version < KERNEL_VERSION(2,6,32));
|
||||
|
||||
if (old_kernel && (ipset_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) != -1)
|
||||
return;
|
||||
|
||||
if (!old_kernel &&
|
||||
(buffer = safe_malloc(BUFF_SZ)) &&
|
||||
(ipset_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER)) != -1 &&
|
||||
(bind(ipset_sock, (struct sockaddr *)&snl, sizeof(snl)) != -1))
|
||||
return;
|
||||
|
||||
die (_("failed to create IPset control socket: %s"), NULL, EC_MISC);
|
||||
}
|
||||
|
||||
static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr, int af, int remove)
|
||||
{
|
||||
struct nlmsghdr *nlh;
|
||||
struct nfgenmsg *nfg;
|
||||
struct nlattr *nested[2];
|
||||
uint8_t proto;
|
||||
int addrsz = INADDRSZ;
|
||||
ssize_t rc;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (af == AF_INET6)
|
||||
addrsz = IN6ADDRSZ;
|
||||
#endif
|
||||
|
||||
if (strlen(setname) >= IPSET_MAXNAMELEN)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(buffer, 0, BUFF_SZ);
|
||||
|
||||
nlh = (struct nlmsghdr *)buffer;
|
||||
nlh->nlmsg_len = NL_ALIGN(sizeof(struct nlmsghdr));
|
||||
nlh->nlmsg_type = (remove ? IPSET_CMD_DEL : IPSET_CMD_ADD) | (NFNL_SUBSYS_IPSET << 8);
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST;
|
||||
|
||||
nfg = (struct nfgenmsg *)(buffer + nlh->nlmsg_len);
|
||||
nlh->nlmsg_len += NL_ALIGN(sizeof(struct nfgenmsg));
|
||||
nfg->nfgen_family = af;
|
||||
nfg->version = NFNETLINK_V0;
|
||||
nfg->res_id = htons(0);
|
||||
|
||||
proto = IPSET_PROTOCOL;
|
||||
add_attr(nlh, IPSET_ATTR_PROTOCOL, sizeof(proto), &proto);
|
||||
add_attr(nlh, IPSET_ATTR_SETNAME, strlen(setname) + 1, setname);
|
||||
nested[0] = (struct nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
|
||||
nlh->nlmsg_len += NL_ALIGN(sizeof(struct nlattr));
|
||||
nested[0]->nla_type = NLA_F_NESTED | IPSET_ATTR_DATA;
|
||||
nested[1] = (struct nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
|
||||
nlh->nlmsg_len += NL_ALIGN(sizeof(struct nlattr));
|
||||
nested[1]->nla_type = NLA_F_NESTED | IPSET_ATTR_IP;
|
||||
add_attr(nlh,
|
||||
(af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER,
|
||||
addrsz, &ipaddr->addr);
|
||||
nested[1]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[1];
|
||||
nested[0]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[0];
|
||||
|
||||
while ((rc = sendto(ipset_sock, buffer, nlh->nlmsg_len, 0,
|
||||
(struct sockaddr *)&snl, sizeof(snl))) == -1 && retry_send());
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int old_add_to_ipset(const char *setname, const struct all_addr *ipaddr, int remove)
|
||||
{
|
||||
socklen_t size;
|
||||
struct ip_set_req_adt_get {
|
||||
unsigned op;
|
||||
unsigned version;
|
||||
union {
|
||||
char name[IPSET_MAXNAMELEN];
|
||||
uint16_t index;
|
||||
} set;
|
||||
char typename[IPSET_MAXNAMELEN];
|
||||
} req_adt_get;
|
||||
struct ip_set_req_adt {
|
||||
unsigned op;
|
||||
uint16_t index;
|
||||
uint32_t ip;
|
||||
} req_adt;
|
||||
|
||||
if (strlen(setname) >= sizeof(req_adt_get.set.name))
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
req_adt_get.op = 0x10;
|
||||
req_adt_get.version = 3;
|
||||
strcpy(req_adt_get.set.name, setname);
|
||||
size = sizeof(req_adt_get);
|
||||
if (getsockopt(ipset_sock, SOL_IP, 83, &req_adt_get, &size) < 0)
|
||||
return -1;
|
||||
req_adt.op = remove ? 0x102 : 0x101;
|
||||
req_adt.index = req_adt_get.set.index;
|
||||
req_adt.ip = ntohl(ipaddr->addr.addr4.s_addr);
|
||||
if (setsockopt(ipset_sock, SOL_IP, 83, &req_adt, sizeof(req_adt)) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags, int remove)
|
||||
{
|
||||
int af = AF_INET;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (flags & F_IPV6)
|
||||
{
|
||||
af = AF_INET6;
|
||||
/* old method only supports IPv4 */
|
||||
if (old_kernel)
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return old_kernel ? old_add_to_ipset(setname, ipaddr, remove) : new_add_to_ipset(setname, ipaddr, af, remove);
|
||||
}
|
||||
|
||||
#endif
|
||||
105
src/lease.c
105
src/lease.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
@@ -115,7 +115,7 @@ void lease_init(time_t now)
|
||||
s++;
|
||||
}
|
||||
|
||||
hw_type = atoi(s);
|
||||
hw_type = strtoul(s, NULL, 10);
|
||||
|
||||
if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
|
||||
{
|
||||
@@ -308,7 +308,7 @@ void lease_update_file(time_t now)
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
/* do timed RAs and determine when the next is, also pings to potential SLAAC addresses */
|
||||
if (daemon->ra_contexts)
|
||||
if (daemon->doing_ra)
|
||||
{
|
||||
time_t event;
|
||||
|
||||
@@ -363,12 +363,15 @@ static int find_interface_v4(struct in_addr local, int if_index,
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
static int find_interface_v6(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam)
|
||||
int scope, int if_index, int flags,
|
||||
int preferred, int valid, void *vparam)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
(void)scope;
|
||||
(void)dad;
|
||||
(void)flags;
|
||||
(void)preferred;
|
||||
(void)valid;
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if ((lease->flags & (LEASE_TA | LEASE_NA)))
|
||||
@@ -386,6 +389,18 @@ void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *inte
|
||||
slaac_ping_reply(sender, packet, interface, leases);
|
||||
}
|
||||
|
||||
void lease_update_slaac(time_t now)
|
||||
{
|
||||
/* Called when we contruct a new RA-names context, to add putative
|
||||
new SLAAC addresses to existing leases. */
|
||||
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
if (daemon->dhcp)
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
slaac_add_addrs(lease, now, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -395,10 +410,6 @@ void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *inte
|
||||
start-time. */
|
||||
void lease_find_interfaces(time_t now)
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
build_subnet_map();
|
||||
#endif
|
||||
|
||||
iface_enumerate(AF_INET, &now, find_interface_v4);
|
||||
#ifdef HAVE_DHCP6
|
||||
iface_enumerate(AF_INET6, &now, find_interface_v6);
|
||||
@@ -420,6 +431,11 @@ void lease_update_dns(int force)
|
||||
|
||||
if (daemon->port != 0 && (dns_dirty || force))
|
||||
{
|
||||
#ifndef HAVE_BROKEN_RTC
|
||||
/* force transfer to authoritative secondaries */
|
||||
daemon->soa_sn++;
|
||||
#endif
|
||||
|
||||
cache_unhash_dhcp();
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
@@ -539,8 +555,7 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
/* addr or clid may be NULL for "don't care, both NULL resets "USED" flags both
|
||||
set activates USED check */
|
||||
/* find address for {CLID, IAID, address} */
|
||||
struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
|
||||
int lease_type, int iaid, struct in6_addr *addr)
|
||||
{
|
||||
@@ -551,24 +566,51 @@ struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
|
||||
if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
|
||||
continue;
|
||||
|
||||
if (clid && addr && (lease->flags & LEASE_USED))
|
||||
if (memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0)
|
||||
continue;
|
||||
|
||||
if (addr && memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0)
|
||||
continue;
|
||||
|
||||
if (clid &&
|
||||
(clid_len != lease->clid_len ||
|
||||
if ((clid_len != lease->clid_len ||
|
||||
memcmp(clid, lease->clid, clid_len) != 0))
|
||||
continue;
|
||||
|
||||
if (clid || addr)
|
||||
{
|
||||
lease->flags |= LEASE_USED;
|
||||
return lease;
|
||||
}
|
||||
else
|
||||
lease->flags &= ~LEASE_USED;
|
||||
return lease;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* reset "USED flags */
|
||||
void lease6_reset(void)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
lease->flags &= ~LEASE_USED;
|
||||
}
|
||||
|
||||
/* enumerate all leases belonging to {CLID, IAID} */
|
||||
struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
if (!first)
|
||||
first = leases;
|
||||
else
|
||||
first = first->next;
|
||||
|
||||
for (lease = first; lease; lease = lease->next)
|
||||
{
|
||||
if (lease->flags & LEASE_USED)
|
||||
continue;
|
||||
|
||||
if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
|
||||
continue;
|
||||
|
||||
if ((clid_len != lease->clid_len ||
|
||||
memcmp(clid, lease->clid, clid_len) != 0))
|
||||
continue;
|
||||
|
||||
return lease;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -661,8 +703,11 @@ static struct dhcp_lease *lease_allocate(void)
|
||||
struct dhcp_lease *lease4_allocate(struct in_addr addr)
|
||||
{
|
||||
struct dhcp_lease *lease = lease_allocate();
|
||||
lease->addr = addr;
|
||||
lease->hwaddr_len = 256; /* illegal value */
|
||||
if (lease)
|
||||
{
|
||||
lease->addr = addr;
|
||||
lease->hwaddr_len = 256; /* illegal value */
|
||||
}
|
||||
|
||||
return lease;
|
||||
}
|
||||
@@ -671,8 +716,12 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr)
|
||||
struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
|
||||
{
|
||||
struct dhcp_lease *lease = lease_allocate();
|
||||
memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ;
|
||||
lease->flags |= lease_type;
|
||||
|
||||
if (lease)
|
||||
{
|
||||
memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ;
|
||||
lease->flags |= lease_type;
|
||||
}
|
||||
|
||||
return lease;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
@@ -39,6 +39,7 @@ static struct iovec iov;
|
||||
static u32 netlink_pid;
|
||||
|
||||
static int nl_async(struct nlmsghdr *h);
|
||||
static void nl_newaddress(time_t now);
|
||||
|
||||
void netlink_init(void)
|
||||
{
|
||||
@@ -50,10 +51,14 @@ void netlink_init(void)
|
||||
addr.nl_pid = 0; /* autobind */
|
||||
addr.nl_groups = RTMGRP_IPV4_ROUTE;
|
||||
if (option_bool(OPT_CLEVERBIND))
|
||||
addr.nl_groups |= RTMGRP_IPV4_IFADDR;
|
||||
addr.nl_groups |= RTMGRP_IPV4_IFADDR;
|
||||
#ifdef HAVE_IPV6
|
||||
addr.nl_groups |= RTMGRP_IPV6_ROUTE;
|
||||
if (daemon->ra_contexts || option_bool(OPT_CLEVERBIND))
|
||||
if (option_bool(OPT_CLEVERBIND))
|
||||
addr.nl_groups |= RTMGRP_IPV6_IFADDR;
|
||||
#endif
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->doing_ra || daemon->doing_dhcp6)
|
||||
addr.nl_groups |= RTMGRP_IPV6_IFADDR;
|
||||
#endif
|
||||
|
||||
@@ -187,7 +192,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
|
||||
{
|
||||
/* May be multicast arriving async */
|
||||
if (nl_async(h) && option_bool(OPT_CLEVERBIND))
|
||||
if (nl_async(h))
|
||||
newaddr = 1;
|
||||
}
|
||||
else if (h->nlmsg_type == NLMSG_DONE)
|
||||
@@ -195,11 +200,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
/* handle async new interface address arrivals, these have to be done
|
||||
after we complete as we're not re-entrant */
|
||||
if (newaddr)
|
||||
{
|
||||
enumerate_interfaces();
|
||||
create_bound_listeners(0);
|
||||
}
|
||||
|
||||
nl_newaddress(dnsmasq_time());
|
||||
|
||||
return callback_ok;
|
||||
}
|
||||
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
|
||||
@@ -236,17 +238,32 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
else if (ifa->ifa_family == AF_INET6)
|
||||
{
|
||||
struct in6_addr *addrp = NULL;
|
||||
u32 valid = 0, preferred = 0;
|
||||
int flags = 0;
|
||||
|
||||
while (RTA_OK(rta, len1))
|
||||
{
|
||||
if (rta->rta_type == IFA_ADDRESS)
|
||||
addrp = ((struct in6_addr *)(rta+1));
|
||||
|
||||
else if (rta->rta_type == IFA_CACHEINFO)
|
||||
{
|
||||
struct ifa_cacheinfo *ifc = (struct ifa_cacheinfo *)(rta+1);
|
||||
preferred = ifc->ifa_prefered;
|
||||
valid = ifc->ifa_valid;
|
||||
}
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
}
|
||||
|
||||
if (ifa->ifa_flags & IFA_F_TENTATIVE)
|
||||
flags |= IFACE_TENTATIVE;
|
||||
|
||||
if (ifa->ifa_flags & IFA_F_DEPRECATED)
|
||||
flags |= IFACE_DEPRECATED;
|
||||
|
||||
if (addrp && callback_ok)
|
||||
if (!((*callback)(addrp, (int)(ifa->ifa_prefixlen), (int)(ifa->ifa_scope),
|
||||
(int)(ifa->ifa_index), (int)(ifa->ifa_flags & IFA_F_TENTATIVE), parm)))
|
||||
(int)(ifa->ifa_index), flags,
|
||||
(int) preferred, (int)valid, parm)))
|
||||
callback_ok = 0;
|
||||
}
|
||||
#endif
|
||||
@@ -305,7 +322,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
}
|
||||
}
|
||||
|
||||
void netlink_multicast(void)
|
||||
void netlink_multicast(time_t now)
|
||||
{
|
||||
ssize_t len;
|
||||
struct nlmsghdr *h;
|
||||
@@ -318,17 +335,14 @@ void netlink_multicast(void)
|
||||
|
||||
if ((len = netlink_recv()) != -1)
|
||||
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
|
||||
if (nl_async(h) && option_bool(OPT_CLEVERBIND))
|
||||
if (nl_async(h))
|
||||
newaddr = 1;
|
||||
|
||||
/* restore non-blocking status */
|
||||
fcntl(daemon->netlinkfd, F_SETFL, flags);
|
||||
|
||||
|
||||
if (newaddr)
|
||||
{
|
||||
enumerate_interfaces();
|
||||
create_bound_listeners(0);
|
||||
}
|
||||
nl_newaddress(now);
|
||||
}
|
||||
|
||||
static int nl_async(struct nlmsghdr *h)
|
||||
@@ -336,7 +350,8 @@ static int nl_async(struct nlmsghdr *h)
|
||||
if (h->nlmsg_type == NLMSG_ERROR)
|
||||
{
|
||||
struct nlmsgerr *err = NLMSG_DATA(h);
|
||||
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
|
||||
if (err->error != 0)
|
||||
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
|
||||
return 0;
|
||||
}
|
||||
else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE)
|
||||
@@ -370,25 +385,33 @@ static int nl_async(struct nlmsghdr *h)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (h->nlmsg_type == RTM_NEWADDR)
|
||||
{
|
||||
/* force RAs to sync new network and pick up new interfaces. */
|
||||
if (daemon->ra_contexts)
|
||||
{
|
||||
schedule_subnet_map();
|
||||
ra_start_unsolicted(dnsmasq_time(), NULL);
|
||||
/* cause lease_update_file to run after we return, in case we were called from
|
||||
iface_enumerate and can't re-enter it now */
|
||||
send_alarm(0, 0);
|
||||
}
|
||||
return 1; /* clever bind mode - rescan */
|
||||
}
|
||||
#endif
|
||||
else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
|
||||
return 1; /* clever bind mode - rescan */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nl_newaddress(time_t now)
|
||||
{
|
||||
if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->doing_ra)
|
||||
enumerate_interfaces();
|
||||
|
||||
if (option_bool(OPT_CLEVERBIND))
|
||||
create_bound_listeners(0);
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->doing_dhcp6 || daemon->doing_ra)
|
||||
{
|
||||
join_multicast(0);
|
||||
dhcp_construct_contexts(now);
|
||||
}
|
||||
|
||||
if (daemon->doing_dhcp6)
|
||||
lease_find_interfaces(now);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
301
src/network.c
301
src/network.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
@@ -107,7 +107,7 @@ int indextoname(int fd, int index, char *name)
|
||||
|
||||
#endif
|
||||
|
||||
int iface_check(int family, struct all_addr *addr, char *name)
|
||||
int iface_check(int family, struct all_addr *addr, char *name, int *auth)
|
||||
{
|
||||
struct iname *tmp;
|
||||
int ret = 1;
|
||||
@@ -115,36 +115,95 @@ int iface_check(int family, struct all_addr *addr, char *name)
|
||||
/* Note: have to check all and not bail out early, so that we set the
|
||||
"used" flags. */
|
||||
|
||||
if (auth)
|
||||
*auth = 0;
|
||||
|
||||
if (daemon->if_names || daemon->if_addrs)
|
||||
{
|
||||
ret = 0;
|
||||
|
||||
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
||||
if (tmp->name && wildcard_match(tmp->name, name))
|
||||
ret = tmp->used = 1;
|
||||
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
if (tmp->addr.sa.sa_family == family)
|
||||
{
|
||||
if (family == AF_INET &&
|
||||
tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
|
||||
ret = tmp->used = 1;
|
||||
if (addr)
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
if (tmp->addr.sa.sa_family == family)
|
||||
{
|
||||
if (family == AF_INET &&
|
||||
tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
|
||||
ret = tmp->used = 1;
|
||||
#ifdef HAVE_IPV6
|
||||
else if (family == AF_INET6 &&
|
||||
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr,
|
||||
&addr->addr.addr6))
|
||||
ret = tmp->used = 1;
|
||||
else if (family == AF_INET6 &&
|
||||
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr,
|
||||
&addr->addr.addr6))
|
||||
ret = tmp->used = 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
||||
if (tmp->name && wildcard_match(tmp->name, name))
|
||||
ret = 0;
|
||||
|
||||
|
||||
for (tmp = daemon->authinterface; tmp; tmp = tmp->next)
|
||||
if (tmp->name)
|
||||
{
|
||||
if (strcmp(tmp->name, name) == 0)
|
||||
break;
|
||||
}
|
||||
else if (addr && tmp->addr.sa.sa_family == AF_INET && family == AF_INET &&
|
||||
tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
|
||||
break;
|
||||
#ifdef HAVE_IPV6
|
||||
else if (addr && tmp->addr.sa.sa_family == AF_INET6 && family == AF_INET6 &&
|
||||
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, &addr->addr.addr6))
|
||||
break;
|
||||
#endif
|
||||
|
||||
if (tmp && auth)
|
||||
{
|
||||
*auth = 1;
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Fix for problem that the kernel sometimes reports the loopback inerface as the
|
||||
arrival interface when a packet originates locally, even when sent to address of
|
||||
an interface other than the loopback. Accept packet if it arrived via a loopback
|
||||
interface, even when we're not accepting packets that way, as long as the destination
|
||||
address is one we're believing. Interface list must be up-to-date before calling. */
|
||||
int loopback_exception(int fd, int family, struct all_addr *addr, char *name)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
struct irec *iface;
|
||||
|
||||
strncpy(ifr.ifr_name, name, IF_NAMESIZE);
|
||||
if (ioctl(fd, SIOCGIFFLAGS, &ifr) != -1 &&
|
||||
ifr.ifr_flags & IFF_LOOPBACK)
|
||||
{
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->addr.sa.sa_family == family)
|
||||
{
|
||||
if (family == AF_INET)
|
||||
{
|
||||
if (iface->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
|
||||
return 1;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (IN6_ARE_ADDR_EQUAL(&iface->addr.in6.sin6_addr, &addr->addr.addr6))
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iface_allowed(struct irec **irecp, int if_index,
|
||||
union mysockaddr *addr, struct in_addr netmask, int dad)
|
||||
{
|
||||
@@ -153,6 +212,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
struct ifreq ifr;
|
||||
int tftp_ok = !!option_bool(OPT_TFTP);
|
||||
int dhcp_ok = 1;
|
||||
int auth_dns = 0;
|
||||
#ifdef HAVE_DHCP
|
||||
struct iname *tmp;
|
||||
#endif
|
||||
@@ -198,37 +258,46 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
if (lo->name && strcmp(lo->name, ifr.ifr_name) == 0)
|
||||
break;
|
||||
|
||||
if (!lo &&
|
||||
(lo = whine_malloc(sizeof(struct iname))) &&
|
||||
(lo->name = whine_malloc(strlen(ifr.ifr_name)+1)))
|
||||
if (!lo && (lo = whine_malloc(sizeof(struct iname))))
|
||||
{
|
||||
strcpy(lo->name, ifr.ifr_name);
|
||||
lo->used = 1;
|
||||
lo->next = daemon->if_names;
|
||||
daemon->if_names = lo;
|
||||
if ((lo->name = whine_malloc(strlen(ifr.ifr_name)+1)))
|
||||
{
|
||||
strcpy(lo->name, ifr.ifr_name);
|
||||
lo->used = 1;
|
||||
lo->next = daemon->if_names;
|
||||
daemon->if_names = lo;
|
||||
}
|
||||
else
|
||||
free(lo);
|
||||
}
|
||||
}
|
||||
|
||||
if (addr->sa.sa_family == AF_INET &&
|
||||
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name))
|
||||
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name, &auth_dns))
|
||||
return 1;
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
{
|
||||
tftp_ok = 0;
|
||||
dhcp_ok = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (addr->sa.sa_family == AF_INET6 &&
|
||||
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name))
|
||||
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name, &auth_dns))
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
/* No DHCP where we're doing auth DNS. */
|
||||
if (auth_dns)
|
||||
{
|
||||
tftp_ok = 0;
|
||||
dhcp_ok = 0;
|
||||
}
|
||||
else
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
{
|
||||
tftp_ok = 0;
|
||||
dhcp_ok = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* add to list */
|
||||
if ((iface = whine_malloc(sizeof(struct irec))))
|
||||
{
|
||||
@@ -236,9 +305,11 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
iface->netmask = netmask;
|
||||
iface->tftp_ok = tftp_ok;
|
||||
iface->dhcp_ok = dhcp_ok;
|
||||
iface->dns_auth = auth_dns;
|
||||
iface->mtu = mtu;
|
||||
iface->dad = dad;
|
||||
iface->done = 0;
|
||||
iface->done = iface->multicast_done = 0;
|
||||
iface->index = if_index;
|
||||
if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
|
||||
{
|
||||
strcpy(iface->name, ifr.ifr_name);
|
||||
@@ -247,6 +318,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
return 1;
|
||||
}
|
||||
free(iface);
|
||||
|
||||
}
|
||||
|
||||
errno = ENOMEM;
|
||||
@@ -255,7 +327,8 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
static int iface_allowed_v6(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam)
|
||||
int scope, int if_index, int flags,
|
||||
int preferred, int valid, void *vparam)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
struct in_addr netmask; /* dummy */
|
||||
@@ -263,6 +336,8 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
|
||||
|
||||
(void)prefix; /* warning */
|
||||
(void)scope; /* warning */
|
||||
(void)preferred;
|
||||
(void)valid;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
@@ -273,7 +348,7 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
|
||||
addr.in6.sin6_port = htons(daemon->port);
|
||||
addr.in6.sin6_scope_id = if_index;
|
||||
|
||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, dad);
|
||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, !!(flags & IFACE_TENTATIVE));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -338,13 +413,22 @@ static int make_sock(union mysockaddr *addr, int type, int dienow)
|
||||
sprintf(daemon->addrbuff, "port %d", port);
|
||||
s = _("failed to create listening socket for %s: %s");
|
||||
|
||||
if (dienow)
|
||||
die(s, daemon->addrbuff, EC_BADNET);
|
||||
if (fd != -1)
|
||||
close (fd);
|
||||
|
||||
if (dienow)
|
||||
{
|
||||
/* failure to bind addresses given by --listen-address at this point
|
||||
is OK if we're doing bind-dynamic */
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
die(s, daemon->addrbuff, EC_BADNET);
|
||||
}
|
||||
else
|
||||
my_syslog(LOG_WARNING, s, daemon->addrbuff, strerror(errno));
|
||||
|
||||
my_syslog(LOG_ERR, s, daemon->addrbuff, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || !fix_fd(fd))
|
||||
goto err;
|
||||
|
||||
@@ -411,6 +495,77 @@ int set_ipv6pktinfo(int fd)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Find the interface on which a TCP connection arrived, if possible, or zero otherwise. */
|
||||
int tcp_interface(int fd, int af)
|
||||
{
|
||||
int if_index = 0;
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
int opt = 1;
|
||||
struct cmsghdr *cmptr;
|
||||
struct msghdr msg;
|
||||
|
||||
/* use mshdr do that the CMSDG_* macros are available */
|
||||
msg.msg_control = daemon->packet;
|
||||
msg.msg_controllen = daemon->packet_buff_sz;
|
||||
|
||||
/* we overwrote the buffer... */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
if (af == AF_INET)
|
||||
{
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) != -1 &&
|
||||
getsockopt(fd, IPPROTO_IP, IP_PKTOPTIONS, msg.msg_control, (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;
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
/* Only the RFC-2292 API has the ability to find the interface for TCP connections,
|
||||
it was removed in RFC-3542 !!!!
|
||||
|
||||
Fortunately, Linux kept the 2292 ABI when it moved to 3542. The following code always
|
||||
uses the old ABI, and should work with pre- and post-3542 kernel headers */
|
||||
|
||||
#ifdef IPV6_2292PKTOPTIONS
|
||||
# define PKTOPTIONS IPV6_2292PKTOPTIONS
|
||||
#else
|
||||
# define PKTOPTIONS IPV6_PKTOPTIONS
|
||||
#endif
|
||||
|
||||
if (set_ipv6pktinfo(fd) &&
|
||||
getsockopt(fd, IPPROTO_IPV6, PKTOPTIONS, msg.msg_control, (socklen_t *)&msg.msg_controllen) != -1)
|
||||
{
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in6_pktinfo *p;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
|
||||
if_index = p.p->ipi6_ifindex;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* IPV6 */
|
||||
#endif /* Linux */
|
||||
|
||||
return if_index;
|
||||
}
|
||||
|
||||
static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, int dienow)
|
||||
{
|
||||
@@ -513,7 +668,8 @@ void create_bound_listeners(int dienow)
|
||||
no interface with a matching address. These may be valid: eg it's possible
|
||||
to listen on 127.0.1.1 even if the loopback interface is 127.0.0.1
|
||||
|
||||
If the address isn't valid the bind() will fail and we'll die().
|
||||
If the address isn't valid the bind() will fail and we'll die()
|
||||
(except in bind-dynamic mode, when we'll complain but keep trying.)
|
||||
|
||||
The resulting listeners have the ->iface field NULL, and this has to be
|
||||
handled by the DNS and TFTP code. It disables --localise-queries processing
|
||||
@@ -540,6 +696,61 @@ int is_dad_listeners(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
void join_multicast(int dienow)
|
||||
{
|
||||
struct irec *iface, *tmp;
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->addr.sa.sa_family == AF_INET6 && iface->dhcp_ok && !iface->multicast_done)
|
||||
{
|
||||
/* There's an irec per address but we only want to join for multicast
|
||||
once per interface. Weed out duplicates. */
|
||||
for (tmp = daemon->interfaces; tmp; tmp = tmp->next)
|
||||
if (tmp->multicast_done && tmp->index == iface->index)
|
||||
break;
|
||||
|
||||
iface->multicast_done = 1;
|
||||
|
||||
if (!tmp)
|
||||
{
|
||||
struct ipv6_mreq mreq;
|
||||
int err = 0;
|
||||
|
||||
mreq.ipv6mr_interface = iface->index;
|
||||
|
||||
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
|
||||
|
||||
if (daemon->doing_dhcp6 &&
|
||||
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||
err = 1;
|
||||
|
||||
inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
|
||||
|
||||
if (daemon->doing_dhcp6 &&
|
||||
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||
err = 1;
|
||||
|
||||
inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
|
||||
|
||||
if (daemon->doing_ra &&
|
||||
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||
err = 1;
|
||||
|
||||
if (err)
|
||||
{
|
||||
char *s = _("interface %s failed to join DHCPv6 multicast group: %s");
|
||||
if (dienow)
|
||||
die(s, iface->name, EC_BADNET);
|
||||
else
|
||||
my_syslog(LOG_ERR, s, iface->name, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* return a UDP socket bound to a random port, have to cope with straying into
|
||||
occupied port nos and reserved ones. */
|
||||
int random_sock(int family)
|
||||
|
||||
629
src/option.c
629
src/option.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
@@ -120,6 +120,17 @@ struct myoption {
|
||||
#define LOPT_TFTP_LC 309
|
||||
#define LOPT_RR 310
|
||||
#define LOPT_CLVERBIND 311
|
||||
#define LOPT_MAXCTTL 312
|
||||
#define LOPT_AUTHZONE 313
|
||||
#define LOPT_AUTHSERV 314
|
||||
#define LOPT_AUTHTTL 315
|
||||
#define LOPT_AUTHSOA 316
|
||||
#define LOPT_AUTHSFS 317
|
||||
#define LOPT_AUTHPEER 318
|
||||
#define LOPT_IPSET 319
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
#define LOPT_PREF_CLSS 320
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -184,7 +195,7 @@ static const struct myoption opts[] =
|
||||
{ "localise-queries", 0, 0, 'y' },
|
||||
{ "txt-record", 1, 0, 'Y' },
|
||||
{ "dns-rr", 1, 0, LOPT_RR },
|
||||
{ "enable-dbus", 0, 0, '1' },
|
||||
{ "enable-dbus", 2, 0, '1' },
|
||||
{ "bootp-dynamic", 2, 0, '3' },
|
||||
{ "dhcp-mac", 1, 0, '4' },
|
||||
{ "no-ping", 0, 0, '5' },
|
||||
@@ -223,6 +234,7 @@ static const struct myoption opts[] =
|
||||
{ "dhcp-broadcast", 2, 0, LOPT_BROADCAST },
|
||||
{ "neg-ttl", 1, 0, LOPT_NEGTTL },
|
||||
{ "max-ttl", 1, 0, LOPT_MAXTTL },
|
||||
{ "max-cache-ttl", 1, 0, LOPT_MAXCTTL },
|
||||
{ "dhcp-alternate-port", 2, 0, LOPT_ALTPORT },
|
||||
{ "dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },
|
||||
{ "min-port", 1, 0, LOPT_MINPORT },
|
||||
@@ -245,6 +257,16 @@ static const struct myoption opts[] =
|
||||
{ "dhcp-duid", 1, 0, LOPT_DUID },
|
||||
{ "host-record", 1, 0, LOPT_HOST_REC },
|
||||
{ "bind-dynamic", 0, 0, LOPT_CLVERBIND },
|
||||
{ "auth-zone", 1, 0, LOPT_AUTHZONE },
|
||||
{ "auth-server", 1, 0, LOPT_AUTHSERV },
|
||||
{ "auth-ttl", 1, 0, LOPT_AUTHTTL },
|
||||
{ "auth-soa", 1, 0, LOPT_AUTHSOA },
|
||||
{ "auth-sec-servers", 1, 0, LOPT_AUTHSFS },
|
||||
{ "auth-peer", 1, 0, LOPT_AUTHPEER },
|
||||
{ "ipset", 1, 0, LOPT_IPSET },
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
{ "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
|
||||
#endif
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -326,7 +348,7 @@ static struct {
|
||||
{ LOPT_INTNAME, ARG_DUP, "<name>,<interface>", gettext_noop("Give DNS name to IPv4 address of interface."), NULL },
|
||||
{ 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL },
|
||||
{ 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
|
||||
{ '1', OPT_DBUS, NULL, gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
|
||||
{ '1', ARG_ONE, "[=<busname>]", gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
|
||||
{ '2', ARG_DUP, "<interface>", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
|
||||
{ '3', ARG_DUP, "[=tag:<tag>]...", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
|
||||
{ '4', ARG_DUP, "set:<tag>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
|
||||
@@ -376,7 +398,17 @@ static struct {
|
||||
{ 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_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_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_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 },
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
{ LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
|
||||
#endif
|
||||
{ 0, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -601,6 +633,95 @@ static void do_usage(void)
|
||||
}
|
||||
}
|
||||
|
||||
#define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
|
||||
|
||||
char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags)
|
||||
{
|
||||
int source_port = 0, serv_port = NAMESERVER_PORT;
|
||||
char *portno, *source;
|
||||
#ifdef HAVE_IPV6
|
||||
int scope_index = 0;
|
||||
char *scope_id;
|
||||
#endif
|
||||
|
||||
if ((source = split_chr(arg, '@')) && /* is there a source. */
|
||||
(portno = split_chr(source, '#')) &&
|
||||
!atoi_check16(portno, &source_port))
|
||||
return _("bad port");
|
||||
|
||||
if ((portno = split_chr(arg, '#')) && /* is there a port no. */
|
||||
!atoi_check16(portno, &serv_port))
|
||||
return _("bad port");
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
scope_id = split_chr(arg, '%');
|
||||
#endif
|
||||
|
||||
if ((addr->in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t) -1)
|
||||
{
|
||||
addr->in.sin_port = htons(serv_port);
|
||||
addr->sa.sa_family = source_addr->sa.sa_family = AF_INET;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
source_addr->in.sin_len = addr->in.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
source_addr->in.sin_addr.s_addr = INADDR_ANY;
|
||||
source_addr->in.sin_port = htons(daemon->query_port);
|
||||
|
||||
if (source)
|
||||
{
|
||||
if (flags)
|
||||
*flags |= SERV_HAS_SOURCE;
|
||||
source_addr->in.sin_port = htons(source_port);
|
||||
if ((source_addr->in.sin_addr.s_addr = inet_addr(source)) == (in_addr_t) -1)
|
||||
{
|
||||
#if defined(SO_BINDTODEVICE)
|
||||
source_addr->in.sin_addr.s_addr = INADDR_ANY;
|
||||
strncpy(interface, source, IF_NAMESIZE - 1);
|
||||
#else
|
||||
return _("interface binding not supported");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
|
||||
{
|
||||
if (scope_id && (scope_index = if_nametoindex(scope_id)) == 0)
|
||||
return _("bad interface name");
|
||||
|
||||
addr->in6.sin6_port = htons(serv_port);
|
||||
addr->in6.sin6_scope_id = scope_index;
|
||||
source_addr->in6.sin6_addr = in6addr_any;
|
||||
source_addr->in6.sin6_port = htons(daemon->query_port);
|
||||
source_addr->in6.sin6_scope_id = 0;
|
||||
addr->sa.sa_family = source_addr->sa.sa_family = AF_INET6;
|
||||
addr->in6.sin6_flowinfo = source_addr->in6.sin6_flowinfo = 0;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr->in6.sin6_len = source_addr->in6.sin6_len = sizeof(addr->in6);
|
||||
#endif
|
||||
if (source)
|
||||
{
|
||||
if (flags)
|
||||
*flags |= SERV_HAS_SOURCE;
|
||||
source_addr->in6.sin6_port = htons(source_port);
|
||||
if (inet_pton(AF_INET6, source, &source_addr->in6.sin6_addr) == 0)
|
||||
{
|
||||
#if defined(SO_BINDTODEVICE)
|
||||
source_addr->in6.sin6_addr = in6addr_any;
|
||||
strncpy(interface, source, IF_NAMESIZE - 1);
|
||||
#else
|
||||
return _("interface binding not supported");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
return _("bad address");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
|
||||
static int is_tag_prefix(char *arg)
|
||||
@@ -619,8 +740,6 @@ static char *set_prefix(char *arg)
|
||||
return arg;
|
||||
}
|
||||
|
||||
#define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
|
||||
|
||||
/* This is too insanely large to keep in-line in the switch */
|
||||
static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
{
|
||||
@@ -631,6 +750,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
struct dhcp_netid *np = NULL;
|
||||
u16 opt_len = 0;
|
||||
int is6 = 0;
|
||||
int option_ok = 0;
|
||||
|
||||
new->len = 0;
|
||||
new->flags = flags;
|
||||
@@ -650,14 +770,19 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
{
|
||||
new->opt = atoi(arg);
|
||||
opt_len = 0;
|
||||
option_ok = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strstr(arg, "option:") == arg)
|
||||
{
|
||||
new->opt = lookup_dhcp_opt(AF_INET, arg+7);
|
||||
opt_len = lookup_dhcp_len(AF_INET, new->opt);
|
||||
/* option:<optname> must follow tag and vendor string. */
|
||||
if ((new->opt = lookup_dhcp_opt(AF_INET, arg+7)) != -1)
|
||||
{
|
||||
opt_len = lookup_dhcp_len(AF_INET, new->opt);
|
||||
/* option:<optname> must follow tag and vendor string. */
|
||||
if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
|
||||
option_ok = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifdef HAVE_DHCP6
|
||||
@@ -671,11 +796,16 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
{
|
||||
new->opt = atoi(arg+8);
|
||||
opt_len = 0;
|
||||
option_ok = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
new->opt = lookup_dhcp_opt(AF_INET6, arg+8);
|
||||
opt_len = lookup_dhcp_len(AF_INET6, new->opt);
|
||||
if ((new->opt = lookup_dhcp_opt(AF_INET6, arg+8)) != -1)
|
||||
{
|
||||
opt_len = lookup_dhcp_len(AF_INET6, new->opt);
|
||||
if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
|
||||
option_ok = 1;
|
||||
}
|
||||
}
|
||||
/* option6:<opt>|<optname> must follow tag and vendor string. */
|
||||
is6 = 1;
|
||||
@@ -698,7 +828,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
new->flags |= DHOPT_RFC3925;
|
||||
if (flags == DHOPT_MATCH)
|
||||
{
|
||||
new->opt = 1; /* avoid error below */
|
||||
option_ok = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -725,16 +855,16 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
|
||||
if (opt_len == 0 &&
|
||||
!(new->flags & DHOPT_RFC3925))
|
||||
opt_len = lookup_dhcp_len(AF_INET6 ,new->opt);
|
||||
opt_len = lookup_dhcp_len(AF_INET6, new->opt);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (opt_len == 0 &&
|
||||
!(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925)))
|
||||
opt_len = lookup_dhcp_len(AF_INET ,new->opt);
|
||||
opt_len = lookup_dhcp_len(AF_INET, new->opt);
|
||||
|
||||
/* option may be missing with rfc3925 match */
|
||||
if (new->opt == 0)
|
||||
if (!option_ok)
|
||||
ret_err(_("bad dhcp-option"));
|
||||
|
||||
if (comma)
|
||||
@@ -764,7 +894,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
}
|
||||
else if (c == '.')
|
||||
{
|
||||
is_addr6 =is_dec = is_hex = 0;
|
||||
is_addr6 = is_dec = is_hex = 0;
|
||||
dots++;
|
||||
}
|
||||
else if (c == '-')
|
||||
@@ -811,8 +941,40 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
/* or names */
|
||||
else if (opt_len & (OT_NAME | OT_RFC1035_NAME | OT_CSTRING))
|
||||
is_addr6 = is_addr = is_dec = is_hex = 0;
|
||||
|
||||
if (is_hex && digs > 1)
|
||||
|
||||
if (found_dig && (opt_len & OT_TIME) && strlen(comma) > 0)
|
||||
{
|
||||
int val, fac = 1;
|
||||
|
||||
switch (comma[strlen(comma) - 1])
|
||||
{
|
||||
case 'w':
|
||||
case 'W':
|
||||
fac *= 7;
|
||||
/* fall through */
|
||||
case 'd':
|
||||
case 'D':
|
||||
fac *= 24;
|
||||
/* fall though */
|
||||
case 'h':
|
||||
case 'H':
|
||||
fac *= 60;
|
||||
/* fall through */
|
||||
case 'm':
|
||||
case 'M':
|
||||
fac *= 60;
|
||||
/* fall through */
|
||||
case 's':
|
||||
case 'S':
|
||||
comma[strlen(comma) - 1] = 0;
|
||||
}
|
||||
|
||||
new->len = 4;
|
||||
new->val = opt_malloc(4);
|
||||
val = atoi(comma);
|
||||
*((int *)new->val) = htonl(val * fac);
|
||||
}
|
||||
else if (is_hex && digs > 1)
|
||||
{
|
||||
new->len = digs;
|
||||
new->val = opt_malloc(new->len);
|
||||
@@ -1230,14 +1392,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
strcat(path, "/");
|
||||
strcat(path, ent->d_name);
|
||||
|
||||
/* files must be readable */
|
||||
if (stat(path, &buf) == -1)
|
||||
die(_("cannot access %s: %s"), path, EC_FILE);
|
||||
/* only reg files allowed. */
|
||||
if (!S_ISREG(buf.st_mode))
|
||||
continue;
|
||||
|
||||
/* files must be readable */
|
||||
one_file(path, 0);
|
||||
/* only reg files allowed. */
|
||||
if (S_ISREG(buf.st_mode))
|
||||
one_file(path, 0);
|
||||
|
||||
free(path);
|
||||
}
|
||||
|
||||
@@ -1253,6 +1415,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
break;
|
||||
}
|
||||
|
||||
case '1': /* --enable-dbus */
|
||||
set_option_bool(OPT_DBUS);
|
||||
if (arg)
|
||||
daemon->dbus_name = opt_string_alloc(arg);
|
||||
else
|
||||
daemon->dbus_name = DNSMASQ_SERVICE;
|
||||
break;
|
||||
|
||||
case '8': /* --log-facility */
|
||||
/* may be a filename */
|
||||
if (strchr(arg, '/') || strcmp (arg, "-") == 0)
|
||||
@@ -1384,7 +1554,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->next = daemon->dhcp_hosts_file;
|
||||
daemon->dhcp_hosts_file = new;
|
||||
}
|
||||
else if (option == LOPT_DHCP_OPTS)
|
||||
else if (option == LOPT_DHCP_OPTS)
|
||||
{
|
||||
new->next = daemon->dhcp_opts_file;
|
||||
daemon->dhcp_opts_file = new;
|
||||
@@ -1392,6 +1562,131 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
break;
|
||||
}
|
||||
|
||||
case LOPT_AUTHSERV: /* --auth-server */
|
||||
if (!(comma = split(arg)))
|
||||
ret_err(gen_err);
|
||||
|
||||
daemon->authserver = opt_string_alloc(arg);
|
||||
arg = comma;
|
||||
do {
|
||||
struct iname *new = opt_malloc(sizeof(struct iname));
|
||||
comma = split(arg);
|
||||
new->name = NULL;
|
||||
unhide_metas(arg);
|
||||
if ((new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
|
||||
new->addr.sa.sa_family = AF_INET;
|
||||
#ifdef HAVE_IPV6
|
||||
else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
|
||||
new->addr.sa.sa_family = AF_INET6;
|
||||
#endif
|
||||
else
|
||||
new->name = opt_string_alloc(arg);
|
||||
|
||||
new->next = daemon->authinterface;
|
||||
daemon->authinterface = new;
|
||||
|
||||
arg = comma;
|
||||
} while (arg);
|
||||
|
||||
break;
|
||||
|
||||
case LOPT_AUTHSFS: /* --auth-sec-servers */
|
||||
{
|
||||
struct name_list *new;
|
||||
|
||||
do {
|
||||
comma = split(arg);
|
||||
new = opt_malloc(sizeof(struct name_list));
|
||||
new->name = opt_string_alloc(arg);
|
||||
new->next = daemon->secondary_forward_server;
|
||||
daemon->secondary_forward_server = new;
|
||||
arg = comma;
|
||||
} while (arg);
|
||||
break;
|
||||
}
|
||||
|
||||
case LOPT_AUTHZONE: /* --auth-zone */
|
||||
{
|
||||
struct auth_zone *new;
|
||||
|
||||
comma = split(arg);
|
||||
|
||||
new = opt_malloc(sizeof(struct auth_zone));
|
||||
new->domain = opt_string_alloc(arg);
|
||||
new->subnet = NULL;
|
||||
new->next = daemon->auth_zones;
|
||||
daemon->auth_zones = new;
|
||||
|
||||
while ((arg = comma))
|
||||
{
|
||||
int prefixlen = 0;
|
||||
char *prefix;
|
||||
struct subnet *subnet = opt_malloc(sizeof(struct subnet));
|
||||
|
||||
subnet->next = new->subnet;
|
||||
new->subnet = subnet;
|
||||
|
||||
comma = split(arg);
|
||||
prefix = split_chr(arg, '/');
|
||||
|
||||
if (prefix && !atoi_check(prefix, &prefixlen))
|
||||
ret_err(gen_err);
|
||||
|
||||
if (inet_pton(AF_INET, arg, &subnet->addr4))
|
||||
{
|
||||
if ((prefixlen & 0x07) != 0 || prefixlen > 24)
|
||||
ret_err(_("bad prefix"));
|
||||
subnet->prefixlen = (prefixlen == 0) ? 24 : prefixlen;
|
||||
subnet->is6 = 0;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (inet_pton(AF_INET6, arg, &subnet->addr6))
|
||||
{
|
||||
subnet->prefixlen = (prefixlen == 0) ? 64 : prefixlen;
|
||||
subnet->is6 = 1;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
ret_err(gen_err);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case LOPT_AUTHSOA: /* --auth-soa */
|
||||
comma = split(arg);
|
||||
atoi_check(arg, (int *)&daemon->soa_sn);
|
||||
if (comma)
|
||||
{
|
||||
char *cp;
|
||||
arg = comma;
|
||||
comma = split(arg);
|
||||
daemon->hostmaster = opt_string_alloc(arg);
|
||||
for (cp = daemon->hostmaster; *cp; cp++)
|
||||
if (*cp == '@')
|
||||
*cp = '.';
|
||||
|
||||
if (comma)
|
||||
{
|
||||
arg = comma;
|
||||
comma = split(arg);
|
||||
atoi_check(arg, (int *)&daemon->soa_refresh);
|
||||
if (comma)
|
||||
{
|
||||
arg = comma;
|
||||
comma = split(arg);
|
||||
atoi_check(arg, (int *)&daemon->soa_retry);
|
||||
if (comma)
|
||||
{
|
||||
arg = comma;
|
||||
comma = split(arg);
|
||||
atoi_check(arg, (int *)&daemon->soa_expiry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 's': /* --domain */
|
||||
if (strcmp (arg, "#") == 0)
|
||||
set_option_bool(OPT_RESOLV_DOMAIN);
|
||||
@@ -1405,7 +1700,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
if (comma)
|
||||
{
|
||||
struct cond_domain *new = safe_malloc(sizeof(struct cond_domain));
|
||||
struct cond_domain *new = opt_malloc(sizeof(struct cond_domain));
|
||||
char *netpart;
|
||||
|
||||
unhide_metas(comma);
|
||||
@@ -1619,14 +1914,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
|
||||
case 'a': /* --listen-address */
|
||||
case LOPT_AUTHPEER: /* --auth-peer */
|
||||
do {
|
||||
struct iname *new = opt_malloc(sizeof(struct iname));
|
||||
comma = split(arg);
|
||||
unhide_metas(arg);
|
||||
new->next = daemon->if_addrs;
|
||||
if (arg && (new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
|
||||
{
|
||||
new->addr.sa.sa_family = AF_INET;
|
||||
new->addr.in.sin_port = 0;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
new->addr.in.sin_len = sizeof(new->addr.in);
|
||||
#endif
|
||||
@@ -1637,6 +1933,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->addr.sa.sa_family = AF_INET6;
|
||||
new->addr.in6.sin6_flowinfo = 0;
|
||||
new->addr.in6.sin6_scope_id = 0;
|
||||
new->addr.in6.sin6_port = 0;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
new->addr.in6.sin6_len = sizeof(new->addr.in6);
|
||||
#endif
|
||||
@@ -1646,7 +1943,16 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
ret_err(gen_err);
|
||||
|
||||
new->used = 0;
|
||||
daemon->if_addrs = new;
|
||||
if (option == 'a')
|
||||
{
|
||||
new->next = daemon->if_addrs;
|
||||
daemon->if_addrs = new;
|
||||
}
|
||||
else
|
||||
{
|
||||
new->next = daemon->auth_peers;
|
||||
daemon->auth_peers = new;
|
||||
}
|
||||
arg = comma;
|
||||
} while (arg);
|
||||
break;
|
||||
@@ -1720,84 +2026,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
else
|
||||
{
|
||||
int source_port = 0, serv_port = NAMESERVER_PORT;
|
||||
char *portno, *source;
|
||||
#ifdef HAVE_IPV6
|
||||
int scope_index = 0;
|
||||
char *scope_id;
|
||||
#endif
|
||||
|
||||
if ((source = split_chr(arg, '@')) && /* is there a source. */
|
||||
(portno = split_chr(source, '#')) &&
|
||||
!atoi_check16(portno, &source_port))
|
||||
ret_err(_("bad port"));
|
||||
|
||||
if ((portno = split_chr(arg, '#')) && /* is there a port no. */
|
||||
!atoi_check16(portno, &serv_port))
|
||||
ret_err(_("bad port"));
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
scope_id = split_chr(arg, '%');
|
||||
#endif
|
||||
|
||||
if ((newlist->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t) -1)
|
||||
{
|
||||
newlist->addr.in.sin_port = htons(serv_port);
|
||||
newlist->source_addr.in.sin_port = htons(source_port);
|
||||
newlist->addr.sa.sa_family = newlist->source_addr.sa.sa_family = AF_INET;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
newlist->source_addr.in.sin_len = newlist->addr.in.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
if (source)
|
||||
{
|
||||
newlist->flags |= SERV_HAS_SOURCE;
|
||||
if ((newlist->source_addr.in.sin_addr.s_addr = inet_addr(source)) == (in_addr_t) -1)
|
||||
{
|
||||
#if defined(SO_BINDTODEVICE)
|
||||
newlist->source_addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
strncpy(newlist->interface, source, IF_NAMESIZE - 1);
|
||||
#else
|
||||
ret_err(_("interface binding not supported"));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
newlist->source_addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (inet_pton(AF_INET6, arg, &newlist->addr.in6.sin6_addr) > 0)
|
||||
{
|
||||
if (scope_id && (scope_index = if_nametoindex(scope_id)) == 0)
|
||||
ret_err(_("bad interface name"));
|
||||
|
||||
newlist->addr.in6.sin6_port = htons(serv_port);
|
||||
newlist->addr.in6.sin6_scope_id = scope_index;
|
||||
newlist->source_addr.in6.sin6_port = htons(source_port);
|
||||
newlist->source_addr.in6.sin6_scope_id = 0;
|
||||
newlist->addr.sa.sa_family = newlist->source_addr.sa.sa_family = AF_INET6;
|
||||
newlist->addr.in6.sin6_flowinfo = newlist->source_addr.in6.sin6_flowinfo = 0;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
newlist->addr.in6.sin6_len = newlist->source_addr.in6.sin6_len = sizeof(newlist->addr.in6);
|
||||
#endif
|
||||
if (source)
|
||||
{
|
||||
newlist->flags |= SERV_HAS_SOURCE;
|
||||
if (inet_pton(AF_INET6, source, &newlist->source_addr.in6.sin6_addr) == 0)
|
||||
{
|
||||
#if defined(SO_BINDTODEVICE)
|
||||
newlist->source_addr.in6.sin6_addr = in6addr_any;
|
||||
strncpy(newlist->interface, source, IF_NAMESIZE - 1);
|
||||
#else
|
||||
ret_err(_("interface binding not supported"));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
newlist->source_addr.in6.sin6_addr = in6addr_any;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
ret_err(gen_err);
|
||||
char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
|
||||
if (err)
|
||||
ret_err(err);
|
||||
}
|
||||
|
||||
serv = newlist;
|
||||
@@ -1806,12 +2037,81 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
serv->next->flags = serv->flags;
|
||||
serv->next->addr = serv->addr;
|
||||
serv->next->source_addr = serv->source_addr;
|
||||
strcpy(serv->next->interface, serv->interface);
|
||||
serv = serv->next;
|
||||
}
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = newlist;
|
||||
break;
|
||||
}
|
||||
|
||||
case LOPT_IPSET: /* --ipset */
|
||||
#ifndef HAVE_IPSET
|
||||
ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives"));
|
||||
break;
|
||||
#else
|
||||
{
|
||||
struct ipsets ipsets_head;
|
||||
struct ipsets *ipsets = &ipsets_head;
|
||||
int size;
|
||||
char *end;
|
||||
char **sets, **sets_pos;
|
||||
memset(ipsets, 0, sizeof(struct ipsets));
|
||||
unhide_metas(arg);
|
||||
if (arg && *arg == '/')
|
||||
{
|
||||
arg++;
|
||||
while ((end = split_chr(arg, '/')))
|
||||
{
|
||||
char *domain = NULL;
|
||||
/* elide leading dots - they are implied in the search algorithm */
|
||||
while (*arg == '.')
|
||||
arg++;
|
||||
/* # matches everything and becomes a zero length domain string */
|
||||
if (strcmp(arg, "#") == 0 || !*arg)
|
||||
domain = "";
|
||||
else if (strlen(arg) != 0 && !(domain = canonicalise_opt(arg)))
|
||||
option = '?';
|
||||
ipsets->next = opt_malloc(sizeof(struct ipsets));
|
||||
ipsets = ipsets->next;
|
||||
memset(ipsets, 0, sizeof(struct ipsets));
|
||||
ipsets->domain = domain;
|
||||
arg = end;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ipsets->next = opt_malloc(sizeof(struct ipsets));
|
||||
ipsets = ipsets->next;
|
||||
memset(ipsets, 0, sizeof(struct ipsets));
|
||||
ipsets->domain = "";
|
||||
}
|
||||
if (!arg || !*arg)
|
||||
{
|
||||
option = '?';
|
||||
break;
|
||||
}
|
||||
size = 2;
|
||||
for (end = arg; *end; ++end)
|
||||
if (*end == ',')
|
||||
++size;
|
||||
|
||||
sets = sets_pos = opt_malloc(sizeof(char *) * size);
|
||||
|
||||
do {
|
||||
end = split(arg);
|
||||
*sets_pos++ = opt_string_alloc(arg);
|
||||
arg = end;
|
||||
} while (end);
|
||||
*sets_pos = 0;
|
||||
for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next)
|
||||
ipsets->next->sets = sets;
|
||||
ipsets->next = daemon->ipsets;
|
||||
daemon->ipsets = ipsets_head.next;
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case 'c': /* --cache-size */
|
||||
{
|
||||
@@ -1877,6 +2177,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
case 'T': /* --local-ttl */
|
||||
case LOPT_NEGTTL: /* --neg-ttl */
|
||||
case LOPT_MAXTTL: /* --max-ttl */
|
||||
case LOPT_MAXCTTL: /* --max-cache-ttl */
|
||||
case LOPT_AUTHTTL: /* --auth-ttl */
|
||||
{
|
||||
int ttl;
|
||||
if (!atoi_check(arg, &ttl))
|
||||
@@ -1885,6 +2187,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
daemon->neg_ttl = (unsigned long)ttl;
|
||||
else if (option == LOPT_MAXTTL)
|
||||
daemon->max_ttl = (unsigned long)ttl;
|
||||
else if (option == LOPT_MAXCTTL)
|
||||
daemon->max_cache_ttl = (unsigned long)ttl;
|
||||
else if (option == LOPT_AUTHTTL)
|
||||
daemon->auth_ttl = (unsigned long)ttl;
|
||||
else
|
||||
daemon->local_ttl = (unsigned long)ttl;
|
||||
break;
|
||||
@@ -1963,7 +2269,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
case 'F': /* --dhcp-range */
|
||||
{
|
||||
int k, leasepos = 2;
|
||||
char *cp, *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
|
||||
char *cp, *a[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
|
||||
struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
|
||||
|
||||
memset (new, 0, sizeof(*new));
|
||||
@@ -2010,7 +2316,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
}
|
||||
|
||||
for (k = 1; k < 7; k++)
|
||||
for (k = 1; k < 8; k++)
|
||||
if (!(a[k] = split(a[k-1])))
|
||||
break;
|
||||
|
||||
@@ -2057,34 +2363,35 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
new->prefix = 64; /* default */
|
||||
new->end6 = new->start6;
|
||||
|
||||
|
||||
/* dhcp-range=:: enables DHCP stateless on any interface */
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&new->start6))
|
||||
new->prefix = 0;
|
||||
|
||||
for (leasepos = 1; leasepos < k; leasepos++)
|
||||
{
|
||||
if (strcmp(a[leasepos], "static") == 0)
|
||||
new->flags |= CONTEXT_STATIC | CONTEXT_DHCP;
|
||||
else if (strcmp(a[leasepos], "ra-only") == 0 || strcmp(a[leasepos], "slaac") == 0 )
|
||||
new->flags |= CONTEXT_RA_ONLY;
|
||||
new->flags |= CONTEXT_RA_ONLY | CONTEXT_RA;
|
||||
else if (strcmp(a[leasepos], "ra-names") == 0)
|
||||
new->flags |= CONTEXT_RA_NAME;
|
||||
new->flags |= CONTEXT_RA_NAME | CONTEXT_RA;
|
||||
else if (strcmp(a[leasepos], "ra-stateless") == 0)
|
||||
new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP;
|
||||
new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP | CONTEXT_RA;
|
||||
else if (leasepos == 1 && inet_pton(AF_INET6, a[leasepos], &new->end6))
|
||||
new->flags |= CONTEXT_DHCP;
|
||||
else if (strstr(a[leasepos], "constructor:") == a[leasepos])
|
||||
{
|
||||
new->template_interface = opt_string_alloc(a[leasepos] + 12);
|
||||
new->flags |= CONTEXT_TEMPLATE;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (new->flags & CONTEXT_DHCP)
|
||||
{
|
||||
new->next = daemon->dhcp6;
|
||||
daemon->dhcp6 = new;
|
||||
}
|
||||
else
|
||||
{
|
||||
new->next = daemon->ra_contexts;
|
||||
daemon->ra_contexts = new;
|
||||
}
|
||||
|
||||
new->next = daemon->dhcp6;
|
||||
daemon->dhcp6 = new;
|
||||
|
||||
/* bare integer < 128 is prefix value */
|
||||
if (leasepos < k)
|
||||
{
|
||||
@@ -2096,10 +2403,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
new->prefix = pref;
|
||||
leasepos++;
|
||||
if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)) &&
|
||||
new->prefix != 64)
|
||||
ret_err(_("prefix must be exactly 64 for RA subnets"));
|
||||
else if (new->prefix < 64)
|
||||
if (new->prefix != 64)
|
||||
{
|
||||
if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
|
||||
ret_err(_("prefix must be exactly 64 for RA subnets"));
|
||||
else if (new->template_interface)
|
||||
ret_err(_("prefix must be exactly 64 for subnet constructors"));
|
||||
}
|
||||
if (new->prefix < 64)
|
||||
ret_err(_("prefix must be at least 64"));
|
||||
}
|
||||
}
|
||||
@@ -2114,6 +2425,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
ret_err(_("bad dhcp-range"));
|
||||
|
||||
if (leasepos < k)
|
||||
{
|
||||
@@ -2128,6 +2441,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
switch (a[leasepos][strlen(a[leasepos]) - 1])
|
||||
{
|
||||
case 'w':
|
||||
case 'W':
|
||||
fac *= 7;
|
||||
/* fall through */
|
||||
case 'd':
|
||||
case 'D':
|
||||
fac *= 24;
|
||||
@@ -2145,6 +2462,13 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
a[leasepos][strlen(a[leasepos]) - 1] = 0;
|
||||
}
|
||||
|
||||
for (cp = a[leasepos]; *cp; cp++)
|
||||
if (!(*cp >= '0' && *cp <= '9'))
|
||||
break;
|
||||
|
||||
if (*cp || (leasepos+1 < k))
|
||||
ret_err(_("bad dhcp-range"));
|
||||
|
||||
new->lease_time = atoi(a[leasepos]) * fac;
|
||||
/* Leases of a minute or less confuse
|
||||
some clients, notably Apple's */
|
||||
@@ -2232,6 +2556,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
if (!inet_pton(AF_INET6, arg, &new->addr6))
|
||||
ret_err(_("bad IPv6 address"));
|
||||
|
||||
for (i= 0; i < 8; i++)
|
||||
if (new->addr6.s6_addr[i] != 0)
|
||||
break;
|
||||
|
||||
/* set WILDCARD if network part all zeros */
|
||||
if (i == 8)
|
||||
new->flags |= CONFIG_WILDCARD;
|
||||
|
||||
new->flags |= CONFIG_ADDR6;
|
||||
}
|
||||
@@ -2278,6 +2610,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
last = *lastp;
|
||||
switch (last)
|
||||
{
|
||||
case 'w':
|
||||
case 'W':
|
||||
fac *= 7;
|
||||
/* fall through */
|
||||
case 'd':
|
||||
case 'D':
|
||||
fac *= 24;
|
||||
@@ -2388,6 +2724,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
else
|
||||
{
|
||||
new->set = NULL;
|
||||
free(newtag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2619,7 +2956,25 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
case LOPT_PREF_CLSS: /* --dhcp-prefix-class */
|
||||
{
|
||||
struct prefix_class *new = opt_malloc(sizeof(struct prefix_class));
|
||||
|
||||
if (!(comma = split(arg)) ||
|
||||
!atoi_check16(comma, &new->class))
|
||||
ret_err(gen_err);
|
||||
|
||||
new->tag.net = opt_string_alloc(set_prefix(arg));
|
||||
new->next = daemon->prefix_classes;
|
||||
daemon->prefix_classes = new;
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
case 'U': /* --dhcp-vendorclass */
|
||||
case 'j': /* --dhcp-userclass */
|
||||
case LOPT_CIRCUIT: /* --dhcp-circuitid */
|
||||
@@ -3098,10 +3453,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
for (tmp = new->names; tmp->next; tmp = tmp->next);
|
||||
tmp->next = nl;
|
||||
}
|
||||
|
||||
arg = comma;
|
||||
comma = split(arg);
|
||||
}
|
||||
|
||||
arg = comma;
|
||||
comma = split(arg);
|
||||
}
|
||||
|
||||
/* Keep list order */
|
||||
@@ -3543,6 +3898,10 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
daemon->tftp_max = TFTP_MAX_CONNECTIONS;
|
||||
daemon->edns_pktsz = EDNS_PKTSZ;
|
||||
daemon->log_fac = -1;
|
||||
daemon->auth_ttl = AUTH_TTL;
|
||||
daemon->soa_refresh = SOA_REFRESH;
|
||||
daemon->soa_retry = SOA_RETRY;
|
||||
daemon->soa_expiry = SOA_EXPIRY;
|
||||
add_txt("version.bind", "dnsmasq-" VERSION );
|
||||
add_txt("authors.bind", "Simon Kelley");
|
||||
add_txt("copyright.bind", COPYRIGHT);
|
||||
@@ -3650,7 +4009,15 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
tmp->addr.in6.sin6_port = htons(daemon->port);
|
||||
#endif /* IPv6 */
|
||||
}
|
||||
|
||||
|
||||
/* create default, if not specified */
|
||||
if (daemon->authserver && !daemon->hostmaster)
|
||||
{
|
||||
strcpy(buff, "hostmaster.");
|
||||
strcat(buff, daemon->authserver);
|
||||
daemon->hostmaster = opt_string_alloc(buff);
|
||||
}
|
||||
|
||||
/* only one of these need be specified: the other defaults to the host-name */
|
||||
if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
|
||||
221
src/radv.c
221
src/radv.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
@@ -27,25 +27,28 @@
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
struct ra_param {
|
||||
time_t now;
|
||||
int ind, managed, other, found_context, first;
|
||||
char *if_name;
|
||||
struct dhcp_netid *tags;
|
||||
struct in6_addr link_local;
|
||||
struct in6_addr link_local, link_global;
|
||||
unsigned int pref_time;
|
||||
};
|
||||
|
||||
struct search_param {
|
||||
time_t now; int iface;
|
||||
};
|
||||
|
||||
static void send_ra(int iface, char *iface_name, struct in6_addr *dest);
|
||||
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
|
||||
static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam);
|
||||
int scope, int if_index, int flags,
|
||||
unsigned int preferred, unsigned int valid, void *vparam);
|
||||
static int iface_search(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam);
|
||||
int scope, int if_index, int flags,
|
||||
int prefered, int valid, void *vparam);
|
||||
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
|
||||
|
||||
static int hop_limit;
|
||||
static time_t ra_short_period_start;
|
||||
|
||||
void ra_init(time_t now)
|
||||
{
|
||||
@@ -62,7 +65,7 @@ void ra_init(time_t now)
|
||||
expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
|
||||
|
||||
/* See if we're guessing SLAAC addresses, if so we need to recieve ping replies */
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_RA_NAME))
|
||||
break;
|
||||
|
||||
@@ -94,18 +97,20 @@ void ra_start_unsolicted(time_t now, struct dhcp_context *context)
|
||||
if it's not appropriate to advertise those contexts.
|
||||
This gets re-called on a netlink route-change to re-do the advertisement
|
||||
and pick up new interfaces */
|
||||
|
||||
|
||||
if (context)
|
||||
context->ra_time = now;
|
||||
context->ra_short_period_start = context->ra_time = now;
|
||||
else
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
|
||||
|
||||
/* re-do frequently for a minute or so, in case the first gets lost. */
|
||||
ra_short_period_start = now;
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (!(context->flags & CONTEXT_TEMPLATE))
|
||||
{
|
||||
context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
|
||||
/* re-do frequently for a minute or so, in case the first gets lost. */
|
||||
context->ra_short_period_start = now;
|
||||
}
|
||||
}
|
||||
|
||||
void icmp6_packet(void)
|
||||
void icmp6_packet(time_t now)
|
||||
{
|
||||
char interface[IF_NAMESIZE+1];
|
||||
ssize_t sz;
|
||||
@@ -149,11 +154,11 @@ void icmp6_packet(void)
|
||||
if (!indextoname(daemon->icmp6fd, if_index, interface))
|
||||
return;
|
||||
|
||||
if (!iface_check(AF_LOCAL, NULL, interface))
|
||||
if (!iface_check(AF_LOCAL, NULL, interface, NULL))
|
||||
return;
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, interface) == 0))
|
||||
if (tmp->name && wildcard_match(tmp->name, interface))
|
||||
return;
|
||||
|
||||
if (packet[1] != 0)
|
||||
@@ -174,11 +179,11 @@ void icmp6_packet(void)
|
||||
|
||||
my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
|
||||
/* source address may not be valid in solicit request. */
|
||||
send_ra(if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
|
||||
send_ra(now, if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
||||
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
|
||||
{
|
||||
struct ra_packet *ra;
|
||||
struct ra_param parm;
|
||||
@@ -188,7 +193,10 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
||||
struct dhcp_netid iface_id;
|
||||
struct dhcp_opt *opt_cfg;
|
||||
int done_dns = 0;
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
FILE *f;
|
||||
#endif
|
||||
|
||||
save_counter(0);
|
||||
ra = expand(sizeof(struct ra_packet));
|
||||
|
||||
@@ -196,7 +204,7 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
||||
ra->code = 0;
|
||||
ra->hop_limit = hop_limit;
|
||||
ra->flags = 0x00;
|
||||
ra->lifetime = htons(1800); /* AdvDefaultLifetime*/
|
||||
ra->lifetime = htons(RA_INTERVAL * 3); /* AdvDefaultLifetime * 3 */
|
||||
ra->reachable_time = 0;
|
||||
ra->retrans_time = 0;
|
||||
|
||||
@@ -206,13 +214,15 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
||||
parm.found_context = 0;
|
||||
parm.if_name = iface_name;
|
||||
parm.first = 1;
|
||||
|
||||
parm.now = now;
|
||||
parm.pref_time = 0;
|
||||
|
||||
/* set tag with name == interface */
|
||||
iface_id.net = iface_name;
|
||||
iface_id.next = NULL;
|
||||
parm.tags = &iface_id;
|
||||
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
{
|
||||
context->flags &= ~CONTEXT_RA_DONE;
|
||||
context->netid.next = &context->netid;
|
||||
@@ -223,14 +233,23 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
||||
return;
|
||||
|
||||
strncpy(ifr.ifr_name, iface_name, IF_NAMESIZE);
|
||||
|
||||
if (ioctl(daemon->icmp6fd, SIOCGIFMTU, &ifr) != -1)
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* Note that IPv6 MTU is not necessarilly 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")))
|
||||
{
|
||||
put_opt6_char(ICMP6_OPT_MTU);
|
||||
put_opt6_char(1);
|
||||
put_opt6_short(0);
|
||||
put_opt6_long(ifr.ifr_mtu);
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
iface_enumerate(AF_LOCAL, &iface, add_lla);
|
||||
|
||||
@@ -256,11 +275,11 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
||||
put_opt6_char(ICMP6_OPT_RDNSS);
|
||||
put_opt6_char((opt_cfg->len/8) + 1);
|
||||
put_opt6_short(0);
|
||||
put_opt6_long(1800); /* lifetime - twice RA retransmit */
|
||||
put_opt6_long(RA_INTERVAL * 2); /* lifetime - twice RA retransmit */
|
||||
/* zero means "self" */
|
||||
for (i = 0; i < opt_cfg->len; i += IN6ADDRSZ, a++)
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(a))
|
||||
put_opt6(&parm.link_local, IN6ADDRSZ);
|
||||
put_opt6(&parm.link_global, IN6ADDRSZ);
|
||||
else
|
||||
put_opt6(a, IN6ADDRSZ);
|
||||
}
|
||||
@@ -287,8 +306,8 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
||||
put_opt6_char(ICMP6_OPT_RDNSS);
|
||||
put_opt6_char(3);
|
||||
put_opt6_short(0);
|
||||
put_opt6_long(1800); /* lifetime - twice RA retransmit */
|
||||
put_opt6(&parm.link_local, IN6ADDRSZ);
|
||||
put_opt6_long(RA_INTERVAL * 2); /* lifetime - twice RA retransmit */
|
||||
put_opt6(&parm.link_global, IN6ADDRSZ);
|
||||
}
|
||||
|
||||
/* set managed bits unless we're providing only RA on this link */
|
||||
@@ -320,29 +339,30 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
||||
}
|
||||
|
||||
static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam)
|
||||
int scope, int if_index, int flags,
|
||||
unsigned int preferred, unsigned int valid, void *vparam)
|
||||
{
|
||||
struct ra_param *param = vparam;
|
||||
|
||||
(void)scope; /* warning */
|
||||
(void)dad;
|
||||
|
||||
|
||||
if (if_index == param->ind)
|
||||
{
|
||||
if (IN6_IS_ADDR_LINKLOCAL(local))
|
||||
param->link_local = *local;
|
||||
else if (!IN6_IS_ADDR_LOOPBACK(local) &&
|
||||
!IN6_IS_ADDR_LINKLOCAL(local) &&
|
||||
!IN6_IS_ADDR_MULTICAST(local))
|
||||
{
|
||||
int do_prefix = 0;
|
||||
int do_slaac = 0;
|
||||
int deprecate = 0;
|
||||
int constructed = 0;
|
||||
unsigned int time = 0xffffffff;
|
||||
struct dhcp_context *context;
|
||||
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
if (prefix == context->prefix &&
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (!(context->flags & CONTEXT_TEMPLATE) &&
|
||||
prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
{
|
||||
@@ -365,13 +385,21 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
param->managed = 1;
|
||||
param->other = 1;
|
||||
}
|
||||
|
||||
/* find floor time */
|
||||
if (time > context->lease_time)
|
||||
time = context->lease_time;
|
||||
|
||||
/* find floor time, don't reduce below RA interval. */
|
||||
if (time > context->lease_time)
|
||||
{
|
||||
time = context->lease_time;
|
||||
if (time < ((unsigned int)RA_INTERVAL))
|
||||
time = RA_INTERVAL;
|
||||
}
|
||||
|
||||
if (context->flags & CONTEXT_DEPRECATE)
|
||||
deprecate = 1;
|
||||
|
||||
if (context->flags & CONTEXT_CONSTRUCTED)
|
||||
constructed = 1;
|
||||
|
||||
|
||||
/* collect dhcp-range tags */
|
||||
if (context->netid.next == &context->netid && context->netid.net)
|
||||
@@ -395,6 +423,26 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
param->first = 0;
|
||||
param->found_context = 1;
|
||||
}
|
||||
|
||||
/* configured time is ceiling */
|
||||
if (!constructed || valid > time)
|
||||
valid = time;
|
||||
|
||||
if (flags & IFACE_DEPRECATED)
|
||||
preferred = 0;
|
||||
|
||||
if (deprecate)
|
||||
time = 0;
|
||||
|
||||
/* configured time is ceiling */
|
||||
if (!constructed || preferred > time)
|
||||
preferred = time;
|
||||
|
||||
if (preferred > param->pref_time)
|
||||
{
|
||||
param->pref_time = preferred;
|
||||
param->link_global = *local;
|
||||
}
|
||||
|
||||
if (do_prefix)
|
||||
{
|
||||
@@ -405,17 +453,13 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
/* zero net part of address */
|
||||
setaddr6part(local, addr6part(local) & ~((prefix == 64) ? (u64)-1LL : (1LLU << (128 - prefix)) - 1LLU));
|
||||
|
||||
/* lifetimes must be min 2 hrs, by RFC 2462 */
|
||||
if (time < 7200)
|
||||
time = 7200;
|
||||
|
||||
opt->type = ICMP6_OPT_PREFIX;
|
||||
opt->len = 4;
|
||||
opt->prefix_len = prefix;
|
||||
/* autonomous only if we're not doing dhcp */
|
||||
opt->flags = do_slaac ? 0x40 : 0x00;
|
||||
opt->valid_lifetime = htonl(time);
|
||||
opt->preferred_lifetime = htonl(deprecate ? 0 : time);
|
||||
/* autonomous only if we're not doing dhcp, always set "on-link" */
|
||||
opt->flags = do_slaac ? 0xC0 : 0x80;
|
||||
opt->valid_lifetime = htonl(valid);
|
||||
opt->preferred_lifetime = htonl(preferred);
|
||||
opt->reserved = 0;
|
||||
opt->prefix = *local;
|
||||
|
||||
@@ -457,11 +501,12 @@ time_t periodic_ra(time_t now)
|
||||
char interface[IF_NAMESIZE+1];
|
||||
|
||||
param.now = now;
|
||||
param.iface = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* find overdue events, and time of first future event */
|
||||
for (next_event = 0, context = daemon->ra_contexts; context; context = context->next)
|
||||
for (next_event = 0, context = daemon->dhcp6; context; context = context->next)
|
||||
if (context->ra_time != 0)
|
||||
{
|
||||
if (difftime(context->ra_time, now) <= 0.0)
|
||||
@@ -482,42 +527,64 @@ time_t periodic_ra(time_t now)
|
||||
ever be able to send ra's and satistfy it. */
|
||||
if (iface_enumerate(AF_INET6, ¶m, iface_search))
|
||||
context->ra_time = 0;
|
||||
else if (indextoname(daemon->icmp6fd, param.iface, interface))
|
||||
send_ra(param.iface, interface, NULL);
|
||||
}
|
||||
|
||||
else if (param.iface != 0 &&
|
||||
indextoname(daemon->icmp6fd, param.iface, interface) &&
|
||||
iface_check(AF_LOCAL, NULL, interface, NULL))
|
||||
{
|
||||
struct iname *tmp;
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, interface))
|
||||
break;
|
||||
if (!tmp)
|
||||
send_ra(now, param.iface, interface, NULL);
|
||||
}
|
||||
}
|
||||
return next_event;
|
||||
}
|
||||
|
||||
|
||||
static int iface_search(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam)
|
||||
int scope, int if_index, int flags,
|
||||
int preferred, int valid, void *vparam)
|
||||
{
|
||||
struct search_param *param = vparam;
|
||||
struct dhcp_context *context;
|
||||
|
||||
(void)scope;
|
||||
(void)dad;
|
||||
(void)preferred;
|
||||
(void)valid;
|
||||
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
if (prefix == context->prefix &&
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (!(context->flags & CONTEXT_TEMPLATE) &&
|
||||
prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
if (context->ra_time != 0 && difftime(context->ra_time, param->now) <= 0.0)
|
||||
{
|
||||
/* found an interface that's overdue for RA determine new
|
||||
timeout value and zap other contexts on the same interface
|
||||
so they don't timeout independently .*/
|
||||
is_same_net6(local, &context->end6, prefix) &&
|
||||
context->ra_time != 0 &&
|
||||
difftime(context->ra_time, param->now) <= 0.0)
|
||||
{
|
||||
/* found an interface that's overdue for RA determine new
|
||||
timeout value and arrange for RA to be sent unless interface is
|
||||
still doing DAD.*/
|
||||
|
||||
if (!(flags & IFACE_TENTATIVE))
|
||||
param->iface = if_index;
|
||||
|
||||
if (difftime(param->now, ra_short_period_start) < 60.0)
|
||||
/* range 5 - 20 */
|
||||
context->ra_time = param->now + 5 + (rand16()/4400);
|
||||
else
|
||||
/* range 450 - 600 */
|
||||
context->ra_time = param->now + 450 + (rand16()/440);
|
||||
|
||||
return 0; /* found, abort */
|
||||
}
|
||||
|
||||
if (difftime(param->now, context->ra_short_period_start) < 60.0)
|
||||
/* range 5 - 20 */
|
||||
context->ra_time = param->now + 5 + (rand16()/4400);
|
||||
else
|
||||
/* range 3/4 - 1 times RA_INTERVAL */
|
||||
context->ra_time = param->now + (3 * RA_INTERVAL)/4 + ((RA_INTERVAL * (unsigned int)rand16()) >> 18);
|
||||
|
||||
/* zero timers for other contexts on the same subnet, so they don't timeout
|
||||
independently */
|
||||
for (context = context->next; context; context = context->next)
|
||||
if (prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
context->ra_time = 0;
|
||||
|
||||
return 0; /* found, abort */
|
||||
}
|
||||
|
||||
return 1; /* keep searching */
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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,10 +16,6 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
static int add_resource_record(struct dns_header *header, char *limit, int *truncp,
|
||||
unsigned int nameoffset, unsigned char **pp,
|
||||
unsigned long ttl, unsigned int *offset, unsigned short type,
|
||||
unsigned short class, char *format, ...);
|
||||
|
||||
#define CHECK_LEN(header, pp, plen, len) \
|
||||
((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))
|
||||
@@ -27,8 +23,8 @@ static int add_resource_record(struct dns_header *header, char *limit, int *trun
|
||||
#define ADD_RDLEN(header, pp, plen, len) \
|
||||
(!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))
|
||||
|
||||
static int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
char *name, int isExtract, int extrabytes)
|
||||
int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
char *name, int isExtract, int extrabytes)
|
||||
{
|
||||
unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
|
||||
unsigned int j, l, hops = 0;
|
||||
@@ -173,7 +169,7 @@ static int extract_name(struct dns_header *header, size_t plen, unsigned char **
|
||||
|
||||
/* Max size of input string (for IPv6) is 75 chars.) */
|
||||
#define MAXARPANAME 75
|
||||
static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
|
||||
int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
|
||||
{
|
||||
int j;
|
||||
char name[MAXARPANAME+1], *cp1;
|
||||
@@ -333,7 +329,7 @@ static unsigned char *skip_name(unsigned char *ansp, struct dns_header *header,
|
||||
return ansp;
|
||||
}
|
||||
|
||||
static unsigned char *skip_questions(struct dns_header *header, size_t plen)
|
||||
unsigned char *skip_questions(struct dns_header *header, size_t plen)
|
||||
{
|
||||
int q;
|
||||
unsigned char *ansp = (unsigned char *)(header+1);
|
||||
@@ -781,13 +777,18 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name)
|
||||
expired and cleaned out that way.
|
||||
Return 1 if we reject an address because it look like part of dns-rebinding attack. */
|
||||
int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
|
||||
int is_sign, int check_rebind, int checking_disabled)
|
||||
char **ipsets, int is_sign, int check_rebind, int checking_disabled)
|
||||
{
|
||||
unsigned char *p, *p1, *endrr, *namep;
|
||||
int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
|
||||
unsigned long ttl = 0;
|
||||
struct all_addr addr;
|
||||
|
||||
#ifdef HAVE_IPSET
|
||||
char **ipsets_cur;
|
||||
#else
|
||||
(void)ipsets; /* unused */
|
||||
#endif
|
||||
|
||||
cache_start_insert();
|
||||
|
||||
/* find_soa is needed for dns_doctor and logging side-effects, so don't call it lazily if there are any. */
|
||||
@@ -970,6 +971,15 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
(flags & F_IPV4) &&
|
||||
private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
|
||||
return 1;
|
||||
|
||||
#ifdef HAVE_IPSET
|
||||
if (ipsets && (flags & (F_IPV4 | F_IPV6)))
|
||||
{
|
||||
ipsets_cur = ipsets;
|
||||
while (*ipsets_cur)
|
||||
add_to_ipset(*ipsets_cur++, &addr, flags, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD);
|
||||
if (newc && cpp)
|
||||
@@ -1189,8 +1199,8 @@ int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_resource_record(struct dns_header *header, char *limit, int *truncp, unsigned int nameoffset, unsigned char **pp,
|
||||
unsigned long ttl, unsigned int *offset, unsigned short type, unsigned short class, char *format, ...)
|
||||
int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
|
||||
unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
unsigned char *sav, *p = *pp;
|
||||
@@ -1201,8 +1211,26 @@ static int add_resource_record(struct dns_header *header, char *limit, int *trun
|
||||
|
||||
if (truncp && *truncp)
|
||||
return 0;
|
||||
|
||||
va_start(ap, format); /* make ap point to 1st unamed argument */
|
||||
|
||||
if (nameoffset > 0)
|
||||
{
|
||||
PUTSHORT(nameoffset | 0xc000, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *name = va_arg(ap, char *);
|
||||
if (name)
|
||||
p = do_rfc1035_name(p, name);
|
||||
if (nameoffset < 0)
|
||||
{
|
||||
PUTSHORT(-nameoffset | 0xc000, p);
|
||||
}
|
||||
else
|
||||
*p++ = 0;
|
||||
}
|
||||
|
||||
PUTSHORT(nameoffset | 0xc000, p);
|
||||
PUTSHORT(type, p);
|
||||
PUTSHORT(class, p);
|
||||
PUTLONG(ttl, p); /* TTL */
|
||||
@@ -1210,8 +1238,6 @@ static int add_resource_record(struct dns_header *header, char *limit, int *trun
|
||||
sav = p; /* Save pointer to RDLength field */
|
||||
PUTSHORT(0, p); /* Placeholder RDLength */
|
||||
|
||||
va_start(ap, format); /* make ap point to 1st unamed argument */
|
||||
|
||||
for (; *format; format++)
|
||||
switch (*format)
|
||||
{
|
||||
@@ -1307,7 +1333,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
unsigned char *p, *ansp, *pheader;
|
||||
int qtype, qclass;
|
||||
struct all_addr addr;
|
||||
unsigned int nameoffset;
|
||||
int nameoffset;
|
||||
unsigned short flag;
|
||||
int q, ans, anscount = 0, addncount = 0;
|
||||
int dryrun = 0, sec_reqd = 0;
|
||||
@@ -1689,7 +1715,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
ans = found = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
unsigned int offset;
|
||||
int offset;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
|
||||
&offset, T_MX, C_IN, "sd", rec->weight, rec->target))
|
||||
@@ -1727,7 +1753,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
found = ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
unsigned int offset;
|
||||
int offset;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
|
||||
&offset, T_SRV, C_IN, "sssd",
|
||||
@@ -1857,7 +1883,3 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
return ansp - (unsigned char *)header;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
@@ -493,8 +493,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
lease_set_interface(lease, int_index, now);
|
||||
|
||||
clear_packet(mess, end);
|
||||
match_vendor_opts(NULL, daemon->dhcp_opts); /* clear flags */
|
||||
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
|
||||
netid, subnet_addr, 0, 0, 0, NULL, 0, now);
|
||||
netid, subnet_addr, 0, 0, -1, NULL, 0, now);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,11 +516,22 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
op += 3;
|
||||
pp = op;
|
||||
|
||||
/* Always force update, since the client has no way to do it itself. */
|
||||
if (!option_bool(OPT_FQDN_UPDATE) && !(fqdn_flags & 0x01))
|
||||
fqdn_flags |= 0x03;
|
||||
|
||||
fqdn_flags &= ~0x08;
|
||||
/* NB, the following always sets at least one bit */
|
||||
if (option_bool(OPT_FQDN_UPDATE))
|
||||
{
|
||||
if (fqdn_flags & 0x01)
|
||||
{
|
||||
fqdn_flags |= 0x02; /* set O */
|
||||
fqdn_flags &= ~0x01; /* clear S */
|
||||
}
|
||||
fqdn_flags |= 0x08; /* set N */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(fqdn_flags & 0x01))
|
||||
fqdn_flags |= 0x03; /* set S and O */
|
||||
fqdn_flags &= ~0x08; /* clear N */
|
||||
}
|
||||
|
||||
if (fqdn_flags & 0x04)
|
||||
while (*op != 0 && ((op + (*op) + 1) - pp) < len)
|
||||
@@ -1244,7 +1256,20 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
add_extradata_opt(lease, oui);
|
||||
add_extradata_opt(lease, serial);
|
||||
add_extradata_opt(lease, class);
|
||||
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
|
||||
{
|
||||
add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_CIRCUIT_ID, 1));
|
||||
add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBSCR_ID, 1));
|
||||
add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_REMOTE_ID, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
add_extradata_opt(lease, NULL);
|
||||
add_extradata_opt(lease, NULL);
|
||||
add_extradata_opt(lease, NULL);
|
||||
}
|
||||
|
||||
/* space-concat tag set */
|
||||
if (!tagif_netid)
|
||||
add_extradata_opt(lease, NULL);
|
||||
@@ -1375,6 +1400,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
if (lease)
|
||||
{
|
||||
lease_set_interface(lease, int_index, now);
|
||||
if (override.s_addr != 0)
|
||||
lease->override = override;
|
||||
else
|
||||
@@ -1385,16 +1411,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
|
||||
|
||||
if (lease)
|
||||
{
|
||||
if (lease->expires == 0)
|
||||
time = 0xffffffff;
|
||||
else
|
||||
time = (unsigned int)difftime(lease->expires, now);
|
||||
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
|
||||
lease_set_interface(lease, int_index, now);
|
||||
}
|
||||
|
||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||
|
||||
@@ -1736,7 +1752,7 @@ static unsigned char *free_space(struct dhcp_packet *mess, unsigned char *end, i
|
||||
if (overload[2] & 2)
|
||||
{
|
||||
p = dhcp_skip_opts(mess->sname);
|
||||
if (p + len + 3 >= mess->sname + sizeof(mess->file))
|
||||
if (p + len + 3 >= mess->sname + sizeof(mess->sname))
|
||||
p = NULL;
|
||||
}
|
||||
}
|
||||
@@ -2231,7 +2247,8 @@ static void do_options(struct dhcp_context *context,
|
||||
!option_find2(OPTION_ROUTER))
|
||||
option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
|
||||
|
||||
if (in_list(req_options, OPTION_DNSSERVER) &&
|
||||
if (daemon->port == NAMESERVER_PORT &&
|
||||
in_list(req_options, OPTION_DNSSERVER) &&
|
||||
!option_find2(OPTION_DNSSERVER))
|
||||
option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
|
||||
}
|
||||
@@ -2261,7 +2278,7 @@ static void do_options(struct dhcp_context *context,
|
||||
|
||||
if ((p = free_space(mess, end, OPTION_CLIENT_FQDN, len)))
|
||||
{
|
||||
*(p++) = fqdn_flags;
|
||||
*(p++) = fqdn_flags & 0x0f; /* MBZ bits to zero */
|
||||
*(p++) = 255;
|
||||
*(p++) = 255;
|
||||
|
||||
|
||||
1505
src/rfc3315.c
1505
src/rfc3315.c
File diff suppressed because it is too large
Load Diff
60
src/slaac.c
60
src/slaac.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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,6 @@
|
||||
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
static int map_rebuild = 0;
|
||||
static int ping_id = 0;
|
||||
|
||||
void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
|
||||
@@ -38,7 +37,7 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
|
||||
old = lease->slaac_address;
|
||||
lease->slaac_address = NULL;
|
||||
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_RA_NAME) && lease->last_interface == context->if_index)
|
||||
{
|
||||
struct in6_addr addr = context->start6;
|
||||
@@ -123,7 +122,7 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
|
||||
struct slaac_address *slaac;
|
||||
time_t next_event = 0;
|
||||
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_RA_NAME))
|
||||
break;
|
||||
|
||||
@@ -134,12 +133,6 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
|
||||
while (ping_id == 0)
|
||||
ping_id = rand16();
|
||||
|
||||
if (map_rebuild)
|
||||
{
|
||||
map_rebuild = 0;
|
||||
build_subnet_map();
|
||||
}
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
|
||||
{
|
||||
@@ -211,51 +204,4 @@ void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *inte
|
||||
lease_update_dns(gotone);
|
||||
}
|
||||
|
||||
/* Build a map from ra-names subnets to corresponding interfaces. This
|
||||
is used to go from DHCPv4 leases to SLAAC addresses,
|
||||
interface->IPv6-subnet, IPv6-subnet + MAC address -> SLAAC.
|
||||
*/
|
||||
static int add_subnet(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
|
||||
(void)scope;
|
||||
(void)dad;
|
||||
(void)vparam;
|
||||
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_RA_NAME) &&
|
||||
prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
{
|
||||
context->if_index = if_index;
|
||||
context->local6 = *local;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void build_subnet_map(void)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
int ok = 0;
|
||||
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
{
|
||||
context->if_index = 0;
|
||||
if ((context->flags & CONTEXT_RA_NAME))
|
||||
ok = 1;
|
||||
}
|
||||
|
||||
/* ra-names configured */
|
||||
if (ok)
|
||||
iface_enumerate(AF_INET6, NULL, add_subnet);
|
||||
}
|
||||
|
||||
void schedule_subnet_map(void)
|
||||
{
|
||||
map_rebuild = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
20
src/tftp.c
20
src/tftp.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
@@ -61,6 +61,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
char *name = NULL;
|
||||
char *prefix = daemon->tftp_prefix;
|
||||
struct tftp_prefix *pref;
|
||||
struct all_addr addra;
|
||||
|
||||
union {
|
||||
struct cmsghdr align; /* this ensures alignment */
|
||||
@@ -113,7 +114,6 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
else
|
||||
{
|
||||
struct cmsghdr *cmptr;
|
||||
int check;
|
||||
|
||||
if (msg.msg_controllen < sizeof(struct cmsghdr))
|
||||
return;
|
||||
@@ -190,18 +190,26 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
return;
|
||||
|
||||
name = namebuff;
|
||||
|
||||
addra.addr.addr4 = addr.in.sin_addr;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (listen->family == AF_INET6)
|
||||
check = iface_check(AF_INET6, (struct all_addr *)&addr.in6.sin6_addr, name);
|
||||
else
|
||||
addra.addr.addr6 = addr.in6.sin6_addr;
|
||||
#endif
|
||||
check = iface_check(AF_INET, (struct all_addr *)&addr.in.sin_addr, name);
|
||||
|
||||
if (!iface_check(listen->family, &addra, name, NULL))
|
||||
{
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces();
|
||||
if (!loopback_exception(listen->tftpfd, listen->family, &addra, name))
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
/* allowed interfaces are the same as for DHCP */
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
||||
if (tmp->name && wildcard_match(tmp->name, name))
|
||||
return;
|
||||
#endif
|
||||
|
||||
|
||||
21
src/util.c
21
src/util.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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
|
||||
@@ -280,7 +280,7 @@ int sa_len(union mysockaddr *addr)
|
||||
}
|
||||
|
||||
/* don't use strcasecmp and friends here - they may be messed up by LOCALE */
|
||||
int hostname_isequal(char *a, char *b)
|
||||
int hostname_isequal(const char *a, const char *b)
|
||||
{
|
||||
unsigned int c1, c2;
|
||||
|
||||
@@ -581,3 +581,20 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Basically match a string value against a wildcard pattern. */
|
||||
int wildcard_match(const char* wildcard, const char* match)
|
||||
{
|
||||
while (*wildcard && *match)
|
||||
{
|
||||
if (*wildcard == '*')
|
||||
return 1;
|
||||
|
||||
if (*wildcard != *match)
|
||||
return 0;
|
||||
|
||||
++wildcard;
|
||||
++match;
|
||||
}
|
||||
|
||||
return *wildcard == *match;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user