mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-06 15:51:41 +00:00
Compare commits
136
Commits
v2.56
...
v2.61test10
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a813111379 | ||
|
|
18f0fb050b | ||
|
|
05e92e5afe | ||
|
|
4723d49dad | ||
|
|
fbbc14541a | ||
|
|
5ef33279f2 | ||
|
|
1e02a85970 | ||
|
|
0e88d53faa | ||
|
|
01d1b8ddf2 | ||
|
|
c8257540bc | ||
|
|
2240704863 | ||
|
|
e8ca69ea16 | ||
|
|
da632e7cc1 | ||
|
|
30cd96663f | ||
|
|
7dbe98147d | ||
|
|
5d71d83420 | ||
|
|
38a59a9ff7 | ||
|
|
4b028ad612 | ||
|
|
442560beb4 | ||
|
|
7d2b5c9583 | ||
|
|
29689cfa5a | ||
|
|
52d4abf2f9 | ||
|
|
a953096485 | ||
|
|
884a6dfe6d | ||
|
|
0068301d24 | ||
|
|
353ae4d270 | ||
|
|
e759d426fa | ||
|
|
40ef23b547 | ||
|
|
f5e8562f96 | ||
|
|
1567feae3c | ||
|
|
daf061c9de | ||
|
|
d0e2c6c9ab | ||
|
|
8643ec7fea | ||
|
|
5cfea3d402 | ||
|
|
6c8f21e4a4 | ||
|
|
1d0f91c4a9 | ||
|
|
2a82db4caf | ||
|
|
dd88c17f15 | ||
|
|
8b37270410 | ||
|
|
760169fc43 | ||
|
|
7023e38294 | ||
|
|
a7cf58cc47 | ||
|
|
e25d1a2ea2 | ||
|
|
70969c1757 | ||
|
|
3803437dcc | ||
|
|
eabc6dd76a | ||
|
|
e28d2e2b77 | ||
|
|
96fafe2ed6 | ||
|
|
c81d390f84 | ||
|
|
08456c61f6 | ||
|
|
bc26f9a03f | ||
|
|
6ffeff86be | ||
|
|
f444cddbaf | ||
|
|
d13191a46c | ||
|
|
801ca9a7b7 | ||
|
|
df66e341de | ||
|
|
71ee7ee254 | ||
|
|
a156cae901 | ||
|
|
22b135a116 | ||
|
|
0f08983d85 | ||
|
|
e3e86343fc | ||
|
|
7b6dd880f7 | ||
|
|
b7f4020133 | ||
|
|
c46c7c7584 | ||
|
|
552af8b988 | ||
|
|
4f8ff361dc | ||
|
|
0010b47439 | ||
|
|
4b86b65d07 | ||
|
|
248489401a | ||
|
|
bc5992daf6 | ||
|
|
fdacfb0119 | ||
|
|
0d5d35d052 | ||
|
|
843c96b4b3 | ||
|
|
58dc02ebf2 | ||
|
|
c239f7de25 | ||
|
|
ac8540c3c5 | ||
|
|
22d904db95 | ||
|
|
741c2952d4 | ||
|
|
96f6979c4f | ||
|
|
c5379c1ab6 | ||
|
|
a4a5205fd7 | ||
|
|
c5ad4e7998 | ||
|
|
270dc2e199 | ||
|
|
948a0b6e81 | ||
|
|
87b8ecb13a | ||
|
|
e44ddcac63 | ||
|
|
00e9ad5217 | ||
|
|
96c3879bed | ||
|
|
57f460de2f | ||
|
|
6caacacf6d | ||
|
|
60ac5af682 | ||
|
|
caa94380ac | ||
|
|
0793380b40 | ||
|
|
1adadf585d | ||
|
|
e5ffdb9c77 | ||
|
|
6da5201092 | ||
|
|
b36ae19434 | ||
|
|
2307eac613 | ||
|
|
127ea40ae7 | ||
|
|
6aef600d48 | ||
|
|
98d76a0326 | ||
|
|
6ea6dcf05b | ||
|
|
627797800d | ||
|
|
c6cc03ed0c | ||
|
|
3d7b550f52 | ||
|
|
751d6f4ae6 | ||
|
|
a5c72ab51d | ||
|
|
9bbc88762b | ||
|
|
ceae00dddf | ||
|
|
3634c54e8d | ||
|
|
d74942a03d | ||
|
|
70c5e3e076 | ||
|
|
4cb1b32009 | ||
|
|
3268e90f5e | ||
|
|
e98170816a | ||
|
|
52b92f4db8 | ||
|
|
a2761754da | ||
|
|
805a11345c | ||
|
|
1ab62aec37 | ||
|
|
915363f976 | ||
|
|
205fafa577 | ||
|
|
be2daf4ad5 | ||
|
|
8ecfaa4adf | ||
|
|
03bfcf6462 | ||
|
|
39bec5ff32 | ||
|
|
246839d64a | ||
|
|
3862deb398 | ||
|
|
5954608577 | ||
|
|
984d2fded6 | ||
|
|
a4f04ed45a | ||
|
|
07736e8dcb | ||
|
|
00fc082d68 | ||
|
|
c72daea868 | ||
|
|
74c95c2542 | ||
|
|
7de060b08d | ||
|
|
572b41eb50 |
No files matched your search
@@ -0,0 +1,3 @@
|
|||||||
|
ifneq ($(TARGET_SIMULATOR),true)
|
||||||
|
include $(call all-subdir-makefiles)
|
||||||
|
endif
|
||||||
@@ -1,3 +1,298 @@
|
|||||||
|
version 2.61
|
||||||
|
Re-write interface discovery code on *BSD to use
|
||||||
|
getifaddrs. This is more portable, more straightforward,
|
||||||
|
and allows us to find the prefix length for IPv6
|
||||||
|
addresses.
|
||||||
|
|
||||||
|
Add ra-names, ra-stateless and slaac keywords for DHCPv6.
|
||||||
|
Dnsmasq can now synthesise AAAA records for dual-stack
|
||||||
|
hosts which get IPv6 addresses via SLAAC. It is also now
|
||||||
|
possible to use SLAAC and stateless DHCPv6, and to
|
||||||
|
tell clients to use SLAAC addresses as well as DHCP ones.
|
||||||
|
Thanks to Dave Taht for help with this.
|
||||||
|
|
||||||
|
Add --dhcp-duid to allow DUID-EN uids to be used.
|
||||||
|
|
||||||
|
Explicity send DHCPv6 replies to the correct port, instead
|
||||||
|
of relying on clients to send requests with the correct
|
||||||
|
source address, since at least one client in the wild gets
|
||||||
|
this wrong. Thanks to Conrda Kostecki for help tracking
|
||||||
|
this down.
|
||||||
|
|
||||||
|
Send a preference value of 255 in DHCPv6 replies when
|
||||||
|
--dhcp-authoritative is in effect. This tells clients not
|
||||||
|
to wait around for other DHCP servers.
|
||||||
|
|
||||||
|
Better logging of DHCPv6 options.
|
||||||
|
|
||||||
|
Add --host-record. Thanks to Rob Zwissler for the
|
||||||
|
suggestion.
|
||||||
|
|
||||||
|
Invoke the DHCP script with action "tftp" when a TFTP file
|
||||||
|
transfer completes. The size of the file, address to which
|
||||||
|
it was sent and complete pathname are supplied. Note that
|
||||||
|
version 2.60 introduced some script incompatibilties
|
||||||
|
associated with DHCPv6, and this is a further change. To
|
||||||
|
be safe, scripts should ignore unknown actions, and if
|
||||||
|
not IPv6-aware, should exit if the environment
|
||||||
|
variable DNSMASQ_IAID is set. The use-case for this is
|
||||||
|
to track netboot/install. Suggestion from Shantanu
|
||||||
|
Gadgil.
|
||||||
|
|
||||||
|
Update contrib/port-forward/dnsmasq-portforward to reflect
|
||||||
|
the above.
|
||||||
|
|
||||||
|
Set the environment variable DNSMASQ_LOG_DHCP when running
|
||||||
|
the script id --log-dhcp is in effect, so that script can
|
||||||
|
taylor their logging verbosity. Suggestion from Malte
|
||||||
|
Forkel.
|
||||||
|
|
||||||
|
Arrange that addresses specified with --listen-address
|
||||||
|
work even if there is no interface carrying the
|
||||||
|
address. This is chiefly useful for IPv4 loopback
|
||||||
|
addresses, where any address in 127.0.0.0/8 is a valid
|
||||||
|
loopback address, but normally only 127.0.0.1 appears on
|
||||||
|
the lo interface. Thanks to Mathieu Trudel-Lapierre for
|
||||||
|
the idea and initial patch.
|
||||||
|
|
||||||
|
Fix crash, introduced in 2.60, when a DHCPINFORM is
|
||||||
|
received from a network which has no valid dhcp-range.
|
||||||
|
Thanks to Stephane Glondu for the bug report.
|
||||||
|
|
||||||
|
Add a new DHCP lease time keyword, "deprecated" for
|
||||||
|
--dhcp-range. This is only valid for IPv6, and sets the
|
||||||
|
preffered lease time for both DHCP and RA to zero. The
|
||||||
|
effect is that clients can continue to use the address
|
||||||
|
for existing connections, but new connections will use
|
||||||
|
other addresses, if they exist. This makes hitless
|
||||||
|
renumbering at least possible.
|
||||||
|
|
||||||
|
Fix bug in address6_available() which caused DHCPv6 lease
|
||||||
|
aquistion to fail of more than one dhcp-range in use.
|
||||||
|
|
||||||
|
Provide RDNSS and DNSSL data in router advertisements,
|
||||||
|
using the settings provided for DHCP options
|
||||||
|
option6:domain-search and option6:dns-server.
|
||||||
|
|
||||||
|
|
||||||
|
version 2.60
|
||||||
|
Fix compilation problem in Mac OS X Lion. Thanks to Olaf
|
||||||
|
Flebbe for the patch.
|
||||||
|
|
||||||
|
Fix DHCP when using --listen-address with an IP address
|
||||||
|
which is not the primary address of an interface.
|
||||||
|
|
||||||
|
Add --dhcp-client-update option.
|
||||||
|
|
||||||
|
Add Lua integration. Dnsmasq can now execute a DHCP
|
||||||
|
lease-change script written in Lua. This needs to be
|
||||||
|
enabled at compile time by setting HAVE_LUASCRIPT in
|
||||||
|
src/config.h or running "make COPTS=-DHAVE_LUASCRIPT"
|
||||||
|
Thanks to Jan-Piet Mens for the idea and proof-of-concept
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
Tidied src/config.h to distinguish between
|
||||||
|
platform-dependent compile-time options which are selected
|
||||||
|
automatically, and builder-selectable compile time
|
||||||
|
options. Document the latter better, and describe how to
|
||||||
|
set them from the make command line.
|
||||||
|
|
||||||
|
Tidied up IPPROTO_IP/SOL_IP (and IPv6 equivalent)
|
||||||
|
confusion. IPPROTO_IP works everywhere now.
|
||||||
|
|
||||||
|
Set TOS on DHCP sockets, this improves things on busy
|
||||||
|
wireless networks. Thanks to Dave Taht for the patch.
|
||||||
|
|
||||||
|
Determine VERSION automatically based on git magic:
|
||||||
|
release tags or hash values.
|
||||||
|
|
||||||
|
Improve start-up speed when reading large hosts files
|
||||||
|
containing many distinct addresses.
|
||||||
|
|
||||||
|
Fix problem if dnsmasq is started without the stdin,
|
||||||
|
stdout and stderr file descriptors open. This can manifest
|
||||||
|
itself as 100% CPU use. Thanks to Chris Moore for finding
|
||||||
|
this.
|
||||||
|
|
||||||
|
Fix shell-scripting bug in bld/pkg-wrapper. Thanks to
|
||||||
|
Mark Mitchell for the patch.
|
||||||
|
|
||||||
|
Allow the TFP server or boot server in --pxe-service, to
|
||||||
|
be a domain name instead of an IP address. This allows for
|
||||||
|
round-robin to multiple servers, in the same way as
|
||||||
|
--dhcp-boot. A good suggestion from Cristiano Cumer.
|
||||||
|
|
||||||
|
Support BUILDDIR variable in the Makefile. Allows builds
|
||||||
|
for multiple archs from the same source tree with eg.
|
||||||
|
make BUILDDIR=linux (relative to dnsmasq tree)
|
||||||
|
make BUILDDIR=/tmp/openbsd (absolute path)
|
||||||
|
If BUILDDIR is not set, compilation happens in the src
|
||||||
|
directory, as before. Suggestion from Mark Mitchell.
|
||||||
|
|
||||||
|
Support DHCPv6. Support is there for the sort of things
|
||||||
|
the existing v4 server does, including tags, options,
|
||||||
|
static addresses and relay support. Missing is prefix
|
||||||
|
delegation, which is probably not required in the dnsmasq
|
||||||
|
niche, and an easy way to accept prefix delegations from
|
||||||
|
an upstream DHCPv6 server, which is. Future plans include
|
||||||
|
support for DHCPv6 router option and MAC address option
|
||||||
|
(to make selecting clients by MAC address work like IPv4).
|
||||||
|
These will be added as the standards mature.
|
||||||
|
This code has been tested, but this is the first release,
|
||||||
|
so don't bet the farm on it just yet. Many thanks to all
|
||||||
|
testers who have got it this far.
|
||||||
|
|
||||||
|
Support IPv6 router advertisements. This is a
|
||||||
|
simple-minded implementation, aimed at providing the
|
||||||
|
vestigial RA needed to go alongside IPv6. Is picks up
|
||||||
|
configuration from the DHCPv6 conf, and should just need
|
||||||
|
enabling with --enable-ra.
|
||||||
|
|
||||||
|
Fix long-standing wrinkle with --localise-queries that
|
||||||
|
could result in wrong answers when DNS packets arrive
|
||||||
|
via an interface other than the expected one. Thanks to
|
||||||
|
Lorenzo Milesi and John Hanks for spotting this one.
|
||||||
|
|
||||||
|
Update French translation. Thanks to Gildas Le Nadan.
|
||||||
|
|
||||||
|
Update Polish translation. Thanks to Jan Psota.
|
||||||
|
|
||||||
|
|
||||||
|
version 2.59
|
||||||
|
Fix regression in 2.58 which caused failure to start up
|
||||||
|
with some combinations of dnsmasq config and IPv6 kernel
|
||||||
|
network config. Thanks to Brielle Bruns for the bug
|
||||||
|
report.
|
||||||
|
|
||||||
|
Improve dnsmasq's behaviour when network interfaces are
|
||||||
|
still doing duplicate address detection (DAD). Previously,
|
||||||
|
dnsmasq would wait up to 20 seconds at start-up for the
|
||||||
|
DAD state to terminate. This is broken for bridge
|
||||||
|
interfaces on recent Linux kernels, which don't start DAD
|
||||||
|
until the bridge comes up, and so can take arbitrary
|
||||||
|
time. The new behaviour lets dnsmasq poll for an arbitrary
|
||||||
|
time whilst providing service on other interfaces. Thanks
|
||||||
|
to Stephen Hemminger for pointing out the problem.
|
||||||
|
|
||||||
|
|
||||||
|
version 2.58
|
||||||
|
Provide a definition of the SA_SIZE macro where it's
|
||||||
|
missing. Fixes build failure on openBSD.
|
||||||
|
|
||||||
|
Don't include a zero terminator at the end of messages
|
||||||
|
sent to /dev/log when /dev/log is a datagram socket.
|
||||||
|
Thanks to Didier Rabound for spotting the problem.
|
||||||
|
|
||||||
|
Add --dhcp-sequential-ip flag, to force allocation of IP
|
||||||
|
addresses in ascending order. Note that the default
|
||||||
|
pseudo-random mode is in general better but some
|
||||||
|
server-deployment applications need this.
|
||||||
|
|
||||||
|
Fix problem where a server-id of 0.0.0.0 is sent to a
|
||||||
|
client when a dhcp-relay is in use if a client renews a
|
||||||
|
lease after dnsmasq restart and before any clients on the
|
||||||
|
subnet get a new lease. Thanks to Mike Ruiz for assistance
|
||||||
|
in chasing this one down.
|
||||||
|
|
||||||
|
Don't return NXDOMAIN to an AAAA query if we have CNAME
|
||||||
|
which points to an A record only: NODATA is the correct
|
||||||
|
reply in this case. Thanks to Tom Fernandes for spotting
|
||||||
|
the problem.
|
||||||
|
|
||||||
|
Relax the need to supply a netmask in --dhcp-range for
|
||||||
|
networks which use a DHCP relay. Whilst this is still
|
||||||
|
desireable, in the absence of a netmask dnsmasq will use
|
||||||
|
a default based on the class (A, B, or C) of the address.
|
||||||
|
This should at least remove a cause of mysterious failure
|
||||||
|
for people using RFC1918 addresses and relays.
|
||||||
|
|
||||||
|
Add support for Linux conntrack connection marking. If
|
||||||
|
enabled with --conntrack, the connection mark for incoming
|
||||||
|
DNS queries will be copied to the outgoing connections
|
||||||
|
used to answer those queries. This allows clever firewall
|
||||||
|
and accounting stuff. Only available if dnsmasq is
|
||||||
|
compiled with HAVE_CONNTRACK and adds a dependency on
|
||||||
|
libnetfilter-conntrack. Thanks to Ed Wildgoose for the
|
||||||
|
initial idea, testing and sponsorship of this function.
|
||||||
|
|
||||||
|
Provide a sane error message when someone attempts to
|
||||||
|
match a tag in --dhcp-host.
|
||||||
|
|
||||||
|
Tweak the behaviour of --domain-needed, to avoid problems
|
||||||
|
with recursive nameservers downstream of dnsmasq. The new
|
||||||
|
behaviour only stops A and AAAA queries, and returns
|
||||||
|
NODATA rather than NXDOMAIN replies.
|
||||||
|
|
||||||
|
Efficiency fix for very large DHCP configurations, thanks
|
||||||
|
to James Gartrell and Mike Ruiz for help with this.
|
||||||
|
|
||||||
|
Allow the TFTP-server address in --dhcp-boot to be a
|
||||||
|
domain-name which is looked up in /etc/hosts. This can
|
||||||
|
give multiple IP addresses which are used round-robin,
|
||||||
|
thus doing TFTP server load-balancing. Thanks to Sushil
|
||||||
|
Agrawal for the patch.
|
||||||
|
|
||||||
|
When two tagged dhcp-options for a particular option
|
||||||
|
number are both valid, use the one which is valid without
|
||||||
|
a tag from the dhcp-range. Allows overriding of the value
|
||||||
|
of a DHCP option for a particular host as well as
|
||||||
|
per-network values. So
|
||||||
|
--dhcp-range=set:interface1,......
|
||||||
|
--dhcp-host=set:myhost,.....
|
||||||
|
--dhcp-option=tag:interface1,option:nis-domain,"domain1"
|
||||||
|
--dhcp-option=tag:myhost,option:nis-domain,"domain2"
|
||||||
|
will set the NIS-domain to domain1 for hosts in the range, but
|
||||||
|
override that to domain2 for a particular host.
|
||||||
|
|
||||||
|
Fix bug which resulted in truncated files and timeouts for
|
||||||
|
some TFTP transfers. The bug only occurs with netascii
|
||||||
|
transfers and needs an unfortunate relationship between
|
||||||
|
file size, blocksize and the number of newlines in the
|
||||||
|
last block before it manifests itself. Many thanks to
|
||||||
|
Alkis Georgopoulos for spotting the problem and providing
|
||||||
|
a comprehensive test-case.
|
||||||
|
|
||||||
|
Fix regression in TFTP server on *BSD platforms introduced
|
||||||
|
in version 2.56, due to confusion with sockaddr
|
||||||
|
length. Many thanks to Loïc Pefferkorn for finding this.
|
||||||
|
|
||||||
|
Support scope-ids in IPv6 addresses of nameservers from
|
||||||
|
/etc/resolv.conf and in --server options. Eg
|
||||||
|
nameserver fe80::202:a412:4512:7bbf%eth0 or
|
||||||
|
server=fe80::202:a412:4512:7bbf%eth0. Thanks to
|
||||||
|
Michael Stapelberg for the suggestion.
|
||||||
|
|
||||||
|
Update Polish translation, thanks to Jan Psota.
|
||||||
|
|
||||||
|
Update French translation. Thanks to Gildas Le Nadan.
|
||||||
|
|
||||||
|
|
||||||
|
version 2.57
|
||||||
|
Add patches to allow build under Android.
|
||||||
|
|
||||||
|
Provide our own header for the DNS protocol, rather than
|
||||||
|
relying on arpa/nameser.h. This has proved more or less
|
||||||
|
defective over the years and the final straw is that it's
|
||||||
|
effectively empty on Android.
|
||||||
|
|
||||||
|
Fix regression in 2.56 which caused hex constants in
|
||||||
|
configuration to be rejected if they contain the '*'
|
||||||
|
wildcard.
|
||||||
|
|
||||||
|
Correct wrong casts of arguments to ctype.h functions,
|
||||||
|
isdigit(), isxdigit() etc. Thanks to Matthias Andree for
|
||||||
|
spotting this.
|
||||||
|
|
||||||
|
Allow build with IDN support independently from i18n.
|
||||||
|
IDN support continues to be included automatically
|
||||||
|
when i18n is included.
|
||||||
|
'make COPTS=-DHAVE_IDN' is the magic incantation.
|
||||||
|
|
||||||
|
Modify check on extraneous command line junk (added in
|
||||||
|
2.56) so that it doesn't complain about extra _empty_
|
||||||
|
arguments. Otherwise this breaks libvirt.
|
||||||
|
|
||||||
|
|
||||||
version 2.56
|
version 2.56
|
||||||
Add a patch to allow dnsmasq to get interface names right in a
|
Add a patch to allow dnsmasq to get interface names right in a
|
||||||
Solaris zone. Thanks to Dj Padzensky for this.
|
Solaris zone. Thanks to Dj Padzensky for this.
|
||||||
@@ -117,9 +412,9 @@ version 2.56
|
|||||||
request meant for another DHCP server. NAKing this is
|
request meant for another DHCP server. NAKing this is
|
||||||
wrong. Thanks to Brad D'Hondt for assistance with this.
|
wrong. Thanks to Brad D'Hondt for assistance with this.
|
||||||
|
|
||||||
Fix cosmetic bug which produced strange output when
|
Fix cosmetic bug which produced strange output when
|
||||||
dumping cache statistics with some configurations. Thanks
|
dumping cache statistics with some configurations. Thanks
|
||||||
to Fedor Kozhevnikov for spotting this.
|
to Fedor Kozhevnikov for spotting this.
|
||||||
|
|
||||||
|
|
||||||
version 2.55
|
version 2.55
|
||||||
|
|||||||
@@ -303,7 +303,7 @@ A: Yes, new releases of dnsmasq are always announced through
|
|||||||
|
|
||||||
Q: What does the dhcp-authoritative option do?
|
Q: What does the dhcp-authoritative option do?
|
||||||
|
|
||||||
A: See http://www.isc.org/index.pl?/sw/dhcp/authoritative.php - that's
|
A: See http://www.isc.org/files/auth.html - that's
|
||||||
for the ISC daemon, but the same applies to dnsmasq.
|
for the ISC daemon, but the same applies to dnsmasq.
|
||||||
|
|
||||||
Q: Why does my Gentoo box pause for a minute before getting a new
|
Q: Why does my Gentoo box pause for a minute before getting a new
|
||||||
@@ -381,7 +381,7 @@ A: Probably the nameserver is an authoritative nameserver for a
|
|||||||
Q: Does the dnsmasq DHCP server probe addresses before allocating
|
Q: Does the dnsmasq DHCP server probe addresses before allocating
|
||||||
them, as recommended in RFC2131?
|
them, as recommended in RFC2131?
|
||||||
|
|
||||||
A: Yes, dynmaically allocated IP addresses are checked by sending an
|
A: Yes, dynamically allocated IP addresses are checked by sending an
|
||||||
ICMP echo request (ping). If a reply is received, then dnsmasq
|
ICMP echo request (ping). If a reply is received, then dnsmasq
|
||||||
assumes that the address is in use, and attempts to allocate an
|
assumes that the address is in use, and attempts to allocate an
|
||||||
different address. The wait for a reply is between two and three
|
different address. The wait for a reply is between two and three
|
||||||
@@ -467,8 +467,18 @@ A: The DHCP client on windows Vista (and possibly later versions)
|
|||||||
work).
|
work).
|
||||||
|
|
||||||
|
|
||||||
|
Q: DHCP doesn't work with windows 7 but everything else is fine.
|
||||||
|
|
||||||
|
A: There seems to be a problem if Windows 7 doesn't get a value for
|
||||||
|
DHCP option 252 in DHCP packets it gets from the server. The
|
||||||
|
symtoms have beeen variously reported as continual DHCPINFORM
|
||||||
|
requests in an attempt to get an option-252, or even ignoring DHCP
|
||||||
|
offers completely (and failing to get an IP address) if there is no
|
||||||
|
option-252 supplied. DHCP option 252 is for WPAD, WWW Proxy
|
||||||
|
Auto Detection and if you don't want or need to use that, then
|
||||||
|
simplest fix seems to be to supply an empty option with:
|
||||||
|
|
||||||
|
dhcp-option=252,"\n"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
# dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -13,85 +13,122 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
PREFIX = /usr/local
|
# NOTE: Building the i18n targets requires GNU-make
|
||||||
BINDIR = ${PREFIX}/sbin
|
|
||||||
MANDIR = ${PREFIX}/share/man
|
|
||||||
LOCALEDIR = ${PREFIX}/share/locale
|
|
||||||
|
|
||||||
PKG_CONFIG = pkg-config
|
|
||||||
INSTALL = install
|
|
||||||
MSGMERGE = msgmerge
|
|
||||||
MSGFMT = msgfmt
|
|
||||||
XGETTEXT = xgettext
|
|
||||||
|
|
||||||
CFLAGS = -Wall -W -O2
|
# Variables you may well want to override.
|
||||||
|
|
||||||
|
PREFIX = /usr/local
|
||||||
|
BINDIR = $(PREFIX)/sbin
|
||||||
|
MANDIR = $(PREFIX)/share/man
|
||||||
|
LOCALEDIR = $(PREFIX)/share/locale
|
||||||
|
BUILDDIR = $(SRC)
|
||||||
|
DESTDIR =
|
||||||
|
CFLAGS = -Wall -W -O2
|
||||||
|
LDFLAGS =
|
||||||
|
COPTS =
|
||||||
|
RPM_OPT_FLAGS =
|
||||||
|
LIBS =
|
||||||
|
|
||||||
#################################################################
|
#################################################################
|
||||||
|
|
||||||
|
# Variables you might want to override.
|
||||||
|
|
||||||
|
PKG_CONFIG = pkg-config
|
||||||
|
INSTALL = install
|
||||||
|
MSGMERGE = msgmerge
|
||||||
|
MSGFMT = msgfmt
|
||||||
|
XGETTEXT = xgettext
|
||||||
|
|
||||||
SRC = src
|
SRC = src
|
||||||
PO = po
|
PO = po
|
||||||
MAN = man
|
MAN = man
|
||||||
|
|
||||||
DNSMASQ_CFLAGS=`echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
|
#################################################################
|
||||||
DNSMASQ_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
|
|
||||||
SUNOS_LIBS= `if uname | grep SunOS 2>&1 >/dev/null; then echo -lsocket -lnsl -lposix4; fi`
|
|
||||||
|
|
||||||
OBJS = cache.o rfc1035.o util.o option.o forward.o network.o \
|
# pmake way. (NB no spaces to keep gmake 3.82 happy)
|
||||||
|
top!=pwd
|
||||||
|
# GNU make way.
|
||||||
|
top?=$(CURDIR)
|
||||||
|
|
||||||
|
dbus_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
|
||||||
|
dbus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
|
||||||
|
idn_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
|
||||||
|
idn_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
|
||||||
|
ct_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
|
||||||
|
ct_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
|
||||||
|
lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.1`
|
||||||
|
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.1`
|
||||||
|
sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
|
||||||
|
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 \
|
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
|
||||||
helper.o tftp.o log.o
|
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
|
||||||
|
dhcp-common.o outpacket.o radv.o slaac.o
|
||||||
|
|
||||||
all :
|
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||||
@cd $(SRC) && $(MAKE) \
|
dns-protocol.h radv-protocol.h
|
||||||
BUILD_CFLAGS="$(DNSMASQ_CFLAGS)" \
|
|
||||||
BUILD_LIBS="$(DNSMASQ_LIBS) $(SUNOS_LIBS)" \
|
all : $(BUILDDIR)
|
||||||
-f ../Makefile dnsmasq
|
@cd $(BUILDDIR) && $(MAKE) \
|
||||||
|
top="$(top)" \
|
||||||
|
build_cflags="$(version) $(dbus_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags)" \
|
||||||
|
build_libs="$(dbus_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs)" \
|
||||||
|
-f $(top)/Makefile dnsmasq
|
||||||
|
|
||||||
clean :
|
clean :
|
||||||
rm -f *~ $(SRC)/*.mo contrib/*/*~ */*~ $(SRC)/*.pot
|
rm -f *~ $(BUILDDIR)/*.mo contrib/*/*~ */*~ $(BUILDDIR)/*.pot
|
||||||
rm -f $(SRC)/*.o $(SRC)/dnsmasq.a $(SRC)/dnsmasq core */core
|
rm -f $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq core */core
|
||||||
|
|
||||||
install : all install-common
|
install : all install-common
|
||||||
|
|
||||||
install-common :
|
install-common :
|
||||||
$(INSTALL) -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8
|
$(INSTALL) -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8
|
||||||
$(INSTALL) -m 644 $(MAN)/dnsmasq.8 $(DESTDIR)$(MANDIR)/man8
|
$(INSTALL) -m 644 $(MAN)/dnsmasq.8 $(DESTDIR)$(MANDIR)/man8
|
||||||
$(INSTALL) -m 755 $(SRC)/dnsmasq $(DESTDIR)$(BINDIR)
|
$(INSTALL) -m 755 $(BUILDDIR)/dnsmasq $(DESTDIR)$(BINDIR)
|
||||||
|
|
||||||
all-i18n :
|
all-i18n : $(BUILDDIR)
|
||||||
@cd $(SRC) && $(MAKE) \
|
@cd $(BUILDDIR) && $(MAKE) \
|
||||||
I18N=-DLOCALEDIR='\"$(LOCALEDIR)\"' \
|
top="$(top)" \
|
||||||
BUILD_CFLAGS="$(DNSMASQ_CFLAGS) `$(PKG_CONFIG) --cflags libidn`" \
|
i18n=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
|
||||||
BUILD_LIBS="$(DNSMASQ_LIBS) $(SUNOS_LIBS) `$(PKG_CONFIG) --libs libidn`" \
|
build_cflags="$(version) $(dbus_cflags) $(ct_cflags) $(lua_cflags) `$(PKG_CONFIG) --cflags libidn`" \
|
||||||
-f ../Makefile dnsmasq
|
build_libs="$(dbus_libs) $(ct_libs) $(lua_libs) $(sunos_libs) `$(PKG_CONFIG) --libs libidn`" \
|
||||||
@cd $(PO); for f in *.po; do \
|
-f $(top)/Makefile dnsmasq
|
||||||
cd ../$(SRC) && $(MAKE) \
|
for f in `cd $(PO); echo *.po`; do \
|
||||||
-f ../Makefile $${f%.po}.mo; \
|
cd $(top) && cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile $${f%.po}.mo; \
|
||||||
done
|
done
|
||||||
|
|
||||||
install-i18n : all-i18n install-common
|
install-i18n : all-i18n install-common
|
||||||
cd $(SRC); ../bld/install-mo $(DESTDIR)$(LOCALEDIR) $(INSTALL)
|
cd $(BUILDDIR); $(top)/bld/install-mo $(DESTDIR)$(LOCALEDIR) $(INSTALL)
|
||||||
cd $(MAN); ../bld/install-man $(DESTDIR)$(MANDIR) $(INSTALL)
|
cd $(MAN); ../bld/install-man $(DESTDIR)$(MANDIR) $(INSTALL)
|
||||||
|
|
||||||
merge :
|
merge :
|
||||||
@cd $(SRC) && $(MAKE) -f ../Makefile dnsmasq.pot
|
@cd $(BUILDDIR) && $(MAKE) -f $(top)/Makefile dnsmasq.pot
|
||||||
@cd $(PO); for f in *.po; do \
|
for f in `cd $(PO); echo *.po`; do \
|
||||||
echo -n msgmerge $$f && $(MSGMERGE) --no-wrap -U $$f ../$(SRC)/dnsmasq.pot; \
|
echo -n msgmerge $(PO)/$$f && $(MSGMERGE) --no-wrap -U $(PO)/$$f $(BUILDDIR)/dnsmasq.pot; \
|
||||||
done
|
done
|
||||||
|
|
||||||
|
$(BUILDDIR):
|
||||||
|
mkdir -p $(BUILDDIR)
|
||||||
|
|
||||||
|
|
||||||
# rules below are targets in recusive makes with cwd=$(SRC)
|
# rules below are targets in recusive makes with cwd=$(SRC)
|
||||||
|
|
||||||
|
$(objs:.o=.c) $(hdrs):
|
||||||
|
ln -s $(top)/$(SRC)/$@ .
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
$(CC) $(CFLAGS) $(COPTS) $(I18N) $(BUILD_CFLAGS) $(RPM_OPT_FLAGS) -c $<
|
$(CC) $(CFLAGS) $(COPTS) $(i18n) $(build_cflags) $(RPM_OPT_FLAGS) -c $<
|
||||||
|
|
||||||
dnsmasq : $(OBJS)
|
dnsmasq : $(hdrs) $(objs)
|
||||||
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(BUILD_LIBS) $(LIBS)
|
$(CC) $(LDFLAGS) -o $@ $(objs) $(build_libs) $(LIBS)
|
||||||
|
|
||||||
dnsmasq.pot : $(OBJS:.o=.c) dnsmasq.h config.h
|
dnsmasq.pot : $(objs:.o=.c) $(hdrs)
|
||||||
$(XGETTEXT) -d dnsmasq --foreign-user --omit-header --keyword=_ -o $@ -i $(OBJS:.o=.c)
|
$(XGETTEXT) -d dnsmasq --foreign-user --omit-header --keyword=_ -o $@ -i $(objs:.o=.c)
|
||||||
|
|
||||||
%.mo : ../po/%.po dnsmasq.pot
|
%.mo : $(top)/$(PO)/%.po dnsmasq.pot
|
||||||
$(MSGMERGE) -o - ../po/$*.po dnsmasq.pot | $(MSGFMT) -o $*.mo -
|
$(MSGMERGE) -o - $(top)/$(PO)/$*.po dnsmasq.pot | $(MSGFMT) -o $*.mo -
|
||||||
|
|
||||||
|
|
||||||
.PHONY : all clean install install-common all-i18n install-i18n merge
|
.PHONY : all clean install install-common all-i18n install-i18n merge
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
LOCAL_PATH := external/dnsmasq/src
|
||||||
|
|
||||||
|
#########################
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
||||||
|
forward.c helper.c lease.c log.c \
|
||||||
|
netlink.c network.c option.c rfc1035.c \
|
||||||
|
rfc2131.c tftp.c util.c conntrack.c \
|
||||||
|
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
|
||||||
|
radv.c slaac.c
|
||||||
|
|
||||||
|
LOCAL_MODULE := dnsmasq
|
||||||
|
|
||||||
|
LOCAL_C_INCLUDES := external/dnsmasq/src
|
||||||
|
|
||||||
|
LOCAL_CFLAGS := -O2 -g -W -Wall -D__ANDROID__ -DNO_IPV6 -DNO_TFTP -DNO_SCRIPT
|
||||||
|
LOCAL_SYSTEM_SHARED_LIBRARIES := libc libcutils
|
||||||
|
|
||||||
|
include $(BUILD_EXECUTABLE)
|
||||||
Executable
+28
@@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Determine the version string to build into a binary.
|
||||||
|
# When building in the git repository, we can use the output
|
||||||
|
# of "git describe" which gives an unequivocal answer.
|
||||||
|
#
|
||||||
|
# Failing that, we use the contents of the VERSION file
|
||||||
|
# which has a set of references substituted into it by git.
|
||||||
|
# If we can find one which matches $v[0-9].* then we assume it's
|
||||||
|
# a version-number tag, else we just use the whole string.
|
||||||
|
|
||||||
|
if which git >/dev/null 2>&1 && [ -d $1/.git ]; then
|
||||||
|
cd $1; git describe
|
||||||
|
elif grep '\$Format:%d\$' $1/VERSION >/dev/null 2>&1; then
|
||||||
|
# unsubstituted VERSION, but no git available.
|
||||||
|
echo UNKNOWN
|
||||||
|
else
|
||||||
|
vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep $v[0-9]`
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "${vers}" | head -n 1 | tail -c +2
|
||||||
|
else
|
||||||
|
cat $1/VERSION
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
+1
-1
@@ -4,6 +4,6 @@ for f in *; do
|
|||||||
if [ -d $f ]; then
|
if [ -d $f ]; then
|
||||||
$2 -m 755 -d $1/$f/man8
|
$2 -m 755 -d $1/$f/man8
|
||||||
$2 -m 644 $f/dnsmasq.8 $1/$f/man8
|
$2 -m 644 $f/dnsmasq.8 $1/$f/man8
|
||||||
echo installing $1/$f/man8/dnsmasq.8
|
echo installing $f/man8/dnsmasq.8
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
for f in *.mo; do
|
for f in *.mo; do
|
||||||
$2 -m 755 -d $1/${f%.mo}/LC_MESSAGES
|
$2 -m 755 -d $1/${f%.mo}/LC_MESSAGES
|
||||||
$2 -m 644 $f $1/${f%.mo}/LC_MESSAGES/dnsmasq.mo
|
$2 -m 644 $f $1/${f%.mo}/LC_MESSAGES/dnsmasq.mo
|
||||||
echo installing $1/${f%.mo}/LC_MESSAGES/dnsmasq.mo
|
echo installing ${f%.mo}/LC_MESSAGES/dnsmasq.mo
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
+2
-2
@@ -3,8 +3,8 @@
|
|||||||
search=$1
|
search=$1
|
||||||
shift
|
shift
|
||||||
|
|
||||||
if grep "^\#.*define.*$search" config.h 2>&1 >/dev/null || \
|
if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
|
||||||
grep $search 2>&1 >/dev/null ; then
|
grep $search >/dev/null 2>&1; then
|
||||||
exec $*
|
exec $*
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
Linux iptables includes that ability to mark individual network packets
|
||||||
|
with a "firewall mark". Additionally there is a component called
|
||||||
|
"conntrack" which tries to string sequences of related packets together
|
||||||
|
into a "connection" (it even relates sequences of UDP and ICMP packets).
|
||||||
|
There is a related mark for a connection called a "connection mark".
|
||||||
|
Marks can be copied freely between the firewall and connection marks
|
||||||
|
|
||||||
|
Using these two features it become possible to tag all related traffic
|
||||||
|
in arbitrary ways, eg authenticated users, traffic from a particular IP,
|
||||||
|
port, etc. Unfortunately any kind of "proxy" breaks this relationship
|
||||||
|
because network packets go in one side of the proxy and a completely new
|
||||||
|
connection comes out of the other side. However, sometimes, we want to
|
||||||
|
maintain that relationship through the proxy and continue the connection
|
||||||
|
mark on packets upstream of our proxy
|
||||||
|
|
||||||
|
DNSMasq includes such a feature enabled by the --conntrack
|
||||||
|
option. This allows, for example, using iptables to mark traffic from
|
||||||
|
a particular IP, and that mark to be persisted to requests made *by*
|
||||||
|
DNSMasq. Such a feature could be useful for bandwidth accounting,
|
||||||
|
captive portals and the like. Note a similar feature has been
|
||||||
|
implemented in Squid 2.2
|
||||||
|
|
||||||
|
|
||||||
|
As an example consider the following iptables rules:
|
||||||
|
|
||||||
|
|
||||||
|
1) iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
|
||||||
|
2) iptables -t mangle -A PREROUTING -m mark --mark 0 -s 192.168.111.137
|
||||||
|
-j MARK --set-mark 137
|
||||||
|
3) iptables -t mangle -A PREROUTING -j CONNMARK --save-mark
|
||||||
|
|
||||||
|
4) iptables -t mangle -A OUTPUT -m mark ! --mark 0 -j CONNMARK --save-mark
|
||||||
|
|
||||||
|
1-3) are all applied to the PREROUTING table and affect all packets
|
||||||
|
entering the firewall.
|
||||||
|
|
||||||
|
1) copies any existing connection mark into the firewall mark. 2) Checks
|
||||||
|
the packet not already marked and if not applies an arbitrary mark based
|
||||||
|
on IP address. 3) Saves the firewall mark back to the connection mark
|
||||||
|
(which will persist it across related packets)
|
||||||
|
|
||||||
|
4) is applied to the OUTPUT table, which is where we first see packets
|
||||||
|
generated locally. DNSMasq will have already copied the firewall mark
|
||||||
|
from the request, across to the new packet, and so all that remains is
|
||||||
|
for iptables to copy it to the connection mark so it's persisted across
|
||||||
|
packets.
|
||||||
|
|
||||||
|
Note: iptables can be quite confusing to the beginner. The following
|
||||||
|
diagram is extremely helpful in understanding the flows
|
||||||
|
http://linux-ip.net/nf/nfk-traversal.png
|
||||||
|
Additionally the following URL contains a useful "starting guide" on
|
||||||
|
linux connection tracking/marking
|
||||||
|
http://home.regit.org/netfilter-en/netfilter-connmark/
|
||||||
|
|
||||||
@@ -34,11 +34,21 @@ if [ ${DNSMASQ_OLD_HOSTNAME} ] && [ ${action} = old ] ; then
|
|||||||
hostname=${DNSMASQ_OLD_HOSTNAME}
|
hostname=${DNSMASQ_OLD_HOSTNAME}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# IPv6 leases are not our concern. no NAT there!
|
||||||
|
if [ ${DNSMASQ_IAID} ] ; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
# action init is not relevant, and will only be seen when leasefile-ro is set.
|
# action init is not relevant, and will only be seen when leasefile-ro is set.
|
||||||
if [ ${action} = init ] ; then
|
if [ ${action} = init ] ; then
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# action tftp is not relevant.
|
||||||
|
if [ ${action} = tftp ] ; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
if [ ${hostname} ]; then
|
if [ ${hostname} ]; then
|
||||||
ports=$(sed -n -e "/^${hostname}\ .*/ s/^.* //p" ${PORTSFILE})
|
ports=$(sed -n -e "/^${hostname}\ .*/ s/^.* //p" ${PORTSFILE})
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
Hello,
|
||||||
|
|
||||||
|
I created a systemd service file for dnsmasq.
|
||||||
|
systemd is a sysvinit replacement (see [1] for more information).
|
||||||
|
One of the goals of systemd is to encourage standardization between different
|
||||||
|
distributions. This means, while I also submitted a ticket in Debian GNU/Linux,
|
||||||
|
I would like to ask you to accept this service file as the upstream
|
||||||
|
distributor, so that other distributions can use the same service file and
|
||||||
|
don’t have to ship their own.
|
||||||
|
|
||||||
|
Please include this file in your next release (just like in init script).
|
||||||
|
|
||||||
|
|
||||||
|
[1] http://en.wikipedia.org/wiki/Systemd
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=A lightweight DHCP and caching DNS server
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=dbus
|
||||||
|
BusName=uk.org.thekelleys.dnsmasq
|
||||||
|
ExecStartPre=/usr/sbin/dnsmasq --test
|
||||||
|
ExecStart=/usr/sbin/dnsmasq -k
|
||||||
|
ExecReload=/bin/kill -HUP $MAINPID
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
.TH DHCP_LEASE_TIME 1
|
||||||
|
.SH NAME
|
||||||
|
dhcp_lease_time \- Query remaining time of a lease on a the local dnsmasq DHCP server.
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B dhcp_lease_time <address>
|
||||||
|
.SH "DESCRIPTION"
|
||||||
|
Send a DHCPINFORM message to a dnsmasq server running on the local host
|
||||||
|
and print (to stdout) the time remaining in any lease for the given
|
||||||
|
address. The time is given as string printed to stdout.
|
||||||
|
|
||||||
|
If an error occurs or no lease exists for the given address,
|
||||||
|
nothing is sent to stdout a message is sent to stderr and a
|
||||||
|
non-zero error code is returned.
|
||||||
|
|
||||||
|
Requires dnsmasq 2.40 or later and may not work with other DHCP servers.
|
||||||
|
|
||||||
|
The address argument is a dotted-quad IP addresses and mandatory.
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR dnsmasq (8)
|
||||||
|
.SH AUTHOR
|
||||||
|
This manual page was written by Simon Kelley <simon@thekelleys.org.uk>.
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
.TH DHCP_RELEASE 1
|
||||||
|
.SH NAME
|
||||||
|
dhcp_release \- Release a DHCP lease on a the local dnsmasq DHCP server.
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B dhcp_release <interface> <address> <MAC address> <client_id>
|
||||||
|
.SH "DESCRIPTION"
|
||||||
|
A utility which forces the DHCP server running on this machine to release a
|
||||||
|
DHCP lease.
|
||||||
|
.PP
|
||||||
|
Send a DHCPRELEASE message via the specified interface to tell the
|
||||||
|
local DHCP server to delete a particular lease.
|
||||||
|
|
||||||
|
The interface argument is the interface in which a DHCP
|
||||||
|
request _would_ be received if it was coming from the client,
|
||||||
|
rather than being faked up here.
|
||||||
|
|
||||||
|
The address argument is a dotted-quad IP addresses and mandatory.
|
||||||
|
|
||||||
|
The MAC address is colon separated hex, and is mandatory. It may be
|
||||||
|
prefixed by an address-type byte followed by -, eg
|
||||||
|
|
||||||
|
10-11:22:33:44:55:66
|
||||||
|
|
||||||
|
but if the address-type byte is missing it is assumed to be 1, the type
|
||||||
|
for ethernet. This encoding is the one used in dnsmasq lease files.
|
||||||
|
|
||||||
|
The client-id is optional. If it is "*" then it treated as being missing.
|
||||||
|
.SH NOTES
|
||||||
|
MUST be run as root - will fail otherwise.
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR dnsmasq (8)
|
||||||
|
.SH AUTHOR
|
||||||
|
This manual page was written by Simon Kelley <simon@thekelleys.org.uk>.
|
||||||
|
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@ static int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
|
|||||||
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
|
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct in_addr find_interface(struct in_addr client, int fd, int index)
|
static struct in_addr find_interface(struct in_addr client, int fd, unsigned int index)
|
||||||
{
|
{
|
||||||
struct sockaddr_nl addr;
|
struct sockaddr_nl addr;
|
||||||
struct nlmsghdr *h;
|
struct nlmsghdr *h;
|
||||||
|
|||||||
Vendored
+1026
File diff suppressed because it is too large.
Load diff
Vendored
+6
@@ -0,0 +1,6 @@
|
|||||||
|
/etc/init.d/dnsmasq
|
||||||
|
/etc/default/dnsmasq
|
||||||
|
/etc/dnsmasq.conf
|
||||||
|
/etc/resolvconf/update.d/dnsmasq
|
||||||
|
/etc/dbus-1/system.d/dnsmasq.conf
|
||||||
|
/etc/insserv.conf.d/dnsmasq
|
||||||
Vendored
+41
@@ -0,0 +1,41 @@
|
|||||||
|
Source: dnsmasq
|
||||||
|
Section: net
|
||||||
|
Priority: optional
|
||||||
|
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any], libidn11-dev, libdbus-1-dev (>=0.61)
|
||||||
|
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
|
||||||
|
Standards-Version: 3.9.3
|
||||||
|
|
||||||
|
Package: dnsmasq
|
||||||
|
Architecture: all
|
||||||
|
Depends: netbase, adduser, dnsmasq-base(>= ${source:Version})
|
||||||
|
Suggests: resolvconf
|
||||||
|
Conflicts: resolvconf (<<1.15)
|
||||||
|
Description: Small caching DNS proxy and DHCP/TFTP server
|
||||||
|
Dnsmasq is a lightweight, easy to configure, DNS forwarder and DHCP
|
||||||
|
server. It is designed to provide DNS and optionally, DHCP, to a
|
||||||
|
small network. It can serve the names of local machines which are
|
||||||
|
not in the global DNS. The DHCP server integrates with the DNS
|
||||||
|
server and allows machines with DHCP-allocated addresses
|
||||||
|
to appear in the DNS with names configured either in each host or
|
||||||
|
in a central configuration file. Dnsmasq supports static and dynamic
|
||||||
|
DHCP leases and BOOTP/TFTP for network booting of diskless machines.
|
||||||
|
|
||||||
|
Package: dnsmasq-base
|
||||||
|
Architecture: any
|
||||||
|
Depends: ${shlibs:Depends}
|
||||||
|
Conflicts: dnsmasq (<<2.41)
|
||||||
|
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
|
||||||
|
that, install the dnsmasq package.
|
||||||
|
|
||||||
|
Package: dnsmasq-utils
|
||||||
|
Architecture: linux-any
|
||||||
|
Depends: ${shlibs:Depends}
|
||||||
|
Conflicts: dnsmasq (<<2.40)
|
||||||
|
Description: Utilities for manipulating DHCP leases
|
||||||
|
Small utilities to query a DHCP server's lease database and
|
||||||
|
remove leases from it. These programs are distributed with dnsmasq
|
||||||
|
and may not work correctly with other DHCP servers.
|
||||||
|
|
||||||
|
|
||||||
Vendored
+21
@@ -0,0 +1,21 @@
|
|||||||
|
dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
|
It was downloaded from: http://www.thekelleys.org.uk/dnsmasq/
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
On Debian GNU/Linux systems, the text of the GNU general public license is
|
||||||
|
available in the file /usr/share/common-licenses/GPL-2 or
|
||||||
|
/usr/share/common-licenses/GPL-3
|
||||||
|
|
||||||
|
The Debian package of dnsmasq was created by Simon Kelley with assistance
|
||||||
|
from Lars Bahner.
|
||||||
|
|
||||||
Vendored
+18
@@ -0,0 +1,18 @@
|
|||||||
|
<!DOCTYPE busconfig PUBLIC
|
||||||
|
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||||
|
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||||
|
<busconfig>
|
||||||
|
<policy user="root">
|
||||||
|
<allow own="uk.org.thekelleys.dnsmasq"/>
|
||||||
|
<allow send_destination="uk.org.thekelleys.dnsmasq"/>
|
||||||
|
</policy>
|
||||||
|
<policy user="dnsmasq">
|
||||||
|
<allow own="uk.org.thekelleys.dnsmasq"/>
|
||||||
|
<allow send_destination="uk.org.thekelleys.dnsmasq"/>
|
||||||
|
</policy>
|
||||||
|
<policy context="default">
|
||||||
|
<deny own="uk.org.thekelleys.dnsmasq"/>
|
||||||
|
<deny send_destination="uk.org.thekelleys.dnsmasq"/>
|
||||||
|
</policy>
|
||||||
|
</busconfig>
|
||||||
|
|
||||||
Vendored
+33
@@ -0,0 +1,33 @@
|
|||||||
|
# This file has five functions:
|
||||||
|
# 1) to completely disable starting dnsmasq,
|
||||||
|
# 2) to set DOMAIN_SUFFIX by running `dnsdomainname`
|
||||||
|
# 3) to select an alternative config file
|
||||||
|
# by setting DNSMASQ_OPTS to --conf-file=<file>
|
||||||
|
# 4) to tell dnsmasq to read the files in /etc/dnsmasq.d for
|
||||||
|
# more configuration variables.
|
||||||
|
# 5) to stop the resolvconf package from controlling dnsmasq's
|
||||||
|
# idea of which upstream nameservers to use.
|
||||||
|
# For upgraders from very old versions, all the shell variables set
|
||||||
|
# here in previous versions are still honored by the init script
|
||||||
|
# so if you just keep your old version of this file nothing will break.
|
||||||
|
|
||||||
|
#DOMAIN_SUFFIX=`dnsdomainname`
|
||||||
|
#DNSMASQ_OPTS="--conf-file=/etc/dnsmasq.alt"
|
||||||
|
|
||||||
|
# Whether or not to run the dnsmasq daemon; set to 0 to disable.
|
||||||
|
ENABLED=1
|
||||||
|
|
||||||
|
# By default search this drop directory for configuration options.
|
||||||
|
# Libvirt leaves a file here to make the system dnsmasq play nice.
|
||||||
|
# Comment out this line if you don't want this. The dpkg-* are file
|
||||||
|
# endings which cause dnsmasq to skip that file. This avoids pulling
|
||||||
|
# in backups made by dpkg.
|
||||||
|
CONFIG_DIR=/etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new
|
||||||
|
|
||||||
|
# If the resolvconf package is installed, dnsmasq will use its output
|
||||||
|
# rather than the contents of /etc/resolv.conf to find upstream
|
||||||
|
# nameservers. Uncommenting this line inhibits this behaviour.
|
||||||
|
# Not that including a "resolv-file=<filename>" line in
|
||||||
|
# /etc/dnsmasq.conf is not enough to override resolvconf if it is
|
||||||
|
# installed: the line below must be uncommented.
|
||||||
|
#IGNORE_RESOLVCONF=yes
|
||||||
Vendored
+269
@@ -0,0 +1,269 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
### BEGIN INIT INFO
|
||||||
|
# Provides: dnsmasq
|
||||||
|
# Required-Start: $network $remote_fs $syslog
|
||||||
|
# Required-Stop: $network $remote_fs $syslog
|
||||||
|
# Default-Start: 2 3 4 5
|
||||||
|
# Default-Stop: 0 1 6
|
||||||
|
# Description: DHCP and DNS server
|
||||||
|
### END INIT INFO
|
||||||
|
|
||||||
|
set +e # Don't exit on error status
|
||||||
|
|
||||||
|
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||||
|
DAEMON=/usr/sbin/dnsmasq
|
||||||
|
NAME=dnsmasq
|
||||||
|
DESC="DNS forwarder and DHCP server"
|
||||||
|
|
||||||
|
# Most configuration options in /etc/default/dnsmasq are deprecated
|
||||||
|
# but still honoured.
|
||||||
|
ENABLED=1
|
||||||
|
if [ -r /etc/default/$NAME ]; then
|
||||||
|
. /etc/default/$NAME
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get the system locale, so that messages are in the correct language, and the
|
||||||
|
# charset for IDN is correct
|
||||||
|
if [ -r /etc/default/locale ]; then
|
||||||
|
. /etc/default/locale
|
||||||
|
export LANG
|
||||||
|
fi
|
||||||
|
|
||||||
|
test -x $DAEMON || exit 0
|
||||||
|
|
||||||
|
# Provide skeleton LSB log functions for backports which don't have LSB functions.
|
||||||
|
if [ -f /lib/lsb/init-functions ]; then
|
||||||
|
. /lib/lsb/init-functions
|
||||||
|
else
|
||||||
|
log_warning_msg () {
|
||||||
|
echo "${@}."
|
||||||
|
}
|
||||||
|
|
||||||
|
log_success_msg () {
|
||||||
|
echo "${@}."
|
||||||
|
}
|
||||||
|
|
||||||
|
log_daemon_msg () {
|
||||||
|
echo -n "${1}: $2"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_end_msg () {
|
||||||
|
if [ $1 -eq 0 ]; then
|
||||||
|
echo "."
|
||||||
|
elif [ $1 -eq 255 ]; then
|
||||||
|
/bin/echo -e " (warning)."
|
||||||
|
else
|
||||||
|
/bin/echo -e " failed!"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# RESOLV_CONF:
|
||||||
|
# If the resolvconf package is installed then use the resolv conf file
|
||||||
|
# that it provides as the default. Otherwise use /etc/resolv.conf as
|
||||||
|
# the default.
|
||||||
|
#
|
||||||
|
# If IGNORE_RESOLVCONF is set in /etc/default/dnsmasq or an explicit
|
||||||
|
# filename is set there then this inhibits the use of the resolvconf-provided
|
||||||
|
# information.
|
||||||
|
#
|
||||||
|
# Note that if the resolvconf package is installed it is not possible to
|
||||||
|
# override it just by configuration in /etc/dnsmasq.conf, it is necessary
|
||||||
|
# to set IGNORE_RESOLVCONF=yes in /etc/default/dnsmasq.
|
||||||
|
|
||||||
|
if [ ! "$RESOLV_CONF" ] &&
|
||||||
|
[ "$IGNORE_RESOLVCONF" != "yes" ] &&
|
||||||
|
[ -x /sbin/resolvconf ]
|
||||||
|
then
|
||||||
|
RESOLV_CONF=/var/run/dnsmasq/resolv.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
for INTERFACE in $DNSMASQ_INTERFACE; do
|
||||||
|
DNSMASQ_INTERFACES="$DNSMASQ_INTERFACES -i $INTERFACE"
|
||||||
|
done
|
||||||
|
|
||||||
|
for INTERFACE in $DNSMASQ_EXCEPT; do
|
||||||
|
DNSMASQ_INTERFACES="$DNSMASQ_INTERFACES -I $INTERFACE"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ! "$DNSMASQ_USER" ]; then
|
||||||
|
DNSMASQ_USER="dnsmasq"
|
||||||
|
fi
|
||||||
|
|
||||||
|
start()
|
||||||
|
{
|
||||||
|
# Return
|
||||||
|
# 0 if daemon has been started
|
||||||
|
# 1 if daemon was already running
|
||||||
|
# 2 if daemon could not be started
|
||||||
|
|
||||||
|
# /var/run may be volatile, so we need to ensure that
|
||||||
|
# /var/run/dnsmasq exists here as well as in postinst
|
||||||
|
if [ ! -d /var/run/dnsmasq ]; then
|
||||||
|
mkdir /var/run/dnsmasq || return 2
|
||||||
|
chown dnsmasq:nogroup /var/run/dnsmasq || return 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null || return 1
|
||||||
|
start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON -- \
|
||||||
|
-x /var/run/dnsmasq/$NAME.pid \
|
||||||
|
${MAILHOSTNAME:+ -m $MAILHOSTNAME} \
|
||||||
|
${MAILTARGET:+ -t $MAILTARGET} \
|
||||||
|
${DNSMASQ_USER:+ -u $DNSMASQ_USER} \
|
||||||
|
${DNSMASQ_INTERFACES:+ $DNSMASQ_INTERFACES} \
|
||||||
|
${DHCP_LEASE:+ -l $DHCP_LEASE} \
|
||||||
|
${DOMAIN_SUFFIX:+ -s $DOMAIN_SUFFIX} \
|
||||||
|
${RESOLV_CONF:+ -r $RESOLV_CONF} \
|
||||||
|
${CACHESIZE:+ -c $CACHESIZE} \
|
||||||
|
${CONFIG_DIR:+ -7 $CONFIG_DIR} \
|
||||||
|
${DNSMASQ_OPTS:+ $DNSMASQ_OPTS} \
|
||||||
|
|| return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
start_resolvconf()
|
||||||
|
{
|
||||||
|
# If interface "lo" is explicitly disabled in /etc/default/dnsmasq
|
||||||
|
# Then dnsmasq won't be providing local DNS, so don't add it to
|
||||||
|
# the resolvconf server set.
|
||||||
|
for interface in $DNSMASQ_EXCEPT
|
||||||
|
do
|
||||||
|
[ $interface = lo ] && return
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -x /sbin/resolvconf ] ; then
|
||||||
|
echo "nameserver 127.0.0.1" | /sbin/resolvconf -a lo.$NAME
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
stop()
|
||||||
|
{
|
||||||
|
# Return
|
||||||
|
# 0 if daemon has been stopped
|
||||||
|
# 1 if daemon was already stopped
|
||||||
|
# 2 if daemon could not be stopped
|
||||||
|
# other if a failure occurred
|
||||||
|
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile /var/run/dnsmasq/$NAME.pid --name $NAME
|
||||||
|
RETVAL="$?"
|
||||||
|
[ "$RETVAL" = 2 ] && return 2
|
||||||
|
return "$RETVAL"
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_resolvconf()
|
||||||
|
{
|
||||||
|
if [ -x /sbin/resolvconf ] ; then
|
||||||
|
/sbin/resolvconf -d lo.$NAME
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
status()
|
||||||
|
{
|
||||||
|
# Return
|
||||||
|
# 0 if daemon is running
|
||||||
|
# 1 if daemon is dead and pid file exists
|
||||||
|
# 3 if daemon is not running
|
||||||
|
# 4 if daemon status is unknown
|
||||||
|
start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null
|
||||||
|
case "$?" in
|
||||||
|
0) [ -e "/var/run/dnsmasq/$NAME.pid" ] && return 1 ; return 3 ;;
|
||||||
|
1) return 0 ;;
|
||||||
|
*) return 4 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
test "$ENABLED" != "0" || exit 0
|
||||||
|
log_daemon_msg "Starting $DESC" "$NAME"
|
||||||
|
start
|
||||||
|
case "$?" in
|
||||||
|
0)
|
||||||
|
log_end_msg 0
|
||||||
|
start_resolvconf
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
1)
|
||||||
|
log_success_msg "(already running)"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_end_msg 1
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
stop_resolvconf
|
||||||
|
if [ "$ENABLED" != "0" ]; then
|
||||||
|
log_daemon_msg "Stopping $DESC" "$NAME"
|
||||||
|
fi
|
||||||
|
stop
|
||||||
|
RETVAL="$?"
|
||||||
|
if [ "$ENABLED" = "0" ]; then
|
||||||
|
case "$RETVAL" in
|
||||||
|
0) log_daemon_msg "Stopping $DESC" "$NAME"; log_end_msg 0 ;;
|
||||||
|
esac
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
case "$RETVAL" in
|
||||||
|
0) log_end_msg 0 ; exit 0 ;;
|
||||||
|
1) log_warning_msg "(not running)" ; exit 0 ;;
|
||||||
|
*) log_end_msg 1; exit 1 ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
restart|force-reload)
|
||||||
|
test "$ENABLED" != "0" || exit 1
|
||||||
|
$DAEMON --test ${CONFIG_DIR:+ -7 $CONFIG_DIR} ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS} >/dev/null 2>&1
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
NAME="configuration syntax check"
|
||||||
|
RETVAL="2"
|
||||||
|
else
|
||||||
|
stop_resolvconf
|
||||||
|
stop
|
||||||
|
RETVAL="$?"
|
||||||
|
fi
|
||||||
|
log_daemon_msg "Restarting $DESC" "$NAME"
|
||||||
|
case "$RETVAL" in
|
||||||
|
0|1)
|
||||||
|
sleep 2
|
||||||
|
start
|
||||||
|
case "$?" in
|
||||||
|
0)
|
||||||
|
log_end_msg 0
|
||||||
|
start_resolvconf
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_end_msg 1
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_end_msg 1
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
log_daemon_msg "Checking $DESC" "$NAME"
|
||||||
|
status
|
||||||
|
case "$?" in
|
||||||
|
0) log_success_msg "(running)" ; exit 0 ;;
|
||||||
|
1) log_success_msg "(dead, pid file exists)" ; exit 1 ;;
|
||||||
|
3) log_success_msg "(not running)" ; exit 3 ;;
|
||||||
|
*) log_success_msg "(unknown)" ; exit 4 ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
dump-stats)
|
||||||
|
kill -s USR1 `cat /var/run/dnsmasq/$NAME.pid`
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload|dump-stats|status}" >&2
|
||||||
|
exit 3
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
$named dnsmasq
|
||||||
Vendored
+49
@@ -0,0 +1,49 @@
|
|||||||
|
#!/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
|
||||||
|
|
||||||
|
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ]; then
|
||||||
|
if [ -e /var/run/dnsmasq/dnsmasq.pid ]; then
|
||||||
|
ACTION=restart
|
||||||
|
else
|
||||||
|
ACTION=start
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -x /usr/sbin/invoke-rc.d ] ; then
|
||||||
|
invoke-rc.d dnsmasq $ACTION || true
|
||||||
|
else
|
||||||
|
/etc/init.d/dnsmasq $ACTION || true
|
||||||
|
fi
|
||||||
|
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
|
||||||
|
|
||||||
Vendored
+12
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
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
|
||||||
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$1" = "remove" ]; then
|
||||||
|
if [ -x /usr/sbin/invoke-rc.d ] ; then
|
||||||
|
invoke-rc.d dnsmasq stop || true
|
||||||
|
else
|
||||||
|
/etc/init.d/dnsmasq stop || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
|
||||||
Vendored
+76
@@ -0,0 +1,76 @@
|
|||||||
|
Notes on configuring dnsmasq as packaged for Debian.
|
||||||
|
|
||||||
|
(1) To configure dnsmasq edit /etc/dnsmasq.conf. The file is well
|
||||||
|
commented; see also the dnsmasq.8 man page for explanation of
|
||||||
|
the options. The file /etc/default/dnsmasq also exists but it
|
||||||
|
shouldn't need to be touched in most cases. To set up DHCP
|
||||||
|
options you might need to refer to a copy of RFC 2132. This is
|
||||||
|
available on Debian systems in the package doc-rfc-std as the file
|
||||||
|
/usr/share/doc/RFC/draft-standard/rfc2132.txt.gz .
|
||||||
|
|
||||||
|
(2) Installing the dnsmasq package also creates the directory
|
||||||
|
/etc/dnsmasq.d which is searched by dnsmasq for configuration file
|
||||||
|
fragments. This behaviour can be disabled by editing
|
||||||
|
/etc/default/dnsmasq.
|
||||||
|
|
||||||
|
(3) If the Debian resolvconf package is installed then, regardless
|
||||||
|
of what interface configuration daemons are employed, the list of
|
||||||
|
nameservers to which dnsmasq should forward queries can be found
|
||||||
|
in /var/run/dnsmasq/resolv.conf; also, 127.0.0.1 is listed as the
|
||||||
|
first nameserver address in /etc/resolv.conf. This works using the
|
||||||
|
default configurations of resolvconf and dnsmasq.
|
||||||
|
|
||||||
|
(4) In the absence of resolvconf, if you are using dhcpcd then
|
||||||
|
dnsmasq should read the list of nameservers from the automatically
|
||||||
|
generated file /etc/dhcpc/resolv.conf. You should list 127.0.0.1
|
||||||
|
as the first nameserver address in /etc/resolv.conf.
|
||||||
|
|
||||||
|
(5) In the absence of resolvconf, if you are using pppd then
|
||||||
|
dnsmasq should read the list of nameservers from the automatically
|
||||||
|
generated file /etc/ppp/resolv.conf. You should list 127.0.0.1
|
||||||
|
as the first nameserver address in /etc/resolv.conf.
|
||||||
|
|
||||||
|
(6) In the absence of resolvconf, dns-nameservers lines in
|
||||||
|
/etc/network/interfaces are ignored. If you do do not use
|
||||||
|
resolvconf, list 127.0.0.1 as the first nameserver address
|
||||||
|
in /etc/resolv.conf and configure your nameservers using
|
||||||
|
"server=<IP-address>" lines in /etc/dnsmasq.conf.
|
||||||
|
|
||||||
|
(7) If you run multiple DNS servers on a single machine, each
|
||||||
|
listening on a different interface, then it is necessary to use
|
||||||
|
the bind-interfaces option by uncommenting "bind-interfaces" in
|
||||||
|
/etc/dnsmasq.conf. This option stops dnsmasq from binding the
|
||||||
|
wildcard address and allows servers listening on port 53 on
|
||||||
|
interfaces not in use by dnsmasq to work. The Debian
|
||||||
|
libvirt package will add a configuration file in /etc/dnsmasq.d
|
||||||
|
which does this so that the "system" dnsmasq and "private" dnsmasq
|
||||||
|
instances started by libvirt do not clash.
|
||||||
|
|
||||||
|
(8) The following options are supported in DEB_BUILD_OPTIONS
|
||||||
|
noopt : compile without optimisation.
|
||||||
|
nostrip : don't remove symbols from binary.
|
||||||
|
nodocs : omit documentation.
|
||||||
|
notftp : omit TFTP support.
|
||||||
|
nodhcp : omit DHCP support.
|
||||||
|
nodhcp6 : omit DHCPv6 support.
|
||||||
|
noscript : omit lease-change script support.
|
||||||
|
use_lua : provide support for lease-change scripts written
|
||||||
|
in Lua.
|
||||||
|
noipv6 : omit IPv6 support.
|
||||||
|
nodbus : omit DBus support.
|
||||||
|
noconntrack : omit connection tracking 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
|
||||||
|
combined with noi18n to be effective.
|
||||||
|
|
||||||
|
|
||||||
|
(9) Dnsmasq comes as three packages - dnsmasq-utils, dnsmasq-base and
|
||||||
|
dnsmasq. Dnsmasq-base provides the dnsmasq executable and
|
||||||
|
documentation (including this file). Dnsmasq, which depends on
|
||||||
|
dnsmasq-base, provides the init script and configuration
|
||||||
|
infrastructure. This file assumes that both are installed. It is
|
||||||
|
possible to install only dnsmasq-base and use dnsmasq as a
|
||||||
|
non-"system" daemon. Libvirt, for instance, does this.
|
||||||
|
Dnsmasq-utils provides the utilities dhcp_release and
|
||||||
|
dhcp_lease_time.
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
# All files in this directory will be read by dnsmasq as
|
||||||
|
# configuration files, except if their names end in
|
||||||
|
# ".dpkg-dist",".dpkg-old" or ".dpkg-new"
|
||||||
|
#
|
||||||
|
# This can be changed by editing /etc/default/dnsmasq
|
||||||
|
|
||||||
|
|
||||||
Vendored
+70
@@ -0,0 +1,70 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Script to update the resolver list for dnsmasq
|
||||||
|
#
|
||||||
|
# N.B. Resolvconf may run us even if dnsmasq is not running.
|
||||||
|
# If dnsmasq is installed then we go ahead and update
|
||||||
|
# the resolver list in case dnsmasq is started later.
|
||||||
|
#
|
||||||
|
# Assumption: On entry, PWD contains the resolv.conf-type files
|
||||||
|
#
|
||||||
|
# Requires bash because it uses a non-POSIX printf extension.
|
||||||
|
#
|
||||||
|
# Licensed under the GNU GPL. See /usr/share/common-licenses/GPL.
|
||||||
|
#
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
RUN_DIR="/var/run/dnsmasq"
|
||||||
|
RSLVRLIST_FILE="${RUN_DIR}/resolv.conf"
|
||||||
|
TMP_FILE="${RSLVRLIST_FILE}_new.$$"
|
||||||
|
|
||||||
|
[ -x /usr/sbin/dnsmasq ] || exit 0
|
||||||
|
[ -x /lib/resolvconf/list-records ] || exit 1
|
||||||
|
|
||||||
|
PATH=/bin:/sbin
|
||||||
|
|
||||||
|
report_err() { echo "$0: Error: $*" >&2 ; }
|
||||||
|
|
||||||
|
# Stores arguments (minus duplicates) in RSLT, separated by spaces
|
||||||
|
# Doesn't work properly if an argument itself contain whitespace
|
||||||
|
uniquify()
|
||||||
|
{
|
||||||
|
RSLT=""
|
||||||
|
while [ "$1" ] ; do
|
||||||
|
for E in $RSLT ; do
|
||||||
|
[ "$1" = "$E" ] && { shift ; continue 2 ; }
|
||||||
|
done
|
||||||
|
RSLT="${RSLT:+$RSLT }$1"
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ ! -d "$RUN_DIR" ] && ! mkdir --parents --mode=0755 "$RUN_DIR" ; then
|
||||||
|
report_err "Failed trying to create directory $RUN_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
RSLVCNFFILES="$(/lib/resolvconf/list-records | sed -e '/^lo.dnsmasq$/d')"
|
||||||
|
|
||||||
|
NMSRVRS=""
|
||||||
|
if [ "$RSLVCNFFILES" ] ; then
|
||||||
|
uniquify $(sed -n -e 's/^[[:space:]]*nameserver[[:space:]]\+//p' $RSLVCNFFILES)
|
||||||
|
NMSRVRS="$RSLT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Dnsmasq uses the mtime of $RSLVRLIST_FILE, with a resolution of one second,
|
||||||
|
# to detect changes in the file. This means that if a resolvconf update occurs
|
||||||
|
# within one second of the previous one then dnsmasq may fail to notice the
|
||||||
|
# more recent change. To work around this problem we sleep here to ensure
|
||||||
|
# that the new mtime is different.
|
||||||
|
if [ -f "$RSLVRLIST_FILE" ] && [ "$(ls -go --time-style='+%s' "$RSLVRLIST_FILE" | { read p h s t n ; echo "$t" ; })" = "$(date +%s)" ] ; then
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
clean_up() { rm -f "$TMP_FILE" ; }
|
||||||
|
trap clean_up EXIT
|
||||||
|
: >| "$TMP_FILE"
|
||||||
|
for N in $NMSRVRS ; do echo "nameserver $N" >> "$TMP_FILE" ; done
|
||||||
|
mv -f "$TMP_FILE" "$RSLVRLIST_FILE"
|
||||||
|
|
||||||
Vendored
+13
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Resolvconf packaging event hook script for the dnsmasq package
|
||||||
|
restart_dnsmasq() {
|
||||||
|
if which invoke-rc.d >/dev/null 2>&1 ; then
|
||||||
|
invoke-rc.d dnsmasq restart
|
||||||
|
elif [ -x /etc/init.d/dnsmasq ] ; then
|
||||||
|
/etc/init.d/dnsmasq restart
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
install) restart_dnsmasq ;;
|
||||||
|
esac
|
||||||
+197
@@ -0,0 +1,197 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
# debian/rules file - for dnsmasq.
|
||||||
|
# Copyright 2001-2011 by Simon Kelley
|
||||||
|
# Based on the sample in the debian hello package which carries the following:
|
||||||
|
# Copyright 1994,1995 by Ian Jackson.
|
||||||
|
# I hereby give you perpetual unlimited permission to copy,
|
||||||
|
# modify and relicense this file, provided that you do not remove
|
||||||
|
# my name from the file itself. (I assert my moral right of
|
||||||
|
# paternity under the Copyright, Designs and Patents Act 1988.)
|
||||||
|
# This file may have to be extensively modified
|
||||||
|
|
||||||
|
package=dnsmasq-base
|
||||||
|
|
||||||
|
# policy manual, section 10.1
|
||||||
|
ifneq (,$(filter noopt,$(DEB_BUILD_OPTIONS)))
|
||||||
|
CFLAGS = -g -O0 -Wall -W
|
||||||
|
else
|
||||||
|
CFLAGS = -g -O2 -Wall -W
|
||||||
|
endif
|
||||||
|
|
||||||
|
COPTS =
|
||||||
|
TARGET = install-i18n
|
||||||
|
|
||||||
|
DEB_BUILD_ARCH_OS := $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS)
|
||||||
|
|
||||||
|
ifeq (,$(filter nodbus,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DHAVE_DBUS
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq (,$(filter noconntrack,$(DEB_BUILD_OPTIONS)))
|
||||||
|
ifeq ($(DEB_BUILD_ARCH_OS),linux)
|
||||||
|
COPTS += -DHAVE_CONNTRACK
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter nodhcp6,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DNO_DHCP6
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter noipv6,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DNO_IPV6
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter notftp,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DNO_TFTP
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter nodhcp,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DNO_DHCP
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter noscript,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DNO_SCRIPT
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter nortc,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DHAVE_BROKEN_RTC
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter noi18n,$(DEB_BUILD_OPTIONS)))
|
||||||
|
TARGET = install
|
||||||
|
ifeq (,$(filter noidn, $(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DHAVE_IDN
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter uselua,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DHAVE_LUASCRIPT
|
||||||
|
endif
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(checkdir)
|
||||||
|
rm -rf debian/daemon debian/base debian/utils debian/*~ debian/files debian/substvars debian/utils-substvars
|
||||||
|
make clean
|
||||||
|
make -C contrib/wrt clean
|
||||||
|
|
||||||
|
binary-indep: checkroot
|
||||||
|
$(checkdir)
|
||||||
|
rm -rf debian/daemon
|
||||||
|
install -m 755 \
|
||||||
|
-d debian/daemon/DEBIAN \
|
||||||
|
-d debian/daemon/usr/share/doc \
|
||||||
|
-d debian/daemon/etc/init.d \
|
||||||
|
-d debian/daemon/etc/dnsmasq.d \
|
||||||
|
-d debian/daemon/etc/resolvconf/update.d \
|
||||||
|
-d debian/daemon/usr/lib/resolvconf/dpkg-event.d \
|
||||||
|
-d debian/daemon/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
|
||||||
|
install -m 755 debian/postinst debian/postrm debian/prerm debian/daemon/DEBIAN
|
||||||
|
install -m 755 debian/init debian/daemon/etc/init.d/dnsmasq
|
||||||
|
install -m 755 debian/resolvconf debian/daemon/etc/resolvconf/update.d/dnsmasq
|
||||||
|
install -m 755 debian/resolvconf-package debian/daemon/usr/lib/resolvconf/dpkg-event.d/dnsmasq
|
||||||
|
install -m 644 debian/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
|
||||||
|
cd debian/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
|
||||||
|
dpkg-gencontrol -pdnsmasq -Pdebian/daemon
|
||||||
|
chown -R root.root debian/daemon
|
||||||
|
chmod -R g-ws debian/daemon
|
||||||
|
dpkg --build debian/daemon ..
|
||||||
|
|
||||||
|
binary-arch: checkroot
|
||||||
|
$(checkdir)
|
||||||
|
rm -rf debian/base
|
||||||
|
install -m 755 \
|
||||||
|
-d debian/base/DEBIAN \
|
||||||
|
-d debian/base/usr/share/doc/$(package) \
|
||||||
|
-d debian/base/usr/share/doc/$(package)/examples \
|
||||||
|
-d debian/base/var/run \
|
||||||
|
-d debian/base/var/lib/misc
|
||||||
|
make $(TARGET) PREFIX=/usr DESTDIR=`pwd`/debian/base CFLAGS="$(CFLAGS)" COPTS="$(COPTS)" CC=gcc
|
||||||
|
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||||
|
install -m 644 doc.html debian/base/usr/share/doc/$(package)/.
|
||||||
|
install -m 644 setup.html debian/base/usr/share/doc/$(package)/.
|
||||||
|
install -m 644 dnsmasq.conf.example debian/base/usr/share/doc/$(package)/examples/.
|
||||||
|
install -m 644 FAQ debian/base/usr/share/doc/$(package)/.
|
||||||
|
gzip -9 debian/base/usr/share/doc/$(package)/FAQ
|
||||||
|
install -m 644 CHANGELOG debian/base/usr/share/doc/$(package)/changelog
|
||||||
|
gzip -9 debian/base/usr/share/doc/$(package)/changelog
|
||||||
|
install -m 644 CHANGELOG.archive debian/base/usr/share/doc/$(package)/changelog.archive
|
||||||
|
gzip -9 debian/base/usr/share/doc/$(package)/changelog.archive
|
||||||
|
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/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
|
||||||
|
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 \
|
||||||
|
gzip -9 $$f/man8/dnsmasq.8 ; \
|
||||||
|
fi \
|
||||||
|
done
|
||||||
|
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||||
|
strip -R .note -R .comment debian/base/usr/sbin/dnsmasq
|
||||||
|
endif
|
||||||
|
cd debian/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
|
||||||
|
dpkg-shlibdeps debian/base/usr/sbin/dnsmasq
|
||||||
|
dpkg-gencontrol -pdnsmasq-base -Pdebian/base
|
||||||
|
chown -R root.root debian/base
|
||||||
|
chmod -R g-ws debian/base
|
||||||
|
dpkg --build debian/base ..
|
||||||
|
|
||||||
|
ifeq ($(DEB_BUILD_ARCH_OS),linux)
|
||||||
|
rm -rf debian/utils
|
||||||
|
install -m 755 -d debian/utils/DEBIAN \
|
||||||
|
-d debian/utils/usr/share/man/man1 \
|
||||||
|
-d debian/utils/usr/bin \
|
||||||
|
-d debian/utils/usr/share/doc/dnsmasq-utils
|
||||||
|
make -C contrib/wrt PREFIX=/usr DESTDIR=`pwd`/debian/utils CFLAGS="$(CFLAGS)" COPTS="$(COPTS)" CC=gcc
|
||||||
|
install -m 755 contrib/wrt/dhcp_release debian/utils/usr/bin/dhcp_release
|
||||||
|
install -m 644 contrib/wrt/dhcp_release.1 debian/utils/usr/share/man/man1/dhcp_release.1
|
||||||
|
gzip -9 debian/utils/usr/share/man/man1/dhcp_release.1
|
||||||
|
install -m 755 contrib/wrt/dhcp_lease_time debian/utils/usr/bin/dhcp_lease_time
|
||||||
|
install -m 644 contrib/wrt/dhcp_lease_time.1 debian/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||||
|
install -m 644 debian/copyright debian/utils/usr/share/doc/dnsmasq-utils/copyright
|
||||||
|
install -m 644 debian/changelog debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||||
|
gzip -9 debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||||
|
gzip -9 debian/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||||
|
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||||
|
strip -R .note -R .comment debian/utils/usr/bin/dhcp_release
|
||||||
|
strip -R .note -R .comment debian/utils/usr/bin/dhcp_lease_time
|
||||||
|
endif
|
||||||
|
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
|
||||||
|
dpkg-shlibdeps -Tdebian/utils-substvars debian/utils/usr/bin/dhcp_release debian/utils/usr/bin/dhcp_lease_time
|
||||||
|
dpkg-gencontrol -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/utils
|
||||||
|
chown -R root.root debian/utils
|
||||||
|
chmod -R g-ws debian/utils
|
||||||
|
dpkg --build debian/utils ..
|
||||||
|
endif
|
||||||
|
|
||||||
|
define checkdir
|
||||||
|
test -f Makefile -a -f debian/rules
|
||||||
|
endef
|
||||||
|
|
||||||
|
# Below here is fairly generic really
|
||||||
|
|
||||||
|
binary: binary-arch binary-indep
|
||||||
|
|
||||||
|
build:
|
||||||
|
build-arch:
|
||||||
|
build-indep:
|
||||||
|
|
||||||
|
checkroot:
|
||||||
|
test root = "`whoami`"
|
||||||
|
|
||||||
|
.PHONY: binary binary-arch binary-indep clean checkroot
|
||||||
|
|
||||||
|
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
1.0
|
||||||
Vendored
+31
@@ -0,0 +1,31 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=A lightweight DHCP and caching DNS server
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=dbus
|
||||||
|
BusName=uk.org.thekelleys.dnsmasq
|
||||||
|
|
||||||
|
# Test the config file and refuse starting if it is not valid.
|
||||||
|
ExecStartPre=/usr/sbin/dnsmasq --test
|
||||||
|
|
||||||
|
# Enable DBus by default because we use DBus activation.
|
||||||
|
#
|
||||||
|
# Drop privileges and become the 'dnsmasq' user. It is recommended by dnsmasq
|
||||||
|
# upstream to run dnsmasq as an isolated user that does not run any other
|
||||||
|
# processes, owns no files and has no shell. The default 'nobody' user has a
|
||||||
|
# shell and might be used for other processes.
|
||||||
|
#
|
||||||
|
# Debian-specific: add /etc/dnsmasq.d to config search path (with the exception
|
||||||
|
# of .dpkg-*). Packages such as libvirt leave config files there.
|
||||||
|
#
|
||||||
|
# --pid-file without argument disables writing a PIDfile, we don't need one.
|
||||||
|
ExecStart=/usr/sbin/dnsmasq -k \
|
||||||
|
--enable-dbus \
|
||||||
|
--user=dnsmasq \
|
||||||
|
-7 /etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new \
|
||||||
|
--pid-file
|
||||||
|
|
||||||
|
ExecReload=/bin/kill -HUP $MAINPID
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
+70
-4
@@ -7,8 +7,8 @@
|
|||||||
# The following two options make you a better netizen, since they
|
# The following two options make you a better netizen, since they
|
||||||
# tell dnsmasq to filter out queries which the public DNS cannot
|
# tell dnsmasq to filter out queries which the public DNS cannot
|
||||||
# answer, and which load the servers (especially the root servers)
|
# answer, and which load the servers (especially the root servers)
|
||||||
# necessarily. If you have a dial-on-demand link they also stop
|
# unnecessarily. If you have a dial-on-demand link they also stop
|
||||||
# these requests from bringing up the link necessarily.
|
# these requests from bringing up the link unnecessarily.
|
||||||
|
|
||||||
# Never forward plain names (without a dot or domain part)
|
# Never forward plain names (without a dot or domain part)
|
||||||
#domain-needed
|
#domain-needed
|
||||||
@@ -157,11 +157,50 @@
|
|||||||
# an explicit netmask instead.
|
# an explicit netmask instead.
|
||||||
#dhcp-range=192.168.0.0,static
|
#dhcp-range=192.168.0.0,static
|
||||||
|
|
||||||
|
# Enable DHCPv6. Note that the prefix-length does not need to be specified
|
||||||
|
# and defaults to 64 if missing/
|
||||||
|
#dhcp-range=1234::2, 1234::500, 64, 12h
|
||||||
|
|
||||||
|
# Do Router Advertisements, BUT NOT DHCP for this subnet.
|
||||||
|
#dhcp-range=1234::, ra-only
|
||||||
|
|
||||||
|
# Do Router Advertisements, BUT NOT DHCP for this subnet, also try and
|
||||||
|
# add names to the DNS for the IPv6 address of SLAAC-configured dual-stack
|
||||||
|
# hosts. Use the DHCPv4 lease to derive the name, network segment and
|
||||||
|
# MAC address and assume that the host will also have an
|
||||||
|
# IPv6 address calculated using the SLAAC alogrithm.
|
||||||
|
#dhcp-range=1234::, ra-names
|
||||||
|
|
||||||
|
# Do Router Advertisements, BUT NOT DHCP for this subnet.
|
||||||
|
# Set the lifetime to 46 hours. (Note: minimum lifetime is 2 hours.)
|
||||||
|
#dhcp-range=1234::, ra-only, 48h
|
||||||
|
|
||||||
|
# Do DHCP and Router Advertisements for this subnet. Set the A bit in the RA
|
||||||
|
# so that clients can use SLAAC addresses as well as DHCP ones.
|
||||||
|
#dhcp-range=1234::2, 1234::500, slaac
|
||||||
|
|
||||||
|
# Do Router Advertisements and stateless DHCP for this subnet. Clients will
|
||||||
|
# not get addresses from DHCP, but they will get other configuration information.
|
||||||
|
# They will use SLAAC for addresses.
|
||||||
|
#dhcp-range=1234::, ra-stateless
|
||||||
|
|
||||||
|
# Do stateless DHCP, SLAAC, and generate DNS names for SLAAC addresses
|
||||||
|
# from DHCPv4 leases.
|
||||||
|
#dhcp-range=1234::, ra-stateless, ra-names
|
||||||
|
|
||||||
|
# Do router advertisements for all subnets where we're doing DHCPv6
|
||||||
|
# Unless overriden by ra-stateless, ra-names, et al, the router
|
||||||
|
# advertisements will have the M and O bits set, so that the clients
|
||||||
|
# get addresses and configuration from DHCPv6, and the A bit reset, so the
|
||||||
|
# clients don't use SLAAC addresses.
|
||||||
|
#enable-ra
|
||||||
|
|
||||||
# Supply parameters for specified hosts using DHCP. There are lots
|
# Supply parameters for specified hosts using DHCP. There are lots
|
||||||
# of valid alternatives, so we will give examples of each. Note that
|
# of valid alternatives, so we will give examples of each. Note that
|
||||||
# IP addresses DO NOT have to be in the range given above, they just
|
# IP addresses DO NOT have to be in the range given above, they just
|
||||||
# need to be on the same network. The order of the parameters in these
|
# need to be on the same network. The order of the parameters in these
|
||||||
# do not matter, it's permissible to give name,address and MAC in any order
|
# do not matter, it's permissible to give name, address and MAC in any
|
||||||
|
# order.
|
||||||
|
|
||||||
# Always allocate the host with Ethernet address 11:22:33:44:55:66
|
# Always allocate the host with Ethernet address 11:22:33:44:55:66
|
||||||
# The IP address 192.168.0.60
|
# The IP address 192.168.0.60
|
||||||
@@ -218,7 +257,13 @@
|
|||||||
# any machine with Ethernet address starting 11:22:33:
|
# any machine with Ethernet address starting 11:22:33:
|
||||||
#dhcp-host=11:22:33:*:*:*,set:red
|
#dhcp-host=11:22:33:*:*:*,set:red
|
||||||
|
|
||||||
# Ignore any clients which are specified in dhcp-host lines
|
# Give a fixed IPv6 address and name to client with
|
||||||
|
# DUID 00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2
|
||||||
|
# Note the MAC addresses CANNOT be used to identify DHCPv6 clients.
|
||||||
|
# Note also the they [] around the IPv6 address are obilgatory.
|
||||||
|
#dhcp-host=id:00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2, fred, [1234::5]
|
||||||
|
|
||||||
|
# Ignore any clients which are not specified in dhcp-host lines
|
||||||
# or /etc/ethers. Equivalent to ISC "deny unknown-clients".
|
# or /etc/ethers. Equivalent to ISC "deny unknown-clients".
|
||||||
# This relies on the special "known" tag which is set when
|
# This relies on the special "known" tag which is set when
|
||||||
# a host is matched.
|
# a host is matched.
|
||||||
@@ -269,6 +314,13 @@
|
|||||||
# Set the NTP time server addresses to 192.168.0.4 and 10.10.0.5
|
# Set the NTP time server addresses to 192.168.0.4 and 10.10.0.5
|
||||||
#dhcp-option=option:ntp-server,192.168.0.4,10.10.0.5
|
#dhcp-option=option:ntp-server,192.168.0.4,10.10.0.5
|
||||||
|
|
||||||
|
# Send DHCPv6 option. Note [] around IPv6 addresses.
|
||||||
|
#dhcp-option=option6:dns-server,[1234::77],[1234::88]
|
||||||
|
|
||||||
|
# Send DHCPv6 option for namservers as the machine running
|
||||||
|
# dnsmasq and another.
|
||||||
|
#dhcp-option=option6:dns-server,[::],[1234::88]
|
||||||
|
|
||||||
# Set the NTP time server address to be the same machine as
|
# Set the NTP time server address to be the same machine as
|
||||||
# is running dnsmasq
|
# is running dnsmasq
|
||||||
#dhcp-option=42,0.0.0.0
|
#dhcp-option=42,0.0.0.0
|
||||||
@@ -303,6 +355,9 @@
|
|||||||
#dhcp-option=45,0.0.0.0 # netbios datagram distribution server
|
#dhcp-option=45,0.0.0.0 # netbios datagram distribution server
|
||||||
#dhcp-option=46,8 # netbios node type
|
#dhcp-option=46,8 # netbios node type
|
||||||
|
|
||||||
|
# Send an empty WPAD option. This may be REQUIRED to get windows 7 to behave.
|
||||||
|
#dhcp-option=252,"\n"
|
||||||
|
|
||||||
# Send RFC-3397 DNS domain search DHCP option. WARNING: Your DHCP client
|
# Send RFC-3397 DNS domain search DHCP option. WARNING: Your DHCP client
|
||||||
# probably doesn't support this......
|
# probably doesn't support this......
|
||||||
#dhcp-option=option:domain-search,eng.apple.com,marketing.apple.com
|
#dhcp-option=option:domain-search,eng.apple.com,marketing.apple.com
|
||||||
@@ -347,6 +402,9 @@
|
|||||||
# external one. (See below for how to enable the TFTP server.)
|
# external one. (See below for how to enable the TFTP server.)
|
||||||
#dhcp-boot=pxelinux.0
|
#dhcp-boot=pxelinux.0
|
||||||
|
|
||||||
|
# The same as above, but use custom tftp-server instead machine running dnsmasq
|
||||||
|
#dhcp-boot=pxelinux,server.name,192.168.1.100
|
||||||
|
|
||||||
# Boot for Etherboot gPXE. The idea is to send two different
|
# Boot for Etherboot gPXE. The idea is to send two different
|
||||||
# filenames, the first loads gPXE, and the second tells gPXE what to
|
# filenames, the first loads gPXE, and the second tells gPXE what to
|
||||||
# load. The dhcp-match sets the gpxe tag for requests from gPXE.
|
# load. The dhcp-match sets the gpxe tag for requests from gPXE.
|
||||||
@@ -421,6 +479,14 @@
|
|||||||
# Can fail with old PXE ROMS. Overridden by --pxe-service.
|
# Can fail with old PXE ROMS. Overridden by --pxe-service.
|
||||||
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3
|
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3
|
||||||
|
|
||||||
|
# If there are multiple external tftp servers having a same name
|
||||||
|
# (using /etc/hosts) then that name can be specified as the
|
||||||
|
# tftp_servername (the third option to dhcp-boot) and in that
|
||||||
|
# case dnsmasq resolves this name and returns the resultant IP
|
||||||
|
# addresses in round robin fasion. This facility can be used to
|
||||||
|
# load balance the tftp load among a set of servers.
|
||||||
|
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,tftp_server_name
|
||||||
|
|
||||||
# Set the limit on DHCP leases, the default is 150
|
# Set the limit on DHCP leases, the default is 150
|
||||||
#dhcp-lease-max=150
|
#dhcp-lease-max=150
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ connection but would be a good choice for any smallish network (up to
|
|||||||
1000 clients is known to work) where low
|
1000 clients is known to work) where low
|
||||||
resource use and ease of configuration are important.
|
resource use and ease of configuration are important.
|
||||||
<P>
|
<P>
|
||||||
Supported platforms include Linux (with glibc and uclibc), *BSD,
|
Supported platforms include Linux (with glibc and uclibc), Android, *BSD,
|
||||||
Solaris and Mac OS X.
|
Solaris and Mac OS X.
|
||||||
Dnsmasq is included in at least the following Linux distributions:
|
Dnsmasq is included in at least the following Linux distributions:
|
||||||
Gentoo, Debian, Slackware, Suse, Fedora,
|
Gentoo, Debian, Slackware, Suse, Fedora,
|
||||||
@@ -88,24 +88,19 @@ for any or all local machines.
|
|||||||
</LI>
|
</LI>
|
||||||
</DIR>
|
</DIR>
|
||||||
|
|
||||||
<H2>Download.</H2>
|
<H2>Get code.</H2>
|
||||||
|
|
||||||
<A HREF="http://www.thekelleys.org.uk/dnsmasq/"> Download</A> dnsmasq here.
|
<A HREF="http://www.thekelleys.org.uk/dnsmasq/">Download</A> dnsmasq here.
|
||||||
The tarball includes this documentation, source, and manpage.
|
The tarball includes this documentation, source, and manpage.
|
||||||
There is also a <A HREF="CHANGELOG"> CHANGELOG</A> and a <A HREF="FAQ">FAQ</A>.
|
There is also a <A HREF="CHANGELOG"> CHANGELOG</A> and a <A HREF="FAQ">FAQ</A>.
|
||||||
Dnsmasq is part of the Debian distribution, it can be downloaded from
|
|
||||||
<A HREF="http://ftp.debian.org/debian/pool/main/d/dnsmasq/"> here</A> or installed using <TT>apt</TT>.
|
|
||||||
|
|
||||||
<H2>Links.</H2>
|
Dnsmasq has a git repository which contains the complete release
|
||||||
Damien Raude-Morvan has an article in French at <A HREF="http://www.drazzib.com/docs-dnsmasq.html">http://www.drazzib.com/docs-dnsmasq.html</A>
|
history of version 2 and development history from 2.60. You can
|
||||||
There is a good article about dnsmasq at <A
|
<A HREF="http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=summary">browse</A>
|
||||||
HREF="http://www.enterprisenetworkingplanet.com/netos/article.php/3377351">http://www.enterprisenetworkingplanet.com/netos/article.php/3377351</A>
|
the repo, or get a copy using git protocol with the command
|
||||||
and another at <A
|
|
||||||
HREF="http://www.linux.com/articles/149040">http://www.linux.com/articles/149040</A>
|
<PRE><TT>git clone git://thekelleys.org.uk/dnsmasq.git </TT></PRE>
|
||||||
and Ilya Evseev has an article in Russian about dnsmasq to be found at
|
|
||||||
<A HREF="http://ilya-evseev.narod.ru/articles/dnsmasq">
|
|
||||||
http://ilya-evseev.narod.ru/articles/dnsmasq</A>. Ismael Ull has an
|
|
||||||
article about dnsmasq in Spanish at <A HREF="http://www.mey-online.com.ar/blog/index.php/archives/guia-rapida-de-dnsmasq">http://www.mey-online.com.ar/blog/index.php/archives/guia-rapida-de-dnsmasq</A>
|
|
||||||
<H2>License.</H2>
|
<H2>License.</H2>
|
||||||
Dnsmasq is distributed under the GPL. See the file COPYING in the distribution
|
Dnsmasq is distributed under the GPL. See the file COPYING in the distribution
|
||||||
for details.
|
for details.
|
||||||
|
|||||||
+316
-58
@@ -23,7 +23,7 @@ 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.
|
||||||
.PP
|
.PP
|
||||||
Dnsmasq
|
Dnsmasq
|
||||||
supports IPv6 for DNS and TFTP, but not DHCP.
|
supports IPv6 for all functions and a minimal router-advertisemnet daemon.
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
Note that in general missing parameters are allowed and switch off
|
Note that in general missing parameters are allowed and switch off
|
||||||
functions, for instance "--pid-file" disables writing a PID file. On
|
functions, for instance "--pid-file" disables writing a PID file. On
|
||||||
@@ -51,7 +51,7 @@ apply to domain names in cnames, PTR records, TXT records etc.
|
|||||||
.B \-T, --local-ttl=<time>
|
.B \-T, --local-ttl=<time>
|
||||||
When replying with information from /etc/hosts or the DHCP leases
|
When replying with information from /etc/hosts or the DHCP leases
|
||||||
file dnsmasq by default sets the time-to-live field to zero, meaning
|
file dnsmasq by default sets the time-to-live field to zero, meaning
|
||||||
that the requestor should not itself cache the information. This is
|
that the requester should not itself cache the information. This is
|
||||||
the correct thing to do in almost all situations. This option allows a
|
the correct thing to do in almost all situations. This option allows a
|
||||||
time-to-live (in seconds) to be given for these replies. This will
|
time-to-live (in seconds) to be given for these replies. This will
|
||||||
reduce the load on the server at the expense of clients using stale
|
reduce the load on the server at the expense of clients using stale
|
||||||
@@ -249,8 +249,8 @@ requested name has underscores, to catch LDAP requests.
|
|||||||
.B \-r, --resolv-file=<file>
|
.B \-r, --resolv-file=<file>
|
||||||
Read the IP addresses of the upstream nameservers from <file>, instead of
|
Read the IP addresses of the upstream nameservers from <file>, instead of
|
||||||
/etc/resolv.conf. For the format of this file see
|
/etc/resolv.conf. For the format of this file see
|
||||||
.BR resolv.conf (5)
|
.BR resolv.conf (5).
|
||||||
the only lines relevant to dnsmasq are nameserver ones. Dnsmasq can
|
The only lines relevant to dnsmasq are nameserver ones. Dnsmasq can
|
||||||
be told to poll more than one resolv.conf file, the first file name specified
|
be told to poll more than one resolv.conf file, the first file name specified
|
||||||
overrides the default, subsequent ones add to the list. This is only
|
overrides the default, subsequent ones add to the list. This is only
|
||||||
allowed when polling; the file with the currently latest modification
|
allowed when polling; the file with the currently latest modification
|
||||||
@@ -276,7 +276,7 @@ server strictly in the order they appear in /etc/resolv.conf
|
|||||||
By default, when dnsmasq has more than one upstream server available,
|
By default, when dnsmasq has more than one upstream server available,
|
||||||
it will send queries to just one server. Setting this flag forces
|
it will send queries to just one server. Setting this flag forces
|
||||||
dnsmasq to send all queries to all available servers. The reply from
|
dnsmasq to send all queries to all available servers. The reply from
|
||||||
the server which answers first will be returned to the original requestor.
|
the server which answers first will be returned to the original requester.
|
||||||
.TP
|
.TP
|
||||||
.B --stop-dns-rebind
|
.B --stop-dns-rebind
|
||||||
Reject (and log) addresses from upstream nameservers which are in the
|
Reject (and log) addresses from upstream nameservers which are in the
|
||||||
@@ -303,7 +303,7 @@ This is useful when new nameservers may have different
|
|||||||
data than that held in cache.
|
data than that held in cache.
|
||||||
.TP
|
.TP
|
||||||
.B \-D, --domain-needed
|
.B \-D, --domain-needed
|
||||||
Tells dnsmasq to never forward queries for plain names, without dots
|
Tells dnsmasq to never forward A or AAAA queries for plain names, without dots
|
||||||
or domain parts, to upstream nameservers. If the name is not known
|
or domain parts, to upstream nameservers. If the name is not known
|
||||||
from /etc/hosts or DHCP then a "not found" answer is returned.
|
from /etc/hosts or DHCP then a "not found" answer is returned.
|
||||||
.TP
|
.TP
|
||||||
@@ -350,6 +350,9 @@ is a synonym for
|
|||||||
.B server
|
.B server
|
||||||
to make configuration files clearer in this case.
|
to make configuration files clearer in this case.
|
||||||
|
|
||||||
|
IPv6 addresses may include a %interface scope-id, eg
|
||||||
|
fe80::202:a412:4512:7bbf%eth0.
|
||||||
|
|
||||||
The optional string after the @ character tells
|
The optional string after the @ character tells
|
||||||
dnsmasq how to set the source of the queries to this
|
dnsmasq how to set the source of the queries to this
|
||||||
nameserver. It should be an ip-address, which should belong to the machine on which
|
nameserver. It should be an ip-address, which should belong to the machine on which
|
||||||
@@ -413,6 +416,22 @@ zone files: the port, weight and priority numbers are in a different
|
|||||||
order. More than one SRV record for a given service/domain is allowed,
|
order. More than one SRV record for a given service/domain is allowed,
|
||||||
all that match are returned.
|
all that match are returned.
|
||||||
.TP
|
.TP
|
||||||
|
.B --host-record=<name>[,<name>....][<IPv4-address>],[IPv6-address]
|
||||||
|
Add A, AAAA and PTR records to the DNS. This adds one or more names to
|
||||||
|
the DNS with associated IPv4 (A) and IPv6 (AAAA) records. A name may
|
||||||
|
appear in more than one
|
||||||
|
.B host-record
|
||||||
|
and therefore be assigned more than one address. Only the first
|
||||||
|
address creates a PTR record linking the address to the name. This is
|
||||||
|
the same rule as is used reading hosts-files.
|
||||||
|
.B host-record
|
||||||
|
options are considered to be read before host-files, so a name
|
||||||
|
appearing there inhibits PTR-record creation if it appears in
|
||||||
|
hosts-file also. Unlike host-files, names are not expanded, even when
|
||||||
|
.B expand-hosts
|
||||||
|
is in effect. Short and long names may appear in the same
|
||||||
|
.B host-record, eg. --host-record=laptop,laptop.thekelleys.org,192.168.0.1,1234::100
|
||||||
|
.TP
|
||||||
.B \-Y, --txt-record=<name>[[,<text>],<text>]
|
.B \-Y, --txt-record=<name>[[,<text>],<text>]
|
||||||
Return a TXT DNS record. The value of TXT record is a set of strings,
|
Return a TXT DNS record. The value of TXT record is a set of strings,
|
||||||
so any number may be included, delimited by commas; use quotes to put
|
so any number may be included, delimited by commas; use quotes to put
|
||||||
@@ -481,7 +500,20 @@ If you use the first DNSSEC mode, validating resolvers in clients,
|
|||||||
this option is not required. Dnsmasq always returns all the data
|
this option is not required. Dnsmasq always returns all the data
|
||||||
needed for a client to do validation itself.
|
needed for a client to do validation itself.
|
||||||
.TP
|
.TP
|
||||||
.B \-F, --dhcp-range=[interface:<interface>,][tag:<tag>[,tag:<tag>],][set:<tag],]<start-addr>,<end-addr>[,<netmask>[,<broadcast>]][,<lease time>]
|
.B --conntrack
|
||||||
|
Read the Linux connection track mark associated with incoming DNS
|
||||||
|
queries and set the same mark value on upstream traffic used to answer
|
||||||
|
those queries. This allows traffic generated by dnsmasq to be
|
||||||
|
associated with the queries which cause it, useful for bandwidth
|
||||||
|
accounting and firewalling. Dnsmasq must have conntrack support
|
||||||
|
compiled in and the kernel must have conntrack support
|
||||||
|
included and configured. This option cannot be combined with
|
||||||
|
--query-port.
|
||||||
|
.TP
|
||||||
|
.B \-F, --dhcp-range=[interface:<interface>,][tag:<tag>[,tag:<tag>],][set:<tag],]<start-addr>[,<end-addr>][,<mode>][,<netmask>[,<broadcast>]][,<lease time>]
|
||||||
|
.TP
|
||||||
|
.B \-F, --dhcp-range=[interface:<interface>,][tag:<tag>[,tag:<tag>],][set:<tag],]<start-IPv6addr>[,<end-IPv6addr>][,<mode>][,<prefix-len>][,<lease time>]
|
||||||
|
|
||||||
Enable the DHCP server. Addresses will be given out from the range
|
Enable the DHCP server. Addresses will be given out from the range
|
||||||
<start-addr> to <end-addr> and from statically defined addresses given
|
<start-addr> to <end-addr> and from statically defined addresses given
|
||||||
in
|
in
|
||||||
@@ -490,29 +522,45 @@ options. If the lease time is given, then leases
|
|||||||
will be given for that length of time. The lease time is in seconds,
|
will be given for that length of time. The lease time is in seconds,
|
||||||
or minutes (eg 45m) or hours (eg 1h) or "infinite". If not given,
|
or minutes (eg 45m) or hours (eg 1h) or "infinite". If not given,
|
||||||
the default lease time is one hour. The
|
the default lease time is one hour. The
|
||||||
minimum lease time is two minutes. This
|
minimum lease time is two minutes. For IPv6 ranges, the lease time
|
||||||
option may be repeated, with different addresses, to enable DHCP
|
maybe "deprecated"; this sets the preferred lifetime sent in a DHCP
|
||||||
|
lease or router advertisement to zero, which causes clients to use
|
||||||
|
other addresses, if available, for new connections as a prelude to renumbering.
|
||||||
|
|
||||||
|
This option may be repeated, with different addresses, to enable DHCP
|
||||||
service to more than one network. For directly connected networks (ie,
|
service to more than one network. For directly connected networks (ie,
|
||||||
networks on which the machine running dnsmasq has an interface) the
|
networks on which the machine running dnsmasq has an interface) the
|
||||||
netmask is optional. It is, however, required for networks which
|
netmask is optional: dnsmasq will determine it from the interface
|
||||||
receive DHCP service via a relay agent. The broadcast address is
|
configuration. For networks which receive DHCP service via a relay
|
||||||
|
agent, dnsmasq cannot determine the netmask itself, so it should be
|
||||||
|
specified, otherwise dnsmasq will have to guess, based on the class (A, B or
|
||||||
|
C) of the network address. The broadcast address is
|
||||||
always optional. It is always
|
always optional. It is always
|
||||||
allowed to have more than one dhcp-range in a single subnet.
|
allowed to have more than one dhcp-range in a single subnet.
|
||||||
|
|
||||||
|
For IPv6, the parameters are slightly different: instead of netmask
|
||||||
|
and broadcast address, there is an optional prefix length. If not
|
||||||
|
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.
|
||||||
|
|
||||||
The optional
|
The optional
|
||||||
.B set:<tag>
|
.B set:<tag>
|
||||||
sets an alphanumeric label which marks this network so that
|
sets an alphanumeric label which marks this network so that
|
||||||
dhcp options may be specified on a per-network basis.
|
dhcp options may be specified on a per-network basis.
|
||||||
When it is prefixed with 'tag:' instead, then its meaning changes from setting
|
When it is prefixed with 'tag:' instead, then its meaning changes from setting
|
||||||
a tag to matching it. Only one tag may be set, but more than one tag may be matched.
|
a tag to matching it. Only one tag may be set, but more than one tag
|
||||||
The end address may be replaced by the keyword
|
may be matched.
|
||||||
|
|
||||||
|
The optional <mode> keyword may be
|
||||||
.B static
|
.B static
|
||||||
which tells dnsmasq to enable DHCP for the network specified, but not
|
which tells dnsmasq to enable DHCP for the network specified, but not
|
||||||
to dynamically allocate IP addresses: only hosts which have static
|
to dynamically allocate IP addresses: only hosts which have static
|
||||||
addresses given via
|
addresses given via
|
||||||
.B dhcp-host
|
.B dhcp-host
|
||||||
or from /etc/ethers will be served. The end address may be replaced by
|
or from /etc/ethers will be served.
|
||||||
the keyword
|
|
||||||
|
Fot IPv4, the <mode> may be
|
||||||
.B proxy
|
.B proxy
|
||||||
in which case dnsmasq will provide proxy-DHCP on the specified
|
in which case dnsmasq will provide proxy-DHCP on the specified
|
||||||
subnet. (See
|
subnet. (See
|
||||||
@@ -521,6 +569,42 @@ and
|
|||||||
.B pxe-service
|
.B pxe-service
|
||||||
for details.)
|
for details.)
|
||||||
|
|
||||||
|
For IPv6, the mode may be some combination of
|
||||||
|
.B ra-only, slaac, ra-names, ra-stateless.
|
||||||
|
|
||||||
|
.B ra-only
|
||||||
|
tells dnsmasq to offer Router Advertisement only on this subnet,
|
||||||
|
and not DHCP.
|
||||||
|
|
||||||
|
.B slaac
|
||||||
|
tells dnsmasq to offer Router Advertisement on this subnet and to set
|
||||||
|
the A bit in the router advertisement, so that the client will use
|
||||||
|
SLAAC addresses. When used with a DHCP range or static DHCP address
|
||||||
|
this results in the client having both a DHCP-assigned and a SLAAC
|
||||||
|
address.
|
||||||
|
|
||||||
|
.B ra-stateless
|
||||||
|
sends router advertisements with the O and A bits set, and provides a
|
||||||
|
stateless DHCP service. The client will use a SLAAC address, and use
|
||||||
|
DHCP for other configuration information.
|
||||||
|
|
||||||
|
.B ra-names
|
||||||
|
enables a mode
|
||||||
|
which gives DNS names to dual-stack hosts which do SLAAC for
|
||||||
|
IPv6. Dnsmasq uses the host's IPv4 lease to derive the name, network
|
||||||
|
segment and MAC address and assumes that the host will also have an
|
||||||
|
IPv6 address calculated using the SLAAC alogrithm, on the same network
|
||||||
|
segment. The address is pinged, and if a reply is received, an AAAA
|
||||||
|
record is added to the DNS for this IPv6
|
||||||
|
address. Note that this is only happens for directly-connected
|
||||||
|
networks, (not one doing DHCP via a relay) and it will not work
|
||||||
|
if a host is using privacy extensions.
|
||||||
|
.B ra-names
|
||||||
|
can be combined with
|
||||||
|
.B ra-stateless
|
||||||
|
and
|
||||||
|
.B slaac.
|
||||||
|
|
||||||
The interface:<interface name> section is not normally used. See the
|
The interface:<interface name> section is not normally used. See the
|
||||||
NOTES section for details of this.
|
NOTES section for details of this.
|
||||||
.TP
|
.TP
|
||||||
@@ -529,7 +613,7 @@ Specify per host parameters for the DHCP server. This allows a machine
|
|||||||
with a particular hardware address to be always allocated the same
|
with a particular hardware address to be always allocated the same
|
||||||
hostname, IP address and lease time. A hostname specified like this
|
hostname, IP address and lease time. A hostname specified like this
|
||||||
overrides any supplied by the DHCP client on the machine. It is also
|
overrides any supplied by the DHCP client on the machine. It is also
|
||||||
allowable to ommit the hardware address and include the hostname, in
|
allowable to omit the hardware address and include the hostname, in
|
||||||
which case the IP address and lease times will apply to any machine
|
which case the IP address and lease times will apply to any machine
|
||||||
claiming that name. For example
|
claiming that name. For example
|
||||||
.B --dhcp-host=00:20:e0:3b:13:af,wap,infinite
|
.B --dhcp-host=00:20:e0:3b:13:af,wap,infinite
|
||||||
@@ -554,6 +638,12 @@ refers to the host with client identifier 01:02:03:04. It is also
|
|||||||
allowed to specify the client ID as text, like this:
|
allowed to specify the client ID as text, like this:
|
||||||
.B --dhcp-host=id:clientidastext,.....
|
.B --dhcp-host=id:clientidastext,.....
|
||||||
|
|
||||||
|
A single
|
||||||
|
.B dhcp-host
|
||||||
|
may contain an IPv4 address or an IPv6 address, or both. IPv6 addresses must be bracketed by square brackets thus:
|
||||||
|
.B --dhcp-host=laptop,[1234::56]
|
||||||
|
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
|
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
|
and use MAC addresses only." This is useful when a client presents a client-id sometimes
|
||||||
but not others.
|
but not others.
|
||||||
@@ -601,7 +691,7 @@ will only match a
|
|||||||
Token-Ring hardware address, since the ARP-address type for token ring
|
Token-Ring hardware address, since the ARP-address type for token ring
|
||||||
is 6.
|
is 6.
|
||||||
|
|
||||||
As a special case, it is possible to include more than one
|
As a special case, in DHCPv4, it is possible to include more than one
|
||||||
hardware address. eg:
|
hardware address. eg:
|
||||||
.B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2
|
.B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2
|
||||||
This allows an IP address to be associated with
|
This allows an IP address to be associated with
|
||||||
@@ -639,14 +729,14 @@ hostname or dotted-quad IP address. When read by dnsmasq these lines
|
|||||||
have exactly the same effect as
|
have exactly the same effect as
|
||||||
.B --dhcp-host
|
.B --dhcp-host
|
||||||
options containing the same information. /etc/ethers is re-read when
|
options containing the same information. /etc/ethers is re-read when
|
||||||
dnsmasq receives SIGHUP.
|
dnsmasq receives SIGHUP. IPv6 addresses are NOT read from /etc/ethers.
|
||||||
.TP
|
.TP
|
||||||
.B \-O, --dhcp-option=[tag:<tag>,[tag:<tag>,]][encap:<opt>,][vi-encap:<enterprise>,][vendor:[<vendor-class>],][<opt>|option:<opt-name>],[<value>[,<value>]]
|
.B \-O, --dhcp-option=[tag:<tag>,[tag:<tag>,]][encap:<opt>,][vi-encap:<enterprise>,][vendor:[<vendor-class>],][<opt>|option:<opt-name>|option6:<opt>|option6:<opt-name>],[<value>[,<value>]]
|
||||||
Specify different or extra options to DHCP clients. By default,
|
Specify different or extra options to DHCP clients. By default,
|
||||||
dnsmasq sends some standard options to DHCP clients, the netmask and
|
dnsmasq sends some standard options to DHCP clients, the netmask and
|
||||||
broadcast address are set to the same as the host running dnsmasq, and
|
broadcast address are set to the same as the host running dnsmasq, and
|
||||||
the DNS server and default route are set to the address of the machine
|
the DNS server and default route are set to the address of the machine
|
||||||
running dnsmasq. If the domain name option has been set, that is sent.
|
running dnsmasq. (Equivalent rules apply for IPv6.) If the domain name option has been set, that is sent.
|
||||||
This configuration allows these defaults to be overridden,
|
This configuration allows these defaults to be overridden,
|
||||||
or other options specified. The option, to be sent may be given as a
|
or other options specified. The option, to be sent may be given as a
|
||||||
decimal number or as "option:<option-name>" The option numbers are
|
decimal number or as "option:<option-name>" The option numbers are
|
||||||
@@ -661,7 +751,7 @@ and to set the time-server address to 192.168.0.4, do
|
|||||||
.B --dhcp-option = 42,192.168.0.4
|
.B --dhcp-option = 42,192.168.0.4
|
||||||
or
|
or
|
||||||
.B --dhcp-option = option:ntp-server, 192.168.0.4
|
.B --dhcp-option = option:ntp-server, 192.168.0.4
|
||||||
The special address 0.0.0.0 is taken to mean "the address of the
|
The special address 0.0.0.0 (or [::] for DHCPv6) is taken to mean "the address of the
|
||||||
machine running dnsmasq". Data types allowed are comma separated
|
machine running dnsmasq". Data types allowed are comma separated
|
||||||
dotted-quad IP addresses, a decimal number, colon-separated hex digits
|
dotted-quad IP addresses, a decimal number, colon-separated hex digits
|
||||||
and a text string. If the optional tags are given then
|
and a text string. If the optional tags are given then
|
||||||
@@ -673,6 +763,14 @@ to option 120 are handled as per RFC 3361. Dotted-quad IP addresses
|
|||||||
which are followed by a slash and then a netmask size are encoded as
|
which are followed by a slash and then a netmask size are encoded as
|
||||||
described in RFC 3442.
|
described in RFC 3442.
|
||||||
|
|
||||||
|
IPv6 options are specified using the
|
||||||
|
.B option6:
|
||||||
|
keyword, followed by the option number or option name. The IPv6 option
|
||||||
|
name space is disjoint from the IPv4 option name space. IPv6 addresses
|
||||||
|
in options must be bracketed with square brackets, eg.
|
||||||
|
.B --dhcp-option=option6:ntp-server,[1234::56]
|
||||||
|
|
||||||
|
|
||||||
Be careful: no checking is done that the correct type of data for the
|
Be careful: no checking is done that the correct type of data for the
|
||||||
option number is sent, it is quite possible to
|
option number is sent, it is quite possible to
|
||||||
persuade dnsmasq to generate illegal DHCP packets with injudicious use
|
persuade dnsmasq to generate illegal DHCP packets with injudicious use
|
||||||
@@ -688,7 +786,7 @@ literal string, use quotes. For instance when using option 66 to send
|
|||||||
a literal IP address as TFTP server name, it is necessary to do
|
a literal IP address as TFTP server name, it is necessary to do
|
||||||
.B --dhcp-option=66,"1.2.3.4"
|
.B --dhcp-option=66,"1.2.3.4"
|
||||||
|
|
||||||
Encapsulated Vendor-class options may also be specified using
|
Encapsulated Vendor-class options may also be specified (IPv4 only) using
|
||||||
--dhcp-option: for instance
|
--dhcp-option: for instance
|
||||||
.B --dhcp-option=vendor:PXEClient,1,0.0.0.0
|
.B --dhcp-option=vendor:PXEClient,1,0.0.0.0
|
||||||
sends the encapsulated vendor
|
sends the encapsulated vendor
|
||||||
@@ -700,9 +798,9 @@ for selecting encapsulated options in preference to any sent by the
|
|||||||
client. It is
|
client. It is
|
||||||
possible to omit the vendorclass completely;
|
possible to omit the vendorclass completely;
|
||||||
.B --dhcp-option=vendor:,1,0.0.0.0
|
.B --dhcp-option=vendor:,1,0.0.0.0
|
||||||
in which case the encapsulated option is always sent.
|
in which case the encapsulated option is always sent.
|
||||||
|
|
||||||
Options may be encapsulated within other options: for instance
|
Options may be encapsulated (IPv4 only) within other options: for instance
|
||||||
.B --dhcp-option=encap:175, 190, "iscsi-client0"
|
.B --dhcp-option=encap:175, 190, "iscsi-client0"
|
||||||
will send option 175, within which is the option 190. If multiple
|
will send option 175, within which is the option 190. If multiple
|
||||||
options are given which are encapsulated with the same option number
|
options are given which are encapsulated with the same option number
|
||||||
@@ -713,8 +811,9 @@ The final variant on encapsulated options is "Vendor-Identifying
|
|||||||
Vendor Options" as specified by RFC3925. These are denoted like this:
|
Vendor Options" as specified by RFC3925. These are denoted like this:
|
||||||
.B --dhcp-option=vi-encap:2, 10, "text"
|
.B --dhcp-option=vi-encap:2, 10, "text"
|
||||||
The number in the vi-encap: section is the IANA enterprise number
|
The number in the vi-encap: section is the IANA enterprise number
|
||||||
used to identify this option.
|
used to identify this option. This form of encapsulation is supported
|
||||||
|
in IPv6.
|
||||||
|
|
||||||
The address 0.0.0.0 is not treated specially in
|
The address 0.0.0.0 is not treated specially in
|
||||||
encapsulated options.
|
encapsulated options.
|
||||||
.TP
|
.TP
|
||||||
@@ -726,14 +825,14 @@ not ask for it in the parameter request list. This is sometimes
|
|||||||
needed, for example when sending options to PXELinux.
|
needed, for example when sending options to PXELinux.
|
||||||
.TP
|
.TP
|
||||||
.B --dhcp-no-override
|
.B --dhcp-no-override
|
||||||
Disable re-use of the DHCP servername and filename fields as extra
|
(IPv4 only) Disable re-use of the DHCP servername and filename fields as extra
|
||||||
option space. If it can, dnsmasq moves the boot server and filename
|
option space. If it can, dnsmasq moves the boot server and filename
|
||||||
information (from dhcp-boot) out of their dedicated fields into
|
information (from dhcp-boot) out of their dedicated fields into
|
||||||
DHCP options. This make extra space available in the DHCP packet for
|
DHCP options. This make extra space available in the DHCP packet for
|
||||||
options but can, rarely, confuse old or broken clients. This flag
|
options but can, rarely, confuse old or broken clients. This flag
|
||||||
forces "simple and safe" behaviour to avoid problems in such a case.
|
forces "simple and safe" behaviour to avoid problems in such a case.
|
||||||
.TP
|
.TP
|
||||||
.B \-U, --dhcp-vendorclass=set:<tag>,<vendor-class>
|
.B \-U, --dhcp-vendorclass=set:<tag>,[enterprise:<IANA-enterprise number>,]<vendor-class>
|
||||||
Map from a vendor-class string to a tag. Most DHCP clients provide a
|
Map from a vendor-class string to a tag. Most DHCP clients provide a
|
||||||
"vendor class" which represents, in some sense, the type of host. This option
|
"vendor class" which represents, in some sense, the type of host. This option
|
||||||
maps vendor classes to tags, so that DHCP options may be selectively delivered
|
maps vendor classes to tags, so that DHCP options may be selectively delivered
|
||||||
@@ -743,7 +842,13 @@ will allow options to be set only for HP printers like so:
|
|||||||
.B --dhcp-option=tag:printers,3,192.168.4.4
|
.B --dhcp-option=tag:printers,3,192.168.4.4
|
||||||
The vendor-class string is
|
The vendor-class string is
|
||||||
substring matched against the vendor-class supplied by the client, to
|
substring matched against the vendor-class supplied by the client, to
|
||||||
allow fuzzy matching. The set: prefix is optional but allowed for consistency.
|
allow fuzzy matching. The set: prefix is optional but allowed for
|
||||||
|
consistency.
|
||||||
|
|
||||||
|
Note that in IPv6 only, vendorclasses are namespaced with an
|
||||||
|
IANA-allocated enterprise number. This is given with enterprise:
|
||||||
|
keyword and specifies that only vendorclasses matching the specified
|
||||||
|
number should be searched.
|
||||||
.TP
|
.TP
|
||||||
.B \-j, --dhcp-userclass=set:<tag>,<user-class>
|
.B \-j, --dhcp-userclass=set:<tag>,<user-class>
|
||||||
Map from a user-class string to a tag (with substring
|
Map from a user-class string to a tag (with substring
|
||||||
@@ -755,7 +860,7 @@ this to set a different printer server for hosts in the class
|
|||||||
"accounts" than for hosts in the class "engineering".
|
"accounts" than for hosts in the class "engineering".
|
||||||
.TP
|
.TP
|
||||||
.B \-4, --dhcp-mac=set:<tag>,<MAC address>
|
.B \-4, --dhcp-mac=set:<tag>,<MAC address>
|
||||||
Map from a MAC address to a tag. The MAC address may include
|
(IPv4 only) Map from a MAC address to a tag. The MAC address may include
|
||||||
wildcards. For example
|
wildcards. For example
|
||||||
.B --dhcp-mac=set:3com,01:34:23:*:*:*
|
.B --dhcp-mac=set:3com,01:34:23:*:*:*
|
||||||
will set the tag "3com" for any host whose MAC address matches the pattern.
|
will set the tag "3com" for any host whose MAC address matches the pattern.
|
||||||
@@ -765,13 +870,16 @@ Map from RFC3046 relay agent options to tags. This data may
|
|||||||
be provided by DHCP relay agents. The circuit-id or remote-id is
|
be provided by DHCP relay agents. The circuit-id or remote-id is
|
||||||
normally given as colon-separated hex, but is also allowed to be a
|
normally given as colon-separated hex, but is also allowed to be a
|
||||||
simple string. If an exact match is achieved between the circuit or
|
simple string. If an exact match is achieved between the circuit or
|
||||||
agent ID and one provided by a relay agent, the tag is set.
|
agent ID and one provided by a relay agent, the tag is set.
|
||||||
|
|
||||||
|
.B dhcp-remoteid
|
||||||
|
(but not dhcp-circuitid) is supported in IPv6.
|
||||||
.TP
|
.TP
|
||||||
.B --dhcp-subscrid=set:<tag>,<subscriber-id>
|
.B --dhcp-subscrid=set:<tag>,<subscriber-id>
|
||||||
Map from RFC3993 subscriber-id relay agent options to tags.
|
(IPv4 and IPv6) Map from RFC3993 subscriber-id relay agent options to tags.
|
||||||
.TP
|
.TP
|
||||||
.B --dhcp-proxy[=<ip addr>]......
|
.B --dhcp-proxy[=<ip addr>]......
|
||||||
A normal DHCP relay agent is only used to forward the initial parts of
|
(IPv4 only) A normal DHCP relay agent is only used to forward the initial parts of
|
||||||
a DHCP interaction to the DHCP server. Once a client is configured, it
|
a DHCP interaction to the DHCP server. Once a client is configured, it
|
||||||
communicates directly with the server. This is undesirable if the
|
communicates directly with the server. This is undesirable if the
|
||||||
relay agent is addding extra information to the DHCP packets, such as
|
relay agent is addding extra information to the DHCP packets, such as
|
||||||
@@ -831,7 +939,7 @@ dhcp-host configuration in dnsmasq and the contents of /etc/hosts and
|
|||||||
/etc/ethers.
|
/etc/ethers.
|
||||||
.TP
|
.TP
|
||||||
.B --dhcp-generate-names=tag:<tag>[,tag:<tag>]
|
.B --dhcp-generate-names=tag:<tag>[,tag:<tag>]
|
||||||
Generate a name for DHCP clients which do not otherwise have one,
|
(IPv4 only) Generate a name for DHCP clients which do not otherwise have one,
|
||||||
using the MAC address expressed in hex, seperated by dashes. Note that
|
using the MAC address expressed in hex, seperated by dashes. Note that
|
||||||
if a host provides a name, it will be used by preference to this,
|
if a host provides a name, it will be used by preference to this,
|
||||||
unless
|
unless
|
||||||
@@ -839,14 +947,14 @@ unless
|
|||||||
is set.
|
is set.
|
||||||
.TP
|
.TP
|
||||||
.B --dhcp-broadcast[=tag:<tag>[,tag:<tag>]]
|
.B --dhcp-broadcast[=tag:<tag>[,tag:<tag>]]
|
||||||
When all the given tags appear in the tag set, always use broadcast to
|
(IPv4 only) When all the given tags appear in the tag set, always use broadcast to
|
||||||
communicate with the host when it is unconfigured. It is permissible
|
communicate with the host when it is unconfigured. It is permissible
|
||||||
to supply no tags, in which case this is unconditional. Most DHCP clients which
|
to supply no tags, in which case this is unconditional. Most DHCP clients which
|
||||||
need broadcast replies set a flag in their requests so that this
|
need broadcast replies set a flag in their requests so that this
|
||||||
happens automatically, some old BOOTP clients do not.
|
happens automatically, some old BOOTP clients do not.
|
||||||
.TP
|
.TP
|
||||||
.B \-M, --dhcp-boot=[tag:<tag>,]<filename>,[<servername>[,<server address>]]
|
.B \-M, --dhcp-boot=[tag:<tag>,]<filename>,[<servername>[,<server address>|<tftp_servername>]]
|
||||||
Set BOOTP options to be returned by the DHCP server. Server name and
|
(IPv4 only) Set BOOTP options to be returned by the DHCP server. Server name and
|
||||||
address are optional: if not provided, the name is left empty, and the
|
address are optional: if not provided, the name is left empty, and the
|
||||||
address set to the address of the machine running dnsmasq. If dnsmasq
|
address set to the address of the machine running dnsmasq. If dnsmasq
|
||||||
is providing a TFTP service (see
|
is providing a TFTP service (see
|
||||||
@@ -854,8 +962,25 @@ is providing a TFTP service (see
|
|||||||
) then only the filename is required here to enable network booting.
|
) then only the filename is required here to enable network booting.
|
||||||
If the optional tag(s) are given,
|
If the optional tag(s) are given,
|
||||||
they must match for this configuration to be sent.
|
they must match for this configuration to be sent.
|
||||||
|
Instead of an IP address, the TFTP server address can be given as a domain
|
||||||
|
name which is looked up in /etc/hosts. This name can be associated in
|
||||||
|
/etc/hosts with multiple IP addresses, which are used round-robin.
|
||||||
|
This facility can be used to load balance the tftp load among a set of servers.
|
||||||
.TP
|
.TP
|
||||||
.B --pxe-service=[tag:<tag>,]<CSA>,<menu text>[,<basename>|<bootservicetype>][,<server address>]
|
.B --dhcp-sequential-ip
|
||||||
|
Dnsmasq is designed to choose IP addresses for DHCP clients using a
|
||||||
|
hash of the client's MAC address. This normally allows a client's
|
||||||
|
address to remain stable long-term, even if the client sometimes allows its DHCP
|
||||||
|
lease to expire. In this default mode IP addresses are distributed
|
||||||
|
pseudo-randomly over the entire available address range. There are
|
||||||
|
sometimes circumstances (typically server deployment) where it is more
|
||||||
|
convenient to have IP
|
||||||
|
addresses allocated sequentially, starting from the lowest available
|
||||||
|
address, and setting this flag enables this mode. Note that in the
|
||||||
|
sequential mode, clients which allow a lease to expire are much more
|
||||||
|
likely to move IP address; for this reason it should not be generally used.
|
||||||
|
.TP
|
||||||
|
.B --pxe-service=[tag:<tag>,]<CSA>,<menu text>[,<basename>|<bootservicetype>][,<server address>|<server_name>]
|
||||||
Most uses of PXE boot-ROMS simply allow the PXE
|
Most uses of PXE boot-ROMS simply allow the PXE
|
||||||
system to obtain an IP address and then download the file specified by
|
system to obtain an IP address and then download the file specified by
|
||||||
.B dhcp-boot
|
.B dhcp-boot
|
||||||
@@ -871,17 +996,19 @@ parameter after the menu text may be a file name, in which case dnsmasq acts as
|
|||||||
boot server and directs the PXE client to download the file by TFTP,
|
boot server and directs the PXE client to download the file by TFTP,
|
||||||
either from itself (
|
either from itself (
|
||||||
.B enable-tftp
|
.B enable-tftp
|
||||||
must be set for this to work) or another TFTP server if the final IP
|
must be set for this to work) or another TFTP server if the final server
|
||||||
address is given.
|
address/name is given.
|
||||||
Note that the "layer"
|
Note that the "layer"
|
||||||
suffix (normally ".0") is supplied by PXE, and should not be added to
|
suffix (normally ".0") is supplied by PXE, and should not be added to
|
||||||
the basename. If an integer boot service type, rather than a basename
|
the basename. If an integer boot service type, rather than a basename
|
||||||
is given, then the PXE client will search for a
|
is given, then the PXE client will search for a
|
||||||
suitable boot service for that type on the network. This search may be done
|
suitable boot service for that type on the network. This search may be done
|
||||||
by broadcast, or direct to a server if its IP address is provided.
|
by broadcast, or direct to a server if its IP address/name is provided.
|
||||||
If no boot service type or filename is provided (or a boot service type of 0 is specified)
|
If no boot service type or filename is provided (or a boot service type of 0 is specified)
|
||||||
then the menu entry will abort the net boot procedure and
|
then the menu entry will abort the net boot procedure and
|
||||||
continue booting from local media.
|
continue booting from local media. The server address can be given as a domain
|
||||||
|
name which is looked up in /etc/hosts. This name can be associated in
|
||||||
|
/etc/hosts with multiple IP addresses, which are used round-robin.
|
||||||
.TP
|
.TP
|
||||||
.B --pxe-prompt=[tag:<tag>,]<prompt>[,<timeout>]
|
.B --pxe-prompt=[tag:<tag>,]<prompt>[,<timeout>]
|
||||||
Setting this provides a prompt to be displayed after PXE boot. If the
|
Setting this provides a prompt to be displayed after PXE boot. If the
|
||||||
@@ -914,7 +1041,7 @@ create thousands of leases and use lots of memory in the dnsmasq
|
|||||||
process.
|
process.
|
||||||
.TP
|
.TP
|
||||||
.B \-K, --dhcp-authoritative
|
.B \-K, --dhcp-authoritative
|
||||||
Should be set when dnsmasq is definitely the only DHCP server on a network.
|
(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
|
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
|
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
|
to get a lease without a tedious timeout under all circumstances. It also
|
||||||
@@ -922,7 +1049,7 @@ 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.
|
||||||
.TP
|
.TP
|
||||||
.B --dhcp-alternate-port[=<server port>[,<client port>]]
|
.B --dhcp-alternate-port[=<server port>[,<client port>]]
|
||||||
Change the ports used for DHCP from the default. If this option is
|
(IPv4 only) Change the ports used for DHCP from the default. If this option is
|
||||||
given alone, without arguments, it changes the ports used for DHCP
|
given alone, without arguments, it changes the ports used for DHCP
|
||||||
from 67 and 68 to 1067 and 1068. If a single argument is given, that
|
from 67 and 68 to 1067 and 1068. If a single argument is given, that
|
||||||
port number is used for the server and the port number plus one used
|
port number is used for the server and the port number plus one used
|
||||||
@@ -930,7 +1057,7 @@ for the client. Finally, two port numbers allows arbitrary
|
|||||||
specification of both server and client ports for DHCP.
|
specification of both server and client ports for DHCP.
|
||||||
.TP
|
.TP
|
||||||
.B \-3, --bootp-dynamic[=<network-id>[,<network-id>]]
|
.B \-3, --bootp-dynamic[=<network-id>[,<network-id>]]
|
||||||
Enable dynamic allocation of IP addresses to BOOTP clients. Use this
|
(IPv4 only) Enable dynamic allocation of IP addresses to BOOTP clients. Use this
|
||||||
with care, since each address allocated to a BOOTP client is leased
|
with care, since each address allocated to a BOOTP client is leased
|
||||||
forever, and therefore becomes permanently unavailable for re-use by
|
forever, and therefore becomes permanently unavailable for re-use by
|
||||||
other hosts. if this is given without tags, then it unconditionally
|
other hosts. if this is given without tags, then it unconditionally
|
||||||
@@ -938,7 +1065,7 @@ enables dynamic allocation. With tags, only when the tags are all
|
|||||||
set. It may be repeated with different tag sets.
|
set. It may be repeated with different tag sets.
|
||||||
.TP
|
.TP
|
||||||
.B \-5, --no-ping
|
.B \-5, --no-ping
|
||||||
By default, the DHCP server will attempt to ensure that an address in
|
(IPv4 only) By default, the DHCP server will attempt to ensure that an address in
|
||||||
not in use before allocating it to a host. It does this by sending an
|
not in use before allocating it to a host. It does this by sending an
|
||||||
ICMP echo request (aka "ping") to the address in question. If it gets
|
ICMP echo request (aka "ping") to the address in question. If it gets
|
||||||
a reply, then the address must already be in use, and another is
|
a reply, then the address must already be in use, and another is
|
||||||
@@ -951,13 +1078,24 @@ the tags used to determine them.
|
|||||||
.B \-l, --dhcp-leasefile=<path>
|
.B \-l, --dhcp-leasefile=<path>
|
||||||
Use the specified file to store DHCP lease information.
|
Use the specified file to store DHCP lease information.
|
||||||
.TP
|
.TP
|
||||||
|
.B --dhcp-duid=<enterprise-id>,<uid>
|
||||||
|
(IPv6 only) Specify the server persistent UID which the DHCPv6 server
|
||||||
|
will use. This option is not normally required as dnsmasq creates a
|
||||||
|
DUID automatically when it is first needed. When given, this option
|
||||||
|
provides dnsmasq the data required to create a DUID-EN type DUID. Note
|
||||||
|
that once set, the DUID is stored in the lease database, so to change between DUID-EN and
|
||||||
|
automatically created DUIDs or vice-versa, the lease database must be
|
||||||
|
re-intialised. The enterprise-id is assigned by IANA, and the uid is a
|
||||||
|
string of hex octets unique to a particular device.
|
||||||
|
.TP
|
||||||
.B \-6 --dhcp-script=<path>
|
.B \-6 --dhcp-script=<path>
|
||||||
Whenever a new DHCP lease is created, or an old one destroyed, the
|
Whenever a new DHCP lease is created, or an old one destroyed, or a
|
||||||
|
TFTP file transfer completes, the
|
||||||
executable specified by this option is run. <path>
|
executable specified by this option is run. <path>
|
||||||
must be an absolute pathname, no PATH search occurs.
|
must be an absolute pathname, no PATH search occurs.
|
||||||
The arguments to the process
|
The arguments to the process
|
||||||
are "add", "old" or "del", the MAC
|
are "add", "old" or "del", the MAC
|
||||||
address of the host, the IP address, and the hostname,
|
address of the host (or DUID for IPv6) , the IP address, and the hostname,
|
||||||
if known. "add" means a lease has been created, "del" means it has
|
if known. "add" means a lease has been created, "del" means it has
|
||||||
been destroyed, "old" is a notification of an existing lease when
|
been destroyed, "old" is a notification of an existing lease when
|
||||||
dnsmasq starts or a change to MAC address or hostname of an existing
|
dnsmasq starts or a change to MAC address or hostname of an existing
|
||||||
@@ -968,21 +1106,17 @@ token ring. The process is run as root (assuming that dnsmasq was originally run
|
|||||||
root) even if dnsmasq is configured to change UID to an unprivileged user.
|
root) even if dnsmasq is configured to change UID to an unprivileged user.
|
||||||
|
|
||||||
The environment is inherited from the invoker of dnsmasq, with some or
|
The environment is inherited from the invoker of dnsmasq, with some or
|
||||||
all of the following variables added.
|
all of the following variables added
|
||||||
|
|
||||||
DNSMASQ_CLIENT_ID if the host provided a client-id.
|
For both IPv4 and IPv6:
|
||||||
|
|
||||||
DNSMASQ_DOMAIN if the fully-qualified domain name of the host is
|
DNSMASQ_DOMAIN if the fully-qualified domain name of the host is
|
||||||
known, this is set to the domain part. (Note that the hostname passed
|
known, this is set to the domain part. (Note that the hostname passed
|
||||||
to the script as an argument is never fully-qualified.)
|
to the script as an argument is never fully-qualified.)
|
||||||
|
|
||||||
If the client provides vendor-class, hostname or user-class,
|
If the client provides a hostname, DNSMASQ_SUPPLIED_HOSTNAME
|
||||||
these are provided in DNSMASQ_VENDOR_CLASS
|
|
||||||
DNSMASQ_SUPPLIED_HOSTNAME and
|
If the client provides user-classes, DNSMASQ_USER_CLASS0..DNSMASQ_USER_CLASSn
|
||||||
DNSMASQ_USER_CLASS0..DNSMASQ_USER_CLASSn variables, but only for
|
|
||||||
"add" actions or "old" actions when a host resumes an existing lease,
|
|
||||||
since these data are not held in dnsmasq's lease
|
|
||||||
database.
|
|
||||||
|
|
||||||
If dnsmasq was compiled with HAVE_BROKEN_RTC, then
|
If dnsmasq was compiled with HAVE_BROKEN_RTC, then
|
||||||
the length of the lease (in seconds) is stored in
|
the length of the lease (in seconds) is stored in
|
||||||
@@ -1006,6 +1140,36 @@ is known.
|
|||||||
DNSMASQ_TAGS contains all the tags set during the
|
DNSMASQ_TAGS contains all the tags set during the
|
||||||
DHCP transaction, separated by spaces.
|
DHCP transaction, separated by spaces.
|
||||||
|
|
||||||
|
DNSMASQ_LOG_DHCP is set if --log-dhcp is in effect.
|
||||||
|
|
||||||
|
For IPv4 only:
|
||||||
|
|
||||||
|
DNSMASQ_CLIENT_ID if the host provided a client-id.
|
||||||
|
|
||||||
|
If the client provides vendor-class, DNSMASQ_VENDOR_CLASS.
|
||||||
|
|
||||||
|
For IPv6 only:
|
||||||
|
|
||||||
|
If the client provides vendor-class, DNSMASQ_VENDOR_CLASS_ID,
|
||||||
|
containing the IANA enterprise id for the class, and
|
||||||
|
DNSMASQ_VENDOR_CLASS0..DNSMASQ_VENDOR_CLASSn for the data.
|
||||||
|
|
||||||
|
DNSMASQ_SERVER_DUID containing the DUID of the server: this is the same for
|
||||||
|
every call to the script.
|
||||||
|
|
||||||
|
DNSMASQ_IAID containing the IAID for the lease. If the lease is a
|
||||||
|
temporary allocation, this is prefixed to 'T'.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Note that the supplied hostname, vendorclass and userclass data is
|
||||||
|
only supplied for
|
||||||
|
"add" actions or "old" actions when a host resumes an existing lease,
|
||||||
|
since these data are not held in dnsmasq's lease
|
||||||
|
database.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All file descriptors are
|
All file descriptors are
|
||||||
closed except stdin, stdout and stderr which are open to /dev/null
|
closed except stdin, stdout and stderr which are open to /dev/null
|
||||||
(except in debug mode).
|
(except in debug mode).
|
||||||
@@ -1024,9 +1188,66 @@ all existing leases as they are read from the lease file. Expired
|
|||||||
leases will be called with "del" and others with "old". When dnsmasq
|
leases will be called with "del" and others with "old". When dnsmasq
|
||||||
receives a HUP signal, the script will be invoked for existing leases
|
receives a HUP signal, the script will be invoked for existing leases
|
||||||
with an "old " event.
|
with an "old " event.
|
||||||
|
|
||||||
|
|
||||||
|
There are two further actions which may appear as the first argument
|
||||||
|
to the script, "init" and "tftp". More may be added in the future, so
|
||||||
|
scripts should be written to ignore unknown actions. "init" is
|
||||||
|
decsribed below in
|
||||||
|
.B --leasefile-ro
|
||||||
|
The "tftp" action is invoked when a TFTP file transfer completes: the
|
||||||
|
arguments are the file size in bytes, the address to which the file
|
||||||
|
was sent, and the complete pathname of the file.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B --dhcp-luascript=<path>
|
||||||
|
Specify a script written in Lua, to be run when leases are created,
|
||||||
|
destroyed or changed. To use this option, dnsmasq must be compiled
|
||||||
|
with the correct support. The Lua interpreter is intialised once, when
|
||||||
|
dnsmasq starts, so that global variables persist between lease
|
||||||
|
events. The Lua code must define a
|
||||||
|
.B lease
|
||||||
|
function, and may provide
|
||||||
|
.B init
|
||||||
|
and
|
||||||
|
.B shutdown
|
||||||
|
functions, which are called, without arguments when dnsmasq starts up
|
||||||
|
and terminates. It may also provide a
|
||||||
|
.B tftp
|
||||||
|
function.
|
||||||
|
|
||||||
|
The
|
||||||
|
.B lease
|
||||||
|
function receives the information detailed in
|
||||||
|
.B --dhcp-script.
|
||||||
|
It gets two arguments, firstly the action, which is a string
|
||||||
|
containing, "add", "old" or "del", and secondly a table of tag value
|
||||||
|
pairs. The tags mostly correspond to the environment variables
|
||||||
|
detailed above, for instance the tag "domain" holds the same data as
|
||||||
|
the environment variable DNSMASQ_DOMAIN. There are a few extra tags
|
||||||
|
which hold the data supplied as arguments to
|
||||||
|
.B --dhcp-script.
|
||||||
|
These are
|
||||||
|
.B mac_address, ip_address
|
||||||
|
and
|
||||||
|
.B hostname
|
||||||
|
for IPv4, and
|
||||||
|
.B client_duid, ip_address
|
||||||
|
and
|
||||||
|
.B hostname
|
||||||
|
for IPv6.
|
||||||
|
|
||||||
|
The
|
||||||
|
.B tftp
|
||||||
|
function is called in the same way as the lease function, and the
|
||||||
|
table holds the tags
|
||||||
|
.B destination_address,
|
||||||
|
.B file_name
|
||||||
|
and
|
||||||
|
.B file_size.
|
||||||
.TP
|
.TP
|
||||||
.B --dhcp-scriptuser
|
.B --dhcp-scriptuser
|
||||||
Specify the user as which to run the lease-change script. This defaults to root, but can be changed to another user using this flag.
|
Specify the user as which to run the lease-change script or Lua script. This defaults to root, but can be changed to another user using this flag.
|
||||||
.TP
|
.TP
|
||||||
.B \-9, --leasefile-ro
|
.B \-9, --leasefile-ro
|
||||||
Completely suppress use of the lease database file. The file will not
|
Completely suppress use of the lease database file. The file will not
|
||||||
@@ -1101,6 +1322,32 @@ without an address specified when
|
|||||||
.B --dhcp-fqdn
|
.B --dhcp-fqdn
|
||||||
is set.
|
is set.
|
||||||
.TP
|
.TP
|
||||||
|
.B --dhcp-client-update
|
||||||
|
Normally, when giving a DHCP lease, dnsmasq sets flags in the FQDN
|
||||||
|
option to tell the client not to attempt a DDNS update with its name
|
||||||
|
and IP address. This is because the name-IP pair is automatically
|
||||||
|
added into dnsmasq's DNS view. This flag suppresses that behaviour,
|
||||||
|
this is useful, for instance, to allow Windows clients to update
|
||||||
|
Active Directory servers. See RFC 4702 for details.
|
||||||
|
.TP
|
||||||
|
.B --enable-ra
|
||||||
|
Enable dnsmasq's IPv6 Router Advertisement feature. DHCPv6 doesn't
|
||||||
|
handle complete network configuration in the same way as DHCPv4. Router
|
||||||
|
discovery and (possibly) prefix discovery for autonomous address
|
||||||
|
creation are handled by a different protocol. When DHCP is in use,
|
||||||
|
only a subset of this is needed, and dnsmasq can handle it, using
|
||||||
|
existing DHCP configuration to provide most data. When RA is enabled,
|
||||||
|
dnsmasq will advertise a prefix for each dhcp-range, with default
|
||||||
|
router and recursive DNS server as the relevant link-local address on
|
||||||
|
the machine running dnsmasq. By default, he "managed address" bits are set, and
|
||||||
|
the "use SLAAC" bit is reset. This can be changed for individual
|
||||||
|
subnets with the mode keywords described in
|
||||||
|
.B --dhcp-range.
|
||||||
|
RFC6106 DNS parameters are included in the advertisements. By default,
|
||||||
|
the relevant link-local address of the machine running dnsmasq is sent
|
||||||
|
as recursive DNS server. If provided, the DHCPv6 options dns-server and
|
||||||
|
domain-search are used for RDNSS and DNSSL.
|
||||||
|
.TP
|
||||||
.B --enable-tftp[=<interface>]
|
.B --enable-tftp[=<interface>]
|
||||||
Enable the TFTP server function. This is deliberately limited to that
|
Enable the TFTP server function. This is deliberately limited to that
|
||||||
needed to net-boot a client. Only reading is allowed; the tsize and
|
needed to net-boot a client. Only reading is allowed; the tsize and
|
||||||
@@ -1324,6 +1571,17 @@ so --dhcp=option=tag:!purple,3,1.2.3.4 sends the option when the
|
|||||||
tag purple is not in the set of valid tags. (If using this in a
|
tag purple is not in the set of valid tags. (If using this in a
|
||||||
command line rather than a configuration file, be sure to escape !,
|
command line rather than a configuration file, be sure to escape !,
|
||||||
which is a shell metacharacter)
|
which is a shell metacharacter)
|
||||||
|
|
||||||
|
When selecting dhcp-options, a tag from dhcp-range is second class
|
||||||
|
relative to other tags, to make it easy to override options for
|
||||||
|
individual hosts, so
|
||||||
|
.B dhcp-range=set:interface1,......
|
||||||
|
.B dhcp-host=set:myhost,.....
|
||||||
|
.B dhcp-option=tag:interface1,option:nis-domain,"domain1"
|
||||||
|
.B dhcp-option=tag:myhost,option:nis-domain,"domain2"
|
||||||
|
will set the NIS-domain to domain1 for hosts in the range, but
|
||||||
|
override that to domain2 for a particular host.
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
Note that for
|
Note that for
|
||||||
.B dhcp-range
|
.B dhcp-range
|
||||||
|
|||||||
+276
-92
@@ -347,10 +347,10 @@ Cela est utile si les nouveaux serveurs sont susceptibles d'avoir des données
|
|||||||
différentes de celles stockées dans le cache.
|
différentes de celles stockées dans le cache.
|
||||||
.TP
|
.TP
|
||||||
.B \-D, --domain-needed
|
.B \-D, --domain-needed
|
||||||
Indique à Dnsmasq de ne jamais transmettre en amont de requêtes pour des noms
|
Indique à Dnsmasq de ne jamais transmettre en amont de requêtes A ou AAAA pour
|
||||||
simples, ne comprenant donc ni points ni nom de domaine. Si un nom n'est pas
|
des noms simples, c'est à dire ne comprenant ni points ni nom de domaine. Si un
|
||||||
dans /etc/hosts ou dans la liste des baux DHCP, alors une réponse de type
|
nom n'est pas dans /etc/hosts ou dans la liste des baux DHCP, alors une réponse
|
||||||
"non trouvé" est renvoyée.
|
de type "non trouvé" est renvoyée.
|
||||||
.TP
|
.TP
|
||||||
.B \-S, --local, --server=[/[<domaine>]/[domaine/]][<Adresse IP>[#<port>][@<Adresse IP source>|<interface>[#<port>]]]
|
.B \-S, --local, --server=[/[<domaine>]/[domaine/]][<Adresse IP>[#<port>][@<Adresse IP source>|<interface>[#<port>]]]
|
||||||
Spécifie directement l'adresse IP d'un serveur de nom amont. Cette option ne
|
Spécifie directement l'adresse IP d'un serveur de nom amont. Cette option ne
|
||||||
@@ -402,6 +402,10 @@ est synonyme de
|
|||||||
("serveur") afin de rendre plus claire l'utilisation de cette option pour cet
|
("serveur") afin de rendre plus claire l'utilisation de cette option pour cet
|
||||||
usage particulier.
|
usage particulier.
|
||||||
|
|
||||||
|
Les adresses IPv6 peuvent inclure un identifiant de zone sous la forme
|
||||||
|
%interface tel que par exemple
|
||||||
|
fe80::202:a412:4512:7bbf%eth0.
|
||||||
|
|
||||||
La chaîne de caractères optionnelle suivant le caractère @ permet de définir
|
La chaîne de caractères optionnelle suivant le caractère @ permet de définir
|
||||||
la source que Dnsmasq doit utiliser pour les réponses à ce
|
la source que Dnsmasq doit utiliser pour les réponses à ce
|
||||||
serveur de nom. Il doit s'agir d'une des adresses IP appartenant à la machine sur
|
serveur de nom. Il doit s'agir d'une des adresses IP appartenant à la machine sur
|
||||||
@@ -565,7 +569,19 @@ 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
|
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.
|
données nécessaires par un client pour effectuer la validation lui-même.
|
||||||
.TP
|
.TP
|
||||||
.B \-F, --dhcp-range=[interface:<interface>,][tag:<label>[,tag:<label>],][set:<label],]<adresse de début>,<adresse de fin>[,<masque de réseau>[,<broadcast>]][,<durée de bail>]
|
.B --conntrack
|
||||||
|
Lis le marquage de suivi de connexion Linux associé aux requêtes DNS entrantes
|
||||||
|
et positionne la même marque au trafic amont utilisé pour répondre à ces
|
||||||
|
requétes. Cela permet au trafic généré par Dnsmasq d'étre associé aux requêtes
|
||||||
|
l'ayant déclenché, ce qui est pratique pour la gestion de la bande passante
|
||||||
|
(accounting) et le filtrage (firewall). Dnsmasq doit pour cela être compilé
|
||||||
|
avec le support conntrack, le noyau doit également inclure conntrack et être
|
||||||
|
configuré pour cela. Cette option ne peut pas être combinée avec
|
||||||
|
--query-port.
|
||||||
|
.TP
|
||||||
|
.B \-F, --dhcp-range=[interface:<interface>,][tag:<label>[,tag:<label>],][set:<label>],]<adresse de début>,<adresse de fin>[,<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>[,<longueur de préfixe>][,<durée de bail>]
|
||||||
Active le serveur DHCP. Les adresses seront données dans la plage comprise entre
|
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
|
<adresse de début> et <adresse de fin> et à partir des adresses définies
|
||||||
statiquement dans l'option
|
statiquement dans l'option
|
||||||
@@ -579,12 +595,25 @@ minutes.
|
|||||||
Cette option peut être répétée, avec différentes adresses,
|
Cette option peut être répétée, avec différentes adresses,
|
||||||
pour activer le service DHCP sur plus d'un réseau. Pour des réseaux directement
|
pour activer le service DHCP sur plus d'un réseau. Pour des réseaux directement
|
||||||
connectés (c'est-à-dire des réseaux dans lesquels la machine sur laquelle tourne
|
connectés (c'est-à-dire des réseaux dans lesquels la machine sur laquelle tourne
|
||||||
Dnsmasq possède une interface), le masque de réseau est optionnel. Il est par
|
Dnsmasq possède une interface), le masque de réseau est optionnel : Dnsmasq la
|
||||||
contre requis pour les réseaux pour lesquels le service DHCP se fait via un
|
déterminera à partir de la configuration des interfaces.
|
||||||
relais DHCP ("relay agent"). L'adresse de broadcast est toujours optionnelle.
|
|
||||||
|
Pour les réseaux pour lesquels le service DHCP se fait via un relais DHCP
|
||||||
|
("relay agent"), Dnsmasq est incapable de déterminer le masque par lui-même,
|
||||||
|
aussi il doit être spécifié, faute de quoi Dnsmasq essaiera de le deviner en
|
||||||
|
fonction de la classe (A, B ou C) de l'adresse réseau. L'adresse de broadcast
|
||||||
|
est toujours optionnelle.
|
||||||
|
|
||||||
Il est toujours possible d'avoir plus d'une plage DHCP pour un même
|
Il est toujours possible d'avoir plus d'une plage DHCP pour un même
|
||||||
sous-réseau.
|
sous-réseau.
|
||||||
|
|
||||||
|
Pour IPv6, les paramètres sont légèrement différents : au lieu d'un masque de
|
||||||
|
réseau et d'une adresse de broadcast, il existe une longueur de préfixe
|
||||||
|
optionnelle. Si elle est omise, la valeur par défaut est 64. À la différence
|
||||||
|
d'IPv4, la longueur de préfixe n'est pas automatiquement déduite de la
|
||||||
|
configuration de l'interface. La taille minimale pour la longueur de préfixe
|
||||||
|
est 64.
|
||||||
|
|
||||||
L'identifiant de label optionnel
|
L'identifiant de label optionnel
|
||||||
.B set:<label>
|
.B set:<label>
|
||||||
fournie une étiquette alphanumérique qui identifie ce réseau, afin de permettre
|
fournie une étiquette alphanumérique qui identifie ce réseau, afin de permettre
|
||||||
@@ -608,7 +637,15 @@ spécifié. (voir
|
|||||||
.B pxe-prompt
|
.B pxe-prompt
|
||||||
et
|
et
|
||||||
.B pxe-service
|
.B pxe-service
|
||||||
pour plus de détails).
|
pour plus de détails, s'applique à IPv4 seulement).
|
||||||
|
|
||||||
|
L'adresse de fin peut être remplacée par le mot-clef
|
||||||
|
.B ra-only
|
||||||
|
qui indique à dnsmasq de n'effectuer que des annonces de routeur (Router
|
||||||
|
Advertisement, RA) sur ce sous-réseau, et de ne pas faire de DHCP. Ceci
|
||||||
|
s'applique uniquement à IPv6, voir
|
||||||
|
.B enable-ra
|
||||||
|
pour plus de détails.
|
||||||
|
|
||||||
La section interface:<nom d'interface> n'est normalement pas utilisée. Se
|
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.
|
référer aux indications de la section NOTES pour plus de détail à ce sujet.
|
||||||
@@ -644,6 +681,15 @@ spécifier l'identifiant client sous la forme d'une chaîne de caractères, comm
|
|||||||
ceci :
|
ceci :
|
||||||
.B --dhcp-host=id:identifiantclientsousformedechaine,.....
|
.B --dhcp-host=id:identifiantclientsousformedechaine,.....
|
||||||
|
|
||||||
|
Un seul
|
||||||
|
.B dhcp-host
|
||||||
|
peut contenir une adresse IPv4, une adresse IPv6, ou les deux en même temps.
|
||||||
|
Les adresses IPv6 doivent-être mises entre crochets comme suit :
|
||||||
|
.B --dhcp-host=laptop,[1234::56]
|
||||||
|
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.
|
||||||
|
|
||||||
L'option spéciale id:* signifie : "ignorer tout identifiant client et n'utiliser
|
L'option spéciale id:* signifie : "ignorer tout identifiant client et n'utiliser
|
||||||
que l'adresse matérielle". Cela est utile lorsqu'un client présente un
|
que l'adresse matérielle". Cela est utile lorsqu'un client présente un
|
||||||
identifiant client mais pas les autres.
|
identifiant client mais pas les autres.
|
||||||
@@ -690,7 +736,7 @@ ARP en les précédant du type ARP (en Hexadécimal) et de "-". Ainsi
|
|||||||
coïncidera uniquement avec des adresses matérielles Token-Ring, puisque le type
|
coïncidera uniquement avec des adresses matérielles Token-Ring, puisque le type
|
||||||
ARP pour une adresse Token-Ring est 6.
|
ARP pour une adresse Token-Ring est 6.
|
||||||
|
|
||||||
Un cas spécial correspond à l'inclusion d'une ou plusieurs adresses
|
Un cas spécial, pour IPv4, correspond à l'inclusion d'une ou plusieurs adresses
|
||||||
matérielles, c-à-d :
|
matérielles, c-à-d :
|
||||||
.B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2.
|
.B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2.
|
||||||
Cela permet à une adresse IP d'être associé à plusieurs adresses
|
Cela permet à une adresse IP d'être associé à plusieurs adresses
|
||||||
@@ -731,22 +777,22 @@ une adresse IP sous la forme de 4 chiffres séparés par des points. Lorsque lu
|
|||||||
par Dnsmasq, ces lignes ont exactement le même effet que l'option
|
par Dnsmasq, ces lignes ont exactement le même effet que l'option
|
||||||
.B --dhcp-host
|
.B --dhcp-host
|
||||||
contenant les mêmes informations. /etc/ethers est relu à la réception d'un
|
contenant les mêmes informations. /etc/ethers est relu à la réception d'un
|
||||||
signal SIGHUP par Dnsmasq.
|
signal SIGHUP par Dnsmasq. Les adresses IPv6 ne sont PAS lues dans /etc/ethers.
|
||||||
.TP
|
.TP
|
||||||
.B \-O, --dhcp-option=[tag:<label>,[tag:<label>]][encap:<option>,][vi-encap:<entreprise>,][vendor:[<classe_vendeur>],][<option>|option:<nom d'option>],[<valeur>[,<valeur>]]
|
.B \-O, --dhcp-option=[tag:<label>,[tag:<label>]][encap:<option>,][vi-encap:<entreprise>,][vendor:[<classe_vendeur>],][<option>|option:<nom d'option>|option6:<option>|option6:<nom d'option>],[<valeur>[,<valeur>]]
|
||||||
Spécifie des options différentes ou supplémentaires pour des clients DHCP. Par
|
Spécifie des options différentes ou supplémentaires pour des clients DHCP. Par
|
||||||
défaut, Dnsmasq envoie un ensemble standard d'options aux clients DHCP : le
|
défaut, Dnsmasq envoie un ensemble standard d'options aux clients DHCP : le
|
||||||
masque de réseau et l'adresse de broadcast sont les mêmes que pour l'hôte
|
masque de réseau et l'adresse de broadcast sont les mêmes que pour l'hôte
|
||||||
sur lequel tourne Dnsmasq, et le serveur DNS ainsi que la route par défaut
|
sur lequel tourne Dnsmasq, et le serveur DNS ainsi que la route par défaut
|
||||||
prennent comme valeur l'adresse de la machine sur laquelle tourne Dnsmasq. Si
|
prennent comme valeur l'adresse de la machine sur laquelle tourne Dnsmasq.
|
||||||
une option de nom de domaine a été définie, son contenu est transmis. Cette
|
(Des règles équivalentes s'appliquent en IPv6). Si une option de nom de domaine
|
||||||
option de configuration permet de changer toutes ces valeurs par défaut, ou de
|
a été définie, son contenu est transmis. Cette option de configuration permet
|
||||||
spécifier d'autres options. L'option DHCP à transmettre peut être fournie sous
|
de changer toutes ces valeurs par défaut, ou de spécifier d'autres options.
|
||||||
forme d'un nombre décimal ou sous la forme "option:<nom d'option>". Les nombres
|
L'option DHCP à transmettre peut être fournie sous forme d'un nombre décimal
|
||||||
correspondants aux options sont définis dans la RFC2132 et suivants. Les noms
|
ou sous la forme "option:<nom d'option>". Les nombres correspondants aux options
|
||||||
d'options connus par Dnsmasq peuvent être obtenus via "Dnsmasq --help dhcp".
|
sont définis dans la RFC2132 et suivants. Les noms d'options connus par Dnsmasq
|
||||||
Par exemple, pour définir la route par défaut à 192.168.4.4, il est possible de
|
peuvent être obtenus via "Dnsmasq --help dhcp". Par exemple, pour définir la
|
||||||
faire
|
route par défaut à 192.168.4.4, il est possible de faire
|
||||||
.B --dhcp-option=3,192.168.4.4
|
.B --dhcp-option=3,192.168.4.4
|
||||||
ou
|
ou
|
||||||
.B --dhcp-option = option:router, 192.168.4.4
|
.B --dhcp-option = option:router, 192.168.4.4
|
||||||
@@ -769,6 +815,13 @@ de l'option 120 sont traités conforméments à la RFC 3361. Les adresses IP sou
|
|||||||
forme de 4 chiffres séparés par des points suivies par une barre montante "/",
|
forme de 4 chiffres séparés par des points suivies par une barre montante "/",
|
||||||
puis une taille de masque sont encodés conforméments à la RFC 3442.
|
puis une taille de masque sont encodés conforméments à la RFC 3442.
|
||||||
|
|
||||||
|
Les options IPv6 sont fournies en utilisant le mot-clef
|
||||||
|
.B option6:
|
||||||
|
suivi par le numéro d'option ou le nom d'option. L'espace de nommage des options
|
||||||
|
IPv6 est disjint de l'espace de nommage des options IPv4. Les adresses IPv6
|
||||||
|
en option doivent être entourées de crochets, comme par exemple :
|
||||||
|
.B --dhcp-option=option6:ntp-server,[1234::56]
|
||||||
|
|
||||||
Attention : aucun test n'étant fait pour vérifier que des données d'un type
|
Attention : aucun test n'étant fait pour vérifier que des données d'un type
|
||||||
adéquat sont envoyées pour un numéro d'option donné, il est tout à fait possible
|
adéquat sont envoyées pour un numéro d'option donné, il est tout à fait possible
|
||||||
de persuader Dnsmasq de générer des paquets DHCP illégaux par une utilisation
|
de persuader Dnsmasq de générer des paquets DHCP illégaux par une utilisation
|
||||||
@@ -787,8 +840,8 @@ d'une chaîne de caractères comme nom de serveur TFTP, il est nécessaire de fa
|
|||||||
comme suit :
|
comme suit :
|
||||||
.B --dhcp-option=66,"1.2.3.4"
|
.B --dhcp-option=66,"1.2.3.4"
|
||||||
|
|
||||||
Les options encapsulées de classes de vendeurs peuvent-être aussi spécifiées en
|
Les options encapsulées de classes de vendeurs peuvent-être aussi spécifiées
|
||||||
utilisant
|
(pour IPv4 seulement) en utilisant
|
||||||
.B --dhcp-option
|
.B --dhcp-option
|
||||||
: par exemple
|
: par exemple
|
||||||
.B --dhcp-option=vendor:PXEClient,1,0.0.0.0
|
.B --dhcp-option=vendor:PXEClient,1,0.0.0.0
|
||||||
@@ -804,7 +857,7 @@ par le client. Il est possible d'omettre complètement une classe de vendeur :
|
|||||||
.B --dhcp-option=vendor:,1,0.0.0.0
|
.B --dhcp-option=vendor:,1,0.0.0.0
|
||||||
Dans ce cas l'option encapsulée est toujours envoyée.
|
Dans ce cas l'option encapsulée est toujours envoyée.
|
||||||
|
|
||||||
Les options peuvent-être encapsulées au sein d'autres options :
|
En IPv4, les options peuvent-être encapsulées au sein d'autres options :
|
||||||
par exemple
|
par exemple
|
||||||
.B --dhcp-option=encap:175, 190, "iscsi-client0"
|
.B --dhcp-option=encap:175, 190, "iscsi-client0"
|
||||||
enverra l'option 175, au sein de laquelle se trouve l'option 190.
|
enverra l'option 175, au sein de laquelle se trouve l'option 190.
|
||||||
@@ -817,7 +870,8 @@ identifiant le vendeur" ("Vendor-Identifying Vendor Options") telle que
|
|||||||
décrite dans le RFC3925. Celles-ci sont spécifiées comme suit :
|
décrite dans le RFC3925. Celles-ci sont spécifiées comme suit :
|
||||||
.B --dhcp-option=vi-encap:2, 10, "text"
|
.B --dhcp-option=vi-encap:2, 10, "text"
|
||||||
Le numéro dans la section vi-encap: est le numéro IANA de l'entreprise servant
|
Le numéro dans la section vi-encap: est le numéro IANA de l'entreprise servant
|
||||||
à identifier cette option.
|
à identifier cette option. Cette forme d'encapsulation est également supportée
|
||||||
|
en IPv6.
|
||||||
|
|
||||||
L'adresse 0.0.0.0 n'est pas traitée de manière particulière lorsque fournie dans
|
L'adresse 0.0.0.0 n'est pas traitée de manière particulière lorsque fournie dans
|
||||||
une option encapsulée.
|
une option encapsulée.
|
||||||
@@ -830,8 +884,8 @@ dans la liste de paramêtres requis. Cela est parfois nécessaire, par exemple l
|
|||||||
de la fourniture d'options à PXELinux.
|
de la fourniture d'options à PXELinux.
|
||||||
.TP
|
.TP
|
||||||
.B --dhcp-no-override
|
.B --dhcp-no-override
|
||||||
Désactive la réutilisation des champs DHCP nom de serveur et nom de
|
(IPv4 seulement) Désactive la réutilisation des champs DHCP nom de serveur et
|
||||||
fichier comme espace supplémentaire pour les options. Si cela est
|
nom de fichier comme espace supplémentaire pour les options. Si cela est
|
||||||
possible, dnsmasq déplace les informations sur le serveur de démarrage
|
possible, dnsmasq déplace les informations sur le serveur de démarrage
|
||||||
et le nom de fichier (fournis par 'dhcp-boot') en dehors des champs
|
et le nom de fichier (fournis par 'dhcp-boot') en dehors des champs
|
||||||
dédiés à cet usage dans les options DHCP. Cet espace supplémentaire est
|
dédiés à cet usage dans les options DHCP. Cet espace supplémentaire est
|
||||||
@@ -840,7 +894,8 @@ quelques rares cas, perturber des clients vieux ou défectueux. Cette
|
|||||||
option force le comportement à l'utilisation des valeurs "simples et sûres"
|
option force le comportement à l'utilisation des valeurs "simples et sûres"
|
||||||
afin d'éviter des problèmes dans de tels cas.
|
afin d'éviter des problèmes dans de tels cas.
|
||||||
.TP
|
.TP
|
||||||
.B \-U, --dhcp-vendorclass=set:<label>,<classe de vendeur>
|
.B \-U, --dhcp-vendorclass=set:<label>,[enterprise:<numéro IANA d'enterprise>,]<classe de vendeur>
|
||||||
|
|
||||||
Associe une chaîne de classe de vendeur à un label. La plupart
|
Associe une chaîne de classe de vendeur à un label. La plupart
|
||||||
des clients DHCP fournissent une "classe de vendeur" ("vendor class") qui
|
des clients DHCP fournissent une "classe de vendeur" ("vendor class") qui
|
||||||
représente, d'une certaine façon, le type d'hôte. Cette option associe des
|
représente, d'une certaine façon, le type d'hôte. Cette option associe des
|
||||||
@@ -856,6 +911,11 @@ en temps que sous-chaîne de caractères au sein de la classe de vendeur fournie
|
|||||||
par le client, de façon à permettre la recherche d'un sous-ensemble de la chaîne
|
par le client, de façon à permettre la recherche d'un sous-ensemble de la chaîne
|
||||||
de caractères ("fuzzy matching"). Le préfixe set: est optionnel mais autorisé
|
de caractères ("fuzzy matching"). Le préfixe set: est optionnel mais autorisé
|
||||||
afin de conserver une certaine homogénéité.
|
afin de conserver une certaine homogénéité.
|
||||||
|
|
||||||
|
Notez qu'en IPv6 (et seulement en IPv6), les noms de classes de vendeurs
|
||||||
|
sont dans un espace de nom associé au numéro attribué à l'entreprise par
|
||||||
|
l'IANA. Ce numéro est fourni par le biais du mot-clef enterprise: et seules
|
||||||
|
les classes de vendeurs associées au numéro spécifié seront cherchées.
|
||||||
.TP
|
.TP
|
||||||
.B \-j, --dhcp-userclass=set:<label>,<classe utilisateur>
|
.B \-j, --dhcp-userclass=set:<label>,<classe utilisateur>
|
||||||
Associe une chaîne de classe d'utilisateur à un label (effectue la
|
Associe une chaîne de classe d'utilisateur à un label (effectue la
|
||||||
@@ -868,7 +928,7 @@ d'impression différent pour les hôtes de la classe "comptes" et ceux de la
|
|||||||
classe "ingénierie".
|
classe "ingénierie".
|
||||||
.TP
|
.TP
|
||||||
.B \-4, --dhcp-mac=set:<label>,<adresse MAC>
|
.B \-4, --dhcp-mac=set:<label>,<adresse MAC>
|
||||||
Associe une adresse matérielle (MAC) à un label. L'adresse
|
(IPv4 uniquement) Associe une adresse matérielle (MAC) à un label. L'adresse
|
||||||
matérielle peut inclure des jokers. Par exemple
|
matérielle peut inclure des jokers. Par exemple
|
||||||
.B --dhcp-mac=set:3com,01:34:23:*:*:*
|
.B --dhcp-mac=set:3com,01:34:23:*:*:*
|
||||||
permet de définir le label "3com" pour n'importe quel hôte dont l'adresse
|
permet de définir le label "3com" pour n'importe quel hôte dont l'adresse
|
||||||
@@ -882,16 +942,19 @@ chaîne de valeurs hexadécimales séparées par des ":", mais il est également
|
|||||||
possible qu'elle le soit sous la forme d'une simple chaîne de caractères. Si
|
possible qu'elle le soit sous la forme d'une simple chaîne de caractères. Si
|
||||||
l'identifiant de circuit ou d'agent correspond exactement à celui fourni par le
|
l'identifiant de circuit ou d'agent correspond exactement à celui fourni par le
|
||||||
relais DHCP, alors le label est apposé.
|
relais DHCP, alors le label est apposé.
|
||||||
|
.B dhcp-remoteid
|
||||||
|
est supporté en IPv6 (mais non dhcp-circuitid).
|
||||||
.TP
|
.TP
|
||||||
.B --dhcp-subscrid=set:<label>,<identifiant d'abonné>
|
.B --dhcp-subscrid=set:<label>,<identifiant d'abonné>
|
||||||
Associe des options de relais DHCP issues de la RFC3993 à des labels.
|
(IPv4 et IPv6) Associe des options de relais DHCP issues de la RFC3993 à des
|
||||||
|
labels.
|
||||||
.TP
|
.TP
|
||||||
.B --dhcp-proxy[=<adresse ip>]......
|
.B --dhcp-proxy[=<adresse ip>]......
|
||||||
Un agent relai DHCP normal est uniquement utilisé pour faire suivre les
|
(IPv4 seulement) Un agent relai DHCP normal est uniquement utilisé pour faire
|
||||||
éléments initiaux de l'interaction avec le serveur DHCP. Une fois que le
|
suivre les éléments initiaux de l'interaction avec le serveur DHCP. Une fois
|
||||||
client est configuré, il communique directement avec le serveur. Cela n'est pas
|
que le client est configuré, il communique directement avec le serveur. Cela
|
||||||
souhaitable si le relais rajoute des informations supplémentaires aux paquets
|
n'est pas souhaitable si le relais rajoute des informations supplémentaires
|
||||||
DHCP, telles que celles utilisées dans
|
aux paquets DHCP, telles que celles utilisées dans
|
||||||
.B dhcp-circuitid
|
.B dhcp-circuitid
|
||||||
et
|
et
|
||||||
.B dhcp-remoteid.
|
.B dhcp-remoteid.
|
||||||
@@ -954,33 +1017,54 @@ configuration dhcp-host de Dnsmasq, ainsi que le contenu des fichiers /etc/hosts
|
|||||||
et /etc/ethers.
|
et /etc/ethers.
|
||||||
.TP
|
.TP
|
||||||
.B --dhcp-generate-names=tag:<label>[,tag:<label>]
|
.B --dhcp-generate-names=tag:<label>[,tag:<label>]
|
||||||
Générer un nom pour les clients DHCP qui autrement n'en aurait pas, en
|
(IPv4 seulement) Générer un nom pour les clients DHCP qui autrement n'en aurait
|
||||||
utilisant l'adresse MAC sous sa forme hexadécimale, séparée par des tirets.
|
pas, en utilisant l'adresse MAC sous sa forme hexadécimale, séparée par des
|
||||||
|
tirets.
|
||||||
Noter que si un hôte fourni un nom, celui-ci sera utilisé de préférence au nom
|
Noter que si un hôte fourni un nom, celui-ci sera utilisé de préférence au nom
|
||||||
autogénéré, à moins que
|
autogénéré, à moins que
|
||||||
.B --dhcp-ignore-names
|
.B --dhcp-ignore-names
|
||||||
ne soit positionné.
|
ne soit positionné.
|
||||||
.TP
|
.TP
|
||||||
.B --dhcp-broadcast=[tag:<label>[,tag:<label>]]
|
.B --dhcp-broadcast=[tag:<label>[,tag:<label>]]
|
||||||
Lorsque tous les labels fournis dans l'option sont présents, toujours utiliser
|
(IPv4 seulement) Lorsque tous les labels fournis dans l'option sont présents,
|
||||||
le broadcast pour communiquer avec l'hôte lorsque celui-ci n'est
|
toujours utiliser le broadcast pour communiquer avec l'hôte lorsque celui-ci
|
||||||
pas configuré. Il est possible de ne spécifier aucun label, auquel cas cette
|
n'est pas configuré. Il est possible de ne spécifier aucun label, auquel cas
|
||||||
option s'applique inconditionnellement. La plupart des clients DHCP nécessitant une réponse par le biais
|
cette option s'applique inconditionnellement. La plupart des clients DHCP
|
||||||
d'un broadcast activent une option dans leur requête, ce qui fait que cela
|
nécessitant une réponse par le biais d'un broadcast activent une option dans
|
||||||
se fait automatiquement, mais ce n'est pas la cas de certains vieux clients BOOTP.
|
leur requête, ce qui fait que cela se fait automatiquement, mais ce n'est pas
|
||||||
|
le cas de certains vieux clients BOOTP.
|
||||||
.TP
|
.TP
|
||||||
.B \-M, --dhcp-boot=[tag:<label>,]<nom de fichier>,[<nom de serveur>[,<adresse de serveur>]]
|
.B \-M, --dhcp-boot=[tag:<label>,]<nom de fichier>,[<nom de serveur>[,<adresse de serveur>|<nom du serveur tftp>]]
|
||||||
Spécifie les options BOOTP devant être retournées par le serveur DHCP. Le nom de
|
(IPv4 seulement) Spécifie les options BOOTP devant être retournées par le
|
||||||
serveur ainsi que l'adresse sont optionnels : s'ils ne sont pas fournis, le nom
|
serveur DHCP. Le nom de serveur ainsi que l'adresse sont optionnels : s'ils
|
||||||
est laissé vide et l'adresse fournie est celle de la machine sur laquelle
|
ne sont pas fournis, le nom est laissé vide et l'adresse fournie est celle de
|
||||||
s'exécute Dnsmasq. Si Dnsmasq founit un service TFTP (voir
|
la machine sur laquelle s'exécute Dnsmasq. Si Dnsmasq founit un service TFTP (voir
|
||||||
.B --enable-tftp
|
.B --enable-tftp
|
||||||
), alors seul un nom de fichier est requis ici pour permettre un démarrage par
|
), alors seul un nom de fichier est requis ici pour permettre un démarrage par
|
||||||
le réseau.
|
le réseau.
|
||||||
Si d'éventuels labels sont fournis, ils doivent coïncider avec
|
Si d'éventuels labels sont fournis, ils doivent coïncider avec
|
||||||
ceux du client pour que cet élement de configuration lui soit envoyé.
|
ceux du client pour que cet élement de configuration lui soit envoyé.
|
||||||
|
Une adresse de serveur TFTP peut être spécifiée à la place de l'adresse IP,
|
||||||
|
sous la forme d'un nom de domaine qui sera cherché dans le fichier /etc/hosts.
|
||||||
|
Ce nom peut être associé dans /etc/hosts avec plusieurs adresses IP, auquel cas
|
||||||
|
celles-ci seront utilisées tour à tour (algorithme round-robin).
|
||||||
|
Cela peut-être utiliser pour équilibrer la charge tftp sur plusieurs serveurs.
|
||||||
.TP
|
.TP
|
||||||
.B --pxe-service=[tag:<label>,]<CSA>,<entrée de menu>[,<nom de fichier>|<type de service de démarrage>][,<adresse de serveur>]
|
.B --dhcp-sequential-ip
|
||||||
|
Dnsmasq est conçu pour choisir l'adresse IP des clients DHCP en utilisant
|
||||||
|
un hachage de l'adresse MAC du client. Cela permet en général à l'adresse
|
||||||
|
IP du client de rester stable au fil du temps, même lorsque le client laisse
|
||||||
|
expirer son bail DHCP de temps en temps. Dans ce mode de fonctionnement par
|
||||||
|
défaut, les adresses IP sont distribuées de façon pseudo-aléatoire dans la
|
||||||
|
totalité de la plage d'adresses utilisable. Il existe des circonstances (par
|
||||||
|
exemples pour du déploiement de serveur) où il est plus pratique d'allouer les
|
||||||
|
adresses IP de manière séquentielle, en commençant par la plus petite adresse
|
||||||
|
disponible, et c'est ce mode de fonctionnement qui est permis par cette option.
|
||||||
|
Veuillez noter que dans ce mode séquentiel, les clients qui laissent expirer
|
||||||
|
leur bail ont beaucoup plus de chance de voir leur adresse IP changer, aussi
|
||||||
|
cette option ne devrait pas être utilisée dans un cas général.
|
||||||
|
.TP
|
||||||
|
.B --pxe-service=[tag:<label>,]<CSA>,<entrée de menu>[,<nom de fichier>|<type de service de démarrage>][,<adresse de serveur>|<nom de serveur>]
|
||||||
La plupart des ROMS de démarrage PXE ne permettent au système PXE que la simple
|
La plupart des ROMS de démarrage PXE ne permettent au système PXE que la simple
|
||||||
obtention d'une adresse IP, le téléchargement du fichier spécifié dans
|
obtention d'une adresse IP, le téléchargement du fichier spécifié dans
|
||||||
.B dhcp-boot
|
.B dhcp-boot
|
||||||
@@ -998,17 +1082,20 @@ client PXE qu'il faut télécharger ce fichier via TFTP, soit depuis ce serveur
|
|||||||
(l'option
|
(l'option
|
||||||
.B enable-tftp
|
.B enable-tftp
|
||||||
doit être spécifiée pour que cela marche), soit depuis un autre serveur TFTP
|
doit être spécifiée pour que cela marche), soit depuis un autre serveur TFTP
|
||||||
si une adresse de serveur est fournie.
|
si une adresse ou un nom de serveur est fournie.
|
||||||
Veuillez noter que le suffixe de "couche" (en principe ".0") est fourni par PXE
|
Veuillez noter que le suffixe de "couche" (en principe ".0") est fourni par PXE
|
||||||
et ne doit pas être rajouté au nom de fichier. Si une valeur numérique entière
|
et ne doit pas être rajouté au nom de fichier. Si une valeur numérique entière
|
||||||
est fournir pour le type de démarrage, en remplacement du nom de fichier, le
|
est fournir pour le type de démarrage, en remplacement du nom de fichier, le
|
||||||
client PXE devra chercher un service de démarrage de ce type sur le réseau.
|
client PXE devra chercher un service de démarrage de ce type sur le réseau.
|
||||||
Cette recherche peut être faite via broadcast ou directement auprès d'un
|
Cette recherche peut être faite via broadcast ou directement auprès d'un
|
||||||
serveur si son adresse IP est fournie dans l'option.
|
serveur si son adresse IP ou son nom sont fournis dans l'option.
|
||||||
Si aucun nom de fichier n'est donné ni aucune valeur de type de service de
|
Si aucun nom de fichier n'est donné ni aucune valeur de type de service de
|
||||||
démarrage n'est fournie (ou qu'une valeur de 0 est donnée pour le type de
|
démarrage n'est fournie (ou qu'une valeur de 0 est donnée pour le type de
|
||||||
service), alors l'entrée de menu provoque l'interruption du démarrage par
|
service), alors l'entrée de menu provoque l'interruption du démarrage par
|
||||||
le réseau et la poursuite du démarrage sur un média local.
|
le réseau et la poursuite du démarrage sur un média local. L'adresse de serveur
|
||||||
|
peut être donnée sous la forme de nom de domaine qui est recherché dans
|
||||||
|
/etc/hosts. Ce nom peut-être associé à plusieurs adresses IP, qui dans ce cas
|
||||||
|
sont utilisées à tour de rôle (en "round-robin").
|
||||||
.TP
|
.TP
|
||||||
.B --pxe-prompt=[tag:<label>,]<invite>[,<délai>]
|
.B --pxe-prompt=[tag:<label>,]<invite>[,<délai>]
|
||||||
Cette option permet d'afficher une invite à la suite du démarrage PXE. Si un
|
Cette option permet d'afficher une invite à la suite du démarrage PXE. Si un
|
||||||
@@ -1041,38 +1128,39 @@ créant des milliers de baux et utilisant beaucoup de mémoire dans le processus
|
|||||||
Dnsmasq.
|
Dnsmasq.
|
||||||
.TP
|
.TP
|
||||||
.B \-K, --dhcp-authoritative
|
.B \-K, --dhcp-authoritative
|
||||||
Cette option doit être donnée lorsque Dnsmasq est le seul serveur DHCP sur le
|
(IPv4 seulement) Cette option doit être donnée lorsque Dnsmasq est le seul
|
||||||
réseau. Cela change le comportement par défaut qui est celui d'un strict respect
|
serveur DHCP sur le réseau. Cela change le comportement par défaut qui est
|
||||||
des RFC, afin que les requêtes DHCP pour des baux inconnus par des hôtes
|
celui d'un strict respect des RFC, afin que les requêtes DHCP pour des baux
|
||||||
inconnus ne soient pas ignorées. Cela permet à de nouveaux hôtes d'obtenir des
|
inconnus par des hôtes inconnus ne soient pas ignorées. Cela permet à de
|
||||||
baux sans tenir compte de fastidieuses temporisations ("timeout"). Cela permet
|
nouveaux hôtes d'obtenir des baux sans tenir compte de fastidieuses
|
||||||
également à Dnsmasq de reconstruire sa base de donnée contenant les baux sans
|
temporisations ("timeout"). Cela permet également à Dnsmasq de reconstruire
|
||||||
que les clients n'aient besoin de redemander un bail, si celle-ci est perdue.
|
sa base de données contenant les baux sans que les clients n'aient besoin de
|
||||||
|
redemander un bail, si celle-ci est perdue.
|
||||||
.TP
|
.TP
|
||||||
.B --dhcp-alternate-port[=<port serveur>[,<port client>]]
|
.B --dhcp-alternate-port[=<port serveur>[,<port client>]]
|
||||||
Change les ports utilisés par défaut pour le DHCP. Si cette option est donnée
|
(IPv4 seulement) Change les ports utilisés par défaut pour le DHCP. Si cette
|
||||||
toute seule sans arguments, alors change les ports utilisés pour le DHCP
|
option est donnée seule sans argument, alors change les ports utilisés pour le
|
||||||
de 67 et 68 respectivement à 1067 et 1068. Si un seul argument est donné, ce
|
DHCP de 67 et 68 respectivement à 1067 et 1068. Si un seul argument est donné, ce
|
||||||
numéro est utilisé pour le port serveur et ce numéro plus 1 est utilisé pour le
|
numéro est utilisé pour le port serveur et ce numéro plus 1 est utilisé pour le
|
||||||
port client. Enfin, en fournissant deux numéros de ports, il est possible de
|
port client. Enfin, en fournissant deux numéros de ports, il est possible de
|
||||||
spécifier arbitrairement 2 ports à la fois pour le serveur et pour le client DHCP.
|
spécifier arbitrairement 2 ports à la fois pour le serveur et pour le client DHCP.
|
||||||
.TP
|
.TP
|
||||||
.B \-3, --bootp-dynamic[=<identifiant de réseau>[,<identifiant de réseau>]]
|
.B \-3, --bootp-dynamic[=<identifiant de réseau>[,<identifiant de réseau>]]
|
||||||
Permet l'allocation dynamique d'adresses IP à des clients BOOTP. Utiliser cette
|
(IPv4 seulement) Permet l'allocation dynamique d'adresses IP à des clients BOOTP.
|
||||||
option avec précaution, une adresse allouée à un client BOOTP étant perpétuelle,
|
Utiliser cette option avec précaution, une adresse allouée à un client BOOTP
|
||||||
et de fait n'est plus disponibles pour d'autres hôtes. Si aucun argument n'est
|
étant perpétuelle, et de fait n'est plus disponibles pour d'autres hôtes. Si
|
||||||
donné, alors cette option permet une allocation dynamique dans tous les cas. Si
|
aucun argument n'est donné, alors cette option permet une allocation dynamique
|
||||||
des arguments sont spécifiés, alors l'allocation ne se fait que lorsque tous
|
dans tous les cas. Si des arguments sont spécifiés, alors l'allocation ne se
|
||||||
les identifiants coïncident. Il est possible de répeter cette option avec
|
fait que lorsque tous les identifiants coïncident. Il est possible de répeter
|
||||||
plusieurs jeux d'arguments.
|
cette option avec plusieurs jeux d'arguments.
|
||||||
.TP
|
.TP
|
||||||
.B \-5, --no-ping
|
.B \-5, --no-ping
|
||||||
Par défaut, le serveur DHCP tente de s'assurer qu'une adresse n'est pas utilisée
|
(IPv4 seulement) Par défaut, le serveur DHCP tente de s'assurer qu'une adresse
|
||||||
avant de l'allouer à un hôte. Cela est fait en envoyant une requête ICMP de type
|
n'est pas utilisée avant de l'allouer à un hôte. Cela est fait en envoyant une
|
||||||
"echo request" (aussi connue sous le nom de "ping") à l'adresse en question. Si
|
requête ICMP de type "echo request" (aussi connue sous le nom de "ping") à
|
||||||
le serveur obtient une réponse, alors l'adresse doit déjà être utilisée et une
|
l'adresse en question. Si le serveur obtient une réponse, alors l'adresse doit
|
||||||
autre est essayée. Cette option permet de supprimer cette vérification. A
|
déjà être utilisée et une autre est essayée. Cette option permet de supprimer
|
||||||
utiliser avec précaution.
|
cette vérification. A utiliser avec précaution.
|
||||||
.TP
|
.TP
|
||||||
.B --log-dhcp
|
.B --log-dhcp
|
||||||
Traces additionnelles pour le service DHCP : enregistre toutes les options
|
Traces additionnelles pour le service DHCP : enregistre toutes les options
|
||||||
@@ -1089,11 +1177,11 @@ chemin est spécifié est exécuté. Le <chemin de fichier> doit être un chemi
|
|||||||
absolu, aucune recherche n'est effectuée via la variable d'environnement PATH.
|
absolu, aucune recherche n'est effectuée via la variable d'environnement PATH.
|
||||||
Les arguments fournis à celui-ci sont soit
|
Les arguments fournis à celui-ci sont soit
|
||||||
"add" ("ajouter"), "old" ("ancien") ou "del" ("supprimer"), suivi de l'adresse
|
"add" ("ajouter"), "old" ("ancien") ou "del" ("supprimer"), suivi de l'adresse
|
||||||
MAC de l'hôte puis l'adresse IP et le nom d'hôte si celui-ci est
|
MAC de l'hôte (ou le DUID pour IPv6) puis l'adresse IP et le nom d'hôte si
|
||||||
connu."add" signifie qu'un bail a été créé, "del" signifie qu'il a été supprimé,
|
celui-ci est connu."add" signifie qu'un bail a été créé, "del" signifie qu'il a
|
||||||
"old" notifie que le bail existait au lancement de Dnsmasq, ou un changement
|
été supprimé, "old" notifie que le bail existait au lancement de Dnsmasq, ou un
|
||||||
d'adresse MAC ou de nom d'hôte pour un bail existant (ou, dans le cas où
|
changement d'adresse MAC ou de nom d'hôte pour un bail existant (ou, dans le cas
|
||||||
leasefile-ro est spécifié, un changement de durée de bail ou d'identifiant
|
où leasefile-ro est spécifié, un changement de durée de bail ou d'identifiant
|
||||||
d'hôte). Si l'adresse Mac est d'un type de réseau autre qu'ethernet, il est
|
d'hôte). Si l'adresse Mac est d'un type de réseau autre qu'ethernet, il est
|
||||||
nécessaire de la préceder du type de réseau, par exemple "06-01:23:45:67:89:ab"
|
nécessaire de la préceder du type de réseau, par exemple "06-01:23:45:67:89:ab"
|
||||||
pour du token ring. Le processus est exécuté en temps que super-utilisateur
|
pour du token ring. Le processus est exécuté en temps que super-utilisateur
|
||||||
@@ -1103,18 +1191,16 @@ pour changer son UID pour celle d'un utilisateur non-privilégié.
|
|||||||
L'environnement est hérité de celui de l'invocation du processus Dnsmasq,
|
L'environnement est hérité de celui de l'invocation du processus Dnsmasq,
|
||||||
auquel se rajoute quelques unes ou toutes les variables décrites ci-dessous :
|
auquel se rajoute quelques unes ou toutes les variables décrites ci-dessous :
|
||||||
|
|
||||||
DNSMASQ_CLIENT_ID, si l'hôte a fourni un identifiant de client.
|
Pour IPv4 et IPv6 :
|
||||||
|
|
||||||
DNSMASQ_DOMAIN si le nom de domaine pleinement qualifié de l'hôte est connu, la
|
DNSMASQ_DOMAIN si le nom de domaine pleinement qualifié de l'hôte est connu, la
|
||||||
part relative au domaine y est stockée. (Notez que le nom d'hôte transmis comme
|
part relative au domaine y est stockée. (Notez que le nom d'hôte transmis comme
|
||||||
argument au script n'est jamais pleinement qualifié).
|
argument au script n'est jamais pleinement qualifié).
|
||||||
|
|
||||||
Si le client fournit une information de classe de vendeur, un nom d'hôte, ou
|
Si le client fournit un nom d'hôte, DNSMASQ_SUPPLIED_HOSTNAME.
|
||||||
des classes d'utilisateur, celles-ci sont fournies dans les
|
|
||||||
variables DNSMASQ_VENDOR_CLASS et DNSMASQ_USER_CLASS0 à DNSMASQ_USER_CLASSn
|
Si le client fournit des classes d'utilisateur, DNSMASQ_USER_CLASS0 à
|
||||||
et DNSMASQ_SUPPLIED_HOSTNAME respectivement, mais seulement pour les actions
|
DNSMASQ_USER_CLASSn.
|
||||||
"add" et "old" lorsqu'un hôte reprend un bail existant, ces variables n'étant
|
|
||||||
pas stockées dans la base de baux de Dnsmasq.
|
|
||||||
|
|
||||||
Si Dnsmasq a été compilé avec l'option HAVE_BROKEN_RTC ("horloge RTC
|
Si Dnsmasq a été compilé avec l'option HAVE_BROKEN_RTC ("horloge RTC
|
||||||
défectueuse"), alors la durée du bail (en secondes) est stockée dans la
|
défectueuse"), alors la durée du bail (en secondes) est stockée dans la
|
||||||
@@ -1137,6 +1223,29 @@ relai DHCP pour contacter Dnsmasq, si l'adresse IP du relai est connue.
|
|||||||
DNSMASQ_TAGS contient tous les labels fournis pendant la transaction DHCP,
|
DNSMASQ_TAGS contient tous les labels fournis pendant la transaction DHCP,
|
||||||
séparés par des espaces.
|
séparés par des espaces.
|
||||||
|
|
||||||
|
Pour IPv4 seulement :
|
||||||
|
|
||||||
|
DNSMASQ_CLIENT_ID, si l'hôte a fourni un identifiant de client.
|
||||||
|
|
||||||
|
Si le client fournit une information de classe de vendeur, DNSMASQ_VENDOR_CLASS.
|
||||||
|
|
||||||
|
Pour IPv6 seulement :
|
||||||
|
|
||||||
|
Si le client fournit une classe de vendeur (vendor-class), positionne
|
||||||
|
DNSMASQ_VENDOR_CLASS_ID avec comme contenu le numéro IANA de l'entreprise pour
|
||||||
|
la classe, et DNSMASQ_VENDOR_CLASS0..DNSMASQ_VENDOR_CLASSn pour les données.
|
||||||
|
|
||||||
|
DNSMASQ_SERVER_DUID contient le DUID du serveur : cette valeur est la même
|
||||||
|
pour chaque appel au script.
|
||||||
|
|
||||||
|
DNSMASQ_IAID contenant l'IAID pour le bail. Si le bail est une allocation
|
||||||
|
temporaire, cela est préfixé par le caractère 'T'.
|
||||||
|
|
||||||
|
A noter que le nom d'hôte fourni, la classe de vendeur ou les données de classe
|
||||||
|
d'utilisateur sont uniquement fournies pour les actions "add" ou l'action "old"
|
||||||
|
lorsqu'un hôte reprend un bail existant, puisque ces informations ne sont pas
|
||||||
|
conservées dans la base de baux de dnsmasq.
|
||||||
|
|
||||||
Tous les descripteurs de fichiers sont fermés, sauf stdin, stdout et stderr qui
|
Tous les descripteurs de fichiers sont fermés, sauf stdin, stdout et stderr qui
|
||||||
sont ouverts sur /dev/null (sauf en mode déverminage).
|
sont ouverts sur /dev/null (sauf en mode déverminage).
|
||||||
|
|
||||||
@@ -1153,11 +1262,50 @@ Au démarrage de Dnsmasq, le script sera invoqué pour chacun des baux existants
|
|||||||
dans le fichier des baux. Le script sera lancé avec l'action "del" pour les
|
dans le fichier des baux. Le script sera lancé avec l'action "del" pour les
|
||||||
baux expirés, et "old" pour les autres. Lorsque Dnsmasq reçoit un signal HUP,
|
baux expirés, et "old" pour les autres. Lorsque Dnsmasq reçoit un signal HUP,
|
||||||
le script sera invoqué avec une action "old" pour tous les baux existants.
|
le script sera invoqué avec une action "old" pour tous les baux existants.
|
||||||
.TP
|
.TP
|
||||||
|
.B --dhcp-luascript=<chemin>
|
||||||
|
Spécifie un script écrit en Lua, devant être exécuté lorsque des baux sont
|
||||||
|
créés, détruits ou modifiés. Pour utiliser cette option, dnsmasq doit être
|
||||||
|
compilé avec avec le support de Lua. L'interpréteur Lua est initialisé une
|
||||||
|
seule fois, lorsque dnsmasq démarre, ce qui fait que les variables globales
|
||||||
|
persistent entre les évênements liés aux baux. Le code Lua doit définir une
|
||||||
|
fonction
|
||||||
|
.B lease
|
||||||
|
et peut fournir des fonctions
|
||||||
|
.B init
|
||||||
|
et
|
||||||
|
.B shutdown
|
||||||
|
qui sont appellées, sans arguments, lorsque dnsmasq démarre ou s'arrête.
|
||||||
|
|
||||||
|
La méthode
|
||||||
|
.B lease
|
||||||
|
reçoit les informations détaillées dans
|
||||||
|
.B --dhcp-script.
|
||||||
|
Il reçoit deux arguments. Le premier spécifie l'action, qui est une chaîne de
|
||||||
|
caractères contenant les valeurs "add" (ajout), "old" (réactivation d'un bail
|
||||||
|
existant) ou "del" (suppression). Le deuxième est une table contenant des
|
||||||
|
paires de valeurs de labels. Les labels correspondent pour l'essentiel aux
|
||||||
|
valeurs d'environnement détaillées ci-dessus, ainsi le label "domain" (domaine)
|
||||||
|
contient les mêmes données que la variable d'environnement DNSMASQ_DOMAIN. Il
|
||||||
|
existe quelques labels supplémentaires contenant les données fournies comme
|
||||||
|
arguments à
|
||||||
|
.B --dhcp-script.
|
||||||
|
Ces labels sont
|
||||||
|
.B mac_address, ip_address
|
||||||
|
(pour respectivement l'adresse MAC et l'adresse IP)
|
||||||
|
et
|
||||||
|
.B hostname
|
||||||
|
(le nom d'hôte) dans le cas d'IPv4, et
|
||||||
|
.B client_duid, ip_address
|
||||||
|
(valeur DUID du client et adresse IP respectivement)
|
||||||
|
ainsi que
|
||||||
|
.B hostname
|
||||||
|
(le nom d'hôte) dans le cas d'IPv6.
|
||||||
|
.TP
|
||||||
.B --dhcp-scriptuser
|
.B --dhcp-scriptuser
|
||||||
Spécifie l'utilisateur sous lequel le script lease-change doit être exécuté. La
|
Spécifie l'utilisateur sous lequel le script shell lease-change ou le script
|
||||||
valeur par défaut correspond à l'utilisateur root mais peut-être changée par le
|
doivent être exécutés. La valeur par défaut correspond à l'utilisateur root
|
||||||
biais de cette option.
|
mais peut-être changée par le biais de cette option.
|
||||||
.TP
|
.TP
|
||||||
.B \-9, --leasefile-ro
|
.B \-9, --leasefile-ro
|
||||||
Supprimer complètement l'usage du fichier servant de base de donnée pour les
|
Supprimer complètement l'usage du fichier servant de base de donnée pour les
|
||||||
@@ -1242,6 +1390,32 @@ sans gamme d'adresses de spécifié lorsque l'option
|
|||||||
.B --dhcp-fqdn
|
.B --dhcp-fqdn
|
||||||
est configurée.
|
est configurée.
|
||||||
.TP
|
.TP
|
||||||
|
.B --dhcp-client-update
|
||||||
|
Normalement, lorsque dnsmasq fournit un bail DHCP, il positionne un label
|
||||||
|
dans l'option FQDN pour indiquer au client qu'il ne doit pas tenter de faire
|
||||||
|
une mise à jour DDNS avec son nom et son adresse IP. Ceci parce que la paire
|
||||||
|
Nom-IP est rajoutée automatiquement dans la partie DNS de dnsmasq. Cette option
|
||||||
|
inhibe ce comportement ce qui est utile, par exemple, pour permettre aux clients
|
||||||
|
Windows de la mise à jour de serveurs Active Directory. Voir la RFC 4702 pour
|
||||||
|
plus de détails.
|
||||||
|
.TP
|
||||||
|
.B --enable-ra
|
||||||
|
Active la fonctionalité d'annonces routeurs IPv6 ("IPv6 Router Advertisement").
|
||||||
|
DHCPv6 ne gère pas la configuration complète du réseau de la même façon que
|
||||||
|
DHCPv4. La découverte de routeurs et la découverte (éventuelle) de préfixes pour
|
||||||
|
la création autonome d'adresse sont gérées par un protocole différent.
|
||||||
|
Lorsque DHCP est utilisé, seul un sous-ensemble de tout ceci est nécessaire et
|
||||||
|
dnsmasq est à même de le gérer, en utilisant la configuration DHCP présente pour
|
||||||
|
fournir la majorité des données. Lorsque les annonces routeurs (RA pour "Router
|
||||||
|
Advertisement") sont activées, dnsmasq va annoncer un préfixe pour chaque
|
||||||
|
dhcp-range et, par défaut, fournir comme valeur de routeur et de DNS récursif
|
||||||
|
la valeur d'adresse link-local appropriée parmi celles de la machine sur
|
||||||
|
laquelle tourne dnsmasq.
|
||||||
|
Les bits "managed address" sont positionnés, sauf pour un dhcp-range marqué
|
||||||
|
comme "ra-only" (annonce routeur uniquement). Dans ce cas le service d'annonce
|
||||||
|
routeur est rendu mais aucun service DHCPv6 n'est assuré, et les bits "managed
|
||||||
|
address" ne sont pas positionnés.
|
||||||
|
.TP
|
||||||
.B --enable-tftp[=<interface>]
|
.B --enable-tftp[=<interface>]
|
||||||
Active la fonction serveur TFTP. Celui-ci est de manière délibérée limité aux
|
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
|
fonctions nécessaires au démarrage par le réseau ("net-boot") d'un client. Seul
|
||||||
@@ -1417,7 +1591,6 @@ Dans le cas de l'utilisation du logiciel logrotate, les options requises sont
|
|||||||
.B create
|
.B create
|
||||||
et
|
et
|
||||||
.B delaycompress.
|
.B delaycompress.
|
||||||
|
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
Dnsmasq est un logiciel de transmission de requêtes DNS : il n'est pas capable
|
Dnsmasq est un logiciel de transmission de requêtes DNS : il n'est pas capable
|
||||||
@@ -1509,6 +1682,17 @@ labels définis pour l'hôte considéré. (dans le cas de l'utilisation dans une
|
|||||||
ligne de commande au lieu d'un fichier de configuration, ne pas oublier
|
ligne de commande au lieu d'un fichier de configuration, ne pas oublier
|
||||||
d'échapper le caractère !, qui est un méta-caractère d'interpréteur de commande
|
d'échapper le caractère !, qui est un méta-caractère d'interpréteur de commande
|
||||||
shell).
|
shell).
|
||||||
|
|
||||||
|
Lors de la sélection d'une option, une étiquette spécifiée par dhcp-range
|
||||||
|
passe après les autres étiquettes, ce qui permet de facilement remplacer des
|
||||||
|
option génériques pour des hôtes spécifiques, ainsi :
|
||||||
|
.B dhcp-range=set:interface1,......
|
||||||
|
.B dhcp-host=set:monhote,.....
|
||||||
|
.B dhcp-option=tag:interface1,option:nis-domain,"domaine1"
|
||||||
|
.B dhcp-option=tag:monhote,option:nis-domain,"domaine2"
|
||||||
|
va positionner l'option NIS-domain à domaine1 pour les hôtes dans la plage
|
||||||
|
d'adresse, sauf pour monhote pour lequel cette valeur sera domaine2.
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
Veuillez noter que pour
|
Veuillez noter que pour
|
||||||
.B dhcp-range
|
.B dhcp-range
|
||||||
|
|||||||
+700
-558
File diff suppressed because it is too large.
Load diff
+1
-1
@@ -221,7 +221,7 @@ triggering dial-on-demand internet links.
|
|||||||
Sending SIGHUP to the dnsmasq process will cause it to empty its cache and
|
Sending SIGHUP to the dnsmasq process will cause it to empty its cache and
|
||||||
then re-load <TT>/etc/hosts</TT> and <TT>/etc/resolv.conf</TT>.
|
then re-load <TT>/etc/hosts</TT> and <TT>/etc/resolv.conf</TT>.
|
||||||
<P> Sending SIGUSR1 (killall -10 dnsmasq) to the dnsmasq process will
|
<P> Sending SIGUSR1 (killall -10 dnsmasq) to the dnsmasq process will
|
||||||
cause to to write cache usage statisticss to the log, typically
|
cause to write cache usage statisticss to the log, typically
|
||||||
<TT>/var/log/syslog</TT> or <TT>/var/log/messages</TT>.
|
<TT>/var/log/syslog</TT> or <TT>/var/log/messages</TT>.
|
||||||
<P> The <TT>log-queries</TT> option tells dnsmasq to verbosely log the queries
|
<P> The <TT>log-queries</TT> option tells dnsmasq to verbosely log the queries
|
||||||
it is handling and causes SIGUSR1 to trigger a complete dump of the
|
it is handling and causes SIGUSR1 to trigger a complete dump of the
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -17,24 +17,21 @@
|
|||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
#if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
|
#if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
|
||||||
|
#include <ifaddrs.h>
|
||||||
static struct iovec ifconf = {
|
|
||||||
.iov_base = NULL,
|
|
||||||
.iov_len = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct iovec ifreq = {
|
|
||||||
.iov_base = NULL,
|
|
||||||
.iov_len = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||||
|
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <net/route.h>
|
#include <net/route.h>
|
||||||
#include <net/if_dl.h>
|
#include <net/if_dl.h>
|
||||||
#include <netinet/if_ether.h>
|
#include <netinet/if_ether.h>
|
||||||
|
|
||||||
|
#ifndef SA_SIZE
|
||||||
|
#define SA_SIZE(sa) \
|
||||||
|
( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
|
||||||
|
sizeof(long) : \
|
||||||
|
1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
|
||||||
|
#endif
|
||||||
|
|
||||||
int arp_enumerate(void *parm, int (*callback)())
|
int arp_enumerate(void *parm, int (*callback)())
|
||||||
{
|
{
|
||||||
int mib[6];
|
int mib[6];
|
||||||
@@ -43,8 +40,12 @@ int arp_enumerate(void *parm, int (*callback)())
|
|||||||
struct rt_msghdr *rtm;
|
struct rt_msghdr *rtm;
|
||||||
struct sockaddr_inarp *sin2;
|
struct sockaddr_inarp *sin2;
|
||||||
struct sockaddr_dl *sdl;
|
struct sockaddr_dl *sdl;
|
||||||
|
struct iovec buff;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
buff.iov_base = NULL;
|
||||||
|
buff.iov_len = 0;
|
||||||
|
|
||||||
mib[0] = CTL_NET;
|
mib[0] = CTL_NET;
|
||||||
mib[1] = PF_ROUTE;
|
mib[1] = PF_ROUTE;
|
||||||
mib[2] = 0;
|
mib[2] = 0;
|
||||||
@@ -60,9 +61,9 @@ int arp_enumerate(void *parm, int (*callback)())
|
|||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (!expand_buf(&ifconf, needed))
|
if (!expand_buf(&buff, needed))
|
||||||
return 0;
|
return 0;
|
||||||
if ((rc = sysctl(mib, 6, ifconf.iov_base, &needed, NULL, 0)) == 0 ||
|
if ((rc = sysctl(mib, 6, buff.iov_base, &needed, NULL, 0)) == 0 ||
|
||||||
errno != ENOMEM)
|
errno != ENOMEM)
|
||||||
break;
|
break;
|
||||||
needed += needed / 8;
|
needed += needed / 8;
|
||||||
@@ -70,7 +71,7 @@ int arp_enumerate(void *parm, int (*callback)())
|
|||||||
if (rc == -1)
|
if (rc == -1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (next = ifconf.iov_base ; next < (char *)ifconf.iov_base + needed; next += rtm->rtm_msglen)
|
for (next = buff.iov_base ; next < (char *)buff.iov_base + needed; next += rtm->rtm_msglen)
|
||||||
{
|
{
|
||||||
rtm = (struct rt_msghdr *)next;
|
rtm = (struct rt_msghdr *)next;
|
||||||
sin2 = (struct sockaddr_inarp *)(rtm + 1);
|
sin2 = (struct sockaddr_inarp *)(rtm + 1);
|
||||||
@@ -81,19 +82,14 @@ int arp_enumerate(void *parm, int (*callback)())
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int iface_enumerate(int family, void *parm, int (*callback)())
|
int iface_enumerate(int family, void *parm, int (*callback)())
|
||||||
{
|
{
|
||||||
char *ptr;
|
struct ifaddrs *head, *addrs;
|
||||||
struct ifreq *ifr;
|
int errsav, ret = 0;
|
||||||
struct ifconf ifc;
|
|
||||||
int fd, errsav, ret = 0;
|
|
||||||
int lastlen = 0;
|
|
||||||
size_t len = 0;
|
|
||||||
|
|
||||||
if (family == AF_UNSPEC)
|
if (family == AF_UNSPEC)
|
||||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||||
return arp_enumerate(parm, callback);
|
return arp_enumerate(parm, callback);
|
||||||
@@ -101,87 +97,69 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
return 0; /* need code for Solaris and MacOS*/
|
return 0; /* need code for Solaris and MacOS*/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
|
/* AF_LINK doesn't exist in Linux, so we can't use it in our API */
|
||||||
|
if (family == AF_LOCAL)
|
||||||
|
family = AF_LINK;
|
||||||
|
|
||||||
|
if (getifaddrs(&head) == -1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
while(1)
|
|
||||||
{
|
|
||||||
len += 10*sizeof(struct ifreq);
|
|
||||||
|
|
||||||
if (!expand_buf(&ifconf, len))
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
ifc.ifc_len = len;
|
|
||||||
ifc.ifc_buf = ifconf.iov_base;
|
|
||||||
|
|
||||||
if (ioctl(fd, SIOCGIFCONF, &ifc) == -1)
|
|
||||||
{
|
|
||||||
if (errno != EINVAL || lastlen != 0)
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (ifc.ifc_len == lastlen)
|
|
||||||
break; /* got a big enough buffer now */
|
|
||||||
lastlen = ifc.ifc_len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ptr = ifc.ifc_buf; ptr < (char *)(ifc.ifc_buf + ifc.ifc_len); ptr += len)
|
|
||||||
{
|
|
||||||
/* subsequent entries may not be aligned, so copy into
|
|
||||||
an aligned buffer to avoid nasty complaints about
|
|
||||||
unaligned accesses. */
|
|
||||||
|
|
||||||
len = sizeof(struct ifreq);
|
for (addrs = head; addrs; addrs = addrs->ifa_next)
|
||||||
|
{
|
||||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
if (addrs->ifa_addr->sa_family == family)
|
||||||
ifr = (struct ifreq *)ptr;
|
|
||||||
if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_ifru))
|
|
||||||
len = ifr->ifr_addr.sa_len + offsetof(struct ifreq, ifr_ifru);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!expand_buf(&ifreq, len))
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
ifr = (struct ifreq *)ifreq.iov_base;
|
|
||||||
memcpy(ifr, ptr, len);
|
|
||||||
|
|
||||||
if (ifr->ifr_addr.sa_family == family)
|
|
||||||
{
|
{
|
||||||
|
int iface_index = if_nametoindex(addrs->ifa_name);
|
||||||
|
|
||||||
|
if (iface_index == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (family == AF_INET)
|
if (family == AF_INET)
|
||||||
{
|
{
|
||||||
struct in_addr addr, netmask, broadcast;
|
struct in_addr addr, netmask, broadcast;
|
||||||
broadcast.s_addr = 0;
|
addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
|
||||||
addr = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
|
||||||
if (ioctl(fd, SIOCGIFNETMASK, ifr) == -1)
|
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
|
||||||
continue;
|
if (!((*callback)(addr, iface_index, netmask, broadcast, parm)))
|
||||||
netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
|
||||||
if (ioctl(fd, SIOCGIFBRDADDR, ifr) != -1)
|
|
||||||
broadcast = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
|
||||||
if (!((*callback)(addr,
|
|
||||||
(int)if_nametoindex(ifr->ifr_name),
|
|
||||||
netmask, broadcast,
|
|
||||||
parm)))
|
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else if (family == AF_INET6)
|
else if (family == AF_INET6)
|
||||||
{
|
{
|
||||||
struct in6_addr *addr = &((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr;
|
struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr;
|
||||||
|
unsigned char *netmask = (unsigned char *) &((struct sockaddr_in6 *) addrs->ifa_netmask)->sin6_addr;
|
||||||
|
int scope_id = ((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id;
|
||||||
|
int i, j, prefix = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < IN6ADDRSZ; i++, prefix += 8)
|
||||||
|
if (netmask[i] != 0xff)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (i != IN6ADDRSZ && netmask[i])
|
||||||
|
for (j = 7; j > 0; j--, prefix++)
|
||||||
|
if ((netmask[i] & (1 << j)) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
/* voodoo to clear interface field in address */
|
/* voodoo to clear interface field in address */
|
||||||
if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
|
if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
|
||||||
{
|
{
|
||||||
addr->s6_addr[2] = 0;
|
addr->s6_addr[2] = 0;
|
||||||
addr->s6_addr[3] = 0;
|
addr->s6_addr[3] = 0;
|
||||||
}
|
}
|
||||||
if (!((*callback)(addr,
|
|
||||||
(int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
|
if (!((*callback)(addr, prefix, scope_id, iface_index, 0, parm)))
|
||||||
(int)if_nametoindex(ifr->ifr_name),
|
goto err;
|
||||||
parm)))
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
else if (family == AF_LINK)
|
||||||
|
{
|
||||||
|
/* Assume ethernet again here */
|
||||||
|
struct sockaddr_dl *sdl = (struct sockaddr_dl *) addrs->ifa_addr;
|
||||||
|
if (sdl->sdl_alen != 0 &&
|
||||||
|
!((*callback)(iface_index, ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm)))
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +167,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
|
|
||||||
err:
|
err:
|
||||||
errsav = errno;
|
errsav = errno;
|
||||||
close(fd);
|
freeifaddrs(head);
|
||||||
errno = errsav;
|
errno = errsav;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -206,13 +184,10 @@ void init_bpf(void)
|
|||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
/* useful size which happens to be sufficient */
|
sprintf(daemon->dhcp_buff, "/dev/bpf%d", i++);
|
||||||
if (expand_buf(&ifreq, sizeof(struct ifreq)))
|
if ((daemon->dhcp_raw_fd = open(daemon->dhcp_buff, O_RDWR, 0)) != -1)
|
||||||
{
|
return;
|
||||||
sprintf(ifreq.iov_base, "/dev/bpf%d", i++);
|
|
||||||
if ((daemon->dhcp_raw_fd = open(ifreq.iov_base, O_RDWR, 0)) != -1)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (errno != EBUSY)
|
if (errno != EBUSY)
|
||||||
die(_("cannot create DHCP BPF socket: %s"), NULL, EC_BADNET);
|
die(_("cannot create DHCP BPF socket: %s"), NULL, EC_BADNET);
|
||||||
}
|
}
|
||||||
|
|||||||
+151
-88
@@ -1,4 +1,4 @@
|
|||||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -25,7 +25,6 @@ static int cache_inserted = 0, cache_live_freed = 0, insert_error;
|
|||||||
static union bigname *big_free = NULL;
|
static union bigname *big_free = NULL;
|
||||||
static int bignames_left, hash_size;
|
static int bignames_left, hash_size;
|
||||||
static int uid = 0;
|
static int uid = 0;
|
||||||
static char *addrbuff = NULL;
|
|
||||||
|
|
||||||
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
|
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
|
||||||
static const struct {
|
static const struct {
|
||||||
@@ -75,9 +74,6 @@ void cache_init(void)
|
|||||||
struct crec *crecp;
|
struct crec *crecp;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (option_bool(OPT_LOG))
|
|
||||||
addrbuff = safe_malloc(ADDRSTRLEN);
|
|
||||||
|
|
||||||
bignames_left = daemon->cachesize/10;
|
bignames_left = daemon->cachesize/10;
|
||||||
|
|
||||||
if (daemon->cachesize > 0)
|
if (daemon->cachesize > 0)
|
||||||
@@ -638,12 +634,14 @@ struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
|
static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
|
||||||
unsigned short flags, int index, int addr_dup)
|
int index, struct crec **rhash, int hashsz)
|
||||||
{
|
{
|
||||||
struct crec *lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6));
|
struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
|
||||||
int i, nameexists = 0;
|
int i, nameexists = 0;
|
||||||
struct cname *a;
|
struct cname *a;
|
||||||
|
unsigned int j;
|
||||||
|
|
||||||
/* Remove duplicates in hosts files. */
|
/* Remove duplicates in hosts files. */
|
||||||
if (lookup && (lookup->flags & F_HOSTS))
|
if (lookup && (lookup->flags & F_HOSTS))
|
||||||
@@ -657,39 +655,44 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure there is only one address -> name mapping (first one trumps)
|
/* Ensure there is only one address -> name mapping (first one trumps)
|
||||||
We do this by steam here, first we see if the address is the same as
|
We do this by steam here, The entries are kept in hash chains, linked
|
||||||
the last one we saw, which eliminates most in the case of an ad-block
|
by ->next (which is unused at this point) held in hash buckets in
|
||||||
file with thousands of entries for the same address.
|
the array rhash, hashed on address. Note that rhash and the values
|
||||||
Then we search and bail at the first matching address that came from
|
in ->next are only valid whilst reading hosts files: the buckets are
|
||||||
a HOSTS file. Since the first host entry gets reverse, we know
|
then freed, and the ->next pointer used for other things.
|
||||||
then that it must exist without searching exhaustively for it. */
|
|
||||||
|
Only insert each unique address once into this hashing structure.
|
||||||
|
|
||||||
|
This complexity avoids O(n^2) divergent CPU use whilst reading
|
||||||
|
large (10000 entry) hosts files. */
|
||||||
|
|
||||||
if (addr_dup)
|
/* hash address */
|
||||||
flags &= ~F_REVERSE;
|
for (j = 0, i = 0; i < addrlen; i++)
|
||||||
else
|
j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
|
||||||
for (i=0; i<hash_size; i++)
|
|
||||||
|
for (lookup = rhash[j]; lookup; lookup = lookup->next)
|
||||||
|
if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
|
||||||
|
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
|
||||||
{
|
{
|
||||||
for (lookup = hash_table[i]; lookup; lookup = lookup->hash_next)
|
cache->flags &= ~F_REVERSE;
|
||||||
if ((lookup->flags & F_HOSTS) &&
|
break;
|
||||||
(lookup->flags & flags & (F_IPV4 | F_IPV6)) &&
|
|
||||||
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
|
|
||||||
{
|
|
||||||
flags &= ~F_REVERSE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (lookup)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cache->flags = flags;
|
/* maintain address hash chain, insert new unique address */
|
||||||
|
if (!lookup)
|
||||||
|
{
|
||||||
|
cache->next = rhash[j];
|
||||||
|
rhash[j] = cache;
|
||||||
|
}
|
||||||
|
|
||||||
cache->uid = index;
|
cache->uid = index;
|
||||||
memcpy(&cache->addr.addr, addr, addrlen);
|
memcpy(&cache->addr.addr, addr, addrlen);
|
||||||
cache_hash(cache);
|
cache_hash(cache);
|
||||||
|
|
||||||
/* don't need to do alias stuff for second and subsequent addresses. */
|
/* don't need to do alias stuff for second and subsequent addresses. */
|
||||||
if (!nameexists)
|
if (!nameexists)
|
||||||
for (a = daemon->cnames; a; a = a->next)
|
for (a = daemon->cnames; a; a = a->next)
|
||||||
if (hostname_isequal(cache->name.sname, a->target) &&
|
if (hostname_isequal(cache_get_name(cache), a->target) &&
|
||||||
(lookup = whine_malloc(sizeof(struct crec))))
|
(lookup = whine_malloc(sizeof(struct crec))))
|
||||||
{
|
{
|
||||||
lookup->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_HOSTS | F_CNAME;
|
lookup->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_HOSTS | F_CNAME;
|
||||||
@@ -747,14 +750,14 @@ static int gettok(FILE *f, char *token)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_hostsfile(char *filename, int index, int cache_size)
|
static int read_hostsfile(char *filename, int index, int cache_size, struct crec **rhash, int hashsz)
|
||||||
{
|
{
|
||||||
FILE *f = fopen(filename, "r");
|
FILE *f = fopen(filename, "r");
|
||||||
char *token = daemon->namebuff, *domain_suffix = NULL;
|
char *token = daemon->namebuff, *domain_suffix = NULL;
|
||||||
int addr_count = 0, name_count = cache_size, lineno = 0;
|
int addr_count = 0, name_count = cache_size, lineno = 0;
|
||||||
unsigned short flags = 0, saved_flags = 0;
|
unsigned short flags = 0;
|
||||||
struct all_addr addr, saved_addr;
|
struct all_addr addr;
|
||||||
int atnl, addrlen = 0, addr_dup;
|
int atnl, addrlen = 0;
|
||||||
|
|
||||||
if (!f)
|
if (!f)
|
||||||
{
|
{
|
||||||
@@ -766,28 +769,20 @@ static int read_hostsfile(char *filename, int index, int cache_size)
|
|||||||
|
|
||||||
while ((atnl = gettok(f, token)) != EOF)
|
while ((atnl = gettok(f, token)) != EOF)
|
||||||
{
|
{
|
||||||
addr_dup = 0;
|
|
||||||
lineno++;
|
lineno++;
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
if (inet_pton(AF_INET, token, &addr) > 0)
|
if (inet_pton(AF_INET, token, &addr) > 0)
|
||||||
{
|
{
|
||||||
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
|
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
|
||||||
addrlen = INADDRSZ;
|
addrlen = INADDRSZ;
|
||||||
domain_suffix = get_domain(addr.addr.addr4);
|
domain_suffix = get_domain(addr.addr.addr4);
|
||||||
}
|
}
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
else if (inet_pton(AF_INET6, token, &addr) > 0)
|
else if (inet_pton(AF_INET6, token, &addr) > 0)
|
||||||
{
|
{
|
||||||
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
|
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
|
||||||
addrlen = IN6ADDRSZ;
|
addrlen = IN6ADDRSZ;
|
||||||
domain_suffix = daemon->domain_suffix;
|
domain_suffix = get_domain6(&addr.addr.addr6);
|
||||||
}
|
|
||||||
#else
|
|
||||||
if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1)
|
|
||||||
{
|
|
||||||
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
|
|
||||||
addrlen = INADDRSZ;
|
|
||||||
domain_suffix = get_domain(addr.addr.addr4);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
@@ -798,14 +793,6 @@ static int read_hostsfile(char *filename, int index, int cache_size)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (saved_flags == flags && memcmp(&addr, &saved_addr, addrlen) == 0)
|
|
||||||
addr_dup = 1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
saved_flags = flags;
|
|
||||||
saved_addr = addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr_count++;
|
addr_count++;
|
||||||
|
|
||||||
/* rehash every 1000 names. */
|
/* rehash every 1000 names. */
|
||||||
@@ -836,14 +823,15 @@ static int read_hostsfile(char *filename, int index, int cache_size)
|
|||||||
strcpy(cache->name.sname, canon);
|
strcpy(cache->name.sname, canon);
|
||||||
strcat(cache->name.sname, ".");
|
strcat(cache->name.sname, ".");
|
||||||
strcat(cache->name.sname, domain_suffix);
|
strcat(cache->name.sname, domain_suffix);
|
||||||
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
|
cache->flags = flags;
|
||||||
addr_dup = 1;
|
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
|
||||||
name_count++;
|
name_count++;
|
||||||
}
|
}
|
||||||
if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
|
if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
|
||||||
{
|
{
|
||||||
strcpy(cache->name.sname, canon);
|
strcpy(cache->name.sname, canon);
|
||||||
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
|
cache->flags = flags;
|
||||||
|
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
|
||||||
name_count++;
|
name_count++;
|
||||||
}
|
}
|
||||||
free(canon);
|
free(canon);
|
||||||
@@ -865,8 +853,10 @@ static int read_hostsfile(char *filename, int index, int cache_size)
|
|||||||
void cache_reload(void)
|
void cache_reload(void)
|
||||||
{
|
{
|
||||||
struct crec *cache, **up, *tmp;
|
struct crec *cache, **up, *tmp;
|
||||||
int i, total_size = daemon->cachesize;
|
int revhashsz, i, total_size = daemon->cachesize;
|
||||||
struct hostsfile *ah;
|
struct hostsfile *ah;
|
||||||
|
struct host_record *hr;
|
||||||
|
struct name_list *nl;
|
||||||
|
|
||||||
cache_inserted = cache_live_freed = 0;
|
cache_inserted = cache_live_freed = 0;
|
||||||
|
|
||||||
@@ -893,20 +883,48 @@ void cache_reload(void)
|
|||||||
up = &cache->hash_next;
|
up = &cache->hash_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* borrow the packet buffer for a temporary by-address hash */
|
||||||
|
memset(daemon->packet, 0, daemon->packet_buff_sz);
|
||||||
|
revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
|
||||||
|
/* we overwrote the buffer... */
|
||||||
|
daemon->srv_save = NULL;
|
||||||
|
|
||||||
|
/* Do host_records in config. */
|
||||||
|
for (hr = daemon->host_records; hr; hr = hr->next)
|
||||||
|
for (nl = hr->names; nl; nl = nl->next)
|
||||||
|
{
|
||||||
|
if (hr->addr.s_addr != 0 &&
|
||||||
|
(cache = whine_malloc(sizeof(struct crec))))
|
||||||
|
{
|
||||||
|
cache->name.namep = nl->name;
|
||||||
|
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
|
||||||
|
add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
|
||||||
|
}
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
|
||||||
|
(cache = whine_malloc(sizeof(struct crec))))
|
||||||
|
{
|
||||||
|
cache->name.namep = nl->name;
|
||||||
|
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
|
||||||
|
add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
|
if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
|
||||||
{
|
{
|
||||||
if (daemon->cachesize > 0)
|
if (daemon->cachesize > 0)
|
||||||
my_syslog(LOG_INFO, _("cleared cache"));
|
my_syslog(LOG_INFO, _("cleared cache"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!option_bool(OPT_NO_HOSTS))
|
if (!option_bool(OPT_NO_HOSTS))
|
||||||
total_size = read_hostsfile(HOSTSFILE, 0, total_size);
|
total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz);
|
||||||
|
|
||||||
daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
|
daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
|
||||||
for (ah = daemon->addn_hosts; ah; ah = ah->next)
|
for (ah = daemon->addn_hosts; ah; ah = ah->next)
|
||||||
if (!(ah->flags & AH_INACTIVE))
|
if (!(ah->flags & AH_INACTIVE))
|
||||||
total_size = read_hostsfile(ah->fname, ah->index, total_size);
|
total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *get_domain(struct in_addr addr)
|
char *get_domain(struct in_addr addr)
|
||||||
@@ -914,14 +932,49 @@ char *get_domain(struct in_addr addr)
|
|||||||
struct cond_domain *c;
|
struct cond_domain *c;
|
||||||
|
|
||||||
for (c = daemon->cond_domain; c; c = c->next)
|
for (c = daemon->cond_domain; c; c = c->next)
|
||||||
if (ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
|
if (!c->is6 &&
|
||||||
|
ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
|
||||||
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
|
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
|
||||||
return c->domain;
|
return c->domain;
|
||||||
|
|
||||||
return daemon->domain_suffix;
|
return daemon->domain_suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
char *get_domain6(struct in6_addr *addr)
|
||||||
|
{
|
||||||
|
struct cond_domain *c;
|
||||||
|
|
||||||
|
u64 addrpart = addr6part(addr);
|
||||||
|
|
||||||
|
for (c = daemon->cond_domain; c; c = c->next)
|
||||||
|
if (c->is6 &&
|
||||||
|
is_same_net6(addr, &c->start6, 64) &&
|
||||||
|
addrpart >= addr6part(&c->start6) &&
|
||||||
|
addrpart <= addr6part(&c->end6))
|
||||||
|
return c->domain;
|
||||||
|
|
||||||
|
return daemon->domain_suffix;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
|
struct in_addr a_record_from_hosts(char *name, time_t now)
|
||||||
|
{
|
||||||
|
struct crec *crecp = NULL;
|
||||||
|
struct in_addr ret;
|
||||||
|
|
||||||
|
while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
|
||||||
|
if (crecp->flags & F_HOSTS)
|
||||||
|
return *(struct in_addr *)&crecp->addr;
|
||||||
|
|
||||||
|
my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
|
||||||
|
|
||||||
|
ret.s_addr = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void cache_unhash_dhcp(void)
|
void cache_unhash_dhcp(void)
|
||||||
{
|
{
|
||||||
struct crec *cache, **up;
|
struct crec *cache, **up;
|
||||||
@@ -939,15 +992,24 @@ void cache_unhash_dhcp(void)
|
|||||||
up = &cache->hash_next;
|
up = &cache->hash_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cache_add_dhcp_entry(char *host_name,
|
void cache_add_dhcp_entry(char *host_name, int prot,
|
||||||
struct in_addr *host_address, time_t ttd)
|
struct all_addr *host_address, time_t ttd)
|
||||||
{
|
{
|
||||||
struct crec *crec = NULL, *aliasc;
|
struct crec *crec = NULL, *aliasc;
|
||||||
unsigned short flags = F_NAMEP | F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
|
unsigned short flags = F_IPV4;
|
||||||
int in_hosts = 0;
|
int in_hosts = 0;
|
||||||
struct cname *a;
|
struct cname *a;
|
||||||
|
size_t addrlen = sizeof(struct in_addr);
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
if (prot == AF_INET6)
|
||||||
|
{
|
||||||
|
flags = F_IPV6;
|
||||||
|
addrlen = sizeof(struct in6_addr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
while ((crec = cache_find_by_name(crec, host_name, 0, F_IPV4 | F_CNAME)))
|
while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
|
||||||
{
|
{
|
||||||
/* check all addresses associated with name */
|
/* check all addresses associated with name */
|
||||||
if (crec->flags & F_HOSTS)
|
if (crec->flags & F_HOSTS)
|
||||||
@@ -955,23 +1017,25 @@ void cache_add_dhcp_entry(char *host_name,
|
|||||||
/* if in hosts, don't need DHCP record */
|
/* if in hosts, don't need DHCP record */
|
||||||
in_hosts = 1;
|
in_hosts = 1;
|
||||||
|
|
||||||
|
inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
|
||||||
if (crec->flags & F_CNAME)
|
if (crec->flags & F_CNAME)
|
||||||
|
|
||||||
my_syslog(MS_DHCP | LOG_WARNING,
|
my_syslog(MS_DHCP | LOG_WARNING,
|
||||||
_("%s is a CNAME, not giving it to the DHCP lease of %s"),
|
_("%s is a CNAME, not giving it to the DHCP lease of %s"),
|
||||||
host_name, inet_ntoa(*host_address));
|
host_name, daemon->addrbuff);
|
||||||
else if (crec->addr.addr.addr.addr4.s_addr != host_address->s_addr)
|
else if (memcmp(&crec->addr.addr, host_address, addrlen) != 0)
|
||||||
{
|
{
|
||||||
strcpy(daemon->namebuff, inet_ntoa(crec->addr.addr.addr.addr4));
|
inet_ntop(prot, &crec->addr.addr, daemon->namebuff, MAXDNAME);
|
||||||
my_syslog(MS_DHCP | LOG_WARNING,
|
my_syslog(MS_DHCP | LOG_WARNING,
|
||||||
_("not giving name %s to the DHCP lease of %s because "
|
_("not giving name %s to the DHCP lease of %s because "
|
||||||
"the name exists in %s with address %s"),
|
"the name exists in %s with address %s"),
|
||||||
host_name, inet_ntoa(*host_address),
|
host_name, daemon->addrbuff,
|
||||||
record_source(crec->uid), daemon->namebuff);
|
record_source(crec->uid), daemon->namebuff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!(crec->flags & F_DHCP))
|
else if (!(crec->flags & F_DHCP))
|
||||||
{
|
{
|
||||||
cache_scan_free(host_name, NULL, 0, crec->flags & (F_IPV4 | F_CNAME | F_FORWARD));
|
cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD));
|
||||||
/* scan_free deletes all addresses associated with name */
|
/* scan_free deletes all addresses associated with name */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -980,14 +1044,16 @@ void cache_add_dhcp_entry(char *host_name,
|
|||||||
if (in_hosts)
|
if (in_hosts)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, F_IPV4)))
|
if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
|
||||||
{
|
{
|
||||||
if (crec->flags & F_NEG)
|
if (crec->flags & F_NEG)
|
||||||
cache_scan_free(NULL, (struct all_addr *)host_address, 0, F_IPV4 | F_REVERSE);
|
{
|
||||||
else
|
flags |= F_REVERSE;
|
||||||
/* avoid multiple reverse mappings */
|
cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
|
||||||
flags &= ~F_REVERSE;
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
flags |= F_REVERSE;
|
||||||
|
|
||||||
if ((crec = dhcp_spare))
|
if ((crec = dhcp_spare))
|
||||||
dhcp_spare = dhcp_spare->next;
|
dhcp_spare = dhcp_spare->next;
|
||||||
@@ -996,12 +1062,12 @@ void cache_add_dhcp_entry(char *host_name,
|
|||||||
|
|
||||||
if (crec) /* malloc may fail */
|
if (crec) /* malloc may fail */
|
||||||
{
|
{
|
||||||
crec->flags = flags;
|
crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
|
||||||
if (ttd == 0)
|
if (ttd == 0)
|
||||||
crec->flags |= F_IMMORTAL;
|
crec->flags |= F_IMMORTAL;
|
||||||
else
|
else
|
||||||
crec->ttd = ttd;
|
crec->ttd = ttd;
|
||||||
crec->addr.addr.addr.addr4 = *host_address;
|
crec->addr.addr = *host_address;
|
||||||
crec->name.namep = host_name;
|
crec->name.namep = host_name;
|
||||||
crec->uid = uid++;
|
crec->uid = uid++;
|
||||||
cache_hash(crec);
|
cache_hash(crec);
|
||||||
@@ -1042,9 +1108,6 @@ void dump_cache(time_t now)
|
|||||||
my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
|
my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
|
||||||
daemon->queries_forwarded, daemon->local_answer);
|
daemon->queries_forwarded, daemon->local_answer);
|
||||||
|
|
||||||
if (!addrbuff && !(addrbuff = whine_malloc(ADDRSTRLEN)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* sum counts from different records for same server */
|
/* sum counts from different records for same server */
|
||||||
for (serv = daemon->servers; serv; serv = serv->next)
|
for (serv = daemon->servers; serv; serv = serv->next)
|
||||||
serv->flags &= ~SERV_COUNTED;
|
serv->flags &= ~SERV_COUNTED;
|
||||||
@@ -1064,8 +1127,8 @@ void dump_cache(time_t now)
|
|||||||
queries += serv1->queries;
|
queries += serv1->queries;
|
||||||
failed_queries += serv1->failed_queries;
|
failed_queries += serv1->failed_queries;
|
||||||
}
|
}
|
||||||
port = prettyprint_addr(&serv->addr, addrbuff);
|
port = prettyprint_addr(&serv->addr, daemon->addrbuff);
|
||||||
my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), addrbuff, port, queries, failed_queries);
|
my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), daemon->addrbuff, port, queries, failed_queries);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
|
if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
|
||||||
@@ -1090,11 +1153,11 @@ void dump_cache(time_t now)
|
|||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
a = addrbuff;
|
a = daemon->addrbuff;
|
||||||
if (cache->flags & F_IPV4)
|
if (cache->flags & F_IPV4)
|
||||||
inet_ntop(AF_INET, &cache->addr.addr, addrbuff, ADDRSTRLEN);
|
inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN);
|
||||||
else if (cache->flags & F_IPV6)
|
else if (cache->flags & F_IPV6)
|
||||||
inet_ntop(AF_INET6, &cache->addr.addr, addrbuff, ADDRSTRLEN);
|
inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
else
|
else
|
||||||
@@ -1149,7 +1212,7 @@ void querystr(char *str, unsigned short type)
|
|||||||
|
|
||||||
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||||
{
|
{
|
||||||
char *source, *dest = addrbuff;
|
char *source, *dest = daemon->addrbuff;
|
||||||
char *verb = "is";
|
char *verb = "is";
|
||||||
|
|
||||||
if (!option_bool(OPT_LOG))
|
if (!option_bool(OPT_LOG))
|
||||||
@@ -1159,16 +1222,16 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
|||||||
{
|
{
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
||||||
addr, addrbuff, ADDRSTRLEN);
|
addr, daemon->addrbuff, ADDRSTRLEN);
|
||||||
#else
|
#else
|
||||||
strncpy(addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
|
strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & F_REVERSE)
|
if (flags & F_REVERSE)
|
||||||
{
|
{
|
||||||
dest = name;
|
dest = name;
|
||||||
name = addrbuff;
|
name = daemon->addrbuff;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & F_NEG)
|
if (flags & F_NEG)
|
||||||
|
|||||||
+190
-116
@@ -1,4 +1,4 @@
|
|||||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -14,8 +14,6 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define VERSION "2.56"
|
|
||||||
|
|
||||||
#define FTABSIZ 150 /* max number of outstanding requests (default) */
|
#define FTABSIZ 150 /* max number of outstanding requests (default) */
|
||||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||||
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
|
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
|
||||||
@@ -34,81 +32,19 @@
|
|||||||
#define SMALLDNAME 40 /* most domain names are smaller than this */
|
#define SMALLDNAME 40 /* most domain names are smaller than this */
|
||||||
#define HOSTSFILE "/etc/hosts"
|
#define HOSTSFILE "/etc/hosts"
|
||||||
#define ETHERSFILE "/etc/ethers"
|
#define ETHERSFILE "/etc/ethers"
|
||||||
#ifdef __uClinux__
|
|
||||||
# define RESOLVFILE "/etc/config/resolv.conf"
|
|
||||||
#else
|
|
||||||
# define RESOLVFILE "/etc/resolv.conf"
|
|
||||||
#endif
|
|
||||||
#define RUNFILE "/var/run/dnsmasq.pid"
|
#define RUNFILE "/var/run/dnsmasq.pid"
|
||||||
|
|
||||||
#ifndef LEASEFILE
|
|
||||||
# if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
|
|
||||||
# define LEASEFILE "/var/db/dnsmasq.leases"
|
|
||||||
# elif defined(__sun__) || defined (__sun)
|
|
||||||
# define LEASEFILE "/var/cache/dnsmasq.leases"
|
|
||||||
# else
|
|
||||||
# define LEASEFILE "/var/lib/misc/dnsmasq.leases"
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CONFFILE
|
|
||||||
# if defined(__FreeBSD__)
|
|
||||||
# define CONFFILE "/usr/local/etc/dnsmasq.conf"
|
|
||||||
# else
|
|
||||||
# define CONFFILE "/etc/dnsmasq.conf"
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||||
#define CHUSER "nobody"
|
#define CHUSER "nobody"
|
||||||
#define CHGRP "dip"
|
#define CHGRP "dip"
|
||||||
#define DHCP_SERVER_PORT 67
|
|
||||||
#define DHCP_CLIENT_PORT 68
|
|
||||||
#define DHCP_SERVER_ALTPORT 1067
|
|
||||||
#define DHCP_CLIENT_ALTPORT 1068
|
|
||||||
#define PXE_PORT 4011
|
|
||||||
#define TFTP_PORT 69
|
|
||||||
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
|
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
|
||||||
#define LOG_MAX 5 /* log-queue length */
|
#define LOG_MAX 5 /* log-queue length */
|
||||||
#define RANDFILE "/dev/urandom"
|
#define RANDFILE "/dev/urandom"
|
||||||
#define DAD_WAIT 20 /* retry binding IPv6 sockets for this long */
|
|
||||||
#define EDNS0_OPTION_MAC 5 /* dyndns.org temporary assignment */
|
#define EDNS0_OPTION_MAC 5 /* dyndns.org temporary assignment */
|
||||||
|
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* DBUS interface specifics */
|
||||||
/* DBUS interface specifics */
|
|
||||||
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"
|
|
||||||
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
|
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
|
||||||
|
|
||||||
/* A small collection of RR-types which are missing on some platforms */
|
/* compile-time options: uncomment below to enable or do eg.
|
||||||
|
make COPTS=-DHAVE_BROKEN_RTC
|
||||||
#ifndef T_SIG
|
|
||||||
# define T_SIG 24
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef T_SRV
|
|
||||||
# define T_SRV 33
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef T_OPT
|
|
||||||
# define T_OPT 41
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef T_TKEY
|
|
||||||
# define T_TKEY 249
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef T_TSIG
|
|
||||||
# define T_TSIG 250
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* Follows system specific switches. If you run on a
|
|
||||||
new system, you may want to edit these.
|
|
||||||
May replace this with Autoconf one day.
|
|
||||||
|
|
||||||
HAVE_LINUX_NETWORK
|
|
||||||
HAVE_BSD_NETWORK
|
|
||||||
HAVE_SOLARIS_NETWORK
|
|
||||||
define exactly one of these to alter interaction with kernel networking.
|
|
||||||
|
|
||||||
HAVE_BROKEN_RTC
|
HAVE_BROKEN_RTC
|
||||||
define this on embedded systems which don't have an RTC
|
define this on embedded systems which don't have an RTC
|
||||||
@@ -128,69 +64,118 @@ HAVE_TFTP
|
|||||||
define this to get dnsmasq's built-in TFTP server.
|
define this to get dnsmasq's built-in TFTP server.
|
||||||
|
|
||||||
HAVE_DHCP
|
HAVE_DHCP
|
||||||
define this to get dnsmasq's DHCP server.
|
define this to get dnsmasq's DHCPv4 server.
|
||||||
|
|
||||||
|
HAVE_DHCP6
|
||||||
|
define this to get dnsmasq's DHCPv6 server. (implies HAVE_DHCP).
|
||||||
|
|
||||||
HAVE_SCRIPT
|
HAVE_SCRIPT
|
||||||
define this to get the ability to call scripts on lease-change
|
define this to get the ability to call scripts on lease-change.
|
||||||
|
|
||||||
HAVE_GETOPT_LONG
|
HAVE_LUASCRIPT
|
||||||
define this if you have GNU libc or GNU getopt.
|
define this to get the ability to call Lua script on lease-change. (implies HAVE_SCRIPT)
|
||||||
|
|
||||||
HAVE_ARC4RANDOM
|
|
||||||
define this if you have arc4random() to get better security from DNS spoofs
|
|
||||||
by using really random ids (OpenBSD)
|
|
||||||
|
|
||||||
HAVE_SOCKADDR_SA_LEN
|
|
||||||
define this if struct sockaddr has sa_len field (*BSD)
|
|
||||||
|
|
||||||
HAVE_DBUS
|
HAVE_DBUS
|
||||||
Define this if you want to link against libdbus, and have dnsmasq
|
define this if you want to link against libdbus, and have dnsmasq
|
||||||
define some methods to allow (re)configuration of the upstream DNS
|
support some methods to allow (re)configuration of the upstream DNS
|
||||||
servers via DBus.
|
servers via DBus.
|
||||||
|
|
||||||
NOTES:
|
HAVE_IDN
|
||||||
For Linux you should define
|
define this if you want international domain name support.
|
||||||
HAVE_LINUX_NETWORK
|
NOTE: for backwards compatibility, IDN support is automatically
|
||||||
HAVE_GETOPT_LONG
|
included when internationalisation support is built, using the
|
||||||
you should NOT define
|
*-i18n makefile targets, even if HAVE_IDN is not explicitly set.
|
||||||
HAVE_ARC4RANDOM
|
|
||||||
HAVE_SOCKADDR_SA_LEN
|
|
||||||
|
|
||||||
For *BSD systems you should define
|
HAVE_CONNTRACK
|
||||||
HAVE_BSD_NETWORK
|
define this to include code which propogates conntrack marks from
|
||||||
HAVE_SOCKADDR_SA_LEN
|
incoming DNS queries to the corresponding upstream queries. This adds
|
||||||
and you MAY define
|
a build-dependency on libnetfilter_conntrack, but the resulting binary will
|
||||||
HAVE_ARC4RANDOM - OpenBSD and FreeBSD and NetBSD version 2.0 or later
|
still run happily on a kernel without conntrack support.
|
||||||
HAVE_GETOPT_LONG - NetBSD, later FreeBSD
|
|
||||||
(FreeBSD and OpenBSD only if you link GNU getopt)
|
NO_IPV6
|
||||||
|
NO_TFTP
|
||||||
|
NO_DHCP
|
||||||
|
NO_DHCP6
|
||||||
|
NO_SCRIPT
|
||||||
|
NO_LARGEFILE
|
||||||
|
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
|
||||||
|
with something like "make COPTS=-DNO_SCRIPT" will do the trick.
|
||||||
|
|
||||||
|
LEASEFILE
|
||||||
|
CONFFILE
|
||||||
|
RESOLVFILE
|
||||||
|
the default locations of these files are determined below, but may be overridden
|
||||||
|
in a build command line using COPTS.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* platform independent options- uncomment to enable */
|
|
||||||
|
/* The default set of options to build. Built with these options, dnsmasq
|
||||||
|
has no library dependencies other than libc */
|
||||||
|
|
||||||
#define HAVE_DHCP
|
#define HAVE_DHCP
|
||||||
|
#define HAVE_DHCP6
|
||||||
#define HAVE_TFTP
|
#define HAVE_TFTP
|
||||||
#define HAVE_SCRIPT
|
#define HAVE_SCRIPT
|
||||||
|
/* #define HAVE_LUASCRIPT */
|
||||||
/* #define HAVE_BROKEN_RTC */
|
/* #define HAVE_BROKEN_RTC */
|
||||||
/* #define HAVE_DBUS */
|
/* #define HAVE_DBUS */
|
||||||
|
/* #define HAVE_IDN */
|
||||||
|
/* #define HAVE_CONNTRACK */
|
||||||
|
|
||||||
/* Allow TFTP to be disabled with COPTS=-DNO_TFTP */
|
|
||||||
#ifdef NO_TFTP
|
|
||||||
#undef HAVE_TFTP
|
/* Default locations for important system files. */
|
||||||
|
|
||||||
|
#ifndef LEASEFILE
|
||||||
|
# if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
|
||||||
|
# define LEASEFILE "/var/db/dnsmasq.leases"
|
||||||
|
# elif defined(__sun__) || defined (__sun)
|
||||||
|
# define LEASEFILE "/var/cache/dnsmasq.leases"
|
||||||
|
# elif defined(__ANDROID__)
|
||||||
|
# define LEASEFILE "/data/misc/dhcp/dnsmasq.leases"
|
||||||
|
# else
|
||||||
|
# define LEASEFILE "/var/lib/misc/dnsmasq.leases"
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Allow DHCP to be disabled with COPTS=-DNO_DHCP */
|
#ifndef CONFFILE
|
||||||
#ifdef NO_DHCP
|
# if defined(__FreeBSD__)
|
||||||
#undef HAVE_DHCP
|
# define CONFFILE "/usr/local/etc/dnsmasq.conf"
|
||||||
|
# else
|
||||||
|
# define CONFFILE "/etc/dnsmasq.conf"
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Allow scripts to be disabled with COPTS=-DNO_SCRIPT */
|
#ifndef RESOLVFILE
|
||||||
#ifdef NO_SCRIPT
|
# if defined(__uClinux__)
|
||||||
#undef HAVE_SCRIPT
|
# define RESOLVFILE "/etc/config/resolv.conf"
|
||||||
|
# else
|
||||||
|
# define RESOLVFILE "/etc/resolv.conf"
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* platform dependent options. */
|
/* platform dependent options: these are determined automatically below
|
||||||
|
|
||||||
|
HAVE_LINUX_NETWORK
|
||||||
|
HAVE_BSD_NETWORK
|
||||||
|
HAVE_SOLARIS_NETWORK
|
||||||
|
define exactly one of these to alter interaction with kernel networking.
|
||||||
|
|
||||||
|
HAVE_GETOPT_LONG
|
||||||
|
defined when GNU-style getopt_long available.
|
||||||
|
|
||||||
|
HAVE_ARC4RANDOM
|
||||||
|
defined if arc4random() available to get better security from DNS spoofs
|
||||||
|
by using really random ids (OpenBSD)
|
||||||
|
|
||||||
|
HAVE_SOCKADDR_SA_LEN
|
||||||
|
defined if struct sockaddr has sa_len field (*BSD)
|
||||||
|
*/
|
||||||
|
|
||||||
/* Must preceed __linux__ since uClinux defines __linux__ too. */
|
/* Must preceed __linux__ since uClinux defines __linux__ too. */
|
||||||
#if defined(__uClinux__)
|
#if defined(__uClinux__)
|
||||||
@@ -266,18 +251,12 @@ NOTES:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Decide if we're going to support IPv6 */
|
/* Decide if we're going to support IPv6 */
|
||||||
/* IPv6 can be forced off with "make COPTS=-DNO_IPV6" */
|
|
||||||
/* We assume that systems which don't have IPv6
|
/* We assume that systems which don't have IPv6
|
||||||
headers don't have ntop and pton either */
|
headers don't have ntop and pton either */
|
||||||
|
|
||||||
#if defined(INET6_ADDRSTRLEN) && defined(IPV6_V6ONLY) && !defined(NO_IPV6)
|
#if defined(INET6_ADDRSTRLEN) && defined(IPV6_V6ONLY)
|
||||||
# define HAVE_IPV6
|
# define HAVE_IPV6
|
||||||
# define ADDRSTRLEN INET6_ADDRSTRLEN
|
# define ADDRSTRLEN INET6_ADDRSTRLEN
|
||||||
# if defined(SOL_IPV6)
|
|
||||||
# define IPV6_LEVEL SOL_IPV6
|
|
||||||
# else
|
|
||||||
# define IPV6_LEVEL IPPROTO_IPV6
|
|
||||||
# endif
|
|
||||||
#elif defined(INET_ADDRSTRLEN)
|
#elif defined(INET_ADDRSTRLEN)
|
||||||
# undef HAVE_IPV6
|
# undef HAVE_IPV6
|
||||||
# define ADDRSTRLEN INET_ADDRSTRLEN
|
# define ADDRSTRLEN INET_ADDRSTRLEN
|
||||||
@@ -286,8 +265,103 @@ NOTES:
|
|||||||
# define ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
|
# define ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Can't do scripts without fork */
|
|
||||||
#ifdef NOFORK
|
/* rules to implement compile-time option dependencies and
|
||||||
# undef HAVE_SCRIPT
|
the NO_XXX flags */
|
||||||
|
|
||||||
|
#ifdef NO_IPV6
|
||||||
|
#undef HAVE_IPV6
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef NO_TFTP
|
||||||
|
#undef HAVE_TFTP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NO_DHCP
|
||||||
|
#undef HAVE_DHCP
|
||||||
|
#undef HAVE_DHCP6
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(NO_DHCP6) || !defined(HAVE_IPV6)
|
||||||
|
#undef HAVE_DHCP6
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* DHCP6 needs DHCP too */
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
#define HAVE_DHCP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(NO_SCRIPT) || !defined(HAVE_DHCP) || defined(NO_FORK)
|
||||||
|
#undef HAVE_SCRIPT
|
||||||
|
#undef HAVE_LUASCRIPT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Must HAVE_SCRIPT to HAVE_LUASCRIPT */
|
||||||
|
#ifdef HAVE_LUASCRIPT
|
||||||
|
#define HAVE_SCRIPT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Define a string indicating which options are in use.
|
||||||
|
DNSMASQP_COMPILE_OPTS is only defined in dnsmasq.c */
|
||||||
|
|
||||||
|
#ifdef DNSMASQ_COMPILE_OPTS
|
||||||
|
|
||||||
|
static char *compile_opts =
|
||||||
|
#ifndef HAVE_IPV6
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"IPv6 "
|
||||||
|
#ifndef HAVE_GETOPT_LONG
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"GNU-getopt "
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
"no-RTC "
|
||||||
|
#endif
|
||||||
|
#ifdef NO_FORK
|
||||||
|
"no-MMU "
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_DBUS
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"DBus "
|
||||||
|
#ifndef LOCALEDIR
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"i18n "
|
||||||
|
#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"IDN "
|
||||||
|
#ifndef HAVE_DHCP
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"DHCP "
|
||||||
|
#if defined(HAVE_DHCP)
|
||||||
|
# if !defined (HAVE_DHCP6)
|
||||||
|
"no-"
|
||||||
|
# endif
|
||||||
|
"DHCPv6 "
|
||||||
|
# if !defined(HAVE_SCRIPT)
|
||||||
|
"no-scripts "
|
||||||
|
# else
|
||||||
|
# if !defined(HAVE_LUASCRIPT)
|
||||||
|
"no-"
|
||||||
|
# endif
|
||||||
|
"Lua "
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TFTP
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"TFTP "
|
||||||
|
#ifndef HAVE_CONNTRACK
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"conntrack";
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 dated June, 1991, or
|
||||||
|
(at your option) version 3 dated 29 June, 2007.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_CONNTRACK
|
||||||
|
|
||||||
|
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
|
||||||
|
|
||||||
|
static int gotit = 0; /* yuck */
|
||||||
|
|
||||||
|
static int callback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data);
|
||||||
|
|
||||||
|
int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr, int istcp, unsigned int *markp)
|
||||||
|
{
|
||||||
|
struct nf_conntrack *ct;
|
||||||
|
struct nfct_handle *h;
|
||||||
|
|
||||||
|
gotit = 0;
|
||||||
|
|
||||||
|
if ((ct = nfct_new()))
|
||||||
|
{
|
||||||
|
nfct_set_attr_u8(ct, ATTR_L4PROTO, istcp ? IPPROTO_TCP : IPPROTO_UDP);
|
||||||
|
nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(daemon->port));
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
if (peer_addr->sa.sa_family == AF_INET6)
|
||||||
|
{
|
||||||
|
nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET6);
|
||||||
|
nfct_set_attr(ct, ATTR_IPV6_SRC, peer_addr->in6.sin6_addr.s6_addr);
|
||||||
|
nfct_set_attr_u16(ct, ATTR_PORT_SRC, peer_addr->in6.sin6_port);
|
||||||
|
nfct_set_attr(ct, ATTR_IPV6_DST, local_addr->addr.addr6.s6_addr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET);
|
||||||
|
nfct_set_attr_u32(ct, ATTR_IPV4_SRC, peer_addr->in.sin_addr.s_addr);
|
||||||
|
nfct_set_attr_u16(ct, ATTR_PORT_SRC, peer_addr->in.sin_port);
|
||||||
|
nfct_set_attr_u32(ct, ATTR_IPV4_DST, local_addr->addr.addr4.s_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ((h = nfct_open(CONNTRACK, 0)))
|
||||||
|
{
|
||||||
|
nfct_callback_register(h, NFCT_T_ALL, callback, (void *)markp);
|
||||||
|
if (nfct_query(h, NFCT_Q_GET, ct) == -1)
|
||||||
|
{
|
||||||
|
static int warned = 0;
|
||||||
|
if (!warned)
|
||||||
|
{
|
||||||
|
my_syslog(LOG_ERR, _("Conntrack connection mark retrieval failed: %s"), strerror(errno));
|
||||||
|
warned = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nfct_close(h);
|
||||||
|
}
|
||||||
|
nfct_destroy(ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
return gotit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int callback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data)
|
||||||
|
{
|
||||||
|
unsigned int *ret = (unsigned int *)data;
|
||||||
|
*ret = nfct_get_attr_u32(ct, ATTR_MARK);
|
||||||
|
(void)type; /* eliminate warning */
|
||||||
|
gotit = 1;
|
||||||
|
|
||||||
|
return NFCT_CB_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+19
-10
@@ -1,4 +1,4 @@
|
|||||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -396,7 +396,7 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
|
|||||||
DBusConnection *connection = (DBusConnection *)daemon->dbus;
|
DBusConnection *connection = (DBusConnection *)daemon->dbus;
|
||||||
DBusMessage* message = NULL;
|
DBusMessage* message = NULL;
|
||||||
DBusMessageIter args;
|
DBusMessageIter args;
|
||||||
char *action_str, *addr, *mac = daemon->namebuff;
|
char *action_str, *mac = daemon->namebuff;
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -406,10 +406,21 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
|
|||||||
if (!hostname)
|
if (!hostname)
|
||||||
hostname = "";
|
hostname = "";
|
||||||
|
|
||||||
p = extended_hwaddr(lease->hwaddr_type, lease->hwaddr_len,
|
#ifdef HAVE_DHCP6
|
||||||
lease->hwaddr, lease->clid_len, lease->clid, &i);
|
if (lease->flags & (LEASE_TA | LEASE_NA))
|
||||||
print_mac(mac, p, i);
|
{
|
||||||
|
print_mac(mac, lease->clid, lease->clid_len);
|
||||||
|
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
p = extended_hwaddr(lease->hwaddr_type, lease->hwaddr_len,
|
||||||
|
lease->hwaddr, lease->clid_len, lease->clid, &i);
|
||||||
|
print_mac(mac, p, i);
|
||||||
|
inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
}
|
||||||
|
|
||||||
if (action == ACTION_DEL)
|
if (action == ACTION_DEL)
|
||||||
action_str = "DhcpLeaseDeleted";
|
action_str = "DhcpLeaseDeleted";
|
||||||
else if (action == ACTION_ADD)
|
else if (action == ACTION_ADD)
|
||||||
@@ -419,14 +430,12 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
|
|||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
addr = inet_ntoa(lease->addr);
|
|
||||||
|
|
||||||
if (!(message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, action_str)))
|
if (!(message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, action_str)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dbus_message_iter_init_append(message, &args);
|
dbus_message_iter_init_append(message, &args);
|
||||||
|
|
||||||
if (dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &addr) &&
|
if (dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &daemon->addrbuff) &&
|
||||||
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &mac) &&
|
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &mac) &&
|
||||||
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &hostname))
|
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &hostname))
|
||||||
dbus_connection_send(connection, message, NULL);
|
dbus_connection_send(connection, message, NULL);
|
||||||
|
|||||||
@@ -0,0 +1,755 @@
|
|||||||
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 dated June, 1991, or
|
||||||
|
(at your option) version 3 dated 29 June, 2007.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP
|
||||||
|
|
||||||
|
void dhcp_common_init(void)
|
||||||
|
{
|
||||||
|
/* These each hold a DHCP option max size 255
|
||||||
|
and get a terminating zero added */
|
||||||
|
daemon->dhcp_buff = safe_malloc(256);
|
||||||
|
daemon->dhcp_buff2 = safe_malloc(256);
|
||||||
|
daemon->dhcp_buff3 = safe_malloc(256);
|
||||||
|
|
||||||
|
/* dhcp_packet is used by v4 and v6, outpacket only by v6
|
||||||
|
sizeof(struct dhcp_packet) is as good an initial size as any,
|
||||||
|
even for v6 */
|
||||||
|
expand_buf(&daemon->dhcp_packet, sizeof(struct dhcp_packet));
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (daemon->dhcp6)
|
||||||
|
expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
|
||||||
|
{
|
||||||
|
ssize_t sz;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
msg->msg_flags = 0;
|
||||||
|
while ((sz = recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
|
||||||
|
|
||||||
|
if (sz == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!(msg->msg_flags & MSG_TRUNC))
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Very new Linux kernels return the actual size needed,
|
||||||
|
older ones always return truncated size */
|
||||||
|
if ((size_t)sz == msg->msg_iov->iov_len)
|
||||||
|
{
|
||||||
|
if (!expand_buf(msg->msg_iov, sz + 100))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
expand_buf(msg->msg_iov, sz);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
|
||||||
|
|
||||||
|
return (msg->msg_flags & MSG_TRUNC) ? -1 : sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
|
||||||
|
{
|
||||||
|
struct tag_if *exprs;
|
||||||
|
struct dhcp_netid_list *list;
|
||||||
|
|
||||||
|
for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
|
||||||
|
if (match_netid(exprs->tag, tags, 1))
|
||||||
|
for (list = exprs->set; list; list = list->next)
|
||||||
|
{
|
||||||
|
list->list->next = tags;
|
||||||
|
tags = list->list;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *context_tags, struct dhcp_opt *opts)
|
||||||
|
{
|
||||||
|
struct dhcp_netid *tagif = run_tag_if(tags);
|
||||||
|
struct dhcp_opt *opt;
|
||||||
|
|
||||||
|
/* flag options which are valid with the current tag set (sans context tags) */
|
||||||
|
for (opt = opts; opt; opt = opt->next)
|
||||||
|
{
|
||||||
|
opt->flags &= ~DHOPT_TAGOK;
|
||||||
|
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
|
||||||
|
match_netid(opt->netid, tagif, 0))
|
||||||
|
opt->flags |= DHOPT_TAGOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now flag options which are valid, including the context tags,
|
||||||
|
otherwise valid options are inhibited if we found a higher priority one above */
|
||||||
|
if (context_tags)
|
||||||
|
{
|
||||||
|
struct dhcp_netid *last_tag;
|
||||||
|
|
||||||
|
for (last_tag = context_tags; last_tag->next; last_tag = last_tag->next);
|
||||||
|
last_tag->next = tags;
|
||||||
|
tagif = run_tag_if(context_tags);
|
||||||
|
|
||||||
|
/* reset stuff with tag:!<tag> which now matches. */
|
||||||
|
for (opt = opts; opt; opt = opt->next)
|
||||||
|
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
|
||||||
|
(opt->flags & DHOPT_TAGOK) &&
|
||||||
|
!match_netid(opt->netid, tagif, 0))
|
||||||
|
opt->flags &= ~DHOPT_TAGOK;
|
||||||
|
|
||||||
|
for (opt = opts; opt; opt = opt->next)
|
||||||
|
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) &&
|
||||||
|
match_netid(opt->netid, tagif, 0))
|
||||||
|
{
|
||||||
|
struct dhcp_opt *tmp;
|
||||||
|
for (tmp = opts; tmp; tmp = tmp->next)
|
||||||
|
if (tmp->opt == opt->opt && opt->netid && (tmp->flags & DHOPT_TAGOK))
|
||||||
|
break;
|
||||||
|
if (!tmp)
|
||||||
|
opt->flags |= DHOPT_TAGOK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now flag untagged options which are not overridden by tagged ones */
|
||||||
|
for (opt = opts; opt; opt = opt->next)
|
||||||
|
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
|
||||||
|
{
|
||||||
|
struct dhcp_opt *tmp;
|
||||||
|
for (tmp = opts; tmp; tmp = tmp->next)
|
||||||
|
if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
|
||||||
|
break;
|
||||||
|
if (!tmp)
|
||||||
|
opt->flags |= DHOPT_TAGOK;
|
||||||
|
else if (!tmp->netid)
|
||||||
|
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tagif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is every member of check matched by a member of pool?
|
||||||
|
If tagnotneeded, untagged is OK */
|
||||||
|
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded)
|
||||||
|
{
|
||||||
|
struct dhcp_netid *tmp1;
|
||||||
|
|
||||||
|
if (!check && !tagnotneeded)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (; check; check = check->next)
|
||||||
|
{
|
||||||
|
/* '#' for not is for backwards compat. */
|
||||||
|
if (check->net[0] != '!' && check->net[0] != '#')
|
||||||
|
{
|
||||||
|
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
||||||
|
if (strcmp(check->net, tmp1->net) == 0)
|
||||||
|
break;
|
||||||
|
if (!tmp1)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
||||||
|
if (strcmp((check->net)+1, tmp1->net) == 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return domain or NULL if none. */
|
||||||
|
char *strip_hostname(char *hostname)
|
||||||
|
{
|
||||||
|
char *dot = strchr(hostname, '.');
|
||||||
|
|
||||||
|
if (!dot)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*dot = 0; /* truncate */
|
||||||
|
if (strlen(dot+1) != 0)
|
||||||
|
return dot+1;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_tags(struct dhcp_netid *netid, u32 xid)
|
||||||
|
{
|
||||||
|
if (netid && option_bool(OPT_LOG_OPTS))
|
||||||
|
{
|
||||||
|
char *s = daemon->namebuff;
|
||||||
|
for (*s = 0; netid; netid = netid->next)
|
||||||
|
{
|
||||||
|
/* kill dupes. */
|
||||||
|
struct dhcp_netid *n;
|
||||||
|
|
||||||
|
for (n = netid->next; n; n = n->next)
|
||||||
|
if (strcmp(netid->net, n->net) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!n)
|
||||||
|
{
|
||||||
|
strncat (s, netid->net, (MAXDNAME-1) - strlen(s));
|
||||||
|
if (netid->next)
|
||||||
|
strncat (s, ", ", (MAXDNAME-1) - strlen(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), xid, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (o->len > len)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (o->len == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (o->flags & DHOPT_HEX)
|
||||||
|
{
|
||||||
|
if (memcmp_masked(o->val, p, o->len, o->u.wildcard_mask))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
for (i = 0; i <= (len - o->len); )
|
||||||
|
{
|
||||||
|
if (memcmp(o->val, p + i, o->len) == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (o->flags & DHOPT_STRING)
|
||||||
|
i++;
|
||||||
|
else
|
||||||
|
i += o->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_dhcp_hosts(int fatal)
|
||||||
|
{
|
||||||
|
/* If the same IP appears in more than one host config, then DISCOVER
|
||||||
|
for one of the hosts will get the address, but REQUEST will be NAKed,
|
||||||
|
since the address is reserved by the other one -> protocol loop.
|
||||||
|
Also check that FQDNs match the domain we are using. */
|
||||||
|
|
||||||
|
struct dhcp_config *configs, *cp;
|
||||||
|
|
||||||
|
for (configs = daemon->dhcp_conf; configs; configs = configs->next)
|
||||||
|
{
|
||||||
|
char *domain;
|
||||||
|
|
||||||
|
if ((configs->flags & DHOPT_BANK) || fatal)
|
||||||
|
{
|
||||||
|
for (cp = configs->next; cp; cp = cp->next)
|
||||||
|
if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr)
|
||||||
|
{
|
||||||
|
if (fatal)
|
||||||
|
die(_("duplicate IP address %s in dhcp-config directive."),
|
||||||
|
inet_ntoa(cp->addr), EC_BADCONF);
|
||||||
|
else
|
||||||
|
my_syslog(MS_DHCP | LOG_ERR, _("duplicate IP address %s in %s."),
|
||||||
|
inet_ntoa(cp->addr), daemon->dhcp_hosts_file);
|
||||||
|
configs->flags &= ~CONFIG_ADDR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* split off domain part */
|
||||||
|
if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
|
||||||
|
configs->domain = domain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dhcp_update_configs(struct dhcp_config *configs)
|
||||||
|
{
|
||||||
|
/* Some people like to keep all static IP addresses in /etc/hosts.
|
||||||
|
This goes through /etc/hosts and sets static addresses for any DHCP config
|
||||||
|
records which don't have an address and whose name matches.
|
||||||
|
We take care to maintain the invariant that any IP address can appear
|
||||||
|
in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
|
||||||
|
restore the status-quo ante first. */
|
||||||
|
|
||||||
|
struct dhcp_config *config;
|
||||||
|
struct crec *crec;
|
||||||
|
int prot = AF_INET;
|
||||||
|
|
||||||
|
for (config = configs; config; config = config->next)
|
||||||
|
if (config->flags & CONFIG_ADDR_HOSTS)
|
||||||
|
config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR6 | CONFIG_ADDR_HOSTS);
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
again:
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (daemon->port != 0)
|
||||||
|
for (config = configs; config; config = config->next)
|
||||||
|
{
|
||||||
|
int conflags = CONFIG_ADDR;
|
||||||
|
int cacheflags = F_IPV4;
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (prot == AF_INET6)
|
||||||
|
{
|
||||||
|
conflags = CONFIG_ADDR6;
|
||||||
|
cacheflags = F_IPV6;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!(config->flags & conflags) &&
|
||||||
|
(config->flags & CONFIG_NAME) &&
|
||||||
|
(crec = cache_find_by_name(NULL, config->hostname, 0, cacheflags)) &&
|
||||||
|
(crec->flags & F_HOSTS))
|
||||||
|
{
|
||||||
|
if (cache_find_by_name(crec, config->hostname, 0, cacheflags))
|
||||||
|
{
|
||||||
|
/* use primary (first) address */
|
||||||
|
while (crec && !(crec->flags & F_REVERSE))
|
||||||
|
crec = cache_find_by_name(crec, config->hostname, 0, cacheflags);
|
||||||
|
if (!crec)
|
||||||
|
continue; /* should be never */
|
||||||
|
inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
|
||||||
|
config->hostname, daemon->addrbuff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prot == AF_INET && !config_find_by_address(configs, crec->addr.addr.addr.addr4))
|
||||||
|
{
|
||||||
|
config->addr = crec->addr.addr.addr.addr4;
|
||||||
|
config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (prot == AF_INET6 && !config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0))
|
||||||
|
{
|
||||||
|
memcpy(&config->addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ);
|
||||||
|
config->flags |= CONFIG_ADDR6 | CONFIG_ADDR_HOSTS;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
|
||||||
|
daemon->addrbuff, config->hostname);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (prot == AF_INET)
|
||||||
|
{
|
||||||
|
prot = AF_INET6;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_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 dhcp_context *context;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* weird libvirt-inspired access control */
|
||||||
|
for (context = daemon->dhcp6; context; context = context->next)
|
||||||
|
if (!context->interface || strcmp(context->interface, ifrn_name) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
static const struct opttab_t {
|
||||||
|
char *name;
|
||||||
|
u16 val, size;
|
||||||
|
} opttab[] = {
|
||||||
|
{ "netmask", 1, OT_ADDR_LIST },
|
||||||
|
{ "time-offset", 2, 4 },
|
||||||
|
{ "router", 3, OT_ADDR_LIST },
|
||||||
|
{ "dns-server", 6, OT_ADDR_LIST },
|
||||||
|
{ "log-server", 7, OT_ADDR_LIST },
|
||||||
|
{ "lpr-server", 9, OT_ADDR_LIST },
|
||||||
|
{ "hostname", 12, OT_INTERNAL | OT_NAME },
|
||||||
|
{ "boot-file-size", 13, 2 | OT_DEC },
|
||||||
|
{ "domain-name", 15, OT_NAME },
|
||||||
|
{ "swap-server", 16, OT_ADDR_LIST },
|
||||||
|
{ "root-path", 17, OT_NAME },
|
||||||
|
{ "extension-path", 18, OT_NAME },
|
||||||
|
{ "ip-forward-enable", 19, 1 },
|
||||||
|
{ "non-local-source-routing", 20, 1 },
|
||||||
|
{ "policy-filter", 21, OT_ADDR_LIST },
|
||||||
|
{ "max-datagram-reassembly", 22, 2 | OT_DEC },
|
||||||
|
{ "default-ttl", 23, 1 | OT_DEC },
|
||||||
|
{ "mtu", 26, 2 | OT_DEC },
|
||||||
|
{ "all-subnets-local", 27, 1 },
|
||||||
|
{ "broadcast", 28, OT_INTERNAL | OT_ADDR_LIST },
|
||||||
|
{ "router-discovery", 31, 1 },
|
||||||
|
{ "router-solicitation", 32, OT_ADDR_LIST },
|
||||||
|
{ "static-route", 33, OT_ADDR_LIST },
|
||||||
|
{ "trailer-encapsulation", 34, 1 },
|
||||||
|
{ "arp-timeout", 35, 4 | OT_DEC },
|
||||||
|
{ "ethernet-encap", 36, 1 },
|
||||||
|
{ "tcp-ttl", 37, 1 },
|
||||||
|
{ "tcp-keepalive", 38, 4 | OT_DEC },
|
||||||
|
{ "nis-domain", 40, OT_NAME },
|
||||||
|
{ "nis-server", 41, OT_ADDR_LIST },
|
||||||
|
{ "ntp-server", 42, OT_ADDR_LIST },
|
||||||
|
{ "vendor-encap", 43, OT_INTERNAL },
|
||||||
|
{ "netbios-ns", 44, OT_ADDR_LIST },
|
||||||
|
{ "netbios-dd", 45, OT_ADDR_LIST },
|
||||||
|
{ "netbios-nodetype", 46, 1 },
|
||||||
|
{ "netbios-scope", 47, 0 },
|
||||||
|
{ "x-windows-fs", 48, OT_ADDR_LIST },
|
||||||
|
{ "x-windows-dm", 49, OT_ADDR_LIST },
|
||||||
|
{ "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
|
||||||
|
{ "lease-time", 51, OT_INTERNAL | OT_DEC },
|
||||||
|
{ "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},
|
||||||
|
{ "vendor-class", 60, 0 },
|
||||||
|
{ "client-id", 61, OT_INTERNAL },
|
||||||
|
{ "nis+-domain", 64, OT_NAME },
|
||||||
|
{ "nis+-server", 65, OT_ADDR_LIST },
|
||||||
|
{ "tftp-server", 66, OT_NAME },
|
||||||
|
{ "bootfile-name", 67, OT_NAME },
|
||||||
|
{ "mobile-ip-home", 68, OT_ADDR_LIST },
|
||||||
|
{ "smtp-server", 69, OT_ADDR_LIST },
|
||||||
|
{ "pop3-server", 70, OT_ADDR_LIST },
|
||||||
|
{ "nntp-server", 71, OT_ADDR_LIST },
|
||||||
|
{ "irc-server", 74, OT_ADDR_LIST },
|
||||||
|
{ "user-class", 77, 0 },
|
||||||
|
{ "FQDN", 81, OT_INTERNAL },
|
||||||
|
{ "agent-id", 82, OT_INTERNAL },
|
||||||
|
{ "client-arch", 93, 2 | OT_DEC },
|
||||||
|
{ "client-interface-id", 94, 0 },
|
||||||
|
{ "client-machine-id", 97, 0 },
|
||||||
|
{ "subnet-select", 118, OT_INTERNAL },
|
||||||
|
{ "domain-search", 119, OT_RFC1035_NAME },
|
||||||
|
{ "sip-server", 120, 0 },
|
||||||
|
{ "classless-static-route", 121, 0 },
|
||||||
|
{ "vendor-id-encap", 125, 0 },
|
||||||
|
{ "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
|
||||||
|
{ NULL, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
static const struct opttab_t opttab6[] = {
|
||||||
|
{ "client-id", 1, OT_INTERNAL },
|
||||||
|
{ "server-id", 2, OT_INTERNAL },
|
||||||
|
{ "ia-na", 3, OT_INTERNAL },
|
||||||
|
{ "ia-ta", 4, OT_INTERNAL },
|
||||||
|
{ "iaaddr", 5, OT_INTERNAL },
|
||||||
|
{ "oro", 6, OT_INTERNAL },
|
||||||
|
{ "preference", 7, OT_INTERNAL | OT_DEC },
|
||||||
|
{ "unicast", 12, OT_INTERNAL },
|
||||||
|
{ "status", 13, OT_INTERNAL },
|
||||||
|
{ "rapid-commit", 14, OT_INTERNAL },
|
||||||
|
{ "user-class", 15, OT_INTERNAL | OT_CSTRING },
|
||||||
|
{ "vendor-class", 16, OT_INTERNAL | OT_CSTRING },
|
||||||
|
{ "vendor-opts", 17, OT_INTERNAL },
|
||||||
|
{ "sip-server-domain", 21, OT_RFC1035_NAME },
|
||||||
|
{ "sip-server", 22, OT_ADDR_LIST },
|
||||||
|
{ "dns-server", 23, OT_ADDR_LIST },
|
||||||
|
{ "domain-search", 24, OT_RFC1035_NAME },
|
||||||
|
{ "nis-server", 27, OT_ADDR_LIST },
|
||||||
|
{ "nis+-server", 28, OT_ADDR_LIST },
|
||||||
|
{ "nis-domain", 29, OT_RFC1035_NAME },
|
||||||
|
{ "nis+-domain", 30, OT_RFC1035_NAME },
|
||||||
|
{ "sntp-server", 31, OT_ADDR_LIST },
|
||||||
|
{ "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
|
||||||
|
{ "ntp-server", 56, OT_ADDR_LIST },
|
||||||
|
{ "bootfile-url", 59, OT_NAME },
|
||||||
|
{ "bootfile-param", 60, OT_CSTRING },
|
||||||
|
{ NULL, 0, 0 }
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void display_opts(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
printf(_("Known DHCP options:\n"));
|
||||||
|
|
||||||
|
for (i = 0; opttab[i].name; i++)
|
||||||
|
if (!(opttab[i].size & OT_INTERNAL))
|
||||||
|
printf("%3d %s\n", opttab[i].val, opttab[i].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
void display_opts6(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
printf(_("Known DHCPv6 options:\n"));
|
||||||
|
|
||||||
|
for (i = 0; opttab6[i].name; i++)
|
||||||
|
if (!(opttab6[i].size & OT_INTERNAL))
|
||||||
|
printf("%3d %s\n", opttab6[i].val, opttab6[i].name);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
u16 lookup_dhcp_opt(int prot, char *name)
|
||||||
|
{
|
||||||
|
const struct opttab_t *t;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (prot == AF_INET6)
|
||||||
|
t = opttab6;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
t = opttab;
|
||||||
|
|
||||||
|
for (i = 0; t[i].name; i++)
|
||||||
|
if (!(t[i].size & OT_INTERNAL) &&
|
||||||
|
strcasecmp(t[i].name, name) == 0)
|
||||||
|
return t[i].val;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 lookup_dhcp_len(int prot, u16 val)
|
||||||
|
{
|
||||||
|
const struct opttab_t *t;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (prot == AF_INET6)
|
||||||
|
t = opttab6;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
t = opttab;
|
||||||
|
|
||||||
|
for (i = 0; t[i].name; i++)
|
||||||
|
if (val == t[i].val)
|
||||||
|
{
|
||||||
|
if (t[i].size & OT_INTERNAL)
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
int o, i, j, nodecode = 0;
|
||||||
|
const struct opttab_t *ot = opttab;
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (prot == AF_INET6)
|
||||||
|
ot = opttab6;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (o = 0; ot[o].name; o++)
|
||||||
|
if (ot[o].val == opt)
|
||||||
|
{
|
||||||
|
if (buf)
|
||||||
|
{
|
||||||
|
memset(buf, 0, buf_len);
|
||||||
|
|
||||||
|
if (ot[o].size & OT_ADDR_LIST)
|
||||||
|
{
|
||||||
|
struct all_addr addr;
|
||||||
|
int addr_len = INADDRSZ;
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (prot == AF_INET6)
|
||||||
|
addr_len = IN6ADDRSZ;
|
||||||
|
#endif
|
||||||
|
for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len)
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
strncat(buf, ", ", buf_len - strlen(buf));
|
||||||
|
/* align */
|
||||||
|
memcpy(&addr, &val[i], addr_len);
|
||||||
|
inet_ntop(prot, &val[i], daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
strncat(buf, daemon->addrbuff, buf_len - strlen(buf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ot[o].size & OT_NAME)
|
||||||
|
for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
|
||||||
|
{
|
||||||
|
char c = val[i];
|
||||||
|
if (isprint((int)c))
|
||||||
|
buf[j++] = c;
|
||||||
|
}
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
/* We don't handle compressed rfc1035 names, so no good in IPv4 land */
|
||||||
|
else if ((ot[o].size & OT_RFC1035_NAME) && prot == AF_INET6)
|
||||||
|
{
|
||||||
|
i = 0, j = 0;
|
||||||
|
while (i < opt_len && val[i] != 0)
|
||||||
|
{
|
||||||
|
int k, l = i + val[i] + 1;
|
||||||
|
for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++)
|
||||||
|
{
|
||||||
|
char c = val[k];
|
||||||
|
if (isprint((int)c))
|
||||||
|
buf[j++] = c;
|
||||||
|
}
|
||||||
|
i = l;
|
||||||
|
if (val[i] != 0 && j < buf_len)
|
||||||
|
buf[j++] = '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((ot[o].size & OT_CSTRING))
|
||||||
|
{
|
||||||
|
int k, len;
|
||||||
|
unsigned char *p;
|
||||||
|
|
||||||
|
i = 0, j = 0;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
p = &val[i];
|
||||||
|
GETSHORT(len, p);
|
||||||
|
for (k = 0; k < len && j < buf_len; k++)
|
||||||
|
{
|
||||||
|
char c = *p++;
|
||||||
|
if (isprint((int)c))
|
||||||
|
buf[j++] = c;
|
||||||
|
}
|
||||||
|
i += len +2;
|
||||||
|
if (i >= opt_len)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (j < buf_len)
|
||||||
|
buf[j++] = ',';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if ((ot[o].size & OT_DEC) && opt_len != 0)
|
||||||
|
{
|
||||||
|
unsigned int dec = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < opt_len; i++)
|
||||||
|
dec = (dec << 8) | val[i];
|
||||||
|
|
||||||
|
sprintf(buf, "%u", dec);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
nodecode = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt_len != 0 && buf && (!ot[o].name || nodecode))
|
||||||
|
{
|
||||||
|
int trunc = 0;
|
||||||
|
if (opt_len > 14)
|
||||||
|
{
|
||||||
|
trunc = 1;
|
||||||
|
opt_len = 14;
|
||||||
|
}
|
||||||
|
print_mac(buf, val, opt_len);
|
||||||
|
if (trunc)
|
||||||
|
strncat(buf, "...", buf_len - strlen(buf));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return ot[o].name ? ot[o].name : "";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 dated June, 1991, or
|
||||||
|
(at your option) version 3 dated 29 June, 2007.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#define DHCP_SERVER_PORT 67
|
||||||
|
#define DHCP_CLIENT_PORT 68
|
||||||
|
#define DHCP_SERVER_ALTPORT 1067
|
||||||
|
#define DHCP_CLIENT_ALTPORT 1068
|
||||||
|
#define PXE_PORT 4011
|
||||||
|
|
||||||
|
#define BOOTREQUEST 1
|
||||||
|
#define BOOTREPLY 2
|
||||||
|
#define DHCP_COOKIE 0x63825363
|
||||||
|
|
||||||
|
/* The Linux in-kernel DHCP client silently ignores any packet
|
||||||
|
smaller than this. Sigh........... */
|
||||||
|
#define MIN_PACKETSZ 300
|
||||||
|
|
||||||
|
#define OPTION_PAD 0
|
||||||
|
#define OPTION_NETMASK 1
|
||||||
|
#define OPTION_ROUTER 3
|
||||||
|
#define OPTION_DNSSERVER 6
|
||||||
|
#define OPTION_HOSTNAME 12
|
||||||
|
#define OPTION_DOMAINNAME 15
|
||||||
|
#define OPTION_BROADCAST 28
|
||||||
|
#define OPTION_VENDOR_CLASS_OPT 43
|
||||||
|
#define OPTION_REQUESTED_IP 50
|
||||||
|
#define OPTION_LEASE_TIME 51
|
||||||
|
#define OPTION_OVERLOAD 52
|
||||||
|
#define OPTION_MESSAGE_TYPE 53
|
||||||
|
#define OPTION_SERVER_IDENTIFIER 54
|
||||||
|
#define OPTION_REQUESTED_OPTIONS 55
|
||||||
|
#define OPTION_MESSAGE 56
|
||||||
|
#define OPTION_MAXMESSAGE 57
|
||||||
|
#define OPTION_T1 58
|
||||||
|
#define OPTION_T2 59
|
||||||
|
#define OPTION_VENDOR_ID 60
|
||||||
|
#define OPTION_CLIENT_ID 61
|
||||||
|
#define OPTION_SNAME 66
|
||||||
|
#define OPTION_FILENAME 67
|
||||||
|
#define OPTION_USER_CLASS 77
|
||||||
|
#define OPTION_CLIENT_FQDN 81
|
||||||
|
#define OPTION_AGENT_ID 82
|
||||||
|
#define OPTION_ARCH 93
|
||||||
|
#define OPTION_PXE_UUID 97
|
||||||
|
#define OPTION_SUBNET_SELECT 118
|
||||||
|
#define OPTION_DOMAIN_SEARCH 119
|
||||||
|
#define OPTION_SIP_SERVER 120
|
||||||
|
#define OPTION_VENDOR_IDENT 124
|
||||||
|
#define OPTION_VENDOR_IDENT_OPT 125
|
||||||
|
#define OPTION_END 255
|
||||||
|
|
||||||
|
#define SUBOPT_CIRCUIT_ID 1
|
||||||
|
#define SUBOPT_REMOTE_ID 2
|
||||||
|
#define SUBOPT_SUBNET_SELECT 5 /* RFC 3527 */
|
||||||
|
#define SUBOPT_SUBSCR_ID 6 /* RFC 3393 */
|
||||||
|
#define SUBOPT_SERVER_OR 11 /* RFC 5107 */
|
||||||
|
|
||||||
|
#define SUBOPT_PXE_BOOT_ITEM 71 /* PXE standard */
|
||||||
|
#define SUBOPT_PXE_DISCOVERY 6
|
||||||
|
#define SUBOPT_PXE_SERVERS 8
|
||||||
|
#define SUBOPT_PXE_MENU 9
|
||||||
|
#define SUBOPT_PXE_MENU_PROMPT 10
|
||||||
|
|
||||||
|
#define DHCPDISCOVER 1
|
||||||
|
#define DHCPOFFER 2
|
||||||
|
#define DHCPREQUEST 3
|
||||||
|
#define DHCPDECLINE 4
|
||||||
|
#define DHCPACK 5
|
||||||
|
#define DHCPNAK 6
|
||||||
|
#define DHCPRELEASE 7
|
||||||
|
#define DHCPINFORM 8
|
||||||
|
|
||||||
|
#define BRDBAND_FORUM_IANA 3561 /* Broadband forum IANA enterprise */
|
||||||
|
|
||||||
|
#define DHCP_CHADDR_MAX 16
|
||||||
|
|
||||||
|
struct dhcp_packet {
|
||||||
|
u8 op, htype, hlen, hops;
|
||||||
|
u32 xid;
|
||||||
|
u16 secs, flags;
|
||||||
|
struct in_addr ciaddr, yiaddr, siaddr, giaddr;
|
||||||
|
u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
|
||||||
|
u8 options[312];
|
||||||
|
};
|
||||||
+180
-284
@@ -1,4 +1,4 @@
|
|||||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,13 +19,19 @@
|
|||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
|
|
||||||
struct iface_param {
|
struct iface_param {
|
||||||
struct in_addr relay, primary;
|
|
||||||
struct dhcp_context *current;
|
struct dhcp_context *current;
|
||||||
int ind;
|
int ind;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct match_param {
|
||||||
|
int ind, matched;
|
||||||
|
struct in_addr netmask, broadcast, addr;
|
||||||
|
};
|
||||||
|
|
||||||
static int complete_context(struct in_addr local, int if_index,
|
static int complete_context(struct in_addr local, int if_index,
|
||||||
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
||||||
|
static int check_listen_addrs(struct in_addr local, int if_index,
|
||||||
|
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
||||||
|
|
||||||
static int make_fd(int port)
|
static int make_fd(int port)
|
||||||
{
|
{
|
||||||
@@ -35,16 +41,22 @@ static int make_fd(int port)
|
|||||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||||
int mtu = IP_PMTUDISC_DONT;
|
int mtu = IP_PMTUDISC_DONT;
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
|
||||||
|
int tos = IPTOS_CLASS_CS6;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
die (_("cannot create DHCP socket: %s"), NULL, EC_BADNET);
|
die (_("cannot create DHCP socket: %s"), NULL, EC_BADNET);
|
||||||
|
|
||||||
if (!fix_fd(fd) ||
|
if (!fix_fd(fd) ||
|
||||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||||
setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
|
setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
|
||||||
|
#endif
|
||||||
|
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
|
||||||
|
setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1 ||
|
||||||
#endif
|
#endif
|
||||||
#if defined(HAVE_LINUX_NETWORK)
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
|
setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
|
||||||
#else
|
#else
|
||||||
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
|
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
|
||||||
#endif
|
#endif
|
||||||
@@ -107,11 +119,8 @@ void dhcp_init(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
check_dhcp_hosts(1);
|
check_dhcp_hosts(1);
|
||||||
|
|
||||||
daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet);
|
|
||||||
daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dhcp_packet(time_t now, int pxe_fd)
|
void dhcp_packet(time_t now, int pxe_fd)
|
||||||
{
|
{
|
||||||
int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
|
int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
|
||||||
@@ -125,7 +134,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
ssize_t sz;
|
ssize_t sz;
|
||||||
int iface_index = 0, unicast_dest = 0, is_inform = 0;
|
int iface_index = 0, unicast_dest = 0, is_inform = 0;
|
||||||
struct in_addr iface_addr, *addrp = NULL;
|
struct in_addr iface_addr;
|
||||||
struct iface_param parm;
|
struct iface_param parm;
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
struct arpreq arp_req;
|
struct arpreq arp_req;
|
||||||
@@ -141,56 +150,23 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
|
char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
|
||||||
#endif
|
#endif
|
||||||
} control_u;
|
} control_u;
|
||||||
|
struct dhcp_bridge *bridge, *alias;
|
||||||
msg.msg_control = NULL;
|
|
||||||
msg.msg_controllen = 0;
|
msg.msg_controllen = sizeof(control_u);
|
||||||
msg.msg_name = NULL;
|
msg.msg_control = control_u.control;
|
||||||
msg.msg_namelen = 0;
|
msg.msg_name = &dest;
|
||||||
|
msg.msg_namelen = sizeof(dest);
|
||||||
msg.msg_iov = &daemon->dhcp_packet;
|
msg.msg_iov = &daemon->dhcp_packet;
|
||||||
msg.msg_iovlen = 1;
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
while (1)
|
if ((sz = recv_dhcp_packet(fd, &msg)) == -1 ||
|
||||||
{
|
(sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options))))
|
||||||
msg.msg_flags = 0;
|
|
||||||
while ((sz = recvmsg(fd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
|
|
||||||
|
|
||||||
if (sz == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!(msg.msg_flags & MSG_TRUNC))
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Very new Linux kernels return the actual size needed,
|
|
||||||
older ones always return truncated size */
|
|
||||||
if ((size_t)sz == daemon->dhcp_packet.iov_len)
|
|
||||||
{
|
|
||||||
if (!expand_buf(&daemon->dhcp_packet, sz + 100))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
expand_buf(&daemon->dhcp_packet, sz);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* expand_buf may have moved buffer */
|
|
||||||
mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
|
|
||||||
msg.msg_controllen = sizeof(control_u);
|
|
||||||
msg.msg_control = control_u.control;
|
|
||||||
msg.msg_flags = 0;
|
|
||||||
msg.msg_name = &dest;
|
|
||||||
msg.msg_namelen = sizeof(dest);
|
|
||||||
|
|
||||||
while ((sz = recvmsg(fd, &msg, 0)) == -1 && errno == EINTR);
|
|
||||||
|
|
||||||
if ((msg.msg_flags & MSG_TRUNC) || sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#if defined (HAVE_LINUX_NETWORK)
|
#if defined (HAVE_LINUX_NETWORK)
|
||||||
if (msg.msg_controllen >= sizeof(struct cmsghdr))
|
if (msg.msg_controllen >= sizeof(struct cmsghdr))
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
unsigned char *c;
|
unsigned char *c;
|
||||||
@@ -237,26 +213,50 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
|
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* One form of bridging on BSD has the property that packets
|
||||||
|
can be recieved on bridge interfaces which do not have an IP address.
|
||||||
|
We allow these to be treated as aliases of another interface which does have
|
||||||
|
an IP address with --dhcp-bridge=interface,alias,alias */
|
||||||
|
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
|
||||||
|
{
|
||||||
|
for (alias = bridge->alias; alias; alias = alias->next)
|
||||||
|
if (strncmp(ifr.ifr_name, alias->iface, IF_NAMESIZE) == 0)
|
||||||
|
{
|
||||||
|
if (!(iface_index = if_nametoindex(bridge->iface)))
|
||||||
|
{
|
||||||
|
my_syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), ifr.ifr_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strncpy(ifr.ifr_name, bridge->iface, IF_NAMESIZE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alias)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef MSG_BCAST
|
#ifdef MSG_BCAST
|
||||||
/* OpenBSD tells us when a packet was broadcast */
|
/* OpenBSD tells us when a packet was broadcast */
|
||||||
if (!(msg.msg_flags & MSG_BCAST))
|
if (!(msg.msg_flags & MSG_BCAST))
|
||||||
unicast_dest = 1;
|
unicast_dest = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ifr.ifr_addr.sa_family = AF_INET;
|
ifr.ifr_addr.sa_family = AF_INET;
|
||||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
|
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
|
||||||
|
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
addrp = &iface_addr;
|
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
|
||||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name, &iface_index))
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* weird libvirt-inspired access control */
|
/* weird libvirt-inspired access control */
|
||||||
for (context = daemon->dhcp; context; context = context->next)
|
for (context = daemon->dhcp; context; context = context->next)
|
||||||
if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
|
if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
|
||||||
@@ -264,44 +264,42 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
|
|
||||||
if (!context)
|
if (!context)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* unlinked contexts are marked by context->current == context */
|
/* unlinked contexts are marked by context->current == context */
|
||||||
for (context = daemon->dhcp; context; context = context->next)
|
for (context = daemon->dhcp; context; context = context->next)
|
||||||
context->current = context;
|
context->current = context;
|
||||||
|
|
||||||
parm.relay = mess->giaddr;
|
|
||||||
parm.primary = iface_addr;
|
|
||||||
parm.current = NULL;
|
parm.current = NULL;
|
||||||
parm.ind = iface_index;
|
parm.ind = iface_index;
|
||||||
|
|
||||||
/* interface may have been changed by alias in iface_check, make sure it gets priority in case
|
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name))
|
||||||
there is more than one address on the interface in the same subnet */
|
|
||||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
|
|
||||||
{
|
{
|
||||||
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
|
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
|
||||||
return;
|
for a secondary */
|
||||||
}
|
struct match_param match;
|
||||||
else
|
|
||||||
{
|
|
||||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
|
||||||
if (ioctl(daemon->dhcpfd, SIOCGIFNETMASK, &ifr) != -1)
|
|
||||||
{
|
|
||||||
struct in_addr netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
|
||||||
if (ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) != -1)
|
|
||||||
{
|
|
||||||
struct in_addr broadcast = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
|
||||||
complete_context(iface_addr, iface_index, netmask, broadcast, &parm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
match.matched = 0;
|
||||||
|
match.ind = iface_index;
|
||||||
|
|
||||||
|
if (!daemon->if_addrs ||
|
||||||
|
!iface_enumerate(AF_INET, &match, check_listen_addrs) ||
|
||||||
|
!match.matched)
|
||||||
|
return;
|
||||||
|
|
||||||
|
iface_addr = match.addr;
|
||||||
|
/* make sure secondary address gets priority in case
|
||||||
|
there is more than one address on the interface in the same subnet */
|
||||||
|
complete_context(match.addr, iface_index, match.netmask, match.broadcast, &parm);
|
||||||
|
}
|
||||||
|
|
||||||
if (!iface_enumerate(AF_INET, &parm, complete_context))
|
if (!iface_enumerate(AF_INET, &parm, complete_context))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lease_prune(NULL, now); /* lose any expired leases */
|
lease_prune(NULL, now); /* lose any expired leases */
|
||||||
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
|
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
|
||||||
now, unicast_dest, &is_inform, pxe_fd);
|
now, unicast_dest, &is_inform, pxe_fd, iface_addr);
|
||||||
lease_update_file(now);
|
lease_update_file(now);
|
||||||
lease_update_dns();
|
lease_update_dns(0);
|
||||||
|
|
||||||
if (iov.iov_len == 0)
|
if (iov.iov_len == 0)
|
||||||
return;
|
return;
|
||||||
@@ -319,7 +317,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
dest.sin_len = sizeof(struct sockaddr_in);
|
dest.sin_len = sizeof(struct sockaddr_in);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (pxe_fd)
|
if (pxe_fd)
|
||||||
{
|
{
|
||||||
if (mess->ciaddr.s_addr != 0)
|
if (mess->ciaddr.s_addr != 0)
|
||||||
@@ -357,7 +355,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
pkt->ipi_ifindex = iface_index;
|
pkt->ipi_ifindex = iface_index;
|
||||||
pkt->ipi_spec_dst.s_addr = 0;
|
pkt->ipi_spec_dst.s_addr = 0;
|
||||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||||
cmptr->cmsg_level = SOL_IP;
|
cmptr->cmsg_level = IPPROTO_IP;
|
||||||
cmptr->cmsg_type = IP_PKTINFO;
|
cmptr->cmsg_type = IP_PKTINFO;
|
||||||
dest.sin_addr.s_addr = INADDR_BROADCAST;
|
dest.sin_addr.s_addr = INADDR_BROADCAST;
|
||||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||||
@@ -414,6 +412,30 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
while(sendmsg(fd, &msg, 0) == -1 && retry_send());
|
while(sendmsg(fd, &msg, 0) == -1 && retry_send());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check against secondary interface addresses */
|
||||||
|
static int check_listen_addrs(struct in_addr local, int if_index,
|
||||||
|
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||||
|
{
|
||||||
|
struct match_param *param = vparam;
|
||||||
|
struct iname *tmp;
|
||||||
|
|
||||||
|
if (if_index == param->ind)
|
||||||
|
{
|
||||||
|
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||||
|
if ( tmp->addr.sa.sa_family == AF_INET &&
|
||||||
|
tmp->addr.in.sin_addr.s_addr == local.s_addr)
|
||||||
|
{
|
||||||
|
param->matched = 1;
|
||||||
|
param->addr = local;
|
||||||
|
param->netmask = netmask;
|
||||||
|
param->broadcast = broadcast;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
|
/* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
|
||||||
of each interface (and any relay address) and does the following things:
|
of each interface (and any relay address) and does the following things:
|
||||||
|
|
||||||
@@ -448,38 +470,27 @@ static int complete_context(struct in_addr local, int if_index,
|
|||||||
context->netmask = netmask;
|
context->netmask = netmask;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context->netmask.s_addr)
|
if (context->netmask.s_addr != 0 &&
|
||||||
|
is_same_net(local, context->start, context->netmask) &&
|
||||||
|
is_same_net(local, context->end, context->netmask))
|
||||||
{
|
{
|
||||||
if (is_same_net(local, context->start, context->netmask) &&
|
/* link it onto the current chain if we've not seen it before */
|
||||||
is_same_net(local, context->end, context->netmask))
|
if (if_index == param->ind && context->current == context)
|
||||||
{
|
{
|
||||||
/* link it onto the current chain if we've not seen it before */
|
context->router = local;
|
||||||
if (if_index == param->ind && context->current == context)
|
context->local = local;
|
||||||
{
|
context->current = param->current;
|
||||||
context->router = local;
|
param->current = context;
|
||||||
context->local = local;
|
}
|
||||||
context->current = param->current;
|
|
||||||
param->current = context;
|
if (!(context->flags & CONTEXT_BRDCAST))
|
||||||
}
|
|
||||||
|
|
||||||
if (!(context->flags & CONTEXT_BRDCAST))
|
|
||||||
{
|
|
||||||
if (is_same_net(broadcast, context->start, context->netmask))
|
|
||||||
context->broadcast = broadcast;
|
|
||||||
else
|
|
||||||
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (param->relay.s_addr && is_same_net(param->relay, context->start, context->netmask))
|
|
||||||
{
|
{
|
||||||
context->router = param->relay;
|
if (is_same_net(broadcast, context->start, context->netmask))
|
||||||
context->local = param->primary;
|
context->broadcast = broadcast;
|
||||||
/* fill in missing broadcast addresses for relayed ranges */
|
else
|
||||||
if (!(context->flags & CONTEXT_BRDCAST))
|
|
||||||
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
|
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -505,7 +516,7 @@ struct dhcp_context *address_available(struct dhcp_context *context,
|
|||||||
start = ntohl(tmp->start.s_addr);
|
start = ntohl(tmp->start.s_addr);
|
||||||
end = ntohl(tmp->end.s_addr);
|
end = ntohl(tmp->end.s_addr);
|
||||||
|
|
||||||
if (!(tmp->flags & CONTEXT_STATIC) &&
|
if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) &&
|
||||||
addr >= start &&
|
addr >= start &&
|
||||||
addr <= end &&
|
addr <= end &&
|
||||||
match_netid(tmp->filter, netids, 1))
|
match_netid(tmp->filter, netids, 1))
|
||||||
@@ -540,7 +551,8 @@ struct dhcp_context *narrow_context(struct dhcp_context *context,
|
|||||||
if (!tmp)
|
if (!tmp)
|
||||||
for (tmp = context; tmp; tmp = tmp->current)
|
for (tmp = context; tmp; tmp = tmp->current)
|
||||||
if (match_netid(tmp->filter, netids, 1) &&
|
if (match_netid(tmp->filter, netids, 1) &&
|
||||||
is_same_net(taddr, tmp->start, tmp->netmask))
|
is_same_net(taddr, tmp->start, tmp->netmask) &&
|
||||||
|
!(tmp->flags & CONTEXT_PROXY))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -562,50 +574,6 @@ struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct i
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is every member of check matched by a member of pool?
|
|
||||||
If tagnotneeded, untagged is OK */
|
|
||||||
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded)
|
|
||||||
{
|
|
||||||
struct dhcp_netid *tmp1;
|
|
||||||
|
|
||||||
if (!check && !tagnotneeded)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (; check; check = check->next)
|
|
||||||
{
|
|
||||||
/* '#' for not is for backwards compat. */
|
|
||||||
if (check->net[0] != '!' && check->net[0] != '#')
|
|
||||||
{
|
|
||||||
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
|
||||||
if (strcmp(check->net, tmp1->net) == 0)
|
|
||||||
break;
|
|
||||||
if (!tmp1)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
|
||||||
if (strcmp((check->net)+1, tmp1->net) == 0)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
|
|
||||||
{
|
|
||||||
struct tag_if *exprs;
|
|
||||||
struct dhcp_netid_list *list;
|
|
||||||
|
|
||||||
for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
|
|
||||||
if (match_netid(exprs->tag, tags, 1))
|
|
||||||
for (list = exprs->set; list; list = list->next)
|
|
||||||
{
|
|
||||||
list->list->next = tags;
|
|
||||||
tags = list->list;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tags;
|
|
||||||
}
|
|
||||||
|
|
||||||
int address_allocate(struct dhcp_context *context,
|
int address_allocate(struct dhcp_context *context,
|
||||||
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
|
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
|
||||||
struct dhcp_netid *netids, time_t now)
|
struct dhcp_netid *netids, time_t now)
|
||||||
@@ -626,16 +594,22 @@ int address_allocate(struct dhcp_context *context,
|
|||||||
|
|
||||||
for (pass = 0; pass <= 1; pass++)
|
for (pass = 0; pass <= 1; pass++)
|
||||||
for (c = context; c; c = c->current)
|
for (c = context; c; c = c->current)
|
||||||
if (c->flags & CONTEXT_STATIC)
|
if (c->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
|
||||||
continue;
|
continue;
|
||||||
else if (!match_netid(c->filter, netids, pass))
|
else if (!match_netid(c->filter, netids, pass))
|
||||||
continue;
|
continue;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* pick a seed based on hwaddr then iterate until we find a free address. */
|
if (option_bool(OPT_CONSEC_ADDR))
|
||||||
start.s_addr = addr.s_addr =
|
/* seed is largest extant lease addr in this context */
|
||||||
htonl(ntohl(c->start.s_addr) +
|
start = lease_find_max_addr(c);
|
||||||
((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
|
else
|
||||||
|
/* pick a seed based on hwaddr */
|
||||||
|
start.s_addr = htonl(ntohl(c->start.s_addr) +
|
||||||
|
((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
|
||||||
|
|
||||||
|
/* iterate until we find a free address. */
|
||||||
|
addr = start;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
/* eliminate addresses in use by the server. */
|
/* eliminate addresses in use by the server. */
|
||||||
@@ -660,9 +634,6 @@ int address_allocate(struct dhcp_context *context,
|
|||||||
|
|
||||||
*addrp = addr;
|
*addrp = addr;
|
||||||
|
|
||||||
if (option_bool(OPT_NO_PING))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* check if we failed to ping addr sometime in the last
|
/* check if we failed to ping addr sometime in the last
|
||||||
PING_CACHE_TIME seconds. If so, assume the same situation still exists.
|
PING_CACHE_TIME seconds. If so, assume the same situation still exists.
|
||||||
This avoids problems when a stupid client bangs
|
This avoids problems when a stupid client bangs
|
||||||
@@ -672,33 +643,51 @@ int address_allocate(struct dhcp_context *context,
|
|||||||
for (count = 0, r = daemon->ping_results; r; r = r->next)
|
for (count = 0, r = daemon->ping_results; r; r = r->next)
|
||||||
if (difftime(now, r->time) > (float)PING_CACHE_TIME)
|
if (difftime(now, r->time) > (float)PING_CACHE_TIME)
|
||||||
victim = r; /* old record */
|
victim = r; /* old record */
|
||||||
else if (++count == max || r->addr.s_addr == addr.s_addr)
|
else
|
||||||
return 1;
|
{
|
||||||
|
count++;
|
||||||
if (icmp_ping(addr))
|
if (r->addr.s_addr == addr.s_addr)
|
||||||
/* address in use: perturb address selection so that we are
|
{
|
||||||
less likely to try this address again. */
|
/* consec-ip mode: we offered this address for another client
|
||||||
c->addr_epoch++;
|
(different hash) recently, don't offer it to this one. */
|
||||||
else
|
if (option_bool(OPT_CONSEC_ADDR) && r->hash != j)
|
||||||
|
break;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!r)
|
||||||
{
|
{
|
||||||
/* at this point victim may hold an expired record */
|
if ((count < max) && !option_bool(OPT_NO_PING) && icmp_ping(addr))
|
||||||
if (!victim)
|
|
||||||
{
|
{
|
||||||
if ((victim = whine_malloc(sizeof(struct ping_result))))
|
/* address in use: perturb address selection so that we are
|
||||||
|
less likely to try this address again. */
|
||||||
|
if (!option_bool(OPT_CONSEC_ADDR))
|
||||||
|
c->addr_epoch++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* at this point victim may hold an expired record */
|
||||||
|
if (!victim)
|
||||||
{
|
{
|
||||||
victim->next = daemon->ping_results;
|
if ((victim = whine_malloc(sizeof(struct ping_result))))
|
||||||
daemon->ping_results = victim;
|
{
|
||||||
|
victim->next = daemon->ping_results;
|
||||||
|
daemon->ping_results = victim;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* record that this address is OK for 30s
|
||||||
|
without more ping checks */
|
||||||
|
if (victim)
|
||||||
|
{
|
||||||
|
victim->addr = addr;
|
||||||
|
victim->time = now;
|
||||||
|
victim->hash = j;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* record that this address is OK for 30s
|
|
||||||
without more ping checks */
|
|
||||||
if (victim)
|
|
||||||
{
|
|
||||||
victim->addr = addr;
|
|
||||||
victim->time = now;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -709,6 +698,7 @@ int address_allocate(struct dhcp_context *context,
|
|||||||
|
|
||||||
} while (addr.s_addr != start.s_addr);
|
} while (addr.s_addr != start.s_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -779,7 +769,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
|
|||||||
is_addr_in_context(context, config))
|
is_addr_in_context(context, config))
|
||||||
return config;
|
return config;
|
||||||
|
|
||||||
/* use match with fewest wildcast octets */
|
/* use match with fewest wildcard octets */
|
||||||
for (candidate = NULL, count = 0, config = configs; config; config = config->next)
|
for (candidate = NULL, count = 0, config = configs; config; config = config->next)
|
||||||
if (is_addr_in_context(context, config))
|
if (is_addr_in_context(context, config))
|
||||||
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
|
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
|
||||||
@@ -956,85 +946,6 @@ void dhcp_read_ethers(void)
|
|||||||
my_syslog(MS_DHCP | LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
|
my_syslog(MS_DHCP | LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_dhcp_hosts(int fatal)
|
|
||||||
{
|
|
||||||
/* If the same IP appears in more than one host config, then DISCOVER
|
|
||||||
for one of the hosts will get the address, but REQUEST will be NAKed,
|
|
||||||
since the address is reserved by the other one -> protocol loop.
|
|
||||||
Also check that FQDNs match the domain we are using. */
|
|
||||||
|
|
||||||
struct dhcp_config *configs, *cp;
|
|
||||||
|
|
||||||
for (configs = daemon->dhcp_conf; configs; configs = configs->next)
|
|
||||||
{
|
|
||||||
char *domain;
|
|
||||||
|
|
||||||
if ((configs->flags & DHOPT_BANK) || fatal)
|
|
||||||
{
|
|
||||||
for (cp = configs->next; cp; cp = cp->next)
|
|
||||||
if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr)
|
|
||||||
{
|
|
||||||
if (fatal)
|
|
||||||
die(_("duplicate IP address %s in dhcp-config directive."),
|
|
||||||
inet_ntoa(cp->addr), EC_BADCONF);
|
|
||||||
else
|
|
||||||
my_syslog(MS_DHCP | LOG_ERR, _("duplicate IP address %s in %s."),
|
|
||||||
inet_ntoa(cp->addr), daemon->dhcp_hosts_file);
|
|
||||||
configs->flags &= ~CONFIG_ADDR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* split off domain part */
|
|
||||||
if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
|
|
||||||
configs->domain = domain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void dhcp_update_configs(struct dhcp_config *configs)
|
|
||||||
{
|
|
||||||
/* Some people like to keep all static IP addresses in /etc/hosts.
|
|
||||||
This goes through /etc/hosts and sets static addresses for any DHCP config
|
|
||||||
records which don't have an address and whose name matches.
|
|
||||||
We take care to maintain the invariant that any IP address can appear
|
|
||||||
in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
|
|
||||||
restore the status-quo ante first. */
|
|
||||||
|
|
||||||
struct dhcp_config *config;
|
|
||||||
struct crec *crec;
|
|
||||||
|
|
||||||
for (config = configs; config; config = config->next)
|
|
||||||
if (config->flags & CONFIG_ADDR_HOSTS)
|
|
||||||
config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS);
|
|
||||||
|
|
||||||
|
|
||||||
if (daemon->port != 0)
|
|
||||||
for (config = configs; config; config = config->next)
|
|
||||||
if (!(config->flags & CONFIG_ADDR) &&
|
|
||||||
(config->flags & CONFIG_NAME) &&
|
|
||||||
(crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
|
|
||||||
(crec->flags & F_HOSTS))
|
|
||||||
{
|
|
||||||
if (cache_find_by_name(crec, config->hostname, 0, F_IPV4))
|
|
||||||
{
|
|
||||||
/* use primary (first) address */
|
|
||||||
while (crec && !(crec->flags & F_REVERSE))
|
|
||||||
crec = cache_find_by_name(crec, config->hostname, 0, F_IPV4);
|
|
||||||
if (!crec)
|
|
||||||
continue; /* should be never */
|
|
||||||
my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
|
|
||||||
config->hostname, inet_ntoa(crec->addr.addr.addr.addr4));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config_find_by_address(configs, crec->addr.addr.addr.addr4))
|
|
||||||
my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
|
|
||||||
inet_ntoa(crec->addr.addr.addr.addr4), config->hostname);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
config->addr = crec->addr.addr.addr.addr4;
|
|
||||||
config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
|
/* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
|
||||||
for this address. If it has a domain part, that must match the set domain and
|
for this address. If it has a domain part, that must match the set domain and
|
||||||
@@ -1075,20 +986,5 @@ char *host_from_dns(struct in_addr addr)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return domain or NULL if none. */
|
|
||||||
char *strip_hostname(char *hostname)
|
|
||||||
{
|
|
||||||
char *dot = strchr(hostname, '.');
|
|
||||||
|
|
||||||
if (!dot)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
*dot = 0; /* truncate */
|
|
||||||
if (strlen(dot+1) != 0)
|
|
||||||
return dot+1;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 dated June, 1991, or
|
||||||
|
(at your option) version 3 dated 29 June, 2007.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DHCPV6_SERVER_PORT 547
|
||||||
|
#define DHCPV6_CLIENT_PORT 546
|
||||||
|
|
||||||
|
#define ALL_SERVERS "FF05::1:3"
|
||||||
|
#define ALL_RELAY_AGENTS_AND_SERVERS "FF02::1:2"
|
||||||
|
|
||||||
|
#define DHCP6SOLICIT 1
|
||||||
|
#define DHCP6ADVERTISE 2
|
||||||
|
#define DHCP6REQUEST 3
|
||||||
|
#define DHCP6CONFIRM 4
|
||||||
|
#define DHCP6RENEW 5
|
||||||
|
#define DHCP6REBIND 6
|
||||||
|
#define DHCP6REPLY 7
|
||||||
|
#define DHCP6RELEASE 8
|
||||||
|
#define DHCP6DECLINE 9
|
||||||
|
#define DHCP6RECONFIGURE 10
|
||||||
|
#define DHCP6IREQ 11
|
||||||
|
#define DHCP6RELAYFORW 12
|
||||||
|
#define DHCP6RELAYREPL 13
|
||||||
|
|
||||||
|
#define OPTION6_CLIENT_ID 1
|
||||||
|
#define OPTION6_SERVER_ID 2
|
||||||
|
#define OPTION6_IA_NA 3
|
||||||
|
#define OPTION6_IA_TA 4
|
||||||
|
#define OPTION6_IAADDR 5
|
||||||
|
#define OPTION6_ORO 6
|
||||||
|
#define OPTION6_PREFERENCE 7
|
||||||
|
#define OPTION6_ELAPSED_TIME 8
|
||||||
|
#define OPTION6_RELAY_MSG 9
|
||||||
|
#define OPTION6_AUTH 11
|
||||||
|
#define OPTION6_UNICAST 12
|
||||||
|
#define OPTION6_STATUS_CODE 13
|
||||||
|
#define OPTION6_RAPID_COMMIT 14
|
||||||
|
#define OPTION6_USER_CLASS 15
|
||||||
|
#define OPTION6_VENDOR_CLASS 16
|
||||||
|
#define OPTION6_VENDOR_OPTS 17
|
||||||
|
#define OPTION6_INTERFACE_ID 18
|
||||||
|
#define OPTION6_RECONFIGURE_MSG 19
|
||||||
|
#define OPTION6_RECONF_ACCEPT 20
|
||||||
|
#define OPTION6_DNS_SERVER 23
|
||||||
|
#define OPTION6_DOMAIN_SEARCH 24
|
||||||
|
#define OPTION6_REMOTE_ID 37
|
||||||
|
#define OPTION6_SUBSCRIBER_ID 38
|
||||||
|
#define OPTION6_FQDN 39
|
||||||
|
|
||||||
|
#define DHCP6SUCCESS 0
|
||||||
|
#define DHCP6UNSPEC 1
|
||||||
|
#define DHCP6NOADDRS 2
|
||||||
|
#define DHCP6NOBINDING 3
|
||||||
|
#define DHCP6NOTONLINK 4
|
||||||
|
#define DHCP6USEMULTI 5
|
||||||
|
|
||||||
+431
@@ -0,0 +1,431 @@
|
|||||||
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 dated June, 1991, or
|
||||||
|
(at your option) version 3 dated 29 June, 2007.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
|
||||||
|
struct iface_param {
|
||||||
|
struct dhcp_context *current;
|
||||||
|
struct in6_addr fallback;
|
||||||
|
int ind;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int complete_context6(struct in6_addr *local, int prefix,
|
||||||
|
int scope, int if_index, int dad, void *vparam);
|
||||||
|
|
||||||
|
static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm);
|
||||||
|
|
||||||
|
void dhcp6_init(void)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct sockaddr_in6 saddr;
|
||||||
|
#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
|
||||||
|
int class = IPTOS_CLASS_CS6;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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
|
||||||
|
!fix_fd(fd) ||
|
||||||
|
!set_ipv6pktinfo(fd))
|
||||||
|
die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
|
||||||
|
|
||||||
|
memset(&saddr, 0, sizeof(saddr));
|
||||||
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
|
saddr.sin6_len = sizeof(struct sockaddr_in6);
|
||||||
|
#endif
|
||||||
|
saddr.sin6_family = AF_INET6;
|
||||||
|
saddr.sin6_addr = in6addr_any;
|
||||||
|
saddr.sin6_port = htons(DHCPV6_SERVER_PORT);
|
||||||
|
|
||||||
|
if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in6)))
|
||||||
|
die(_("failed to bind DHCPv6 server socket: %s"), NULL, EC_BADNET);
|
||||||
|
|
||||||
|
daemon->dhcp6fd = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dhcp6_packet(time_t now)
|
||||||
|
{
|
||||||
|
struct dhcp_context *context;
|
||||||
|
struct iface_param parm;
|
||||||
|
struct cmsghdr *cmptr;
|
||||||
|
struct msghdr msg;
|
||||||
|
int if_index = 0;
|
||||||
|
union {
|
||||||
|
struct cmsghdr align; /* this ensures alignment */
|
||||||
|
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||||
|
} control_u;
|
||||||
|
struct sockaddr_in6 from;
|
||||||
|
struct all_addr dest;
|
||||||
|
ssize_t sz;
|
||||||
|
struct ifreq ifr;
|
||||||
|
struct iname *tmp;
|
||||||
|
unsigned short port;
|
||||||
|
|
||||||
|
msg.msg_control = control_u.control6;
|
||||||
|
msg.msg_controllen = sizeof(control_u);
|
||||||
|
msg.msg_flags = 0;
|
||||||
|
msg.msg_name = &from;
|
||||||
|
msg.msg_namelen = sizeof(from);
|
||||||
|
msg.msg_iov = &daemon->dhcp_packet;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
|
if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg)) == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
|
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
unsigned char *c;
|
||||||
|
struct in6_pktinfo *p;
|
||||||
|
} p;
|
||||||
|
p.c = CMSG_DATA(cmptr);
|
||||||
|
|
||||||
|
if_index = p.p->ipi6_ifindex;
|
||||||
|
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->dhcp_except; tmp; tmp = tmp->next)
|
||||||
|
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* weird libvirt-inspired access control */
|
||||||
|
for (context = daemon->dhcp6; context; context = context->next)
|
||||||
|
if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
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;
|
||||||
|
memset(&parm.fallback, 0, IN6ADDRSZ);
|
||||||
|
|
||||||
|
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
|
||||||
|
return;
|
||||||
|
|
||||||
|
lease_prune(NULL, now); /* lose any expired leases */
|
||||||
|
|
||||||
|
port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
|
||||||
|
sz, IN6_IS_ADDR_MULTICAST(&from.sin6_addr), now);
|
||||||
|
|
||||||
|
lease_update_file(now);
|
||||||
|
lease_update_dns(0);
|
||||||
|
|
||||||
|
/* The port in the source address of the original request should
|
||||||
|
be correct, but at least once client sends from the server port,
|
||||||
|
so we explicitly send to the client port to a client, and the
|
||||||
|
server port to a relay. */
|
||||||
|
if (port != 0)
|
||||||
|
{
|
||||||
|
from.sin6_port = htons(port);
|
||||||
|
while (sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, save_counter(0),
|
||||||
|
0, (struct sockaddr *)&from, sizeof(from)) == -1 &&
|
||||||
|
retry_send());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int complete_context6(struct in6_addr *local, int prefix,
|
||||||
|
int scope, int if_index, int dad, void *vparam)
|
||||||
|
{
|
||||||
|
struct dhcp_context *context;
|
||||||
|
struct iface_param *param = vparam;
|
||||||
|
|
||||||
|
(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))
|
||||||
|
{
|
||||||
|
/* Determine a globally address on the arrival interface, even
|
||||||
|
if we have no matching dhcp-context, because we're only
|
||||||
|
allocating on remote subnets via relays. This
|
||||||
|
is used as a default for the DNS server option. */
|
||||||
|
param->fallback = *local;
|
||||||
|
|
||||||
|
for (context = daemon->dhcp6; context; context = context->next)
|
||||||
|
{
|
||||||
|
if (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;
|
||||||
|
context->local6 = *local;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr)
|
||||||
|
{
|
||||||
|
struct dhcp_config *config;
|
||||||
|
|
||||||
|
for (config = configs; config; config = config->next)
|
||||||
|
if ((config->flags & CONFIG_ADDR6) &&
|
||||||
|
is_same_net6(&config->addr6, net, prefix) &&
|
||||||
|
(prefix == 128 || addr6part(&config->addr6) == addr))
|
||||||
|
return config;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
|
||||||
|
int serial, struct dhcp_netid *netids, struct in6_addr *ans)
|
||||||
|
{
|
||||||
|
/* Find a free address: exclude anything in use and anything allocated to
|
||||||
|
a particular hwaddr/clientid/hostname in our configuration.
|
||||||
|
Try to return from contexts which match netids first.
|
||||||
|
|
||||||
|
Note that we assume the address prefix lengths are 64 or greater, so we can
|
||||||
|
get by with 64 bit arithmetic.
|
||||||
|
*/
|
||||||
|
|
||||||
|
u64 start, addr;
|
||||||
|
struct dhcp_context *c, *d;
|
||||||
|
int i, pass;
|
||||||
|
u64 j;
|
||||||
|
|
||||||
|
/* hash hwaddr: use the SDBM hashing algorithm. This works
|
||||||
|
for MAC addresses, let's see how it manages with client-ids! */
|
||||||
|
for (j = 0, i = 0; i < clid_len; i++)
|
||||||
|
j += clid[i] + (j << 6) + (j << 16) - j;
|
||||||
|
|
||||||
|
for (pass = 0; pass <= 1; pass++)
|
||||||
|
for (c = context; c; c = c->current)
|
||||||
|
if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS))
|
||||||
|
continue;
|
||||||
|
else if (!match_netid(c->filter, netids, pass))
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (option_bool(OPT_CONSEC_ADDR))
|
||||||
|
/* seed is largest extant lease addr in this context */
|
||||||
|
start = lease_find_max_addr6(c) + serial;
|
||||||
|
else
|
||||||
|
start = addr6part(&c->start6) + ((j + c->addr_epoch + serial) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
|
||||||
|
|
||||||
|
/* iterate until we find a free address. */
|
||||||
|
addr = start;
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* eliminate addresses in use by the server. */
|
||||||
|
for (d = context; d; d = d->current)
|
||||||
|
if (addr == addr6part(&d->local6))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!d &&
|
||||||
|
!lease6_find_by_addr(&c->start6, c->prefix, addr) &&
|
||||||
|
!config_find_by_address6(daemon->dhcp_conf, &c->start6, c->prefix, addr))
|
||||||
|
{
|
||||||
|
*ans = c->start6;
|
||||||
|
setaddr6part (ans, addr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr++;
|
||||||
|
|
||||||
|
if (addr == addr6part(&c->end6) + 1)
|
||||||
|
addr = addr6part(&c->start6);
|
||||||
|
|
||||||
|
} while (addr != start);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dhcp_context *address6_available(struct dhcp_context *context,
|
||||||
|
struct in6_addr *taddr,
|
||||||
|
struct dhcp_netid *netids)
|
||||||
|
{
|
||||||
|
u64 start, end, addr = addr6part(taddr);
|
||||||
|
struct dhcp_context *tmp;
|
||||||
|
|
||||||
|
for (tmp = context; tmp; tmp = tmp->current)
|
||||||
|
{
|
||||||
|
start = addr6part(&tmp->start6);
|
||||||
|
end = addr6part(&tmp->end6);
|
||||||
|
|
||||||
|
if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_RA_STATELESS)) &&
|
||||||
|
is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
|
||||||
|
is_same_net6(&tmp->end6, taddr, tmp->prefix) &&
|
||||||
|
addr >= start &&
|
||||||
|
addr <= end &&
|
||||||
|
match_netid(tmp->filter, netids, 1))
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dhcp_context *narrow_context6(struct dhcp_context *context,
|
||||||
|
struct in6_addr *taddr,
|
||||||
|
struct dhcp_netid *netids)
|
||||||
|
{
|
||||||
|
/* We start of with a set of possible contexts, all on the current physical interface.
|
||||||
|
These are chained on ->current.
|
||||||
|
Here we have an address, and return the actual context 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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int is_addr_in_context6(struct dhcp_context *context, struct dhcp_config *config)
|
||||||
|
{
|
||||||
|
if (!context) /* called via find_config() from lease_update_from_configs() */
|
||||||
|
return 1;
|
||||||
|
if (!(config->flags & CONFIG_ADDR6))
|
||||||
|
return 1;
|
||||||
|
for (; context; context = context->current)
|
||||||
|
if (is_same_net6(&config->addr6, &context->start6, context->prefix))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct dhcp_config *find_config6(struct dhcp_config *configs,
|
||||||
|
struct dhcp_context *context,
|
||||||
|
unsigned char *duid, int duid_len,
|
||||||
|
char *hostname)
|
||||||
|
{
|
||||||
|
struct dhcp_config *config;
|
||||||
|
|
||||||
|
if (duid)
|
||||||
|
for (config = configs; config; config = config->next)
|
||||||
|
if (config->flags & CONFIG_CLID)
|
||||||
|
{
|
||||||
|
if (config->clid_len == duid_len &&
|
||||||
|
memcmp(config->clid, duid, duid_len) == 0 &&
|
||||||
|
is_addr_in_context6(context, config))
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hostname && context)
|
||||||
|
for (config = configs; config; config = config->next)
|
||||||
|
if ((config->flags & CONFIG_NAME) &&
|
||||||
|
hostname_isequal(config->hostname, hostname) &&
|
||||||
|
is_addr_in_context6(context, config))
|
||||||
|
return config;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void make_duid(time_t now)
|
||||||
|
{
|
||||||
|
if (daemon->duid_config)
|
||||||
|
{
|
||||||
|
unsigned char *p;
|
||||||
|
|
||||||
|
daemon->duid = p = safe_malloc(daemon->duid_config_len + 6);
|
||||||
|
daemon->duid_len = daemon->duid_config_len + 6;
|
||||||
|
PUTSHORT(2, p); /* DUID_EN */
|
||||||
|
PUTLONG(daemon->duid_enterprise, p);
|
||||||
|
memcpy(p, daemon->duid_config, daemon->duid_config_len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* rebase epoch to 1/1/2000 */
|
||||||
|
time_t newnow = now - 946684800;
|
||||||
|
|
||||||
|
iface_enumerate(AF_LOCAL, &newnow, make_duid1);
|
||||||
|
|
||||||
|
if(!daemon->duid)
|
||||||
|
die("Cannot create DHCPv6 server DUID: %s", NULL, EC_MISC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm)
|
||||||
|
{
|
||||||
|
/* create DUID as specified in RFC3315. We use the MAC of the
|
||||||
|
first interface we find that isn't loopback or P-to-P and
|
||||||
|
has address-type < 256. Address types above 256 are things like
|
||||||
|
tunnels which don't have usable MAC addresses. */
|
||||||
|
|
||||||
|
unsigned char *p;
|
||||||
|
(void)index;
|
||||||
|
|
||||||
|
if (type >= 256)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
daemon->duid = p = safe_malloc(maclen + 4);
|
||||||
|
daemon->duid_len = maclen + 4;
|
||||||
|
PUTSHORT(3, p); /* DUID_LL */
|
||||||
|
PUTSHORT(type, p); /* address type */
|
||||||
|
#else
|
||||||
|
daemon->duid = p = safe_malloc(maclen + 8);
|
||||||
|
daemon->duid_len = maclen + 8;
|
||||||
|
PUTSHORT(1, p); /* DUID_LLT */
|
||||||
|
PUTSHORT(type, p); /* address type */
|
||||||
|
PUTLONG(*((time_t *)parm), p); /* time */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memcpy(p, mac, maclen);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 dated June, 1991, or
|
||||||
|
(at your option) version 3 dated 29 June, 2007.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define NAMESERVER_PORT 53
|
||||||
|
#define TFTP_PORT 69
|
||||||
|
|
||||||
|
#define IN6ADDRSZ 16
|
||||||
|
#define INADDRSZ 4
|
||||||
|
|
||||||
|
#define PACKETSZ 512 /* maximum packet size */
|
||||||
|
#define MAXDNAME 1025 /* maximum presentation domain name */
|
||||||
|
#define RRFIXEDSZ 10 /* #/bytes of fixed data in r record */
|
||||||
|
#define MAXLABEL 63 /* maximum length of domain label */
|
||||||
|
|
||||||
|
#define NOERROR 0 /* no error */
|
||||||
|
#define FORMERR 1 /* format error */
|
||||||
|
#define SERVFAIL 2 /* server failure */
|
||||||
|
#define NXDOMAIN 3 /* non existent domain */
|
||||||
|
#define NOTIMP 4 /* not implemented */
|
||||||
|
#define REFUSED 5 /* query refused */
|
||||||
|
|
||||||
|
#define QUERY 0 /* opcode */
|
||||||
|
|
||||||
|
#define C_IN 1 /* the arpa internet */
|
||||||
|
#define C_CHAOS 3 /* for chaos net (MIT) */
|
||||||
|
#define C_ANY 255 /* wildcard match */
|
||||||
|
|
||||||
|
#define T_A 1
|
||||||
|
#define T_NS 2
|
||||||
|
#define T_CNAME 5
|
||||||
|
#define T_SOA 6
|
||||||
|
#define T_PTR 12
|
||||||
|
#define T_MX 15
|
||||||
|
#define T_TXT 16
|
||||||
|
#define T_SIG 24
|
||||||
|
#define T_AAAA 28
|
||||||
|
#define T_SRV 33
|
||||||
|
#define T_NAPTR 35
|
||||||
|
#define T_OPT 41
|
||||||
|
#define T_TKEY 249
|
||||||
|
#define T_TSIG 250
|
||||||
|
#define T_MAILB 253
|
||||||
|
#define T_ANY 255
|
||||||
|
|
||||||
|
struct dns_header {
|
||||||
|
u16 id;
|
||||||
|
u8 hb3,hb4;
|
||||||
|
u16 qdcount,ancount,nscount,arcount;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define HB3_QR 0x80
|
||||||
|
#define HB3_OPCODE 0x78
|
||||||
|
#define HB3_AA 0x04
|
||||||
|
#define HB3_TC 0x02
|
||||||
|
#define HB3_RD 0x01
|
||||||
|
|
||||||
|
#define HB4_RA 0x80
|
||||||
|
#define HB4_AD 0x20
|
||||||
|
#define HB4_CD 0x10
|
||||||
|
#define HB4_RCODE 0x0f
|
||||||
|
|
||||||
|
#define OPCODE(x) (((x)->hb3 & HB3_OPCODE) >> 3)
|
||||||
|
#define RCODE(x) ((x)->hb4 & HB4_RCODE)
|
||||||
|
#define SET_RCODE(x, code) (x)->hb4 = ((x)->hb4 & ~HB4_RCODE) | code
|
||||||
|
|
||||||
|
#define GETSHORT(s, cp) { \
|
||||||
|
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||||
|
(s) = ((u16)t_cp[0] << 8) \
|
||||||
|
| ((u16)t_cp[1]) \
|
||||||
|
; \
|
||||||
|
(cp) += 2; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GETLONG(l, cp) { \
|
||||||
|
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||||
|
(l) = ((u32)t_cp[0] << 24) \
|
||||||
|
| ((u32)t_cp[1] << 16) \
|
||||||
|
| ((u32)t_cp[2] << 8) \
|
||||||
|
| ((u32)t_cp[3]) \
|
||||||
|
; \
|
||||||
|
(cp) += 4; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PUTSHORT(s, cp) { \
|
||||||
|
u16 t_s = (u16)(s); \
|
||||||
|
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||||
|
*t_cp++ = t_s >> 8; \
|
||||||
|
*t_cp = t_s; \
|
||||||
|
(cp) += 2; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PUTLONG(l, cp) { \
|
||||||
|
u32 t_l = (u32)(l); \
|
||||||
|
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||||
|
*t_cp++ = t_l >> 24; \
|
||||||
|
*t_cp++ = t_l >> 16; \
|
||||||
|
*t_cp++ = t_l >> 8; \
|
||||||
|
*t_cp = t_l; \
|
||||||
|
(cp) += 4; \
|
||||||
|
}
|
||||||
|
|
||||||
+366
-136
@@ -1,4 +1,4 @@
|
|||||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -14,47 +14,13 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Declare static char *compiler_opts in config.h */
|
||||||
|
#define DNSMASQ_COMPILE_OPTS
|
||||||
|
|
||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
struct daemon *daemon;
|
struct daemon *daemon;
|
||||||
|
|
||||||
static char *compile_opts =
|
|
||||||
#ifndef HAVE_IPV6
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"IPv6 "
|
|
||||||
#ifndef HAVE_GETOPT_LONG
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"GNU-getopt "
|
|
||||||
#ifdef HAVE_BROKEN_RTC
|
|
||||||
"no-RTC "
|
|
||||||
#endif
|
|
||||||
#ifdef NO_FORK
|
|
||||||
"no-MMU "
|
|
||||||
#endif
|
|
||||||
#ifndef HAVE_DBUS
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"DBus "
|
|
||||||
#ifndef LOCALEDIR
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"I18N "
|
|
||||||
#ifndef HAVE_DHCP
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"DHCP "
|
|
||||||
#if defined(HAVE_DHCP) && !defined(HAVE_SCRIPT)
|
|
||||||
"no-scripts "
|
|
||||||
#endif
|
|
||||||
#ifndef HAVE_TFTP
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"TFTP";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static volatile pid_t pid = 0;
|
static volatile pid_t pid = 0;
|
||||||
static volatile int pipewrite;
|
static volatile int pipewrite;
|
||||||
|
|
||||||
@@ -62,7 +28,8 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
|
|||||||
static void check_dns_listeners(fd_set *set, time_t now);
|
static void check_dns_listeners(fd_set *set, time_t now);
|
||||||
static void sig_handler(int sig);
|
static void sig_handler(int sig);
|
||||||
static void async_event(int pipe, time_t now);
|
static void async_event(int pipe, time_t now);
|
||||||
static void fatal_event(struct event_desc *ev);
|
static void fatal_event(struct event_desc *ev, char *msg);
|
||||||
|
static int read_event(int fd, struct event_desc *evp, char **msg);
|
||||||
|
|
||||||
int main (int argc, char **argv)
|
int main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
@@ -72,7 +39,7 @@ int main (int argc, char **argv)
|
|||||||
struct iname *if_tmp;
|
struct iname *if_tmp;
|
||||||
int piperead, pipefd[2], err_pipe[2];
|
int piperead, pipefd[2], err_pipe[2];
|
||||||
struct passwd *ent_pw = NULL;
|
struct passwd *ent_pw = NULL;
|
||||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
#if defined(HAVE_SCRIPT)
|
||||||
uid_t script_uid = 0;
|
uid_t script_uid = 0;
|
||||||
gid_t script_gid = 0;
|
gid_t script_gid = 0;
|
||||||
#endif
|
#endif
|
||||||
@@ -115,29 +82,38 @@ int main (int argc, char **argv)
|
|||||||
daemon->edns_pktsz : DNSMASQ_PACKETSZ;
|
daemon->edns_pktsz : DNSMASQ_PACKETSZ;
|
||||||
daemon->packet = safe_malloc(daemon->packet_buff_sz);
|
daemon->packet = safe_malloc(daemon->packet_buff_sz);
|
||||||
|
|
||||||
|
daemon->addrbuff = safe_malloc(ADDRSTRLEN);
|
||||||
|
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
if (!daemon->lease_file)
|
if (!daemon->lease_file)
|
||||||
{
|
{
|
||||||
if (daemon->dhcp)
|
if (daemon->dhcp || daemon->dhcp6)
|
||||||
daemon->lease_file = LEASEFILE;
|
daemon->lease_file = LEASEFILE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Close any file descriptors we inherited apart from std{in|out|err} */
|
/* Close any file descriptors we inherited apart from std{in|out|err}
|
||||||
|
|
||||||
|
Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist,
|
||||||
|
otherwise file descriptors we create can end up being 0, 1, or 2
|
||||||
|
and then get accidentally closed later when we make 0, 1, and 2
|
||||||
|
open to /dev/null. Normally we'll be started with 0, 1 and 2 open,
|
||||||
|
but it's not guaranteed. By opening /dev/null three times, we
|
||||||
|
ensure that we're not using those fds for real stuff. */
|
||||||
for (i = 0; i < max_fd; i++)
|
for (i = 0; i < max_fd; i++)
|
||||||
if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
|
if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
|
||||||
close(i);
|
close(i);
|
||||||
|
else
|
||||||
|
open("/dev/null", O_RDWR);
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifndef HAVE_LINUX_NETWORK
|
||||||
netlink_init();
|
# if !(defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
|
||||||
#elif !(defined(IP_RECVDSTADDR) && \
|
|
||||||
defined(IP_RECVIF) && \
|
|
||||||
defined(IP_SENDSRCADDR))
|
|
||||||
if (!option_bool(OPT_NOWILD))
|
if (!option_bool(OPT_NOWILD))
|
||||||
{
|
{
|
||||||
bind_fallback = 1;
|
bind_fallback = 1;
|
||||||
set_option_bool(OPT_NOWILD);
|
set_option_bool(OPT_NOWILD);
|
||||||
}
|
}
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef HAVE_TFTP
|
#ifndef HAVE_TFTP
|
||||||
@@ -145,46 +121,97 @@ int main (int argc, char **argv)
|
|||||||
die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
|
die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_CONNTRACK
|
||||||
|
if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
|
||||||
|
die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
|
||||||
|
#else
|
||||||
|
if (option_bool(OPT_CONNTRACK))
|
||||||
|
die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_SOLARIS_NETWORK
|
#ifdef HAVE_SOLARIS_NETWORK
|
||||||
if (daemon->max_logs != 0)
|
if (daemon->max_logs != 0)
|
||||||
die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
|
die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
if (daemon->max_logs != 0)
|
||||||
|
die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
|
||||||
|
#endif
|
||||||
|
|
||||||
rand_init();
|
rand_init();
|
||||||
|
|
||||||
now = dnsmasq_time();
|
now = dnsmasq_time();
|
||||||
|
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
if (daemon->dhcp)
|
if (daemon->dhcp || daemon->dhcp6)
|
||||||
{
|
{
|
||||||
/* Note that order matters here, we must call lease_init before
|
/* Note that order matters here, we must call lease_init before
|
||||||
creating any file descriptors which shouldn't be leaked
|
creating any file descriptors which shouldn't be leaked
|
||||||
to the lease-script init process. */
|
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);
|
lease_init(now);
|
||||||
dhcp_init();
|
|
||||||
|
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->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->dhcp6)
|
||||||
|
dhcp6_init();
|
||||||
|
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
|
/* After lease_init */
|
||||||
|
netlink_init();
|
||||||
|
#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
|
#endif
|
||||||
|
|
||||||
if (!enumerate_interfaces())
|
if (!enumerate_interfaces())
|
||||||
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
|
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
|
||||||
|
|
||||||
if (option_bool(OPT_NOWILD))
|
if (option_bool(OPT_NOWILD))
|
||||||
{
|
{
|
||||||
daemon->listeners = create_bound_listeners();
|
create_bound_listeners(1);
|
||||||
|
|
||||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||||
if (if_tmp->name && !if_tmp->used)
|
if (if_tmp->name && !if_tmp->used)
|
||||||
die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
|
die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
|
||||||
|
|
||||||
for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
|
|
||||||
if (!if_tmp->used)
|
|
||||||
{
|
|
||||||
prettyprint_addr(&if_tmp->addr, daemon->namebuff);
|
|
||||||
die(_("no interface with address %s"), daemon->namebuff, EC_BADNET);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
daemon->listeners = create_wildcard_listeners();
|
create_wildcard_listeners();
|
||||||
|
|
||||||
if (daemon->port != 0)
|
if (daemon->port != 0)
|
||||||
cache_init();
|
cache_init();
|
||||||
@@ -205,9 +232,11 @@ int main (int argc, char **argv)
|
|||||||
if (daemon->port != 0)
|
if (daemon->port != 0)
|
||||||
pre_allocate_sfds();
|
pre_allocate_sfds();
|
||||||
|
|
||||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
#if defined(HAVE_SCRIPT)
|
||||||
/* Note getpwnam returns static storage */
|
/* Note getpwnam returns static storage */
|
||||||
if (daemon->dhcp && daemon->lease_change_command && daemon->scriptuser)
|
if ((daemon->dhcp || daemon->dhcp6) &&
|
||||||
|
daemon->scriptuser &&
|
||||||
|
(daemon->lease_change_command || daemon->luascript))
|
||||||
{
|
{
|
||||||
if ((ent_pw = getpwnam(daemon->scriptuser)))
|
if ((ent_pw = getpwnam(daemon->scriptuser)))
|
||||||
{
|
{
|
||||||
@@ -270,7 +299,7 @@ int main (int argc, char **argv)
|
|||||||
piperead = pipefd[0];
|
piperead = pipefd[0];
|
||||||
pipewrite = pipefd[1];
|
pipewrite = pipefd[1];
|
||||||
/* prime the pipe to load stuff first time. */
|
/* prime the pipe to load stuff first time. */
|
||||||
send_event(pipewrite, EVENT_RELOAD, 0);
|
send_event(pipewrite, EVENT_RELOAD, 0, NULL);
|
||||||
|
|
||||||
err_pipe[1] = -1;
|
err_pipe[1] = -1;
|
||||||
|
|
||||||
@@ -293,18 +322,19 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
if ((pid = fork()) == -1)
|
if ((pid = fork()) == -1)
|
||||||
/* fd == -1 since we've not forked, never returns. */
|
/* fd == -1 since we've not forked, never returns. */
|
||||||
send_event(-1, EVENT_FORK_ERR, errno);
|
send_event(-1, EVENT_FORK_ERR, errno, NULL);
|
||||||
|
|
||||||
if (pid != 0)
|
if (pid != 0)
|
||||||
{
|
{
|
||||||
struct event_desc ev;
|
struct event_desc ev;
|
||||||
|
char *msg;
|
||||||
|
|
||||||
/* close our copy of write-end */
|
/* close our copy of write-end */
|
||||||
close(err_pipe[1]);
|
close(err_pipe[1]);
|
||||||
|
|
||||||
/* check for errors after the fork */
|
/* check for errors after the fork */
|
||||||
if (read_write(err_pipe[0], (unsigned char *)&ev, sizeof(ev), 1))
|
if (read_event(err_pipe[0], &ev, &msg))
|
||||||
fatal_event(&ev);
|
fatal_event(&ev, msg);
|
||||||
|
|
||||||
_exit(EC_GOOD);
|
_exit(EC_GOOD);
|
||||||
}
|
}
|
||||||
@@ -316,7 +346,7 @@ int main (int argc, char **argv)
|
|||||||
setsid();
|
setsid();
|
||||||
|
|
||||||
if ((pid = fork()) == -1)
|
if ((pid = fork()) == -1)
|
||||||
send_event(err_pipe[1], EVENT_FORK_ERR, errno);
|
send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
|
||||||
|
|
||||||
if (pid != 0)
|
if (pid != 0)
|
||||||
_exit(0);
|
_exit(0);
|
||||||
@@ -336,7 +366,7 @@ int main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
else if (getuid() == 0)
|
else if (getuid() == 0)
|
||||||
{
|
{
|
||||||
send_event(err_pipe[1], EVENT_PIDFILE, errno);
|
send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,8 +386,8 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
/* if we are to run scripts, we need to fork a helper before dropping root. */
|
/* if we are to run scripts, we need to fork a helper before dropping root. */
|
||||||
daemon->helperfd = -1;
|
daemon->helperfd = -1;
|
||||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
#ifdef HAVE_SCRIPT
|
||||||
if (daemon->dhcp && daemon->lease_change_command)
|
if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
|
||||||
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
|
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -371,20 +401,26 @@ int main (int argc, char **argv)
|
|||||||
(setgroups(0, &dummy) == -1 ||
|
(setgroups(0, &dummy) == -1 ||
|
||||||
setgid(gp->gr_gid) == -1))
|
setgid(gp->gr_gid) == -1))
|
||||||
{
|
{
|
||||||
send_event(err_pipe[1], EVENT_GROUP_ERR, errno);
|
send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ent_pw && ent_pw->pw_uid != 0)
|
if (ent_pw && ent_pw->pw_uid != 0)
|
||||||
{
|
{
|
||||||
#if defined(HAVE_LINUX_NETWORK)
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
/* On linux, we keep CAP_NETADMIN (for ARP-injection) and
|
/* On linux, we keep CAP_NETADMIN (for ARP-injection) and
|
||||||
CAP_NET_RAW (for icmp) if we're doing dhcp */
|
CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
|
||||||
data->effective = data->permitted = data->inheritable =
|
ports because of DAD, we need CAP_NET_BIND_SERVICE too. */
|
||||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
|
if (is_dad_listeners())
|
||||||
|
data->effective = data->permitted = data->inheritable =
|
||||||
|
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
|
||||||
|
(1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
|
||||||
|
else
|
||||||
|
data->effective = data->permitted = data->inheritable =
|
||||||
|
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
|
||||||
|
|
||||||
/* Tell kernel to not clear capabilities when dropping root */
|
/* Tell kernel to not clear capabilities when dropping root */
|
||||||
if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1) == -1)
|
if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
|
||||||
bad_capabilities = errno;
|
bad_capabilities = errno;
|
||||||
|
|
||||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||||
@@ -411,26 +447,30 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
if (bad_capabilities != 0)
|
if (bad_capabilities != 0)
|
||||||
{
|
{
|
||||||
send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities);
|
send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* finally drop root */
|
/* finally drop root */
|
||||||
if (setuid(ent_pw->pw_uid) == -1)
|
if (setuid(ent_pw->pw_uid) == -1)
|
||||||
{
|
{
|
||||||
send_event(err_pipe[1], EVENT_USER_ERR, errno);
|
send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
data->effective = data->permitted =
|
if (is_dad_listeners())
|
||||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
|
data->effective = data->permitted =
|
||||||
|
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
|
||||||
|
else
|
||||||
|
data->effective = data->permitted =
|
||||||
|
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
|
||||||
data->inheritable = 0;
|
data->inheritable = 0;
|
||||||
|
|
||||||
/* lose the setuid and setgid capbilities */
|
/* lose the setuid and setgid capbilities */
|
||||||
if (capset(hdr, data) == -1)
|
if (capset(hdr, data) == -1)
|
||||||
{
|
{
|
||||||
send_event(err_pipe[1], EVENT_CAP_ERR, errno);
|
send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -440,7 +480,7 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
if (option_bool(OPT_DEBUG))
|
if (option_bool(OPT_DEBUG))
|
||||||
prctl(PR_SET_DUMPABLE, 1);
|
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (daemon->port == 0)
|
if (daemon->port == 0)
|
||||||
@@ -485,27 +525,92 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
if (daemon->max_logs != 0)
|
if (daemon->max_logs != 0)
|
||||||
my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
|
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
|
#ifdef HAVE_DHCP
|
||||||
if (daemon->dhcp)
|
if (daemon->dhcp || daemon->dhcp6 || daemon->ra_contexts)
|
||||||
{
|
{
|
||||||
struct dhcp_context *dhcp_tmp;
|
struct dhcp_context *dhcp_tmp;
|
||||||
|
int family = AF_INET;
|
||||||
for (dhcp_tmp = daemon->dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
|
dhcp_tmp = daemon->dhcp;
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
again:
|
||||||
|
#endif
|
||||||
|
for (; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
|
||||||
{
|
{
|
||||||
prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time);
|
void *start = &dhcp_tmp->start;
|
||||||
strcpy(daemon->dhcp_buff, inet_ntoa(dhcp_tmp->start));
|
void *end = &dhcp_tmp->end;
|
||||||
my_syslog(MS_DHCP | LOG_INFO,
|
|
||||||
(dhcp_tmp->flags & CONTEXT_STATIC) ?
|
#ifdef HAVE_DHCP6
|
||||||
_("DHCP, static leases only on %.0s%s, lease time %s") :
|
if (family == AF_INET6)
|
||||||
(dhcp_tmp->flags & CONTEXT_PROXY) ?
|
{
|
||||||
_("DHCP, proxy on subnet %.0s%s%.0s") :
|
start = &dhcp_tmp->start6;
|
||||||
_("DHCP, IP range %s -- %s, lease time %s"),
|
end = &dhcp_tmp->end6;
|
||||||
daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), daemon->dhcp_buff2);
|
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);
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_TFTP
|
#ifdef HAVE_TFTP
|
||||||
if (daemon->tftp_unlimited || daemon->tftp_interfaces)
|
if (daemon->tftp_unlimited || daemon->tftp_interfaces)
|
||||||
{
|
{
|
||||||
@@ -585,6 +690,13 @@ int main (int argc, char **argv)
|
|||||||
t.tv_usec = 250000;
|
t.tv_usec = 250000;
|
||||||
tp = &t;
|
tp = &t;
|
||||||
}
|
}
|
||||||
|
/* Wake every second whilst waiting for DAD to complete */
|
||||||
|
else if (is_dad_listeners())
|
||||||
|
{
|
||||||
|
t.tv_sec = 1;
|
||||||
|
t.tv_usec = 0;
|
||||||
|
tp = &t;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_DBUS
|
#ifdef HAVE_DBUS
|
||||||
set_dbus_listeners(&maxfd, &rset, &wset, &eset);
|
set_dbus_listeners(&maxfd, &rset, &wset, &eset);
|
||||||
@@ -603,6 +715,20 @@ int main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (daemon->dhcp6)
|
||||||
|
{
|
||||||
|
FD_SET(daemon->dhcp6fd, &rset);
|
||||||
|
bump_maxfd(daemon->dhcp6fd, &maxfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (daemon->ra_contexts)
|
||||||
|
{
|
||||||
|
FD_SET(daemon->icmp6fd, &rset);
|
||||||
|
bump_maxfd(daemon->icmp6fd, &maxfd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
FD_SET(daemon->netlinkfd, &rset);
|
FD_SET(daemon->netlinkfd, &rset);
|
||||||
bump_maxfd(daemon->netlinkfd, &maxfd);
|
bump_maxfd(daemon->netlinkfd, &maxfd);
|
||||||
@@ -615,6 +741,10 @@ int main (int argc, char **argv)
|
|||||||
# ifdef HAVE_SCRIPT
|
# ifdef HAVE_SCRIPT
|
||||||
while (helper_buf_empty() && do_script_run(now));
|
while (helper_buf_empty() && do_script_run(now));
|
||||||
|
|
||||||
|
# ifdef HAVE_TFTP
|
||||||
|
while (helper_buf_empty() && do_tftp_script_run());
|
||||||
|
# endif
|
||||||
|
|
||||||
if (!helper_buf_empty())
|
if (!helper_buf_empty())
|
||||||
{
|
{
|
||||||
FD_SET(daemon->helperfd, &wset);
|
FD_SET(daemon->helperfd, &wset);
|
||||||
@@ -623,6 +753,11 @@ int main (int argc, char **argv)
|
|||||||
# else
|
# else
|
||||||
/* need this for other side-effects */
|
/* need this for other side-effects */
|
||||||
while (do_script_run(now));
|
while (do_script_run(now));
|
||||||
|
|
||||||
|
# ifdef HAVE_TFTP
|
||||||
|
while (do_tftp_script_run());
|
||||||
|
# endif
|
||||||
|
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -639,6 +774,15 @@ int main (int argc, char **argv)
|
|||||||
now = dnsmasq_time();
|
now = dnsmasq_time();
|
||||||
|
|
||||||
check_log_writer(&wset);
|
check_log_writer(&wset);
|
||||||
|
|
||||||
|
/* Check the interfaces to see if any have exited DAD state
|
||||||
|
and if so, bind the address. */
|
||||||
|
if (is_dad_listeners())
|
||||||
|
{
|
||||||
|
enumerate_interfaces();
|
||||||
|
/* NB, is_dad_listeners() == 1 --> we're binding interfaces */
|
||||||
|
create_bound_listeners(0);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
if (FD_ISSET(daemon->netlinkfd, &rset))
|
if (FD_ISSET(daemon->netlinkfd, &rset))
|
||||||
@@ -689,6 +833,17 @@ int main (int argc, char **argv)
|
|||||||
dhcp_packet(now, 1);
|
dhcp_packet(now, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (daemon->dhcp6)
|
||||||
|
{
|
||||||
|
if (FD_ISSET(daemon->dhcp6fd, &rset))
|
||||||
|
dhcp6_packet(now);
|
||||||
|
|
||||||
|
if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
|
||||||
|
icmp6_packet();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
# ifdef HAVE_SCRIPT
|
# ifdef HAVE_SCRIPT
|
||||||
if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
|
if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
|
||||||
helper_write();
|
helper_write();
|
||||||
@@ -733,28 +888,70 @@ static void sig_handler(int sig)
|
|||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
send_event(pipewrite, event, 0);
|
send_event(pipewrite, event, 0, NULL);
|
||||||
errno = errsave;
|
errno = errsave;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_event(int fd, int event, int data)
|
/* now == 0 -> queue immediate callback */
|
||||||
|
void send_alarm(time_t event, time_t now)
|
||||||
|
{
|
||||||
|
if (now == 0 || event != 0)
|
||||||
|
{
|
||||||
|
/* alarm(0) or alarm(-ve) doesn't do what we want.... */
|
||||||
|
if ((now == 0 || difftime(event, now) <= 0.0))
|
||||||
|
send_event(pipewrite, EVENT_ALARM, 0, NULL);
|
||||||
|
else
|
||||||
|
alarm((unsigned)difftime(event, now));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_event(int fd, int event, int data, char *msg)
|
||||||
{
|
{
|
||||||
struct event_desc ev;
|
struct event_desc ev;
|
||||||
|
struct iovec iov[2];
|
||||||
|
|
||||||
ev.event = event;
|
ev.event = event;
|
||||||
ev.data = data;
|
ev.data = data;
|
||||||
|
ev.msg_sz = msg ? strlen(msg) : 0;
|
||||||
|
|
||||||
|
iov[0].iov_base = &ev;
|
||||||
|
iov[0].iov_len = sizeof(ev);
|
||||||
|
iov[1].iov_base = msg;
|
||||||
|
iov[1].iov_len = ev.msg_sz;
|
||||||
|
|
||||||
/* error pipe, debug mode. */
|
/* error pipe, debug mode. */
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
fatal_event(&ev);
|
fatal_event(&ev, msg);
|
||||||
else
|
else
|
||||||
/* pipe is non-blocking and struct event_desc is smaller than
|
/* pipe is non-blocking and struct event_desc is smaller than
|
||||||
PIPE_BUF, so this either fails or writes everything */
|
PIPE_BUF, so this either fails or writes everything */
|
||||||
while (write(fd, &ev, sizeof(ev)) == -1 && errno == EINTR);
|
while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fatal_event(struct event_desc *ev)
|
/* NOTE: the memory used to return msg is leaked: use msgs in events only
|
||||||
|
to describe fatal errors. */
|
||||||
|
static int read_event(int fd, struct event_desc *evp, char **msg)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*msg = NULL;
|
||||||
|
|
||||||
|
if (evp->msg_sz != 0 &&
|
||||||
|
(buf = malloc(evp->msg_sz + 1)) &&
|
||||||
|
read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
|
||||||
|
{
|
||||||
|
buf[evp->msg_sz] = 0;
|
||||||
|
*msg = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fatal_event(struct event_desc *ev, char *msg)
|
||||||
{
|
{
|
||||||
errno = ev->data;
|
errno = ev->data;
|
||||||
|
|
||||||
@@ -773,19 +970,19 @@ static void fatal_event(struct event_desc *ev)
|
|||||||
die(_("setting capabilities failed: %s"), NULL, EC_MISC);
|
die(_("setting capabilities failed: %s"), NULL, EC_MISC);
|
||||||
|
|
||||||
case EVENT_USER_ERR:
|
case EVENT_USER_ERR:
|
||||||
case EVENT_HUSER_ERR:
|
die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
|
||||||
die(_("failed to change user-id to %s: %s"),
|
|
||||||
ev->event == EVENT_USER_ERR ? daemon->username : daemon->scriptuser,
|
|
||||||
EC_MISC);
|
|
||||||
|
|
||||||
case EVENT_GROUP_ERR:
|
case EVENT_GROUP_ERR:
|
||||||
die(_("failed to change group-id to %s: %s"), daemon->groupname, EC_MISC);
|
die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
|
||||||
|
|
||||||
case EVENT_PIDFILE:
|
case EVENT_PIDFILE:
|
||||||
die(_("failed to open pidfile %s: %s"), daemon->runfile, EC_FILE);
|
die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
|
||||||
|
|
||||||
case EVENT_LOG_ERR:
|
case EVENT_LOG_ERR:
|
||||||
die(_("cannot open %s: %s"), daemon->log_file ? daemon->log_file : "log", EC_FILE);
|
die(_("cannot open log %s: %s"), msg, EC_FILE);
|
||||||
|
|
||||||
|
case EVENT_LUA_ERR:
|
||||||
|
die(_("failed to load Lua script: %s"), msg, EC_MISC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -794,8 +991,12 @@ static void async_event(int pipe, time_t now)
|
|||||||
pid_t p;
|
pid_t p;
|
||||||
struct event_desc ev;
|
struct event_desc ev;
|
||||||
int i;
|
int i;
|
||||||
|
char *msg;
|
||||||
if (read_write(pipe, (unsigned char *)&ev, sizeof(ev), 1))
|
|
||||||
|
/* NOTE: the memory used to return msg is leaked: use msgs in events only
|
||||||
|
to describe fatal errors. */
|
||||||
|
|
||||||
|
if (read_event(pipe, &ev, &msg))
|
||||||
switch (ev.event)
|
switch (ev.event)
|
||||||
{
|
{
|
||||||
case EVENT_RELOAD:
|
case EVENT_RELOAD:
|
||||||
@@ -817,11 +1018,16 @@ static void async_event(int pipe, time_t now)
|
|||||||
|
|
||||||
case EVENT_ALARM:
|
case EVENT_ALARM:
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
if (daemon->dhcp)
|
if (daemon->dhcp || daemon->dhcp6)
|
||||||
{
|
{
|
||||||
lease_prune(NULL, now);
|
lease_prune(NULL, now);
|
||||||
lease_update_file(now);
|
lease_update_file(now);
|
||||||
}
|
}
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
else if (daemon->ra_contexts)
|
||||||
|
/* Not doing DHCP, so no lease system, manage alarms for ra only */
|
||||||
|
send_alarm(periodic_ra(now), now);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -840,11 +1046,11 @@ static void async_event(int pipe, time_t now)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_KILLED:
|
case EVENT_KILLED:
|
||||||
my_syslog(LOG_WARNING, _("child process killed by signal %d"), ev.data);
|
my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_EXITED:
|
case EVENT_EXITED:
|
||||||
my_syslog(LOG_WARNING, _("child process exited with status %d"), ev.data);
|
my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_EXEC_ERR:
|
case EVENT_EXEC_ERR:
|
||||||
@@ -853,9 +1059,10 @@ static void async_event(int pipe, time_t now)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* necessary for fatal errors in helper */
|
/* necessary for fatal errors in helper */
|
||||||
case EVENT_HUSER_ERR:
|
case EVENT_USER_ERR:
|
||||||
case EVENT_DIE:
|
case EVENT_DIE:
|
||||||
fatal_event(&ev);
|
case EVENT_LUA_ERR:
|
||||||
|
fatal_event(&ev, msg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_REOPEN:
|
case EVENT_REOPEN:
|
||||||
@@ -872,7 +1079,7 @@ static void async_event(int pipe, time_t now)
|
|||||||
if (daemon->tcp_pids[i] != 0)
|
if (daemon->tcp_pids[i] != 0)
|
||||||
kill(daemon->tcp_pids[i], SIGALRM);
|
kill(daemon->tcp_pids[i], SIGALRM);
|
||||||
|
|
||||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
#if defined(HAVE_SCRIPT)
|
||||||
/* handle pending lease transitions */
|
/* handle pending lease transitions */
|
||||||
if (daemon->helperfd != -1)
|
if (daemon->helperfd != -1)
|
||||||
{
|
{
|
||||||
@@ -974,7 +1181,7 @@ void clear_cache_and_reload(time_t now)
|
|||||||
cache_reload();
|
cache_reload();
|
||||||
|
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
if (daemon->dhcp)
|
if (daemon->dhcp || daemon->dhcp6)
|
||||||
{
|
{
|
||||||
if (option_bool(OPT_ETHERS))
|
if (option_bool(OPT_ETHERS))
|
||||||
dhcp_read_ethers();
|
dhcp_read_ethers();
|
||||||
@@ -983,8 +1190,18 @@ void clear_cache_and_reload(time_t now)
|
|||||||
check_dhcp_hosts(0);
|
check_dhcp_hosts(0);
|
||||||
lease_update_from_configs();
|
lease_update_from_configs();
|
||||||
lease_update_file(now);
|
lease_update_file(now);
|
||||||
lease_update_dns();
|
lease_update_dns(1);
|
||||||
}
|
}
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
else if (daemon->ra_contexts)
|
||||||
|
{
|
||||||
|
/* Not doing DHCP, so no lease system, manage
|
||||||
|
alarms for ra only */
|
||||||
|
time_t next_event = periodic_ra(now);
|
||||||
|
if (next_event != 0)
|
||||||
|
alarm((unsigned)difftime(next_event, now));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1087,18 +1304,19 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
|||||||
int confd;
|
int confd;
|
||||||
struct irec *iface = NULL;
|
struct irec *iface = NULL;
|
||||||
pid_t p;
|
pid_t p;
|
||||||
|
union mysockaddr tcp_addr;
|
||||||
|
socklen_t tcp_len = sizeof(union mysockaddr);
|
||||||
|
|
||||||
|
while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
|
||||||
|
|
||||||
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;
|
continue;
|
||||||
|
|
||||||
if (option_bool(OPT_NOWILD))
|
if (option_bool(OPT_NOWILD))
|
||||||
iface = listener->iface;
|
iface = listener->iface; /* May be NULL */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
union mysockaddr tcp_addr;
|
|
||||||
socklen_t tcp_len = sizeof(union mysockaddr);
|
|
||||||
/* Check for allowed interfaces when binding the wildcard address:
|
/* Check for allowed interfaces when binding the wildcard address:
|
||||||
we do this by looking for an interface with the same address as
|
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
|
the local address of the TCP connection, then looking to see if that's
|
||||||
@@ -1106,14 +1324,13 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
|||||||
interface too, for localisation. */
|
interface too, for localisation. */
|
||||||
|
|
||||||
/* interface may be new since startup */
|
/* interface may be new since startup */
|
||||||
if (enumerate_interfaces() &&
|
if (enumerate_interfaces())
|
||||||
getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) != -1)
|
|
||||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||||
if (sockaddr_isequal(&iface->addr, &tcp_addr))
|
if (sockaddr_isequal(&iface->addr, &tcp_addr))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!iface)
|
if (!iface && !option_bool(OPT_NOWILD))
|
||||||
{
|
{
|
||||||
shutdown(confd, SHUT_RDWR);
|
shutdown(confd, SHUT_RDWR);
|
||||||
close(confd);
|
close(confd);
|
||||||
@@ -1139,10 +1356,13 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
|||||||
unsigned char *buff;
|
unsigned char *buff;
|
||||||
struct server *s;
|
struct server *s;
|
||||||
int flags;
|
int flags;
|
||||||
struct in_addr dst_addr_4;
|
struct in_addr netmask;
|
||||||
|
|
||||||
dst_addr_4.s_addr = 0;
|
if (iface)
|
||||||
|
netmask = iface->netmask;
|
||||||
|
else
|
||||||
|
netmask.s_addr = 0;
|
||||||
|
|
||||||
#ifndef NO_FORK
|
#ifndef NO_FORK
|
||||||
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to
|
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to
|
||||||
terminate the process. */
|
terminate the process. */
|
||||||
@@ -1160,10 +1380,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
|||||||
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
||||||
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
|
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
|
||||||
|
|
||||||
if (listener->family == AF_INET)
|
buff = tcp_request(confd, now, &tcp_addr, netmask);
|
||||||
dst_addr_4 = iface->addr.in.sin_addr;
|
|
||||||
|
|
||||||
buff = tcp_request(confd, now, dst_addr_4, iface->netmask);
|
|
||||||
|
|
||||||
shutdown(confd, SHUT_RDWR);
|
shutdown(confd, SHUT_RDWR);
|
||||||
close(confd);
|
close(confd);
|
||||||
@@ -1274,7 +1491,15 @@ int icmp_ping(struct in_addr addr)
|
|||||||
FD_SET(fd, &rset);
|
FD_SET(fd, &rset);
|
||||||
set_dns_listeners(now, &rset, &maxfd);
|
set_dns_listeners(now, &rset, &maxfd);
|
||||||
set_log_writer(&wset, &maxfd);
|
set_log_writer(&wset, &maxfd);
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (daemon->ra_contexts)
|
||||||
|
{
|
||||||
|
FD_SET(daemon->icmp6fd, &rset);
|
||||||
|
bump_maxfd(daemon->icmp6fd, &maxfd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
|
if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
|
||||||
{
|
{
|
||||||
FD_ZERO(&rset);
|
FD_ZERO(&rset);
|
||||||
@@ -1286,6 +1511,11 @@ int icmp_ping(struct in_addr addr)
|
|||||||
check_log_writer(&wset);
|
check_log_writer(&wset);
|
||||||
check_dns_listeners(&rset, now);
|
check_dns_listeners(&rset, now);
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
|
||||||
|
icmp6_packet();
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_TFTP
|
#ifdef HAVE_TFTP
|
||||||
check_tftp_listeners(&rset, now);
|
check_tftp_listeners(&rset, now);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+268
-78
@@ -1,4 +1,4 @@
|
|||||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
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/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define COPYRIGHT "Copyright (c) 2000-2011 Simon Kelley"
|
#define COPYRIGHT "Copyright (c) 2000-2012 Simon Kelley"
|
||||||
|
|
||||||
#ifndef NO_LARGEFILE
|
#ifndef NO_LARGEFILE
|
||||||
/* Ensure we can use files >2GB (log files may grow this big) */
|
/* Ensure we can use files >2GB (log files may grow this big) */
|
||||||
@@ -24,7 +24,9 @@
|
|||||||
|
|
||||||
/* Get linux C library versions and define _GNU_SOURCE for kFreeBSD. */
|
/* Get linux C library versions and define _GNU_SOURCE for kFreeBSD. */
|
||||||
#if defined(__linux__) || defined(__GLIBC__)
|
#if defined(__linux__) || defined(__GLIBC__)
|
||||||
# define _GNU_SOURCE
|
# ifndef __ANDROID__
|
||||||
|
# define _GNU_SOURCE
|
||||||
|
# endif
|
||||||
# include <features.h>
|
# include <features.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -37,20 +39,30 @@
|
|||||||
/* get these before config.h for IPv6 stuff... */
|
/* get these before config.h for IPv6 stuff... */
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
# include <nameser.h>
|
/* Define before netinet/in.h to select API. OSX Lion onwards. */
|
||||||
# include <arpa/nameser_compat.h>
|
# define __APPLE_USE_RFC_3542
|
||||||
#else
|
|
||||||
# include <arpa/nameser.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
/* and this. */
|
/* Also needed before config.h. */
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
typedef unsigned char u8;
|
||||||
|
typedef unsigned short u16;
|
||||||
|
typedef unsigned int u32;
|
||||||
|
typedef unsigned long long u64;
|
||||||
|
|
||||||
|
#include "dns-protocol.h"
|
||||||
|
#include "dhcp-protocol.h"
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
#include "dhcp6-protocol.h"
|
||||||
|
#include "radv-protocol.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define gettext_noop(S) (S)
|
#define gettext_noop(S) (S)
|
||||||
#ifndef LOCALEDIR
|
#ifndef LOCALEDIR
|
||||||
# define _(S) (S)
|
# define _(S) (S)
|
||||||
@@ -89,7 +101,7 @@
|
|||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__) || defined (__sun)
|
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__) || defined (__sun) || defined (__ANDROID__)
|
||||||
# include <netinet/if_ether.h>
|
# include <netinet/if_ether.h>
|
||||||
#else
|
#else
|
||||||
# include <net/ethernet.h>
|
# include <net/ethernet.h>
|
||||||
@@ -125,7 +137,7 @@ extern int capget(cap_user_header_t header, cap_user_data_t data);
|
|||||||
|
|
||||||
/* Async event queue */
|
/* Async event queue */
|
||||||
struct event_desc {
|
struct event_desc {
|
||||||
int event, data;
|
int event, data, msg_sz;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define EVENT_RELOAD 1
|
#define EVENT_RELOAD 1
|
||||||
@@ -146,6 +158,7 @@ struct event_desc {
|
|||||||
#define EVENT_DIE 16
|
#define EVENT_DIE 16
|
||||||
#define EVENT_LOG_ERR 17
|
#define EVENT_LOG_ERR 17
|
||||||
#define EVENT_FORK_ERR 18
|
#define EVENT_FORK_ERR 18
|
||||||
|
#define EVENT_LUA_ERR 19
|
||||||
|
|
||||||
/* Exit codes. */
|
/* Exit codes. */
|
||||||
#define EC_GOOD 0
|
#define EC_GOOD 0
|
||||||
@@ -163,7 +176,7 @@ struct event_desc {
|
|||||||
*/
|
*/
|
||||||
#define DNSMASQ_PACKETSZ PACKETSZ+MAXDNAME+RRFIXEDSZ
|
#define DNSMASQ_PACKETSZ PACKETSZ+MAXDNAME+RRFIXEDSZ
|
||||||
|
|
||||||
/* Trust the compiler dead-code elimator.... */
|
/* Trust the compiler dead-code eliminator.... */
|
||||||
#define option_bool(x) (((x) < 32) ? daemon->options & (1u << (x)) : daemon->options2 & (1u << ((x) - 32)))
|
#define option_bool(x) (((x) < 32) ? daemon->options & (1u << (x)) : daemon->options2 & (1u << ((x) - 32)))
|
||||||
|
|
||||||
#define OPT_BOGUSPRIV 0
|
#define OPT_BOGUSPRIV 0
|
||||||
@@ -200,7 +213,11 @@ struct event_desc {
|
|||||||
#define OPT_NO_REBIND 31
|
#define OPT_NO_REBIND 31
|
||||||
#define OPT_ADD_MAC 32
|
#define OPT_ADD_MAC 32
|
||||||
#define OPT_DNSSEC 33
|
#define OPT_DNSSEC 33
|
||||||
#define OPT_LAST 34
|
#define OPT_CONSEC_ADDR 34
|
||||||
|
#define OPT_CONNTRACK 35
|
||||||
|
#define OPT_FQDN_UPDATE 36
|
||||||
|
#define OPT_RA 37
|
||||||
|
#define OPT_LAST 38
|
||||||
|
|
||||||
/* extra flags for my_syslog, we use a couple of facilities since they are known
|
/* extra flags for my_syslog, we use a couple of facilities since they are known
|
||||||
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
|
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
|
||||||
@@ -257,6 +274,18 @@ struct cname {
|
|||||||
struct cname *next;
|
struct cname *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct host_record {
|
||||||
|
struct name_list {
|
||||||
|
char *name;
|
||||||
|
struct name_list *next;
|
||||||
|
} *names;
|
||||||
|
struct in_addr addr;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
struct in6_addr addr6;
|
||||||
|
#endif
|
||||||
|
struct host_record *next;
|
||||||
|
};
|
||||||
|
|
||||||
struct interface_name {
|
struct interface_name {
|
||||||
char *name; /* domain name */
|
char *name; /* domain name */
|
||||||
char *intr; /* interface name */
|
char *intr; /* interface name */
|
||||||
@@ -307,7 +336,6 @@ struct crec {
|
|||||||
#define F_RRNAME (1u<<17)
|
#define F_RRNAME (1u<<17)
|
||||||
#define F_SERVER (1u<<18)
|
#define F_SERVER (1u<<18)
|
||||||
#define F_QUERY (1u<<19)
|
#define F_QUERY (1u<<19)
|
||||||
#define F_NSRR (1u<<20)
|
|
||||||
|
|
||||||
|
|
||||||
/* struct sockaddr is not large enough to hold any address,
|
/* struct sockaddr is not large enough to hold any address,
|
||||||
@@ -360,14 +388,14 @@ struct server {
|
|||||||
struct irec {
|
struct irec {
|
||||||
union mysockaddr addr;
|
union mysockaddr addr;
|
||||||
struct in_addr netmask; /* only valid for IPv4 */
|
struct in_addr netmask; /* only valid for IPv4 */
|
||||||
int tftp_ok, mtu;
|
int tftp_ok, mtu, done, dad;
|
||||||
char *name;
|
char *name;
|
||||||
struct irec *next;
|
struct irec *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct listener {
|
struct listener {
|
||||||
int fd, tcpfd, tftpfd, family;
|
int fd, tcpfd, tftpfd, family;
|
||||||
struct irec *iface; /* only valid for non-wildcard */
|
struct irec *iface; /* only sometimes valid for non-wildcard */
|
||||||
struct listener *next;
|
struct listener *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -416,33 +444,55 @@ struct frec {
|
|||||||
struct frec *next;
|
struct frec *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* flags in top of length field for DHCP-option tables */
|
||||||
|
#define OT_ADDR_LIST 0x8000
|
||||||
|
#define OT_RFC1035_NAME 0x4000
|
||||||
|
#define OT_INTERNAL 0x2000
|
||||||
|
#define OT_NAME 0x1000
|
||||||
|
#define OT_CSTRING 0x0800
|
||||||
|
#define OT_DEC 0x0400
|
||||||
|
|
||||||
|
|
||||||
/* actions in the daemon->helper RPC */
|
/* actions in the daemon->helper RPC */
|
||||||
#define ACTION_DEL 1
|
#define ACTION_DEL 1
|
||||||
#define ACTION_OLD_HOSTNAME 2
|
#define ACTION_OLD_HOSTNAME 2
|
||||||
#define ACTION_OLD 3
|
#define ACTION_OLD 3
|
||||||
#define ACTION_ADD 4
|
#define ACTION_ADD 4
|
||||||
|
#define ACTION_TFTP 5
|
||||||
|
|
||||||
#define DHCP_CHADDR_MAX 16
|
#define LEASE_NEW 1 /* newly created */
|
||||||
|
#define LEASE_CHANGED 2 /* modified */
|
||||||
|
#define LEASE_AUX_CHANGED 4 /* CLID or expiry changed */
|
||||||
|
#define LEASE_AUTH_NAME 8 /* hostname came from config, not from client */
|
||||||
|
#define LEASE_USED 16 /* used this DHCPv6 transaction */
|
||||||
|
#define LEASE_NA 32 /* IPv6 no-temporary lease */
|
||||||
|
#define LEASE_TA 64 /* IPv6 temporary lease */
|
||||||
|
#define LEASE_HAVE_HWADDR 128 /* Have set hwaddress */
|
||||||
|
|
||||||
struct dhcp_lease {
|
struct dhcp_lease {
|
||||||
int clid_len; /* length of client identifier */
|
int clid_len; /* length of client identifier */
|
||||||
unsigned char *clid; /* clientid */
|
unsigned char *clid; /* clientid */
|
||||||
char *hostname, *fqdn; /* name from client-hostname option or config */
|
char *hostname, *fqdn; /* name from client-hostname option or config */
|
||||||
char *old_hostname; /* hostname before it moved to another lease */
|
char *old_hostname; /* hostname before it moved to another lease */
|
||||||
char auth_name; /* hostname came from config, not from client */
|
int flags;
|
||||||
char new; /* newly created */
|
|
||||||
char changed; /* modified */
|
|
||||||
char aux_changed; /* CLID or expiry changed */
|
|
||||||
time_t expires; /* lease expiry */
|
time_t expires; /* lease expiry */
|
||||||
#ifdef HAVE_BROKEN_RTC
|
#ifdef HAVE_BROKEN_RTC
|
||||||
unsigned int length;
|
unsigned int length;
|
||||||
#endif
|
#endif
|
||||||
int hwaddr_len, hwaddr_type;
|
int hwaddr_len, hwaddr_type; /* hw_type used for iaid in v6 */
|
||||||
unsigned char hwaddr[DHCP_CHADDR_MAX];
|
unsigned char hwaddr[DHCP_CHADDR_MAX]; /* also IPv6 address */
|
||||||
struct in_addr addr, override, giaddr;
|
struct in_addr addr, override, giaddr;
|
||||||
unsigned char *extradata;
|
unsigned char *extradata;
|
||||||
unsigned int extradata_len, extradata_size;
|
unsigned int extradata_len, extradata_size;
|
||||||
int last_interface;
|
int last_interface;
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
struct slaac_address {
|
||||||
|
struct in6_addr addr, local;
|
||||||
|
time_t ping_time;
|
||||||
|
int backoff; /* zero -> confirmed */
|
||||||
|
struct slaac_address *next;
|
||||||
|
} *slaac_address;
|
||||||
|
#endif
|
||||||
struct dhcp_lease *next;
|
struct dhcp_lease *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -475,6 +525,9 @@ struct dhcp_config {
|
|||||||
unsigned char *clid; /* clientid */
|
unsigned char *clid; /* clientid */
|
||||||
char *hostname, *domain;
|
char *hostname, *domain;
|
||||||
struct dhcp_netid_list *netid;
|
struct dhcp_netid_list *netid;
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
struct in6_addr addr6;
|
||||||
|
#endif
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
time_t decline_time;
|
time_t decline_time;
|
||||||
unsigned int lease_time;
|
unsigned int lease_time;
|
||||||
@@ -482,6 +535,8 @@ struct dhcp_config {
|
|||||||
struct dhcp_config *next;
|
struct dhcp_config *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
|
||||||
|
|
||||||
#define CONFIG_DISABLE 1
|
#define CONFIG_DISABLE 1
|
||||||
#define CONFIG_CLID 2
|
#define CONFIG_CLID 2
|
||||||
#define CONFIG_TIME 8
|
#define CONFIG_TIME 8
|
||||||
@@ -492,6 +547,7 @@ struct dhcp_config {
|
|||||||
#define CONFIG_ADDR_HOSTS 512 /* address added by from /etc/hosts */
|
#define CONFIG_ADDR_HOSTS 512 /* address added by from /etc/hosts */
|
||||||
#define CONFIG_DECLINED 1024 /* address declined by client */
|
#define CONFIG_DECLINED 1024 /* address declined by client */
|
||||||
#define CONFIG_BANK 2048 /* from dhcp hosts file */
|
#define CONFIG_BANK 2048 /* from dhcp hosts file */
|
||||||
|
#define CONFIG_ADDR6 4096
|
||||||
|
|
||||||
struct dhcp_opt {
|
struct dhcp_opt {
|
||||||
int opt, len, flags;
|
int opt, len, flags;
|
||||||
@@ -517,9 +573,11 @@ struct dhcp_opt {
|
|||||||
#define DHOPT_HEX 512
|
#define DHOPT_HEX 512
|
||||||
#define DHOPT_VENDOR_MATCH 1024
|
#define DHOPT_VENDOR_MATCH 1024
|
||||||
#define DHOPT_RFC3925 2048
|
#define DHOPT_RFC3925 2048
|
||||||
|
#define DHOPT_TAGOK 4096
|
||||||
|
#define DHOPT_ADDR6 8192
|
||||||
|
|
||||||
struct dhcp_boot {
|
struct dhcp_boot {
|
||||||
char *file, *sname;
|
char *file, *sname, *tftp_sname;
|
||||||
struct in_addr next_server;
|
struct in_addr next_server;
|
||||||
struct dhcp_netid *netid;
|
struct dhcp_netid *netid;
|
||||||
struct dhcp_boot *next;
|
struct dhcp_boot *next;
|
||||||
@@ -527,7 +585,7 @@ struct dhcp_boot {
|
|||||||
|
|
||||||
struct pxe_service {
|
struct pxe_service {
|
||||||
unsigned short CSA, type;
|
unsigned short CSA, type;
|
||||||
char *menu, *basename;
|
char *menu, *basename, *sname;
|
||||||
struct in_addr server;
|
struct in_addr server;
|
||||||
struct dhcp_netid *netid;
|
struct dhcp_netid *netid;
|
||||||
struct pxe_service *next;
|
struct pxe_service *next;
|
||||||
@@ -541,7 +599,8 @@ struct pxe_service {
|
|||||||
|
|
||||||
/* vendorclass, userclass, remote-id or cicuit-id */
|
/* vendorclass, userclass, remote-id or cicuit-id */
|
||||||
struct dhcp_vendor {
|
struct dhcp_vendor {
|
||||||
int len, match_type, option;
|
int len, match_type;
|
||||||
|
unsigned int enterprise;
|
||||||
char *data;
|
char *data;
|
||||||
struct dhcp_netid netid;
|
struct dhcp_netid netid;
|
||||||
struct dhcp_vendor *next;
|
struct dhcp_vendor *next;
|
||||||
@@ -563,6 +622,10 @@ struct dhcp_bridge {
|
|||||||
struct cond_domain {
|
struct cond_domain {
|
||||||
char *domain;
|
char *domain;
|
||||||
struct in_addr start, end;
|
struct in_addr start, end;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
struct in6_addr start6, end6;
|
||||||
|
#endif
|
||||||
|
int is6;
|
||||||
struct cond_domain *next;
|
struct cond_domain *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -571,35 +634,33 @@ struct dhcp_context {
|
|||||||
struct in_addr netmask, broadcast;
|
struct in_addr netmask, broadcast;
|
||||||
struct in_addr local, router;
|
struct in_addr local, router;
|
||||||
struct in_addr start, end; /* range of available addresses */
|
struct in_addr start, end; /* range of available addresses */
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
struct in6_addr start6, end6; /* range of available addresses */
|
||||||
|
struct in6_addr local6;
|
||||||
|
int prefix, if_index;
|
||||||
|
time_t ra_time;
|
||||||
|
#endif
|
||||||
int flags;
|
int flags;
|
||||||
char *interface;
|
char *interface;
|
||||||
struct dhcp_netid netid, *filter;
|
struct dhcp_netid netid, *filter;
|
||||||
struct dhcp_context *next, *current;
|
struct dhcp_context *next, *current;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CONTEXT_STATIC 1
|
#define CONTEXT_STATIC 1
|
||||||
#define CONTEXT_NETMASK 2
|
#define CONTEXT_NETMASK 2
|
||||||
#define CONTEXT_BRDCAST 4
|
#define CONTEXT_BRDCAST 4
|
||||||
#define CONTEXT_PROXY 8
|
#define CONTEXT_PROXY 8
|
||||||
|
#define CONTEXT_RA_ONLY 16
|
||||||
|
#define CONTEXT_RA_DONE 32
|
||||||
typedef unsigned char u8;
|
#define CONTEXT_RA_NAME 64
|
||||||
typedef unsigned short u16;
|
#define CONTEXT_RA_STATELESS 128
|
||||||
typedef unsigned int u32;
|
#define CONTEXT_DHCP 256
|
||||||
|
#define CONTEXT_DEPRECATE 512
|
||||||
|
|
||||||
struct dhcp_packet {
|
|
||||||
u8 op, htype, hlen, hops;
|
|
||||||
u32 xid;
|
|
||||||
u16 secs, flags;
|
|
||||||
struct in_addr ciaddr, yiaddr, siaddr, giaddr;
|
|
||||||
u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
|
|
||||||
u8 options[312];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ping_result {
|
struct ping_result {
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
time_t time;
|
time_t time;
|
||||||
|
unsigned int hash;
|
||||||
struct ping_result *next;
|
struct ping_result *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -652,11 +713,13 @@ extern struct daemon {
|
|||||||
struct naptr *naptr;
|
struct naptr *naptr;
|
||||||
struct txt_record *txt;
|
struct txt_record *txt;
|
||||||
struct ptr_record *ptr;
|
struct ptr_record *ptr;
|
||||||
|
struct host_record *host_records, *host_records_tail;
|
||||||
struct cname *cnames;
|
struct cname *cnames;
|
||||||
struct interface_name *int_names;
|
struct interface_name *int_names;
|
||||||
char *mxtarget;
|
char *mxtarget;
|
||||||
char *lease_file;
|
char *lease_file;
|
||||||
char *username, *groupname, *scriptuser;
|
char *username, *groupname, *scriptuser;
|
||||||
|
char *luascript;
|
||||||
int group_set, osport;
|
int group_set, osport;
|
||||||
char *domain_suffix;
|
char *domain_suffix;
|
||||||
struct cond_domain *cond_domain;
|
struct cond_domain *cond_domain;
|
||||||
@@ -672,9 +735,9 @@ extern struct daemon {
|
|||||||
int port, query_port, min_port;
|
int port, query_port, min_port;
|
||||||
unsigned long local_ttl, neg_ttl, max_ttl;
|
unsigned long local_ttl, neg_ttl, max_ttl;
|
||||||
struct hostsfile *addn_hosts;
|
struct hostsfile *addn_hosts;
|
||||||
struct dhcp_context *dhcp;
|
struct dhcp_context *dhcp, *dhcp6, *ra_contexts;
|
||||||
struct dhcp_config *dhcp_conf;
|
struct dhcp_config *dhcp_conf;
|
||||||
struct dhcp_opt *dhcp_opts, *dhcp_match;
|
struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6;
|
||||||
struct dhcp_vendor *dhcp_vendors;
|
struct dhcp_vendor *dhcp_vendors;
|
||||||
struct dhcp_mac *dhcp_macs;
|
struct dhcp_mac *dhcp_macs;
|
||||||
struct dhcp_boot *boot_config;
|
struct dhcp_boot *boot_config;
|
||||||
@@ -696,6 +759,8 @@ extern struct daemon {
|
|||||||
struct tftp_prefix *if_prefix; /* per-interface TFTP prefixes */
|
struct tftp_prefix *if_prefix; /* per-interface TFTP prefixes */
|
||||||
struct interface_list *tftp_interfaces; /* interfaces for limited TFTP service */
|
struct interface_list *tftp_interfaces; /* interfaces for limited TFTP service */
|
||||||
int tftp_unlimited;
|
int tftp_unlimited;
|
||||||
|
unsigned int duid_enterprise, duid_config_len;
|
||||||
|
unsigned char *duid_config;
|
||||||
|
|
||||||
/* globally used stuff for DNS */
|
/* globally used stuff for DNS */
|
||||||
char *packet; /* packet buffer */
|
char *packet; /* packet buffer */
|
||||||
@@ -728,7 +793,12 @@ extern struct daemon {
|
|||||||
struct ping_result *ping_results;
|
struct ping_result *ping_results;
|
||||||
FILE *lease_stream;
|
FILE *lease_stream;
|
||||||
struct dhcp_bridge *bridges;
|
struct dhcp_bridge *bridges;
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
int duid_len;
|
||||||
|
unsigned char *duid;
|
||||||
|
struct iovec outpacket;
|
||||||
|
int dhcp6fd, icmp6fd;
|
||||||
|
#endif
|
||||||
/* DBus stuff */
|
/* DBus stuff */
|
||||||
/* void * here to avoid depending on dbus headers outside dbus.c */
|
/* void * here to avoid depending on dbus headers outside dbus.c */
|
||||||
void *dbus;
|
void *dbus;
|
||||||
@@ -737,7 +807,10 @@ extern struct daemon {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* TFTP stuff */
|
/* TFTP stuff */
|
||||||
struct tftp_transfer *tftp_trans;
|
struct tftp_transfer *tftp_trans, *tftp_done_trans;
|
||||||
|
|
||||||
|
/* utility string buffer, hold max sized IP address as string */
|
||||||
|
char *addrbuff;
|
||||||
|
|
||||||
} *daemon;
|
} *daemon;
|
||||||
|
|
||||||
@@ -756,31 +829,35 @@ void cache_start_insert(void);
|
|||||||
struct crec *cache_insert(char *name, struct all_addr *addr,
|
struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||||
time_t now, unsigned long ttl, unsigned short flags);
|
time_t now, unsigned long ttl, unsigned short flags);
|
||||||
void cache_reload(void);
|
void cache_reload(void);
|
||||||
void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd);
|
void cache_add_dhcp_entry(char *host_name, int prot, struct all_addr *host_address, time_t ttd);
|
||||||
|
struct in_addr a_record_from_hosts(char *name, time_t now);
|
||||||
void cache_unhash_dhcp(void);
|
void cache_unhash_dhcp(void);
|
||||||
void dump_cache(time_t now);
|
void dump_cache(time_t now);
|
||||||
char *cache_get_name(struct crec *crecp);
|
char *cache_get_name(struct crec *crecp);
|
||||||
char *get_domain(struct in_addr addr);
|
char *get_domain(struct in_addr addr);
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
char *get_domain6(struct in6_addr *addr);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* rfc1035.c */
|
/* rfc1035.c */
|
||||||
unsigned int extract_request(HEADER *header, size_t qlen,
|
unsigned int extract_request(struct dns_header *header, size_t qlen,
|
||||||
char *name, unsigned short *typep);
|
char *name, unsigned short *typep);
|
||||||
size_t setup_reply(HEADER *header, size_t qlen,
|
size_t setup_reply(struct dns_header *header, size_t qlen,
|
||||||
struct all_addr *addrp, unsigned int flags,
|
struct all_addr *addrp, unsigned int flags,
|
||||||
unsigned long local_ttl);
|
unsigned long local_ttl);
|
||||||
int extract_addresses(HEADER *header, size_t qlen, char *namebuff,
|
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, int is_sign, int checkrebind, int checking_disabled);
|
||||||
size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
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);
|
struct in_addr local_addr, struct in_addr local_netmask, time_t now);
|
||||||
int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
|
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||||
struct bogus_addr *addr, time_t now);
|
struct bogus_addr *addr, time_t now);
|
||||||
unsigned char *find_pseudoheader(HEADER *header, size_t plen,
|
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
|
||||||
size_t *len, unsigned char **p, int *is_sign);
|
size_t *len, unsigned char **p, int *is_sign);
|
||||||
int check_for_local_domain(char *name, time_t now);
|
int check_for_local_domain(char *name, time_t now);
|
||||||
unsigned int questions_crc(HEADER *header, size_t plen, char *buff);
|
unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
|
||||||
size_t resize_packet(HEADER *header, size_t plen,
|
size_t resize_packet(struct dns_header *header, size_t plen,
|
||||||
unsigned char *pheader, size_t hlen);
|
unsigned char *pheader, size_t hlen);
|
||||||
size_t add_mac(HEADER *header, size_t plen, char *limit, union mysockaddr *l3);
|
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
|
||||||
|
|
||||||
/* util.c */
|
/* util.c */
|
||||||
void rand_init(void);
|
void rand_init(void);
|
||||||
@@ -796,6 +873,11 @@ int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
|
|||||||
int hostname_isequal(char *a, char *b);
|
int hostname_isequal(char *a, char *b);
|
||||||
time_t dnsmasq_time(void);
|
time_t dnsmasq_time(void);
|
||||||
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
|
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen);
|
||||||
|
u64 addr6part(struct in6_addr *addr);
|
||||||
|
void setaddr6part(struct in6_addr *addr, u64 host);
|
||||||
|
#endif
|
||||||
int retry_send(void);
|
int retry_send(void);
|
||||||
void prettyprint_time(char *buf, unsigned int t);
|
void prettyprint_time(char *buf, unsigned int t);
|
||||||
int prettyprint_addr(union mysockaddr *addr, char *buf);
|
int prettyprint_addr(union mysockaddr *addr, char *buf);
|
||||||
@@ -819,7 +901,8 @@ void flush_log(void);
|
|||||||
|
|
||||||
/* option.c */
|
/* option.c */
|
||||||
void read_opts (int argc, char **argv, char *compile_opts);
|
void read_opts (int argc, char **argv, char *compile_opts);
|
||||||
char *option_string(unsigned char opt, int *is_ip, int *is_name);
|
char *option_string(int prot, unsigned int opt, unsigned char *val,
|
||||||
|
int opt_len, char *buf, int buf_len);
|
||||||
void reread_dhcp(void);
|
void reread_dhcp(void);
|
||||||
void set_option_bool(unsigned int opt);
|
void set_option_bool(unsigned int opt);
|
||||||
struct hostsfile *expand_filelist(struct hostsfile *list);
|
struct hostsfile *expand_filelist(struct hostsfile *list);
|
||||||
@@ -828,9 +911,12 @@ struct hostsfile *expand_filelist(struct hostsfile *list);
|
|||||||
void reply_query(int fd, int family, time_t now);
|
void reply_query(int fd, int family, time_t now);
|
||||||
void receive_query(struct listener *listen, time_t now);
|
void receive_query(struct listener *listen, time_t now);
|
||||||
unsigned char *tcp_request(int confd, time_t now,
|
unsigned char *tcp_request(int confd, time_t now,
|
||||||
struct in_addr local_addr, struct in_addr netmask);
|
union mysockaddr *local_addr, struct in_addr netmask);
|
||||||
void server_gone(struct server *server);
|
void server_gone(struct server *server);
|
||||||
struct frec *get_new_frec(time_t now, int *wait);
|
struct frec *get_new_frec(time_t now, int *wait);
|
||||||
|
int send_from(int fd, int nowild, char *packet, size_t len,
|
||||||
|
union mysockaddr *to, struct all_addr *source,
|
||||||
|
unsigned int iface, int *errp);
|
||||||
|
|
||||||
/* network.c */
|
/* network.c */
|
||||||
int indextoname(int fd, int index, char *name);
|
int indextoname(int fd, int index, char *name);
|
||||||
@@ -840,11 +926,15 @@ void pre_allocate_sfds(void);
|
|||||||
int reload_servers(char *fname);
|
int reload_servers(char *fname);
|
||||||
void check_servers(void);
|
void check_servers(void);
|
||||||
int enumerate_interfaces();
|
int enumerate_interfaces();
|
||||||
struct listener *create_wildcard_listeners(void);
|
void create_wildcard_listeners(void);
|
||||||
struct listener *create_bound_listeners(void);
|
void create_bound_listeners(int die);
|
||||||
int iface_check(int family, struct all_addr *addr, char *name, int *indexp);
|
int is_dad_listeners(void);
|
||||||
|
int iface_check(int family, struct all_addr *addr, char *name);
|
||||||
int fix_fd(int fd);
|
int fix_fd(int fd);
|
||||||
struct in_addr get_ifaddr(char *intr);
|
struct in_addr get_ifaddr(char *intr);
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
int set_ipv6pktinfo(int fd);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* dhcp.c */
|
/* dhcp.c */
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
@@ -856,50 +946,58 @@ struct dhcp_context *address_available(struct dhcp_context *context,
|
|||||||
struct dhcp_context *narrow_context(struct dhcp_context *context,
|
struct dhcp_context *narrow_context(struct dhcp_context *context,
|
||||||
struct in_addr taddr,
|
struct in_addr taddr,
|
||||||
struct dhcp_netid *netids);
|
struct dhcp_netid *netids);
|
||||||
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly);
|
|
||||||
int address_allocate(struct dhcp_context *context,
|
int address_allocate(struct dhcp_context *context,
|
||||||
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
|
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
|
||||||
struct dhcp_netid *netids, time_t now);
|
struct dhcp_netid *netids, time_t now);
|
||||||
struct dhcp_netid *run_tag_if(struct dhcp_netid *input);
|
|
||||||
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
|
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
|
||||||
struct dhcp_config *find_config(struct dhcp_config *configs,
|
struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||||
struct dhcp_context *context,
|
struct dhcp_context *context,
|
||||||
unsigned char *clid, int clid_len,
|
unsigned char *clid, int clid_len,
|
||||||
unsigned char *hwaddr, int hw_len,
|
unsigned char *hwaddr, int hw_len,
|
||||||
int hw_type, char *hostname);
|
int hw_type, char *hostname);
|
||||||
void dhcp_update_configs(struct dhcp_config *configs);
|
|
||||||
void dhcp_read_ethers(void);
|
void dhcp_read_ethers(void);
|
||||||
void check_dhcp_hosts(int fatal);
|
|
||||||
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
|
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
|
||||||
char *strip_hostname(char *hostname);
|
|
||||||
char *host_from_dns(struct in_addr addr);
|
char *host_from_dns(struct in_addr addr);
|
||||||
char *get_domain(struct in_addr addr);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* lease.c */
|
/* lease.c */
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
void lease_update_file(time_t now);
|
void lease_update_file(time_t now);
|
||||||
void lease_update_dns();
|
void lease_update_dns(int force);
|
||||||
void lease_init(time_t now);
|
void lease_init(time_t now);
|
||||||
struct dhcp_lease *lease_allocate(struct in_addr addr);
|
struct dhcp_lease *lease4_allocate(struct in_addr addr);
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type);
|
||||||
|
struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
|
||||||
|
int lease_type, int iaid, struct in6_addr *addr);
|
||||||
|
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);
|
||||||
|
#endif
|
||||||
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||||
unsigned char *clid, int hw_len, int hw_type, int clid_len);
|
unsigned char *clid, int hw_len, int hw_type, int clid_len, time_t now);
|
||||||
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth);
|
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain);
|
||||||
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now);
|
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now);
|
||||||
void lease_set_interface(struct dhcp_lease *lease, int interface);
|
void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now);
|
||||||
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
|
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
|
||||||
unsigned char *clid, int clid_len);
|
unsigned char *clid, int clid_len);
|
||||||
struct dhcp_lease *lease_find_by_addr(struct in_addr addr);
|
struct dhcp_lease *lease_find_by_addr(struct in_addr addr);
|
||||||
|
struct in_addr lease_find_max_addr(struct dhcp_context *context);
|
||||||
void lease_prune(struct dhcp_lease *target, time_t now);
|
void lease_prune(struct dhcp_lease *target, time_t now);
|
||||||
void lease_update_from_configs(void);
|
void lease_update_from_configs(void);
|
||||||
int do_script_run(time_t now);
|
int do_script_run(time_t now);
|
||||||
void rerun_scripts(void);
|
void rerun_scripts(void);
|
||||||
|
void lease_find_interfaces(time_t now);
|
||||||
|
#ifdef HAVE_SCRIPT
|
||||||
|
void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data,
|
||||||
|
unsigned int len, int delim);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* rfc2131.c */
|
/* rfc2131.c */
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||||
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe_fd);
|
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe_fd, struct in_addr fallback);
|
||||||
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
|
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
|
||||||
int clid_len, unsigned char *clid, int *len_out);
|
int clid_len, unsigned char *clid, int *len_out);
|
||||||
#endif
|
#endif
|
||||||
@@ -909,7 +1007,8 @@ unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
|
|||||||
int make_icmp_sock(void);
|
int make_icmp_sock(void);
|
||||||
int icmp_ping(struct in_addr addr);
|
int icmp_ping(struct in_addr addr);
|
||||||
#endif
|
#endif
|
||||||
void send_event(int fd, int event, int data);
|
void send_alarm(time_t event, time_t now);
|
||||||
|
void send_event(int fd, int event, int data, char *msg);
|
||||||
void clear_cache_and_reload(time_t now);
|
void clear_cache_and_reload(time_t now);
|
||||||
void poll_resolv(int force, int do_reload, time_t now);
|
void poll_resolv(int force, int do_reload, time_t now);
|
||||||
|
|
||||||
@@ -940,11 +1039,14 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* helper.c */
|
/* helper.c */
|
||||||
#if defined(HAVE_DHCP) && !defined(NO_FORK)
|
#if defined(HAVE_SCRIPT)
|
||||||
int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd);
|
int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd);
|
||||||
void helper_write(void);
|
void helper_write(void);
|
||||||
void queue_script(int action, struct dhcp_lease *lease,
|
void queue_script(int action, struct dhcp_lease *lease,
|
||||||
char *hostname, time_t now);
|
char *hostname, time_t now);
|
||||||
|
#ifdef HAVE_TFTP
|
||||||
|
void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer);
|
||||||
|
#endif
|
||||||
int helper_buf_empty(void);
|
int helper_buf_empty(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -952,4 +1054,92 @@ int helper_buf_empty(void);
|
|||||||
#ifdef HAVE_TFTP
|
#ifdef HAVE_TFTP
|
||||||
void tftp_request(struct listener *listen, time_t now);
|
void tftp_request(struct listener *listen, time_t now);
|
||||||
void check_tftp_listeners(fd_set *rset, time_t now);
|
void check_tftp_listeners(fd_set *rset, time_t now);
|
||||||
|
int do_tftp_script_run(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* conntrack.c */
|
||||||
|
#ifdef HAVE_CONNTRACK
|
||||||
|
int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
|
||||||
|
int istcp, unsigned int *markp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* dhcp6.c */
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
void dhcp6_init(void);
|
||||||
|
void dhcp6_packet(time_t now);
|
||||||
|
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_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_config *find_config6(struct dhcp_config *configs,
|
||||||
|
struct dhcp_context *context,
|
||||||
|
unsigned char *duid, int duid_len,
|
||||||
|
char *hostname);
|
||||||
|
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);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* rfc3315.c */
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
|
||||||
|
struct in6_addr *fallback, size_t sz, int is_multicast, time_t now);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* dhcp-common.c */
|
||||||
|
#ifdef HAVE_DHCP
|
||||||
|
void dhcp_common_init(void);
|
||||||
|
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg);
|
||||||
|
struct dhcp_netid *run_tag_if(struct dhcp_netid *input);
|
||||||
|
struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *context_tags,
|
||||||
|
struct dhcp_opt *opts);
|
||||||
|
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly);
|
||||||
|
char *strip_hostname(char *hostname);
|
||||||
|
void log_tags(struct dhcp_netid *netid, u32 xid);
|
||||||
|
int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
|
||||||
|
void dhcp_update_configs(struct dhcp_config *configs);
|
||||||
|
void check_dhcp_hosts(int fatal);
|
||||||
|
void display_opts(void);
|
||||||
|
u16 lookup_dhcp_opt(int prot, char *name);
|
||||||
|
u16 lookup_dhcp_len(int prot, u16 val);
|
||||||
|
char *option_string(int prot, unsigned int opt, unsigned char *val,
|
||||||
|
int opt_len, char *buf, int buf_len);
|
||||||
|
# ifdef HAVE_DHCP6
|
||||||
|
void display_opts6(void);
|
||||||
|
void join_multicast(void);
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* outpacket.c */
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
void end_opt6(int container);
|
||||||
|
int save_counter(int newval);
|
||||||
|
void *expand(size_t headroom);
|
||||||
|
int new_opt6(int opt);
|
||||||
|
void *put_opt6(void *data, size_t len);
|
||||||
|
void put_opt6_long(unsigned int val);
|
||||||
|
void put_opt6_short(unsigned int val);
|
||||||
|
void put_opt6_char(unsigned int val);
|
||||||
|
void put_opt6_string(char *s);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* radv.c */
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
void ra_init(time_t now);
|
||||||
|
void icmp6_packet(void);
|
||||||
|
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);
|
||||||
|
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
|
#endif
|
||||||
+149
-90
@@ -1,4 +1,4 @@
|
|||||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -26,9 +26,9 @@ static struct randfd *allocate_rfd(int family);
|
|||||||
|
|
||||||
/* Send a UDP packet with its source address set as "source"
|
/* Send a UDP packet with its source address set as "source"
|
||||||
unless nowild is true, when we just send it with the kernel default */
|
unless nowild is true, when we just send it with the kernel default */
|
||||||
static void send_from(int fd, int nowild, char *packet, size_t len,
|
int send_from(int fd, int nowild, char *packet, size_t len,
|
||||||
union mysockaddr *to, struct all_addr *source,
|
union mysockaddr *to, struct all_addr *source,
|
||||||
unsigned int iface)
|
unsigned int iface, int *errp)
|
||||||
{
|
{
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
struct iovec iov[1];
|
struct iovec iov[1];
|
||||||
@@ -70,7 +70,7 @@ static void send_from(int fd, int nowild, char *packet, size_t len,
|
|||||||
p.ipi_spec_dst = source->addr.addr4;
|
p.ipi_spec_dst = source->addr.addr4;
|
||||||
memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
|
memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
|
||||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||||
cmptr->cmsg_level = SOL_IP;
|
cmptr->cmsg_level = IPPROTO_IP;
|
||||||
cmptr->cmsg_type = IP_PKTINFO;
|
cmptr->cmsg_type = IP_PKTINFO;
|
||||||
#elif defined(IP_SENDSRCADDR)
|
#elif defined(IP_SENDSRCADDR)
|
||||||
memcpy(CMSG_DATA(cmptr), &(source->addr.addr4), sizeof(source->addr.addr4));
|
memcpy(CMSG_DATA(cmptr), &(source->addr.addr4), sizeof(source->addr.addr4));
|
||||||
@@ -88,10 +88,10 @@ static void send_from(int fd, int nowild, char *packet, size_t len,
|
|||||||
memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
|
memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
|
||||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
||||||
cmptr->cmsg_type = daemon->v6pktinfo;
|
cmptr->cmsg_type = daemon->v6pktinfo;
|
||||||
cmptr->cmsg_level = IPV6_LEVEL;
|
cmptr->cmsg_level = IPPROTO_IPV6;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
iface = 0; /* eliminate warning */
|
(void)iface; /* eliminate warning */
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,9 +106,19 @@ static void send_from(int fd, int nowild, char *packet, size_t len,
|
|||||||
msg.msg_controllen = 0;
|
msg.msg_controllen = 0;
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retry_send())
|
if (retry_send())
|
||||||
goto retry;
|
goto retry;
|
||||||
|
|
||||||
|
if (errp)
|
||||||
|
*errp = errno;
|
||||||
|
else
|
||||||
|
my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno));
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int search_servers(time_t now, struct all_addr **addrpp,
|
static unsigned int search_servers(time_t now, struct all_addr **addrpp,
|
||||||
@@ -207,10 +217,10 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags == 0 && !(qtype & F_NSRR) &&
|
if (flags == 0 && !(qtype & F_QUERY) &&
|
||||||
option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
|
option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
|
||||||
/* don't forward simple names, make exception for NS queries and empty name. */
|
/* don't forward A or AAAA queries for simple names, except the empty name */
|
||||||
flags = F_NXDOMAIN;
|
flags = F_NOERR;
|
||||||
|
|
||||||
if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
|
if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
|
||||||
flags = F_NOERR;
|
flags = F_NOERR;
|
||||||
@@ -234,7 +244,7 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp,
|
|||||||
|
|
||||||
static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||||
struct all_addr *dst_addr, unsigned int dst_iface,
|
struct all_addr *dst_addr, unsigned int dst_iface,
|
||||||
HEADER *header, size_t plen, time_t now, struct frec *forward)
|
struct dns_header *header, size_t plen, time_t now, struct frec *forward)
|
||||||
{
|
{
|
||||||
char *domain = NULL;
|
char *domain = NULL;
|
||||||
int type = 0, norebind = 0;
|
int type = 0, norebind = 0;
|
||||||
@@ -243,10 +253,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
unsigned int flags = 0;
|
unsigned int flags = 0;
|
||||||
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||||
struct server *start = NULL;
|
struct server *start = NULL;
|
||||||
|
|
||||||
/* RFC 4035: sect 4.6 para 2 */
|
/* RFC 4035: sect 4.6 para 2 */
|
||||||
header->ad = 0;
|
header->hb4 &= ~HB4_AD;
|
||||||
|
|
||||||
/* may be no servers available. */
|
/* may be no servers available. */
|
||||||
if (!daemon->servers)
|
if (!daemon->servers)
|
||||||
forward = NULL;
|
forward = NULL;
|
||||||
@@ -286,7 +296,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
forward->forwardall = 0;
|
forward->forwardall = 0;
|
||||||
if (norebind)
|
if (norebind)
|
||||||
forward->flags |= FREC_NOREBIND;
|
forward->flags |= FREC_NOREBIND;
|
||||||
if (header->cd)
|
if (header->hb4 & HB4_CD)
|
||||||
forward->flags |= FREC_CHECKING_DISABLED;
|
forward->flags |= FREC_CHECKING_DISABLED;
|
||||||
|
|
||||||
header->id = htons(forward->new_id);
|
header->id = htons(forward->new_id);
|
||||||
@@ -366,6 +376,16 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
daemon->rfd_save = forward->rfd4;
|
daemon->rfd_save = forward->rfd4;
|
||||||
fd = forward->rfd4->fd;
|
fd = forward->rfd4->fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_CONNTRACK
|
||||||
|
/* Copy connection mark of incoming query to outgoing connection. */
|
||||||
|
if (option_bool(OPT_CONNTRACK))
|
||||||
|
{
|
||||||
|
unsigned int mark;
|
||||||
|
if (get_incoming_mark(udpaddr, dst_addr, 0, &mark))
|
||||||
|
setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sendto(fd, (char *)header, plen, 0,
|
if (sendto(fd, (char *)header, plen, 0,
|
||||||
@@ -419,13 +439,13 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
if (udpfd != -1)
|
if (udpfd != -1)
|
||||||
{
|
{
|
||||||
plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
|
plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
|
||||||
send_from(udpfd, option_bool(OPT_NOWILD), (char *)header, plen, udpaddr, dst_addr, dst_iface);
|
send_from(udpfd, option_bool(OPT_NOWILD), (char *)header, plen, udpaddr, dst_addr, dst_iface, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t process_reply(HEADER *header, time_t now,
|
static size_t process_reply(struct dns_header *header, time_t now,
|
||||||
struct server *server, size_t n, int check_rebind, int checking_disabled)
|
struct server *server, size_t n, int check_rebind, int checking_disabled)
|
||||||
{
|
{
|
||||||
unsigned char *pheader, *sizep;
|
unsigned char *pheader, *sizep;
|
||||||
@@ -448,13 +468,13 @@ static size_t process_reply(HEADER *header, time_t now,
|
|||||||
|
|
||||||
/* RFC 4035 sect 4.6 para 3 */
|
/* RFC 4035 sect 4.6 para 3 */
|
||||||
if (!is_sign && !option_bool(OPT_DNSSEC))
|
if (!is_sign && !option_bool(OPT_DNSSEC))
|
||||||
header->ad = 0;
|
header->hb4 &= ~HB4_AD;
|
||||||
|
|
||||||
if (header->opcode != QUERY || (header->rcode != NOERROR && header->rcode != NXDOMAIN))
|
if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN))
|
||||||
return n;
|
return n;
|
||||||
|
|
||||||
/* Complain loudly if the upstream server is non-recursive. */
|
/* Complain loudly if the upstream server is non-recursive. */
|
||||||
if (!header->ra && header->rcode == NOERROR && ntohs(header->ancount) == 0 &&
|
if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR && ntohs(header->ancount) == 0 &&
|
||||||
server && !(server->flags & SERV_WARNED_RECURSIVE))
|
server && !(server->flags & SERV_WARNED_RECURSIVE))
|
||||||
{
|
{
|
||||||
prettyprint_addr(&server->addr, daemon->namebuff);
|
prettyprint_addr(&server->addr, daemon->namebuff);
|
||||||
@@ -463,16 +483,16 @@ static size_t process_reply(HEADER *header, time_t now,
|
|||||||
server->flags |= SERV_WARNED_RECURSIVE;
|
server->flags |= SERV_WARNED_RECURSIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (daemon->bogus_addr && header->rcode != NXDOMAIN &&
|
if (daemon->bogus_addr && RCODE(header) != NXDOMAIN &&
|
||||||
check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
|
check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
|
||||||
{
|
{
|
||||||
munged = 1;
|
munged = 1;
|
||||||
header->rcode = NXDOMAIN;
|
SET_RCODE(header, NXDOMAIN);
|
||||||
header->aa = 0;
|
header->hb3 &= ~HB3_AA;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (header->rcode == NXDOMAIN &&
|
if (RCODE(header) == NXDOMAIN &&
|
||||||
extract_request(header, n, daemon->namebuff, NULL) &&
|
extract_request(header, n, daemon->namebuff, NULL) &&
|
||||||
check_for_local_domain(daemon->namebuff, now))
|
check_for_local_domain(daemon->namebuff, now))
|
||||||
{
|
{
|
||||||
@@ -480,8 +500,8 @@ static size_t process_reply(HEADER *header, time_t now,
|
|||||||
an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
|
an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
|
||||||
since we know that the domain exists, even if upstream doesn't */
|
since we know that the domain exists, even if upstream doesn't */
|
||||||
munged = 1;
|
munged = 1;
|
||||||
header->aa = 1;
|
header->hb3 |= HB3_AA;
|
||||||
header->rcode = NOERROR;
|
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, is_sign, check_rebind, checking_disabled))
|
||||||
@@ -512,7 +532,7 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
{
|
{
|
||||||
/* packet from peer server, extract data for cache, and send to
|
/* packet from peer server, extract data for cache, and send to
|
||||||
original requester */
|
original requester */
|
||||||
HEADER *header;
|
struct dns_header *header;
|
||||||
union mysockaddr serveraddr;
|
union mysockaddr serveraddr;
|
||||||
struct frec *forward;
|
struct frec *forward;
|
||||||
socklen_t addrlen = sizeof(serveraddr);
|
socklen_t addrlen = sizeof(serveraddr);
|
||||||
@@ -536,16 +556,16 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
sockaddr_isequal(&server->addr, &serveraddr))
|
sockaddr_isequal(&server->addr, &serveraddr))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
header = (HEADER *)daemon->packet;
|
header = (struct dns_header *)daemon->packet;
|
||||||
|
|
||||||
if (!server ||
|
if (!server ||
|
||||||
n < (int)sizeof(HEADER) || !header->qr ||
|
n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR) ||
|
||||||
!(forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff))))
|
!(forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff))))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
server = forward->sentto;
|
server = forward->sentto;
|
||||||
|
|
||||||
if ((header->rcode == SERVFAIL || header->rcode == REFUSED) &&
|
if ((RCODE(header) == SERVFAIL || RCODE(header) == REFUSED) &&
|
||||||
!option_bool(OPT_ORDER) &&
|
!option_bool(OPT_ORDER) &&
|
||||||
forward->forwardall == 0)
|
forward->forwardall == 0)
|
||||||
/* for broken servers, attempt to send to another one. */
|
/* for broken servers, attempt to send to another one. */
|
||||||
@@ -563,8 +583,7 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
header->arcount = htons(0);
|
header->arcount = htons(0);
|
||||||
if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
|
if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
|
||||||
{
|
{
|
||||||
header->qr = 0;
|
header->hb3 &= ~(HB3_QR | HB3_TC);
|
||||||
header->tc = 0;
|
|
||||||
forward_query(-1, NULL, NULL, 0, header, nn, now, forward);
|
forward_query(-1, NULL, NULL, 0, header, nn, now, forward);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -573,7 +592,7 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
|
|
||||||
if ((forward->sentto->flags & SERV_TYPE) == 0)
|
if ((forward->sentto->flags & SERV_TYPE) == 0)
|
||||||
{
|
{
|
||||||
if (header->rcode == SERVFAIL || header->rcode == REFUSED)
|
if (RCODE(header) == SERVFAIL || RCODE(header) == REFUSED)
|
||||||
server = NULL;
|
server = NULL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -597,7 +616,7 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
had replies from all to avoid filling the forwarding table when
|
had replies from all to avoid filling the forwarding table when
|
||||||
everything is broken */
|
everything is broken */
|
||||||
if (forward->forwardall == 0 || --forward->forwardall == 1 ||
|
if (forward->forwardall == 0 || --forward->forwardall == 1 ||
|
||||||
(header->rcode != REFUSED && header->rcode != SERVFAIL))
|
(RCODE(header) != REFUSED && RCODE(header) != SERVFAIL))
|
||||||
{
|
{
|
||||||
int check_rebind = !(forward->flags & FREC_NOREBIND);
|
int check_rebind = !(forward->flags & FREC_NOREBIND);
|
||||||
|
|
||||||
@@ -607,9 +626,9 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, forward->flags & FREC_CHECKING_DISABLED)))
|
if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, forward->flags & FREC_CHECKING_DISABLED)))
|
||||||
{
|
{
|
||||||
header->id = htons(forward->orig_id);
|
header->id = htons(forward->orig_id);
|
||||||
header->ra = 1; /* recursion if available */
|
header->hb4 |= HB4_RA; /* recursion if available */
|
||||||
send_from(forward->fd, option_bool(OPT_NOWILD), daemon->packet, nn,
|
send_from(forward->fd, option_bool(OPT_NOWILD), daemon->packet, nn,
|
||||||
&forward->source, &forward->dest, forward->iface);
|
&forward->source, &forward->dest, forward->iface, NULL);
|
||||||
}
|
}
|
||||||
free_frec(forward); /* cancel */
|
free_frec(forward); /* cancel */
|
||||||
}
|
}
|
||||||
@@ -618,7 +637,7 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
|
|
||||||
void receive_query(struct listener *listen, time_t now)
|
void receive_query(struct listener *listen, time_t now)
|
||||||
{
|
{
|
||||||
HEADER *header = (HEADER *)daemon->packet;
|
struct dns_header *header = (struct dns_header *)daemon->packet;
|
||||||
union mysockaddr source_addr;
|
union mysockaddr source_addr;
|
||||||
unsigned short type;
|
unsigned short type;
|
||||||
struct all_addr dst_addr;
|
struct all_addr dst_addr;
|
||||||
@@ -648,7 +667,7 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
/* packet buffer overwritten */
|
/* packet buffer overwritten */
|
||||||
daemon->srv_save = NULL;
|
daemon->srv_save = NULL;
|
||||||
|
|
||||||
if (listen->family == AF_INET && option_bool(OPT_NOWILD))
|
if (listen->iface && listen->family == AF_INET && option_bool(OPT_NOWILD))
|
||||||
{
|
{
|
||||||
dst_addr_4 = listen->iface->addr.in.sin_addr;
|
dst_addr_4 = listen->iface->addr.in.sin_addr;
|
||||||
netmask = listen->iface->netmask;
|
netmask = listen->iface->netmask;
|
||||||
@@ -673,9 +692,9 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
|
if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (n < (int)sizeof(HEADER) ||
|
if (n < (int)sizeof(struct dns_header) ||
|
||||||
(msg.msg_flags & MSG_TRUNC) ||
|
(msg.msg_flags & MSG_TRUNC) ||
|
||||||
header->qr)
|
(header->hb3 & HB3_QR))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
source_addr.sa.sa_family = listen->family;
|
source_addr.sa.sa_family = listen->family;
|
||||||
@@ -694,7 +713,7 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
#if defined(HAVE_LINUX_NETWORK)
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
if (listen->family == AF_INET)
|
if (listen->family == AF_INET)
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
unsigned char *c;
|
unsigned char *c;
|
||||||
@@ -734,7 +753,7 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
if (listen->family == AF_INET6)
|
if (listen->family == AF_INET6)
|
||||||
{
|
{
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == daemon->v6pktinfo)
|
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
unsigned char *c;
|
unsigned char *c;
|
||||||
@@ -751,15 +770,36 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
/* enforce available interface configuration */
|
/* enforce available interface configuration */
|
||||||
|
|
||||||
if (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
|
if (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
|
||||||
!iface_check(listen->family, &dst_addr, ifr.ifr_name, &if_index))
|
!iface_check(listen->family, &dst_addr, ifr.ifr_name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (listen->family == AF_INET &&
|
if (listen->family == AF_INET && option_bool(OPT_LOCALISE))
|
||||||
option_bool(OPT_LOCALISE) &&
|
{
|
||||||
ioctl(listen->fd, SIOCGIFNETMASK, &ifr) == -1)
|
struct irec *iface;
|
||||||
return;
|
|
||||||
|
/* get the netmask of the interface whch has the address we were sent to.
|
||||||
netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
This is no neccessarily the interface we arrived on. */
|
||||||
|
|
||||||
|
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||||
|
if (iface->addr.sa.sa_family == AF_INET &&
|
||||||
|
iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* interface may be new */
|
||||||
|
if (!iface)
|
||||||
|
enumerate_interfaces();
|
||||||
|
|
||||||
|
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||||
|
if (iface->addr.sa.sa_family == AF_INET &&
|
||||||
|
iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* If we failed, abandon localisation */
|
||||||
|
if (iface)
|
||||||
|
netmask = iface->netmask;
|
||||||
|
else
|
||||||
|
dst_addr_4.s_addr = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extract_request(header, (size_t)n, daemon->namebuff, &type))
|
if (extract_request(header, (size_t)n, daemon->namebuff, &type))
|
||||||
@@ -783,7 +823,7 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
if (m >= 1)
|
if (m >= 1)
|
||||||
{
|
{
|
||||||
send_from(listen->fd, option_bool(OPT_NOWILD), (char *)header,
|
send_from(listen->fd, option_bool(OPT_NOWILD), (char *)header,
|
||||||
m, &source_addr, &dst_addr, if_index);
|
m, &source_addr, &dst_addr, if_index, NULL);
|
||||||
daemon->local_answer++;
|
daemon->local_answer++;
|
||||||
}
|
}
|
||||||
else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
|
else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
|
||||||
@@ -798,7 +838,7 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
about resources for debug mode, when the fork is suppressed: that's
|
about resources for debug mode, when the fork is suppressed: that's
|
||||||
done by the caller. */
|
done by the caller. */
|
||||||
unsigned char *tcp_request(int confd, time_t now,
|
unsigned char *tcp_request(int confd, time_t now,
|
||||||
struct in_addr local_addr, struct in_addr netmask)
|
union mysockaddr *local_addr, struct in_addr netmask)
|
||||||
{
|
{
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
int norebind = 0;
|
int norebind = 0;
|
||||||
@@ -808,9 +848,15 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
unsigned char c1, c2;
|
unsigned char c1, c2;
|
||||||
/* Max TCP packet + slop */
|
/* Max TCP packet + slop */
|
||||||
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ);
|
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ);
|
||||||
HEADER *header;
|
struct dns_header *header;
|
||||||
struct server *last_server;
|
struct server *last_server;
|
||||||
|
struct in_addr dst_addr_4;
|
||||||
|
union mysockaddr peer_addr;
|
||||||
|
socklen_t peer_len = sizeof(union mysockaddr);
|
||||||
|
|
||||||
|
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
||||||
|
return packet;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (!packet ||
|
if (!packet ||
|
||||||
@@ -819,42 +865,41 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
!read_write(confd, packet, size, 1))
|
!read_write(confd, packet, size, 1))
|
||||||
return packet;
|
return packet;
|
||||||
|
|
||||||
if (size < (int)sizeof(HEADER))
|
if (size < (int)sizeof(struct dns_header))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
header = (HEADER *)packet;
|
header = (struct dns_header *)packet;
|
||||||
|
|
||||||
/* save state of "cd" flag in query */
|
/* save state of "cd" flag in query */
|
||||||
checking_disabled = header->cd;
|
checking_disabled = header->hb4 & HB4_CD;
|
||||||
|
|
||||||
/* RFC 4035: sect 4.6 para 2 */
|
/* RFC 4035: sect 4.6 para 2 */
|
||||||
header->ad = 0;
|
header->hb4 &= ~HB4_AD;
|
||||||
|
|
||||||
if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
|
if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
|
||||||
{
|
{
|
||||||
union mysockaddr peer_addr;
|
char types[20];
|
||||||
socklen_t peer_len = sizeof(union mysockaddr);
|
|
||||||
|
|
||||||
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
|
querystr(types, qtype);
|
||||||
{
|
|
||||||
char types[20];
|
if (peer_addr.sa.sa_family == AF_INET)
|
||||||
|
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||||
querystr(types, qtype);
|
(struct all_addr *)&peer_addr.in.sin_addr, types);
|
||||||
|
|
||||||
if (peer_addr.sa.sa_family == AF_INET)
|
|
||||||
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
|
|
||||||
(struct all_addr *)&peer_addr.in.sin_addr, types);
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else
|
else
|
||||||
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
|
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||||
(struct all_addr *)&peer_addr.in6.sin6_addr, types);
|
(struct all_addr *)&peer_addr.in6.sin6_addr, types);
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (local_addr->sa.sa_family == AF_INET)
|
||||||
|
dst_addr_4 = local_addr->in.sin_addr;
|
||||||
|
else
|
||||||
|
dst_addr_4.s_addr = 0;
|
||||||
|
|
||||||
/* m > 0 if answered from cache */
|
/* m > 0 if answered from cache */
|
||||||
m = answer_request(header, ((char *) header) + 65536, (unsigned int)size,
|
m = answer_request(header, ((char *) header) + 65536, (unsigned int)size,
|
||||||
local_addr, netmask, now);
|
dst_addr_4, netmask, now);
|
||||||
|
|
||||||
/* Do this by steam now we're not in the select() loop */
|
/* Do this by steam now we're not in the select() loop */
|
||||||
check_log_writer(NULL);
|
check_log_writer(NULL);
|
||||||
@@ -867,14 +912,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
char *domain = NULL;
|
char *domain = NULL;
|
||||||
|
|
||||||
if (option_bool(OPT_ADD_MAC))
|
if (option_bool(OPT_ADD_MAC))
|
||||||
{
|
size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
|
||||||
union mysockaddr peer_addr;
|
|
||||||
socklen_t peer_len = sizeof(union mysockaddr);
|
|
||||||
|
|
||||||
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
|
|
||||||
size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gotname)
|
if (gotname)
|
||||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
||||||
|
|
||||||
@@ -908,18 +947,38 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
if (type != (last_server->flags & SERV_TYPE) ||
|
if (type != (last_server->flags & SERV_TYPE) ||
|
||||||
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
|
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((last_server->tcpfd == -1) &&
|
if (last_server->tcpfd == -1)
|
||||||
(last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) != -1 &&
|
|
||||||
(!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);
|
if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
|
||||||
last_server->tcpfd = -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
|
||||||
}
|
}
|
||||||
|
|
||||||
if (last_server->tcpfd == -1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
c1 = size >> 8;
|
c1 = size >> 8;
|
||||||
c2 = size;
|
c2 = size;
|
||||||
|
|||||||
+483
-119
@@ -1,4 +1,4 @@
|
|||||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_SCRIPT
|
||||||
|
|
||||||
/* This file has code to fork a helper process which recieves data via a pipe
|
/* This file has code to fork a helper process which recieves data via a pipe
|
||||||
shared with the main process and which is responsible for calling a script when
|
shared with the main process and which is responsible for calling a script when
|
||||||
DHCP leases change.
|
DHCP leases change.
|
||||||
@@ -28,15 +30,25 @@
|
|||||||
main process.
|
main process.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
|
||||||
|
|
||||||
static void my_setenv(const char *name, const char *value, int *error);
|
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);
|
static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err);
|
||||||
|
|
||||||
|
#ifdef HAVE_LUASCRIPT
|
||||||
|
#include <lua.h>
|
||||||
|
#include <lualib.h>
|
||||||
|
#include <lauxlib.h>
|
||||||
|
|
||||||
|
lua_State *lua;
|
||||||
|
|
||||||
|
static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
struct script_data
|
struct script_data
|
||||||
{
|
{
|
||||||
unsigned char action, hwaddr_len, hwaddr_type;
|
int flags;
|
||||||
unsigned char clid_len, hostname_len, ed_len;
|
int action, hwaddr_len, hwaddr_type;
|
||||||
|
int clid_len, hostname_len, ed_len;
|
||||||
struct in_addr addr, giaddr;
|
struct in_addr addr, giaddr;
|
||||||
unsigned int remaining_time;
|
unsigned int remaining_time;
|
||||||
#ifdef HAVE_BROKEN_RTC
|
#ifdef HAVE_BROKEN_RTC
|
||||||
@@ -46,6 +58,7 @@ struct script_data
|
|||||||
#endif
|
#endif
|
||||||
unsigned char hwaddr[DHCP_CHADDR_MAX];
|
unsigned char hwaddr[DHCP_CHADDR_MAX];
|
||||||
char interface[IF_NAMESIZE];
|
char interface[IF_NAMESIZE];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct script_data *buf = NULL;
|
static struct script_data *buf = NULL;
|
||||||
@@ -61,7 +74,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
then fork our process. */
|
then fork our process. */
|
||||||
if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
|
if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
|
||||||
{
|
{
|
||||||
send_event(err_fd, EVENT_PIPE_ERR, errno);
|
send_event(err_fd, EVENT_PIPE_ERR, errno, NULL);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,37 +101,99 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
{
|
{
|
||||||
if (option_bool(OPT_NO_FORK))
|
if (option_bool(OPT_NO_FORK))
|
||||||
/* send error to daemon process if no-fork */
|
/* send error to daemon process if no-fork */
|
||||||
send_event(event_fd, EVENT_HUSER_ERR, errno);
|
send_event(event_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* kill daemon */
|
/* kill daemon */
|
||||||
send_event(event_fd, EVENT_DIE, 0);
|
send_event(event_fd, EVENT_DIE, 0, NULL);
|
||||||
/* return error */
|
/* return error */
|
||||||
send_event(err_fd, EVENT_HUSER_ERR, errno);
|
send_event(err_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
|
||||||
}
|
}
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* close all the sockets etc, we don't need them here. This closes err_fd, so that
|
/* close all the sockets etc, we don't need them here.
|
||||||
main process can return. */
|
Don't close err_fd, in case the lua-init fails.
|
||||||
|
Note that we have to do this before lua init
|
||||||
|
so we don't close any lua fds. */
|
||||||
for (max_fd--; max_fd >= 0; max_fd--)
|
for (max_fd--; max_fd >= 0; max_fd--)
|
||||||
if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO &&
|
if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO &&
|
||||||
max_fd != STDIN_FILENO && max_fd != pipefd[0] && max_fd != event_fd)
|
max_fd != STDIN_FILENO && max_fd != pipefd[0] &&
|
||||||
|
max_fd != event_fd && max_fd != err_fd)
|
||||||
close(max_fd);
|
close(max_fd);
|
||||||
|
|
||||||
|
#ifdef HAVE_LUASCRIPT
|
||||||
|
if (daemon->luascript)
|
||||||
|
{
|
||||||
|
const char *lua_err = NULL;
|
||||||
|
lua = lua_open();
|
||||||
|
luaL_openlibs(lua);
|
||||||
|
|
||||||
|
/* get Lua to load our script file */
|
||||||
|
if (luaL_dofile(lua, daemon->luascript) != 0)
|
||||||
|
lua_err = lua_tostring(lua, -1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lua_getglobal(lua, "lease");
|
||||||
|
if (lua_type(lua, -1) != LUA_TFUNCTION)
|
||||||
|
lua_err = _("lease() function missing in Lua script");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_err)
|
||||||
|
{
|
||||||
|
if (option_bool(OPT_NO_FORK) || option_bool(OPT_DEBUG))
|
||||||
|
/* send error to daemon process if no-fork */
|
||||||
|
send_event(event_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* kill daemon */
|
||||||
|
send_event(event_fd, EVENT_DIE, 0, NULL);
|
||||||
|
/* return error */
|
||||||
|
send_event(err_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
|
||||||
|
}
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pop(lua, 1); /* remove nil from stack */
|
||||||
|
lua_getglobal(lua, "init");
|
||||||
|
if (lua_type(lua, -1) == LUA_TFUNCTION)
|
||||||
|
lua_call(lua, 0, 0);
|
||||||
|
else
|
||||||
|
lua_pop(lua, 1); /* remove nil from stack */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* All init done, close our copy of the error pipe, so that main process can return */
|
||||||
|
if (err_fd != -1)
|
||||||
|
close(err_fd);
|
||||||
|
|
||||||
/* loop here */
|
/* loop here */
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
struct script_data data;
|
struct script_data data;
|
||||||
char *p, *action_str, *hostname = NULL;
|
char *p, *action_str, *hostname = NULL, *domain = NULL;
|
||||||
unsigned char *buf = (unsigned char *)daemon->namebuff;
|
unsigned char *buf = (unsigned char *)daemon->namebuff;
|
||||||
unsigned char *end, *alloc_buff = NULL;
|
unsigned char *end, *extradata, *alloc_buff = NULL;
|
||||||
int err = 0;
|
int is6, err = 0;
|
||||||
|
|
||||||
|
free(alloc_buff);
|
||||||
|
|
||||||
/* we read zero bytes when pipe closed: this is our signal to exit */
|
/* we read zero bytes when pipe closed: this is our signal to exit */
|
||||||
if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), 1))
|
if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), 1))
|
||||||
_exit(0);
|
{
|
||||||
|
#ifdef HAVE_LUASCRIPT
|
||||||
|
if (daemon->luascript)
|
||||||
|
{
|
||||||
|
lua_getglobal(lua, "shutdown");
|
||||||
|
if (lua_type(lua, -1) == LUA_TFUNCTION)
|
||||||
|
lua_call(lua, 0, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
is6 = !!(data.flags & (LEASE_TA | LEASE_NA));
|
||||||
|
|
||||||
if (data.action == ACTION_DEL)
|
if (data.action == ACTION_DEL)
|
||||||
action_str = "del";
|
action_str = "del";
|
||||||
@@ -126,55 +201,252 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
action_str = "add";
|
action_str = "add";
|
||||||
else if (data.action == ACTION_OLD || data.action == ACTION_OLD_HOSTNAME)
|
else if (data.action == ACTION_OLD || data.action == ACTION_OLD_HOSTNAME)
|
||||||
action_str = "old";
|
action_str = "old";
|
||||||
|
else if (data.action == ACTION_TFTP)
|
||||||
|
{
|
||||||
|
action_str = "tftp";
|
||||||
|
is6 = (data.flags != AF_INET);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* stringify MAC into dhcp_buff */
|
|
||||||
p = daemon->dhcp_buff;
|
if (!is6)
|
||||||
if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
|
|
||||||
p += sprintf(p, "%.2x-", data.hwaddr_type);
|
|
||||||
for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
|
|
||||||
{
|
|
||||||
p += sprintf(p, "%.2x", data.hwaddr[i]);
|
|
||||||
if (i != data.hwaddr_len - 1)
|
|
||||||
p += sprintf(p, ":");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* and CLID into packet, avoid overwrite from bad data */
|
|
||||||
if ((data.clid_len > daemon->packet_buff_sz) || !read_write(pipefd[0], buf, data.clid_len, 1))
|
|
||||||
continue;
|
|
||||||
for (p = daemon->packet, i = 0; i < data.clid_len; i++)
|
|
||||||
{
|
{
|
||||||
p += sprintf(p, "%.2x", buf[i]);
|
/* stringify MAC into dhcp_buff */
|
||||||
if (i != data.clid_len - 1)
|
p = daemon->dhcp_buff;
|
||||||
p += sprintf(p, ":");
|
if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
|
||||||
|
p += sprintf(p, "%.2x-", data.hwaddr_type);
|
||||||
|
for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
|
||||||
|
{
|
||||||
|
p += sprintf(p, "%.2x", data.hwaddr[i]);
|
||||||
|
if (i != data.hwaddr_len - 1)
|
||||||
|
p += sprintf(p, ":");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* and expiry or length into dhcp_buff2 */
|
/* expiry or length into dhcp_buff2 */
|
||||||
#ifdef HAVE_BROKEN_RTC
|
#ifdef HAVE_BROKEN_RTC
|
||||||
sprintf(daemon->dhcp_buff2, "%u", data.length);
|
sprintf(daemon->dhcp_buff2, "%u", data.length);
|
||||||
#else
|
#else
|
||||||
sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
|
sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* supplied data may just exceed normal buffer (unlikely) */
|
/* supplied data may just exceed normal buffer (unlikely) */
|
||||||
if ((data.hostname_len + data.ed_len) > daemon->packet_buff_sz &&
|
if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME &&
|
||||||
!(alloc_buff = buf = malloc(data.hostname_len + data.ed_len)))
|
!(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!read_write(pipefd[0], buf,
|
if (!read_write(pipefd[0], buf,
|
||||||
data.hostname_len + data.ed_len, 1))
|
data.hostname_len + data.ed_len + data.clid_len, 1))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* CLID into packet */
|
||||||
|
if (!is6)
|
||||||
|
for (p = daemon->packet, i = 0; i < data.clid_len; i++)
|
||||||
|
{
|
||||||
|
p += sprintf(p, "%.2x", buf[i]);
|
||||||
|
if (i != data.clid_len - 1)
|
||||||
|
p += sprintf(p, ":");
|
||||||
|
}
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* or IAID and server DUID for IPv6 */
|
||||||
|
sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.hwaddr_type);
|
||||||
|
for (p = daemon->packet, i = 0; i < daemon->duid_len; i++)
|
||||||
|
{
|
||||||
|
p += sprintf(p, "%.2x", daemon->duid[i]);
|
||||||
|
if (i != daemon->duid_len - 1)
|
||||||
|
p += sprintf(p, ":");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* duid not MAC for IPv6 */
|
||||||
|
for (p = daemon->dhcp_buff, i = 0; i < data.clid_len; i++)
|
||||||
|
{
|
||||||
|
p += sprintf(p, "%.2x", buf[i]);
|
||||||
|
if (i != data.clid_len - 1)
|
||||||
|
p += sprintf(p, ":");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
buf += data.clid_len;
|
||||||
|
|
||||||
|
if (data.hostname_len != 0)
|
||||||
|
{
|
||||||
|
char *dot;
|
||||||
|
hostname = (char *)buf;
|
||||||
|
hostname[data.hostname_len - 1] = 0;
|
||||||
|
if (data.action != ACTION_TFTP)
|
||||||
|
{
|
||||||
|
if (!legal_hostname(hostname))
|
||||||
|
hostname = NULL;
|
||||||
|
else if ((dot = strchr(hostname, '.')))
|
||||||
|
{
|
||||||
|
domain = dot+1;
|
||||||
|
*dot = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extradata = buf + data.hostname_len;
|
||||||
|
|
||||||
|
if (!is6)
|
||||||
|
inet_ntop(AF_INET, &data.addr, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
else
|
||||||
|
inet_ntop(AF_INET6, &data.hwaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* file length */
|
||||||
|
if (data.action == ACTION_TFTP)
|
||||||
|
sprintf(daemon->dhcp_buff, "%u", data.hwaddr_len);
|
||||||
|
|
||||||
|
#ifdef HAVE_LUASCRIPT
|
||||||
|
if (daemon->luascript)
|
||||||
|
{
|
||||||
|
if (data.action == ACTION_TFTP)
|
||||||
|
{
|
||||||
|
lua_getglobal(lua, "tftp");
|
||||||
|
if (lua_type(lua, -1) != LUA_TFUNCTION)
|
||||||
|
lua_pop(lua, 1); /* tftp function optional */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, action_str); /* arg1 - action */
|
||||||
|
lua_newtable(lua); /* arg2 - data table */
|
||||||
|
lua_pushstring(lua, daemon->addrbuff);
|
||||||
|
lua_setfield(lua, -2, "destination_address");
|
||||||
|
lua_pushstring(lua, hostname);
|
||||||
|
lua_setfield(lua, -2, "file_name");
|
||||||
|
lua_pushstring(lua, daemon->dhcp_buff);
|
||||||
|
lua_setfield(lua, -2, "file_size");
|
||||||
|
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lua_getglobal(lua, "lease"); /* function to call */
|
||||||
|
lua_pushstring(lua, action_str); /* arg1 - action */
|
||||||
|
lua_newtable(lua); /* arg2 - data table */
|
||||||
|
|
||||||
|
if (is6)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, daemon->dhcp_buff);
|
||||||
|
lua_setfield(lua, -2, "client_duid");
|
||||||
|
lua_pushstring(lua, daemon->packet);
|
||||||
|
lua_setfield(lua, -2, "server_duid");
|
||||||
|
lua_pushstring(lua, daemon->dhcp_buff3);
|
||||||
|
lua_setfield(lua, -2, "iaid");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is6 && data.clid_len != 0)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, daemon->packet);
|
||||||
|
lua_setfield(lua, -2, "client_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(data.interface) != 0)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, data.interface);
|
||||||
|
lua_setfield(lua, -2, "interface");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
lua_pushnumber(lua, data.length);
|
||||||
|
lua_setfield(lua, -2, "lease_length");
|
||||||
|
#else
|
||||||
|
lua_pushnumber(lua, data.expires);
|
||||||
|
lua_setfield(lua, -2, "lease_expires");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (hostname)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, hostname);
|
||||||
|
lua_setfield(lua, -2, "hostname");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (domain)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, domain);
|
||||||
|
lua_setfield(lua, -2, "domain");
|
||||||
|
}
|
||||||
|
|
||||||
|
end = extradata + data.ed_len;
|
||||||
|
buf = extradata;
|
||||||
|
|
||||||
|
if (!is6)
|
||||||
|
buf = grab_extradata_lua(buf, end, "vendor_class");
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
else
|
||||||
|
for (i = 0; i < data.hwaddr_len; i++)
|
||||||
|
{
|
||||||
|
sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
|
||||||
|
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
buf = grab_extradata_lua(buf, end, "supplied_hostname");
|
||||||
|
|
||||||
|
if (!is6)
|
||||||
|
{
|
||||||
|
buf = grab_extradata_lua(buf, end, "cpewan_oui");
|
||||||
|
buf = grab_extradata_lua(buf, end, "cpewan_serial");
|
||||||
|
buf = grab_extradata_lua(buf, end, "cpewan_class");
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = grab_extradata_lua(buf, end, "tags");
|
||||||
|
|
||||||
|
if (is6)
|
||||||
|
buf = grab_extradata_lua(buf, end, "relay_address");
|
||||||
|
else if (data.giaddr.s_addr != 0)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, inet_ntoa(data.giaddr));
|
||||||
|
lua_setfield(lua, -2, "relay_address");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; buf; i++)
|
||||||
|
{
|
||||||
|
sprintf(daemon->dhcp_buff2, "user_class%i", i);
|
||||||
|
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.action != ACTION_DEL && data.remaining_time != 0)
|
||||||
|
{
|
||||||
|
lua_pushnumber(lua, data.remaining_time);
|
||||||
|
lua_setfield(lua, -2, "time_remaining");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.action == ACTION_OLD_HOSTNAME && hostname)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, hostname);
|
||||||
|
lua_setfield(lua, -2, "old_hostname");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is6)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, daemon->dhcp_buff);
|
||||||
|
lua_setfield(lua, -2, "mac_address");
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pushstring(lua, daemon->addrbuff);
|
||||||
|
lua_setfield(lua, -2, "ip_address");
|
||||||
|
|
||||||
|
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* no script, just lua */
|
||||||
|
if (!daemon->lease_change_command)
|
||||||
|
continue;
|
||||||
|
|
||||||
/* possible fork errors are all temporary resource problems */
|
/* possible fork errors are all temporary resource problems */
|
||||||
while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
|
while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
|
||||||
sleep(2);
|
sleep(2);
|
||||||
|
|
||||||
free(alloc_buff);
|
|
||||||
|
|
||||||
if (pid == -1)
|
if (pid == -1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* wait for child to complete */
|
/* wait for child to complete */
|
||||||
if (pid != 0)
|
if (pid != 0)
|
||||||
{
|
{
|
||||||
@@ -188,9 +460,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
{
|
{
|
||||||
/* On error send event back to main process for logging */
|
/* On error send event back to main process for logging */
|
||||||
if (WIFSIGNALED(status))
|
if (WIFSIGNALED(status))
|
||||||
send_event(event_fd, EVENT_KILLED, WTERMSIG(status));
|
send_event(event_fd, EVENT_KILLED, WTERMSIG(status), NULL);
|
||||||
else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
|
else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
|
||||||
send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status));
|
send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status), NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,62 +473,87 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.clid_len != 0)
|
if (data.action != ACTION_TFTP)
|
||||||
my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);
|
|
||||||
|
|
||||||
if (strlen(data.interface) != 0)
|
|
||||||
my_setenv("DNSMASQ_INTERFACE", data.interface, &err);
|
|
||||||
|
|
||||||
#ifdef HAVE_BROKEN_RTC
|
|
||||||
my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
|
|
||||||
#else
|
|
||||||
my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (data.hostname_len != 0)
|
|
||||||
{
|
{
|
||||||
char *dot;
|
if (is6)
|
||||||
hostname = (char *)buf;
|
|
||||||
hostname[data.hostname_len - 1] = 0;
|
|
||||||
if (!legal_hostname(hostname))
|
|
||||||
hostname = NULL;
|
|
||||||
else if ((dot = strchr(hostname, '.')))
|
|
||||||
{
|
{
|
||||||
my_setenv("DNSMASQ_DOMAIN", dot+1, &err);
|
my_setenv("DNSMASQ_IAID", daemon->dhcp_buff3, &err);
|
||||||
*dot = 0;
|
my_setenv("DNSMASQ_SERVER_DUID", daemon->packet, &err);
|
||||||
}
|
}
|
||||||
buf += data.hostname_len;
|
|
||||||
}
|
if (!is6 && data.clid_len != 0)
|
||||||
|
my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);
|
||||||
end = buf + data.ed_len;
|
|
||||||
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
|
if (strlen(data.interface) != 0)
|
||||||
buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err);
|
my_setenv("DNSMASQ_INTERFACE", data.interface, &err);
|
||||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
|
|
||||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);
|
#ifdef HAVE_BROKEN_RTC
|
||||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
|
my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
|
||||||
buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
|
#else
|
||||||
|
my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
|
||||||
for (i = 0; buf; i++)
|
#endif
|
||||||
{
|
|
||||||
sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i);
|
if (domain)
|
||||||
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
|
my_setenv("DNSMASQ_DOMAIN", domain, &err);
|
||||||
}
|
|
||||||
|
end = extradata + data.ed_len;
|
||||||
if (data.giaddr.s_addr != 0)
|
buf = extradata;
|
||||||
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
|
|
||||||
|
if (!is6)
|
||||||
if (data.action != ACTION_DEL)
|
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
|
||||||
{
|
#ifdef HAVE_DHCP6
|
||||||
sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
|
else
|
||||||
my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
|
{
|
||||||
}
|
if (data.hwaddr_len != 0)
|
||||||
|
{
|
||||||
if (data.action == ACTION_OLD_HOSTNAME && hostname)
|
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err);
|
||||||
{
|
for (i = 0; i < data.hwaddr_len - 1; i++)
|
||||||
my_setenv("DNSMASQ_OLD_HOSTNAME", hostname, &err);
|
{
|
||||||
hostname = NULL;
|
sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i);
|
||||||
|
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err);
|
||||||
|
|
||||||
|
if (!is6)
|
||||||
|
{
|
||||||
|
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
|
||||||
|
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);
|
||||||
|
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
|
||||||
|
|
||||||
|
if (is6)
|
||||||
|
buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
|
||||||
|
else if (data.giaddr.s_addr != 0)
|
||||||
|
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
|
||||||
|
|
||||||
|
for (i = 0; buf; i++)
|
||||||
|
{
|
||||||
|
sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i);
|
||||||
|
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.action != ACTION_DEL && data.remaining_time != 0)
|
||||||
|
{
|
||||||
|
sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
|
||||||
|
my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.action == ACTION_OLD_HOSTNAME && hostname)
|
||||||
|
{
|
||||||
|
my_setenv("DNSMASQ_OLD_HOSTNAME", hostname, &err);
|
||||||
|
hostname = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (option_bool(OPT_LOG_OPTS))
|
||||||
|
my_setenv("DNSMASQ_LOG_DHCP", "1", &err);
|
||||||
|
|
||||||
/* we need to have the event_fd around if exec fails */
|
/* we need to have the event_fd around if exec fails */
|
||||||
if ((i = fcntl(event_fd, F_GETFD)) != -1)
|
if ((i = fcntl(event_fd, F_GETFD)) != -1)
|
||||||
fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
|
fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
|
||||||
@@ -267,11 +564,11 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
{
|
{
|
||||||
execl(daemon->lease_change_command,
|
execl(daemon->lease_change_command,
|
||||||
p ? p+1 : daemon->lease_change_command,
|
p ? p+1 : daemon->lease_change_command,
|
||||||
action_str, daemon->dhcp_buff, inet_ntoa(data.addr), hostname, (char*)NULL);
|
action_str, daemon->dhcp_buff, daemon->addrbuff, hostname, (char*)NULL);
|
||||||
err = errno;
|
err = errno;
|
||||||
}
|
}
|
||||||
/* failed, send event so the main process logs the problem */
|
/* failed, send event so the main process logs the problem */
|
||||||
send_event(event_fd, EVENT_EXEC_ERR, err);
|
send_event(event_fd, EVENT_EXEC_ERR, err, NULL);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -305,26 +602,30 @@ static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, ch
|
|||||||
return next + 1;
|
return next + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pack up lease data into a buffer */
|
#ifdef HAVE_LUASCRIPT
|
||||||
void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
|
static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field)
|
||||||
{
|
{
|
||||||
unsigned char *p;
|
unsigned char *next;
|
||||||
size_t size;
|
|
||||||
unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
|
if (!buf || (buf == end))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (next = buf; *next != 0; next++)
|
||||||
|
if (next == end)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
/* no script */
|
if (next != buf)
|
||||||
if (daemon->helperfd == -1)
|
{
|
||||||
return;
|
lua_pushstring(lua, (char *)buf);
|
||||||
|
lua_setfield(lua, -2, field);
|
||||||
|
}
|
||||||
|
|
||||||
if (lease->extradata)
|
return next + 1;
|
||||||
ed_len = lease->extradata_len;
|
}
|
||||||
if (lease->clid)
|
#endif
|
||||||
clid_len = lease->clid_len;
|
|
||||||
if (hostname)
|
|
||||||
hostname_len = strlen(hostname) + 1;
|
|
||||||
|
|
||||||
size = sizeof(struct script_data) + clid_len + ed_len + hostname_len;
|
|
||||||
|
|
||||||
|
static void buff_alloc(size_t size)
|
||||||
|
{
|
||||||
if (size > buf_size)
|
if (size > buf_size)
|
||||||
{
|
{
|
||||||
struct script_data *new;
|
struct script_data *new;
|
||||||
@@ -340,8 +641,35 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
|
|||||||
buf = new;
|
buf = new;
|
||||||
buf_size = size;
|
buf_size = size;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pack up lease data into a buffer */
|
||||||
|
void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
|
||||||
|
{
|
||||||
|
unsigned char *p;
|
||||||
|
unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
|
||||||
|
int fd = daemon->dhcpfd;
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (!daemon->dhcp)
|
||||||
|
fd = daemon->dhcp6fd;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* no script */
|
||||||
|
if (daemon->helperfd == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (lease->extradata)
|
||||||
|
ed_len = lease->extradata_len;
|
||||||
|
if (lease->clid)
|
||||||
|
clid_len = lease->clid_len;
|
||||||
|
if (hostname)
|
||||||
|
hostname_len = strlen(hostname) + 1;
|
||||||
|
|
||||||
|
buff_alloc(sizeof(struct script_data) + clid_len + ed_len + hostname_len);
|
||||||
|
|
||||||
buf->action = action;
|
buf->action = action;
|
||||||
|
buf->flags = lease->flags;
|
||||||
buf->hwaddr_len = lease->hwaddr_len;
|
buf->hwaddr_len = lease->hwaddr_len;
|
||||||
buf->hwaddr_type = lease->hwaddr_type;
|
buf->hwaddr_type = lease->hwaddr_type;
|
||||||
buf->clid_len = clid_len;
|
buf->clid_len = clid_len;
|
||||||
@@ -349,8 +677,8 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
|
|||||||
buf->hostname_len = hostname_len;
|
buf->hostname_len = hostname_len;
|
||||||
buf->addr = lease->addr;
|
buf->addr = lease->addr;
|
||||||
buf->giaddr = lease->giaddr;
|
buf->giaddr = lease->giaddr;
|
||||||
memcpy(buf->hwaddr, lease->hwaddr, lease->hwaddr_len);
|
memcpy(buf->hwaddr, lease->hwaddr, DHCP_CHADDR_MAX);
|
||||||
if (!indextoname(daemon->dhcpfd, lease->last_interface, buf->interface))
|
if (!indextoname(fd, lease->last_interface, buf->interface))
|
||||||
buf->interface[0] = 0;
|
buf->interface[0] = 0;
|
||||||
|
|
||||||
#ifdef HAVE_BROKEN_RTC
|
#ifdef HAVE_BROKEN_RTC
|
||||||
@@ -358,7 +686,11 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
|
|||||||
#else
|
#else
|
||||||
buf->expires = lease->expires;
|
buf->expires = lease->expires;
|
||||||
#endif
|
#endif
|
||||||
buf->remaining_time = (unsigned int)difftime(lease->expires, now);
|
|
||||||
|
if (lease->expires != 0)
|
||||||
|
buf->remaining_time = (unsigned int)difftime(lease->expires, now);
|
||||||
|
else
|
||||||
|
buf->remaining_time = 0;
|
||||||
|
|
||||||
p = (unsigned char *)(buf+1);
|
p = (unsigned char *)(buf+1);
|
||||||
if (clid_len != 0)
|
if (clid_len != 0)
|
||||||
@@ -379,6 +711,37 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
|
|||||||
bytes_in_buf = p - (unsigned char *)buf;
|
bytes_in_buf = p - (unsigned char *)buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_TFTP
|
||||||
|
/* This nastily re-uses DHCP-fields for TFTP stuff */
|
||||||
|
void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
|
||||||
|
{
|
||||||
|
unsigned int filename_len;
|
||||||
|
|
||||||
|
/* no script */
|
||||||
|
if (daemon->helperfd == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
filename_len = strlen(filename) + 1;
|
||||||
|
buff_alloc(sizeof(struct script_data) + filename_len);
|
||||||
|
memset(buf, 0, sizeof(struct script_data));
|
||||||
|
|
||||||
|
buf->action = ACTION_TFTP;
|
||||||
|
buf->hostname_len = filename_len;
|
||||||
|
buf->hwaddr_len = file_len;
|
||||||
|
|
||||||
|
if ((buf->flags = peer->sa.sa_family) == AF_INET)
|
||||||
|
buf->addr = peer->in.sin_addr;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else
|
||||||
|
memcpy(buf->hwaddr, &peer->in6.sin6_addr, IN6ADDRSZ);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memcpy((unsigned char *)(buf+1), filename, filename_len);
|
||||||
|
|
||||||
|
bytes_in_buf = sizeof(struct script_data) + filename_len;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int helper_buf_empty(void)
|
int helper_buf_empty(void)
|
||||||
{
|
{
|
||||||
return bytes_in_buf == 0;
|
return bytes_in_buf == 0;
|
||||||
@@ -408,3 +771,4 @@ void helper_write(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+505
-83
@@ -1,4 +1,4 @@
|
|||||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,19 +24,13 @@ static int dns_dirty, file_dirty, leases_left;
|
|||||||
void lease_init(time_t now)
|
void lease_init(time_t now)
|
||||||
{
|
{
|
||||||
unsigned long ei;
|
unsigned long ei;
|
||||||
struct in_addr addr;
|
struct all_addr addr;
|
||||||
struct dhcp_lease *lease;
|
struct dhcp_lease *lease;
|
||||||
int clid_len, hw_len, hw_type;
|
int clid_len, hw_len, hw_type;
|
||||||
FILE *leasestream;
|
FILE *leasestream;
|
||||||
|
|
||||||
/* These each hold a DHCP option max size 255
|
|
||||||
and get a terminating zero added */
|
|
||||||
daemon->dhcp_buff = safe_malloc(256);
|
|
||||||
daemon->dhcp_buff2 = safe_malloc(256);
|
|
||||||
daemon->dhcp_buff3 = safe_malloc(256);
|
|
||||||
|
|
||||||
leases_left = daemon->dhcp_max;
|
leases_left = daemon->dhcp_max;
|
||||||
|
|
||||||
if (option_bool(OPT_LEASE_RO))
|
if (option_bool(OPT_LEASE_RO))
|
||||||
{
|
{
|
||||||
/* run "<lease_change_script> init" once to get the
|
/* run "<lease_change_script> init" once to get the
|
||||||
@@ -73,23 +67,69 @@ void lease_init(time_t now)
|
|||||||
/* client-id max length is 255 which is 255*2 digits + 254 colons
|
/* client-id max length is 255 which is 255*2 digits + 254 colons
|
||||||
borrow DNS packet buffer which is always larger than 1000 bytes */
|
borrow DNS packet buffer which is always larger than 1000 bytes */
|
||||||
if (leasestream)
|
if (leasestream)
|
||||||
while (fscanf(leasestream, "%lu %255s %16s %255s %764s",
|
while (fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2) == 2)
|
||||||
&ei, daemon->dhcp_buff2, daemon->namebuff,
|
|
||||||
daemon->dhcp_buff, daemon->packet) == 5)
|
|
||||||
{
|
{
|
||||||
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
|
#ifdef HAVE_DHCP6
|
||||||
/* For backwards compatibility, no explict MAC address type means ether. */
|
if (strcmp(daemon->dhcp_buff3, "duid") == 0)
|
||||||
if (hw_type == 0 && hw_len != 0)
|
{
|
||||||
hw_type = ARPHRD_ETHER;
|
daemon->duid_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, 130, NULL, NULL);
|
||||||
|
daemon->duid = safe_malloc(daemon->duid_len);
|
||||||
|
memcpy(daemon->duid, daemon->dhcp_buff2, daemon->duid_len);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ei = atol(daemon->dhcp_buff3);
|
||||||
|
|
||||||
addr.s_addr = inet_addr(daemon->namebuff);
|
if (fscanf(leasestream, " %64s %255s %764s",
|
||||||
|
daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3)
|
||||||
|
break;
|
||||||
|
|
||||||
/* decode hex in place */
|
|
||||||
clid_len = 0;
|
clid_len = 0;
|
||||||
if (strcmp(daemon->packet, "*") != 0)
|
if (strcmp(daemon->packet, "*") != 0)
|
||||||
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
|
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
|
||||||
|
|
||||||
if (!(lease = lease_allocate(addr)))
|
if (inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4) &&
|
||||||
|
(lease = lease4_allocate(addr.addr.addr4)))
|
||||||
|
{
|
||||||
|
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
|
||||||
|
/* For backwards compatibility, no explict MAC address type means ether. */
|
||||||
|
if (hw_type == 0 && hw_len != 0)
|
||||||
|
hw_type = ARPHRD_ETHER;
|
||||||
|
|
||||||
|
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet,
|
||||||
|
hw_len, hw_type, clid_len, now);
|
||||||
|
|
||||||
|
if (strcmp(daemon->dhcp_buff, "*") != 0)
|
||||||
|
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr), NULL);
|
||||||
|
}
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6))
|
||||||
|
{
|
||||||
|
char *s = daemon->dhcp_buff2;
|
||||||
|
int lease_type = LEASE_NA;
|
||||||
|
|
||||||
|
if (s[0] == 'T')
|
||||||
|
{
|
||||||
|
lease_type = LEASE_TA;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
hw_type = atoi(s);
|
||||||
|
|
||||||
|
if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
|
||||||
|
{
|
||||||
|
lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, hw_type, clid_len, now);
|
||||||
|
|
||||||
|
if (strcmp(daemon->dhcp_buff, "*") != 0)
|
||||||
|
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!lease)
|
||||||
die (_("too many stored leases"), NULL, EC_MISC);
|
die (_("too many stored leases"), NULL, EC_MISC);
|
||||||
|
|
||||||
#ifdef HAVE_BROKEN_RTC
|
#ifdef HAVE_BROKEN_RTC
|
||||||
@@ -104,14 +144,9 @@ void lease_init(time_t now)
|
|||||||
lease->expires = (time_t)ei;
|
lease->expires = (time_t)ei;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len);
|
|
||||||
|
|
||||||
if (strcmp(daemon->dhcp_buff, "*") != 0)
|
|
||||||
lease_set_hostname(lease, daemon->dhcp_buff, 0);
|
|
||||||
|
|
||||||
/* set these correctly: the "old" events are generated later from
|
/* set these correctly: the "old" events are generated later from
|
||||||
the startup synthesised SIGHUP. */
|
the startup synthesised SIGHUP. */
|
||||||
lease->new = lease->changed = 0;
|
lease->flags &= ~(LEASE_NEW | LEASE_CHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SCRIPT
|
#ifdef HAVE_SCRIPT
|
||||||
@@ -150,17 +185,17 @@ void lease_update_from_configs(void)
|
|||||||
struct dhcp_lease *lease;
|
struct dhcp_lease *lease;
|
||||||
struct dhcp_config *config;
|
struct dhcp_config *config;
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
|
if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
|
||||||
lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
|
lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
|
||||||
(config->flags & CONFIG_NAME) &&
|
(config->flags & CONFIG_NAME) &&
|
||||||
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
|
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
|
||||||
lease_set_hostname(lease, config->hostname, 1);
|
lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);
|
||||||
else if ((name = host_from_dns(lease->addr)))
|
else if ((name = host_from_dns(lease->addr)))
|
||||||
lease_set_hostname(lease, name, 1); /* updates auth flag only */
|
lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ourprintf(int *errp, char *format, ...)
|
static void ourprintf(int *errp, char *format, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@@ -186,11 +221,18 @@ void lease_update_file(time_t now)
|
|||||||
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (lease->flags & (LEASE_TA | LEASE_NA))
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_BROKEN_RTC
|
#ifdef HAVE_BROKEN_RTC
|
||||||
ourprintf(&err, "%u ", lease->length);
|
ourprintf(&err, "%u ", lease->length);
|
||||||
#else
|
#else
|
||||||
ourprintf(&err, "%lu ", (unsigned long)lease->expires);
|
ourprintf(&err, "%lu ", (unsigned long)lease->expires);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0)
|
if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0)
|
||||||
ourprintf(&err, "%.2x-", lease->hwaddr_type);
|
ourprintf(&err, "%.2x-", lease->hwaddr_type);
|
||||||
for (i = 0; i < lease->hwaddr_len; i++)
|
for (i = 0; i < lease->hwaddr_len; i++)
|
||||||
@@ -199,8 +241,10 @@ void lease_update_file(time_t now)
|
|||||||
if (i != lease->hwaddr_len - 1)
|
if (i != lease->hwaddr_len - 1)
|
||||||
ourprintf(&err, ":");
|
ourprintf(&err, ":");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
|
||||||
ourprintf(&err, " %s ", inet_ntoa(lease->addr));
|
ourprintf(&err, " %s ", daemon->addrbuff);
|
||||||
ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
|
ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
|
||||||
|
|
||||||
if (lease->clid && lease->clid_len != 0)
|
if (lease->clid && lease->clid_len != 0)
|
||||||
@@ -213,6 +257,44 @@ void lease_update_file(time_t now)
|
|||||||
ourprintf(&err, "*\n");
|
ourprintf(&err, "*\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (daemon->duid)
|
||||||
|
{
|
||||||
|
ourprintf(&err, "duid ");
|
||||||
|
for (i = 0; i < daemon->duid_len - 1; i++)
|
||||||
|
ourprintf(&err, "%.2x:", daemon->duid[i]);
|
||||||
|
ourprintf(&err, "%.2x\n", daemon->duid[i]);
|
||||||
|
|
||||||
|
for (lease = leases; lease; lease = lease->next)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
ourprintf(&err, "%u ", lease->length);
|
||||||
|
#else
|
||||||
|
ourprintf(&err, "%lu ", (unsigned long)lease->expires);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
|
||||||
|
ourprintf(&err, "%s%u %s ", (lease->flags & LEASE_TA) ? "T" : "",
|
||||||
|
lease->hwaddr_type, daemon->addrbuff);
|
||||||
|
ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
|
||||||
|
|
||||||
|
if (lease->clid && lease->clid_len != 0)
|
||||||
|
{
|
||||||
|
for (i = 0; i < lease->clid_len - 1; i++)
|
||||||
|
ourprintf(&err, "%.2x:", lease->clid[i]);
|
||||||
|
ourprintf(&err, "%.2x\n", lease->clid[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ourprintf(&err, "*\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (fflush(daemon->lease_stream) != 0 ||
|
if (fflush(daemon->lease_stream) != 0 ||
|
||||||
fsync(fileno(daemon->lease_stream)) < 0)
|
fsync(fileno(daemon->lease_stream)) < 0)
|
||||||
err = errno;
|
err = errno;
|
||||||
@@ -222,7 +304,22 @@ void lease_update_file(time_t now)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Set alarm for when the first lease expires + slop. */
|
/* Set alarm for when the first lease expires + slop. */
|
||||||
for (next_event = 0, lease = leases; lease; lease = lease->next)
|
next_event = 0;
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
/* do timed RAs and determine when the next is, also pings to potential SLAAC addresses */
|
||||||
|
if (daemon->ra_contexts)
|
||||||
|
{
|
||||||
|
time_t ra_event = periodic_slaac(now, leases);
|
||||||
|
|
||||||
|
next_event = periodic_ra(now);
|
||||||
|
|
||||||
|
if (next_event == 0 || difftime(next_event, ra_event) > 0.0)
|
||||||
|
next_event = ra_event;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (lease = leases; lease; lease = lease->next)
|
||||||
if (lease->expires != 0 &&
|
if (lease->expires != 0 &&
|
||||||
(next_event == 0 || difftime(next_event, lease->expires + 10) > 0.0))
|
(next_event == 0 || difftime(next_event, lease->expires + 10) > 0.0))
|
||||||
next_event = lease->expires + 10;
|
next_event = lease->expires + 10;
|
||||||
@@ -237,25 +334,118 @@ void lease_update_file(time_t now)
|
|||||||
(unsigned int)difftime(next_event, now));
|
(unsigned int)difftime(next_event, now));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next_event != 0)
|
send_alarm(next_event, now);
|
||||||
alarm((unsigned)difftime(next_event, now));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lease_update_dns(void)
|
|
||||||
|
static int find_interface_v4(struct in_addr local, int if_index,
|
||||||
|
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||||
{
|
{
|
||||||
struct dhcp_lease *lease;
|
struct dhcp_lease *lease;
|
||||||
|
|
||||||
if (daemon->port != 0 && dns_dirty)
|
(void) broadcast;
|
||||||
|
(void) vparam;
|
||||||
|
|
||||||
|
for (lease = leases; lease; lease = lease->next)
|
||||||
|
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
|
||||||
|
if (is_same_net(local, lease->addr, netmask))
|
||||||
|
lease_set_interface(lease, if_index, *((time_t *)vparam));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
static int find_interface_v6(struct in6_addr *local, int prefix,
|
||||||
|
int scope, int if_index, int dad, void *vparam)
|
||||||
|
{
|
||||||
|
struct dhcp_lease *lease;
|
||||||
|
|
||||||
|
(void)scope;
|
||||||
|
(void)dad;
|
||||||
|
|
||||||
|
for (lease = leases; lease; lease = lease->next)
|
||||||
|
if ((lease->flags & (LEASE_TA | LEASE_NA)))
|
||||||
|
if (is_same_net6(local, (struct in6_addr *)&lease->hwaddr, prefix))
|
||||||
|
lease_set_interface(lease, if_index, *((time_t *)vparam));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface)
|
||||||
|
{
|
||||||
|
/* We may be doing RA but not DHCPv4, in which case the lease
|
||||||
|
database may not exist and we have nothing to do anyway */
|
||||||
|
if (daemon->dhcp)
|
||||||
|
slaac_ping_reply(sender, packet, interface, leases);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Find interfaces associated with leases at start-up. This gets updated as
|
||||||
|
we do DHCP transactions, but information about directly-connected subnets
|
||||||
|
is useful from scrips and necessary for determining SLAAC addresses from
|
||||||
|
start-time. */
|
||||||
|
void lease_find_interfaces(time_t now)
|
||||||
|
{
|
||||||
|
#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);
|
||||||
|
|
||||||
|
/* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
|
||||||
|
if (!daemon->duid && daemon->dhcp6)
|
||||||
|
{
|
||||||
|
file_dirty = 1;
|
||||||
|
make_duid(now);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void lease_update_dns(int force)
|
||||||
|
{
|
||||||
|
struct dhcp_lease *lease;
|
||||||
|
|
||||||
|
if (daemon->port != 0 && (dns_dirty || force))
|
||||||
{
|
{
|
||||||
cache_unhash_dhcp();
|
cache_unhash_dhcp();
|
||||||
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
{
|
{
|
||||||
|
int prot = AF_INET;
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (lease->flags & (LEASE_TA | LEASE_NA))
|
||||||
|
prot = AF_INET6;
|
||||||
|
else if (lease->hostname || lease->fqdn)
|
||||||
|
{
|
||||||
|
struct slaac_address *slaac;
|
||||||
|
|
||||||
|
for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
|
||||||
|
if (slaac->backoff == 0)
|
||||||
|
{
|
||||||
|
if (lease->fqdn)
|
||||||
|
cache_add_dhcp_entry(lease->fqdn, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
|
||||||
|
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
|
||||||
|
cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (lease->fqdn)
|
if (lease->fqdn)
|
||||||
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
|
cache_add_dhcp_entry(lease->fqdn, prot,
|
||||||
|
prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr,
|
||||||
|
lease->expires);
|
||||||
|
|
||||||
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
|
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
|
||||||
cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires);
|
cache_add_dhcp_entry(lease->hostname, prot,
|
||||||
|
prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr,
|
||||||
|
lease->expires);
|
||||||
}
|
}
|
||||||
|
|
||||||
dns_dirty = 0;
|
dns_dirty = 0;
|
||||||
@@ -275,7 +465,7 @@ void lease_prune(struct dhcp_lease *target, time_t now)
|
|||||||
if (lease->hostname)
|
if (lease->hostname)
|
||||||
dns_dirty = 1;
|
dns_dirty = 1;
|
||||||
|
|
||||||
*up = lease->next; /* unlink */
|
*up = lease->next; /* unlink */
|
||||||
|
|
||||||
/* Put on old_leases list 'till we
|
/* Put on old_leases list 'till we
|
||||||
can run the script */
|
can run the script */
|
||||||
@@ -297,18 +487,30 @@ struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int h
|
|||||||
|
|
||||||
if (clid)
|
if (clid)
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
if (lease->clid && clid_len == lease->clid_len &&
|
{
|
||||||
memcmp(clid, lease->clid, clid_len) == 0)
|
#ifdef HAVE_DHCP6
|
||||||
return lease;
|
if (lease->flags & (LEASE_TA | LEASE_NA))
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
if (lease->clid && clid_len == lease->clid_len &&
|
||||||
|
memcmp(clid, lease->clid, clid_len) == 0)
|
||||||
|
return lease;
|
||||||
|
}
|
||||||
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
if ((!lease->clid || !clid) &&
|
{
|
||||||
hw_len != 0 &&
|
#ifdef HAVE_DHCP6
|
||||||
lease->hwaddr_len == hw_len &&
|
if (lease->flags & (LEASE_TA | LEASE_NA))
|
||||||
lease->hwaddr_type == hw_type &&
|
continue;
|
||||||
memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
|
#endif
|
||||||
return lease;
|
if ((!lease->clid || !clid) &&
|
||||||
|
hw_len != 0 &&
|
||||||
|
lease->hwaddr_len == hw_len &&
|
||||||
|
lease->hwaddr_type == hw_type &&
|
||||||
|
memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
|
||||||
|
return lease;
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,23 +519,125 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
|
|||||||
struct dhcp_lease *lease;
|
struct dhcp_lease *lease;
|
||||||
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
if (lease->addr.s_addr == addr.s_addr)
|
{
|
||||||
return lease;
|
#ifdef HAVE_DHCP6
|
||||||
|
if (lease->flags & (LEASE_TA | LEASE_NA))
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
if (lease->addr.s_addr == addr.s_addr)
|
||||||
|
return lease;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
/* addr or clid may be NULL for "don't care, both NULL resets "USED" flags both
|
||||||
|
set activates USED check */
|
||||||
|
struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
|
||||||
|
int lease_type, int iaid, struct in6_addr *addr)
|
||||||
|
{
|
||||||
|
struct dhcp_lease *lease;
|
||||||
|
|
||||||
|
for (lease = leases; lease; lease = lease->next)
|
||||||
|
{
|
||||||
|
if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (clid && addr && (lease->flags & LEASE_USED))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (addr && memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (clid &&
|
||||||
|
(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 NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)
|
||||||
|
{
|
||||||
|
struct dhcp_lease *lease;
|
||||||
|
|
||||||
|
for (lease = leases; lease; lease = lease->next)
|
||||||
|
{
|
||||||
|
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (is_same_net6((struct in6_addr *)lease->hwaddr, net, prefix) &&
|
||||||
|
(prefix == 128 || addr6part((struct in6_addr *)lease->hwaddr) == addr))
|
||||||
|
return lease;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
struct dhcp_lease *lease_allocate(struct in_addr addr)
|
/* Find largest assigned address in context */
|
||||||
|
u64 lease_find_max_addr6(struct dhcp_context *context)
|
||||||
|
{
|
||||||
|
struct dhcp_lease *lease;
|
||||||
|
u64 addr = addr6part(&context->start6);
|
||||||
|
|
||||||
|
if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
|
||||||
|
for (lease = leases; lease; lease = lease->next)
|
||||||
|
{
|
||||||
|
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (is_same_net6((struct in6_addr *)lease->hwaddr, &context->start6, 64) &&
|
||||||
|
addr6part((struct in6_addr *)lease->hwaddr) > addr6part(&context->start6) &&
|
||||||
|
addr6part((struct in6_addr *)lease->hwaddr) <= addr6part(&context->end6) &&
|
||||||
|
addr6part((struct in6_addr *)lease->hwaddr) > addr)
|
||||||
|
addr = addr6part((struct in6_addr *)lease->hwaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Find largest assigned address in context */
|
||||||
|
struct in_addr lease_find_max_addr(struct dhcp_context *context)
|
||||||
|
{
|
||||||
|
struct dhcp_lease *lease;
|
||||||
|
struct in_addr addr = context->start;
|
||||||
|
|
||||||
|
if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
|
||||||
|
for (lease = leases; lease; lease = lease->next)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (lease->flags & (LEASE_TA | LEASE_NA))
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
|
||||||
|
((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) &&
|
||||||
|
((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr)))
|
||||||
|
addr = lease->addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dhcp_lease *lease_allocate(void)
|
||||||
{
|
{
|
||||||
struct dhcp_lease *lease;
|
struct dhcp_lease *lease;
|
||||||
if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
|
if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
memset(lease, 0, sizeof(struct dhcp_lease));
|
memset(lease, 0, sizeof(struct dhcp_lease));
|
||||||
lease->new = 1;
|
lease->flags = LEASE_NEW;
|
||||||
lease->addr = addr;
|
|
||||||
lease->hwaddr_len = 256; /* illegal value */
|
|
||||||
lease->expires = 1;
|
lease->expires = 1;
|
||||||
#ifdef HAVE_BROKEN_RTC
|
#ifdef HAVE_BROKEN_RTC
|
||||||
lease->length = 0xffffffff; /* illegal value */
|
lease->length = 0xffffffff; /* illegal value */
|
||||||
@@ -347,6 +651,26 @@ struct dhcp_lease *lease_allocate(struct in_addr addr)
|
|||||||
return lease;
|
return lease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct dhcp_lease *lease4_allocate(struct in_addr addr)
|
||||||
|
{
|
||||||
|
struct dhcp_lease *lease = lease_allocate();
|
||||||
|
lease->addr = addr;
|
||||||
|
lease->hwaddr_len = 256; /* illegal value */
|
||||||
|
|
||||||
|
return lease;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
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;
|
||||||
|
|
||||||
|
return lease;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
|
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
|
||||||
{
|
{
|
||||||
time_t exp = now + (time_t)len;
|
time_t exp = now + (time_t)len;
|
||||||
@@ -362,7 +686,8 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
|
|||||||
dns_dirty = 1;
|
dns_dirty = 1;
|
||||||
lease->expires = exp;
|
lease->expires = exp;
|
||||||
#ifndef HAVE_BROKEN_RTC
|
#ifndef HAVE_BROKEN_RTC
|
||||||
lease->aux_changed = file_dirty = 1;
|
lease->flags |= LEASE_AUX_CHANGED;
|
||||||
|
file_dirty = 1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,22 +695,33 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
|
|||||||
if (len != lease->length)
|
if (len != lease->length)
|
||||||
{
|
{
|
||||||
lease->length = len;
|
lease->length = len;
|
||||||
lease->aux_changed = file_dirty = 1;
|
lease->flags |= LEASE_AUX_CHANGED;
|
||||||
|
file_dirty = 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||||
unsigned char *clid, int hw_len, int hw_type, int clid_len)
|
unsigned char *clid, int hw_len, int hw_type, int clid_len, time_t now)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
int change = 0;
|
||||||
|
lease->flags |= LEASE_HAVE_HWADDR;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (hw_len != lease->hwaddr_len ||
|
if (hw_len != lease->hwaddr_len ||
|
||||||
hw_type != lease->hwaddr_type ||
|
hw_type != lease->hwaddr_type ||
|
||||||
(hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
|
(hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
|
||||||
{
|
{
|
||||||
memcpy(lease->hwaddr, hwaddr, hw_len);
|
if (hw_len != 0)
|
||||||
|
memcpy(lease->hwaddr, hwaddr, hw_len);
|
||||||
lease->hwaddr_len = hw_len;
|
lease->hwaddr_len = hw_len;
|
||||||
lease->hwaddr_type = hw_type;
|
lease->hwaddr_type = hw_type;
|
||||||
lease->changed = file_dirty = 1; /* run script on change */
|
lease->flags |= LEASE_CHANGED;
|
||||||
|
file_dirty = 1; /* run script on change */
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
change = 1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* only update clid when one is available, stops packets
|
/* only update clid when one is available, stops packets
|
||||||
@@ -398,18 +734,32 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
|||||||
|
|
||||||
if (lease->clid_len != clid_len)
|
if (lease->clid_len != clid_len)
|
||||||
{
|
{
|
||||||
lease->aux_changed = file_dirty = 1;
|
lease->flags |= LEASE_AUX_CHANGED;
|
||||||
|
file_dirty = 1;
|
||||||
free(lease->clid);
|
free(lease->clid);
|
||||||
if (!(lease->clid = whine_malloc(clid_len)))
|
if (!(lease->clid = whine_malloc(clid_len)))
|
||||||
return;
|
return;
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
change = 1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else if (memcmp(lease->clid, clid, clid_len) != 0)
|
else if (memcmp(lease->clid, clid, clid_len) != 0)
|
||||||
lease->aux_changed = file_dirty = 1;
|
{
|
||||||
|
lease->flags |= LEASE_AUX_CHANGED;
|
||||||
|
file_dirty = 1;
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
change = 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
lease->clid_len = clid_len;
|
lease->clid_len = clid_len;
|
||||||
memcpy(lease->clid, clid, clid_len);
|
memcpy(lease->clid, clid, clid_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (change)
|
||||||
|
slaac_add_addrs(lease, now);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kill_name(struct dhcp_lease *lease)
|
static void kill_name(struct dhcp_lease *lease)
|
||||||
@@ -421,7 +771,7 @@ static void kill_name(struct dhcp_lease *lease)
|
|||||||
free(lease->old_hostname);
|
free(lease->old_hostname);
|
||||||
|
|
||||||
/* If we know the fqdn, pass that. The helper will derive the
|
/* If we know the fqdn, pass that. The helper will derive the
|
||||||
unqualified name from it, free the unqulaified name here. */
|
unqualified name from it, free the unqualified name here. */
|
||||||
|
|
||||||
if (lease->fqdn)
|
if (lease->fqdn)
|
||||||
{
|
{
|
||||||
@@ -434,14 +784,18 @@ static void kill_name(struct dhcp_lease *lease)
|
|||||||
lease->hostname = lease->fqdn = NULL;
|
lease->hostname = lease->fqdn = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
|
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain)
|
||||||
{
|
{
|
||||||
struct dhcp_lease *lease_tmp;
|
struct dhcp_lease *lease_tmp;
|
||||||
char *new_name = NULL, *new_fqdn = NULL;
|
char *new_name = NULL, *new_fqdn = NULL;
|
||||||
|
|
||||||
|
if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
|
||||||
|
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, name);
|
||||||
|
|
||||||
if (lease->hostname && name && hostname_isequal(lease->hostname, name))
|
if (lease->hostname && name && hostname_isequal(lease->hostname, name))
|
||||||
{
|
{
|
||||||
lease->auth_name = auth;
|
if (auth)
|
||||||
|
lease->flags |= LEASE_AUTH_NAME;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,19 +805,21 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
|
|||||||
/* If a machine turns up on a new net without dropping the old lease,
|
/* If a machine turns up on a new net without dropping the old lease,
|
||||||
or two machines claim the same name, then we end up with two interfaces with
|
or two machines claim the same name, then we end up with two interfaces with
|
||||||
the same name. Check for that here and remove the name from the old lease.
|
the same name. Check for that here and remove the name from the old lease.
|
||||||
|
Note that IPv6 leases are different. All the leases to the same DUID are
|
||||||
|
allowed the same name.
|
||||||
|
|
||||||
Don't allow a name from the client to override a name from dnsmasq config. */
|
Don't allow a name from the client to override a name from dnsmasq config. */
|
||||||
|
|
||||||
if (name)
|
if (name)
|
||||||
{
|
{
|
||||||
if ((new_name = whine_malloc(strlen(name) + 1)))
|
if ((new_name = whine_malloc(strlen(name) + 1)))
|
||||||
{
|
{
|
||||||
char *suffix = get_domain(lease->addr);
|
|
||||||
strcpy(new_name, name);
|
strcpy(new_name, name);
|
||||||
if (suffix && (new_fqdn = whine_malloc(strlen(new_name) + strlen(suffix) + 2)))
|
if (domain && (new_fqdn = whine_malloc(strlen(new_name) + strlen(domain) + 2)))
|
||||||
{
|
{
|
||||||
strcpy(new_fqdn, name);
|
strcpy(new_fqdn, name);
|
||||||
strcat(new_fqdn, ".");
|
strcat(new_fqdn, ".");
|
||||||
strcat(new_fqdn, suffix);
|
strcat(new_fqdn, domain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,7 +828,7 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
|
|||||||
{
|
{
|
||||||
if (option_bool(OPT_DHCP_FQDN))
|
if (option_bool(OPT_DHCP_FQDN))
|
||||||
{
|
{
|
||||||
if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn) )
|
if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -480,8 +836,22 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
|
|||||||
if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
|
if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lease_tmp->auth_name && !auth)
|
if (lease->flags & (LEASE_TA | LEASE_NA))
|
||||||
|
{
|
||||||
|
if (!(lease_tmp->flags & (LEASE_TA | LEASE_NA)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* another lease for the same DUID is OK for IPv6 */
|
||||||
|
if (lease->clid_len == lease_tmp->clid_len &&
|
||||||
|
lease->clid && lease_tmp->clid &&
|
||||||
|
memcmp(lease->clid, lease_tmp->clid, lease->clid_len) == 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (lease_tmp->flags & (LEASE_TA | LEASE_NA))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((lease_tmp->flags & LEASE_AUTH_NAME) && !auth)
|
||||||
{
|
{
|
||||||
free(new_name);
|
free(new_name);
|
||||||
free(new_fqdn);
|
free(new_fqdn);
|
||||||
@@ -498,20 +868,26 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
|
|||||||
|
|
||||||
lease->hostname = new_name;
|
lease->hostname = new_name;
|
||||||
lease->fqdn = new_fqdn;
|
lease->fqdn = new_fqdn;
|
||||||
lease->auth_name = auth;
|
|
||||||
|
if (auth)
|
||||||
|
lease->flags |= LEASE_AUTH_NAME;
|
||||||
|
|
||||||
file_dirty = 1;
|
file_dirty = 1;
|
||||||
dns_dirty = 1;
|
dns_dirty = 1;
|
||||||
lease->changed = 1; /* run script on change */
|
lease->flags |= LEASE_CHANGED; /* run script on change */
|
||||||
}
|
}
|
||||||
|
|
||||||
void lease_set_interface(struct dhcp_lease *lease, int interface)
|
void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
|
||||||
{
|
{
|
||||||
if (lease->last_interface == interface)
|
if (lease->last_interface == interface)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lease->last_interface = interface;
|
lease->last_interface = interface;
|
||||||
lease->changed = 1;
|
lease->flags |= LEASE_CHANGED;
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
slaac_add_addrs(lease, now);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void rerun_scripts(void)
|
void rerun_scripts(void)
|
||||||
@@ -519,7 +895,7 @@ void rerun_scripts(void)
|
|||||||
struct dhcp_lease *lease;
|
struct dhcp_lease *lease;
|
||||||
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
lease->changed = 1;
|
lease->flags |= LEASE_CHANGED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* deleted leases get transferred to the old_leases list.
|
/* deleted leases get transferred to the old_leases list.
|
||||||
@@ -554,6 +930,14 @@ int do_script_run(time_t now)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
struct slaac_address *slaac, *tmp;
|
||||||
|
for (slaac = lease->slaac_address; slaac; slaac = tmp)
|
||||||
|
{
|
||||||
|
tmp = slaac->next;
|
||||||
|
free(slaac);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
kill_name(lease);
|
kill_name(lease);
|
||||||
#ifdef HAVE_SCRIPT
|
#ifdef HAVE_SCRIPT
|
||||||
queue_script(ACTION_DEL, lease, lease->old_hostname, now);
|
queue_script(ACTION_DEL, lease, lease->old_hostname, now);
|
||||||
@@ -585,18 +969,18 @@ int do_script_run(time_t now)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
if (lease->new || lease->changed ||
|
if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) ||
|
||||||
(lease->aux_changed && option_bool(OPT_LEASE_RO)))
|
((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)))
|
||||||
{
|
{
|
||||||
#ifdef HAVE_SCRIPT
|
#ifdef HAVE_SCRIPT
|
||||||
queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease,
|
queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
|
||||||
lease->fqdn ? lease->fqdn : lease->hostname, now);
|
lease->fqdn ? lease->fqdn : lease->hostname, now);
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_DBUS
|
#ifdef HAVE_DBUS
|
||||||
emit_dbus_signal(lease->new ? ACTION_ADD : ACTION_OLD, lease,
|
emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
|
||||||
lease->fqdn ? lease->fqdn : lease->hostname);
|
lease->fqdn ? lease->fqdn : lease->hostname);
|
||||||
#endif
|
#endif
|
||||||
lease->new = lease->changed = lease->aux_changed = 0;
|
lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED);
|
||||||
|
|
||||||
/* this is used for the "add" call, then junked, since they're not in the database */
|
/* this is used for the "add" call, then junked, since they're not in the database */
|
||||||
free(lease->extradata);
|
free(lease->extradata);
|
||||||
@@ -608,6 +992,44 @@ int do_script_run(time_t now)
|
|||||||
return 0; /* nothing to do */
|
return 0; /* nothing to do */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_SCRIPT
|
||||||
|
void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
/* check for embeded NULLs */
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
if (data[i] == 0)
|
||||||
|
{
|
||||||
|
len = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((lease->extradata_size - lease->extradata_len) < (len + 1))
|
||||||
|
{
|
||||||
|
size_t newsz = lease->extradata_len + len + 100;
|
||||||
|
unsigned char *new = whine_malloc(newsz);
|
||||||
|
|
||||||
|
if (!new)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (lease->extradata)
|
||||||
|
{
|
||||||
|
memcpy(new, lease->extradata, lease->extradata_len);
|
||||||
|
free(lease->extradata);
|
||||||
|
}
|
||||||
|
|
||||||
|
lease->extradata = new;
|
||||||
|
lease->extradata_size = newsz;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len != 0)
|
||||||
|
memcpy(lease->extradata + lease->extradata_len, data, len);
|
||||||
|
lease->extradata[lease->extradata_len + len] = delim;
|
||||||
|
lease->extradata_len += len + 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
# include <android/log.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Implement logging to /dev/log asynchronously. If syslogd is
|
/* Implement logging to /dev/log asynchronously. If syslogd is
|
||||||
making DNS lookups through dnsmasq, and dnsmasq blocks awaiting
|
making DNS lookups through dnsmasq, and dnsmasq blocks awaiting
|
||||||
syslogd, then the two daemons can deadlock. We get around this
|
syslogd, then the two daemons can deadlock. We get around this
|
||||||
@@ -80,7 +84,7 @@ int log_start(struct passwd *ent_pw, int errfd)
|
|||||||
|
|
||||||
if (!log_reopen(daemon->log_file))
|
if (!log_reopen(daemon->log_file))
|
||||||
{
|
{
|
||||||
send_event(errfd, EVENT_LOG_ERR, errno);
|
send_event(errfd, EVENT_LOG_ERR, errno, daemon->log_file ? daemon->log_file : "");
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +121,7 @@ int log_reopen(char *log_file)
|
|||||||
log_fd = open(log_file, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
|
log_fd = open(log_file, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef HAVE_SOLARIS_NETWORK
|
#if defined(HAVE_SOLARIS_NETWORK) || defined(__ANDROID__)
|
||||||
/* Solaris logging is "different", /dev/log is not unix-domain socket.
|
/* Solaris logging is "different", /dev/log is not unix-domain socket.
|
||||||
Just leave log_fd == -1 and use the vsyslog call for everything.... */
|
Just leave log_fd == -1 and use the vsyslog call for everything.... */
|
||||||
# define _PATH_LOG "" /* dummy */
|
# define _PATH_LOG "" /* dummy */
|
||||||
@@ -150,6 +154,19 @@ static void log_write(void)
|
|||||||
|
|
||||||
while (entries)
|
while (entries)
|
||||||
{
|
{
|
||||||
|
/* The data in the payoad is written with a terminating zero character
|
||||||
|
and the length reflects this. For a stream connection we need to
|
||||||
|
send the zero as a record terminator, but this isn't done for a
|
||||||
|
datagram connection, so treat the length as one less than reality
|
||||||
|
to elide the zero. If we're logging to a file, turn the zero into
|
||||||
|
a newline, and leave the length alone. */
|
||||||
|
int len_adjust = 0;
|
||||||
|
|
||||||
|
if (log_to_file)
|
||||||
|
entries->payload[entries->offset + entries->length - 1] = '\n';
|
||||||
|
else if (connection_type == SOCK_DGRAM)
|
||||||
|
len_adjust = 1;
|
||||||
|
|
||||||
/* Avoid duplicates over a fork() */
|
/* Avoid duplicates over a fork() */
|
||||||
if (entries->pid != getpid())
|
if (entries->pid != getpid())
|
||||||
{
|
{
|
||||||
@@ -159,11 +176,11 @@ static void log_write(void)
|
|||||||
|
|
||||||
connection_good = 1;
|
connection_good = 1;
|
||||||
|
|
||||||
if ((rc = write(log_fd, entries->payload + entries->offset, entries->length)) != -1)
|
if ((rc = write(log_fd, entries->payload + entries->offset, entries->length - len_adjust)) != -1)
|
||||||
{
|
{
|
||||||
entries->length -= rc;
|
entries->length -= rc;
|
||||||
entries->offset += rc;
|
entries->offset += rc;
|
||||||
if (entries->length == 0)
|
if (entries->length == len_adjust)
|
||||||
{
|
{
|
||||||
free_entry();
|
free_entry();
|
||||||
if (entries_lost != 0)
|
if (entries_lost != 0)
|
||||||
@@ -179,7 +196,7 @@ static void log_write(void)
|
|||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (errno == EAGAIN)
|
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||||
return; /* syslogd busy, go again when select() or poll() says so */
|
return; /* syslogd busy, go again when select() or poll() says so */
|
||||||
|
|
||||||
if (errno == ENOBUFS)
|
if (errno == ENOBUFS)
|
||||||
@@ -227,7 +244,8 @@ static void log_write(void)
|
|||||||
errno == ECONNREFUSED ||
|
errno == ECONNREFUSED ||
|
||||||
errno == EISCONN ||
|
errno == EISCONN ||
|
||||||
errno == EINTR ||
|
errno == EINTR ||
|
||||||
errno == EAGAIN)
|
errno == EAGAIN ||
|
||||||
|
errno == EWOULDBLOCK)
|
||||||
{
|
{
|
||||||
/* try again on next syslog() call */
|
/* try again on next syslog() call */
|
||||||
connection_good = 0;
|
connection_good = 0;
|
||||||
@@ -289,8 +307,28 @@ void my_syslog(int priority, const char *format, ...)
|
|||||||
|
|
||||||
if (log_fd == -1)
|
if (log_fd == -1)
|
||||||
{
|
{
|
||||||
/* fall-back to syslog if we die during startup or fail during running. */
|
#ifdef __ANDROID__
|
||||||
|
/* do android-specific logging.
|
||||||
|
log_fd is always -1 on Android except when logging to a file. */
|
||||||
|
int alog_lvl;
|
||||||
|
|
||||||
|
if (priority <= LOG_ERR)
|
||||||
|
alog_lvl = ANDROID_LOG_ERROR;
|
||||||
|
else if (priority == LOG_WARNING)
|
||||||
|
alog_lvl = ANDROID_LOG_WARN;
|
||||||
|
else if (priority <= LOG_INFO)
|
||||||
|
alog_lvl = ANDROID_LOG_INFO;
|
||||||
|
else
|
||||||
|
alog_lvl = ANDROID_LOG_DEBUG;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
__android_log_vprint(alog_lvl, "dnsmasq", format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
#else
|
||||||
|
/* fall-back to syslog if we die during startup or
|
||||||
|
fail during running (always on Solaris). */
|
||||||
static int isopen = 0;
|
static int isopen = 0;
|
||||||
|
|
||||||
if (!isopen)
|
if (!isopen)
|
||||||
{
|
{
|
||||||
openlog("dnsmasq", LOG_PID, log_fac);
|
openlog("dnsmasq", LOG_PID, log_fac);
|
||||||
@@ -299,6 +337,8 @@ void my_syslog(int priority, const char *format, ...)
|
|||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
vsyslog(priority, format, ap);
|
vsyslog(priority, format, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
#endif
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,10 +380,6 @@ void my_syslog(int priority, const char *format, ...)
|
|||||||
entry->length = len > MAX_MESSAGE ? MAX_MESSAGE : len;
|
entry->length = len > MAX_MESSAGE ? MAX_MESSAGE : len;
|
||||||
entry->offset = 0;
|
entry->offset = 0;
|
||||||
entry->pid = pid;
|
entry->pid = pid;
|
||||||
|
|
||||||
/* replace terminator with \n */
|
|
||||||
if (log_to_file)
|
|
||||||
entry->payload[entry->length - 1] = '\n';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* almost always, logging won't block, so try and write this now,
|
/* almost always, logging won't block, so try and write this now,
|
||||||
|
|||||||
+61
-14
@@ -1,4 +1,4 @@
|
|||||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -34,6 +34,7 @@
|
|||||||
# define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
|
# define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static struct iovec iov;
|
static struct iovec iov;
|
||||||
static u32 netlink_pid;
|
static u32 netlink_pid;
|
||||||
|
|
||||||
@@ -127,13 +128,15 @@ static ssize_t netlink_recv(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* family = AF_UNSPEC finds ARP table entries. */
|
/* family = AF_UNSPEC finds ARP table entries.
|
||||||
|
family = AF_LOCAL finds MAC addresses. */
|
||||||
int iface_enumerate(int family, void *parm, int (*callback)())
|
int iface_enumerate(int family, void *parm, int (*callback)())
|
||||||
{
|
{
|
||||||
struct sockaddr_nl addr;
|
struct sockaddr_nl addr;
|
||||||
struct nlmsghdr *h;
|
struct nlmsghdr *h;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
static unsigned int seq = 0;
|
static unsigned int seq = 0;
|
||||||
|
int callback_ok = 1;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct nlmsghdr nlh;
|
struct nlmsghdr nlh;
|
||||||
@@ -144,10 +147,16 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
addr.nl_pad = 0;
|
addr.nl_pad = 0;
|
||||||
addr.nl_groups = 0;
|
addr.nl_groups = 0;
|
||||||
addr.nl_pid = 0; /* address to kernel */
|
addr.nl_pid = 0; /* address to kernel */
|
||||||
|
|
||||||
|
again:
|
||||||
|
if (family == AF_UNSPEC)
|
||||||
|
req.nlh.nlmsg_type = RTM_GETNEIGH;
|
||||||
|
else if (family == AF_LOCAL)
|
||||||
|
req.nlh.nlmsg_type = RTM_GETLINK;
|
||||||
|
else
|
||||||
|
req.nlh.nlmsg_type = RTM_GETADDR;
|
||||||
|
|
||||||
again:
|
|
||||||
req.nlh.nlmsg_len = sizeof(req);
|
req.nlh.nlmsg_len = sizeof(req);
|
||||||
req.nlh.nlmsg_type = family == AF_UNSPEC ? RTM_GETNEIGH : RTM_GETADDR;
|
|
||||||
req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST | NLM_F_ACK;
|
req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST | NLM_F_ACK;
|
||||||
req.nlh.nlmsg_pid = 0;
|
req.nlh.nlmsg_pid = 0;
|
||||||
req.nlh.nlmsg_seq = ++seq;
|
req.nlh.nlmsg_seq = ++seq;
|
||||||
@@ -178,8 +187,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
else if (h->nlmsg_type == NLMSG_ERROR)
|
else if (h->nlmsg_type == NLMSG_ERROR)
|
||||||
nl_err(h);
|
nl_err(h);
|
||||||
else if (h->nlmsg_type == NLMSG_DONE)
|
else if (h->nlmsg_type == NLMSG_DONE)
|
||||||
return 1;
|
return callback_ok;
|
||||||
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC)
|
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
|
||||||
{
|
{
|
||||||
struct ifaddrmsg *ifa = NLMSG_DATA(h);
|
struct ifaddrmsg *ifa = NLMSG_DATA(h);
|
||||||
struct rtattr *rta = IFA_RTA(ifa);
|
struct rtattr *rta = IFA_RTA(ifa);
|
||||||
@@ -205,9 +214,9 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
rta = RTA_NEXT(rta, len1);
|
rta = RTA_NEXT(rta, len1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr.s_addr)
|
if (addr.s_addr && callback_ok)
|
||||||
if (!((*callback)(addr, ifa->ifa_index, netmask, broadcast, parm)))
|
if (!((*callback)(addr, ifa->ifa_index, netmask, broadcast, parm)))
|
||||||
return 0;
|
callback_ok = 0;
|
||||||
}
|
}
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else if (ifa->ifa_family == AF_INET6)
|
else if (ifa->ifa_family == AF_INET6)
|
||||||
@@ -221,9 +230,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
rta = RTA_NEXT(rta, len1);
|
rta = RTA_NEXT(rta, len1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addrp)
|
if (addrp && callback_ok)
|
||||||
if (!((*callback)(addrp, ifa->ifa_index, ifa->ifa_index, parm)))
|
if (!((*callback)(addrp, (int)(ifa->ifa_prefixlen), (int)(ifa->ifa_scope),
|
||||||
return 0;
|
(int)(ifa->ifa_index), (int)(ifa->ifa_flags & IFA_F_TENTATIVE), parm)))
|
||||||
|
callback_ok = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -249,10 +259,35 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
rta = RTA_NEXT(rta, len1);
|
rta = RTA_NEXT(rta, len1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inaddr && mac)
|
if (inaddr && mac && callback_ok)
|
||||||
if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
|
if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
|
||||||
return 0;
|
callback_ok = 0;
|
||||||
}
|
}
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
else if (h->nlmsg_type == RTM_NEWLINK && family == AF_LOCAL)
|
||||||
|
{
|
||||||
|
struct ifinfomsg *link = NLMSG_DATA(h);
|
||||||
|
struct rtattr *rta = IFLA_RTA(link);
|
||||||
|
unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*link));
|
||||||
|
char *mac = NULL;
|
||||||
|
size_t maclen = 0;
|
||||||
|
|
||||||
|
while (RTA_OK(rta, len1))
|
||||||
|
{
|
||||||
|
if (rta->rta_type == IFLA_ADDRESS)
|
||||||
|
{
|
||||||
|
maclen = rta->rta_len - sizeof(struct rtattr);
|
||||||
|
mac = (char *)(rta+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
rta = RTA_NEXT(rta, len1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mac && callback_ok && !((link->ifi_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) &&
|
||||||
|
!((*callback)((int)link->ifi_index, (unsigned int)link->ifi_type, mac, maclen, parm)))
|
||||||
|
callback_ok = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,6 +341,18 @@ static void nl_routechange(struct nlmsghdr *h)
|
|||||||
/* Force re-reading resolv file right now, for luck. */
|
/* Force re-reading resolv file right now, for luck. */
|
||||||
daemon->last_resolv = 0;
|
daemon->last_resolv = 0;
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (daemon->srv_save)
|
if (daemon->srv_save)
|
||||||
{
|
{
|
||||||
if (daemon->srv_save->sfd)
|
if (daemon->srv_save->sfd)
|
||||||
|
|||||||
+144
-132
@@ -1,4 +1,4 @@
|
|||||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
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
|
#endif
|
||||||
|
|
||||||
int iface_check(int family, struct all_addr *addr, char *name, int *indexp)
|
int iface_check(int family, struct all_addr *addr, char *name)
|
||||||
{
|
{
|
||||||
struct iname *tmp;
|
struct iname *tmp;
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
@@ -115,7 +115,7 @@ int iface_check(int family, struct all_addr *addr, char *name, int *indexp)
|
|||||||
/* Note: have to check all and not bail out early, so that we set the
|
/* Note: have to check all and not bail out early, so that we set the
|
||||||
"used" flags. */
|
"used" flags. */
|
||||||
|
|
||||||
if (daemon->if_names || (addr && daemon->if_addrs))
|
if (daemon->if_names || daemon->if_addrs)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
struct dhcp_context *range;
|
struct dhcp_context *range;
|
||||||
@@ -134,7 +134,7 @@ int iface_check(int family, struct all_addr *addr, char *name, int *indexp)
|
|||||||
ret = tmp->used = 1;
|
ret = tmp->used = 1;
|
||||||
|
|
||||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||||
if (addr && tmp->addr.sa.sa_family == family)
|
if (tmp->addr.sa.sa_family == family)
|
||||||
{
|
{
|
||||||
if (family == AF_INET &&
|
if (family == AF_INET &&
|
||||||
tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
|
tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
|
||||||
@@ -151,43 +151,12 @@ int iface_check(int family, struct all_addr *addr, char *name, int *indexp)
|
|||||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||||
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
if (indexp)
|
|
||||||
{
|
|
||||||
/* One form of bridging on BSD has the property that packets
|
|
||||||
can be recieved on bridge interfaces which do not have an IP address.
|
|
||||||
We allow these to be treated as aliases of another interface which does have
|
|
||||||
an IP address with --dhcp-bridge=interface,alias,alias */
|
|
||||||
struct dhcp_bridge *bridge, *alias;
|
|
||||||
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
|
|
||||||
{
|
|
||||||
for (alias = bridge->alias; alias; alias = alias->next)
|
|
||||||
if (strncmp(name, alias->iface, IF_NAMESIZE) == 0)
|
|
||||||
{
|
|
||||||
int newindex;
|
|
||||||
|
|
||||||
if (!(newindex = if_nametoindex(bridge->iface)))
|
|
||||||
{
|
|
||||||
my_syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*indexp = newindex;
|
|
||||||
strncpy(name, bridge->iface, IF_NAMESIZE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (alias)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int iface_allowed(struct irec **irecp, int if_index,
|
static int iface_allowed(struct irec **irecp, int if_index,
|
||||||
union mysockaddr *addr, struct in_addr netmask)
|
union mysockaddr *addr, struct in_addr netmask, int dad)
|
||||||
{
|
{
|
||||||
struct irec *iface;
|
struct irec *iface;
|
||||||
int fd, mtu = 0, loopback;
|
int fd, mtu = 0, loopback;
|
||||||
@@ -202,8 +171,11 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
|||||||
we call this routine multiple times. */
|
we call this routine multiple times. */
|
||||||
for (iface = *irecp; iface; iface = iface->next)
|
for (iface = *irecp; iface; iface = iface->next)
|
||||||
if (sockaddr_isequal(&iface->addr, addr))
|
if (sockaddr_isequal(&iface->addr, addr))
|
||||||
return 1;
|
{
|
||||||
|
iface->dad = dad;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
|
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
|
||||||
!indextoname(fd, if_index, ifr.ifr_name) ||
|
!indextoname(fd, if_index, ifr.ifr_name) ||
|
||||||
ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
|
ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
|
||||||
@@ -260,7 +232,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
|||||||
if (!ir)
|
if (!ir)
|
||||||
{
|
{
|
||||||
if (addr->sa.sa_family == AF_INET &&
|
if (addr->sa.sa_family == AF_INET &&
|
||||||
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name, NULL))
|
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
@@ -271,7 +243,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
|||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if (addr->sa.sa_family == AF_INET6 &&
|
if (addr->sa.sa_family == AF_INET6 &&
|
||||||
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name, NULL))
|
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name))
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -283,6 +255,8 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
|||||||
iface->netmask = netmask;
|
iface->netmask = netmask;
|
||||||
iface->tftp_ok = tftp_ok;
|
iface->tftp_ok = tftp_ok;
|
||||||
iface->mtu = mtu;
|
iface->mtu = mtu;
|
||||||
|
iface->dad = dad;
|
||||||
|
iface->done = 0;
|
||||||
if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
|
if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
|
||||||
strcpy(iface->name, ifr.ifr_name);
|
strcpy(iface->name, ifr.ifr_name);
|
||||||
iface->next = *irecp;
|
iface->next = *irecp;
|
||||||
@@ -295,13 +269,15 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
static int iface_allowed_v6(struct in6_addr *local,
|
static int iface_allowed_v6(struct in6_addr *local, int prefix,
|
||||||
int scope, int if_index, void *vparam)
|
int scope, int if_index, int dad, void *vparam)
|
||||||
{
|
{
|
||||||
union mysockaddr addr;
|
union mysockaddr addr;
|
||||||
struct in_addr netmask; /* dummy */
|
struct in_addr netmask; /* dummy */
|
||||||
|
|
||||||
netmask.s_addr = 0;
|
netmask.s_addr = 0;
|
||||||
|
|
||||||
|
(void)prefix; /* warning */
|
||||||
|
(void)scope; /* warning */
|
||||||
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
@@ -310,9 +286,9 @@ static int iface_allowed_v6(struct in6_addr *local,
|
|||||||
addr.in6.sin6_family = AF_INET6;
|
addr.in6.sin6_family = AF_INET6;
|
||||||
addr.in6.sin6_addr = *local;
|
addr.in6.sin6_addr = *local;
|
||||||
addr.in6.sin6_port = htons(daemon->port);
|
addr.in6.sin6_port = htons(daemon->port);
|
||||||
addr.in6.sin6_scope_id = scope;
|
addr.in6.sin6_scope_id = if_index;
|
||||||
|
|
||||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask);
|
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, dad);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -330,7 +306,7 @@ static int iface_allowed_v4(struct in_addr local, int if_index,
|
|||||||
addr.in.sin_addr = local;
|
addr.in.sin_addr = local;
|
||||||
addr.in.sin_port = htons(daemon->port);
|
addr.in.sin_port = htons(daemon->port);
|
||||||
|
|
||||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask);
|
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int enumerate_interfaces(void)
|
int enumerate_interfaces(void)
|
||||||
@@ -355,13 +331,10 @@ int fix_fd(int fd)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int make_sock(union mysockaddr *addr, int type)
|
static int make_sock(union mysockaddr *addr, int type, int dienow)
|
||||||
{
|
{
|
||||||
int family = addr->sa.sa_family;
|
int family = addr->sa.sa_family;
|
||||||
int fd, rc, opt = 1;
|
int fd, rc, opt = 1;
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
static int dad_count = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ((fd = socket(family, type, 0)) == -1)
|
if ((fd = socket(family, type, 0)) == -1)
|
||||||
{
|
{
|
||||||
@@ -374,42 +347,27 @@ static int make_sock(union mysockaddr *addr, int type)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
port = prettyprint_addr(addr, daemon->namebuff);
|
if (dienow)
|
||||||
if (!option_bool(OPT_NOWILD))
|
{
|
||||||
sprintf(daemon->namebuff, "port %d", port);
|
port = prettyprint_addr(addr, daemon->namebuff);
|
||||||
die(_("failed to create listening socket for %s: %s"),
|
if (!option_bool(OPT_NOWILD))
|
||||||
daemon->namebuff, EC_BADNET);
|
sprintf(daemon->namebuff, "port %d", port);
|
||||||
|
die(_("failed to create listening socket for %s: %s"),
|
||||||
|
daemon->namebuff, EC_BADNET);
|
||||||
|
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || !fix_fd(fd))
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || !fix_fd(fd))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if (family == AF_INET6 && setsockopt(fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
|
if (family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
|
||||||
goto err;
|
goto err;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (1)
|
if ((rc = bind(fd, (struct sockaddr *)addr, sa_len(addr))) == -1)
|
||||||
{
|
|
||||||
if ((rc = bind(fd, (struct sockaddr *)addr, sa_len(addr))) != -1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
/* An interface may have an IPv6 address which is still undergoing DAD.
|
|
||||||
If so, the bind will fail until the DAD completes, so we try over 20 seconds
|
|
||||||
before failing. */
|
|
||||||
if (family == AF_INET6 &&
|
|
||||||
(errno == ENODEV || errno == EADDRNOTAVAIL) &&
|
|
||||||
dad_count++ < DAD_WAIT)
|
|
||||||
{
|
|
||||||
sleep(1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc == -1)
|
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (type == SOCK_STREAM)
|
if (type == SOCK_STREAM)
|
||||||
@@ -422,7 +380,7 @@ static int make_sock(union mysockaddr *addr, int type)
|
|||||||
if (family == AF_INET)
|
if (family == AF_INET)
|
||||||
{
|
{
|
||||||
#if defined(HAVE_LINUX_NETWORK)
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
if (setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1)
|
if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1)
|
||||||
goto err;
|
goto err;
|
||||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||||
if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
||||||
@@ -431,46 +389,52 @@ static int make_sock(union mysockaddr *addr, int type)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else
|
else if (!set_ipv6pktinfo(fd))
|
||||||
{
|
goto err;
|
||||||
/* The API changed around Linux 2.6.14 but the old ABI is still supported:
|
|
||||||
handle all combinations of headers and kernel.
|
|
||||||
OpenWrt note that this fixes the problem addressed by your very broken patch. */
|
|
||||||
daemon->v6pktinfo = IPV6_PKTINFO;
|
|
||||||
|
|
||||||
# ifdef IPV6_RECVPKTINFO
|
|
||||||
# ifdef IPV6_2292PKTINFO
|
|
||||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1)
|
|
||||||
{
|
|
||||||
if (errno == ENOPROTOOPT && setsockopt(fd, IPV6_LEVEL, IPV6_2292PKTINFO, &opt, sizeof(opt)) != -1)
|
|
||||||
daemon->v6pktinfo = IPV6_2292PKTINFO;
|
|
||||||
else
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
# else
|
|
||||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1)
|
|
||||||
goto err;
|
|
||||||
# endif
|
|
||||||
# else
|
|
||||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1)
|
|
||||||
goto err;
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
int set_ipv6pktinfo(int fd)
|
||||||
|
{
|
||||||
|
int opt = 1;
|
||||||
|
|
||||||
|
/* The API changed around Linux 2.6.14 but the old ABI is still supported:
|
||||||
|
handle all combinations of headers and kernel.
|
||||||
|
OpenWrt note that this fixes the problem addressed by your very broken patch. */
|
||||||
|
daemon->v6pktinfo = IPV6_PKTINFO;
|
||||||
|
|
||||||
|
#ifdef IPV6_RECVPKTINFO
|
||||||
|
if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt, sizeof(opt)) != -1)
|
||||||
|
return 1;
|
||||||
|
# ifdef IPV6_2292PKTINFO
|
||||||
|
else if (errno == ENOPROTOOPT && setsockopt(fd, IPPROTO_IPV6, IPV6_2292PKTINFO, &opt, sizeof(opt)) != -1)
|
||||||
|
{
|
||||||
|
daemon->v6pktinfo = IPV6_2292PKTINFO;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &opt, sizeof(opt)) != -1)
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct listener *create_listeners(union mysockaddr *addr, int do_tftp)
|
static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, int dienow)
|
||||||
{
|
{
|
||||||
struct listener *l = NULL;
|
struct listener *l = NULL;
|
||||||
int fd = -1, tcpfd = -1, tftpfd = -1;
|
int fd = -1, tcpfd = -1, tftpfd = -1;
|
||||||
|
|
||||||
if (daemon->port != 0)
|
if (daemon->port != 0)
|
||||||
{
|
{
|
||||||
fd = make_sock(addr, SOCK_DGRAM);
|
fd = make_sock(addr, SOCK_DGRAM, dienow);
|
||||||
tcpfd = make_sock(addr, SOCK_STREAM);
|
tcpfd = make_sock(addr, SOCK_STREAM, dienow);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_TFTP
|
#ifdef HAVE_TFTP
|
||||||
@@ -481,7 +445,7 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp)
|
|||||||
/* port must be restored to DNS port for TCP code */
|
/* port must be restored to DNS port for TCP code */
|
||||||
short save = addr->in.sin_port;
|
short save = addr->in.sin_port;
|
||||||
addr->in.sin_port = htons(TFTP_PORT);
|
addr->in.sin_port = htons(TFTP_PORT);
|
||||||
tftpfd = make_sock(addr, SOCK_DGRAM);
|
tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
|
||||||
addr->in.sin_port = save;
|
addr->in.sin_port = save;
|
||||||
}
|
}
|
||||||
# ifdef HAVE_IPV6
|
# ifdef HAVE_IPV6
|
||||||
@@ -489,7 +453,7 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp)
|
|||||||
{
|
{
|
||||||
short save = addr->in6.sin6_port;
|
short save = addr->in6.sin6_port;
|
||||||
addr->in6.sin6_port = htons(TFTP_PORT);
|
addr->in6.sin6_port = htons(TFTP_PORT);
|
||||||
tftpfd = make_sock(addr, SOCK_DGRAM);
|
tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
|
||||||
addr->in6.sin6_port = save;
|
addr->in6.sin6_port = save;
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
@@ -509,7 +473,7 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp)
|
|||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct listener *create_wildcard_listeners(void)
|
void create_wildcard_listeners(void)
|
||||||
{
|
{
|
||||||
union mysockaddr addr;
|
union mysockaddr addr;
|
||||||
struct listener *l;
|
struct listener *l;
|
||||||
@@ -523,7 +487,7 @@ struct listener *create_wildcard_listeners(void)
|
|||||||
addr.in.sin_addr.s_addr = INADDR_ANY;
|
addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||||
addr.in.sin_port = htons(daemon->port);
|
addr.in.sin_port = htons(daemon->port);
|
||||||
|
|
||||||
l = create_listeners(&addr, tftp_enabled);
|
l = create_listeners(&addr, tftp_enabled, 1);
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
@@ -535,31 +499,61 @@ struct listener *create_wildcard_listeners(void)
|
|||||||
addr.in6.sin6_port = htons(daemon->port);
|
addr.in6.sin6_port = htons(daemon->port);
|
||||||
|
|
||||||
if (l)
|
if (l)
|
||||||
l->next = create_listeners(&addr, tftp_enabled);
|
l->next = create_listeners(&addr, tftp_enabled, 1);
|
||||||
else
|
else
|
||||||
l = create_listeners(&addr, tftp_enabled);
|
l = create_listeners(&addr, tftp_enabled, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return l;
|
daemon->listeners = l;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct listener *create_bound_listeners(void)
|
void create_bound_listeners(int dienow)
|
||||||
{
|
{
|
||||||
struct listener *new, *listeners = NULL;
|
struct listener *new;
|
||||||
struct irec *iface;
|
struct irec *iface;
|
||||||
|
struct iname *if_tmp;
|
||||||
|
|
||||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||||
if ((new = create_listeners(&iface->addr, iface->tftp_ok)))
|
if (!iface->done && !iface->dad &&
|
||||||
|
(new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
|
||||||
{
|
{
|
||||||
new->iface = iface;
|
new->iface = iface;
|
||||||
new->next = listeners;
|
new->next = daemon->listeners;
|
||||||
listeners = new;
|
daemon->listeners = new;
|
||||||
|
iface->done = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for --listen-address options that haven't been used because there's
|
||||||
|
no interface with a matching address. These may be valid: eg it's possible
|
||||||
|
to listen on 127.0.1.1 even if the loopback interface is 127.0.0.1
|
||||||
|
|
||||||
|
If the address isn't valid the bind() will fail and we'll die().
|
||||||
|
|
||||||
|
The resulting listeners have the ->iface field NULL, and this has to be
|
||||||
|
handled by the DNS and TFTP code. It disables --localise-queries processing
|
||||||
|
(no netmask) and some MTU login the tftp code. */
|
||||||
|
|
||||||
|
for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
|
||||||
|
if (!if_tmp->used &&
|
||||||
|
(new = create_listeners(&if_tmp->addr, 1, dienow)))
|
||||||
|
{
|
||||||
|
new->iface = NULL;
|
||||||
|
new->next = daemon->listeners;
|
||||||
|
daemon->listeners = new;
|
||||||
}
|
}
|
||||||
|
|
||||||
return listeners;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int is_dad_listeners(void)
|
||||||
|
{
|
||||||
|
struct irec *iface;
|
||||||
|
|
||||||
|
if (option_bool(OPT_NOWILD))
|
||||||
|
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||||
|
if (iface->dad && !iface->done)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
/* return a UDP socket bound to a random port, have to cope with straying into
|
/* return a UDP socket bound to a random port, have to cope with straying into
|
||||||
occupied port nos and reserved ones. */
|
occupied port nos and reserved ones. */
|
||||||
int random_sock(int family)
|
int random_sock(int family)
|
||||||
@@ -896,20 +890,38 @@ int reload_servers(char *fname)
|
|||||||
source_addr.in.sin_port = htons(daemon->query_port);
|
source_addr.in.sin_port = htons(daemon->query_port);
|
||||||
}
|
}
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0)
|
else
|
||||||
{
|
{
|
||||||
|
int scope_index = 0;
|
||||||
|
char *scope_id = strchr(token, '%');
|
||||||
|
|
||||||
|
if (scope_id)
|
||||||
|
{
|
||||||
|
*(scope_id++) = 0;
|
||||||
|
scope_index = if_nametoindex(scope_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0)
|
||||||
|
{
|
||||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(source_addr.in6);
|
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(source_addr.in6);
|
||||||
#endif
|
#endif
|
||||||
source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
|
source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
|
||||||
addr.in6.sin6_port = htons(NAMESERVER_PORT);
|
source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = 0;
|
||||||
source_addr.in6.sin6_addr = in6addr_any;
|
addr.in6.sin6_port = htons(NAMESERVER_PORT);
|
||||||
source_addr.in6.sin6_port = htons(daemon->query_port);
|
addr.in6.sin6_scope_id = scope_index;
|
||||||
|
source_addr.in6.sin6_addr = in6addr_any;
|
||||||
|
source_addr.in6.sin6_port = htons(daemon->query_port);
|
||||||
|
source_addr.in6.sin6_scope_id = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
#endif /* IPV6 */
|
#else /* IPV6 */
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (old_servers)
|
if (old_servers)
|
||||||
{
|
{
|
||||||
serv = old_servers;
|
serv = old_servers;
|
||||||
|
|||||||
+602
-281
File diff suppressed because it is too large.
Load diff
+108
@@ -0,0 +1,108 @@
|
|||||||
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 dated June, 1991, or
|
||||||
|
(at your option) version 3 dated 29 June, 2007.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
|
||||||
|
static size_t outpacket_counter;
|
||||||
|
|
||||||
|
void end_opt6(int container)
|
||||||
|
{
|
||||||
|
void *p = daemon->outpacket.iov_base + container + 2;
|
||||||
|
u16 len = outpacket_counter - container - 4 ;
|
||||||
|
|
||||||
|
PUTSHORT(len, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
int save_counter(int newval)
|
||||||
|
{
|
||||||
|
int ret = outpacket_counter;
|
||||||
|
if (newval != -1)
|
||||||
|
outpacket_counter = newval;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *expand(size_t headroom)
|
||||||
|
{
|
||||||
|
void *ret;
|
||||||
|
|
||||||
|
if (expand_buf(&daemon->outpacket, outpacket_counter + headroom))
|
||||||
|
{
|
||||||
|
ret = daemon->outpacket.iov_base + outpacket_counter;
|
||||||
|
outpacket_counter += headroom;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int new_opt6(int opt)
|
||||||
|
{
|
||||||
|
int ret = outpacket_counter;
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if ((p = expand(4)))
|
||||||
|
{
|
||||||
|
PUTSHORT(opt, p);
|
||||||
|
PUTSHORT(0, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *put_opt6(void *data, size_t len)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if ((p = expand(len)))
|
||||||
|
memcpy(p, data, len);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void put_opt6_long(unsigned int val)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if ((p = expand(4)))
|
||||||
|
PUTLONG(val, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void put_opt6_short(unsigned int val)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if ((p = expand(2)))
|
||||||
|
PUTSHORT(val, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void put_opt6_char(unsigned int val)
|
||||||
|
{
|
||||||
|
unsigned char *p;
|
||||||
|
|
||||||
|
if ((p = expand(1)))
|
||||||
|
*p = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void put_opt6_string(char *s)
|
||||||
|
{
|
||||||
|
put_opt6(s, strlen(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 dated June, 1991, or
|
||||||
|
(at your option) version 3 dated 29 June, 2007.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ALL_HOSTS "FF02::1"
|
||||||
|
#define ALL_ROUTERS "FF02::2"
|
||||||
|
|
||||||
|
struct ping_packet {
|
||||||
|
u8 type, code;
|
||||||
|
u16 checksum;
|
||||||
|
u16 identifier;
|
||||||
|
u16 sequence_no;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ra_packet {
|
||||||
|
u8 type, code;
|
||||||
|
u16 checksum;
|
||||||
|
u8 hop_limit, flags;
|
||||||
|
u16 lifetime;
|
||||||
|
u32 reachable_time;
|
||||||
|
u32 retrans_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct prefix_opt {
|
||||||
|
u8 type, len, prefix_len, flags;
|
||||||
|
u32 valid_lifetime, preferred_lifetime, reserved;
|
||||||
|
struct in6_addr prefix;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ICMP6_OPT_SOURCE_MAC 1
|
||||||
|
#define ICMP6_OPT_PREFIX 3
|
||||||
|
#define ICMP6_OPT_MTU 5
|
||||||
|
#define ICMP6_OPT_RDNSS 25
|
||||||
|
#define ICMP6_OPT_DNSSL 31
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+529
@@ -0,0 +1,529 @@
|
|||||||
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 dated June, 1991, or
|
||||||
|
(at your option) version 3 dated 29 June, 2007.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* NB. This code may be called during a DHCPv4 or transaction which is in ping-wait
|
||||||
|
It therefore cannot use any DHCP buffer resources except outpacket, which is
|
||||||
|
not used by DHCPv4 code. This code may also be called when DHCP 4 or 6 isn't
|
||||||
|
active, so we ensure that outpacket is allocated here too */
|
||||||
|
|
||||||
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
|
||||||
|
#include <netinet/icmp6.h>
|
||||||
|
|
||||||
|
struct ra_param {
|
||||||
|
int ind, managed, other, found_context, first;
|
||||||
|
char *if_name;
|
||||||
|
struct dhcp_netid *tags;
|
||||||
|
struct in6_addr link_local;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct search_param {
|
||||||
|
time_t now; int iface;
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
static int iface_search(struct in6_addr *local, int prefix,
|
||||||
|
int scope, int if_index, int dad, 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)
|
||||||
|
{
|
||||||
|
struct icmp6_filter filter;
|
||||||
|
int fd;
|
||||||
|
#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
|
||||||
|
int class = IPTOS_CLASS_CS6;
|
||||||
|
#endif
|
||||||
|
int val = 255; /* radvd uses this value */
|
||||||
|
socklen_t len = sizeof(int);
|
||||||
|
struct dhcp_context *context;
|
||||||
|
|
||||||
|
/* ensure this is around even if we're not doing DHCPv6 */
|
||||||
|
expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
|
||||||
|
|
||||||
|
/* See if we're guessing SLAAC addresses, if so we need to recieve ping replies */
|
||||||
|
for (context = daemon->ra_contexts; context; context = context->next)
|
||||||
|
if ((context->flags & CONTEXT_RA_NAME))
|
||||||
|
break;
|
||||||
|
|
||||||
|
ICMP6_FILTER_SETBLOCKALL(&filter);
|
||||||
|
ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
|
||||||
|
if (context)
|
||||||
|
ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
|
||||||
|
|
||||||
|
if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 ||
|
||||||
|
getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
|
||||||
|
#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
|
||||||
|
setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
|
||||||
|
#endif
|
||||||
|
!fix_fd(fd) ||
|
||||||
|
!set_ipv6pktinfo(fd) ||
|
||||||
|
setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val)) ||
|
||||||
|
setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val)) ||
|
||||||
|
setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) == -1)
|
||||||
|
die (_("cannot create ICMPv6 socket: %s"), NULL, EC_BADNET);
|
||||||
|
|
||||||
|
daemon->icmp6fd = fd;
|
||||||
|
|
||||||
|
ra_start_unsolicted(now, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ra_start_unsolicted(time_t now, struct dhcp_context *context)
|
||||||
|
{
|
||||||
|
/* init timers so that we do ra's for some/all soon. some ra_times will end up zeroed
|
||||||
|
if it's not appropriate to advertise those contexts.
|
||||||
|
This gets re-called on a netlink route-change to re-do the advertisement
|
||||||
|
and pick up new interfaces */
|
||||||
|
|
||||||
|
if (context)
|
||||||
|
context->ra_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void icmp6_packet(void)
|
||||||
|
{
|
||||||
|
char interface[IF_NAMESIZE+1];
|
||||||
|
ssize_t sz;
|
||||||
|
int if_index = 0;
|
||||||
|
struct cmsghdr *cmptr;
|
||||||
|
struct msghdr msg;
|
||||||
|
union {
|
||||||
|
struct cmsghdr align; /* this ensures alignment */
|
||||||
|
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||||
|
} control_u;
|
||||||
|
struct sockaddr_in6 from;
|
||||||
|
unsigned char *packet;
|
||||||
|
struct iname *tmp;
|
||||||
|
struct dhcp_context *context;
|
||||||
|
|
||||||
|
/* Note: use outpacket for input buffer */
|
||||||
|
msg.msg_control = control_u.control6;
|
||||||
|
msg.msg_controllen = sizeof(control_u);
|
||||||
|
msg.msg_flags = 0;
|
||||||
|
msg.msg_name = &from;
|
||||||
|
msg.msg_namelen = sizeof(from);
|
||||||
|
msg.msg_iov = &daemon->outpacket;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
|
if ((sz = recv_dhcp_packet(daemon->icmp6fd, &msg)) == -1 || sz < 8)
|
||||||
|
return;
|
||||||
|
|
||||||
|
packet = (unsigned char *)daemon->outpacket.iov_base;
|
||||||
|
|
||||||
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
|
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
unsigned char *c;
|
||||||
|
struct in6_pktinfo *p;
|
||||||
|
} p;
|
||||||
|
p.c = CMSG_DATA(cmptr);
|
||||||
|
|
||||||
|
if_index = p.p->ipi6_ifindex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!indextoname(daemon->icmp6fd, if_index, interface))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!iface_check(AF_LOCAL, NULL, interface))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||||
|
if (tmp->name && (strcmp(tmp->name, interface) == 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* weird libvirt-inspired access control */
|
||||||
|
for (context = daemon->dhcp6; context; context = context->next)
|
||||||
|
if (!context->interface || strcmp(context->interface, interface) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!context || packet[1] != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (packet[0] == ICMP6_ECHO_REPLY)
|
||||||
|
lease_ping_reply(&from.sin6_addr, packet, interface);
|
||||||
|
else if (packet[0] == ND_ROUTER_SOLICIT)
|
||||||
|
{
|
||||||
|
char *mac = "";
|
||||||
|
|
||||||
|
/* look for link-layer address option for logging */
|
||||||
|
if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz)
|
||||||
|
{
|
||||||
|
print_mac(daemon->namebuff, &packet[10], (packet[9] * 8) - 2);
|
||||||
|
mac = daemon->namebuff;
|
||||||
|
}
|
||||||
|
|
||||||
|
my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
|
||||||
|
send_ra(if_index, interface, &from.sin6_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
||||||
|
{
|
||||||
|
struct ra_packet *ra;
|
||||||
|
struct ra_param parm;
|
||||||
|
struct ifreq ifr;
|
||||||
|
struct sockaddr_in6 addr;
|
||||||
|
struct dhcp_context *context;
|
||||||
|
struct dhcp_netid iface_id;
|
||||||
|
struct dhcp_opt *opt_cfg;
|
||||||
|
int done_dns = 0;
|
||||||
|
|
||||||
|
save_counter(0);
|
||||||
|
ra = expand(sizeof(struct ra_packet));
|
||||||
|
|
||||||
|
ra->type = ND_ROUTER_ADVERT;
|
||||||
|
ra->code = 0;
|
||||||
|
ra->hop_limit = hop_limit;
|
||||||
|
ra->flags = 0x00;
|
||||||
|
ra->lifetime = htons(1800); /* AdvDefaultLifetime*/
|
||||||
|
ra->reachable_time = 0;
|
||||||
|
ra->retrans_time = 0;
|
||||||
|
|
||||||
|
parm.ind = iface;
|
||||||
|
parm.managed = 0;
|
||||||
|
parm.other = 0;
|
||||||
|
parm.found_context = 0;
|
||||||
|
parm.if_name = iface_name;
|
||||||
|
parm.first = 1;
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
context->flags &= ~CONTEXT_RA_DONE;
|
||||||
|
context->netid.next = &context->netid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!iface_enumerate(AF_INET6, &parm, add_prefixes) ||
|
||||||
|
!parm.found_context)
|
||||||
|
return;
|
||||||
|
|
||||||
|
strncpy(ifr.ifr_name, iface_name, IF_NAMESIZE);
|
||||||
|
|
||||||
|
if (ioctl(daemon->icmp6fd, SIOCGIFMTU, &ifr) != -1)
|
||||||
|
{
|
||||||
|
put_opt6_char(ICMP6_OPT_MTU);
|
||||||
|
put_opt6_char(1);
|
||||||
|
put_opt6_short(0);
|
||||||
|
put_opt6_long(ifr.ifr_mtu);
|
||||||
|
}
|
||||||
|
|
||||||
|
iface_enumerate(AF_LOCAL, &iface, add_lla);
|
||||||
|
|
||||||
|
/* RDNSS, RFC 6106, use relevant DHCP6 options */
|
||||||
|
(void)option_filter(parm.tags, NULL, daemon->dhcp_opts6);
|
||||||
|
|
||||||
|
for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* netids match and not encapsulated? */
|
||||||
|
if (!(opt_cfg->flags & DHOPT_TAGOK))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (opt_cfg->opt == OPTION6_DNS_SERVER)
|
||||||
|
{
|
||||||
|
struct in6_addr *a = (struct in6_addr *)opt_cfg->val;
|
||||||
|
|
||||||
|
done_dns = 1;
|
||||||
|
if (opt_cfg->len == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
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 */
|
||||||
|
/* 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);
|
||||||
|
else
|
||||||
|
put_opt6(a, IN6ADDRSZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt_cfg->opt == OPTION6_DOMAIN_SEARCH && opt_cfg->len != 0)
|
||||||
|
{
|
||||||
|
int len = ((opt_cfg->len+7)/8);
|
||||||
|
|
||||||
|
put_opt6_char(ICMP6_OPT_DNSSL);
|
||||||
|
put_opt6_char(len + 1);
|
||||||
|
put_opt6_short(0);
|
||||||
|
put_opt6_long(1800); /* lifetime - twice RA retransmit */
|
||||||
|
put_opt6(opt_cfg->val, opt_cfg->len);
|
||||||
|
|
||||||
|
/* pad */
|
||||||
|
for (i = opt_cfg->len; i < len * 8; i++)
|
||||||
|
put_opt6_char(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!done_dns)
|
||||||
|
{
|
||||||
|
/* default == us. */
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set managed bits unless we're providing only RA on this link */
|
||||||
|
if (parm.managed)
|
||||||
|
ra->flags |= 0x80; /* M flag, managed, */
|
||||||
|
if (parm.other)
|
||||||
|
ra->flags |= 0x40; /* O flag, other */
|
||||||
|
|
||||||
|
/* decide where we're sending */
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
|
addr.sin6_len = sizeof(struct sockaddr_in6);
|
||||||
|
#endif
|
||||||
|
addr.sin6_family = AF_INET6;
|
||||||
|
addr.sin6_port = htons(IPPROTO_ICMPV6);
|
||||||
|
if (dest)
|
||||||
|
{
|
||||||
|
addr.sin6_addr = *dest;
|
||||||
|
if (IN6_IS_ADDR_LINKLOCAL(dest) ||
|
||||||
|
IN6_IS_ADDR_MC_LINKLOCAL(dest))
|
||||||
|
addr.sin6_scope_id = iface;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
inet_pton(AF_INET6, ALL_HOSTS, &addr.sin6_addr);
|
||||||
|
|
||||||
|
send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0),
|
||||||
|
(union mysockaddr *)&addr, (struct all_addr *)&parm.link_local, iface, NULL);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_prefixes(struct in6_addr *local, int prefix,
|
||||||
|
int scope, int if_index, int dad, 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;
|
||||||
|
unsigned int time = 0xffffffff;
|
||||||
|
struct dhcp_context *context;
|
||||||
|
|
||||||
|
for (context = daemon->ra_contexts; context; context = context->next)
|
||||||
|
if (prefix == context->prefix &&
|
||||||
|
is_same_net6(local, &context->start6, prefix) &&
|
||||||
|
is_same_net6(local, &context->end6, prefix))
|
||||||
|
{
|
||||||
|
if ((context->flags &
|
||||||
|
(CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
|
||||||
|
{
|
||||||
|
do_slaac = 1;
|
||||||
|
if (context->flags & CONTEXT_DHCP)
|
||||||
|
{
|
||||||
|
param->other = 1;
|
||||||
|
if (!(context->flags & CONTEXT_RA_STATELESS))
|
||||||
|
param->managed = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* don't do RA for non-ra-only unless --enable-ra is set */
|
||||||
|
if (!option_bool(OPT_RA))
|
||||||
|
continue;
|
||||||
|
param->managed = 1;
|
||||||
|
param->other = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find floor time */
|
||||||
|
if (time > context->lease_time)
|
||||||
|
time = context->lease_time;
|
||||||
|
|
||||||
|
if (context->flags & CONTEXT_DEPRECATE)
|
||||||
|
deprecate = 1;
|
||||||
|
|
||||||
|
/* subsequent prefixes on the same interface
|
||||||
|
and subsequent instances of this prefix don't need timers */
|
||||||
|
if (!param->first)
|
||||||
|
context->ra_time = 0;
|
||||||
|
param->first = 0;
|
||||||
|
param->found_context = 1;
|
||||||
|
|
||||||
|
/* collect dhcp-range tags */
|
||||||
|
if (context->netid.next == &context->netid && context->netid.net)
|
||||||
|
{
|
||||||
|
context->netid.next = param->tags;
|
||||||
|
param->tags = &context->netid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(context->flags & CONTEXT_RA_DONE))
|
||||||
|
{
|
||||||
|
context->flags |= CONTEXT_RA_DONE;
|
||||||
|
do_prefix = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do_prefix)
|
||||||
|
{
|
||||||
|
struct prefix_opt *opt;
|
||||||
|
|
||||||
|
if ((opt = expand(sizeof(struct prefix_opt))))
|
||||||
|
{
|
||||||
|
/* 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);
|
||||||
|
opt->reserved = 0;
|
||||||
|
opt->prefix = *local;
|
||||||
|
|
||||||
|
inet_ntop(AF_INET6, local, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm)
|
||||||
|
{
|
||||||
|
(void)type;
|
||||||
|
|
||||||
|
if (index == *((int *)parm))
|
||||||
|
{
|
||||||
|
/* size is in units of 8 octets and includes type and length (2 bytes)
|
||||||
|
add 7 to round up */
|
||||||
|
int len = (maclen + 9) >> 3;
|
||||||
|
unsigned char *p = expand(len << 3);
|
||||||
|
memset(p, 0, len << 3);
|
||||||
|
*p++ = ICMP6_OPT_SOURCE_MAC;
|
||||||
|
*p++ = len;
|
||||||
|
memcpy(p, mac, maclen);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t periodic_ra(time_t now)
|
||||||
|
{
|
||||||
|
struct search_param param;
|
||||||
|
struct dhcp_context *context;
|
||||||
|
time_t next_event;
|
||||||
|
char interface[IF_NAMESIZE+1];
|
||||||
|
|
||||||
|
param.now = now;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* find overdue events, and time of first future event */
|
||||||
|
for (next_event = 0, context = daemon->ra_contexts; context; context = context->next)
|
||||||
|
if (context->ra_time != 0)
|
||||||
|
{
|
||||||
|
if (difftime(context->ra_time, now) <= 0.0)
|
||||||
|
break; /* overdue */
|
||||||
|
|
||||||
|
if (next_event == 0 || difftime(next_event, context->ra_time) > 0.0)
|
||||||
|
next_event = context->ra_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* none overdue */
|
||||||
|
if (!context)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* There's a context overdue, but we can't find an interface
|
||||||
|
associated with it, because it's for a subnet we dont
|
||||||
|
have an interface on. Probably we're doing DHCP on
|
||||||
|
a remote subnet via a relay. Zero the timer, since we won't
|
||||||
|
ever be able to send ra's and 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return next_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iface_search(struct in6_addr *local, int prefix,
|
||||||
|
int scope, int if_index, int dad, void *vparam)
|
||||||
|
{
|
||||||
|
struct search_param *param = vparam;
|
||||||
|
struct dhcp_context *context;
|
||||||
|
|
||||||
|
(void)scope;
|
||||||
|
(void)dad;
|
||||||
|
|
||||||
|
for (context = daemon->ra_contexts; context; context = context->next)
|
||||||
|
if (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 .*/
|
||||||
|
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 */
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1; /* keep searching */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
+74
-62
@@ -1,4 +1,4 @@
|
|||||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
static int add_resource_record(HEADER *header, char *limit, int *truncp,
|
static int add_resource_record(struct dns_header *header, char *limit, int *truncp,
|
||||||
unsigned int nameoffset, unsigned char **pp,
|
unsigned int nameoffset, unsigned char **pp,
|
||||||
unsigned long ttl, unsigned int *offset, unsigned short type,
|
unsigned long ttl, unsigned int *offset, unsigned short type,
|
||||||
unsigned short class, char *format, ...);
|
unsigned short class, char *format, ...);
|
||||||
@@ -25,9 +25,9 @@ static int add_resource_record(HEADER *header, char *limit, int *truncp,
|
|||||||
((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))
|
((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))
|
||||||
|
|
||||||
#define ADD_RDLEN(header, pp, plen, len) \
|
#define ADD_RDLEN(header, pp, plen, len) \
|
||||||
(!CHECK_LEN(header, pp, plen, len) ? 0 : (long)((pp) += (len)), 1)
|
(!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))
|
||||||
|
|
||||||
static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
|
static int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||||
char *name, int isExtract, int extrabytes)
|
char *name, int isExtract, int extrabytes)
|
||||||
{
|
{
|
||||||
unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
|
unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
|
||||||
@@ -217,7 +217,7 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
|
|||||||
as CNAME targets according to RFC 2317 */
|
as CNAME targets according to RFC 2317 */
|
||||||
char *cp;
|
char *cp;
|
||||||
for (cp = cp1; *cp; cp++)
|
for (cp = cp1; *cp; cp++)
|
||||||
if (!isdigit((int)*cp))
|
if (!isdigit((unsigned char)*cp))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
addr[3] = addr[2];
|
addr[3] = addr[2];
|
||||||
@@ -244,7 +244,7 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
|
|||||||
if (*name == '\\' && *(name+1) == '[' &&
|
if (*name == '\\' && *(name+1) == '[' &&
|
||||||
(*(name+2) == 'x' || *(name+2) == 'X'))
|
(*(name+2) == 'x' || *(name+2) == 'X'))
|
||||||
{
|
{
|
||||||
for (j = 0, cp1 = name+3; *cp1 && isxdigit((int) *cp1) && j < 32; cp1++, j++)
|
for (j = 0, cp1 = name+3; *cp1 && isxdigit((unsigned char) *cp1) && j < 32; cp1++, j++)
|
||||||
{
|
{
|
||||||
char xdig[2];
|
char xdig[2];
|
||||||
xdig[0] = *cp1;
|
xdig[0] = *cp1;
|
||||||
@@ -262,7 +262,7 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
|
|||||||
{
|
{
|
||||||
for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
|
for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
|
||||||
{
|
{
|
||||||
if (*(cp1+1) || !isxdigit((int)*cp1))
|
if (*(cp1+1) || !isxdigit((unsigned char)*cp1))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (j = sizeof(struct all_addr)-1; j>0; j--)
|
for (j = sizeof(struct all_addr)-1; j>0; j--)
|
||||||
@@ -278,7 +278,7 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen, int extrabytes)
|
static unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes)
|
||||||
{
|
{
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
@@ -333,7 +333,7 @@ static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen
|
|||||||
return ansp;
|
return ansp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char *skip_questions(HEADER *header, size_t plen)
|
static unsigned char *skip_questions(struct dns_header *header, size_t plen)
|
||||||
{
|
{
|
||||||
int q;
|
int q;
|
||||||
unsigned char *ansp = (unsigned char *)(header+1);
|
unsigned char *ansp = (unsigned char *)(header+1);
|
||||||
@@ -348,7 +348,7 @@ static unsigned char *skip_questions(HEADER *header, size_t plen)
|
|||||||
return ansp;
|
return ansp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char *skip_section(unsigned char *ansp, int count, HEADER *header, size_t plen)
|
static unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen)
|
||||||
{
|
{
|
||||||
int i, rdlen;
|
int i, rdlen;
|
||||||
|
|
||||||
@@ -371,7 +371,7 @@ static unsigned char *skip_section(unsigned char *ansp, int count, HEADER *heade
|
|||||||
than CRC the raw bytes, since replies might be compressed differently.
|
than CRC the raw bytes, since replies might be compressed differently.
|
||||||
We ignore case in the names for the same reason. Return all-ones
|
We ignore case in the names for the same reason. Return all-ones
|
||||||
if there is not question section. */
|
if there is not question section. */
|
||||||
unsigned int questions_crc(HEADER *header, size_t plen, char *name)
|
unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
|
||||||
{
|
{
|
||||||
int q;
|
int q;
|
||||||
unsigned int crc = 0xffffffff;
|
unsigned int crc = 0xffffffff;
|
||||||
@@ -413,7 +413,7 @@ unsigned int questions_crc(HEADER *header, size_t plen, char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t resize_packet(HEADER *header, size_t plen, unsigned char *pheader, size_t hlen)
|
size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
|
||||||
{
|
{
|
||||||
unsigned char *ansp = skip_questions(header, plen);
|
unsigned char *ansp = skip_questions(header, plen);
|
||||||
|
|
||||||
@@ -437,7 +437,7 @@ size_t resize_packet(HEADER *header, size_t plen, unsigned char *pheader, size_t
|
|||||||
return ansp - (unsigned char *)header;
|
return ansp - (unsigned char *)header;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsigned char **p, int *is_sign)
|
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t *len, unsigned char **p, int *is_sign)
|
||||||
{
|
{
|
||||||
/* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
|
/* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
|
||||||
also return length of pseudoheader in *len and pointer to the UDP size in *p
|
also return length of pseudoheader in *len and pointer to the UDP size in *p
|
||||||
@@ -453,7 +453,7 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
|
|||||||
{
|
{
|
||||||
*is_sign = 0;
|
*is_sign = 0;
|
||||||
|
|
||||||
if (header->opcode == QUERY)
|
if (OPCODE(header) == QUERY)
|
||||||
{
|
{
|
||||||
for (i = ntohs(header->qdcount); i != 0; i--)
|
for (i = ntohs(header->qdcount); i != 0; i--)
|
||||||
{
|
{
|
||||||
@@ -513,7 +513,7 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
|
|||||||
|
|
||||||
struct macparm {
|
struct macparm {
|
||||||
unsigned char *limit;
|
unsigned char *limit;
|
||||||
HEADER *header;
|
struct dns_header *header;
|
||||||
size_t plen;
|
size_t plen;
|
||||||
union mysockaddr *l3;
|
union mysockaddr *l3;
|
||||||
};
|
};
|
||||||
@@ -523,7 +523,7 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
|
|||||||
struct macparm *parm = parmv;
|
struct macparm *parm = parmv;
|
||||||
int match = 0;
|
int match = 0;
|
||||||
unsigned short rdlen;
|
unsigned short rdlen;
|
||||||
HEADER *header = parm->header;
|
struct dns_header *header = parm->header;
|
||||||
unsigned char *lenp, *datap, *p;
|
unsigned char *lenp, *datap, *p;
|
||||||
|
|
||||||
if (family == parm->l3->sa.sa_family)
|
if (family == parm->l3->sa.sa_family)
|
||||||
@@ -605,7 +605,7 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t add_mac(HEADER *header, size_t plen, char *limit, union mysockaddr *l3)
|
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
|
||||||
{
|
{
|
||||||
struct macparm parm;
|
struct macparm parm;
|
||||||
|
|
||||||
@@ -639,10 +639,9 @@ static int private_net(struct in_addr addr, int ban_localhost)
|
|||||||
((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ;
|
((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, size_t qlen, char *name)
|
static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name)
|
||||||
{
|
{
|
||||||
int i, qtype, qclass, rdlen;
|
int i, qtype, qclass, rdlen;
|
||||||
unsigned long ttl;
|
|
||||||
|
|
||||||
for (i = count; i != 0; i--)
|
for (i = count; i != 0; i--)
|
||||||
{
|
{
|
||||||
@@ -656,7 +655,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
|
|||||||
|
|
||||||
GETSHORT(qtype, p);
|
GETSHORT(qtype, p);
|
||||||
GETSHORT(qclass, p);
|
GETSHORT(qclass, p);
|
||||||
GETLONG(ttl, p);
|
p += 4; /* ttl */
|
||||||
GETSHORT(rdlen, p);
|
GETSHORT(rdlen, p);
|
||||||
|
|
||||||
if (qclass == C_IN && qtype == T_A)
|
if (qclass == C_IN && qtype == T_A)
|
||||||
@@ -684,7 +683,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
|
|||||||
addr.s_addr &= ~doctor->mask.s_addr;
|
addr.s_addr &= ~doctor->mask.s_addr;
|
||||||
addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
|
addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
|
||||||
/* Since we munged the data, the server it came from is no longer authoritative */
|
/* Since we munged the data, the server it came from is no longer authoritative */
|
||||||
header->aa = 0;
|
header->hb3 &= ~HB3_AA;
|
||||||
memcpy(p, &addr, INADDRSZ);
|
memcpy(p, &addr, INADDRSZ);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -721,7 +720,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_soa(HEADER *header, size_t qlen, char *name)
|
static int find_soa(struct dns_header *header, size_t qlen, char *name)
|
||||||
{
|
{
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
int qtype, qclass, rdlen;
|
int qtype, qclass, rdlen;
|
||||||
@@ -779,7 +778,7 @@ static int find_soa(HEADER *header, size_t qlen, char *name)
|
|||||||
either because of lack of memory, or lack of SOA records. These are treated by the cache code as
|
either because of lack of memory, or lack of SOA records. These are treated by the cache code as
|
||||||
expired and cleaned out that way.
|
expired and cleaned out that way.
|
||||||
Return 1 if we reject an address because it look like part of dns-rebinding attack. */
|
Return 1 if we reject an address because it look like part of dns-rebinding attack. */
|
||||||
int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now,
|
int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
|
||||||
int is_sign, int check_rebind, int checking_disabled)
|
int is_sign, int check_rebind, int checking_disabled)
|
||||||
{
|
{
|
||||||
unsigned char *p, *p1, *endrr, *namep;
|
unsigned char *p, *p1, *endrr, *namep;
|
||||||
@@ -803,7 +802,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now,
|
|||||||
{
|
{
|
||||||
int found = 0, cname_count = 5;
|
int found = 0, cname_count = 5;
|
||||||
struct crec *cpp = NULL;
|
struct crec *cpp = NULL;
|
||||||
int flags = header->rcode == NXDOMAIN ? F_NXDOMAIN : 0;
|
int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
|
||||||
unsigned long cttl = ULONG_MAX, attl;
|
unsigned long cttl = ULONG_MAX, attl;
|
||||||
|
|
||||||
namep = p;
|
namep = p;
|
||||||
@@ -844,7 +843,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now,
|
|||||||
GETLONG(attl, p1);
|
GETLONG(attl, p1);
|
||||||
if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
|
if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
|
||||||
{
|
{
|
||||||
(p1) -= NS_INT32SZ;
|
(p1) -= 4;
|
||||||
PUTLONG(daemon->max_ttl, p1);
|
PUTLONG(daemon->max_ttl, p1);
|
||||||
}
|
}
|
||||||
GETSHORT(ardlen, p1);
|
GETSHORT(ardlen, p1);
|
||||||
@@ -924,7 +923,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now,
|
|||||||
GETLONG(attl, p1);
|
GETLONG(attl, p1);
|
||||||
if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
|
if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
|
||||||
{
|
{
|
||||||
(p1) -= NS_INT32SZ;
|
(p1) -= 4;
|
||||||
PUTLONG(daemon->max_ttl, p1);
|
PUTLONG(daemon->max_ttl, p1);
|
||||||
}
|
}
|
||||||
GETSHORT(ardlen, p1);
|
GETSHORT(ardlen, p1);
|
||||||
@@ -1007,7 +1006,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now,
|
|||||||
/* Don't put stuff from a truncated packet into the cache,
|
/* Don't put stuff from a truncated packet into the cache,
|
||||||
also don't cache replies where DNSSEC validation was turned off, either
|
also don't cache replies where DNSSEC validation was turned off, either
|
||||||
the upstream server told us so, or the original query specified it. */
|
the upstream server told us so, or the original query specified it. */
|
||||||
if (!header->tc && !header->cd && !checking_disabled)
|
if (!(header->hb3 & HB3_TC) && !(header->hb4 & HB4_CD) && !checking_disabled)
|
||||||
cache_end_insert();
|
cache_end_insert();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1016,7 +1015,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now,
|
|||||||
/* If the packet holds exactly one query
|
/* If the packet holds exactly one query
|
||||||
return F_IPV4 or F_IPV6 and leave the name from the query in name */
|
return F_IPV4 or F_IPV6 and leave the name from the query in name */
|
||||||
|
|
||||||
unsigned int extract_request(HEADER *header, size_t qlen, char *name, unsigned short *typep)
|
unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
|
||||||
{
|
{
|
||||||
unsigned char *p = (unsigned char *)(header+1);
|
unsigned char *p = (unsigned char *)(header+1);
|
||||||
int qtype, qclass;
|
int qtype, qclass;
|
||||||
@@ -1024,7 +1023,7 @@ unsigned int extract_request(HEADER *header, size_t qlen, char *name, unsigned s
|
|||||||
if (typep)
|
if (typep)
|
||||||
*typep = 0;
|
*typep = 0;
|
||||||
|
|
||||||
if (ntohs(header->qdcount) != 1 || header->opcode != QUERY)
|
if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
|
||||||
return 0; /* must be exactly one query. */
|
return 0; /* must be exactly one query. */
|
||||||
|
|
||||||
if (!extract_name(header, qlen, &p, name, 1, 4))
|
if (!extract_name(header, qlen, &p, name, 1, 4))
|
||||||
@@ -1044,50 +1043,49 @@ unsigned int extract_request(HEADER *header, size_t qlen, char *name, unsigned s
|
|||||||
return F_IPV6;
|
return F_IPV6;
|
||||||
if (qtype == T_ANY)
|
if (qtype == T_ANY)
|
||||||
return F_IPV4 | F_IPV6;
|
return F_IPV4 | F_IPV6;
|
||||||
if (qtype == T_NS || qtype == T_SOA)
|
|
||||||
return F_QUERY | F_NSRR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return F_QUERY;
|
return F_QUERY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t setup_reply(HEADER *header, size_t qlen,
|
size_t setup_reply(struct dns_header *header, size_t qlen,
|
||||||
struct all_addr *addrp, unsigned int flags, unsigned long ttl)
|
struct all_addr *addrp, unsigned int flags, unsigned long ttl)
|
||||||
{
|
{
|
||||||
unsigned char *p = skip_questions(header, qlen);
|
unsigned char *p = skip_questions(header, qlen);
|
||||||
|
|
||||||
header->qr = 1; /* response */
|
/* clear authoritative and truncated flags, set QR flag */
|
||||||
header->aa = 0; /* authoritive */
|
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
|
||||||
header->ra = 1; /* recursion if available */
|
/* set RA flag */
|
||||||
header->tc = 0; /* not truncated */
|
header->hb4 |= HB4_RA;
|
||||||
|
|
||||||
header->nscount = htons(0);
|
header->nscount = htons(0);
|
||||||
header->arcount = htons(0);
|
header->arcount = htons(0);
|
||||||
header->ancount = htons(0); /* no answers unless changed below */
|
header->ancount = htons(0); /* no answers unless changed below */
|
||||||
if (flags == F_NEG)
|
if (flags == F_NEG)
|
||||||
header->rcode = SERVFAIL; /* couldn't get memory */
|
SET_RCODE(header, SERVFAIL); /* couldn't get memory */
|
||||||
else if (flags == F_NOERR)
|
else if (flags == F_NOERR)
|
||||||
header->rcode = NOERROR; /* empty domain */
|
SET_RCODE(header, NOERROR); /* empty domain */
|
||||||
else if (flags == F_NXDOMAIN)
|
else if (flags == F_NXDOMAIN)
|
||||||
header->rcode = NXDOMAIN;
|
SET_RCODE(header, NXDOMAIN);
|
||||||
else if (p && flags == F_IPV4)
|
else if (p && flags == F_IPV4)
|
||||||
{ /* we know the address */
|
{ /* we know the address */
|
||||||
header->rcode = NOERROR;
|
SET_RCODE(header, NOERROR);
|
||||||
header->ancount = htons(1);
|
header->ancount = htons(1);
|
||||||
header->aa = 1;
|
header->hb3 |= HB3_AA;
|
||||||
add_resource_record(header, NULL, NULL, sizeof(HEADER), &p, ttl, NULL, T_A, C_IN, "4", addrp);
|
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
|
||||||
}
|
}
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else if (p && flags == F_IPV6)
|
else if (p && flags == F_IPV6)
|
||||||
{
|
{
|
||||||
header->rcode = NOERROR;
|
SET_RCODE(header, NOERROR);
|
||||||
header->ancount = htons(1);
|
header->ancount = htons(1);
|
||||||
header->aa = 1;
|
header->hb3 |= HB3_AA;
|
||||||
add_resource_record(header, NULL, NULL, sizeof(HEADER), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
|
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else /* nowhere to forward to */
|
else /* nowhere to forward to */
|
||||||
header->rcode = REFUSED;
|
SET_RCODE(header, REFUSED);
|
||||||
|
|
||||||
return p - (unsigned char *)header;
|
return p - (unsigned char *)header;
|
||||||
}
|
}
|
||||||
@@ -1100,12 +1098,17 @@ int check_for_local_domain(char *name, time_t now)
|
|||||||
struct txt_record *txt;
|
struct txt_record *txt;
|
||||||
struct interface_name *intr;
|
struct interface_name *intr;
|
||||||
struct ptr_record *ptr;
|
struct ptr_record *ptr;
|
||||||
|
struct naptr *naptr;
|
||||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)) &&
|
|
||||||
|
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME)) &&
|
||||||
(crecp->flags & (F_HOSTS | F_DHCP)))
|
(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
for (mx = daemon->mxnames; mx; mx = mx->next)
|
for (naptr = daemon->naptr; naptr; naptr = naptr->next)
|
||||||
|
if (hostname_isequal(name, naptr->name))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
for (mx = daemon->mxnames; mx; mx = mx->next)
|
||||||
if (hostname_isequal(name, mx->name))
|
if (hostname_isequal(name, mx->name))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -1127,7 +1130,7 @@ int check_for_local_domain(char *name, time_t now)
|
|||||||
/* Is the packet a reply with the answer address equal to addr?
|
/* Is the packet a reply with the answer address equal to addr?
|
||||||
If so mung is into an NXDOMAIN reply and also put that information
|
If so mung is into an NXDOMAIN reply and also put that information
|
||||||
in the cache. */
|
in the cache. */
|
||||||
int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
|
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||||
struct bogus_addr *baddr, time_t now)
|
struct bogus_addr *baddr, time_t now)
|
||||||
{
|
{
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
@@ -1174,7 +1177,7 @@ int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_resource_record(HEADER *header, char *limit, int *truncp, unsigned int nameoffset, unsigned char **pp,
|
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, ...)
|
unsigned long ttl, unsigned int *offset, unsigned short type, unsigned short class, char *format, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@@ -1284,7 +1287,7 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
|
|||||||
|
|
||||||
|
|
||||||
/* return zero if we can't answer from cache, or packet size if we can */
|
/* return zero if we can't answer from cache, or packet size if we can */
|
||||||
size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
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)
|
struct in_addr local_addr, struct in_addr local_netmask, time_t now)
|
||||||
{
|
{
|
||||||
char *name = daemon->namebuff;
|
char *name = daemon->namebuff;
|
||||||
@@ -1308,11 +1311,11 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
|||||||
|
|
||||||
if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign))
|
if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign))
|
||||||
{
|
{
|
||||||
unsigned short udpsz, ext_rcode, flags;
|
unsigned short udpsz, flags;
|
||||||
unsigned char *psave = pheader;
|
unsigned char *psave = pheader;
|
||||||
|
|
||||||
GETSHORT(udpsz, pheader);
|
GETSHORT(udpsz, pheader);
|
||||||
GETSHORT(ext_rcode, pheader);
|
pheader += 2; /* ext_rcode */
|
||||||
GETSHORT(flags, pheader);
|
GETSHORT(flags, pheader);
|
||||||
|
|
||||||
sec_reqd = flags & 0x8000; /* do bit */
|
sec_reqd = flags & 0x8000; /* do bit */
|
||||||
@@ -1327,7 +1330,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
|||||||
dryrun = 1;
|
dryrun = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ntohs(header->qdcount) == 0 || header->opcode != QUERY )
|
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (rec = daemon->mxnames; rec; rec = rec->next)
|
for (rec = daemon->mxnames; rec; rec = rec->next)
|
||||||
@@ -1496,7 +1499,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
|||||||
|
|
||||||
for (cp = name, i = 0, a = 0; *cp; i++)
|
for (cp = name, i = 0, a = 0; *cp; i++)
|
||||||
{
|
{
|
||||||
if (!isdigit(*cp) || (x = strtol(cp, &cp, 10)) > 255)
|
if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255)
|
||||||
{
|
{
|
||||||
i = 5;
|
i = 5;
|
||||||
break;
|
break;
|
||||||
@@ -1785,14 +1788,23 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* done all questions, set up header and return length of result */
|
/* done all questions, set up header and return length of result */
|
||||||
header->qr = 1; /* response */
|
/* clear authoritative and truncated flags, set QR flag */
|
||||||
header->aa = auth; /* authoritive - only hosts and DHCP derived names. */
|
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
|
||||||
header->ra = 1; /* recursion if available */
|
/* set RA flag */
|
||||||
header->tc = trunc; /* truncation */
|
header->hb4 |= HB4_RA;
|
||||||
|
|
||||||
|
/* authoritive - only hosts and DHCP derived names. */
|
||||||
|
if (auth)
|
||||||
|
header->hb3 |= HB3_AA;
|
||||||
|
|
||||||
|
/* truncation */
|
||||||
|
if (trunc)
|
||||||
|
header->hb3 |= HB3_TC;
|
||||||
|
|
||||||
if (anscount == 0 && nxdomain)
|
if (anscount == 0 && nxdomain)
|
||||||
header->rcode = NXDOMAIN;
|
SET_RCODE(header, NXDOMAIN);
|
||||||
else
|
else
|
||||||
header->rcode = NOERROR; /* no error */
|
SET_RCODE(header, NOERROR); /* no error */
|
||||||
header->ancount = htons(anscount);
|
header->ancount = htons(anscount);
|
||||||
header->nscount = htons(0);
|
header->nscount = htons(0);
|
||||||
header->arcount = htons(addncount);
|
header->arcount = htons(addncount);
|
||||||
|
|||||||
+192
-317
@@ -1,4 +1,4 @@
|
|||||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -18,78 +18,13 @@
|
|||||||
|
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
|
|
||||||
#define BOOTREQUEST 1
|
|
||||||
#define BOOTREPLY 2
|
|
||||||
#define DHCP_COOKIE 0x63825363
|
|
||||||
|
|
||||||
/* The Linux in-kernel DHCP client silently ignores any packet
|
|
||||||
smaller than this. Sigh........... */
|
|
||||||
#define MIN_PACKETSZ 300
|
|
||||||
|
|
||||||
#define OPTION_PAD 0
|
|
||||||
#define OPTION_NETMASK 1
|
|
||||||
#define OPTION_ROUTER 3
|
|
||||||
#define OPTION_DNSSERVER 6
|
|
||||||
#define OPTION_HOSTNAME 12
|
|
||||||
#define OPTION_DOMAINNAME 15
|
|
||||||
#define OPTION_BROADCAST 28
|
|
||||||
#define OPTION_VENDOR_CLASS_OPT 43
|
|
||||||
#define OPTION_REQUESTED_IP 50
|
|
||||||
#define OPTION_LEASE_TIME 51
|
|
||||||
#define OPTION_OVERLOAD 52
|
|
||||||
#define OPTION_MESSAGE_TYPE 53
|
|
||||||
#define OPTION_SERVER_IDENTIFIER 54
|
|
||||||
#define OPTION_REQUESTED_OPTIONS 55
|
|
||||||
#define OPTION_MESSAGE 56
|
|
||||||
#define OPTION_MAXMESSAGE 57
|
|
||||||
#define OPTION_T1 58
|
|
||||||
#define OPTION_T2 59
|
|
||||||
#define OPTION_VENDOR_ID 60
|
|
||||||
#define OPTION_CLIENT_ID 61
|
|
||||||
#define OPTION_SNAME 66
|
|
||||||
#define OPTION_FILENAME 67
|
|
||||||
#define OPTION_USER_CLASS 77
|
|
||||||
#define OPTION_CLIENT_FQDN 81
|
|
||||||
#define OPTION_AGENT_ID 82
|
|
||||||
#define OPTION_ARCH 93
|
|
||||||
#define OPTION_PXE_UUID 97
|
|
||||||
#define OPTION_SUBNET_SELECT 118
|
|
||||||
#define OPTION_VENDOR_IDENT 124
|
|
||||||
#define OPTION_VENDOR_IDENT_OPT 125
|
|
||||||
#define OPTION_END 255
|
|
||||||
|
|
||||||
#define SUBOPT_CIRCUIT_ID 1
|
|
||||||
#define SUBOPT_REMOTE_ID 2
|
|
||||||
#define SUBOPT_SUBNET_SELECT 5 /* RFC 3527 */
|
|
||||||
#define SUBOPT_SUBSCR_ID 6 /* RFC 3393 */
|
|
||||||
#define SUBOPT_SERVER_OR 11 /* RFC 5107 */
|
|
||||||
|
|
||||||
#define SUBOPT_PXE_BOOT_ITEM 71 /* PXE standard */
|
|
||||||
#define SUBOPT_PXE_DISCOVERY 6
|
|
||||||
#define SUBOPT_PXE_SERVERS 8
|
|
||||||
#define SUBOPT_PXE_MENU 9
|
|
||||||
#define SUBOPT_PXE_MENU_PROMPT 10
|
|
||||||
|
|
||||||
#define DHCPDISCOVER 1
|
|
||||||
#define DHCPOFFER 2
|
|
||||||
#define DHCPREQUEST 3
|
|
||||||
#define DHCPDECLINE 4
|
|
||||||
#define DHCPACK 5
|
|
||||||
#define DHCPNAK 6
|
|
||||||
#define DHCPRELEASE 7
|
|
||||||
#define DHCPINFORM 8
|
|
||||||
|
|
||||||
#define BRDBAND_FORUM_IANA 3561 /* Broadband forum IANA enterprise */
|
|
||||||
|
|
||||||
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
|
|
||||||
#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
|
#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
|
||||||
#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
|
#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
|
||||||
|
|
||||||
#ifdef HAVE_SCRIPT
|
#ifdef HAVE_SCRIPT
|
||||||
static void add_extradata_data(struct dhcp_lease *lease, unsigned char *data, size_t len, int delim);
|
|
||||||
static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt);
|
static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt);
|
||||||
#endif
|
#endif
|
||||||
static int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
|
|
||||||
static int sanitise(unsigned char *opt, char *buf);
|
static int sanitise(unsigned char *opt, char *buf);
|
||||||
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback);
|
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback);
|
||||||
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
|
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
|
||||||
@@ -97,39 +32,38 @@ static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, in
|
|||||||
static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
|
static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
|
||||||
int opt, char *string, int null_term);
|
int opt, char *string, int null_term);
|
||||||
static struct in_addr option_addr(unsigned char *opt);
|
static struct in_addr option_addr(unsigned char *opt);
|
||||||
static struct in_addr option_addr_arr(unsigned char *opt, int offset);
|
|
||||||
static unsigned int option_uint(unsigned char *opt, int i, int size);
|
static unsigned int option_uint(unsigned char *opt, int i, int size);
|
||||||
static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
||||||
int mac_len, char *interface, char *string, u32 xid);
|
int mac_len, char *interface, char *string, u32 xid);
|
||||||
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
|
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
|
||||||
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
|
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
|
||||||
static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *netid,
|
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end);
|
||||||
unsigned char *agent_id, unsigned char *real_end);
|
|
||||||
static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
|
static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
|
||||||
static void do_options(struct dhcp_context *context,
|
static void do_options(struct dhcp_context *context,
|
||||||
struct dhcp_packet *mess,
|
struct dhcp_packet *mess,
|
||||||
unsigned char *real_end,
|
unsigned char *real_end,
|
||||||
unsigned char *req_options,
|
unsigned char *req_options,
|
||||||
char *hostname,
|
char *hostname,
|
||||||
char *domain, char *config_domain,
|
char *config_domain,
|
||||||
struct dhcp_netid *netid,
|
struct dhcp_netid *netid,
|
||||||
struct in_addr subnet_addr,
|
struct in_addr subnet_addr,
|
||||||
unsigned char fqdn_flags,
|
unsigned char fqdn_flags,
|
||||||
int null_term, int pxearch,
|
int null_term, int pxearch,
|
||||||
unsigned char *uuid,
|
unsigned char *uuid,
|
||||||
int vendor_class_len);
|
int vendor_class_len,
|
||||||
|
time_t now);
|
||||||
|
|
||||||
|
|
||||||
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
|
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
|
||||||
static int do_encap_opts(struct dhcp_opt *opts, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
|
static int do_encap_opts(struct dhcp_opt *opts, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
|
||||||
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid);
|
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid);
|
||||||
static int prune_vendor_opts(struct dhcp_netid *netid);
|
static int prune_vendor_opts(struct dhcp_netid *netid);
|
||||||
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local);
|
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);
|
||||||
struct dhcp_boot *find_boot(struct dhcp_netid *netid);
|
struct dhcp_boot *find_boot(struct dhcp_netid *netid);
|
||||||
|
|
||||||
|
|
||||||
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||||
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe)
|
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe, struct in_addr fallback)
|
||||||
{
|
{
|
||||||
unsigned char *opt, *clid = NULL;
|
unsigned char *opt, *clid = NULL;
|
||||||
struct dhcp_lease *ltmp, *lease = NULL;
|
struct dhcp_lease *ltmp, *lease = NULL;
|
||||||
@@ -147,7 +81,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
unsigned int time;
|
unsigned int time;
|
||||||
struct dhcp_config *config;
|
struct dhcp_config *config;
|
||||||
struct dhcp_netid *netid, *tagif_netid;
|
struct dhcp_netid *netid, *tagif_netid;
|
||||||
struct in_addr subnet_addr, fallback, override;
|
struct in_addr subnet_addr, override;
|
||||||
unsigned short fuzz = 0;
|
unsigned short fuzz = 0;
|
||||||
unsigned int mess_type = 0;
|
unsigned int mess_type = 0;
|
||||||
unsigned char fqdn_flags = 0;
|
unsigned char fqdn_flags = 0;
|
||||||
@@ -359,17 +293,43 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
|
|
||||||
if (!context_new)
|
if (!context_new)
|
||||||
for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
|
for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
|
||||||
if (context_tmp->netmask.s_addr &&
|
{
|
||||||
is_same_net(addr, context_tmp->start, context_tmp->netmask) &&
|
struct in_addr netmask = context_tmp->netmask;
|
||||||
is_same_net(addr, context_tmp->end, context_tmp->netmask))
|
|
||||||
{
|
/* guess the netmask for relayed networks */
|
||||||
context_tmp->current = context_new;
|
if (!(context_tmp->flags & CONTEXT_NETMASK) && context_tmp->netmask.s_addr == 0)
|
||||||
context_new = context_tmp;
|
{
|
||||||
}
|
if (IN_CLASSA(ntohl(context_tmp->start.s_addr)) && IN_CLASSA(ntohl(context_tmp->end.s_addr)))
|
||||||
|
netmask.s_addr = htonl(0xff000000);
|
||||||
|
else if (IN_CLASSB(ntohl(context_tmp->start.s_addr)) && IN_CLASSB(ntohl(context_tmp->end.s_addr)))
|
||||||
|
netmask.s_addr = htonl(0xffff0000);
|
||||||
|
else if (IN_CLASSC(ntohl(context_tmp->start.s_addr)) && IN_CLASSC(ntohl(context_tmp->end.s_addr)))
|
||||||
|
netmask.s_addr = htonl(0xffffff00);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This section fills in context mainly when a client which is on a remote (relayed)
|
||||||
|
network renews a lease without using the relay, after dnsmasq has restarted. */
|
||||||
|
if (netmask.s_addr != 0 &&
|
||||||
|
is_same_net(addr, context_tmp->start, netmask) &&
|
||||||
|
is_same_net(addr, context_tmp->end, netmask))
|
||||||
|
{
|
||||||
|
context_tmp->netmask = netmask;
|
||||||
|
if (context_tmp->local.s_addr == 0)
|
||||||
|
context_tmp->local = fallback;
|
||||||
|
if (context_tmp->router.s_addr == 0)
|
||||||
|
context_tmp->router = mess->giaddr;
|
||||||
|
|
||||||
|
/* fill in missing broadcast addresses for relayed ranges */
|
||||||
|
if (!(context_tmp->flags & CONTEXT_BRDCAST) && context_tmp->broadcast.s_addr == 0 )
|
||||||
|
context_tmp->broadcast.s_addr = context_tmp->start.s_addr | ~context_tmp->netmask.s_addr;
|
||||||
|
|
||||||
|
context_tmp->current = context_new;
|
||||||
|
context_new = context_tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (context_new || force)
|
if (context_new || force)
|
||||||
context = context_new;
|
context = context_new;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context)
|
if (!context)
|
||||||
@@ -380,9 +340,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* keep _a_ local address available. */
|
|
||||||
fallback = context->local;
|
|
||||||
|
|
||||||
if (option_bool(OPT_LOG_OPTS))
|
if (option_bool(OPT_LOG_OPTS))
|
||||||
{
|
{
|
||||||
struct dhcp_context *context_tmp;
|
struct dhcp_context *context_tmp;
|
||||||
@@ -503,9 +460,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
else if (context->netid.net)
|
else if (context->netid.net)
|
||||||
{
|
{
|
||||||
context->netid.next = netid;
|
context->netid.next = netid;
|
||||||
netid = &context->netid;
|
tagif_netid = run_tag_if(&context->netid);
|
||||||
tagif_netid = run_tag_if(netid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_tags(tagif_netid, ntohl(mess->xid));
|
||||||
|
|
||||||
if (!message && !nailed)
|
if (!message && !nailed)
|
||||||
{
|
{
|
||||||
@@ -518,31 +476,31 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
|
|
||||||
if (!message &&
|
if (!message &&
|
||||||
!lease &&
|
!lease &&
|
||||||
(!(lease = lease_allocate(mess->yiaddr))))
|
(!(lease = lease4_allocate(mess->yiaddr))))
|
||||||
message = _("no leases left");
|
message = _("no leases left");
|
||||||
|
|
||||||
if (!message)
|
if (!message)
|
||||||
{
|
{
|
||||||
logaddr = &mess->yiaddr;
|
logaddr = &mess->yiaddr;
|
||||||
|
|
||||||
lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0);
|
lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0, now);
|
||||||
if (hostname)
|
if (hostname)
|
||||||
lease_set_hostname(lease, hostname, 1);
|
lease_set_hostname(lease, hostname, 1, get_domain(lease->addr), domain);
|
||||||
/* infinite lease unless nailed in dhcp-host line. */
|
/* infinite lease unless nailed in dhcp-host line. */
|
||||||
lease_set_expires(lease,
|
lease_set_expires(lease,
|
||||||
have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff,
|
have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff,
|
||||||
now);
|
now);
|
||||||
lease_set_interface(lease, int_index);
|
lease_set_interface(lease, int_index, now);
|
||||||
|
|
||||||
clear_packet(mess, end);
|
clear_packet(mess, end);
|
||||||
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
|
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
|
||||||
domain, tagif_netid, subnet_addr, 0, 0, 0, NULL, 0);
|
netid, subnet_addr, 0, 0, 0, NULL, 0, now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, message, mess->xid);
|
log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, message, mess->xid);
|
||||||
|
|
||||||
return message ? 0 : dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
return message ? 0 : dhcp_packet_size(mess, agent_id, real_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 4)))
|
if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 4)))
|
||||||
@@ -558,11 +516,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
pp = op;
|
pp = op;
|
||||||
|
|
||||||
/* Always force update, since the client has no way to do it itself. */
|
/* Always force update, since the client has no way to do it itself. */
|
||||||
if (!(fqdn_flags & 0x01))
|
if (!option_bool(OPT_FQDN_UPDATE) && !(fqdn_flags & 0x01))
|
||||||
fqdn_flags |= 0x02;
|
fqdn_flags |= 0x03;
|
||||||
|
|
||||||
fqdn_flags &= ~0x08;
|
fqdn_flags &= ~0x08;
|
||||||
fqdn_flags |= 0x01;
|
|
||||||
|
|
||||||
if (fqdn_flags & 0x04)
|
if (fqdn_flags & 0x04)
|
||||||
while (*op != 0 && ((op + (*op) + 1) - pp) < len)
|
while (*op != 0 && ((op + (*op) + 1) - pp) < len)
|
||||||
@@ -837,7 +794,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
|
|
||||||
mess->yiaddr = mess->ciaddr;
|
mess->yiaddr = mess->ciaddr;
|
||||||
mess->ciaddr.s_addr = 0;
|
mess->ciaddr.s_addr = 0;
|
||||||
if (service->server.s_addr != 0)
|
if (service->sname)
|
||||||
|
mess->siaddr = a_record_from_hosts(service->sname, now);
|
||||||
|
else if (service->server.s_addr != 0)
|
||||||
mess->siaddr = service->server;
|
mess->siaddr = service->server;
|
||||||
else
|
else
|
||||||
mess->siaddr = context->local;
|
mess->siaddr = context->local;
|
||||||
@@ -857,7 +816,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||||
|
|
||||||
log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, mess->xid);
|
log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, mess->xid);
|
||||||
return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
log_tags(tagif_netid, ntohl(mess->xid));
|
||||||
|
return dhcp_packet_size(mess, agent_id, real_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((opt = option_find(mess, sz, OPTION_ARCH, 2)))
|
if ((opt = option_find(mess, sz, OPTION_ARCH, 2)))
|
||||||
@@ -891,8 +851,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
and set discovery_control = 8 */
|
and set discovery_control = 8 */
|
||||||
if (boot)
|
if (boot)
|
||||||
{
|
{
|
||||||
if (boot->next_server.s_addr)
|
if (boot->next_server.s_addr)
|
||||||
mess->siaddr = boot->next_server;
|
mess->siaddr = boot->next_server;
|
||||||
|
else if (boot->tftp_sname)
|
||||||
|
mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
|
||||||
|
|
||||||
if (boot->file)
|
if (boot->file)
|
||||||
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
|
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
|
||||||
@@ -903,10 +865,11 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
|
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
|
||||||
pxe_misc(mess, end, uuid);
|
pxe_misc(mess, end, uuid);
|
||||||
prune_vendor_opts(tagif_netid);
|
prune_vendor_opts(tagif_netid);
|
||||||
do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||||
|
|
||||||
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", mess->xid);
|
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", mess->xid);
|
||||||
return ignore ? 0 : dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
log_tags(tagif_netid, ntohl(mess->xid));
|
||||||
|
return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1037,15 +1000,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid)))
|
if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
|
|
||||||
|
|
||||||
if (context->netid.net)
|
if (context->netid.net)
|
||||||
{
|
{
|
||||||
context->netid.next = netid;
|
context->netid.next = netid;
|
||||||
netid = &context->netid;
|
tagif_netid = run_tag_if(&context->netid);
|
||||||
tagif_netid = run_tag_if(netid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_tags(tagif_netid, ntohl(mess->xid));
|
||||||
|
|
||||||
|
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
|
||||||
|
|
||||||
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
|
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
|
||||||
clear_packet(mess, end);
|
clear_packet(mess, end);
|
||||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
|
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
|
||||||
@@ -1058,9 +1022,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
option_put(mess, end, OPTION_T2, 4, (time*7)/8);
|
option_put(mess, end, OPTION_T2, 4, (time*7)/8);
|
||||||
}
|
}
|
||||||
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
|
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
|
||||||
domain, tagif_netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len);
|
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||||
|
|
||||||
return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
return dhcp_packet_size(mess, agent_id, real_end);
|
||||||
|
|
||||||
case DHCPREQUEST:
|
case DHCPREQUEST:
|
||||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||||
@@ -1091,12 +1055,30 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
|
|
||||||
if (!context)
|
if (!context)
|
||||||
{
|
{
|
||||||
/* In auth mode, a REQUEST sent to the wrong server
|
/* Handle very strange configs where clients have more than one route to the server.
|
||||||
should be faulted, so that the client establishes
|
If a clients idea of its server-id matches any of our DHCP interfaces, we let it pass.
|
||||||
communication with us, otherwise, silently ignore. */
|
Have to set override to make sure we echo back the correct server-id */
|
||||||
if (!option_bool(OPT_AUTHORITATIVE))
|
struct irec *intr;
|
||||||
return 0;
|
|
||||||
message = _("wrong server-ID");
|
enumerate_interfaces();
|
||||||
|
|
||||||
|
for (intr = daemon->interfaces; intr; intr = intr->next)
|
||||||
|
if (intr->addr.sa.sa_family == AF_INET &&
|
||||||
|
intr->addr.in.sin_addr.s_addr == option_addr(opt).s_addr &&
|
||||||
|
intr->tftp_ok)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (intr)
|
||||||
|
override = intr->addr.in.sin_addr;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* In auth mode, a REQUEST sent to the wrong server
|
||||||
|
should be faulted, so that the client establishes
|
||||||
|
communication with us, otherwise, silently ignore. */
|
||||||
|
if (!option_bool(OPT_AUTHORITATIVE))
|
||||||
|
return 0;
|
||||||
|
message = _("wrong server-ID");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1204,7 +1186,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
|
|
||||||
else if (!lease)
|
else if (!lease)
|
||||||
{
|
{
|
||||||
if ((lease = lease_allocate(mess->yiaddr)))
|
if ((lease = lease4_allocate(mess->yiaddr)))
|
||||||
do_classes = 1;
|
do_classes = 1;
|
||||||
else
|
else
|
||||||
message = _("no leases left");
|
message = _("no leases left");
|
||||||
@@ -1235,9 +1217,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
if (context->netid.net)
|
if (context->netid.net)
|
||||||
{
|
{
|
||||||
context->netid.next = netid;
|
context->netid.next = netid;
|
||||||
netid = &context->netid;
|
tagif_netid = run_tag_if( &context->netid);
|
||||||
tagif_netid = run_tag_if(netid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_tags(tagif_netid, ntohl(mess->xid));
|
||||||
|
|
||||||
#ifdef HAVE_SCRIPT
|
#ifdef HAVE_SCRIPT
|
||||||
if (do_classes && daemon->lease_change_command)
|
if (do_classes && daemon->lease_change_command)
|
||||||
@@ -1247,7 +1230,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
if (mess->giaddr.s_addr)
|
if (mess->giaddr.s_addr)
|
||||||
lease->giaddr = mess->giaddr;
|
lease->giaddr = mess->giaddr;
|
||||||
|
|
||||||
lease->changed = 1;
|
lease->flags |= LEASE_CHANGED;
|
||||||
free(lease->extradata);
|
free(lease->extradata);
|
||||||
lease->extradata = NULL;
|
lease->extradata = NULL;
|
||||||
lease->extradata_size = lease->extradata_len = 0;
|
lease->extradata_size = lease->extradata_len = 0;
|
||||||
@@ -1263,8 +1246,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
add_extradata_opt(lease, NULL);
|
add_extradata_opt(lease, NULL);
|
||||||
else
|
else
|
||||||
for (n = tagif_netid; n; n = n->next)
|
for (n = tagif_netid; n; n = n->next)
|
||||||
add_extradata_data(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
|
{
|
||||||
|
struct dhcp_netid *n1;
|
||||||
|
/* kill dupes */
|
||||||
|
for (n1 = n->next; n1; n1 = n1->next)
|
||||||
|
if (strcmp(n->net, n1->net) == 0)
|
||||||
|
break;
|
||||||
|
if (!n1)
|
||||||
|
lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
|
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
|
||||||
{
|
{
|
||||||
int len = option_len(opt);
|
int len = option_len(opt);
|
||||||
@@ -1272,7 +1263,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
/* If the user-class option started as counted strings, the first byte will be zero. */
|
/* If the user-class option started as counted strings, the first byte will be zero. */
|
||||||
if (len != 0 && ucp[0] == 0)
|
if (len != 0 && ucp[0] == 0)
|
||||||
ucp++, len--;
|
ucp++, len--;
|
||||||
add_extradata_data(lease, ucp, len, 0);
|
lease_add_extradata(lease, ucp, len, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -1285,7 +1276,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
}
|
}
|
||||||
|
|
||||||
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
|
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
|
||||||
lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len);
|
lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len, now);
|
||||||
|
|
||||||
/* if all the netids in the ignore_name list are present, ignore client-supplied name */
|
/* if all the netids in the ignore_name list are present, ignore client-supplied name */
|
||||||
if (!hostname_auth)
|
if (!hostname_auth)
|
||||||
@@ -1316,10 +1307,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hostname)
|
if (hostname)
|
||||||
lease_set_hostname(lease, hostname, hostname_auth);
|
lease_set_hostname(lease, hostname, hostname_auth, get_domain(lease->addr), domain);
|
||||||
|
|
||||||
lease_set_expires(lease, time, now);
|
lease_set_expires(lease, time, now);
|
||||||
lease_set_interface(lease, int_index);
|
lease_set_interface(lease, int_index, now);
|
||||||
|
|
||||||
if (override.s_addr != 0)
|
if (override.s_addr != 0)
|
||||||
lease->override = override;
|
lease->override = override;
|
||||||
@@ -1340,10 +1331,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
|
option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
|
||||||
}
|
}
|
||||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
|
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
|
||||||
domain, tagif_netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len);
|
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
return dhcp_packet_size(mess, agent_id, real_end);
|
||||||
|
|
||||||
case DHCPINFORM:
|
case DHCPINFORM:
|
||||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||||
@@ -1366,15 +1357,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
|
|
||||||
if (!hostname && (hostname = host_from_dns(mess->ciaddr)))
|
if (!hostname && (hostname = host_from_dns(mess->ciaddr)))
|
||||||
domain = get_domain(mess->ciaddr);
|
domain = get_domain(mess->ciaddr);
|
||||||
|
|
||||||
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid);
|
|
||||||
|
|
||||||
if (context && context->netid.net)
|
if (context && context->netid.net)
|
||||||
{
|
{
|
||||||
context->netid.next = netid;
|
context->netid.next = netid;
|
||||||
netid = &context->netid;
|
tagif_netid = run_tag_if(&context->netid);
|
||||||
tagif_netid = run_tag_if(netid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_tags(tagif_netid, ntohl(mess->xid));
|
||||||
|
|
||||||
|
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid);
|
||||||
|
|
||||||
if (lease)
|
if (lease)
|
||||||
{
|
{
|
||||||
@@ -1395,50 +1387,19 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
else
|
else
|
||||||
time = (unsigned int)difftime(lease->expires, now);
|
time = (unsigned int)difftime(lease->expires, now);
|
||||||
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
|
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
|
||||||
lease_set_interface(lease, int_index);
|
lease_set_interface(lease, int_index, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
|
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
|
||||||
domain, tagif_netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len);
|
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||||
|
|
||||||
*is_inform = 1; /* handle reply differently */
|
*is_inform = 1; /* handle reply differently */
|
||||||
return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
return dhcp_packet_size(mess, agent_id, real_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (o->len > len)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (o->len == 0)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (o->flags & DHOPT_HEX)
|
|
||||||
{
|
|
||||||
if (memcmp_masked(o->val, p, o->len, o->u.wildcard_mask))
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
for (i = 0; i <= (len - o->len); )
|
|
||||||
{
|
|
||||||
if (memcmp(o->val, p + i, o->len) == 0)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (o->flags & DHOPT_STRING)
|
|
||||||
i++;
|
|
||||||
else
|
|
||||||
i += o->len;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* find a good value to use as MAC address for logging and address-allocation hashing.
|
/* find a good value to use as MAC address for logging and address-allocation hashing.
|
||||||
This is normally just the chaddr field from the DHCP packet,
|
This is normally just the chaddr field from the DHCP packet,
|
||||||
but eg Firewire will have hlen == 0 and use the client-id instead.
|
but eg Firewire will have hlen == 0 and use the client-id instead.
|
||||||
@@ -1494,7 +1455,7 @@ static struct in_addr server_id(struct dhcp_context *context, struct in_addr ove
|
|||||||
{
|
{
|
||||||
if (override.s_addr != 0)
|
if (override.s_addr != 0)
|
||||||
return override;
|
return override;
|
||||||
else if (context)
|
else if (context && context->local.s_addr != 0)
|
||||||
return context->local;
|
return context->local;
|
||||||
else
|
else
|
||||||
return fallback;
|
return fallback;
|
||||||
@@ -1524,51 +1485,12 @@ static int sanitise(unsigned char *opt, char *buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SCRIPT
|
#ifdef HAVE_SCRIPT
|
||||||
static void add_extradata_data(struct dhcp_lease *lease, unsigned char *data, size_t len, int delim)
|
|
||||||
{
|
|
||||||
if ((lease->extradata_size - lease->extradata_len) < (len + 1))
|
|
||||||
{
|
|
||||||
size_t newsz = lease->extradata_len + len + 100;
|
|
||||||
unsigned char *new = whine_malloc(newsz);
|
|
||||||
|
|
||||||
if (!new)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (lease->extradata)
|
|
||||||
{
|
|
||||||
memcpy(new, lease->extradata, lease->extradata_len);
|
|
||||||
free(lease->extradata);
|
|
||||||
}
|
|
||||||
|
|
||||||
lease->extradata = new;
|
|
||||||
lease->extradata_size = newsz;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len != 0)
|
|
||||||
memcpy(lease->extradata + lease->extradata_len, data, len);
|
|
||||||
lease->extradata[lease->extradata_len + len] = delim;
|
|
||||||
lease->extradata_len += len + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt)
|
static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt)
|
||||||
{
|
{
|
||||||
if (!opt)
|
if (!opt)
|
||||||
add_extradata_data(lease, NULL, 0, 0);
|
lease_add_extradata(lease, NULL, 0, 0);
|
||||||
else
|
else
|
||||||
{
|
lease_add_extradata(lease, option_ptr(opt, 0), option_len(opt), 0);
|
||||||
size_t i, len = option_len(opt);
|
|
||||||
unsigned char *ucp = option_ptr(opt, 0);
|
|
||||||
|
|
||||||
/* check for embeded NULLs */
|
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
if (ucp[i] == 0)
|
|
||||||
{
|
|
||||||
len = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
add_extradata_data(lease, ucp, len, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1606,30 +1528,10 @@ static void log_options(unsigned char *start, u32 xid)
|
|||||||
{
|
{
|
||||||
while (*start != OPTION_END)
|
while (*start != OPTION_END)
|
||||||
{
|
{
|
||||||
int is_ip, is_name, i;
|
char *optname = option_string(AF_INET, start[0], option_ptr(start, 0), option_len(start), daemon->namebuff, MAXDNAME);
|
||||||
char *text = option_string(start[0], &is_ip, &is_name);
|
|
||||||
unsigned char trunc = option_len(start);
|
|
||||||
|
|
||||||
if (is_ip)
|
my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d %s %s",
|
||||||
for (daemon->namebuff[0]= 0, i = 0; i <= trunc - INADDRSZ; i += INADDRSZ)
|
ntohl(xid), option_len(start), start[0], optname, daemon->namebuff);
|
||||||
{
|
|
||||||
if (i != 0)
|
|
||||||
strncat(daemon->namebuff, ", ", 256 - strlen(daemon->namebuff));
|
|
||||||
strncat(daemon->namebuff, inet_ntoa(option_addr_arr(start, i)), 256 - strlen(daemon->namebuff));
|
|
||||||
}
|
|
||||||
else if (!is_name || !sanitise(start, daemon->namebuff))
|
|
||||||
{
|
|
||||||
if (trunc > 13)
|
|
||||||
trunc = 13;
|
|
||||||
print_mac(daemon->namebuff, option_ptr(start, 0), trunc);
|
|
||||||
}
|
|
||||||
|
|
||||||
my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d%s%s%s%s%s",
|
|
||||||
ntohl(xid), option_len(start), start[0],
|
|
||||||
text ? ":" : "", text ? text : "",
|
|
||||||
trunc == 0 ? "" : " ",
|
|
||||||
trunc == 0 ? "" : daemon->namebuff,
|
|
||||||
trunc == option_len(start) ? "" : "...");
|
|
||||||
start += start[1] + 2;
|
start += start[1] + 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1684,22 +1586,17 @@ static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct in_addr option_addr_arr(unsigned char *opt, int offset)
|
static struct in_addr option_addr(unsigned char *opt)
|
||||||
{
|
{
|
||||||
/* this worries about unaligned data in the option. */
|
/* this worries about unaligned data in the option. */
|
||||||
/* struct in_addr is network byte order */
|
/* struct in_addr is network byte order */
|
||||||
struct in_addr ret;
|
struct in_addr ret;
|
||||||
|
|
||||||
memcpy(&ret, option_ptr(opt, offset), INADDRSZ);
|
memcpy(&ret, option_ptr(opt, 0), INADDRSZ);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct in_addr option_addr(unsigned char *opt)
|
|
||||||
{
|
|
||||||
return option_addr_arr(opt, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int option_uint(unsigned char *opt, int offset, int size)
|
static unsigned int option_uint(unsigned char *opt, int offset, int size)
|
||||||
{
|
{
|
||||||
/* this worries about unaligned data and byte order */
|
/* this worries about unaligned data and byte order */
|
||||||
@@ -1734,15 +1631,12 @@ static unsigned char *find_overload(struct dhcp_packet *mess)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *netid,
|
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end)
|
||||||
unsigned char *agent_id, unsigned char *real_end)
|
|
||||||
{
|
{
|
||||||
unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
|
unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
|
||||||
unsigned char *overload;
|
unsigned char *overload;
|
||||||
size_t ret;
|
size_t ret;
|
||||||
struct dhcp_netid_list *id_list;
|
|
||||||
struct dhcp_netid *n;
|
|
||||||
|
|
||||||
/* move agent_id back down to the end of the packet */
|
/* move agent_id back down to the end of the packet */
|
||||||
if (agent_id)
|
if (agent_id)
|
||||||
{
|
{
|
||||||
@@ -1751,27 +1645,6 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *neti
|
|||||||
memset(p, 0, real_end - p); /* in case of overlap */
|
memset(p, 0, real_end - p); /* in case of overlap */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We do logging too */
|
|
||||||
if (netid && option_bool(OPT_LOG_OPTS))
|
|
||||||
{
|
|
||||||
char *s = daemon->namebuff;
|
|
||||||
for (*s = 0; netid; netid = netid->next)
|
|
||||||
{
|
|
||||||
/* kill dupes. */
|
|
||||||
for (n = netid->next; n; n = n->next)
|
|
||||||
if (strcmp(netid->net, n->net) == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!n)
|
|
||||||
{
|
|
||||||
strncat (s, netid->net, (MAXDNAME-1) - strlen(s));
|
|
||||||
if (netid->next)
|
|
||||||
strncat (s, ", ", (MAXDNAME-1) - strlen(s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), ntohl(mess->xid), s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add END options to the regions. */
|
/* add END options to the regions. */
|
||||||
overload = find_overload(mess);
|
overload = find_overload(mess);
|
||||||
|
|
||||||
@@ -1796,12 +1669,6 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *neti
|
|||||||
|
|
||||||
*p++ = OPTION_END;
|
*p++ = OPTION_END;
|
||||||
|
|
||||||
for (id_list = daemon->force_broadcast; id_list; id_list = id_list->next)
|
|
||||||
if ((!id_list->list) || match_netid(id_list->list, netid, 0))
|
|
||||||
break;
|
|
||||||
if (id_list)
|
|
||||||
mess->flags |= htons(0x8000); /* force broadcast */
|
|
||||||
|
|
||||||
if (option_bool(OPT_LOG_OPTS))
|
if (option_bool(OPT_LOG_OPTS))
|
||||||
{
|
{
|
||||||
if (mess->siaddr.s_addr != 0)
|
if (mess->siaddr.s_addr != 0)
|
||||||
@@ -1951,20 +1818,14 @@ static int in_list(unsigned char *list, int opt)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dhcp_opt *option_find2(struct dhcp_netid *netid, struct dhcp_opt *opts, int opt)
|
static struct dhcp_opt *option_find2(int opt)
|
||||||
{
|
{
|
||||||
struct dhcp_opt *tmp;
|
struct dhcp_opt *opts;
|
||||||
for (tmp = opts; tmp; tmp = tmp->next)
|
|
||||||
if (tmp->opt == opt && !(tmp->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
|
for (opts = daemon->dhcp_opts; opts; opts = opts->next)
|
||||||
if (match_netid(tmp->netid, netid, 0))
|
if (opts->opt == opt && (opts->flags & DHOPT_TAGOK))
|
||||||
return tmp;
|
return opts;
|
||||||
|
|
||||||
/* No match, look for one without a netid */
|
|
||||||
for (tmp = opts; tmp; tmp = tmp->next)
|
|
||||||
if (tmp->opt == opt && !(tmp->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
|
|
||||||
if (match_netid(tmp->netid, netid, 1))
|
|
||||||
return tmp;
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2064,7 +1925,7 @@ static int prune_vendor_opts(struct dhcp_netid *netid)
|
|||||||
return force;
|
return force;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local)
|
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now)
|
||||||
{
|
{
|
||||||
#define NUM_OPTS 4
|
#define NUM_OPTS 4
|
||||||
|
|
||||||
@@ -2121,8 +1982,9 @@ static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct
|
|||||||
return daemon->dhcp_opts;
|
return daemon->dhcp_opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
boot_server = service->basename ? local : service->server;
|
boot_server = service->basename ? local :
|
||||||
|
(service->sname ? a_record_from_hosts(service->sname, now) : service->server);
|
||||||
|
|
||||||
if (boot_server.s_addr != 0)
|
if (boot_server.s_addr != 0)
|
||||||
{
|
{
|
||||||
if (q - (unsigned char *)daemon->dhcp_buff3 + 3 + INADDRSZ >= 253)
|
if (q - (unsigned char *)daemon->dhcp_buff3 + 3 + INADDRSZ >= 253)
|
||||||
@@ -2213,13 +2075,14 @@ static void do_options(struct dhcp_context *context,
|
|||||||
unsigned char *end,
|
unsigned char *end,
|
||||||
unsigned char *req_options,
|
unsigned char *req_options,
|
||||||
char *hostname,
|
char *hostname,
|
||||||
char *domain, char *config_domain,
|
char *domain,
|
||||||
struct dhcp_netid *netid,
|
struct dhcp_netid *netid,
|
||||||
struct in_addr subnet_addr,
|
struct in_addr subnet_addr,
|
||||||
unsigned char fqdn_flags,
|
unsigned char fqdn_flags,
|
||||||
int null_term, int pxe_arch,
|
int null_term, int pxe_arch,
|
||||||
unsigned char *uuid,
|
unsigned char *uuid,
|
||||||
int vendor_class_len)
|
int vendor_class_len,
|
||||||
|
time_t now)
|
||||||
{
|
{
|
||||||
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
|
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
|
||||||
struct dhcp_boot *boot;
|
struct dhcp_boot *boot;
|
||||||
@@ -2228,22 +2091,26 @@ static void do_options(struct dhcp_context *context,
|
|||||||
unsigned char f0 = 0, s0 = 0;
|
unsigned char f0 = 0, s0 = 0;
|
||||||
int done_file = 0, done_server = 0;
|
int done_file = 0, done_server = 0;
|
||||||
int done_vendor_class = 0;
|
int done_vendor_class = 0;
|
||||||
|
struct dhcp_netid *tagif;
|
||||||
|
struct dhcp_netid_list *id_list;
|
||||||
|
|
||||||
if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
|
/* filter options based on tags, those we want get DHOPT_TAGOK bit set */
|
||||||
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, hostname);
|
if (context)
|
||||||
|
context->netid.next = NULL;
|
||||||
|
tagif = option_filter(netid, context && context->netid.net ? &context->netid : NULL, config_opts);
|
||||||
|
|
||||||
/* logging */
|
/* logging */
|
||||||
if (option_bool(OPT_LOG_OPTS) && req_options)
|
if (option_bool(OPT_LOG_OPTS) && req_options)
|
||||||
{
|
{
|
||||||
char *q = daemon->namebuff;
|
char *q = daemon->namebuff;
|
||||||
for (i = 0; req_options[i] != OPTION_END; i++)
|
for (i = 0; req_options[i] != OPTION_END; i++)
|
||||||
{
|
{
|
||||||
char *s = option_string(req_options[i], NULL, NULL);
|
char *s = option_string(AF_INET, req_options[i], NULL, 0, NULL, 0);
|
||||||
q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
|
q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
|
||||||
"%d%s%s%s",
|
"%d%s%s%s",
|
||||||
req_options[i],
|
req_options[i],
|
||||||
s ? ":" : "",
|
strlen(s) != 0 ? ":" : "",
|
||||||
s ? s : "",
|
s,
|
||||||
req_options[i+1] == OPTION_END ? "" : ", ");
|
req_options[i+1] == OPTION_END ? "" : ", ");
|
||||||
if (req_options[i+1] == OPTION_END || (q - daemon->namebuff) > 40)
|
if (req_options[i+1] == OPTION_END || (q - daemon->namebuff) > 40)
|
||||||
{
|
{
|
||||||
@@ -2253,6 +2120,12 @@ static void do_options(struct dhcp_context *context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (id_list = daemon->force_broadcast; id_list; id_list = id_list->next)
|
||||||
|
if ((!id_list->list) || match_netid(id_list->list, netid, 0))
|
||||||
|
break;
|
||||||
|
if (id_list)
|
||||||
|
mess->flags |= htons(0x8000); /* force broadcast */
|
||||||
|
|
||||||
if (context)
|
if (context)
|
||||||
mess->siaddr = context->local;
|
mess->siaddr = context->local;
|
||||||
|
|
||||||
@@ -2262,7 +2135,7 @@ static void do_options(struct dhcp_context *context,
|
|||||||
provide an manual option to disable it.
|
provide an manual option to disable it.
|
||||||
Some PXE ROMs have bugs (surprise!) and need zero-terminated
|
Some PXE ROMs have bugs (surprise!) and need zero-terminated
|
||||||
names, so we always send those. */
|
names, so we always send those. */
|
||||||
if ((boot = find_boot(netid)))
|
if ((boot = find_boot(tagif)))
|
||||||
{
|
{
|
||||||
if (boot->sname)
|
if (boot->sname)
|
||||||
{
|
{
|
||||||
@@ -2284,8 +2157,10 @@ static void do_options(struct dhcp_context *context,
|
|||||||
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
|
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boot->next_server.s_addr)
|
if (boot->next_server.s_addr)
|
||||||
mess->siaddr = boot->next_server;
|
mess->siaddr = boot->next_server;
|
||||||
|
else if (boot->tftp_sname)
|
||||||
|
mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* Use the values of the relevant options if no dhcp-boot given and
|
/* Use the values of the relevant options if no dhcp-boot given and
|
||||||
@@ -2294,20 +2169,20 @@ static void do_options(struct dhcp_context *context,
|
|||||||
dhcp-optsfile. */
|
dhcp-optsfile. */
|
||||||
{
|
{
|
||||||
if ((!req_options || !in_list(req_options, OPTION_FILENAME)) &&
|
if ((!req_options || !in_list(req_options, OPTION_FILENAME)) &&
|
||||||
(opt = option_find2(netid, config_opts, OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
|
(opt = option_find2(OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
|
||||||
{
|
{
|
||||||
strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1);
|
strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1);
|
||||||
done_file = 1;
|
done_file = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
|
if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
|
||||||
(opt = option_find2(netid, config_opts, OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
|
(opt = option_find2(OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
|
||||||
{
|
{
|
||||||
strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1);
|
strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1);
|
||||||
done_server = 1;
|
done_server = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((opt = option_find2(netid, config_opts, OPTION_END)))
|
if ((opt = option_find2(OPTION_END)))
|
||||||
mess->siaddr.s_addr = ((struct in_addr *)opt->val)->s_addr;
|
mess->siaddr.s_addr = ((struct in_addr *)opt->val)->s_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2335,36 +2210,36 @@ static void do_options(struct dhcp_context *context,
|
|||||||
/* replies to DHCPINFORM may not have a valid context */
|
/* replies to DHCPINFORM may not have a valid context */
|
||||||
if (context)
|
if (context)
|
||||||
{
|
{
|
||||||
if (!option_find2(netid, config_opts, OPTION_NETMASK))
|
if (!option_find2(OPTION_NETMASK))
|
||||||
option_put(mess, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
|
option_put(mess, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
|
||||||
|
|
||||||
/* May not have a "guessed" broadcast address if we got no packets via a relay
|
/* May not have a "guessed" broadcast address if we got no packets via a relay
|
||||||
from this net yet (ie just unicast renewals after a restart */
|
from this net yet (ie just unicast renewals after a restart */
|
||||||
if (context->broadcast.s_addr &&
|
if (context->broadcast.s_addr &&
|
||||||
!option_find2(netid, config_opts, OPTION_BROADCAST))
|
!option_find2(OPTION_BROADCAST))
|
||||||
option_put(mess, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
|
option_put(mess, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
|
||||||
|
|
||||||
/* Same comments as broadcast apply, and also may not be able to get a sensible
|
/* Same comments as broadcast apply, and also may not be able to get a sensible
|
||||||
default when using subnet select. User must configure by steam in that case. */
|
default when using subnet select. User must configure by steam in that case. */
|
||||||
if (context->router.s_addr &&
|
if (context->router.s_addr &&
|
||||||
in_list(req_options, OPTION_ROUTER) &&
|
in_list(req_options, OPTION_ROUTER) &&
|
||||||
!option_find2(netid, config_opts, OPTION_ROUTER))
|
!option_find2(OPTION_ROUTER))
|
||||||
option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
|
option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
|
||||||
|
|
||||||
if (in_list(req_options, OPTION_DNSSERVER) &&
|
if (in_list(req_options, OPTION_DNSSERVER) &&
|
||||||
!option_find2(netid, config_opts, OPTION_DNSSERVER))
|
!option_find2(OPTION_DNSSERVER))
|
||||||
option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
|
option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (domain && in_list(req_options, OPTION_DOMAINNAME) &&
|
if (domain && in_list(req_options, OPTION_DOMAINNAME) &&
|
||||||
!option_find2(netid, config_opts, OPTION_DOMAINNAME))
|
!option_find2(OPTION_DOMAINNAME))
|
||||||
option_put_string(mess, end, OPTION_DOMAINNAME, domain, null_term);
|
option_put_string(mess, end, OPTION_DOMAINNAME, domain, null_term);
|
||||||
|
|
||||||
/* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */
|
/* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */
|
||||||
if (hostname)
|
if (hostname)
|
||||||
{
|
{
|
||||||
if (in_list(req_options, OPTION_HOSTNAME) &&
|
if (in_list(req_options, OPTION_HOSTNAME) &&
|
||||||
!option_find2(netid, config_opts, OPTION_HOSTNAME))
|
!option_find2(OPTION_HOSTNAME))
|
||||||
option_put_string(mess, end, OPTION_HOSTNAME, hostname, null_term);
|
option_put_string(mess, end, OPTION_HOSTNAME, hostname, null_term);
|
||||||
|
|
||||||
if (fqdn_flags != 0)
|
if (fqdn_flags != 0)
|
||||||
@@ -2413,6 +2288,10 @@ static void do_options(struct dhcp_context *context,
|
|||||||
{
|
{
|
||||||
int optno = opt->opt;
|
int optno = opt->opt;
|
||||||
|
|
||||||
|
/* netids match and not encapsulated? */
|
||||||
|
if (!(opt->flags & DHOPT_TAGOK))
|
||||||
|
continue;
|
||||||
|
|
||||||
/* was it asked for, or are we sending it anyway? */
|
/* was it asked for, or are we sending it anyway? */
|
||||||
if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
|
if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
|
||||||
continue;
|
continue;
|
||||||
@@ -2431,10 +2310,6 @@ static void do_options(struct dhcp_context *context,
|
|||||||
if (optno == OPTION_FILENAME && done_file)
|
if (optno == OPTION_FILENAME && done_file)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* netids match and not encapsulated? */
|
|
||||||
if (opt != option_find2(netid, config_opts, optno))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* For the options we have default values on
|
/* For the options we have default values on
|
||||||
dhc-option=<optionno> means "don't include this option"
|
dhc-option=<optionno> means "don't include this option"
|
||||||
not "include a zero-length option" */
|
not "include a zero-length option" */
|
||||||
@@ -2472,8 +2347,8 @@ static void do_options(struct dhcp_context *context,
|
|||||||
|
|
||||||
/* Now send options to be encapsulated in arbitrary options,
|
/* Now send options to be encapsulated in arbitrary options,
|
||||||
eg dhcp-option=encap:172,17,.......
|
eg dhcp-option=encap:172,17,.......
|
||||||
Also hand vendor-identifying vendor-encapsulated options,
|
Also handle vendor-identifying vendor-encapsulated options,
|
||||||
dhcp-option = rfc3925-encap:13,17,.......
|
dhcp-option = vi-encap:13,17,.......
|
||||||
The may be more that one "outer" to do, so group
|
The may be more that one "outer" to do, so group
|
||||||
all the options which match each outer in turn. */
|
all the options which match each outer in turn. */
|
||||||
for (opt = config_opts; opt; opt = opt->next)
|
for (opt = config_opts; opt; opt = opt->next)
|
||||||
@@ -2501,7 +2376,7 @@ static void do_options(struct dhcp_context *context,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
o->flags |= DHOPT_ENCAP_DONE;
|
o->flags |= DHOPT_ENCAP_DONE;
|
||||||
if (match_netid(o->netid, netid, 1) &&
|
if (match_netid(o->netid, tagif, 1) &&
|
||||||
((o->flags & DHOPT_FORCE) || in_list(req_options, outer)))
|
((o->flags & DHOPT_FORCE) || in_list(req_options, outer)))
|
||||||
{
|
{
|
||||||
o->flags |= DHOPT_ENCAP_MATCH;
|
o->flags |= DHOPT_ENCAP_MATCH;
|
||||||
@@ -2535,12 +2410,12 @@ static void do_options(struct dhcp_context *context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
force_encap = prune_vendor_opts(netid);
|
force_encap = prune_vendor_opts(tagif);
|
||||||
|
|
||||||
if (context && pxe_arch != -1)
|
if (context && pxe_arch != -1)
|
||||||
{
|
{
|
||||||
pxe_misc(mess, end, uuid);
|
pxe_misc(mess, end, uuid);
|
||||||
config_opts = pxe_opts(pxe_arch, netid, context->local);
|
config_opts = pxe_opts(pxe_arch, tagif, context->local, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT)) &&
|
if ((force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT)) &&
|
||||||
|
|||||||
+1502
File diff suppressed because it is too large.
Load diff
+250
@@ -0,0 +1,250 @@
|
|||||||
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 dated June, 1991, or
|
||||||
|
(at your option) version 3 dated 29 June, 2007.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
|
||||||
|
#include <netinet/icmp6.h>
|
||||||
|
|
||||||
|
static int map_rebuild = 0;
|
||||||
|
static int ping_id = 0;
|
||||||
|
|
||||||
|
void slaac_add_addrs(struct dhcp_lease *lease, time_t now)
|
||||||
|
{
|
||||||
|
struct slaac_address *slaac, *old, **up;
|
||||||
|
struct dhcp_context *context;
|
||||||
|
|
||||||
|
if (!(lease->flags & LEASE_HAVE_HWADDR) ||
|
||||||
|
lease->last_interface == 0 ||
|
||||||
|
!lease->hostname)
|
||||||
|
return ;
|
||||||
|
|
||||||
|
old = lease->slaac_address;
|
||||||
|
lease->slaac_address = NULL;
|
||||||
|
|
||||||
|
for (context = daemon->ra_contexts; context; context = context->next)
|
||||||
|
if ((context->flags & CONTEXT_RA_NAME) && lease->last_interface == context->if_index)
|
||||||
|
{
|
||||||
|
struct in6_addr addr = context->start6;
|
||||||
|
if (lease->hwaddr_len == 6 &&
|
||||||
|
(lease->hwaddr_type == ARPHRD_ETHER || lease->hwaddr_type == ARPHRD_IEEE802))
|
||||||
|
{
|
||||||
|
/* convert MAC address to EUI-64 */
|
||||||
|
memcpy(&addr.s6_addr[8], lease->hwaddr, 3);
|
||||||
|
memcpy(&addr.s6_addr[13], &lease->hwaddr[3], 3);
|
||||||
|
addr.s6_addr[11] = 0xff;
|
||||||
|
addr.s6_addr[12] = 0xfe;
|
||||||
|
}
|
||||||
|
#if defined(ARPHRD_EUI64)
|
||||||
|
else if (lease->hwaddr_len == 8 &&
|
||||||
|
lease->hwaddr_type == ARPHRD_EUI64)
|
||||||
|
memcpy(&addr.s6_addr[8], lease->hwaddr, 8);
|
||||||
|
#endif
|
||||||
|
#if defined(ARPHRD_IEEE1394) && defined(ARPHRD_EUI64)
|
||||||
|
else if (lease->clid_len == 9 &&
|
||||||
|
lease->clid[0] == ARPHRD_EUI64 &&
|
||||||
|
lease->hwaddr_type == ARPHRD_IEEE1394)
|
||||||
|
/* firewire has EUI-64 identifier as clid */
|
||||||
|
memcpy(&addr.s6_addr[8], &lease->clid[1], 8);
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
addr.s6_addr[8] ^= 0x02;
|
||||||
|
|
||||||
|
/* check if we already have this one */
|
||||||
|
for (up = &old, slaac = old; slaac; slaac = slaac->next)
|
||||||
|
{
|
||||||
|
if (IN6_ARE_ADDR_EQUAL(&addr, &slaac->addr))
|
||||||
|
{
|
||||||
|
*up = slaac->next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
up = &slaac->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No, make new one */
|
||||||
|
if (!slaac && (slaac = whine_malloc(sizeof(struct slaac_address))))
|
||||||
|
{
|
||||||
|
slaac->ping_time = now;
|
||||||
|
slaac->backoff = 1;
|
||||||
|
slaac->addr = addr;
|
||||||
|
slaac->local = context->local6;
|
||||||
|
/* Do RA's to prod it */
|
||||||
|
ra_start_unsolicted(now, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slaac)
|
||||||
|
{
|
||||||
|
slaac->next = lease->slaac_address;
|
||||||
|
lease->slaac_address = slaac;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free any no reused */
|
||||||
|
for (; old; old = slaac)
|
||||||
|
{
|
||||||
|
slaac = old->next;
|
||||||
|
free(old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
|
||||||
|
{
|
||||||
|
struct dhcp_context *context;
|
||||||
|
struct dhcp_lease *lease;
|
||||||
|
struct slaac_address *slaac;
|
||||||
|
time_t next_event = 0;
|
||||||
|
|
||||||
|
for (context = daemon->ra_contexts; context; context = context->next)
|
||||||
|
if ((context->flags & CONTEXT_RA_NAME))
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* nothing configured */
|
||||||
|
if (!context)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
/* confirmed or given up? */
|
||||||
|
if (slaac->backoff == 0 || slaac->ping_time == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (difftime(slaac->ping_time, now) <= 0.0)
|
||||||
|
{
|
||||||
|
struct ping_packet *ping;
|
||||||
|
struct sockaddr_in6 addr;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
save_counter(0);
|
||||||
|
ping = expand(sizeof(struct ping_packet));
|
||||||
|
ping->type = ICMP6_ECHO_REQUEST;
|
||||||
|
ping->code = 0;
|
||||||
|
ping->identifier = ping_id;
|
||||||
|
ping->sequence_no = slaac->backoff;
|
||||||
|
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
|
addr.sin6_len = sizeof(struct sockaddr_in6);
|
||||||
|
#endif
|
||||||
|
addr.sin6_family = AF_INET6;
|
||||||
|
addr.sin6_port = htons(IPPROTO_ICMPV6);
|
||||||
|
addr.sin6_addr = slaac->addr;
|
||||||
|
|
||||||
|
if (send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0),
|
||||||
|
(union mysockaddr *)&addr, (struct all_addr *)&slaac->local,
|
||||||
|
lease->last_interface, &err))
|
||||||
|
{
|
||||||
|
slaac->ping_time += (1 << (slaac->backoff - 1)) + (rand16()/21785); /* 0 - 3 */
|
||||||
|
if (slaac->backoff > 4)
|
||||||
|
slaac->ping_time += rand16()/4000; /* 0 - 15 */
|
||||||
|
if (slaac->backoff < 12)
|
||||||
|
slaac->backoff++;
|
||||||
|
}
|
||||||
|
else if (err == EHOSTUNREACH)
|
||||||
|
slaac->ping_time = 0; /* Give up */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slaac->ping_time != 0 &&
|
||||||
|
(next_event == 0 || difftime(next_event, slaac->ping_time) >= 0.0))
|
||||||
|
next_event = slaac->ping_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
return next_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface, struct dhcp_lease *leases)
|
||||||
|
{
|
||||||
|
struct dhcp_lease *lease;
|
||||||
|
struct slaac_address *slaac;
|
||||||
|
struct ping_packet *ping = (struct ping_packet *)packet;
|
||||||
|
int gotone = 0;
|
||||||
|
|
||||||
|
if (ping->identifier == ping_id)
|
||||||
|
for (lease = leases; lease; lease = lease->next)
|
||||||
|
for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
|
||||||
|
if (slaac->backoff != 0 && IN6_ARE_ADDR_EQUAL(sender, &slaac->addr))
|
||||||
|
{
|
||||||
|
slaac->backoff = 0;
|
||||||
|
gotone = 1;
|
||||||
|
inet_ntop(AF_INET6, sender, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
my_syslog(MS_DHCP | LOG_INFO, "SLAAC-CONFIRM(%s) %s %s", interface, daemon->addrbuff, lease->hostname);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
+80
-46
@@ -1,4 +1,4 @@
|
|||||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -57,8 +57,7 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
int mtuflag = IP_PMTUDISC_DONT;
|
int mtuflag = IP_PMTUDISC_DONT;
|
||||||
#endif
|
#endif
|
||||||
char namebuff[IF_NAMESIZE];
|
char namebuff[IF_NAMESIZE];
|
||||||
char pretty_addr[ADDRSTRLEN];
|
char *name = NULL;
|
||||||
char *name;
|
|
||||||
char *prefix = daemon->tftp_prefix;
|
char *prefix = daemon->tftp_prefix;
|
||||||
struct tftp_prefix *pref;
|
struct tftp_prefix *pref;
|
||||||
struct interface_list *ir;
|
struct interface_list *ir;
|
||||||
@@ -96,9 +95,20 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
|
|
||||||
if (option_bool(OPT_NOWILD))
|
if (option_bool(OPT_NOWILD))
|
||||||
{
|
{
|
||||||
addr = listen->iface->addr;
|
if (listen->iface)
|
||||||
mtu = listen->iface->mtu;
|
{
|
||||||
name = listen->iface->name;
|
addr = listen->iface->addr;
|
||||||
|
mtu = listen->iface->mtu;
|
||||||
|
name = listen->iface->name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* we're listening on an address that doesn't appear on an interface,
|
||||||
|
ask the kernel what the socket is bound to */
|
||||||
|
socklen_t tcp_len = sizeof(union mysockaddr);
|
||||||
|
if (getsockname(listen->tftpfd, (struct sockaddr *)&addr, &tcp_len) == -1)
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -114,7 +124,7 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
#if defined(HAVE_LINUX_NETWORK)
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
if (listen->family == AF_INET)
|
if (listen->family == AF_INET)
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
unsigned char *c;
|
unsigned char *c;
|
||||||
@@ -163,7 +173,7 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
if (listen->family == AF_INET6)
|
if (listen->family == AF_INET6)
|
||||||
{
|
{
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == daemon->v6pktinfo)
|
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
unsigned char *c;
|
unsigned char *c;
|
||||||
@@ -184,10 +194,10 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if (listen->family == AF_INET6)
|
if (listen->family == AF_INET6)
|
||||||
check = iface_check(AF_INET6, (struct all_addr *)&addr.in6.sin6_addr, name, &if_index);
|
check = iface_check(AF_INET6, (struct all_addr *)&addr.in6.sin6_addr, name);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
check = iface_check(AF_INET, (struct all_addr *)&addr.in.sin_addr, name, &if_index);
|
check = iface_check(AF_INET, (struct all_addr *)&addr.in.sin_addr, name);
|
||||||
|
|
||||||
/* wierd TFTP service override */
|
/* wierd TFTP service override */
|
||||||
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
|
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
|
||||||
@@ -212,27 +222,35 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
mtu = ifr.ifr_mtu;
|
mtu = ifr.ifr_mtu;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check for per-interface prefix */
|
if (name)
|
||||||
for (pref = daemon->if_prefix; pref; pref = pref->next)
|
{
|
||||||
if (strcmp(pref->interface, name) == 0)
|
/* check for per-interface prefix */
|
||||||
prefix = pref->prefix;
|
for (pref = daemon->if_prefix; pref; pref = pref->next)
|
||||||
|
if (strcmp(pref->interface, name) == 0)
|
||||||
/* wierd TFTP interfaces disable special options. */
|
prefix = pref->prefix;
|
||||||
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
|
|
||||||
if (strcmp(ir->interface, name) == 0)
|
/* wierd TFTP interfaces disable special options. */
|
||||||
special = 1;
|
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
|
||||||
|
if (strcmp(ir->interface, name) == 0)
|
||||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
special = 1;
|
||||||
addr.sa.sa_len = sa_len(&addr);
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (listen->family == AF_INET)
|
if (listen->family == AF_INET)
|
||||||
addr.in.sin_port = htons(port);
|
{
|
||||||
|
addr.in.sin_port = htons(port);
|
||||||
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
|
addr.in.sin_len = sizeof(addr.in);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
addr.in6.sin6_port = htons(port);
|
addr.in6.sin6_port = htons(port);
|
||||||
addr.in6.sin6_flowinfo = 0;
|
addr.in6.sin6_flowinfo = 0;
|
||||||
|
addr.in6.sin6_scope_id = 0;
|
||||||
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
|
addr.in6.sin6_len = sizeof(addr.in6);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -255,14 +273,14 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
transfer->opt_blocksize = transfer->opt_transize = 0;
|
transfer->opt_blocksize = transfer->opt_transize = 0;
|
||||||
transfer->netascii = transfer->carrylf = 0;
|
transfer->netascii = transfer->carrylf = 0;
|
||||||
|
|
||||||
prettyprint_addr(&peer, pretty_addr);
|
prettyprint_addr(&peer, daemon->addrbuff);
|
||||||
|
|
||||||
/* if we have a nailed-down range, iterate until we find a free one. */
|
/* if we have a nailed-down range, iterate until we find a free one. */
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (bind(transfer->sockfd, &addr.sa, sizeof(addr)) == -1 ||
|
if (bind(transfer->sockfd, &addr.sa, sa_len(&addr)) == -1 ||
|
||||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||||
setsockopt(transfer->sockfd, SOL_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 ||
|
setsockopt(transfer->sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 ||
|
||||||
#endif
|
#endif
|
||||||
!fix_fd(transfer->sockfd))
|
!fix_fd(transfer->sockfd))
|
||||||
{
|
{
|
||||||
@@ -293,7 +311,7 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
!(filename = next(&p, end)) ||
|
!(filename = next(&p, end)) ||
|
||||||
!(mode = next(&p, end)) ||
|
!(mode = next(&p, end)) ||
|
||||||
(strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
|
(strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
|
||||||
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), pretty_addr);
|
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), daemon->addrbuff);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (strcasecmp(mode, "netascii") == 0)
|
if (strcasecmp(mode, "netascii") == 0)
|
||||||
@@ -343,7 +361,7 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
size_t oldlen = strlen(daemon->namebuff);
|
size_t oldlen = strlen(daemon->namebuff);
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
|
|
||||||
strncat(daemon->namebuff, pretty_addr, (MAXDNAME-1) - strlen(daemon->namebuff));
|
strncat(daemon->namebuff, daemon->addrbuff, (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||||
strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
|
strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||||
|
|
||||||
/* remove unique-directory if it doesn't exist */
|
/* remove unique-directory if it doesn't exist */
|
||||||
@@ -473,7 +491,6 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
|||||||
{
|
{
|
||||||
struct tftp_transfer *transfer, *tmp, **up;
|
struct tftp_transfer *transfer, *tmp, **up;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
char pretty_addr[ADDRSTRLEN];
|
|
||||||
|
|
||||||
struct ack {
|
struct ack {
|
||||||
unsigned short op, block;
|
unsigned short op, block;
|
||||||
@@ -489,7 +506,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
|||||||
/* we overwrote the buffer... */
|
/* we overwrote the buffer... */
|
||||||
daemon->srv_save = NULL;
|
daemon->srv_save = NULL;
|
||||||
|
|
||||||
prettyprint_addr(&transfer->peer, pretty_addr);
|
prettyprint_addr(&transfer->peer, daemon->addrbuff);
|
||||||
|
|
||||||
if ((len = recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0)) >= (ssize_t)sizeof(struct ack))
|
if ((len = recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0)) >= (ssize_t)sizeof(struct ack))
|
||||||
{
|
{
|
||||||
@@ -512,16 +529,16 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
|||||||
err = "";
|
err = "";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *q, *r;
|
unsigned char *q, *r;
|
||||||
for (q = r = err; *r; r++)
|
for (q = r = (unsigned char *)err; *r; r++)
|
||||||
if (isprint((int)*r))
|
if (isprint(*r))
|
||||||
*(q++) = *r;
|
*(q++) = *r;
|
||||||
*q = 0;
|
*q = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
my_syslog(MS_TFTP | LOG_ERR, _("error %d %s received from %s"),
|
my_syslog(MS_TFTP | LOG_ERR, _("error %d %s received from %s"),
|
||||||
(int)ntohs(mess->block), err,
|
(int)ntohs(mess->block), err,
|
||||||
pretty_addr);
|
daemon->addrbuff);
|
||||||
|
|
||||||
/* Got err, ensure we take abort */
|
/* Got err, ensure we take abort */
|
||||||
transfer->timeout = now;
|
transfer->timeout = now;
|
||||||
@@ -552,7 +569,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
|||||||
if (len != 0)
|
if (len != 0)
|
||||||
{
|
{
|
||||||
my_syslog(MS_TFTP | LOG_ERR, _("failed sending %s to %s"),
|
my_syslog(MS_TFTP | LOG_ERR, _("failed sending %s to %s"),
|
||||||
transfer->file->filename, pretty_addr);
|
transfer->file->filename, daemon->addrbuff);
|
||||||
len = 0;
|
len = 0;
|
||||||
endcon = 1;
|
endcon = 1;
|
||||||
}
|
}
|
||||||
@@ -565,10 +582,12 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
|||||||
if (endcon || len == 0)
|
if (endcon || len == 0)
|
||||||
{
|
{
|
||||||
if (!endcon)
|
if (!endcon)
|
||||||
my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), transfer->file->filename, pretty_addr);
|
my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), transfer->file->filename, daemon->addrbuff);
|
||||||
/* unlink */
|
/* unlink */
|
||||||
*up = tmp;
|
*up = tmp;
|
||||||
free_transfer(transfer);
|
/* put on queue to be sent to script and deleted */
|
||||||
|
transfer->next = daemon->tftp_done_trans;
|
||||||
|
daemon->tftp_done_trans = transfer;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -685,15 +704,13 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
|
|||||||
for (i = 0, newcarrylf = 0; i < size; i++)
|
for (i = 0, newcarrylf = 0; i < size; i++)
|
||||||
if (mess->data[i] == '\n' && ( i != 0 || !transfer->carrylf))
|
if (mess->data[i] == '\n' && ( i != 0 || !transfer->carrylf))
|
||||||
{
|
{
|
||||||
if (size == transfer->blocksize)
|
transfer->expansion++;
|
||||||
{
|
|
||||||
transfer->expansion++;
|
if (size != transfer->blocksize)
|
||||||
if (i == size - 1)
|
|
||||||
newcarrylf = 1; /* don't expand LF again if it moves to the next block */
|
|
||||||
}
|
|
||||||
else
|
|
||||||
size++; /* room in this block */
|
size++; /* room in this block */
|
||||||
|
else if (i == size - 1)
|
||||||
|
newcarrylf = 1; /* don't expand LF again if it moves to the next block */
|
||||||
|
|
||||||
/* make space and insert CR */
|
/* make space and insert CR */
|
||||||
memmove(&mess->data[i+1], &mess->data[i], size - (i + 1));
|
memmove(&mess->data[i+1], &mess->data[i], size - (i + 1));
|
||||||
mess->data[i] = '\r';
|
mess->data[i] = '\r';
|
||||||
@@ -708,4 +725,21 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int do_tftp_script_run(void)
|
||||||
|
{
|
||||||
|
struct tftp_transfer *transfer;
|
||||||
|
|
||||||
|
if ((transfer = daemon->tftp_done_trans))
|
||||||
|
{
|
||||||
|
daemon->tftp_done_trans = transfer->next;
|
||||||
|
#ifdef HAVE_SCRIPT
|
||||||
|
queue_tftp(transfer->file->size, transfer->file->filename, &transfer->peer);
|
||||||
|
#endif
|
||||||
|
free_transfer(transfer);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
+63
-15
@@ -1,4 +1,4 @@
|
|||||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
#include <sys/times.h>
|
#include <sys/times.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef LOCALEDIR
|
#if defined(LOCALEDIR) || defined(HAVE_IDN)
|
||||||
#include <idna.h>
|
#include <idna.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -43,11 +43,9 @@ unsigned short rand16(void)
|
|||||||
|
|
||||||
/* SURF random number generator */
|
/* SURF random number generator */
|
||||||
|
|
||||||
typedef unsigned int uint32;
|
static u32 seed[32];
|
||||||
|
static u32 in[12];
|
||||||
static uint32 seed[32];
|
static u32 out[8];
|
||||||
static uint32 in[12];
|
|
||||||
static uint32 out[8];
|
|
||||||
|
|
||||||
void rand_init()
|
void rand_init()
|
||||||
{
|
{
|
||||||
@@ -66,7 +64,7 @@ void rand_init()
|
|||||||
|
|
||||||
static void surf(void)
|
static void surf(void)
|
||||||
{
|
{
|
||||||
uint32 t[12]; uint32 x; uint32 sum = 0;
|
u32 t[12]; u32 x; u32 sum = 0;
|
||||||
int r; int i; int loop;
|
int r; int i; int loop;
|
||||||
|
|
||||||
for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i];
|
for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i];
|
||||||
@@ -120,11 +118,11 @@ static int check_name(char *in)
|
|||||||
dotgap = 0;
|
dotgap = 0;
|
||||||
else if (++dotgap > MAXLABEL)
|
else if (++dotgap > MAXLABEL)
|
||||||
return 0;
|
return 0;
|
||||||
else if (isascii(c) && iscntrl(c))
|
else if (isascii((unsigned char)c) && iscntrl((unsigned char)c))
|
||||||
/* iscntrl only gives expected results for ascii */
|
/* iscntrl only gives expected results for ascii */
|
||||||
return 0;
|
return 0;
|
||||||
#ifndef LOCALEDIR
|
#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
|
||||||
else if (!isascii(c))
|
else if (!isascii((unsigned char)c))
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
else if (c != ' ')
|
else if (c != ' ')
|
||||||
@@ -170,7 +168,7 @@ int legal_hostname(char *name)
|
|||||||
char *canonicalise(char *in, int *nomem)
|
char *canonicalise(char *in, int *nomem)
|
||||||
{
|
{
|
||||||
char *ret = NULL;
|
char *ret = NULL;
|
||||||
#ifdef LOCALEDIR
|
#if defined(LOCALEDIR) || defined(HAVE_IDN)
|
||||||
int rc;
|
int rc;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -180,7 +178,7 @@ char *canonicalise(char *in, int *nomem)
|
|||||||
if (!check_name(in))
|
if (!check_name(in))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
#ifdef LOCALEDIR
|
#if defined(LOCALEDIR) || defined(HAVE_IDN)
|
||||||
if ((rc = idna_to_ascii_lz(in, &ret, 0)) != IDNA_SUCCESS)
|
if ((rc = idna_to_ascii_lz(in, &ret, 0)) != IDNA_SUCCESS)
|
||||||
{
|
{
|
||||||
if (ret)
|
if (ret)
|
||||||
@@ -322,6 +320,48 @@ int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
|
|||||||
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
|
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
|
||||||
|
{
|
||||||
|
int pfbytes = prefixlen >> 3;
|
||||||
|
int pfbits = prefixlen & 7;
|
||||||
|
|
||||||
|
if (memcmp(&a->s6_addr, &b->s6_addr, pfbytes) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (pfbits == 0 ||
|
||||||
|
(a->s6_addr[pfbytes] >> (8 - pfbits) != b->s6_addr[pfbytes] >> (8 - pfbits)))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return least signigicant 64 bits if IPv6 address */
|
||||||
|
u64 addr6part(struct in6_addr *addr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
u64 ret = 0;
|
||||||
|
|
||||||
|
for (i = 8; i < 16; i++)
|
||||||
|
ret = (ret << 8) + addr->s6_addr[i];
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setaddr6part(struct in6_addr *addr, u64 host)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 15; i >= 8; i--)
|
||||||
|
{
|
||||||
|
addr->s6_addr[i] = host;
|
||||||
|
host = host >> 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* returns port number from address */
|
/* returns port number from address */
|
||||||
int prettyprint_addr(union mysockaddr *addr, char *buf)
|
int prettyprint_addr(union mysockaddr *addr, char *buf)
|
||||||
{
|
{
|
||||||
@@ -335,7 +375,15 @@ int prettyprint_addr(union mysockaddr *addr, char *buf)
|
|||||||
}
|
}
|
||||||
else if (addr->sa.sa_family == AF_INET6)
|
else if (addr->sa.sa_family == AF_INET6)
|
||||||
{
|
{
|
||||||
|
char name[IF_NAMESIZE];
|
||||||
inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN);
|
inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN);
|
||||||
|
if (addr->in6.sin6_scope_id != 0 &&
|
||||||
|
if_indextoname(addr->in6.sin6_scope_id, name) &&
|
||||||
|
strlen(buf) + strlen(name) + 2 <= ADDRSTRLEN)
|
||||||
|
{
|
||||||
|
strcat(buf, "%");
|
||||||
|
strcat(buf, name);
|
||||||
|
}
|
||||||
port = ntohs(addr->in6.sin6_port);
|
port = ntohs(addr->in6.sin6_port);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -379,7 +427,7 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
|
|||||||
while (maxlen == -1 || i < maxlen)
|
while (maxlen == -1 || i < maxlen)
|
||||||
{
|
{
|
||||||
for (r = in; *r != 0 && *r != ':' && *r != '-'; r++)
|
for (r = in; *r != 0 && *r != ':' && *r != '-'; r++)
|
||||||
if (!isxdigit((int)*r))
|
if (*r != '*' && !isxdigit((unsigned char)*r))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (*r == 0)
|
if (*r == 0)
|
||||||
@@ -477,7 +525,7 @@ void bump_maxfd(int fd, int *max)
|
|||||||
int retry_send(void)
|
int retry_send(void)
|
||||||
{
|
{
|
||||||
struct timespec waiter;
|
struct timespec waiter;
|
||||||
if (errno == EAGAIN)
|
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||||
{
|
{
|
||||||
waiter.tv_sec = 0;
|
waiter.tv_sec = 0;
|
||||||
waiter.tv_nsec = 10000;
|
waiter.tv_nsec = 10000;
|
||||||
|
|||||||
Reference in new issue
Block a user