Compare commits
235 Commits
v2.72
...
v2.76test1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c0c36f54b | ||
|
|
d6b749af91 | ||
|
|
14ffa0770b | ||
|
|
87985855ad | ||
|
|
a2bc254bed | ||
|
|
a7b27e84fa | ||
|
|
529b030228 | ||
|
|
4caa86dd7d | ||
|
|
e1abeeeec2 | ||
|
|
40205a053e | ||
|
|
b8ac466209 | ||
|
|
d1377fa3c4 | ||
|
|
fa79466c2a | ||
|
|
a93bd4b016 | ||
|
|
407a1f3e95 | ||
|
|
4b6af5d53f | ||
|
|
7aa3f9af66 | ||
|
|
f7cf749943 | ||
|
|
aa300f7167 | ||
|
|
c7f3bd2ac8 | ||
|
|
22fe2fd038 | ||
|
|
7480aeffc8 | ||
|
|
bec366b404 | ||
|
|
e06e6e34bf | ||
|
|
832e47beab | ||
|
|
df3d54f776 | ||
|
|
22c0f4fe87 | ||
|
|
9e4cf47ee8 | ||
|
|
fdc97e1383 | ||
|
|
a18bf3149a | ||
|
|
1566bacb2c | ||
|
|
e6e751b066 | ||
|
|
8de875f0fb | ||
|
|
4ace25c5d6 | ||
|
|
1e5051228d | ||
|
|
926332a764 | ||
|
|
d05dd58de1 | ||
|
|
f7443d76f7 | ||
|
|
f344dbc622 | ||
|
|
f4d0c660ca | ||
|
|
1801a29226 | ||
|
|
92be34a407 | ||
|
|
bb58f63ce5 | ||
|
|
367341f745 | ||
|
|
eddf365284 | ||
|
|
a63b8b89e6 | ||
|
|
5757371d43 | ||
|
|
b633de9413 | ||
|
|
c49778df4a | ||
|
|
53a9173fc0 | ||
|
|
d917275e48 | ||
|
|
cc7cb0b893 | ||
|
|
ec0628c4b2 | ||
|
|
97b1d25764 | ||
|
|
33702ab1f8 | ||
|
|
11867dc28c | ||
|
|
d3a8b39c7d | ||
|
|
15379ea1f2 | ||
|
|
efef497b89 | ||
|
|
5aa5f0ff2f | ||
|
|
5bb88f0963 | ||
|
|
1d03016bbc | ||
|
|
ce5732e84f | ||
|
|
a86fdf437e | ||
|
|
3e86d316c4 | ||
|
|
d67ecac59d | ||
|
|
fa14bec83b | ||
|
|
14a4ae883d | ||
|
|
3b799c826d | ||
|
|
b40f26c019 | ||
|
|
dd4ad9ac7e | ||
|
|
2dbba34b2c | ||
|
|
c2bcd1e183 | ||
|
|
d64c81fff7 | ||
|
|
93be5b1e02 | ||
|
|
9a31b68b59 | ||
|
|
0007ee9064 | ||
|
|
67ab3285b5 | ||
|
|
41a8d9e99b | ||
|
|
90477fb794 | ||
|
|
98079ea898 | ||
|
|
4790115455 | ||
|
|
27b78d990b | ||
|
|
77607cbea0 | ||
|
|
102208df69 | ||
|
|
6de81f1250 | ||
|
|
20fd11e11a | ||
|
|
9cdcfe9f19 | ||
|
|
5e3e464ac4 | ||
|
|
3a3965ac21 | ||
|
|
a7369bef8a | ||
|
|
d2aa7dfbb6 | ||
|
|
63ec5d1264 | ||
|
|
f6381cf482 | ||
|
|
34b5d19488 | ||
|
|
d6cb7e4815 | ||
|
|
d389e0191b | ||
|
|
d3699bb6bc | ||
|
|
13480e8c2a | ||
|
|
5b3b93f80a | ||
|
|
b69e845b1c | ||
|
|
90c3822bfa | ||
|
|
c895a0626d | ||
|
|
b842bc97bb | ||
|
|
0f38fa05a6 | ||
|
|
45c5cb1f8f | ||
|
|
f6d6956261 | ||
|
|
60176c7bf4 | ||
|
|
362c9303da | ||
|
|
5e95a552ee | ||
|
|
90cb222551 | ||
|
|
850163288d | ||
|
|
e3ec6f0bd7 | ||
|
|
f7bfbdc872 | ||
|
|
4918bd5505 | ||
|
|
9bad339af8 | ||
|
|
ba4fc0f996 | ||
|
|
2fd5bc952d | ||
|
|
0ddb8769bb | ||
|
|
654f59e762 | ||
|
|
d91b1fd402 | ||
|
|
c6d82c9ba6 | ||
|
|
4d25cf89d5 | ||
|
|
24e9207e13 | ||
|
|
89130d91d6 | ||
|
|
d644b2a17d | ||
|
|
bd7bfa21c4 | ||
|
|
403de05925 | ||
|
|
46c89f2bd0 | ||
|
|
23facf0d77 | ||
|
|
549b1a478c | ||
|
|
7f8565b94c | ||
|
|
06568c6636 | ||
|
|
5d07d77e75 | ||
|
|
62018e1f72 | ||
|
|
7c0f2543a7 | ||
|
|
ca85a28241 | ||
|
|
585840b033 | ||
|
|
dec180ac00 | ||
|
|
86fa104692 | ||
|
|
b059c96dc6 | ||
|
|
a77cec8d58 | ||
|
|
64bcff1c7c | ||
|
|
2ed162ac20 | ||
|
|
e66b4dff3c | ||
|
|
8efd731cc4 | ||
|
|
a5ae1f8587 | ||
|
|
b8f16556d3 | ||
|
|
cbe379ad6b | ||
|
|
338b340be9 | ||
|
|
a006eb7e14 | ||
|
|
554b580e97 | ||
|
|
0df29f5e23 | ||
|
|
b4c0f092d8 | ||
|
|
78c6184752 | ||
|
|
38440b204d | ||
|
|
ad4a8ff7d9 | ||
|
|
04b0ac0537 | ||
|
|
982faf4024 | ||
|
|
fe3992f9fa | ||
|
|
7aa970e2c7 | ||
|
|
30d0879ed5 | ||
|
|
fd6ad9e481 | ||
|
|
794fccca7f | ||
|
|
394ff492da | ||
|
|
1e153945de | ||
|
|
0b8a5a30a7 | ||
|
|
150162bc37 | ||
|
|
8805283088 | ||
|
|
65c7212000 | ||
|
|
979fe86bc8 | ||
|
|
ff841ebf5a | ||
|
|
360f2513ab | ||
|
|
4c960fa90a | ||
|
|
9003b50b13 | ||
|
|
f6e62e2af9 | ||
|
|
47b9ac59c7 | ||
|
|
0705a7e2d5 | ||
|
|
28b879ac47 | ||
|
|
caeea190f1 | ||
|
|
8ff70de618 | ||
|
|
ee4d1cea92 | ||
|
|
f4f400776b | ||
|
|
b467a454b4 | ||
|
|
efb8b5566a | ||
|
|
f9c863708c | ||
|
|
2941d3ac89 | ||
|
|
d36b732c4c | ||
|
|
d2c5458e31 | ||
|
|
8d8a54ec79 | ||
|
|
1062667618 | ||
|
|
6ef15b34ca | ||
|
|
3d04f46334 | ||
|
|
aff3396280 | ||
|
|
70d1873dd9 | ||
|
|
0491805d2f | ||
|
|
61b838dd57 | ||
|
|
fbf01f7046 | ||
|
|
5f4dc5c6ca | ||
|
|
2ae195f5a7 | ||
|
|
393415597c | ||
|
|
ae4624bf46 | ||
|
|
5e321739db | ||
|
|
9f79ee4ae3 | ||
|
|
28de38768e | ||
|
|
25cf5e373e | ||
|
|
424c4a8a53 | ||
|
|
97e618a0e3 | ||
|
|
d8dbd903d0 | ||
|
|
81c538efce | ||
|
|
d310ab7ecb | ||
|
|
0b1008d367 | ||
|
|
32fc6dbe03 | ||
|
|
83d2ed09fc | ||
|
|
fbc5205702 | ||
|
|
cbc6524234 | ||
|
|
094b5c3d90 | ||
|
|
3267804598 | ||
|
|
476693678e | ||
|
|
bd9520b7ad | ||
|
|
3ad3f3bbd4 | ||
|
|
ad946d555d | ||
|
|
800c5cc1e7 | ||
|
|
857973e6f7 | ||
|
|
9c448c8018 | ||
|
|
193de4abf5 | ||
|
|
98906275a0 | ||
|
|
b9ff5c8f43 | ||
|
|
3d9d2dd001 | ||
|
|
17b475912f | ||
|
|
e9828b6f66 | ||
|
|
72eba2bffc | ||
|
|
6ac3bc0452 | ||
|
|
00cd9d5519 | ||
|
|
f2658275b2 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -3,7 +3,7 @@ src/*.mo
|
||||
src/dnsmasq.pot
|
||||
src/dnsmasq
|
||||
src/dnsmasq_baseline
|
||||
src/.configured
|
||||
src/.copts_*
|
||||
contrib/wrt/dhcp_lease_time
|
||||
contrib/wrt/dhcp_release
|
||||
debian/base/
|
||||
|
||||
226
CHANGELOG
226
CHANGELOG
@@ -1,3 +1,227 @@
|
||||
version 2.76
|
||||
Include 0.0.0.0/8 in DNS rebind checks. This range
|
||||
translates to hosts on the local network, or, at
|
||||
least, 0.0.0.0 accesses the local host, so could
|
||||
be targets for DNS rebinding. See RFC 5735 section 3
|
||||
for details. Thanks to Stephen Röttger for the bug report.
|
||||
|
||||
Enhance --add-subnet to allow arbitrary subnet addresses.
|
||||
Thanks to Ed Barsley for the patch.
|
||||
|
||||
Respect the --no-resolv flag in inotify code. Fixes bug
|
||||
which caused dnsmasq to fail to start if a resolv-file
|
||||
was a dangling symbolic link, even of --no-resolv set.
|
||||
Thanks to Alexander Kurtz for spotting the problem.
|
||||
|
||||
Fix crash when an A or AAAA record is defined locally,
|
||||
in a hosts file, and an upstream server sends a reply
|
||||
that the same name is empty. Thanks to Edwin Török for
|
||||
the patch.
|
||||
|
||||
Fix failure to correctly calculate cache-size when
|
||||
reading a hosts-file fails. Thanks to André Glüpker
|
||||
for the patch.
|
||||
|
||||
Fix wrong answer to simple name query when --domain-needed
|
||||
set, but no upstream servers configured. Dnsmasq returned
|
||||
REFUSED, in this case, when it should be the same as when
|
||||
upstream servers are configured - NOERROR. Thanks to
|
||||
Allain Legacy for spotting the problem.
|
||||
|
||||
Return REFUSED when running out of forwarding table slots,
|
||||
not SERVFAIL.
|
||||
|
||||
Add --max-port configuration. Thanks to Hans Dedecker for
|
||||
the patch.
|
||||
|
||||
Add --script-arp and two new functions for the dhcp-script.
|
||||
These are "arp" and "arp-old" which announce the arrival and
|
||||
removal of entries in the ARP or nieghbour tables.
|
||||
|
||||
Extend --add-mac to allow a new encoding of the MAC address
|
||||
as base64, by configurting --add-mac=base64
|
||||
|
||||
Add --add-cpe-id option.
|
||||
|
||||
Don't crash with divide-by-zero if an IPv6 dhcp-range
|
||||
is declared as a whole /64.
|
||||
(ie xx::0 to xx::ffff:ffff:ffff:ffff)
|
||||
Thanks to Laurent Bendel for spotting this problem.
|
||||
|
||||
Add support for a TTL parameter in --host-record and
|
||||
--cname.
|
||||
|
||||
Add --dhcp-ttl option.
|
||||
|
||||
Add --tftp-mtu option. Thanks to Patrick McLean for the
|
||||
initial patch.
|
||||
|
||||
Check return-code of inet_pton() when parsing dhcp-option.
|
||||
Bad addresses could fail to generate errors and result in
|
||||
garbage dhcp-options being sent. Thanks to Marc Branchaud
|
||||
for spotting this.
|
||||
|
||||
Fix wrong value for EDNS UDP packet size when using
|
||||
--servers-file to define upstream DNS servers. Thanks to
|
||||
Scott Bonar for the bug report.
|
||||
|
||||
|
||||
version 2.75
|
||||
Fix reversion on 2.74 which caused 100% CPU use when a
|
||||
dhcp-script is configured. Thanks to Adrian Davey for
|
||||
reporting the bug and testing the fix.
|
||||
|
||||
|
||||
version 2.74
|
||||
Fix reversion in 2.73 where --conf-file would attempt to
|
||||
read the default file, rather than no file.
|
||||
|
||||
Fix inotify code to handle dangling symlinks better and
|
||||
not SEGV in some circumstances.
|
||||
|
||||
DNSSEC fix. In the case of a signed CNAME generated by a
|
||||
wildcard which pointed to an unsigned domain, the wrong
|
||||
status would be logged, and some necessary checks omitted.
|
||||
|
||||
|
||||
version 2.73
|
||||
Fix crash at startup when an empty suffix is supplied to
|
||||
--conf-dir, also trivial memory leak. Thanks to
|
||||
Tomas Hozza for spotting this.
|
||||
|
||||
Remove floor of 4096 on advertised EDNS0 packet size when
|
||||
DNSSEC in use, the original rationale for this has long gone.
|
||||
Thanks to Anders Kaseorg for spotting this.
|
||||
|
||||
Use inotify for checking on updates to /etc/resolv.conf and
|
||||
friends under Linux. This fixes race conditions when the files are
|
||||
updated rapidly and saves CPU by noy polling. To build
|
||||
a binary that runs on old Linux kernels without inotify,
|
||||
use make COPTS=-DNO_INOTIFY
|
||||
|
||||
Fix breakage of --domain=<domain>,<subnet>,local - only reverse
|
||||
queries were intercepted. THis appears to have been broken
|
||||
since 2.69. Thanks to Josh Stone for finding the bug.
|
||||
|
||||
Eliminate IPv6 privacy addresses and deprecated addresses from
|
||||
the answers given by --interface-name. Note that reverse queries
|
||||
(ie looking for names, given addresses) are not affected.
|
||||
Thanks to Michael Gorbach for the suggestion.
|
||||
|
||||
Fix crash in DNSSEC code with long RRs. Thanks to Marco Davids
|
||||
for the bug report.
|
||||
|
||||
Add --ignore-address option. Ignore replies to A-record
|
||||
queries which include the specified address. No error is
|
||||
generated, dnsmasq simply continues to listen for another
|
||||
reply. This is useful to defeat blocking strategies which
|
||||
rely on quickly supplying a forged answer to a DNS
|
||||
request for certain domains, before the correct answer can
|
||||
arrive. Thanks to Glen Huang for the patch.
|
||||
|
||||
Revisit the part of DNSSEC validation which determines if an
|
||||
unsigned answer is legit, or is in some part of the DNS
|
||||
tree which should be signed. Dnsmasq now works from the
|
||||
DNS root downward looking for the limit of signed
|
||||
delegations, rather than working bottom up. This is
|
||||
both more correct, and less likely to trip over broken
|
||||
nameservers in the unsigned parts of the DNS tree
|
||||
which don't respond well to DNSSEC queries.
|
||||
|
||||
Add --log-queries=extra option, which makes logs easier
|
||||
to search automatically.
|
||||
|
||||
Add --min-cache-ttl option. I've resisted this for a long
|
||||
time, on the grounds that disbelieving TTLs is never a
|
||||
good idea, but I've been persuaded that there are
|
||||
sometimes reasons to do it. (Step forward, GFW).
|
||||
To avoid misuse, there's a hard limit on the TTL
|
||||
floor of one hour. Thansk to RinSatsuki for the patch.
|
||||
|
||||
Cope with multiple interfaces with the same link-local
|
||||
address. (IPv6 addresses are scoped, so this is allowed.)
|
||||
Thanks to Cory Benfield for help with this.
|
||||
|
||||
Add --dhcp-hostsdir. This allows addition of new host
|
||||
configurations to a running dnsmasq instance much more
|
||||
cheaply than having dnsmasq re-read all its existing
|
||||
configuration each time.
|
||||
|
||||
Don't reply to DHCPv6 SOLICIT messages if we're not
|
||||
configured to do stateful DHCPv6. Thanks to Win King Wan
|
||||
for the patch.
|
||||
|
||||
Fix broken DNSSEC validation of ECDSA signatures.
|
||||
|
||||
Add --dnssec-timestamp option, which provides an automatic
|
||||
way to detect when the system time becomes valid after
|
||||
boot on systems without an RTC, whilst allowing DNS
|
||||
queries before the clock is valid so that NTP can run.
|
||||
Thanks to Kevin Darbyshire-Bryant for developing this idea.
|
||||
|
||||
Add --tftp-no-fail option. Thanks to Stefan Tomanek for
|
||||
the patch.
|
||||
|
||||
Fix crash caused by looking up servers.bind, CHAOS text
|
||||
record, when more than about five --servers= lines are
|
||||
in the dnsmasq config. This causes memory corruption
|
||||
which causes a crash later. Thanks to Matt Coddington for
|
||||
sterling work chasing this down.
|
||||
|
||||
Fix crash on receipt of certain malformed DNS requests.
|
||||
Thanks to Nick Sampanis for spotting the problem.
|
||||
Note that this is could allow the dnsmasq process's
|
||||
memory to be read by an attacker under certain
|
||||
circumstances, so it has a CVE, CVE-2015-3294
|
||||
|
||||
Fix crash in authoritative DNS code, if a .arpa zone
|
||||
is declared as authoritative, and then a PTR query which
|
||||
is not to be treated as authoritative arrived. Normally,
|
||||
directly declaring .arpa zone as authoritative is not
|
||||
done, so this crash wouldn't be seen. Instead the
|
||||
relevant .arpa zone should be specified as a subnet
|
||||
in the auth-zone declaration. Thanks to Johnny S. Lee
|
||||
for the bugreport and initial patch.
|
||||
|
||||
Fix authoritative DNS code to correctly reply to NS
|
||||
and SOA queries for .arpa zones for which we are
|
||||
declared authoritative by means of a subnet in auth-zone.
|
||||
Previously we provided correct answers to PTR queries
|
||||
in such zones (including NS and SOA) but not direct
|
||||
NS and SOA queries. Thanks to Johnny S. Lee for
|
||||
pointing out the problem.
|
||||
|
||||
Fix logging of DHCPREPLY which should be suppressed
|
||||
by quiet-dhcp6. Thanks to J. Pablo Abonia for
|
||||
spotting the problem.
|
||||
|
||||
Try and handle net connections with broken fragmentation
|
||||
that lose large UDP packets. If a server times out,
|
||||
reduce the maximum UDP packet size field in the EDNS0
|
||||
header to 1280 bytes. If it then answers, make that
|
||||
change permanent.
|
||||
|
||||
Check IPv4-mapped IPv6 addresses when --stop-rebind
|
||||
is active. Thanks to Jordan Milne for spotting this.
|
||||
|
||||
Allow DHCPv4 options T1 and T2 to be set using --dhcp-option.
|
||||
Thanks to Kevin Benton for patches and work on this.
|
||||
|
||||
Fix code for DHCPCONFIRM DHCPv6 messages to confirm addresses
|
||||
in the correct subnet, even of not in dynamic address
|
||||
allocation range. Thanks to Steve Hirsch for spotting
|
||||
the problem.
|
||||
|
||||
Add AddDhcpLease and DeleteDhcpLease DBus methods. Thanks
|
||||
to Nicolas Cavallari for the patch.
|
||||
|
||||
Allow configuration of router advertisements without the
|
||||
"on-link" bit set. Thanks to Neil Jerram for the patch.
|
||||
|
||||
Extend --bridge-interface to DHCPv6 and router
|
||||
advertisements. Thanks to Neil Jerram for the patch.
|
||||
|
||||
|
||||
version 2.72
|
||||
Add ra-advrouter mode, for RFC-3775 mobile IPv6 support.
|
||||
|
||||
@@ -41,7 +265,7 @@ version 2.72
|
||||
Fix problem with --local-service option on big-endian platforms
|
||||
Thanks to Richard Genoud for the patch.
|
||||
|
||||
|
||||
|
||||
version 2.71
|
||||
Subtle change to error handling to help DNSSEC validation
|
||||
when servers fail to provide NODATA answers for
|
||||
|
||||
21
Makefile
21
Makefile
@@ -1,4 +1,4 @@
|
||||
# dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
# dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -65,11 +65,16 @@ gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC NO_GMP --cop
|
||||
sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
|
||||
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
|
||||
|
||||
sum?=$(shell $(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' ')
|
||||
sum!=$(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' '
|
||||
copts_conf = .copts_$(sum)
|
||||
|
||||
objs = cache.o rfc1035.o util.o option.o forward.o network.o \
|
||||
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
|
||||
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
|
||||
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
|
||||
domain.o dnssec.o blockdata.o tables.o loop.o
|
||||
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
|
||||
poll.o rrfilter.o edns0.o arp.o
|
||||
|
||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
dns-protocol.h radv-protocol.h ip6addr.h
|
||||
@@ -83,7 +88,7 @@ all : $(BUILDDIR)
|
||||
|
||||
mostly_clean :
|
||||
rm -f $(BUILDDIR)/*.mo $(BUILDDIR)/*.pot
|
||||
rm -f $(BUILDDIR)/.configured $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq
|
||||
rm -f $(BUILDDIR)/.copts_* $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq
|
||||
|
||||
clean : mostly_clean
|
||||
rm -f $(BUILDDIR)/dnsmasq_baseline
|
||||
@@ -113,7 +118,7 @@ install-i18n : all-i18n install-common
|
||||
cd $(MAN); ../bld/install-man $(DESTDIR)$(MANDIR) $(INSTALL)
|
||||
|
||||
merge :
|
||||
@cd $(BUILDDIR) && $(MAKE) -f $(top)/Makefile dnsmasq.pot
|
||||
@cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile dnsmasq.pot
|
||||
for f in `cd $(PO); echo *.po`; do \
|
||||
echo -n msgmerge $(PO)/$$f && $(MSGMERGE) --no-wrap -U $(PO)/$$f $(BUILDDIR)/dnsmasq.pot; \
|
||||
done
|
||||
@@ -139,17 +144,19 @@ bloatcheck : $(BUILDDIR)/dnsmasq_baseline mostly_clean all
|
||||
|
||||
# rules below are targets in recusive makes with cwd=$(BUILDDIR)
|
||||
|
||||
.configured: $(hdrs)
|
||||
@rm -f *.o
|
||||
$(copts_conf): $(hdrs)
|
||||
@rm -f *.o .copts_*
|
||||
@touch $@
|
||||
|
||||
$(objs:.o=.c) $(hdrs):
|
||||
ln -s $(top)/$(SRC)/$@ .
|
||||
|
||||
$(objs): $(copts_conf) $(hdrs)
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $(COPTS) $(i18n) $(build_cflags) $(RPM_OPT_FLAGS) -c $<
|
||||
|
||||
dnsmasq : .configured $(hdrs) $(objs)
|
||||
dnsmasq : $(objs)
|
||||
$(CC) $(LDFLAGS) -o $@ $(objs) $(build_libs) $(LIBS)
|
||||
|
||||
dnsmasq.pot : $(objs:.o=.c) $(hdrs)
|
||||
|
||||
@@ -10,7 +10,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
||||
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
|
||||
radv.c slaac.c auth.c ipset.c domain.c \
|
||||
dnssec.c dnssec-openssl.c blockdata.c tables.c \
|
||||
loop.c
|
||||
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c
|
||||
|
||||
LOCAL_MODULE := dnsmasq
|
||||
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
# If there is more than one v[0-9].* tag, sort them and use the
|
||||
# first. This favours, eg v2.63 over 2.63rc6.
|
||||
|
||||
if which git >/dev/null 2>&1 && [ -d $1/.git ]; then
|
||||
cd $1; git describe | sed 's/^v//'
|
||||
if which git >/dev/null 2>&1 && \
|
||||
([ -d $1/.git ] || grep '^gitdir:' $1/.git >/dev/null 2>&1); then
|
||||
cd $1; git describe | sed 's/^v//'
|
||||
elif grep '\$Format:%d\$' $1/VERSION >/dev/null 2>&1; then
|
||||
# unsubstituted VERSION, but no git available.
|
||||
echo UNKNOWN
|
||||
@@ -20,7 +21,7 @@ else
|
||||
vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep ^v[0-9]`
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "${vers}" | sort | head -n 1 | sed 's/^v//'
|
||||
echo "${vers}" | sort -r | head -n 1 | sed 's/^v//'
|
||||
else
|
||||
cat $1/VERSION
|
||||
fi
|
||||
|
||||
18
contrib/reverse-dns/README
Normal file
18
contrib/reverse-dns/README
Normal file
@@ -0,0 +1,18 @@
|
||||
The script reads stdin and replaces all IP addresses with names before
|
||||
outputting it again. IPs from private networks are reverse looked up
|
||||
via dns. Other IP adresses are searched for in the dnsmasq query log.
|
||||
This gives names (CNAMEs if I understand DNS correctly) that are closer
|
||||
to the name the client originally asked for then the names obtained by
|
||||
reverse lookup. Just run
|
||||
|
||||
netstat -n -4 | ./reverse_replace.sh
|
||||
|
||||
to see what it does. It needs
|
||||
|
||||
log-queries
|
||||
log-facility=/var/log/dnsmasq.log
|
||||
|
||||
in the dnsmasq configuration.
|
||||
|
||||
The script runs on debian (with ash installed) and on busybox.
|
||||
|
||||
125
contrib/reverse-dns/reverse_replace.sh
Normal file
125
contrib/reverse-dns/reverse_replace.sh
Normal file
@@ -0,0 +1,125 @@
|
||||
#!/bin/ash
|
||||
# $Id: reverse_replace.sh 18 2015-03-01 16:12:35Z jo $
|
||||
#
|
||||
# Usage e.g.: netstat -n -4 | reverse_replace.sh
|
||||
# Parses stdin for IP4 addresses and replaces them
|
||||
# with names retrieved by parsing the dnsmasq log.
|
||||
# This currently only gives CNAMEs. But these
|
||||
# usually tell ou more than the mones from reverse
|
||||
# lookups.
|
||||
#
|
||||
# This has been tested on debian and asuswrt. Plese
|
||||
# report successful tests on other platforms.
|
||||
#
|
||||
# Author: Joachim Zobel <jz-2014@heute-morgen.de>
|
||||
# License: Consider this MIT style licensed. You can
|
||||
# do as you ike, but you must not remove my name.
|
||||
#
|
||||
|
||||
LOG=/var/log/dnsmasq.log
|
||||
MAX_LINES=15000
|
||||
|
||||
# sed regex do match IPs
|
||||
IP_regex='[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'
|
||||
# private IP ranges
|
||||
IP_private='\(^127\.\)\|\(^192\.168\.\)\|\(^10\.\)\|\(^172\.1[6-9]\.\)\|\(^172\.2[0-9]\.\)\|\(^172\.3[0-1]\.\)'
|
||||
|
||||
#######################################################################
|
||||
# Find Commands
|
||||
|
||||
HOST=nslookup
|
||||
if type host > /dev/null 2>&1; then
|
||||
# echo "No need for nslookup, host is there"
|
||||
HOST=host
|
||||
fi
|
||||
|
||||
#######################################################################
|
||||
# Functions
|
||||
|
||||
# Use shell variables for an (IP) lookup table
|
||||
create_lookup_table()
|
||||
{
|
||||
# Parse log into lookup table
|
||||
local CMDS="$( tail -"$MAX_LINES" "$LOG" | \
|
||||
grep " is $IP_regex" | \
|
||||
sed "s#.* \([^ ]*\) is \($IP_regex\).*#set_val \2 \1;#" )"
|
||||
|
||||
local IFS='
|
||||
'
|
||||
for CMD in $CMDS
|
||||
do
|
||||
eval $CMD
|
||||
done
|
||||
}
|
||||
|
||||
set_val()
|
||||
{
|
||||
local _IP=$(echo $1 | tr . _)
|
||||
local KEY="__IP__$_IP"
|
||||
eval "$KEY"=$2
|
||||
}
|
||||
|
||||
get_val()
|
||||
{
|
||||
local _IP=$(echo $1 | tr . _)
|
||||
local KEY="__IP__$_IP"
|
||||
eval echo -n '${'"$KEY"'}'
|
||||
}
|
||||
|
||||
dns_lookup()
|
||||
{
|
||||
local IP=$1
|
||||
|
||||
local RTN="$($HOST $IP | \
|
||||
sed 's#\s\+#\n#g' | \
|
||||
grep -v '^$' | \
|
||||
tail -1 | tr -d '\n' | \
|
||||
sed 's#\.$##')"
|
||||
if echo $RTN | grep -q NXDOMAIN; then
|
||||
echo -n $IP
|
||||
else
|
||||
echo -n "$RTN"
|
||||
fi
|
||||
}
|
||||
|
||||
reverse_dns()
|
||||
{
|
||||
local IP=$1
|
||||
|
||||
# Skip if it is not an IP
|
||||
if ! echo $IP | grep -q "^$IP_regex$"; then
|
||||
echo -n $IP
|
||||
return
|
||||
fi
|
||||
|
||||
# Do a dns lookup, if it is a local IP
|
||||
if echo $IP | grep -q $IP_private; then
|
||||
dns_lookup $IP
|
||||
return
|
||||
fi
|
||||
|
||||
local NAME="$(get_val $IP)"
|
||||
|
||||
if [ -z "$NAME" ]; then
|
||||
echo -n $IP
|
||||
else
|
||||
echo -n $NAME
|
||||
fi
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Main
|
||||
create_lookup_table
|
||||
|
||||
while read LINE; do
|
||||
for IP in $(echo "$LINE" | \
|
||||
sed "s#\b\($IP_regex\)\b#\n\1\n#g" | \
|
||||
grep $IP_regex)
|
||||
do
|
||||
NAME=`reverse_dns $IP `
|
||||
# echo "$NAME $IP"
|
||||
LINE=`echo "$LINE" | sed "s#$IP#$NAME#" `
|
||||
done
|
||||
echo $LINE
|
||||
done
|
||||
|
||||
@@ -277,6 +277,11 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (inet_addr(argv[2]) == INADDR_NONE)
|
||||
{
|
||||
perror("invalid ip address");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
lease.s_addr = inet_addr(argv[2]);
|
||||
server = find_interface(lease, nl, if_nametoindex(argv[1]));
|
||||
|
||||
@@ -169,6 +169,80 @@ Return an array of strings, each string is the IP address of an upstream
|
||||
server which has been found to loop queries back to this dnsmasq instance, and
|
||||
it therefore not being used.
|
||||
|
||||
AddDhcpLease
|
||||
------------
|
||||
|
||||
Returns nothing. Adds or updates a DHCP or DHCPv6 lease to the internal lease
|
||||
database, as if a client requested and obtained a lease.
|
||||
|
||||
If a lease for the IPv4 or IPv6 address already exist, it is overwritten.
|
||||
|
||||
Note that this function will trigger the DhcpLeaseAdded or DhcpLeaseUpdated
|
||||
D-Bus signal and will run the configured DHCP lease script accordingly.
|
||||
|
||||
This function takes many arguments which are the lease parameters:
|
||||
- A string with the textual representation of the IPv4 or IPv6 address of the
|
||||
client.
|
||||
|
||||
Examples:
|
||||
"192.168.1.115"
|
||||
"1003:1234:abcd::1%eth0"
|
||||
"2001:db8:abcd::1"
|
||||
|
||||
- A string representing the hardware address of the client, using the same
|
||||
format as the one used in the lease database.
|
||||
|
||||
Examples:
|
||||
|
||||
"00:23:45:67:89:ab"
|
||||
"06-00:20:e0:3b:13:af" (token ring)
|
||||
|
||||
- The hostname of the client, as an array of bytes (so there is no problem
|
||||
with non-ASCII character encoding). May be empty.
|
||||
|
||||
Example (for "hostname.or.fqdn"):
|
||||
[104, 111, 115, 116, 110, 97, 109, 101, 46, 111, 114, 46, 102, 113, 100, 110]
|
||||
|
||||
- The client identifier (IPv4) or DUID (IPv6) as an array of bytes. May be
|
||||
empty.
|
||||
|
||||
Examples:
|
||||
|
||||
DHCPv6 DUID:
|
||||
[0, 3, 0, 1, 0, 35, 69, 103, 137, 171]
|
||||
DHCPv4 client identifier:
|
||||
[255, 12, 34, 56, 78, 0, 1, 0, 1, 29, 9, 99, 190, 35, 69, 103, 137, 171]
|
||||
|
||||
- The duration of the lease, in seconds. If the lease is updated, then
|
||||
the duration replaces the previous duration.
|
||||
|
||||
Example:
|
||||
|
||||
7200
|
||||
|
||||
- The IAID (Identity association identifier) of the DHCPv6 lease, as a network
|
||||
byte-order unsigned integer. For DHCPv4 leases, this must be set to 0.
|
||||
|
||||
Example (for IPv6):
|
||||
|
||||
203569230
|
||||
|
||||
- A boolean which, if true, indicates that the DHCPv6 lease is for a temporary
|
||||
address (IA_TA). If false, the DHCPv6 lease is for a non-temporary address
|
||||
(IA_NA). For DHCPv4 leases, this must be set to false.
|
||||
|
||||
RemoveDhcpLease
|
||||
---------------
|
||||
|
||||
Returns nothing. Removes a DHCP or DHCPv6 lease to the internal lease
|
||||
database, as if a client sent a release message to abandon a lease.
|
||||
|
||||
This function takes only one parameter: the text representation of the
|
||||
IPv4 or IPv6 address of the lease to remove.
|
||||
|
||||
Note that this function will trigger the DhcpLeaseRemoved signal and the
|
||||
configured DHCP lease script will be run with the "del" action.
|
||||
|
||||
|
||||
|
||||
2. SIGNALS
|
||||
|
||||
55
debian/changelog
vendored
55
debian/changelog
vendored
@@ -1,3 +1,58 @@
|
||||
dnsmasq (2.76-1) unstable; urgency=low
|
||||
|
||||
* New upstream. (closes: #798586)
|
||||
* Use /run/dnsmasq directly, rather than relying on link from /var/run
|
||||
to avoid problems before /var is mounted. (closes: #800351)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Thur, 10 Sep 2015 23:07:21 +0000
|
||||
|
||||
dnsmasq (2.75-1) unstable; urgency=low
|
||||
|
||||
* New upstream. (closes: #794095)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Thur, 30 Jul 2015 20:58:31 +0000
|
||||
|
||||
dnsmasq (2.74-1) unstable; urgency=low
|
||||
|
||||
* New upstream. (LP: #1468611)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 15 Jul 2015 21:54:11 +0000
|
||||
|
||||
dnsmasq (2.73-2) unstable; urgency=low
|
||||
|
||||
* Fix behaviour of empty --conf-file (closes: #790341)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 7 Jul 2015 21:46:42 +0000
|
||||
|
||||
dnsmasq (2.73-1) unstable; urgency=low
|
||||
|
||||
* New upstream. (closes: #786996)
|
||||
* Tweak field width in cache dump to avoid truncating IPv6
|
||||
addresses. (closes: #771557)
|
||||
* Add newline at the end of example config file. (LP: #1416895)
|
||||
* Make Debian package build reproducible. (closes: #777323)
|
||||
* Add Requires=network.target to systemd unit.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 4 Jun 2015 22:31:42 +0000
|
||||
|
||||
dnsmasq (2.72-3) unstable; urgency=medium
|
||||
|
||||
* debian/systemd.service: switch from Type=dbus to Type=forking.
|
||||
dnsmasq does not depend on dbus, but Type=dbus systemd services cannot
|
||||
work without it. (Closes: #769486, #776530)
|
||||
- debian/init: when called with systemd-exec argument, let dnsmasq
|
||||
go into the background, so Type=forking can detect when it is ready
|
||||
* Remove line containing only whitespace in debian/contol.
|
||||
(closes: #777571)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 11 Feb 2015 21:56:12 +0000
|
||||
|
||||
dnsmasq (2.72-2) unstable; urgency=low
|
||||
|
||||
* Fix build in Debian-kFreeBSD. (closes: #763693)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 02 Oct 2014 22:34:12 +0000
|
||||
|
||||
dnsmasq (2.72-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
|
||||
4
debian/control
vendored
4
debian/control
vendored
@@ -3,7 +3,7 @@ Section: net
|
||||
Priority: optional
|
||||
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any],
|
||||
libidn11-dev, libdbus-1-dev (>=0.61), libgmp-dev,
|
||||
nettle-dev (>=2.4-3)
|
||||
nettle-dev (>=2.4-3), libbsd-dev [!linux-any]
|
||||
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Standards-Version: 3.9.5
|
||||
|
||||
@@ -42,5 +42,3 @@ 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.
|
||||
|
||||
|
||||
|
||||
2
debian/copyright
vendored
2
debian/copyright
vendored
@@ -1,4 +1,4 @@
|
||||
dnsmasq is Copyright (c) 2000-2013 Simon Kelley
|
||||
dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
It was downloaded from: http://www.thekelleys.org.uk/dnsmasq/
|
||||
|
||||
|
||||
6
debian/dnsmasq-base.postinst
vendored
6
debian/dnsmasq-base.postinst
vendored
@@ -17,8 +17,8 @@ if [ "$1" = "configure" ]; then
|
||||
# dnsmasq-base, but it's much easier to create it here so that
|
||||
# we don't have synchronisation issues with the creation of the
|
||||
# dnsmasq user.
|
||||
if [ ! -d /var/run/dnsmasq ]; then
|
||||
mkdir /var/run/dnsmasq
|
||||
chown dnsmasq:nogroup /var/run/dnsmasq
|
||||
if [ ! -d /run/dnsmasq ]; then
|
||||
mkdir /run/dnsmasq
|
||||
chown dnsmasq:nogroup /run/dnsmasq
|
||||
fi
|
||||
fi
|
||||
|
||||
2
debian/dnsmasq-base.postrm
vendored
2
debian/dnsmasq-base.postrm
vendored
@@ -7,5 +7,5 @@ if [ purge = "$1" ]; then
|
||||
else
|
||||
echo >&2 "not removing dnsmasq system account because deluser command was not found"
|
||||
fi
|
||||
rm -rf /var/run/dnsmasq
|
||||
rm -rf /run/dnsmasq
|
||||
fi
|
||||
|
||||
40
debian/init
vendored
40
debian/init
vendored
@@ -81,7 +81,7 @@ if [ ! "$RESOLV_CONF" ] &&
|
||||
[ "$IGNORE_RESOLVCONF" != "yes" ] &&
|
||||
[ -x /sbin/resolvconf ]
|
||||
then
|
||||
RESOLV_CONF=/var/run/dnsmasq/resolv.conf
|
||||
RESOLV_CONF=/run/dnsmasq/resolv.conf
|
||||
fi
|
||||
|
||||
for INTERFACE in $DNSMASQ_INTERFACE; do
|
||||
@@ -121,16 +121,16 @@ start()
|
||||
# 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
|
||||
# /run may be volatile, so we need to ensure that
|
||||
# /run/dnsmasq exists here as well as in postinst
|
||||
if [ ! -d /run/dnsmasq ]; then
|
||||
mkdir /run/dnsmasq || return 2
|
||||
chown dnsmasq:nogroup /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 \
|
||||
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null || return 1
|
||||
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON -- \
|
||||
-x /run/dnsmasq/$NAME.pid \
|
||||
${MAILHOSTNAME:+ -m $MAILHOSTNAME} \
|
||||
${MAILTARGET:+ -t $MAILTARGET} \
|
||||
${DNSMASQ_USER:+ -u $DNSMASQ_USER} \
|
||||
@@ -167,7 +167,7 @@ stop()
|
||||
# 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
|
||||
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile /run/dnsmasq/$NAME.pid --name $NAME
|
||||
}
|
||||
|
||||
stop_resolvconf()
|
||||
@@ -185,9 +185,9 @@ status()
|
||||
# 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
|
||||
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null
|
||||
case "$?" in
|
||||
0) [ -e "/var/run/dnsmasq/$NAME.pid" ] && return 1 ; return 3 ;;
|
||||
0) [ -e "/run/dnsmasq/$NAME.pid" ] && return 1 ; return 3 ;;
|
||||
1) return 0 ;;
|
||||
*) return 4 ;;
|
||||
esac
|
||||
@@ -278,7 +278,7 @@ case "$1" in
|
||||
esac
|
||||
;;
|
||||
dump-stats)
|
||||
kill -s USR1 `cat /var/run/dnsmasq/$NAME.pid`
|
||||
kill -s USR1 `cat /run/dnsmasq/$NAME.pid`
|
||||
;;
|
||||
systemd-start-resolvconf)
|
||||
start_resolvconf
|
||||
@@ -287,15 +287,13 @@ case "$1" in
|
||||
stop_resolvconf
|
||||
;;
|
||||
systemd-exec)
|
||||
# /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
|
||||
# /run may be volatile, so we need to ensure that
|
||||
# /run/dnsmasq exists here as well as in postinst
|
||||
if [ ! -d /run/dnsmasq ]; then
|
||||
mkdir /run/dnsmasq || return 2
|
||||
chown dnsmasq:nogroup /run/dnsmasq || return 2
|
||||
fi
|
||||
# Enable DBus by default because we use DBus activation with systemd.
|
||||
exec $DAEMON --keep-in-foreground --enable-dbus \
|
||||
-x /var/run/dnsmasq/$NAME.pid \
|
||||
exec $DAEMON -x /run/dnsmasq/$NAME.pid \
|
||||
${MAILHOSTNAME:+ -m $MAILHOSTNAME} \
|
||||
${MAILTARGET:+ -t $MAILTARGET} \
|
||||
${DNSMASQ_USER:+ -u $DNSMASQ_USER} \
|
||||
|
||||
2
debian/postinst
vendored
2
debian/postinst
vendored
@@ -21,7 +21,7 @@ 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
|
||||
if [ -e /run/dnsmasq/dnsmasq.pid ]; then
|
||||
ACTION=restart
|
||||
else
|
||||
ACTION=start
|
||||
|
||||
2
debian/resolvconf
vendored
2
debian/resolvconf
vendored
@@ -13,7 +13,7 @@
|
||||
|
||||
set -e
|
||||
|
||||
RUN_DIR="/var/run/dnsmasq"
|
||||
RUN_DIR="/run/dnsmasq"
|
||||
RSLVRLIST_FILE="${RUN_DIR}/resolv.conf"
|
||||
TMP_FILE="${RSLVRLIST_FILE}_new.$$"
|
||||
MY_NAME_FOR_RESOLVCONF="dnsmasq"
|
||||
|
||||
42
debian/rules
vendored
42
debian/rules
vendored
@@ -23,7 +23,8 @@ DEB_COPTS = $(COPTS)
|
||||
|
||||
TARGET = install-i18n
|
||||
|
||||
DEB_BUILD_ARCH_OS := $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS)
|
||||
DEB_HOST_ARCH_OS := $(shell dpkg-architecture -qDEB_HOST_ARCH_OS)
|
||||
BUILD_DATE := $(shell dpkg-parsechangelog --show-field Date)
|
||||
|
||||
# Force package version based on git tags.
|
||||
ifneq (,$(filter gitversion,$(DEB_BUILD_OPTIONS)))
|
||||
@@ -35,7 +36,7 @@ ifeq (,$(filter nodbus,$(DEB_BUILD_OPTIONS)))
|
||||
endif
|
||||
|
||||
ifeq (,$(filter noconntrack,$(DEB_BUILD_OPTIONS)))
|
||||
ifeq ($(DEB_BUILD_ARCH_OS),linux)
|
||||
ifeq ($(DEB_HOST_ARCH_OS),linux)
|
||||
DEB_COPTS += -DHAVE_CONNTRACK
|
||||
endif
|
||||
endif
|
||||
@@ -83,6 +84,11 @@ ifeq (,$(filter nodnssec,$(DEB_BUILD_OPTIONS)))
|
||||
DEB_COPTS += -DHAVE_DNSSEC
|
||||
endif
|
||||
|
||||
ifneq ($(DEB_HOST_ARCH_OS),linux)
|
||||
# For strlcpy in FreeBSD
|
||||
LDFLAGS += -lbsd
|
||||
endif
|
||||
|
||||
clean:
|
||||
$(checkdir)
|
||||
rm -rf debian/daemon debian/base debian/utils debian/*~ debian/files debian/substvars debian/utils-substvars
|
||||
@@ -113,8 +119,9 @@ binary-indep: checkroot
|
||||
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
|
||||
cd debian/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -T -pdnsmasq -Pdebian/daemon
|
||||
find debian/daemon -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/daemon
|
||||
chmod -R g-ws debian/daemon
|
||||
dpkg --build debian/daemon ..
|
||||
@@ -127,7 +134,6 @@ binary-arch: checkroot
|
||||
-d debian/base/etc/dbus-1/system.d \
|
||||
-d debian/base/usr/share/doc/$(package) \
|
||||
-d debian/base/usr/share/doc/$(package)/examples \
|
||||
-d debian/base/var/run \
|
||||
-d debian/base/usr/share/$(package) \
|
||||
-d debian/base/var/lib/misc
|
||||
make $(TARGET) PREFIX=/usr DESTDIR=`pwd`/debian/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=gcc
|
||||
@@ -139,39 +145,40 @@ ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||
install -m 644 dnsmasq.conf.example debian/base/usr/share/doc/$(package)/examples/.
|
||||
install -m 644 trust-anchors.conf debian/base/usr/share/$(package)/.
|
||||
install -m 644 FAQ debian/base/usr/share/doc/$(package)/.
|
||||
gzip -9 debian/base/usr/share/doc/$(package)/FAQ
|
||||
gzip -9n 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
|
||||
gzip -9n 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
|
||||
gzip -9n 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
|
||||
gzip -9n debian/base/usr/share/doc/$(package)/DBus-interface
|
||||
endif
|
||||
install -m 644 debian/dnsmasq-base.conffiles debian/base/DEBIAN/conffiles
|
||||
install -m 755 debian/dnsmasq-base.postinst debian/base/DEBIAN/postinst
|
||||
install -m 755 debian/dnsmasq-base.postrm debian/base/DEBIAN/postrm
|
||||
install -m 644 debian/changelog debian/base/usr/share/doc/$(package)/changelog.Debian
|
||||
gzip -9 debian/base/usr/share/doc/$(package)/changelog.Debian
|
||||
gzip -9n debian/base/usr/share/doc/$(package)/changelog.Debian
|
||||
install -m 644 debian/readme debian/base/usr/share/doc/$(package)/README.Debian
|
||||
install -m 644 debian/copyright debian/base/usr/share/doc/$(package)/copyright
|
||||
install -m 644 debian/dbus.conf debian/base/etc/dbus-1/system.d/dnsmasq.conf
|
||||
gzip -9 debian/base/usr/share/man/man8/dnsmasq.8
|
||||
gzip -9n 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 ; \
|
||||
gzip -9n $$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
|
||||
cd debian/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-shlibdeps --warnings=1 debian/base/usr/sbin/dnsmasq
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base -Pdebian/base
|
||||
find debian/base -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/base
|
||||
chmod -R g-ws debian/base
|
||||
dpkg --build debian/base ..
|
||||
|
||||
ifeq ($(DEB_BUILD_ARCH_OS),linux)
|
||||
ifeq ($(DEB_HOST_ARCH_OS),linux)
|
||||
rm -rf debian/utils
|
||||
install -m 755 -d debian/utils/DEBIAN \
|
||||
-d debian/utils/usr/share/man/man1 \
|
||||
@@ -180,20 +187,21 @@ ifeq ($(DEB_BUILD_ARCH_OS),linux)
|
||||
make -C contrib/wrt PREFIX=/usr DESTDIR=`pwd`/debian/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=gcc
|
||||
install -m 755 contrib/wrt/dhcp_release debian/utils/usr/bin/dhcp_release
|
||||
install -m 644 contrib/wrt/dhcp_release.1 debian/utils/usr/share/man/man1/dhcp_release.1
|
||||
gzip -9 debian/utils/usr/share/man/man1/dhcp_release.1
|
||||
gzip -9n debian/utils/usr/share/man/man1/dhcp_release.1
|
||||
install -m 755 contrib/wrt/dhcp_lease_time debian/utils/usr/bin/dhcp_lease_time
|
||||
install -m 644 contrib/wrt/dhcp_lease_time.1 debian/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||
install -m 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
|
||||
gzip -9n debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||
gzip -9n debian/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
strip -R .note -R .comment debian/utils/usr/bin/dhcp_release
|
||||
strip -R .note -R .comment debian/utils/usr/bin/dhcp_lease_time
|
||||
endif
|
||||
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-shlibdeps -Tdebian/utils-substvars debian/utils/usr/bin/dhcp_release debian/utils/usr/bin/dhcp_lease_time
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/utils
|
||||
find debian/utils -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/utils
|
||||
chmod -R g-ws debian/utils
|
||||
dpkg --build debian/utils ..
|
||||
|
||||
10
debian/systemd.service
vendored
10
debian/systemd.service
vendored
@@ -1,9 +1,10 @@
|
||||
[Unit]
|
||||
Description=dnsmasq - A lightweight DHCP and caching DNS server
|
||||
Requires=network.target
|
||||
|
||||
[Service]
|
||||
Type=dbus
|
||||
BusName=uk.org.thekelleys.dnsmasq
|
||||
Type=forking
|
||||
PIDFile=/run/dnsmasq/dnsmasq.pid
|
||||
|
||||
# Test the config file and refuse starting if it is not valid.
|
||||
ExecStartPre=/usr/sbin/dnsmasq --test
|
||||
@@ -11,11 +12,6 @@ ExecStartPre=/usr/sbin/dnsmasq --test
|
||||
# We run dnsmasq via the /etc/init.d/dnsmasq script which acts as a
|
||||
# wrapper picking up extra configuration files and then execs dnsmasq
|
||||
# itself, when called with the "systemd-exec" function.
|
||||
#
|
||||
# It also adds the command-line flags
|
||||
# --keep-in-foreground --enable-dbus
|
||||
# to enable DBus by default because we use DBus activation.
|
||||
#
|
||||
ExecStart=/etc/init.d/dnsmasq systemd-exec
|
||||
|
||||
# The systemd-*-resolvconf functions configure (and deconfigure)
|
||||
|
||||
@@ -251,6 +251,13 @@
|
||||
# the IP address 192.168.0.60
|
||||
#dhcp-host=id:01:02:02:04,192.168.0.60
|
||||
|
||||
# Always give the Infiniband interface with hardware address
|
||||
# 80:00:00:48:fe:80:00:00:00:00:00:00:f4:52:14:03:00:28:05:81 the
|
||||
# ip address 192.168.0.61. The client id is derived from the prefix
|
||||
# ff:00:00:00:00:00:02:00:00:02:c9:00 and the last 8 pairs of
|
||||
# hex digits of the hardware address.
|
||||
#dhcp-host=id:ff:00:00:00:00:00:02:00:00:02:c9:00:f4:52:14:03:00:28:05:81,192.168.0.61
|
||||
|
||||
# Always give the host with client identifier "marjorie"
|
||||
# the IP address 192.168.0.60
|
||||
#dhcp-host=id:marjorie,192.168.0.60
|
||||
@@ -345,6 +352,14 @@
|
||||
# Ask client to poll for option changes every six hours. (RFC4242)
|
||||
#dhcp-option=option6:information-refresh-time,6h
|
||||
|
||||
# Set option 58 client renewal time (T1). Defaults to half of the
|
||||
# lease time if not specified. (RFC2132)
|
||||
#dhcp-option=option:T1:1m
|
||||
|
||||
# Set option 59 rebinding time (T2). Defaults to 7/8 of the
|
||||
# lease time if not specified. (RFC2132)
|
||||
#dhcp-option=option:T2:2m
|
||||
|
||||
# Set the NTP time server address to be the same machine as
|
||||
# is running dnsmasq
|
||||
#dhcp-option=42,0.0.0.0
|
||||
@@ -486,6 +501,9 @@
|
||||
# Set the root directory for files available via FTP.
|
||||
#tftp-root=/var/ftpd
|
||||
|
||||
# Do not abort if the tftp-root is unavailable
|
||||
#tftp-no-fail
|
||||
|
||||
# Make the TFTP server more secure: with this set, only files owned by
|
||||
# the user dnsmasq is running as will be send over the net.
|
||||
#tftp-secure
|
||||
@@ -645,4 +663,4 @@
|
||||
#conf-dir=/etc/dnsmasq.d,.bak
|
||||
|
||||
# Include all files in a directory which end in .conf
|
||||
#conf-dir=/etc/dnsmasq.d/*.conf
|
||||
#conf-dir=/etc/dnsmasq.d/,*.conf
|
||||
|
||||
4
doc.html
4
doc.html
@@ -74,7 +74,9 @@ for details.
|
||||
There is a dnsmasq mailing list at <A
|
||||
HREF="http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss">
|
||||
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss</A> which should be the
|
||||
first location for queries, bugreports, suggestions etc.
|
||||
first location for queries, bugreports, suggestions etc. The list is mirrored, with a
|
||||
search facility, at <A HREF="https://www.mail-archive.com/dnsmasq-discuss@lists.thekelleys.org.uk/">
|
||||
https://www.mail-archive.com/dnsmasq-discuss@lists.thekelleys.org.uk/</A>.
|
||||
You can contact me at <A
|
||||
HREF="mailto:simon@thekelleys.org.uk">simon@thekelleys.org.uk</A>.
|
||||
|
||||
|
||||
183
man/dnsmasq.8
183
man/dnsmasq.8
@@ -50,13 +50,17 @@ Additional hosts file. Read the specified file as well as /etc/hosts. If -h is g
|
||||
only the specified file. This option may be repeated for more than one
|
||||
additional hosts file. If a directory is given, then read all the files contained in that directory.
|
||||
.TP
|
||||
.B --hostsdir=<path>
|
||||
Read all the hosts files contained in the directory. New or changed files
|
||||
are read automatically. See --dhcp-hostsdir for details.
|
||||
.TP
|
||||
.B \-E, --expand-hosts
|
||||
Add the domain to simple names (without a period) in /etc/hosts
|
||||
in the same way as for DHCP-derived names. Note that this does not
|
||||
apply to domain names in cnames, PTR records, TXT records etc.
|
||||
.TP
|
||||
.B \-T, --local-ttl=<time>
|
||||
When replying with information from /etc/hosts or the DHCP leases
|
||||
When replying with information from /etc/hosts or configuration or the DHCP leases
|
||||
file dnsmasq by default sets the time-to-live field to zero, meaning
|
||||
that the requester should not itself cache the information. This is
|
||||
the correct thing to do in almost all situations. This option allows a
|
||||
@@ -64,6 +68,9 @@ time-to-live (in seconds) to be given for these replies. This will
|
||||
reduce the load on the server at the expense of clients using stale
|
||||
data under some circumstances.
|
||||
.TP
|
||||
.B --dhcp-ttl=<time>
|
||||
As for --local-ttl, but affects only replies with information from DHCP leases. If both are given, --dhcp-ttl applies for DHCP information, and --local-ttl for others. Setting this to zero eliminates the effect of --local-ttl for DHCP.
|
||||
.TP
|
||||
.B --neg-ttl=<time>
|
||||
Negative replies from upstream servers normally contain time-to-live
|
||||
information in SOA records which dnsmasq uses for caching. If the
|
||||
@@ -81,6 +88,12 @@ the upstream DNS servers.
|
||||
.B --max-cache-ttl=<time>
|
||||
Set a maximum TTL value for entries in the cache.
|
||||
.TP
|
||||
.B --min-cache-ttl=<time>
|
||||
Extend short TTL values to the time given when caching them. Note that
|
||||
artificially extending TTL values is in general a bad idea, do not do it
|
||||
unless you have a good reason, and understand what you are doing.
|
||||
Dnsmasq limits the value of this option to one hour, unless recompiled.
|
||||
.TP
|
||||
.B --auth-ttl=<time>
|
||||
Set the TTL value returned in answers from the authoritative server.
|
||||
.TP
|
||||
@@ -98,7 +111,10 @@ only, to stop dnsmasq daemonising in production, use
|
||||
.B -k.
|
||||
.TP
|
||||
.B \-q, --log-queries
|
||||
Log the results of DNS queries handled by dnsmasq. Enable a full cache dump on receipt of SIGUSR1.
|
||||
Log the results of DNS queries handled by dnsmasq. Enable a full cache dump on receipt of SIGUSR1. If the argument "extra" is supplied, ie
|
||||
.B --log-queries=extra
|
||||
then the log has extra information at the start of each line.
|
||||
This consists of a serial number which ties together the log lines associated with an individual query, and the IP address of the requestor.
|
||||
.TP
|
||||
.B \-8, --log-facility=<facility>
|
||||
Set the facility to which dnsmasq will send syslog entries, this
|
||||
@@ -161,6 +177,13 @@ queries. Dnsmasq picks random ports as source for outbound queries:
|
||||
when this option is given, the ports used will always to larger
|
||||
than that specified. Useful for systems behind firewalls.
|
||||
.TP
|
||||
.B --max-port=<port>
|
||||
Use ports lower than that given as source for outbound DNS queries.
|
||||
Dnsmasq picks random ports as source for outbound queries:
|
||||
when this option is given, the ports used will always be lower
|
||||
than that specified. Useful for systems behind firewalls.
|
||||
.TP
|
||||
|
||||
.B \-i, --interface=<interface name>
|
||||
Listen only on the specified interface(s). Dnsmasq automatically adds
|
||||
the loopback (local) interface to the list of interfaces to use when
|
||||
@@ -293,6 +316,12 @@ an advertising web page in response to queries for unregistered names,
|
||||
instead of the correct NXDOMAIN response. This option tells dnsmasq to
|
||||
fake the correct response when it sees this behaviour. As at Sept 2003
|
||||
the IP address being returned by Verisign is 64.94.110.11
|
||||
.TP
|
||||
.B \-B, --ignore-address=<ipaddr>
|
||||
Ignore replies to A-record queries which include the specified address.
|
||||
No error is generated, dnsmasq simply continues to listen for another reply.
|
||||
This is useful to defeat blocking strategies which rely on quickly supplying a
|
||||
forged answer to a DNS request for certain domain, before the correct answer can arrive.
|
||||
.TP
|
||||
.B \-f, --filterwin2k
|
||||
Later versions of windows make periodic DNS requests which don't get sensible answers from
|
||||
@@ -386,7 +415,10 @@ xxx.internal.thekelleys.org.uk at 192.168.1.1 then giving the flag
|
||||
.B -S /internal.thekelleys.org.uk/192.168.1.1
|
||||
will send all queries for
|
||||
internal machines to that nameserver, everything else will go to the
|
||||
servers in /etc/resolv.conf. An empty domain specification,
|
||||
servers in /etc/resolv.conf. DNSSEC validation is turned off for such
|
||||
private nameservers, UNLESS a
|
||||
.B --trust-anchor
|
||||
is specified for the domain in question. An empty domain specification,
|
||||
.B //
|
||||
has the special meaning of "unqualified names only" ie names without any
|
||||
dots in them. A non-standard port may be specified as
|
||||
@@ -441,7 +473,7 @@ but provides some syntactic sugar to make specifying address-to-name queries eas
|
||||
is exactly equivalent to
|
||||
.B --server=/3.2.1.in-addr.arpa/192.168.0.1
|
||||
.TP
|
||||
.B \-A, --address=/<domain>/[domain/]<ipaddr>
|
||||
.B \-A, --address=/<domain>/[domain/][<ipaddr>]
|
||||
Specify an IP address to return for any host in the given domains.
|
||||
Queries in the domains are never forwarded and always replied to
|
||||
with the specified IP address which may be IPv4 or IPv6. To give
|
||||
@@ -453,7 +485,10 @@ domain specification works in the same was as for --server, with the
|
||||
additional facility that /#/ matches any domain. Thus
|
||||
--address=/#/1.2.3.4 will always return 1.2.3.4 for any query not
|
||||
answered from /etc/hosts or DHCP and not sent to an upstream
|
||||
nameserver by a more specific --server directive.
|
||||
nameserver by a more specific --server directive. As for --server,
|
||||
one or more domains with no address returns a no-such-domain answer, so
|
||||
--address=/example.com/ is equivalent to --server=/example.com/ and returns
|
||||
NXDOMAIN for example.com and all its subdomains.
|
||||
.TP
|
||||
.B --ipset=/<domain>/[domain/]<ipset>[,<ipset>]
|
||||
Places the resolved IP addresses of queries for the specified domains
|
||||
@@ -497,7 +532,7 @@ zone files: the port, weight and priority numbers are in a different
|
||||
order. More than one SRV record for a given service/domain is allowed,
|
||||
all that match are returned.
|
||||
.TP
|
||||
.B --host-record=<name>[,<name>....][<IPv4-address>],[<IPv6-address>]
|
||||
.B --host-record=<name>[,<name>....],[<IPv4-address>],[<IPv6-address>][,<TTL>]
|
||||
Add A, AAAA and PTR records to the DNS. This adds one or more names to
|
||||
the DNS with associated IPv4 (A) and IPv6 (AAAA) records. A name may
|
||||
appear in more than one
|
||||
@@ -514,6 +549,10 @@ is in effect. Short and long names may appear in the same
|
||||
.B host-record,
|
||||
eg.
|
||||
.B --host-record=laptop,laptop.thekelleys.org,192.168.0.1,1234::100
|
||||
|
||||
If the time-to-live is given, it overrides the default, which is zero
|
||||
or the value of --local-ttl. The value is a positive integer and gives
|
||||
the time-to-live in seconds.
|
||||
.TP
|
||||
.B \-Y, --txt-record=<name>[[,<text>],<text>]
|
||||
Return a TXT DNS record. The value of TXT record is a set of strings,
|
||||
@@ -527,7 +566,7 @@ Return a PTR DNS record.
|
||||
.B --naptr-record=<name>,<order>,<preference>,<flags>,<service>,<regexp>[,<replacement>]
|
||||
Return an NAPTR DNS record, as specified in RFC3403.
|
||||
.TP
|
||||
.B --cname=<cname>,<target>
|
||||
.B --cname=<cname>,<target>[,<TTL>]
|
||||
Return a CNAME record which indicates that <cname> is really
|
||||
<target>. There are significant limitations on the target; it must be a
|
||||
DNS name which is known to dnsmasq from /etc/hosts (or additional
|
||||
@@ -536,6 +575,10 @@ hosts files), from DHCP, from --interface-name or from another
|
||||
If the target does not satisfy this
|
||||
criteria, the whole cname is ignored. The cname must be unique, but it
|
||||
is permissable to have more than one cname pointing to the same target.
|
||||
|
||||
If the time-to-live is given, it overrides the default, which is zero
|
||||
or the value of -local-ttl. The value is a positive integer and gives
|
||||
the time-to-live in seconds.
|
||||
.TP
|
||||
.B --dns-rr=<name>,<RR-number>,[<hex data>]
|
||||
Return an arbitrary DNS Resource Record. The number is the type of the
|
||||
@@ -572,7 +615,7 @@ configured a zero is added in front of the label. ::1 becomes 0--1.
|
||||
The address range can be of the form
|
||||
<ip address>,<ip address> or <ip address>/<netmask>
|
||||
.TP
|
||||
.B --add-mac
|
||||
.B --add-mac[=base64|text]
|
||||
Add the MAC address of the requestor to DNS queries which are
|
||||
forwarded upstream. This may be used to DNS filtering by the upstream
|
||||
server. The MAC address can only be added if the requestor is on the same
|
||||
@@ -580,19 +623,34 @@ subnet as the dnsmasq server. Note that the mechanism used to achieve this (an E
|
||||
is not yet standardised, so this should be considered
|
||||
experimental. Also note that exposing MAC addresses in this way may
|
||||
have security and privacy implications. The warning about caching
|
||||
given for --add-subnet applies to --add-mac too.
|
||||
given for --add-subnet applies to --add-mac too. An alternative encoding of the
|
||||
MAC, as base64, is enabled by adding the "base64" parameter and a human-readable encoding of hex-and-colons is enabled by added the "text" parameter.
|
||||
.TP
|
||||
.B --add-cpe-id=<string>
|
||||
Add a arbitrary identifying string to o DNS queries which are
|
||||
forwarded upstream.
|
||||
.TP
|
||||
.B --add-subnet[[=<IPv4 prefix length>],<IPv6 prefix length>]
|
||||
Add the subnet address of the requestor to the DNS queries which are
|
||||
forwarded upstream. The amount of the address forwarded depends on the
|
||||
prefix length parameter: 32 (128 for IPv6) forwards the whole address,
|
||||
zero forwards none of it but still marks the request so that no
|
||||
upstream nameserver will add client address information either. The
|
||||
default is zero for both IPv4 and IPv6. Note that upstream nameservers
|
||||
may be configured to return different results based on this
|
||||
information, but the dnsmasq cache does not take account. If a dnsmasq
|
||||
instance is configured such that different results may be encountered,
|
||||
caching should be disabled.
|
||||
.B --add-subnet[[=[<IPv4 address>/]<IPv4 prefix length>][,[<IPv6 address>/]<IPv6 prefix length>]]
|
||||
Add a subnet address to the DNS queries which are forwarded
|
||||
upstream. If an address is specified in the flag, it will be used,
|
||||
otherwise, the address of the requestor will be used. The amount of
|
||||
the address forwarded depends on the prefix length parameter: 32 (128
|
||||
for IPv6) forwards the whole address, zero forwards none of it but
|
||||
still marks the request so that no upstream nameserver will add client
|
||||
address information either. The default is zero for both IPv4 and
|
||||
IPv6. Note that upstream nameservers may be configured to return
|
||||
different results based on this information, but the dnsmasq cache
|
||||
does not take account. If a dnsmasq instance is configured such that
|
||||
different results may be encountered, caching should be disabled.
|
||||
|
||||
For example,
|
||||
.B --add-subnet=24,96
|
||||
will add the /24 and /96 subnets of the requestor for IPv4 and IPv6 requestors, respectively.
|
||||
.B --add-subnet=1.2.3.4/24
|
||||
will add 1.2.3.0/24 for IPv4 requestors and ::/0 for IPv6 requestors.
|
||||
.B --add-subnet=1.2.3.4/24,1.2.3.4/24
|
||||
will add 1.2.3.0/24 for both IPv4 and IPv6 requestors.
|
||||
|
||||
.TP
|
||||
.B \-c, --cache-size=<cachesize>
|
||||
Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching.
|
||||
@@ -632,7 +690,7 @@ Provide DS records to act a trust anchors for DNSSEC
|
||||
validation. Typically these will be the DS record(s) for Zone Signing
|
||||
key(s) of the root zone,
|
||||
but trust anchors for limited domains are also possible. The current
|
||||
root-zone trust anchors may be donwloaded from https://data.iana.org/root-anchors/root-anchors.xml
|
||||
root-zone trust anchors may be downloaded from https://data.iana.org/root-anchors/root-anchors.xml
|
||||
.TP
|
||||
.B --dnssec-check-unsigned
|
||||
As a default, dnsmasq does not check that unsigned DNS replies are
|
||||
@@ -655,6 +713,13 @@ that dnsmasq should be started with this flag when the platform determines that
|
||||
reliable time is established, a SIGHUP should be sent to dnsmasq, which enables time checking, and purges the cache of DNS records
|
||||
which have not been throughly checked.
|
||||
.TP
|
||||
.B --dnssec-timestamp=<path>
|
||||
Enables an alternative way of checking the validity of the system time for DNSSEC (see --dnssec-no-timecheck). In this case, the
|
||||
system time is considered to be valid once it becomes later than the timestamp on the specified file. The file is created and
|
||||
its timestamp set automatically by dnsmasq. The file must be stored on a persistent filesystem, so that it and its mtime are carried
|
||||
over system restarts. The timestamp file is created after dnsmasq has dropped root, so it must be in a location writable by the
|
||||
unprivileged user that dnsmasq runs as.
|
||||
.TP
|
||||
.B --proxy-dnssec
|
||||
Copy the DNSSEC Authenticated Data bit from upstream servers to downstream clients and cache it. This is an
|
||||
alternative to having dnsmasq validate DNSSEC, but it depends on the security of the network between
|
||||
@@ -718,7 +783,7 @@ compiled in and the kernel must have conntrack support
|
||||
included and configured. This option cannot be combined with
|
||||
--query-port.
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-addr>[,<end-addr>][,<mode>][,<netmask>[,<broadcast>]][,<lease time>]
|
||||
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-addr>[,<end-addr>|<mode>][,<netmask>[,<broadcast>]][,<lease time>]
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-IPv6addr>[,<end-IPv6addr>|constructor:<interface>][,<mode>][,<prefix-len>][,<lease time>]
|
||||
|
||||
@@ -804,7 +869,7 @@ and
|
||||
for details.)
|
||||
|
||||
For IPv6, the mode may be some combination of
|
||||
.B ra-only, slaac, ra-names, ra-stateless, ra-advrouter.
|
||||
.B ra-only, slaac, ra-names, ra-stateless, ra-advrouter, off-link.
|
||||
|
||||
.B ra-only
|
||||
tells dnsmasq to offer Router Advertisement only on this subnet,
|
||||
@@ -844,6 +909,9 @@ enables a mode where router address(es) rather than prefix(es) are included in t
|
||||
This is described in RFC-3775 section 7.2 and is used in mobile IPv6. In this mode the interval option
|
||||
is also included, as described in RFC-3775 section 7.3.
|
||||
|
||||
.B off-link
|
||||
tells dnsmasq to advertise the prefix without the on-link (aka L) bit set.
|
||||
|
||||
.TP
|
||||
.B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
|
||||
Specify per host parameters for the DHCP server. This allows a machine
|
||||
@@ -962,6 +1030,18 @@ is given, then read all the files contained in that directory. The advantage of
|
||||
using this option is the same as for --dhcp-hostsfile: the
|
||||
dhcp-optsfile will be re-read when dnsmasq receives SIGHUP. Note that
|
||||
it is possible to encode the information in a
|
||||
.TP
|
||||
.B --dhcp-hostsdir=<path>
|
||||
This is equivalent to dhcp-hostsfile, except for the following. The path MUST be a
|
||||
directory, and not an individual file. Changed or new files within
|
||||
the directory are read automatically, without the need to send SIGHUP.
|
||||
If a file is deleted for changed after it has been read by dnsmasq, then the
|
||||
host record it contained will remain until dnsmasq recieves a SIGHUP, or
|
||||
is restarted; ie host records are only added dynamically.
|
||||
.TP
|
||||
.B --dhcp-optsdir=<path>
|
||||
This is equivalent to dhcp-optsfile, with the differences noted for --dhcp-hostsdir.
|
||||
.TP
|
||||
.B --dhcp-boot
|
||||
flag as DHCP options, using the options names bootfile-name,
|
||||
server-ip-address and tftp-server. This allows these to be included
|
||||
@@ -1347,7 +1427,7 @@ enables dynamic allocation. With tags, only when the tags are all
|
||||
set. It may be repeated with different tag sets.
|
||||
.TP
|
||||
.B \-5, --no-ping
|
||||
(IPv4 only) By default, the DHCP server will attempt to ensure that an address in
|
||||
(IPv4 only) By default, the DHCP server will attempt to ensure that an address is
|
||||
not in use before allocating it to a host. It does this by sending an
|
||||
ICMP echo request (aka "ping") to the address in question. If it gets
|
||||
a reply, then the address must already be in use, and another is
|
||||
@@ -1479,11 +1559,11 @@ At dnsmasq startup, the script will be invoked for
|
||||
all existing leases as they are read from the lease file. Expired
|
||||
leases will be called with "del" and others with "old". When dnsmasq
|
||||
receives a HUP signal, the script will be invoked for existing leases
|
||||
with an "old " event.
|
||||
with an "old" event.
|
||||
|
||||
|
||||
There are two further actions which may appear as the first argument
|
||||
to the script, "init" and "tftp". More may be added in the future, so
|
||||
There are four further actions which may appear as the first argument
|
||||
to the script, "init", "arp-add", "arp-del" and "tftp". More may be added in the future, so
|
||||
scripts should be written to ignore unknown actions. "init" is
|
||||
described below in
|
||||
.B --leasefile-ro
|
||||
@@ -1491,6 +1571,11 @@ The "tftp" action is invoked when a TFTP file transfer completes: the
|
||||
arguments are the file size in bytes, the address to which the file
|
||||
was sent, and the complete pathname of the file.
|
||||
|
||||
The "arp-add" and "arp-del" actions are only called if enabled with
|
||||
.B --script-arp
|
||||
They are are supplied with a MAC address and IP address as arguments. "arp-add" indicates
|
||||
the arrival of a new entry in the ARP or neighbour table, and "arp-del" indicates the deletion of same.
|
||||
|
||||
.TP
|
||||
.B --dhcp-luascript=<path>
|
||||
Specify a script written in Lua, to be run when leases are created,
|
||||
@@ -1537,10 +1622,24 @@ table holds the tags
|
||||
.B file_name
|
||||
and
|
||||
.B file_size.
|
||||
|
||||
The
|
||||
.B arp
|
||||
and
|
||||
.B arp-old
|
||||
functions are called only when enabled with
|
||||
.B --script-arp
|
||||
and have a table which holds the tags
|
||||
.B mac_addres
|
||||
and
|
||||
.B client_address.
|
||||
.TP
|
||||
.B --dhcp-scriptuser
|
||||
Specify the user as which to run the lease-change script or Lua script. This defaults to root, but can be changed to another user using this flag.
|
||||
.TP
|
||||
.TP
|
||||
.B --script-arp
|
||||
Enable the "arp" and "arp-old" functions in the dhcp-script and dhcp-luascript.
|
||||
.TP
|
||||
.B \-9, --leasefile-ro
|
||||
Completely suppress use of the lease database file. The file will not
|
||||
be created, read, or written. Change the way the lease-change
|
||||
@@ -1556,11 +1655,13 @@ option also forces the leasechange script to be called on changes
|
||||
to the client-id and lease length and expiry time.
|
||||
.TP
|
||||
.B --bridge-interface=<interface>,<alias>[,<alias>]
|
||||
Treat DHCP request packets arriving at any of the <alias> interfaces
|
||||
as if they had arrived at <interface>. This option is necessary when
|
||||
using "old style" bridging on BSD platforms, since
|
||||
packets arrive at tap interfaces which don't have an IP address.
|
||||
A trailing '*' wildcard can be used in each <alias>.
|
||||
Treat DHCP (v4 and v6) request and IPv6 Router Solicit packets
|
||||
arriving at any of the <alias> interfaces as if they had arrived at
|
||||
<interface>. This option allows dnsmasq to provide DHCP and RA
|
||||
service over unaddressed and unbridged Ethernet interfaces, e.g. on an
|
||||
OpenStack compute host where each such interface is a TAP interface to
|
||||
a VM, or as in "old style bridging" on BSD platforms. A trailing '*'
|
||||
wildcard can be used in each <alias>.
|
||||
.TP
|
||||
.B \-s, --domain=<domain>[,<address range>[,local]]
|
||||
Specifies DNS domains for the DHCP server. Domains may be be given
|
||||
@@ -1631,15 +1732,15 @@ 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
|
||||
router as the relevant link-local address on
|
||||
the machine running dnsmasq. By default, the "managed address" bits are set, and
|
||||
the "use SLAAC" bit is reset. This can be changed for individual
|
||||
subnets with the mode keywords described in
|
||||
.B --dhcp-range.
|
||||
RFC6106 DNS parameters are included in the advertisements. By default,
|
||||
the relevant link-local address of the machine running dnsmasq is sent
|
||||
as recursive DNS server. If provided, the DHCPv6 options dns-server and
|
||||
domain-search are used for RDNSS and DNSSL.
|
||||
domain-search are used for the DNS server (RDNSS) and the domain serach list (DNSSL).
|
||||
.TP
|
||||
.B --ra-param=<interface>,[high|low],[[<ra-interval>],<router lifetime>]
|
||||
Set non-default values for router advertisements sent via an
|
||||
@@ -1670,6 +1771,9 @@ Absolute paths (starting with /) are allowed, but they must be within
|
||||
the tftp-root. If the optional interface argument is given, the
|
||||
directory is only used for TFTP requests via that interface.
|
||||
.TP
|
||||
.B --tftp-no-fail
|
||||
Do not abort startup if specified tftp root directories are inaccessible.
|
||||
.TP
|
||||
.B --tftp-unique-root
|
||||
Add the IP address of the TFTP client as a path component on the end
|
||||
of the TFTP-root (in standard dotted-quad format). Only valid if a
|
||||
@@ -1706,6 +1810,10 @@ require about (2*n) + 10 descriptors. If
|
||||
.B --tftp-port-range
|
||||
is given, that can affect the number of concurrent connections.
|
||||
.TP
|
||||
.B --tftp-mtu=<mtu size>
|
||||
Use size as the ceiling of the MTU supported by the intervening network when
|
||||
negotiating TFTP blocksize, overriding the MTU setting of the local interface if it is larger.
|
||||
.TP
|
||||
.B --tftp-no-blocksize
|
||||
Stop the TFTP server from negotiating the "blocksize" option with a
|
||||
client. Some buggy clients request this option but then behave badly
|
||||
@@ -1767,7 +1875,8 @@ clears its cache and then re-loads
|
||||
.I /etc/hosts
|
||||
and
|
||||
.I /etc/ethers
|
||||
and any file given by --dhcp-hostsfile, --dhcp-optsfile or --addn-hosts.
|
||||
and any file given by --dhcp-hostsfile, --dhcp-hostsdir, --dhcp-optsfile,
|
||||
--dhcp-optsdir, --addn-hosts or --hostsdir.
|
||||
The dhcp lease change script is called for all
|
||||
existing DHCP leases. If
|
||||
.B
|
||||
|
||||
@@ -1062,10 +1062,14 @@ esta opci
|
||||
cuando hay cambios hechos a el client-id y tiempos de arriendo y vencimiento.
|
||||
.TP
|
||||
.B --bridge-interface=<nombre de interface>,<alias>[,<alias>]
|
||||
Tratar paquetes de pedidos DHCP que llegan a cualquiera de las interfaces <alias>
|
||||
como si hubieran llegado a la interface <nombre de interface>. Esta opción
|
||||
es necesaria al usar bridging estilo viejo en plataformas BSD, dado a que
|
||||
los paquetes llegan a interfaces tap que no tienen una dirección IP.
|
||||
Tratar paquetes de pedidos DHCP (v4 y v6) y de IPv6 Router Solicit que
|
||||
llegan a cualquiera de las interfaces <alias> como si hubieran llegado
|
||||
a la interface <nombre de interface>. Esta opción permite que dnsmasq
|
||||
puede proporcionar los servicios DHCP y RA a través de interfaces
|
||||
ethernet sin dirección y sin puente; por ejemplo en un nodo de cálculo
|
||||
de OpenStack, donde cada una de esas interfaces es una interfaz TAP
|
||||
para una máquina virtual, o al usar bridging estilo viejo en
|
||||
plataformas BSD.
|
||||
.TP
|
||||
.B \-s, --domain=<dominio>[,<rango de IPs>]
|
||||
Especifica los dominios DNS para el servidor DHCP. Dominios pueden ser
|
||||
|
||||
@@ -852,7 +852,7 @@ et
|
||||
pour plus de détails).
|
||||
|
||||
Pour IPv6, le mode peut-être une combinaison des valeurs
|
||||
.B ra-only, slaac, ra-names, ra-stateless.
|
||||
.B ra-only, slaac, ra-names, ra-stateless, off-link.
|
||||
|
||||
.B ra-only
|
||||
indique à dnsmasq de n'effectuer que des annonces de routeur (Router
|
||||
@@ -888,6 +888,9 @@ peut-être combiné avec
|
||||
et
|
||||
.B slaac.
|
||||
|
||||
.B off-link
|
||||
indique à dnsmasq d'annoncer le préfixe sans le bit L (sur lien).
|
||||
|
||||
.TP
|
||||
.B \-G, --dhcp-host=[<adresse matérielle>][,id:<identifiant client>|*][,set:<label>][,<adresse IP>][,<nom d'hôte>][,<durée de bail>][,ignore]
|
||||
Spécifie les paramètres DHCP relatifs à un hôte. Cela permet à une machine
|
||||
@@ -1655,11 +1658,14 @@ changement d'état de bail à chaque changement de l'identifiant de client, de
|
||||
longueur de bail ou de date d'expiration.
|
||||
.TP
|
||||
.B --bridge-interface=<interface>,<alias>[,<alias>]
|
||||
Traiter les requêtes DHCP arrivant sur n'importe laquelle des interfaces <alias>
|
||||
comme si elles arrivaient de l'interface <interface>. Cette option est
|
||||
nécessaire lors de l'utilisation de pont ethernet "ancien mode" sur plate-forme
|
||||
BSD, puisque dans ce cas les paquets arrivent sur des interfaces "tap" n'ont
|
||||
pas d'adresse IP. Chaque <alias> peut finir avec un simple '*' joker.
|
||||
Traiter les requêtes DHCP (v4 et v6) et IPv6 Router Solicit arrivant
|
||||
sur n'importe laquelle des interfaces <alias> comme si elles
|
||||
arrivaient de l'interface <interface>. Cette option permet à dnsmasq
|
||||
de fournir les service DHCP et RA sur les interfaces ethernet non
|
||||
adressés et non pontés; par exemple sur un hôte de calcul d'OpenStack
|
||||
où chaque telle interface est une interface TAP à une machine
|
||||
virtuelle, ou lors de l'utilisation de pont ethernet "ancien mode" sur
|
||||
plate-forme BSD. Chaque <alias> peut finir avec un simple '*' joker.
|
||||
.TP
|
||||
.B \-s, --domain=<domaine>[,<gamme d'adresses>[,local]]
|
||||
Spécifie le domaine du serveur DHCP. Le domaine peut être donné de manière
|
||||
|
||||
1149
po/pt_BR.po
1149
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
247
src/arp.c
Normal file
247
src/arp.c
Normal file
@@ -0,0 +1,247 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
/* Time between forced re-loads from kernel. */
|
||||
#define INTERVAL 90
|
||||
|
||||
#define ARP_MARK 0
|
||||
#define ARP_FOUND 1 /* Confirmed */
|
||||
#define ARP_NEW 2 /* Newly created */
|
||||
#define ARP_EMPTY 3 /* No MAC addr */
|
||||
|
||||
struct arp_record {
|
||||
unsigned short hwlen, status;
|
||||
int family;
|
||||
unsigned char hwaddr[DHCP_CHADDR_MAX];
|
||||
struct all_addr addr;
|
||||
struct arp_record *next;
|
||||
};
|
||||
|
||||
static struct arp_record *arps = NULL, *old = NULL, *freelist = NULL;
|
||||
static time_t last = 0;
|
||||
|
||||
static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
|
||||
{
|
||||
struct arp_record *arp;
|
||||
|
||||
(void)parmv;
|
||||
|
||||
if (maclen > DHCP_CHADDR_MAX)
|
||||
return 1;
|
||||
|
||||
#ifndef HAVE_IPV6
|
||||
if (family != AF_INET)
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
/* Look for existing entry */
|
||||
for (arp = arps; arp; arp = arp->next)
|
||||
{
|
||||
if (family != arp->family || arp->status == ARP_NEW)
|
||||
continue;
|
||||
|
||||
if (family == AF_INET)
|
||||
{
|
||||
if (arp->addr.addr.addr4.s_addr != ((struct in_addr *)addrp)->s_addr)
|
||||
continue;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, (struct in6_addr *)addrp))
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (arp->status == ARP_EMPTY)
|
||||
{
|
||||
/* existing address, was negative. */
|
||||
arp->status = ARP_NEW;
|
||||
arp->hwlen = maclen;
|
||||
memcpy(arp->hwaddr, mac, maclen);
|
||||
}
|
||||
else if (arp->hwlen == maclen && memcmp(arp->hwaddr, mac, maclen) == 0)
|
||||
/* Existing entry matches - confirm. */
|
||||
arp->status = ARP_FOUND;
|
||||
else
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!arp)
|
||||
{
|
||||
/* New entry */
|
||||
if (freelist)
|
||||
{
|
||||
arp = freelist;
|
||||
freelist = freelist->next;
|
||||
}
|
||||
else if (!(arp = whine_malloc(sizeof(struct arp_record))))
|
||||
return 1;
|
||||
|
||||
arp->next = arps;
|
||||
arps = arp;
|
||||
arp->status = ARP_NEW;
|
||||
arp->hwlen = maclen;
|
||||
arp->family = family;
|
||||
memcpy(arp->hwaddr, mac, maclen);
|
||||
if (family == AF_INET)
|
||||
arp->addr.addr.addr4.s_addr = ((struct in_addr *)addrp)->s_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
memcpy(&arp->addr.addr.addr6, addrp, IN6ADDRSZ);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* If in lazy mode, we cache absence of ARP entries. */
|
||||
int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now)
|
||||
{
|
||||
struct arp_record *arp, *tmp, **up;
|
||||
int updated = 0;
|
||||
|
||||
again:
|
||||
|
||||
/* If the database is less then INTERVAL old, look in there */
|
||||
if (difftime(now, last) < INTERVAL)
|
||||
{
|
||||
/* addr == NULL -> just make cache up-to-date */
|
||||
if (!addr)
|
||||
return 0;
|
||||
|
||||
for (arp = arps; arp; arp = arp->next)
|
||||
{
|
||||
if (addr->sa.sa_family != arp->family)
|
||||
continue;
|
||||
|
||||
if (arp->family == AF_INET &&
|
||||
arp->addr.addr.addr4.s_addr != addr->in.sin_addr.s_addr)
|
||||
continue;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (arp->family == AF_INET6 &&
|
||||
!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, &addr->in6.sin6_addr))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
/* Only accept positive entries unless in lazy mode. */
|
||||
if (arp->status != ARP_EMPTY || lazy || updated)
|
||||
{
|
||||
if (mac && arp->hwlen != 0)
|
||||
memcpy(mac, arp->hwaddr, arp->hwlen);
|
||||
return arp->hwlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found, try the kernel */
|
||||
if (!updated)
|
||||
{
|
||||
updated = 1;
|
||||
last = now;
|
||||
|
||||
/* Mark all non-negative entries */
|
||||
for (arp = arps; arp; arp = arp->next)
|
||||
if (arp->status != ARP_EMPTY)
|
||||
arp->status = ARP_MARK;
|
||||
|
||||
iface_enumerate(AF_UNSPEC, NULL, filter_mac);
|
||||
|
||||
/* Remove all unconfirmed entries to old list. */
|
||||
for (arp = arps, up = &arps; arp; arp = tmp)
|
||||
{
|
||||
tmp = arp->next;
|
||||
|
||||
if (arp->status == ARP_MARK)
|
||||
{
|
||||
*up = arp->next;
|
||||
arp->next = old;
|
||||
old = arp;
|
||||
}
|
||||
else
|
||||
up = &arp->next;
|
||||
}
|
||||
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* record failure, so we don't consult the kernel each time
|
||||
we're asked for this address */
|
||||
if (freelist)
|
||||
{
|
||||
arp = freelist;
|
||||
freelist = freelist->next;
|
||||
}
|
||||
else
|
||||
arp = whine_malloc(sizeof(struct arp_record));
|
||||
|
||||
if (arp)
|
||||
{
|
||||
arp->next = arps;
|
||||
arps = arp;
|
||||
arp->status = ARP_EMPTY;
|
||||
arp->family = addr->sa.sa_family;
|
||||
arp->hwlen = 0;
|
||||
|
||||
if (addr->sa.sa_family == AF_INET)
|
||||
arp->addr.addr.addr4.s_addr = addr->in.sin_addr.s_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
memcpy(&arp->addr.addr.addr6, &addr->in6.sin6_addr, IN6ADDRSZ);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_arp_script_run(void)
|
||||
{
|
||||
struct arp_record *arp;
|
||||
|
||||
/* Notify any which went, then move to free list */
|
||||
if (old)
|
||||
{
|
||||
#ifdef HAVE_SCRIPT
|
||||
if (option_bool(OPT_SCRIPT_ARP))
|
||||
queue_arp(ACTION_ARP_DEL, old->hwaddr, old->hwlen, old->family, &old->addr);
|
||||
#endif
|
||||
arp = old;
|
||||
old = arp->next;
|
||||
arp->next = freelist;
|
||||
freelist = arp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (arp = arps; arp; arp = arp->next)
|
||||
if (arp->status == ARP_NEW)
|
||||
{
|
||||
#ifdef HAVE_SCRIPT
|
||||
if (option_bool(OPT_SCRIPT_ARP))
|
||||
queue_arp(ACTION_ARP, arp->hwaddr, arp->hwlen, arp->family, &arp->addr);
|
||||
#endif
|
||||
arp->status = ARP_FOUND;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
81
src/auth.c
81
src/auth.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -81,7 +81,8 @@ int in_zone(struct auth_zone *zone, char *name, char **cut)
|
||||
}
|
||||
|
||||
|
||||
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, int local_query)
|
||||
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr,
|
||||
int local_query, int do_bit, int have_pseudoheader)
|
||||
{
|
||||
char *name = daemon->namebuff;
|
||||
unsigned char *p, *ansp;
|
||||
@@ -131,24 +132,27 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
continue;
|
||||
}
|
||||
|
||||
if (qtype == T_PTR)
|
||||
if ((qtype == T_PTR || qtype == T_SOA || qtype == T_NS) &&
|
||||
(flag = in_arpa_name_2_addr(name, &addr)) &&
|
||||
!local_query)
|
||||
{
|
||||
if (!(flag = in_arpa_name_2_addr(name, &addr)))
|
||||
continue;
|
||||
|
||||
if (!local_query)
|
||||
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
||||
if ((subnet = find_subnet(zone, flag, &addr)))
|
||||
break;
|
||||
|
||||
if (!zone)
|
||||
{
|
||||
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
||||
if ((subnet = find_subnet(zone, flag, &addr)))
|
||||
break;
|
||||
|
||||
if (!zone)
|
||||
{
|
||||
auth = 0;
|
||||
continue;
|
||||
}
|
||||
auth = 0;
|
||||
continue;
|
||||
}
|
||||
else if (qtype == T_SOA)
|
||||
soa = 1, found = 1;
|
||||
else if (qtype == T_NS)
|
||||
ns = 1, found = 1;
|
||||
}
|
||||
|
||||
if (qtype == T_PTR && flag)
|
||||
{
|
||||
intr = NULL;
|
||||
|
||||
if (flag == F_IPV4)
|
||||
@@ -186,7 +190,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
if (intr)
|
||||
{
|
||||
if (in_zone(zone, intr->name, NULL))
|
||||
if (local_query || in_zone(zone, intr->name, NULL))
|
||||
{
|
||||
found = 1;
|
||||
log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
|
||||
@@ -208,8 +212,11 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
*p = 0; /* must be bare name */
|
||||
|
||||
/* add external domain */
|
||||
strcat(name, ".");
|
||||
strcat(name, zone->domain);
|
||||
if (zone)
|
||||
{
|
||||
strcat(name, ".");
|
||||
strcat(name, zone->domain);
|
||||
}
|
||||
log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
@@ -217,7 +224,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
T_PTR, C_IN, "d", name))
|
||||
anscount++;
|
||||
}
|
||||
else if (crecp->flags & (F_DHCP | F_HOSTS) && in_zone(zone, name, NULL))
|
||||
else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL)))
|
||||
{
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
|
||||
found = 1;
|
||||
@@ -240,14 +247,20 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
}
|
||||
|
||||
cname_restart:
|
||||
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
||||
if (in_zone(zone, name, &cut))
|
||||
break;
|
||||
|
||||
if (!zone)
|
||||
if (found)
|
||||
/* NS and SOA .arpa requests have set found above. */
|
||||
cut = NULL;
|
||||
else
|
||||
{
|
||||
auth = 0;
|
||||
continue;
|
||||
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
||||
if (in_zone(zone, name, &cut))
|
||||
break;
|
||||
|
||||
if (!zone)
|
||||
{
|
||||
auth = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (rec = daemon->mxnames; rec; rec = rec->next)
|
||||
@@ -363,6 +376,10 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype &&
|
||||
(local_query || filter_zone(zone, flag, &addrlist->addr)))
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
if (addrlist->flags & ADDRLIST_REVONLY)
|
||||
continue;
|
||||
#endif
|
||||
found = 1;
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
@@ -409,7 +426,10 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
peer_addr->in.sin_port = 0;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
peer_addr->in6.sin6_port = 0;
|
||||
{
|
||||
peer_addr->in6.sin6_port = 0;
|
||||
peer_addr->in6.sin6_scope_id = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (peers = daemon->auth_peers; peers; peers = peers->next)
|
||||
@@ -801,6 +821,11 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
header->ancount = htons(anscount);
|
||||
header->nscount = htons(authcount);
|
||||
header->arcount = htons(0);
|
||||
|
||||
/* Advertise our packet size limit in our reply */
|
||||
if (have_pseudoheader)
|
||||
return add_pseudoheader(header, ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
|
||||
return ansp - (unsigned char *)header;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -20,7 +20,9 @@
|
||||
#include <ifaddrs.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if_dl.h>
|
||||
@@ -359,7 +361,7 @@ void send_via_bpf(struct dhcp_packet *mess, size_t len,
|
||||
iov[3].iov_base = mess;
|
||||
iov[3].iov_len = len;
|
||||
|
||||
while (writev(daemon->dhcp_raw_fd, iov, 4) == -1 && retry_send());
|
||||
while (retry_send(writev(daemon->dhcp_raw_fd, iov, 4)));
|
||||
}
|
||||
|
||||
#endif /* defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP) */
|
||||
|
||||
217
src/cache.c
217
src/cache.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -189,12 +189,7 @@ static void cache_hash(struct crec *crecp)
|
||||
static void cache_blockdata_free(struct crec *crecp)
|
||||
{
|
||||
if (crecp->flags & F_DNSKEY)
|
||||
{
|
||||
if (crecp->flags & F_DS)
|
||||
blockdata_free(crecp->addr.sig.keydata);
|
||||
else
|
||||
blockdata_free(crecp->addr.key.keydata);
|
||||
}
|
||||
blockdata_free(crecp->addr.key.keydata);
|
||||
else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
|
||||
blockdata_free(crecp->addr.ds.keydata);
|
||||
}
|
||||
@@ -322,7 +317,7 @@ static int is_expired(time_t now, struct crec *crecp)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
|
||||
static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
|
||||
{
|
||||
/* Scan and remove old entries.
|
||||
If (flags & F_FORWARD) then remove any forward entries for name and any expired
|
||||
@@ -331,8 +326,8 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
|
||||
entries in the whole cache.
|
||||
If (flags == 0) remove any expired entries in the whole cache.
|
||||
|
||||
In the flags & F_FORWARD case, the return code is valid, and returns zero if the
|
||||
name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
|
||||
In the flags & F_FORWARD case, the return code is valid, and returns a non-NULL pointer
|
||||
to a cache entry if the name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
|
||||
|
||||
We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
|
||||
so that when we hit an entry which isn't reverse and is immortal, we're done. */
|
||||
@@ -361,7 +356,7 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
|
||||
(((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
|
||||
{
|
||||
if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
|
||||
return 0;
|
||||
return crecp;
|
||||
*up = crecp->hash_next;
|
||||
cache_unlink(crecp);
|
||||
cache_free(crecp);
|
||||
@@ -369,16 +364,11 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* Deletion has to be class-sensitive for DS, DNSKEY, RRSIG, also
|
||||
type-covered sensitive for RRSIG */
|
||||
if ((flags & (F_DNSKEY | F_DS)) &&
|
||||
(flags & (F_DNSKEY | F_DS)) == (crecp->flags & (F_DNSKEY | F_DS)) &&
|
||||
crecp->uid == addr->addr.dnssec.class &&
|
||||
(!((flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY)) ||
|
||||
crecp->addr.sig.type_covered == addr->addr.dnssec.type))
|
||||
/* Deletion has to be class-sensitive for DS and DNSKEY */
|
||||
if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == addr->addr.dnssec.class)
|
||||
{
|
||||
if (crecp->flags & F_CONFIG)
|
||||
return 0;
|
||||
return crecp;
|
||||
*up = crecp->hash_next;
|
||||
cache_unlink(crecp);
|
||||
cache_free(crecp);
|
||||
@@ -423,7 +413,7 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
|
||||
up = &crecp->hash_next;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Note: The normal calling sequence is
|
||||
@@ -461,9 +451,11 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
|
||||
{
|
||||
log_query(flags | F_UPSTREAM, name, addr, NULL);
|
||||
/* Don;t mess with TTL for DNSSEC records. */
|
||||
/* Don't mess with TTL for DNSSEC records. */
|
||||
if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
|
||||
ttl = daemon->max_cache_ttl;
|
||||
if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
|
||||
ttl = daemon->min_cache_ttl;
|
||||
}
|
||||
|
||||
/* if previous insertion failed give up now. */
|
||||
@@ -471,10 +463,26 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
return NULL;
|
||||
|
||||
/* First remove any expired entries and entries for the name/address we
|
||||
are currently inserting. Fail if we attempt to delete a name from
|
||||
/etc/hosts or DHCP. */
|
||||
if (!cache_scan_free(name, addr, now, flags))
|
||||
are currently inserting. */
|
||||
if ((new = cache_scan_free(name, addr, now, flags)))
|
||||
{
|
||||
/* We're trying to insert a record over one from
|
||||
/etc/hosts or DHCP, or other config. If the
|
||||
existing record is for an A or AAAA and
|
||||
the record we're trying to insert is the same,
|
||||
just drop the insert, but don't error the whole process. */
|
||||
if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD) && addr)
|
||||
{
|
||||
if ((flags & F_IPV4) && (new->flags & F_IPV4) &&
|
||||
new->addr.addr.addr.addr4.s_addr == addr->addr.addr4.s_addr)
|
||||
return new;
|
||||
#ifdef HAVE_IPV6
|
||||
else if ((flags & F_IPV6) && (new->flags & F_IPV6) &&
|
||||
IN6_ARE_ADDR_EQUAL(&new->addr.addr.addr.addr6, &addr->addr.addr6))
|
||||
return new;
|
||||
#endif
|
||||
}
|
||||
|
||||
insert_error = 1;
|
||||
return NULL;
|
||||
}
|
||||
@@ -514,13 +522,9 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
struct all_addr free_addr = new->addr.addr;;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* For DNSSEC records, addr holds class and type_covered for RRSIG */
|
||||
/* For DNSSEC records, addr holds class. */
|
||||
if (new->flags & (F_DS | F_DNSKEY))
|
||||
{
|
||||
free_addr.addr.dnssec.class = new->uid;
|
||||
if ((new->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
|
||||
free_addr.addr.dnssec.type = new->addr.sig.type_covered;
|
||||
}
|
||||
free_addr.addr.dnssec.class = new->uid;
|
||||
#endif
|
||||
|
||||
free_avail = 1; /* Must be free space now. */
|
||||
@@ -635,9 +639,6 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
|
||||
{
|
||||
if ((crecp->flags & F_FORWARD) &&
|
||||
#ifdef HAVE_DNSSEC
|
||||
(((crecp->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
|
||||
#endif
|
||||
(crecp->flags & prot) &&
|
||||
hostname_isequal(cache_get_name(crecp), name))
|
||||
{
|
||||
@@ -695,9 +696,6 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
|
||||
if (ans &&
|
||||
(ans->flags & F_FORWARD) &&
|
||||
#ifdef HAVE_DNSSEC
|
||||
(((ans->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
|
||||
#endif
|
||||
(ans->flags & prot) &&
|
||||
hostname_isequal(cache_get_name(ans), name))
|
||||
return ans;
|
||||
@@ -780,6 +778,7 @@ static void add_hosts_cname(struct crec *target)
|
||||
(crec = whine_malloc(sizeof(struct crec))))
|
||||
{
|
||||
crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
|
||||
crec->ttd = a->ttl;
|
||||
crec->name.namep = a->alias;
|
||||
crec->addr.cname.target.cache = target;
|
||||
crec->addr.cname.uid = target->uid;
|
||||
@@ -817,27 +816,42 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
|
||||
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. */
|
||||
large (10000 entry) hosts files.
|
||||
|
||||
Note that we only do this process when bulk-reading hosts files,
|
||||
for incremental reads, rhash is NULL, and we use cache lookups
|
||||
instead.
|
||||
*/
|
||||
|
||||
/* hash address */
|
||||
for (j = 0, i = 0; i < addrlen; i++)
|
||||
j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
|
||||
|
||||
for (lookup = rhash[j]; lookup; lookup = lookup->next)
|
||||
if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
|
||||
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
|
||||
{
|
||||
cache->flags &= ~F_REVERSE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* maintain address hash chain, insert new unique address */
|
||||
if (!lookup)
|
||||
if (rhash)
|
||||
{
|
||||
cache->next = rhash[j];
|
||||
rhash[j] = cache;
|
||||
/* hash address */
|
||||
for (j = 0, i = 0; i < addrlen; i++)
|
||||
j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
|
||||
|
||||
for (lookup = rhash[j]; lookup; lookup = lookup->next)
|
||||
if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
|
||||
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
|
||||
{
|
||||
cache->flags &= ~F_REVERSE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* maintain address hash chain, insert new unique address */
|
||||
if (!lookup)
|
||||
{
|
||||
cache->next = rhash[j];
|
||||
rhash[j] = cache;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
/* incremental read, lookup in cache */
|
||||
lookup = cache_find_by_addr(NULL, addr, 0, cache->flags & (F_IPV4 | F_IPV6));
|
||||
if (lookup && lookup->flags & F_HOSTS)
|
||||
cache->flags &= ~F_REVERSE;
|
||||
}
|
||||
|
||||
cache->uid = index;
|
||||
memcpy(&cache->addr.addr, addr, addrlen);
|
||||
cache_hash(cache);
|
||||
@@ -894,7 +908,7 @@ static int gettok(FILE *f, char *token)
|
||||
}
|
||||
}
|
||||
|
||||
static int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
|
||||
int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
|
||||
{
|
||||
FILE *f = fopen(filename, "r");
|
||||
char *token = daemon->namebuff, *domain_suffix = NULL;
|
||||
@@ -906,7 +920,7 @@ static int read_hostsfile(char *filename, unsigned int index, int cache_size, st
|
||||
if (!f)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
|
||||
return 0;
|
||||
return cache_size;
|
||||
}
|
||||
|
||||
eatspace(f);
|
||||
@@ -940,7 +954,7 @@ static int read_hostsfile(char *filename, unsigned int index, int cache_size, st
|
||||
addr_count++;
|
||||
|
||||
/* rehash every 1000 names. */
|
||||
if ((name_count - cache_size) > 1000)
|
||||
if (rhash && ((name_count - cache_size) > 1000))
|
||||
{
|
||||
rehash(name_count);
|
||||
cache_size = name_count;
|
||||
@@ -968,6 +982,7 @@ static int read_hostsfile(char *filename, unsigned int index, int cache_size, st
|
||||
strcat(cache->name.sname, ".");
|
||||
strcat(cache->name.sname, domain_suffix);
|
||||
cache->flags = flags;
|
||||
cache->ttd = daemon->local_ttl;
|
||||
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
|
||||
name_count++;
|
||||
}
|
||||
@@ -975,6 +990,7 @@ static int read_hostsfile(char *filename, unsigned int index, int cache_size, st
|
||||
{
|
||||
strcpy(cache->name.sname, canon);
|
||||
cache->flags = flags;
|
||||
cache->ttd = daemon->local_ttl;
|
||||
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
|
||||
name_count++;
|
||||
}
|
||||
@@ -987,7 +1003,9 @@ static int read_hostsfile(char *filename, unsigned int index, int cache_size, st
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
rehash(name_count);
|
||||
|
||||
if (rhash)
|
||||
rehash(name_count);
|
||||
|
||||
my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
|
||||
|
||||
@@ -1042,6 +1060,7 @@ void cache_reload(void)
|
||||
((cache = whine_malloc(sizeof(struct crec)))))
|
||||
{
|
||||
cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
|
||||
cache->ttd = a->ttl;
|
||||
cache->name.namep = a->alias;
|
||||
cache->addr.cname.target.int_name = intr;
|
||||
cache->addr.cname.uid = SRC_INTERFACE;
|
||||
@@ -1056,6 +1075,7 @@ void cache_reload(void)
|
||||
(cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
|
||||
{
|
||||
cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
|
||||
cache->ttd = daemon->local_ttl;
|
||||
cache->name.namep = ds->name;
|
||||
cache->addr.ds.keylen = ds->digestlen;
|
||||
cache->addr.ds.algo = ds->algo;
|
||||
@@ -1080,6 +1100,7 @@ void cache_reload(void)
|
||||
(cache = whine_malloc(sizeof(struct crec))))
|
||||
{
|
||||
cache->name.namep = nl->name;
|
||||
cache->ttd = hr->ttl;
|
||||
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
|
||||
}
|
||||
@@ -1088,6 +1109,7 @@ void cache_reload(void)
|
||||
(cache = whine_malloc(sizeof(struct crec))))
|
||||
{
|
||||
cache->name.namep = nl->name;
|
||||
cache->ttd = hr->ttl;
|
||||
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
|
||||
}
|
||||
@@ -1098,16 +1120,22 @@ void cache_reload(void)
|
||||
{
|
||||
if (daemon->cachesize > 0)
|
||||
my_syslog(LOG_INFO, _("cleared cache"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!option_bool(OPT_NO_HOSTS))
|
||||
total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
|
||||
|
||||
daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
|
||||
for (ah = daemon->addn_hosts; ah; ah = ah->next)
|
||||
if (!(ah->flags & AH_INACTIVE))
|
||||
total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
|
||||
else
|
||||
{
|
||||
if (!option_bool(OPT_NO_HOSTS))
|
||||
total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
|
||||
|
||||
daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
|
||||
for (ah = daemon->addn_hosts; ah; ah = ah->next)
|
||||
if (!(ah->flags & AH_INACTIVE))
|
||||
total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
|
||||
}
|
||||
|
||||
#ifdef HAVE_INOTIFY
|
||||
set_dynamic_inotify(AH_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
@@ -1326,7 +1354,7 @@ int cache_make_stat(struct txt_record *t)
|
||||
}
|
||||
port = prettyprint_addr(&serv->addr, daemon->addrbuff);
|
||||
lenp = p++; /* length */
|
||||
bytes_avail = (p - buff) + bufflen;
|
||||
bytes_avail = bufflen - (p - buff );
|
||||
bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
|
||||
if (bytes_needed >= bytes_avail)
|
||||
{
|
||||
@@ -1340,7 +1368,7 @@ int cache_make_stat(struct txt_record *t)
|
||||
lenp = p - 1;
|
||||
buff = new;
|
||||
bufflen = newlen;
|
||||
bytes_avail = (p - buff) + bufflen;
|
||||
bytes_avail = bufflen - (p - buff );
|
||||
bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
|
||||
}
|
||||
*lenp = bytes_needed;
|
||||
@@ -1358,6 +1386,20 @@ int cache_make_stat(struct txt_record *t)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* There can be names in the cache containing control chars, don't
|
||||
mess up logging or open security holes. */
|
||||
static char *sanitise(char *name)
|
||||
{
|
||||
unsigned char *r;
|
||||
if (name)
|
||||
for (r = (unsigned char *)name; *r; r++)
|
||||
if (!isprint((int)*r))
|
||||
return "<name unprintable>";
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
void dump_cache(time_t now)
|
||||
{
|
||||
struct server *serv, *serv1;
|
||||
@@ -1411,17 +1453,13 @@ void dump_cache(time_t now)
|
||||
*a = 0;
|
||||
if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
|
||||
n = "<Root>";
|
||||
p += sprintf(p, "%-40.40s ", n);
|
||||
p += sprintf(p, "%-30.30s ", sanitise(n));
|
||||
if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
|
||||
a = cache_get_cname_target(cache);
|
||||
a = sanitise(cache_get_cname_target(cache));
|
||||
#ifdef HAVE_DNSSEC
|
||||
else if (cache->flags & F_DS)
|
||||
{
|
||||
if (cache->flags & F_DNSKEY)
|
||||
/* RRSIG */
|
||||
sprintf(a, "%5u %3u %s", cache->addr.sig.keytag,
|
||||
cache->addr.sig.algo, querystr("", cache->addr.sig.type_covered));
|
||||
else if (!(cache->flags & F_NEG))
|
||||
if (!(cache->flags & F_NEG))
|
||||
sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
|
||||
cache->addr.ds.algo, cache->addr.ds.digest);
|
||||
}
|
||||
@@ -1447,14 +1485,12 @@ void dump_cache(time_t now)
|
||||
else if (cache->flags & F_CNAME)
|
||||
t = "C";
|
||||
#ifdef HAVE_DNSSEC
|
||||
else if ((cache->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
|
||||
t = "G"; /* DNSKEY and DS set -> RRISG */
|
||||
else if (cache->flags & F_DS)
|
||||
t = "S";
|
||||
else if (cache->flags & F_DNSKEY)
|
||||
t = "K";
|
||||
#endif
|
||||
p += sprintf(p, "%-30.30s %s%s%s%s%s%s%s%s%s ", a, t,
|
||||
p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s ", a, t,
|
||||
cache->flags & F_FORWARD ? "F" : " ",
|
||||
cache->flags & F_REVERSE ? "R" : " ",
|
||||
cache->flags & F_IMMORTAL ? "I" : " ",
|
||||
@@ -1487,7 +1523,13 @@ char *record_source(unsigned int index)
|
||||
for (ah = daemon->addn_hosts; ah; ah = ah->next)
|
||||
if (ah->index == index)
|
||||
return ah->fname;
|
||||
|
||||
|
||||
#ifdef HAVE_INOTIFY
|
||||
for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
|
||||
if (ah->index == index)
|
||||
return ah->fname;
|
||||
#endif
|
||||
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
@@ -1540,10 +1582,12 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||
if (!option_bool(OPT_LOG))
|
||||
return;
|
||||
|
||||
name = sanitise(name);
|
||||
|
||||
if (addr)
|
||||
{
|
||||
if (flags & F_KEYTAG)
|
||||
sprintf(daemon->addrbuff, arg, addr->addr.keytag);
|
||||
sprintf(daemon->addrbuff, arg, addr->addr.log.keytag, addr->addr.log.algo, addr->addr.log.digest);
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -1622,7 +1666,16 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||
if (strlen(name) == 0)
|
||||
name = ".";
|
||||
|
||||
my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
|
||||
if (option_bool(OPT_EXTRALOG))
|
||||
{
|
||||
int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
|
||||
if (flags & F_NOEXTRA)
|
||||
my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
|
||||
else
|
||||
my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest);
|
||||
}
|
||||
else
|
||||
my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
|
||||
}
|
||||
|
||||
|
||||
|
||||
20
src/config.h
20
src/config.h
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -17,7 +17,9 @@
|
||||
#define FTABSIZ 150 /* max number of outstanding requests (default) */
|
||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
|
||||
#define TCP_MAX_QUERIES 100 /* Maximum number of queries per incoming TCP connection */
|
||||
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
|
||||
#define SAFE_PKTSZ 1280 /* "go anywhere" UDP packet size */
|
||||
#define KEYBLOCK_LEN 40 /* choose to mininise fragmentation when storing DNSSEC keys */
|
||||
#define DNSSEC_WORK 50 /* Max number of queries to validate one question */
|
||||
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
|
||||
@@ -26,6 +28,7 @@
|
||||
#define RANDOM_SOCKS 64 /* max simultaneous random ports */
|
||||
#define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
|
||||
#define CACHESIZ 150 /* default cache size */
|
||||
#define TTL_FLOOR_LIMIT 3600 /* don't allow --min-cache-ttl to raise TTL above this under any circumstances */
|
||||
#define MAXLEASES 1000 /* maximum number of DHCP leases */
|
||||
#define PING_WAIT 3 /* wait for ping address-in-use test */
|
||||
#define PING_CACHE_TIME 30 /* Ping test assumed to be valid this long. */
|
||||
@@ -113,6 +116,8 @@ HAVE_DNSSEC
|
||||
HAVE_LOOP
|
||||
include functionality to probe for and remove DNS forwarding loops.
|
||||
|
||||
HAVE_INOTIFY
|
||||
use the Linux inotify facility to efficiently re-read configuration files.
|
||||
|
||||
NO_IPV6
|
||||
NO_TFTP
|
||||
@@ -121,6 +126,7 @@ NO_DHCP6
|
||||
NO_SCRIPT
|
||||
NO_LARGEFILE
|
||||
NO_AUTH
|
||||
NO_INOTIFY
|
||||
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
|
||||
@@ -331,7 +337,7 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#define HAVE_DHCP
|
||||
#endif
|
||||
|
||||
#if defined(NO_SCRIPT) || !defined(HAVE_DHCP) || defined(NO_FORK)
|
||||
#if defined(NO_SCRIPT) || defined(NO_FORK)
|
||||
#undef HAVE_SCRIPT
|
||||
#undef HAVE_LUASCRIPT
|
||||
#endif
|
||||
@@ -353,6 +359,10 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#undef HAVE_LOOP
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_LINUX_NETWORK) && !defined(NO_INOTIFY)
|
||||
#define HAVE_INOTIFY
|
||||
#endif
|
||||
|
||||
/* Define a string indicating which options are in use.
|
||||
DNSMASQP_COMPILE_OPTS is only defined in dnsmasq.c */
|
||||
|
||||
@@ -426,7 +436,11 @@ static char *compile_opts =
|
||||
#ifndef HAVE_LOOP
|
||||
"no-"
|
||||
#endif
|
||||
"loop-detect";
|
||||
"loop-detect "
|
||||
#ifndef HAVE_INOTIFY
|
||||
"no-"
|
||||
#endif
|
||||
"inotify";
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
216
src/dbus.c
216
src/dbus.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -70,6 +70,21 @@ const char* introspection_xml_template =
|
||||
" <arg name=\"hwaddr\" type=\"s\"/>\n"
|
||||
" <arg name=\"hostname\" type=\"s\"/>\n"
|
||||
" </signal>\n"
|
||||
#ifdef HAVE_DHCP
|
||||
" <method name=\"AddDhcpLease\">\n"
|
||||
" <arg name=\"ipaddr\" type=\"s\"/>\n"
|
||||
" <arg name=\"hwaddr\" type=\"s\"/>\n"
|
||||
" <arg name=\"hostname\" type=\"ay\"/>\n"
|
||||
" <arg name=\"clid\" type=\"ay\"/>\n"
|
||||
" <arg name=\"lease_duration\" type=\"u\"/>\n"
|
||||
" <arg name=\"ia_id\" type=\"u\"/>\n"
|
||||
" <arg name=\"is_temporary\" type=\"b\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"DeleteDhcpLease\">\n"
|
||||
" <arg name=\"ipaddr\" type=\"s\"/>\n"
|
||||
" <arg name=\"success\" type=\"b\" direction=\"out\"/>\n"
|
||||
" </method>\n"
|
||||
#endif
|
||||
" </interface>\n"
|
||||
"</node>\n";
|
||||
|
||||
@@ -421,18 +436,184 @@ static DBusMessage *dbus_set_bool(DBusMessage *message, int flag, char *name)
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
my_syslog(LOG_INFO, "Enabling --%s option from D-Bus", name);
|
||||
my_syslog(LOG_INFO, _("Enabling --%s option from D-Bus"), name);
|
||||
set_option_bool(flag);
|
||||
}
|
||||
else
|
||||
{
|
||||
my_syslog(LOG_INFO, "Disabling --$s option from D-Bus", name);
|
||||
my_syslog(LOG_INFO, _("Disabling --%s option from D-Bus"), name);
|
||||
reset_option_bool(flag);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
static DBusMessage *dbus_add_lease(DBusMessage* message)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
const char *ipaddr, *hwaddr, *hostname, *tmp;
|
||||
const unsigned char* clid;
|
||||
int clid_len, hostname_len, hw_len, hw_type;
|
||||
dbus_uint32_t expires, ia_id;
|
||||
dbus_bool_t is_temporary;
|
||||
struct all_addr addr;
|
||||
time_t now = dnsmasq_time();
|
||||
unsigned char dhcp_chaddr[DHCP_CHADDR_MAX];
|
||||
|
||||
DBusMessageIter iter, array_iter;
|
||||
if (!dbus_message_iter_init(message, &iter))
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Failed to initialize dbus message iter");
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected string as first argument");
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &ipaddr);
|
||||
dbus_message_iter_next(&iter);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected string as second argument");
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &hwaddr);
|
||||
dbus_message_iter_next(&iter);
|
||||
|
||||
if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
|
||||
(dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE))
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected byte array as third argument");
|
||||
|
||||
dbus_message_iter_recurse(&iter, &array_iter);
|
||||
dbus_message_iter_get_fixed_array(&array_iter, &hostname, &hostname_len);
|
||||
tmp = memchr(hostname, '\0', hostname_len);
|
||||
if (tmp)
|
||||
{
|
||||
if (tmp == &hostname[hostname_len - 1])
|
||||
hostname_len--;
|
||||
else
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Hostname contains an embedded NUL character");
|
||||
}
|
||||
dbus_message_iter_next(&iter);
|
||||
|
||||
if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
|
||||
(dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE))
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected byte array as fourth argument");
|
||||
|
||||
dbus_message_iter_recurse(&iter, &array_iter);
|
||||
dbus_message_iter_get_fixed_array(&array_iter, &clid, &clid_len);
|
||||
dbus_message_iter_next(&iter);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected uint32 as fifth argument");
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &expires);
|
||||
dbus_message_iter_next(&iter);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected uint32 as sixth argument");
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &ia_id);
|
||||
dbus_message_iter_next(&iter);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected uint32 as sixth argument");
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &is_temporary);
|
||||
|
||||
if (inet_pton(AF_INET, ipaddr, &addr.addr.addr4))
|
||||
{
|
||||
if (ia_id != 0 || is_temporary)
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"ia_id and is_temporary must be zero for IPv4 lease");
|
||||
|
||||
if (!(lease = lease_find_by_addr(addr.addr.addr4)))
|
||||
lease = lease4_allocate(addr.addr.addr4);
|
||||
}
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (inet_pton(AF_INET6, ipaddr, &addr.addr.addr6))
|
||||
{
|
||||
if (!(lease = lease6_find_by_addr(&addr.addr.addr6, 128, 0)))
|
||||
lease = lease6_allocate(&addr.addr.addr6,
|
||||
is_temporary ? LEASE_TA : LEASE_NA);
|
||||
lease_set_iaid(lease, ia_id);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid IP address '%s'", ipaddr);
|
||||
|
||||
hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL,
|
||||
&hw_type);
|
||||
if (hw_type == 0 && hw_len != 0)
|
||||
hw_type = ARPHRD_ETHER;
|
||||
|
||||
lease_set_hwaddr(lease, dhcp_chaddr, clid, hw_len, hw_type,
|
||||
clid_len, now, 0);
|
||||
lease_set_expires(lease, expires, now);
|
||||
if (hostname_len != 0)
|
||||
lease_set_hostname(lease, hostname, 0, get_domain(lease->addr), NULL);
|
||||
|
||||
lease_update_file(now);
|
||||
lease_update_dns(0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static DBusMessage *dbus_del_lease(DBusMessage* message)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
DBusMessageIter iter;
|
||||
const char *ipaddr;
|
||||
DBusMessage *reply;
|
||||
struct all_addr addr;
|
||||
dbus_bool_t ret = 1;
|
||||
time_t now = dnsmasq_time();
|
||||
|
||||
if (!dbus_message_iter_init(message, &iter))
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Failed to initialize dbus message iter");
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected string as first argument");
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &ipaddr);
|
||||
|
||||
if (inet_pton(AF_INET, ipaddr, &addr.addr.addr4))
|
||||
lease = lease_find_by_addr(addr.addr.addr4);
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (inet_pton(AF_INET6, ipaddr, &addr.addr.addr6))
|
||||
lease = lease6_find_by_addr(&addr.addr.addr6, 128, 0);
|
||||
#endif
|
||||
else
|
||||
return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid IP address '%s'", ipaddr);
|
||||
|
||||
if (lease)
|
||||
{
|
||||
lease_prune(lease, now);
|
||||
lease_update_file(now);
|
||||
lease_update_dns(0);
|
||||
}
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
if ((reply = dbus_message_new_method_return(message)))
|
||||
dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &ret,
|
||||
DBUS_TYPE_INVALID);
|
||||
|
||||
|
||||
return reply;
|
||||
}
|
||||
#endif
|
||||
|
||||
DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
DBusMessage *message,
|
||||
void *user_data)
|
||||
@@ -490,6 +671,16 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
{
|
||||
reply = dbus_set_bool(message, OPT_BOGUSPRIV, "bogus-priv");
|
||||
}
|
||||
#ifdef HAVE_DHCP
|
||||
else if (strcmp(method, "AddDhcpLease") == 0)
|
||||
{
|
||||
reply = dbus_add_lease(message);
|
||||
}
|
||||
else if (strcmp(method, "DeleteDhcpLease") == 0)
|
||||
{
|
||||
reply = dbus_del_lease(message);
|
||||
}
|
||||
#endif
|
||||
else if (strcmp(method, "ClearCache") == 0)
|
||||
clear_cache = 1;
|
||||
else
|
||||
@@ -558,8 +749,7 @@ char *dbus_init(void)
|
||||
}
|
||||
|
||||
|
||||
void set_dbus_listeners(int *maxfdp,
|
||||
fd_set *rset, fd_set *wset, fd_set *eset)
|
||||
void set_dbus_listeners(void)
|
||||
{
|
||||
struct watch *w;
|
||||
|
||||
@@ -569,19 +759,17 @@ void set_dbus_listeners(int *maxfdp,
|
||||
unsigned int flags = dbus_watch_get_flags(w->watch);
|
||||
int fd = dbus_watch_get_unix_fd(w->watch);
|
||||
|
||||
bump_maxfd(fd, maxfdp);
|
||||
|
||||
if (flags & DBUS_WATCH_READABLE)
|
||||
FD_SET(fd, rset);
|
||||
poll_listen(fd, POLLIN);
|
||||
|
||||
if (flags & DBUS_WATCH_WRITABLE)
|
||||
FD_SET(fd, wset);
|
||||
poll_listen(fd, POLLOUT);
|
||||
|
||||
FD_SET(fd, eset);
|
||||
poll_listen(fd, POLLERR);
|
||||
}
|
||||
}
|
||||
|
||||
void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset)
|
||||
void check_dbus_listeners()
|
||||
{
|
||||
DBusConnection *connection = (DBusConnection *)daemon->dbus;
|
||||
struct watch *w;
|
||||
@@ -592,13 +780,13 @@ void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset)
|
||||
unsigned int flags = 0;
|
||||
int fd = dbus_watch_get_unix_fd(w->watch);
|
||||
|
||||
if (FD_ISSET(fd, rset))
|
||||
if (poll_check(fd, POLLIN))
|
||||
flags |= DBUS_WATCH_READABLE;
|
||||
|
||||
if (FD_ISSET(fd, wset))
|
||||
if (poll_check(fd, POLLOUT))
|
||||
flags |= DBUS_WATCH_WRITABLE;
|
||||
|
||||
if (FD_ISSET(fd, eset))
|
||||
if (poll_check(fd, POLLERR))
|
||||
flags |= DBUS_WATCH_ERROR;
|
||||
|
||||
if (flags != 0)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -545,8 +545,8 @@ static const struct opttab_t {
|
||||
{ "parameter-request", 55, OT_INTERNAL },
|
||||
{ "message", 56, OT_INTERNAL },
|
||||
{ "max-message-size", 57, OT_INTERNAL },
|
||||
{ "T1", 58, OT_INTERNAL | OT_TIME},
|
||||
{ "T2", 59, OT_INTERNAL | OT_TIME},
|
||||
{ "T1", 58, OT_TIME},
|
||||
{ "T2", 59, OT_TIME},
|
||||
{ "vendor-class", 60, 0 },
|
||||
{ "client-id", 61, OT_INTERNAL },
|
||||
{ "nis+-domain", 64, OT_NAME },
|
||||
@@ -599,7 +599,7 @@ static const struct opttab_t opttab6[] = {
|
||||
{ "sntp-server", 31, OT_ADDR_LIST },
|
||||
{ "information-refresh-time", 32, OT_TIME },
|
||||
{ "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
|
||||
{ "ntp-server", 56, OT_ADDR_LIST },
|
||||
{ "ntp-server", 56, 0 },
|
||||
{ "bootfile-url", 59, OT_NAME },
|
||||
{ "bootfile-param", 60, OT_CSTRING },
|
||||
{ NULL, 0, 0 }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
71
src/dhcp.c
71
src/dhcp.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -225,10 +225,11 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
|
||||
#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 */
|
||||
/* If the interface on which the DHCP request was received is an
|
||||
alias of some other interface (as specified by the
|
||||
--bridge-interface option), change ifr.ifr_name so that we look
|
||||
for DHCP contexts associated with the aliased interface instead
|
||||
of with the aliasing one. */
|
||||
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
|
||||
{
|
||||
for (alias = bridge->alias; alias; alias = alias->next)
|
||||
@@ -236,7 +237,9 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
{
|
||||
if (!(iface_index = if_nametoindex(bridge->iface)))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), ifr.ifr_name);
|
||||
my_syslog(MS_DHCP | LOG_WARNING,
|
||||
_("unknown interface %s in bridge-interface"),
|
||||
bridge->iface);
|
||||
return;
|
||||
}
|
||||
else
|
||||
@@ -376,10 +379,9 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
}
|
||||
}
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
|
||||
mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
|
||||
else
|
||||
{
|
||||
/* broadcast to 255.255.255.255 (or mac address invalid) */
|
||||
/* fill cmsg for outbound interface (both broadcast & unicast) */
|
||||
struct in_pktinfo *pkt;
|
||||
msg.msg_control = control_u.control;
|
||||
msg.msg_controllen = sizeof(control_u);
|
||||
@@ -389,23 +391,29 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
pkt->ipi_spec_dst.s_addr = 0;
|
||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||
cmptr->cmsg_level = IPPROTO_IP;
|
||||
cmptr->cmsg_type = IP_PKTINFO;
|
||||
dest.sin_addr.s_addr = INADDR_BROADCAST;
|
||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unicast to unconfigured client. Inject mac address direct into ARP cache.
|
||||
struct sockaddr limits size to 14 bytes. */
|
||||
dest.sin_addr = mess->yiaddr;
|
||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||
memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
|
||||
arp_req.arp_ha.sa_family = mess->htype;
|
||||
memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
|
||||
/* interface name already copied in */
|
||||
arp_req.arp_flags = ATF_COM;
|
||||
if (ioctl(daemon->dhcpfd, SIOCSARP, &arp_req) == -1)
|
||||
my_syslog(MS_DHCP | LOG_ERR, _("ARP-cache injection failed: %s"), strerror(errno));
|
||||
cmptr->cmsg_type = IP_PKTINFO;
|
||||
|
||||
if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
|
||||
mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
|
||||
{
|
||||
/* broadcast to 255.255.255.255 (or mac address invalid) */
|
||||
dest.sin_addr.s_addr = INADDR_BROADCAST;
|
||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unicast to unconfigured client. Inject mac address direct into ARP cache.
|
||||
struct sockaddr limits size to 14 bytes. */
|
||||
dest.sin_addr = mess->yiaddr;
|
||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||
memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
|
||||
arp_req.arp_ha.sa_family = mess->htype;
|
||||
memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
|
||||
/* interface name already copied in */
|
||||
arp_req.arp_flags = ATF_COM;
|
||||
if (ioctl(daemon->dhcpfd, SIOCSARP, &arp_req) == -1)
|
||||
my_syslog(MS_DHCP | LOG_ERR, _("ARP-cache injection failed: %s"), strerror(errno));
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER)
|
||||
@@ -443,9 +451,14 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
|
||||
#endif
|
||||
|
||||
while(sendmsg(fd, &msg, 0) == -1 && retry_send());
|
||||
while(retry_send(sendmsg(fd, &msg, 0)));
|
||||
|
||||
/* This can fail when, eg, iptables DROPS destination 255.255.255.255 */
|
||||
if (errno != 0)
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("Error sending DHCP packet to %s: %s"),
|
||||
inet_ntoa(dest.sin_addr), strerror(errno));
|
||||
}
|
||||
|
||||
|
||||
/* check against secondary interface addresses */
|
||||
static int check_listen_addrs(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||
@@ -638,7 +651,7 @@ int address_allocate(struct dhcp_context *context,
|
||||
/* hash hwaddr: use the SDBM hashing algorithm. Seems to give good
|
||||
dispersal even with similarly-valued "strings". */
|
||||
for (j = 0, i = 0; i < hw_len; i++)
|
||||
j += hwaddr[i] + (j << 6) + (j << 16) - j;
|
||||
j = hwaddr[i] + (j << 6) + (j << 16) - j;
|
||||
|
||||
for (pass = 0; pass <= 1; pass++)
|
||||
for (c = context; c; c = c->current)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
111
src/dhcp6.c
111
src/dhcp6.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -27,17 +27,10 @@ struct iface_param {
|
||||
int ind, addr_match;
|
||||
};
|
||||
|
||||
struct mac_param {
|
||||
struct in6_addr *target;
|
||||
unsigned char *mac;
|
||||
unsigned int maclen;
|
||||
};
|
||||
|
||||
|
||||
static int complete_context6(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int flags,
|
||||
unsigned int preferred, unsigned int valid, void *vparam);
|
||||
static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv);
|
||||
static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm);
|
||||
|
||||
void dhcp6_init(void)
|
||||
@@ -144,6 +137,8 @@ void dhcp6_packet(time_t now)
|
||||
|
||||
if ((port = relay_reply6(&from, sz, ifr.ifr_name)) == 0)
|
||||
{
|
||||
struct dhcp_bridge *bridge, *alias;
|
||||
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
@@ -160,6 +155,30 @@ void dhcp6_packet(time_t now)
|
||||
memset(&parm.fallback, 0, IN6ADDRSZ);
|
||||
memset(&parm.ll_addr, 0, IN6ADDRSZ);
|
||||
memset(&parm.ula_addr, 0, IN6ADDRSZ);
|
||||
|
||||
/* If the interface on which the DHCPv6 request was received is
|
||||
an alias of some other interface (as specified by the
|
||||
--bridge-interface option), change parm.ind so that we look
|
||||
for DHCPv6 contexts associated with the aliased interface
|
||||
instead of with the aliasing one. */
|
||||
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
|
||||
{
|
||||
for (alias = bridge->alias; alias; alias = alias->next)
|
||||
if (wildcard_matchn(alias->iface, ifr.ifr_name, IF_NAMESIZE))
|
||||
{
|
||||
parm.ind = if_nametoindex(bridge->iface);
|
||||
if (!parm.ind)
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_WARNING,
|
||||
_("unknown interface %s in bridge-interface"),
|
||||
bridge->iface);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (alias)
|
||||
break;
|
||||
}
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
|
||||
@@ -201,14 +220,14 @@ void dhcp6_packet(time_t now)
|
||||
inet_pton(AF_INET6, ALL_SERVERS, &all_servers);
|
||||
|
||||
if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))
|
||||
relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id);
|
||||
relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id, now);
|
||||
return;
|
||||
}
|
||||
|
||||
/* May have configured relay, but not DHCP server */
|
||||
if (!daemon->doing_dhcp6)
|
||||
return;
|
||||
|
||||
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
|
||||
port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
|
||||
@@ -225,79 +244,56 @@ void dhcp6_packet(time_t now)
|
||||
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());
|
||||
while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base,
|
||||
save_counter(0), 0, (struct sockaddr *)&from,
|
||||
sizeof(from))));
|
||||
}
|
||||
}
|
||||
|
||||
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsigned int *maclenp, unsigned int *mactypep)
|
||||
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsigned int *maclenp, unsigned int *mactypep, time_t now)
|
||||
{
|
||||
/* Recieving a packet from a host does not populate the neighbour
|
||||
cache, so we send a neighbour discovery request if we can't
|
||||
find the sender. Repeat a few times in case of packet loss. */
|
||||
|
||||
struct neigh_packet neigh;
|
||||
struct sockaddr_in6 addr;
|
||||
struct mac_param mac_param;
|
||||
int i;
|
||||
union mysockaddr addr;
|
||||
int i, maclen;
|
||||
|
||||
neigh.type = ND_NEIGHBOR_SOLICIT;
|
||||
neigh.code = 0;
|
||||
neigh.reserved = 0;
|
||||
neigh.target = *client;
|
||||
|
||||
/* RFC4443 section-2.3: checksum has to be zero to be calculated */
|
||||
neigh.checksum = 0;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.sin6_len = sizeof(struct sockaddr_in6);
|
||||
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
addr.sin6_family = AF_INET6;
|
||||
addr.sin6_port = htons(IPPROTO_ICMPV6);
|
||||
addr.sin6_addr = *client;
|
||||
addr.sin6_scope_id = iface;
|
||||
|
||||
mac_param.target = client;
|
||||
mac_param.maclen = 0;
|
||||
mac_param.mac = mac;
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
addr.in6.sin6_port = htons(IPPROTO_ICMPV6);
|
||||
addr.in6.sin6_addr = *client;
|
||||
addr.in6.sin6_scope_id = iface;
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
iface_enumerate(AF_UNSPEC, &mac_param, find_mac);
|
||||
|
||||
if (mac_param.maclen != 0)
|
||||
if ((maclen = find_mac(&addr, mac, 0, now)) != 0)
|
||||
break;
|
||||
|
||||
sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, (struct sockaddr *)&addr, sizeof(addr));
|
||||
|
||||
sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr));
|
||||
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 100000000; /* 100ms */
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
|
||||
*maclenp = mac_param.maclen;
|
||||
*maclenp = maclen;
|
||||
*mactypep = ARPHRD_ETHER;
|
||||
}
|
||||
|
||||
static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
|
||||
{
|
||||
struct mac_param *parm = parmv;
|
||||
|
||||
if (family == AF_INET6 && IN6_ARE_ADDR_EQUAL(parm->target, (struct in6_addr *)addrp))
|
||||
{
|
||||
if (maclen <= DHCP_CHADDR_MAX)
|
||||
{
|
||||
parm->maclen = maclen;
|
||||
memcpy(parm->mac, mac, maclen);
|
||||
}
|
||||
|
||||
return 0; /* found, abort */
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int complete_context6(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int flags, unsigned int preferred,
|
||||
unsigned int valid, void *vparam)
|
||||
@@ -424,7 +420,7 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c
|
||||
j = rand64();
|
||||
else
|
||||
for (j = iaid, i = 0; i < clid_len; i++)
|
||||
j += clid[i] + (j << 6) + (j << 16) - j;
|
||||
j = clid[i] + (j << 6) + (j << 16) - j;
|
||||
|
||||
for (pass = 0; pass <= plain_range ? 1 : 0; pass++)
|
||||
for (c = context; c; c = c->current)
|
||||
@@ -438,7 +434,16 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c
|
||||
/* seed is largest extant lease addr in this context */
|
||||
start = lease_find_max_addr6(c) + serial;
|
||||
else
|
||||
start = addr6part(&c->start6) + ((j + c->addr_epoch) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
|
||||
{
|
||||
u64 range = 1 + addr6part(&c->end6) - addr6part(&c->start6);
|
||||
u64 offset = j + c->addr_epoch;
|
||||
|
||||
/* don't divide by zero if range is whole 2^64 */
|
||||
if (range != 0)
|
||||
offset = offset % range;
|
||||
|
||||
start = addr6part(&c->start6) + offset;
|
||||
}
|
||||
|
||||
/* iterate until we find a free address. */
|
||||
addr = start;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#define NAMESERVER_PORT 53
|
||||
#define TFTP_PORT 69
|
||||
#define MAX_PORT 65535u
|
||||
|
||||
#define IN6ADDRSZ 16
|
||||
#define INADDRSZ 4
|
||||
@@ -77,6 +78,8 @@
|
||||
|
||||
#define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignment */
|
||||
#define EDNS0_OPTION_CLIENT_SUBNET 8 /* IANA */
|
||||
#define EDNS0_OPTION_NOMDEVICEID 65073 /* Nominum temporary assignment */
|
||||
#define EDNS0_OPTION_NOMCPEID 65074 /* Nominum temporary assignment */
|
||||
|
||||
struct dns_header {
|
||||
u16 id;
|
||||
@@ -84,15 +87,15 @@ struct dns_header {
|
||||
u16 qdcount,ancount,nscount,arcount;
|
||||
};
|
||||
|
||||
#define HB3_QR 0x80
|
||||
#define HB3_QR 0x80 /* Query */
|
||||
#define HB3_OPCODE 0x78
|
||||
#define HB3_AA 0x04
|
||||
#define HB3_TC 0x02
|
||||
#define HB3_RD 0x01
|
||||
#define HB3_AA 0x04 /* Authoritative Answer */
|
||||
#define HB3_TC 0x02 /* TrunCated */
|
||||
#define HB3_RD 0x01 /* Recursion Desired */
|
||||
|
||||
#define HB4_RA 0x80
|
||||
#define HB4_AD 0x20
|
||||
#define HB4_CD 0x10
|
||||
#define HB4_RA 0x80 /* Recursion Available */
|
||||
#define HB4_AD 0x20 /* Authenticated Data */
|
||||
#define HB4_CD 0x10 /* Checking Disabled */
|
||||
#define HB4_RCODE 0x0f
|
||||
|
||||
#define OPCODE(x) (((x)->hb3 & HB3_OPCODE) >> 3)
|
||||
@@ -142,3 +145,11 @@ struct dns_header {
|
||||
|
||||
#define ADD_RDLEN(header, pp, plen, len) \
|
||||
(!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))
|
||||
|
||||
/* Escape character in our presentation format for names.
|
||||
Cannot be '.' or /000 and must be !isprint().
|
||||
Note that escaped chars are stored as
|
||||
<NAME_ESCAPE> <orig-char+1>
|
||||
to ensure that the escaped form of /000 doesn't include /000
|
||||
*/
|
||||
#define NAME_ESCAPE 1
|
||||
|
||||
467
src/dnsmasq.c
467
src/dnsmasq.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -24,8 +24,8 @@ struct daemon *daemon;
|
||||
static volatile pid_t pid = 0;
|
||||
static volatile int pipewrite;
|
||||
|
||||
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 int set_dns_listeners(time_t now);
|
||||
static void check_dns_listeners(time_t now);
|
||||
static void sig_handler(int sig);
|
||||
static void async_event(int pipe, time_t now);
|
||||
static void fatal_event(struct event_desc *ev, char *msg);
|
||||
@@ -58,6 +58,9 @@ int main (int argc, char **argv)
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_relay *relay;
|
||||
#endif
|
||||
#ifdef HAVE_TFTP
|
||||
int tftp_prefix_missing = 0;
|
||||
#endif
|
||||
|
||||
#ifdef LOCALEDIR
|
||||
setlocale(LC_ALL, "");
|
||||
@@ -87,23 +90,34 @@ int main (int argc, char **argv)
|
||||
|
||||
if (daemon->edns_pktsz < PACKETSZ)
|
||||
daemon->edns_pktsz = PACKETSZ;
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* Enforce min packet big enough for DNSSEC */
|
||||
if (option_bool(OPT_DNSSEC_VALID) && daemon->edns_pktsz < EDNS_PKTSZ)
|
||||
daemon->edns_pktsz = EDNS_PKTSZ;
|
||||
#endif
|
||||
|
||||
daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
|
||||
daemon->edns_pktsz : DNSMASQ_PACKETSZ;
|
||||
/* Min buffer size: we check after adding each record, so there must be
|
||||
memory for the largest packet, and the largest record so the
|
||||
min for DNS is PACKETSZ+MAXDNAME+RRFIXEDSZ which is < 1000.
|
||||
This might be increased is EDNS packet size if greater than the minimum. */
|
||||
daemon->packet_buff_sz = daemon->edns_pktsz + MAXDNAME + RRFIXEDSZ;
|
||||
daemon->packet = safe_malloc(daemon->packet_buff_sz);
|
||||
|
||||
daemon->addrbuff = safe_malloc(ADDRSTRLEN);
|
||||
if (option_bool(OPT_EXTRALOG))
|
||||
daemon->addrbuff2 = safe_malloc(ADDRSTRLEN);
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
daemon->keyname = safe_malloc(MAXDNAME);
|
||||
daemon->workspacename = safe_malloc(MAXDNAME);
|
||||
/* Note that both /000 and '.' are allowed within labels. These get
|
||||
represented in presentation format using NAME_ESCAPE as an escape
|
||||
character when in DNSSEC mode.
|
||||
In theory, if all the characters in a name were /000 or
|
||||
'.' or NAME_ESCAPE then all would have to be escaped, so the
|
||||
presentation format would be twice as long as the spec.
|
||||
|
||||
daemon->namebuff was previously allocated by the option-reading
|
||||
code before we knew if we're in DNSSEC mode, so reallocate here. */
|
||||
free(daemon->namebuff);
|
||||
daemon->namebuff = safe_malloc(MAXDNAME * 2);
|
||||
daemon->keyname = safe_malloc(MAXDNAME * 2);
|
||||
daemon->workspacename = safe_malloc(MAXDNAME * 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -146,15 +160,28 @@ int main (int argc, char **argv)
|
||||
reset_option_bool(OPT_CLEVERBIND);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_INOTIFY
|
||||
if (daemon->dynamic_dirs)
|
||||
die(_("dhcp-hostsdir, dhcp-optsdir and hostsdir are not supported on this platform"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (!daemon->ds)
|
||||
die(_("No trust anchors provided for DNSSEC"), NULL, EC_BADCONF);
|
||||
struct ds_config *ds;
|
||||
|
||||
/* Must have at least a root trust anchor, or the DNSSEC code
|
||||
can loop forever. */
|
||||
for (ds = daemon->ds; ds; ds = ds->next)
|
||||
if (ds->name[0] == 0)
|
||||
break;
|
||||
|
||||
if (!ds)
|
||||
die(_("no root trust anchor provided for DNSSEC"), NULL, EC_BADCONF);
|
||||
|
||||
if (daemon->cachesize < CACHESIZ)
|
||||
die(_("Cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
|
||||
die(_("cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
|
||||
#else
|
||||
die(_("DNSSEC not available: set HAVE_DNSSEC in src/config.h"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
@@ -167,10 +194,10 @@ int main (int argc, char **argv)
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
|
||||
die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
|
||||
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);
|
||||
die(_("conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SOLARIS_NETWORK
|
||||
@@ -190,9 +217,15 @@ int main (int argc, char **argv)
|
||||
|
||||
#ifndef HAVE_LOOP
|
||||
if (option_bool(OPT_LOOP_DETECT))
|
||||
die(_("Loop detection not available: set HAVE_LOOP in src/config.h"), NULL, EC_BADCONF);
|
||||
die(_("loop detection not available: set HAVE_LOOP in src/config.h"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
|
||||
if (daemon->max_port != MAX_PORT && daemon->min_port == 0)
|
||||
daemon->min_port = 1024u;
|
||||
|
||||
if (daemon->max_port < daemon->min_port)
|
||||
die(_("max_port cannot be smaller than min_port"), NULL, EC_BADCONF);
|
||||
|
||||
now = dnsmasq_time();
|
||||
|
||||
/* Create a serial at startup if not configured. */
|
||||
@@ -226,8 +259,11 @@ int main (int argc, char **argv)
|
||||
/* Note that order matters here, we must call lease_init before
|
||||
creating any file descriptors which shouldn't be leaked
|
||||
to the lease-script init process. We need to call common_init
|
||||
before lease_init to allocate buffers it uses.*/
|
||||
if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || daemon->relay6)
|
||||
before lease_init to allocate buffers it uses.
|
||||
The script subsystem relies on DHCP buffers, hence the last two
|
||||
conditions below. */
|
||||
if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 ||
|
||||
daemon->relay6 || option_bool(OPT_TFTP) || option_bool(OPT_SCRIPT_ARP))
|
||||
{
|
||||
dhcp_common_init();
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
@@ -315,11 +351,19 @@ int main (int argc, char **argv)
|
||||
if (daemon->port != 0)
|
||||
{
|
||||
cache_init();
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
blockdata_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_INOTIFY
|
||||
if (daemon->port != 0 || daemon->dhcp || daemon->doing_dhcp6)
|
||||
inotify_dnsmasq_init();
|
||||
else
|
||||
daemon->inotifyfd = -1;
|
||||
#endif
|
||||
|
||||
if (option_bool(OPT_DBUS))
|
||||
#ifdef HAVE_DBUS
|
||||
{
|
||||
@@ -332,7 +376,7 @@ int main (int argc, char **argv)
|
||||
#else
|
||||
die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
|
||||
if (daemon->port != 0)
|
||||
pre_allocate_sfds();
|
||||
|
||||
@@ -359,7 +403,7 @@ int main (int argc, char **argv)
|
||||
|
||||
if (baduser)
|
||||
die(_("unknown user or group: %s"), baduser, EC_BADCONF);
|
||||
|
||||
|
||||
/* implement group defaults, "dip" if available, or group associated with uid */
|
||||
if (!daemon->group_set && !gp)
|
||||
{
|
||||
@@ -434,7 +478,7 @@ int main (int argc, char **argv)
|
||||
char *msg;
|
||||
|
||||
/* close our copy of write-end */
|
||||
close(err_pipe[1]);
|
||||
while (retry_send(close(err_pipe[1])));
|
||||
|
||||
/* check for errors after the fork */
|
||||
if (read_event(err_pipe[0], &ev, &msg))
|
||||
@@ -443,7 +487,7 @@ int main (int argc, char **argv)
|
||||
_exit(EC_GOOD);
|
||||
}
|
||||
|
||||
close(err_pipe[0]);
|
||||
while (retry_send(close(err_pipe[0])));
|
||||
|
||||
/* NO calls to die() from here on. */
|
||||
|
||||
@@ -495,10 +539,12 @@ int main (int argc, char **argv)
|
||||
{
|
||||
if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
|
||||
err = 1;
|
||||
|
||||
while (!err && close(fd) == -1)
|
||||
if (!retry_send())
|
||||
err = 1;
|
||||
else
|
||||
{
|
||||
while (retry_send(close(fd)));
|
||||
if (errno != 0)
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
@@ -515,17 +561,21 @@ int main (int argc, char **argv)
|
||||
{
|
||||
/* open stdout etc to /dev/null */
|
||||
int nullfd = open("/dev/null", O_RDWR);
|
||||
dup2(nullfd, STDOUT_FILENO);
|
||||
dup2(nullfd, STDERR_FILENO);
|
||||
dup2(nullfd, STDIN_FILENO);
|
||||
close(nullfd);
|
||||
if (nullfd != -1)
|
||||
{
|
||||
dup2(nullfd, STDOUT_FILENO);
|
||||
dup2(nullfd, STDERR_FILENO);
|
||||
dup2(nullfd, STDIN_FILENO);
|
||||
close(nullfd);
|
||||
}
|
||||
}
|
||||
|
||||
/* if we are to run scripts, we need to fork a helper before dropping root. */
|
||||
daemon->helperfd = -1;
|
||||
#ifdef HAVE_SCRIPT
|
||||
if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
|
||||
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
|
||||
if ((daemon->dhcp || daemon->dhcp6 || option_bool(OPT_TFTP) || option_bool(OPT_SCRIPT_ARP)) &&
|
||||
(daemon->lease_change_command || daemon->luascript))
|
||||
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
|
||||
#endif
|
||||
|
||||
if (!option_bool(OPT_DEBUG) && getuid() == 0)
|
||||
@@ -617,12 +667,14 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
free(hdr);
|
||||
free(data);
|
||||
if (option_bool(OPT_DEBUG))
|
||||
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if (option_bool(OPT_TFTP))
|
||||
if (option_bool(OPT_TFTP))
|
||||
{
|
||||
DIR *dir;
|
||||
struct tftp_prefix *p;
|
||||
@@ -631,20 +683,31 @@ int main (int argc, char **argv)
|
||||
{
|
||||
if (!((dir = opendir(daemon->tftp_prefix))))
|
||||
{
|
||||
send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
|
||||
_exit(0);
|
||||
tftp_prefix_missing = 1;
|
||||
if (!option_bool(OPT_TFTP_NO_FAIL))
|
||||
{
|
||||
send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
else
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
for (p = daemon->if_prefix; p; p = p->next)
|
||||
{
|
||||
p->missing = 0;
|
||||
if (!((dir = opendir(p->prefix))))
|
||||
{
|
||||
send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
|
||||
_exit(0);
|
||||
}
|
||||
closedir(dir);
|
||||
{
|
||||
p->missing = 1;
|
||||
if (!option_bool(OPT_TFTP_NO_FAIL))
|
||||
{
|
||||
send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
closedir(dir);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -674,9 +737,24 @@ int main (int argc, char **argv)
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Delay creating the timestamp file until here, after we've changed user, so that
|
||||
it has the correct owner to allow updating the mtime later.
|
||||
This means we have to report fatal errors via the pipe. */
|
||||
if ((rc = setup_timestamp()) == -1)
|
||||
{
|
||||
send_event(err_pipe[1], EVENT_TIME_ERR, errno, daemon->timestamp_file);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
|
||||
|
||||
if (option_bool(OPT_DNSSEC_TIME))
|
||||
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
|
||||
|
||||
if (rc == 1)
|
||||
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until system time valid"));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -742,18 +820,22 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if (option_bool(OPT_TFTP))
|
||||
if (option_bool(OPT_TFTP))
|
||||
{
|
||||
#ifdef FD_SETSIZE
|
||||
if (FD_SETSIZE < (unsigned)max_fd)
|
||||
max_fd = FD_SETSIZE;
|
||||
#endif
|
||||
struct tftp_prefix *p;
|
||||
|
||||
my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
|
||||
daemon->tftp_prefix ? _("root is ") : _("enabled"),
|
||||
daemon->tftp_prefix ? daemon->tftp_prefix: "",
|
||||
option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
|
||||
|
||||
|
||||
if (tftp_prefix_missing)
|
||||
my_syslog(MS_TFTP | LOG_WARNING, _("warning: %s inaccessible"), daemon->tftp_prefix);
|
||||
|
||||
for (p = daemon->if_prefix; p; p = p->next)
|
||||
if (p->missing)
|
||||
my_syslog(MS_TFTP | LOG_WARNING, _("warning: TFTP directory %s inaccessible"), p->prefix);
|
||||
|
||||
/* This is a guess, it assumes that for small limits,
|
||||
disjoint files might be served, but for large limits,
|
||||
a single file will be sent to may clients (the file only needs
|
||||
@@ -786,127 +868,114 @@ int main (int argc, char **argv)
|
||||
|
||||
/* finished start-up - release original process */
|
||||
if (err_pipe[1] != -1)
|
||||
close(err_pipe[1]);
|
||||
while (retry_send(close(err_pipe[1])));
|
||||
|
||||
if (daemon->port != 0)
|
||||
check_servers();
|
||||
|
||||
pid = getpid();
|
||||
|
||||
#ifdef HAVE_INOTIFY
|
||||
/* Using inotify, have to select a resolv file at startup */
|
||||
poll_resolv(1, 0, now);
|
||||
#endif
|
||||
|
||||
while (1)
|
||||
{
|
||||
int maxfd = -1;
|
||||
struct timeval t, *tp = NULL;
|
||||
fd_set rset, wset, eset;
|
||||
int t, timeout = -1;
|
||||
|
||||
FD_ZERO(&rset);
|
||||
FD_ZERO(&wset);
|
||||
FD_ZERO(&eset);
|
||||
poll_reset();
|
||||
|
||||
/* if we are out of resources, find how long we have to wait
|
||||
for some to come free, we'll loop around then and restart
|
||||
listening for queries */
|
||||
if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
|
||||
{
|
||||
t.tv_usec = 0;
|
||||
tp = &t;
|
||||
}
|
||||
if ((t = set_dns_listeners(now)) != 0)
|
||||
timeout = t * 1000;
|
||||
|
||||
/* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
|
||||
if (daemon->tftp_trans ||
|
||||
(option_bool(OPT_DBUS) && !daemon->dbus))
|
||||
{
|
||||
t.tv_sec = 0;
|
||||
t.tv_usec = 250000;
|
||||
tp = &t;
|
||||
}
|
||||
timeout = 250;
|
||||
|
||||
/* Wake every second whilst waiting for DAD to complete */
|
||||
else if (is_dad_listeners())
|
||||
{
|
||||
t.tv_sec = 1;
|
||||
t.tv_usec = 0;
|
||||
tp = &t;
|
||||
}
|
||||
timeout = 1000;
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
set_dbus_listeners(&maxfd, &rset, &wset, &eset);
|
||||
set_dbus_listeners();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->relay4)
|
||||
{
|
||||
FD_SET(daemon->dhcpfd, &rset);
|
||||
bump_maxfd(daemon->dhcpfd, &maxfd);
|
||||
poll_listen(daemon->dhcpfd, POLLIN);
|
||||
if (daemon->pxefd != -1)
|
||||
{
|
||||
FD_SET(daemon->pxefd, &rset);
|
||||
bump_maxfd(daemon->pxefd, &maxfd);
|
||||
}
|
||||
poll_listen(daemon->pxefd, POLLIN);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->doing_dhcp6 || daemon->relay6)
|
||||
{
|
||||
FD_SET(daemon->dhcp6fd, &rset);
|
||||
bump_maxfd(daemon->dhcp6fd, &maxfd);
|
||||
}
|
||||
|
||||
poll_listen(daemon->dhcp6fd, POLLIN);
|
||||
|
||||
if (daemon->doing_ra)
|
||||
{
|
||||
FD_SET(daemon->icmp6fd, &rset);
|
||||
bump_maxfd(daemon->icmp6fd, &maxfd);
|
||||
}
|
||||
poll_listen(daemon->icmp6fd, POLLIN);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_INOTIFY
|
||||
if (daemon->inotifyfd != -1)
|
||||
poll_listen(daemon->inotifyfd, POLLIN);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
FD_SET(daemon->netlinkfd, &rset);
|
||||
bump_maxfd(daemon->netlinkfd, &maxfd);
|
||||
poll_listen(daemon->netlinkfd, POLLIN);
|
||||
#elif defined(HAVE_BSD_NETWORK)
|
||||
FD_SET(daemon->routefd, &rset);
|
||||
bump_maxfd(daemon->routefd, &maxfd);
|
||||
poll_listen(daemon->routefd, POLLIN);
|
||||
#endif
|
||||
|
||||
poll_listen(piperead, POLLIN);
|
||||
|
||||
FD_SET(piperead, &rset);
|
||||
bump_maxfd(piperead, &maxfd);
|
||||
#ifdef HAVE_SCRIPT
|
||||
# ifdef HAVE_DHCP
|
||||
while (helper_buf_empty() && do_script_run(now));
|
||||
# endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
# ifdef HAVE_SCRIPT
|
||||
while (helper_buf_empty() && do_script_run(now));
|
||||
/* Refresh cache */
|
||||
if (option_bool(OPT_SCRIPT_ARP))
|
||||
find_mac(NULL, NULL, 0, now);
|
||||
while (helper_buf_empty() && do_arp_script_run());
|
||||
|
||||
# ifdef HAVE_TFTP
|
||||
while (helper_buf_empty() && do_tftp_script_run());
|
||||
# endif
|
||||
|
||||
if (!helper_buf_empty())
|
||||
{
|
||||
FD_SET(daemon->helperfd, &wset);
|
||||
bump_maxfd(daemon->helperfd, &maxfd);
|
||||
}
|
||||
# else
|
||||
poll_listen(daemon->helperfd, POLLOUT);
|
||||
#else
|
||||
/* need this for other side-effects */
|
||||
# ifdef HAVE_DHCP
|
||||
while (do_script_run(now));
|
||||
# endif
|
||||
|
||||
while (do_arp_script_run());
|
||||
|
||||
# ifdef HAVE_TFTP
|
||||
while (do_tftp_script_run());
|
||||
# endif
|
||||
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/* must do this just before select(), when we know no
|
||||
more calls to my_syslog() can occur */
|
||||
set_log_writer(&wset, &maxfd);
|
||||
set_log_writer();
|
||||
|
||||
if (do_poll(timeout) < 0)
|
||||
continue;
|
||||
|
||||
if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
|
||||
{
|
||||
/* otherwise undefined after error */
|
||||
FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
|
||||
}
|
||||
|
||||
now = dnsmasq_time();
|
||||
|
||||
check_log_writer(&wset);
|
||||
check_log_writer(0);
|
||||
|
||||
/* prime. */
|
||||
enumerate_interfaces(1);
|
||||
@@ -922,13 +991,20 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
if (FD_ISSET(daemon->netlinkfd, &rset))
|
||||
if (poll_check(daemon->netlinkfd, POLLIN))
|
||||
netlink_multicast();
|
||||
#elif defined(HAVE_BSD_NETWORK)
|
||||
if (FD_ISSET(daemon->routefd, &rset))
|
||||
if (poll_check(daemon->routefd, POLLIN))
|
||||
route_sock();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_INOTIFY
|
||||
if (daemon->inotifyfd != -1 && poll_check(daemon->inotifyfd, POLLIN) && inotify_check(now))
|
||||
{
|
||||
if (daemon->port != 0 && !option_bool(OPT_NO_POLL))
|
||||
poll_resolv(1, 1, now);
|
||||
}
|
||||
#else
|
||||
/* Check for changes to resolv files once per second max. */
|
||||
/* Don't go silent for long periods if the clock goes backwards. */
|
||||
if (daemon->last_resolv == 0 ||
|
||||
@@ -941,8 +1017,9 @@ int main (int argc, char **argv)
|
||||
poll_resolv(0, daemon->last_resolv != 0, now);
|
||||
daemon->last_resolv = now;
|
||||
}
|
||||
|
||||
if (FD_ISSET(piperead, &rset))
|
||||
#endif
|
||||
|
||||
if (poll_check(piperead, POLLIN))
|
||||
async_event(piperead, now);
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
@@ -955,34 +1032,34 @@ int main (int argc, char **argv)
|
||||
if (daemon->dbus)
|
||||
my_syslog(LOG_INFO, _("connected to system DBus"));
|
||||
}
|
||||
check_dbus_listeners(&rset, &wset, &eset);
|
||||
check_dbus_listeners();
|
||||
#endif
|
||||
|
||||
check_dns_listeners(&rset, now);
|
||||
check_dns_listeners(now);
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
check_tftp_listeners(&rset, now);
|
||||
check_tftp_listeners(now);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->relay4)
|
||||
{
|
||||
if (FD_ISSET(daemon->dhcpfd, &rset))
|
||||
if (poll_check(daemon->dhcpfd, POLLIN))
|
||||
dhcp_packet(now, 0);
|
||||
if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
|
||||
if (daemon->pxefd != -1 && poll_check(daemon->pxefd, POLLIN))
|
||||
dhcp_packet(now, 1);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if ((daemon->doing_dhcp6 || daemon->relay6) && FD_ISSET(daemon->dhcp6fd, &rset))
|
||||
if ((daemon->doing_dhcp6 || daemon->relay6) && poll_check(daemon->dhcp6fd, POLLIN))
|
||||
dhcp6_packet(now);
|
||||
|
||||
if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
|
||||
if (daemon->doing_ra && poll_check(daemon->icmp6fd, POLLIN))
|
||||
icmp6_packet(now);
|
||||
#endif
|
||||
|
||||
# ifdef HAVE_SCRIPT
|
||||
if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
|
||||
if (daemon->helperfd != -1 && poll_check(daemon->helperfd, POLLOUT))
|
||||
helper_write();
|
||||
# endif
|
||||
#endif
|
||||
@@ -1128,6 +1205,9 @@ static void fatal_event(struct event_desc *ev, char *msg)
|
||||
|
||||
case EVENT_TFTP_ERR:
|
||||
die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
|
||||
|
||||
case EVENT_TIME_ERR:
|
||||
die(_("cannot create timestamp file %s: %s" ), msg, EC_BADCONF);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1258,7 +1338,7 @@ static void async_event(int pipe, time_t now)
|
||||
if (daemon->tcp_pids[i] != 0)
|
||||
kill(daemon->tcp_pids[i], SIGALRM);
|
||||
|
||||
#if defined(HAVE_SCRIPT)
|
||||
#if defined(HAVE_SCRIPT) && defined(HAVE_DHCP)
|
||||
/* handle pending lease transitions */
|
||||
if (daemon->helperfd != -1)
|
||||
{
|
||||
@@ -1268,13 +1348,22 @@ static void async_event(int pipe, time_t now)
|
||||
do {
|
||||
helper_write();
|
||||
} while (!helper_buf_empty() || do_script_run(now));
|
||||
close(daemon->helperfd);
|
||||
while (retry_send(close(daemon->helperfd)));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (daemon->lease_stream)
|
||||
fclose(daemon->lease_stream);
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* update timestamp file on TERM if time is considered valid */
|
||||
if (daemon->back_to_the_future)
|
||||
{
|
||||
if (utime(daemon->timestamp_file, NULL) == -1)
|
||||
my_syslog(LOG_ERR, _("failed to update mtime on %s: %s"), daemon->timestamp_file, strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (daemon->runfile)
|
||||
unlink(daemon->runfile);
|
||||
|
||||
@@ -1367,6 +1456,9 @@ void clear_cache_and_reload(time_t now)
|
||||
if (option_bool(OPT_ETHERS))
|
||||
dhcp_read_ethers();
|
||||
reread_dhcp();
|
||||
#ifdef HAVE_INOTIFY
|
||||
set_dynamic_inotify(AH_DHCP_HST | AH_DHCP_OPT, 0, NULL, 0);
|
||||
#endif
|
||||
dhcp_update_configs(daemon->dhcp_conf);
|
||||
lease_update_from_configs();
|
||||
lease_update_file(now);
|
||||
@@ -1381,7 +1473,7 @@ void clear_cache_and_reload(time_t now)
|
||||
#endif
|
||||
}
|
||||
|
||||
static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
|
||||
static int set_dns_listeners(time_t now)
|
||||
{
|
||||
struct serverfd *serverfdp;
|
||||
struct listener *listener;
|
||||
@@ -1393,8 +1485,7 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
|
||||
for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
|
||||
{
|
||||
tftp++;
|
||||
FD_SET(transfer->sockfd, set);
|
||||
bump_maxfd(transfer->sockfd, maxfdp);
|
||||
poll_listen(transfer->sockfd, POLLIN);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1403,45 +1494,32 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
|
||||
get_new_frec(now, &wait, 0);
|
||||
|
||||
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
{
|
||||
FD_SET(serverfdp->fd, set);
|
||||
bump_maxfd(serverfdp->fd, maxfdp);
|
||||
}
|
||||
|
||||
poll_listen(serverfdp->fd, POLLIN);
|
||||
|
||||
if (daemon->port != 0 && !daemon->osport)
|
||||
for (i = 0; i < RANDOM_SOCKS; i++)
|
||||
if (daemon->randomsocks[i].refcount != 0)
|
||||
{
|
||||
FD_SET(daemon->randomsocks[i].fd, set);
|
||||
bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
|
||||
}
|
||||
|
||||
poll_listen(daemon->randomsocks[i].fd, POLLIN);
|
||||
|
||||
for (listener = daemon->listeners; listener; listener = listener->next)
|
||||
{
|
||||
/* only listen for queries if we have resources */
|
||||
if (listener->fd != -1 && wait == 0)
|
||||
{
|
||||
FD_SET(listener->fd, set);
|
||||
bump_maxfd(listener->fd, maxfdp);
|
||||
}
|
||||
|
||||
poll_listen(listener->fd, POLLIN);
|
||||
|
||||
/* death of a child goes through the select loop, so
|
||||
we don't need to explicitly arrange to wake up here */
|
||||
if (listener->tcpfd != -1)
|
||||
for (i = 0; i < MAX_PROCS; i++)
|
||||
if (daemon->tcp_pids[i] == 0)
|
||||
{
|
||||
FD_SET(listener->tcpfd, set);
|
||||
bump_maxfd(listener->tcpfd, maxfdp);
|
||||
poll_listen(listener->tcpfd, POLLIN);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
|
||||
{
|
||||
FD_SET(listener->tftpfd, set);
|
||||
bump_maxfd(listener->tftpfd, maxfdp);
|
||||
}
|
||||
poll_listen(listener->tftpfd, POLLIN);
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -1449,33 +1527,33 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
|
||||
return wait;
|
||||
}
|
||||
|
||||
static void check_dns_listeners(fd_set *set, time_t now)
|
||||
static void check_dns_listeners(time_t now)
|
||||
{
|
||||
struct serverfd *serverfdp;
|
||||
struct listener *listener;
|
||||
int i;
|
||||
|
||||
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
if (FD_ISSET(serverfdp->fd, set))
|
||||
if (poll_check(serverfdp->fd, POLLIN))
|
||||
reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
|
||||
|
||||
if (daemon->port != 0 && !daemon->osport)
|
||||
for (i = 0; i < RANDOM_SOCKS; i++)
|
||||
if (daemon->randomsocks[i].refcount != 0 &&
|
||||
FD_ISSET(daemon->randomsocks[i].fd, set))
|
||||
poll_check(daemon->randomsocks[i].fd, POLLIN))
|
||||
reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
|
||||
|
||||
for (listener = daemon->listeners; listener; listener = listener->next)
|
||||
{
|
||||
if (listener->fd != -1 && FD_ISSET(listener->fd, set))
|
||||
if (listener->fd != -1 && poll_check(listener->fd, POLLIN))
|
||||
receive_query(listener, now);
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
|
||||
if (listener->tftpfd != -1 && poll_check(listener->tftpfd, POLLIN))
|
||||
tftp_request(listener, now);
|
||||
#endif
|
||||
|
||||
if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
|
||||
if (listener->tcpfd != -1 && poll_check(listener->tcpfd, POLLIN))
|
||||
{
|
||||
int confd, client_ok = 1;
|
||||
struct irec *iface = NULL;
|
||||
@@ -1490,7 +1568,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
|
||||
if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
|
||||
{
|
||||
close(confd);
|
||||
while (retry_send(close(confd)));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1555,7 +1633,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
if (!client_ok)
|
||||
{
|
||||
shutdown(confd, SHUT_RDWR);
|
||||
close(confd);
|
||||
while (retry_send(close(confd)));
|
||||
}
|
||||
#ifndef NO_FORK
|
||||
else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
|
||||
@@ -1570,7 +1648,10 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
break;
|
||||
}
|
||||
}
|
||||
close(confd);
|
||||
while (retry_send(close(confd)));
|
||||
|
||||
/* The child can use up to TCP_MAX_QUERIES ids, so skip that many. */
|
||||
daemon->log_id += TCP_MAX_QUERIES;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
@@ -1612,7 +1693,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
|
||||
|
||||
shutdown(confd, SHUT_RDWR);
|
||||
close(confd);
|
||||
while (retry_send(close(confd)));
|
||||
|
||||
if (buff)
|
||||
free(buff);
|
||||
@@ -1621,7 +1702,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
if (s->tcpfd != -1)
|
||||
{
|
||||
shutdown(s->tcpfd, SHUT_RDWR);
|
||||
close(s->tcpfd);
|
||||
while (retry_send(close(s->tcpfd)));
|
||||
}
|
||||
#ifndef NO_FORK
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
@@ -1663,14 +1744,22 @@ int icmp_ping(struct in_addr addr)
|
||||
better not use any resources our caller has in use...)
|
||||
but we remain deaf to signals or further DHCP packets. */
|
||||
|
||||
int fd;
|
||||
/* There can be a problem using dnsmasq_time() to end the loop, since
|
||||
it's not monotonic, and can go backwards if the system clock is
|
||||
tweaked, leading to the code getting stuck in this loop and
|
||||
ignoring DHCP requests. To fix this, we check to see if select returned
|
||||
as a result of a timeout rather than a socket becoming available. We
|
||||
only allow this to happen as many times as it takes to get to the wait time
|
||||
in quarter-second chunks. This provides a fallback way to end loop. */
|
||||
|
||||
int fd, rc;
|
||||
struct sockaddr_in saddr;
|
||||
struct {
|
||||
struct ip ip;
|
||||
struct icmp icmp;
|
||||
} packet;
|
||||
unsigned short id = rand16();
|
||||
unsigned int i, j;
|
||||
unsigned int i, j, timeout_count;
|
||||
int gotreply = 0;
|
||||
time_t start, now;
|
||||
|
||||
@@ -1699,57 +1788,47 @@ int icmp_ping(struct in_addr addr)
|
||||
j = (j & 0xffff) + (j >> 16);
|
||||
packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
|
||||
|
||||
while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
|
||||
(struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
|
||||
retry_send());
|
||||
while (retry_send(sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
|
||||
(struct sockaddr *)&saddr, sizeof(saddr))));
|
||||
|
||||
for (now = start = dnsmasq_time();
|
||||
difftime(now, start) < (float)PING_WAIT;)
|
||||
for (now = start = dnsmasq_time(), timeout_count = 0;
|
||||
(difftime(now, start) < (float)PING_WAIT) && (timeout_count < PING_WAIT * 4);)
|
||||
{
|
||||
struct timeval tv;
|
||||
fd_set rset, wset;
|
||||
struct sockaddr_in faddr;
|
||||
int maxfd = fd;
|
||||
socklen_t len = sizeof(faddr);
|
||||
|
||||
tv.tv_usec = 250000;
|
||||
tv.tv_sec = 0;
|
||||
|
||||
FD_ZERO(&rset);
|
||||
FD_ZERO(&wset);
|
||||
FD_SET(fd, &rset);
|
||||
set_dns_listeners(now, &rset, &maxfd);
|
||||
set_log_writer(&wset, &maxfd);
|
||||
poll_reset();
|
||||
poll_listen(fd, POLLIN);
|
||||
set_dns_listeners(now);
|
||||
set_log_writer();
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->doing_ra)
|
||||
{
|
||||
FD_SET(daemon->icmp6fd, &rset);
|
||||
bump_maxfd(daemon->icmp6fd, &maxfd);
|
||||
}
|
||||
poll_listen(daemon->icmp6fd, POLLIN);
|
||||
#endif
|
||||
|
||||
if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
|
||||
{
|
||||
FD_ZERO(&rset);
|
||||
FD_ZERO(&wset);
|
||||
}
|
||||
rc = do_poll(250);
|
||||
|
||||
if (rc < 0)
|
||||
continue;
|
||||
else if (rc == 0)
|
||||
timeout_count++;
|
||||
|
||||
now = dnsmasq_time();
|
||||
|
||||
check_log_writer(&wset);
|
||||
check_dns_listeners(&rset, now);
|
||||
check_log_writer(0);
|
||||
check_dns_listeners(now);
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
|
||||
if (daemon->doing_ra && poll_check(daemon->icmp6fd, POLLIN))
|
||||
icmp6_packet(now);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
check_tftp_listeners(&rset, now);
|
||||
check_tftp_listeners(now);
|
||||
#endif
|
||||
|
||||
if (FD_ISSET(fd, &rset) &&
|
||||
if (poll_check(fd, POLLIN) &&
|
||||
recvfrom(fd, &packet, sizeof(packet), 0,
|
||||
(struct sockaddr *)&faddr, &len) == sizeof(packet) &&
|
||||
saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
|
||||
@@ -1763,7 +1842,7 @@ int icmp_ping(struct in_addr addr)
|
||||
}
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
|
||||
close(fd);
|
||||
while (retry_send(close(fd)));
|
||||
#else
|
||||
opt = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
|
||||
|
||||
185
src/dnsmasq.h
185
src/dnsmasq.h
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -14,7 +14,7 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define COPYRIGHT "Copyright (c) 2000-2014 Simon Kelley"
|
||||
#define COPYRIGHT "Copyright (c) 2000-2016 Simon Kelley"
|
||||
|
||||
#ifndef NO_LARGEFILE
|
||||
/* Ensure we can use files >2GB (log files may grow this big) */
|
||||
@@ -82,7 +82,7 @@ typedef unsigned long long u64;
|
||||
#if defined(HAVE_SOLARIS_NETWORK)
|
||||
# include <sys/sockio.h>
|
||||
#endif
|
||||
#include <sys/select.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/un.h>
|
||||
@@ -117,6 +117,7 @@ typedef unsigned long long u64;
|
||||
#include <sys/uio.h>
|
||||
#include <syslog.h>
|
||||
#include <dirent.h>
|
||||
#include <utime.h>
|
||||
#ifndef HAVE_LINUX_NETWORK
|
||||
# include <net/if_dl.h>
|
||||
#endif
|
||||
@@ -167,6 +168,7 @@ struct event_desc {
|
||||
#define EVENT_INIT 21
|
||||
#define EVENT_NEWADDR 22
|
||||
#define EVENT_NEWROUTE 23
|
||||
#define EVENT_TIME_ERR 24
|
||||
|
||||
/* Exit codes. */
|
||||
#define EC_GOOD 0
|
||||
@@ -177,13 +179,6 @@ struct event_desc {
|
||||
#define EC_MISC 5
|
||||
#define EC_INIT_OFFSET 10
|
||||
|
||||
/* Min buffer size: we check after adding each record, so there must be
|
||||
memory for the largest packet, and the largest record so the
|
||||
min for DNS is PACKETSZ+MAXDNAME+RRFIXEDSZ which is < 1000.
|
||||
This might be increased is EDNS packet size if greater than the minimum.
|
||||
*/
|
||||
#define DNSMASQ_PACKETSZ PACKETSZ+MAXDNAME+RRFIXEDSZ
|
||||
|
||||
/* Trust the compiler dead-code eliminator.... */
|
||||
#define option_bool(x) (((x) < 32) ? daemon->options & (1u << (x)) : daemon->options2 & (1u << ((x) - 32)))
|
||||
|
||||
@@ -238,7 +233,12 @@ struct event_desc {
|
||||
#define OPT_DNSSEC_NO_SIGN 48
|
||||
#define OPT_LOCAL_SERVICE 49
|
||||
#define OPT_LOOP_DETECT 50
|
||||
#define OPT_LAST 51
|
||||
#define OPT_EXTRALOG 51
|
||||
#define OPT_TFTP_NO_FAIL 52
|
||||
#define OPT_SCRIPT_ARP 53
|
||||
#define OPT_MAC_B64 54
|
||||
#define OPT_MAC_HEX 55
|
||||
#define OPT_LAST 56
|
||||
|
||||
/* 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. */
|
||||
@@ -252,8 +252,10 @@ struct all_addr {
|
||||
struct in6_addr addr6;
|
||||
#endif
|
||||
/* for log_query */
|
||||
unsigned int keytag;
|
||||
/* for cache_insert if RRSIG, DNSKEY, DS */
|
||||
struct {
|
||||
unsigned short keytag, algo, digest;
|
||||
} log;
|
||||
/* for cache_insert of DNSKEY, DS */
|
||||
struct {
|
||||
unsigned short class, type;
|
||||
} dnssec;
|
||||
@@ -306,6 +308,7 @@ struct ptr_record {
|
||||
};
|
||||
|
||||
struct cname {
|
||||
int ttl;
|
||||
char *alias, *target;
|
||||
struct cname *next;
|
||||
};
|
||||
@@ -318,6 +321,7 @@ struct ds_config {
|
||||
|
||||
#define ADDRLIST_LITERAL 1
|
||||
#define ADDRLIST_IPV6 2
|
||||
#define ADDRLIST_REVONLY 4
|
||||
|
||||
struct addrlist {
|
||||
struct all_addr addr;
|
||||
@@ -341,6 +345,7 @@ struct auth_zone {
|
||||
|
||||
|
||||
struct host_record {
|
||||
int ttl;
|
||||
struct name_list {
|
||||
char *name;
|
||||
struct name_list *next;
|
||||
@@ -393,14 +398,9 @@ struct crec {
|
||||
unsigned char algo;
|
||||
unsigned char digest;
|
||||
} ds;
|
||||
struct {
|
||||
struct blockdata *keydata;
|
||||
unsigned short keylen, type_covered, keytag;
|
||||
char algo;
|
||||
} sig;
|
||||
} addr;
|
||||
time_t ttd; /* time to die */
|
||||
/* used as class if DNSKEY/DS/RRSIG, index to source for F_HOSTS */
|
||||
/* used as class if DNSKEY/DS, index to source for F_HOSTS */
|
||||
unsigned int uid;
|
||||
unsigned short flags;
|
||||
union {
|
||||
@@ -440,7 +440,7 @@ struct crec {
|
||||
#define F_SECSTAT (1u<<24)
|
||||
#define F_NO_RR (1u<<25)
|
||||
#define F_IPSET (1u<<26)
|
||||
#define F_NSIGMATCH (1u<<27)
|
||||
#define F_NOEXTRA (1u<<27)
|
||||
|
||||
/* Values of uid in crecs with F_CONFIG bit set. */
|
||||
#define SRC_INTERFACE 0
|
||||
@@ -481,6 +481,7 @@ union mysockaddr {
|
||||
#define SERV_NO_REBIND 2048 /* inhibit dns-rebind protection */
|
||||
#define SERV_FROM_FILE 4096 /* read from --servers-file */
|
||||
#define SERV_LOOP 8192 /* server causes forwarding loop */
|
||||
#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */
|
||||
|
||||
struct serverfd {
|
||||
int fd;
|
||||
@@ -499,7 +500,7 @@ struct server {
|
||||
char interface[IF_NAMESIZE+1];
|
||||
struct serverfd *sfd;
|
||||
char *domain; /* set if this server only handles a domain. */
|
||||
int flags, tcpfd;
|
||||
int flags, tcpfd, edns_pktsz;
|
||||
unsigned int queries, failed_queries;
|
||||
#ifdef HAVE_LOOP
|
||||
u32 uid;
|
||||
@@ -535,21 +536,39 @@ struct iname {
|
||||
struct iname *next;
|
||||
};
|
||||
|
||||
/* subnet parameters from command line */
|
||||
struct mysubnet {
|
||||
union mysockaddr addr;
|
||||
int addr_used;
|
||||
int mask;
|
||||
};
|
||||
|
||||
/* resolv-file parms from command-line */
|
||||
struct resolvc {
|
||||
struct resolvc *next;
|
||||
int is_default, logged;
|
||||
time_t mtime;
|
||||
char *name;
|
||||
#ifdef HAVE_INOTIFY
|
||||
int wd; /* inotify watch descriptor */
|
||||
char *file; /* pointer to file part if path */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* adn-hosts parms from command-line (also dhcp-hostsfile and dhcp-optsfile */
|
||||
/* adn-hosts parms from command-line (also dhcp-hostsfile and dhcp-optsfile and dhcp-hostsdir*/
|
||||
#define AH_DIR 1
|
||||
#define AH_INACTIVE 2
|
||||
#define AH_WD_DONE 4
|
||||
#define AH_HOSTS 8
|
||||
#define AH_DHCP_HST 16
|
||||
#define AH_DHCP_OPT 32
|
||||
struct hostsfile {
|
||||
struct hostsfile *next;
|
||||
int flags;
|
||||
char *fname;
|
||||
#ifdef HAVE_INOTIFY
|
||||
int wd; /* inotify watch descriptor */
|
||||
#endif
|
||||
unsigned int index; /* matches to cache entries for logging */
|
||||
};
|
||||
|
||||
@@ -562,10 +581,8 @@ struct hostsfile {
|
||||
#define STAT_NEED_KEY 5
|
||||
#define STAT_TRUNCATED 6
|
||||
#define STAT_SECURE_WILDCARD 7
|
||||
#define STAT_NO_SIG 8
|
||||
#define STAT_NO_DS 9
|
||||
#define STAT_NEED_DS_NEG 10
|
||||
#define STAT_CHASE_CNAME 11
|
||||
#define STAT_OK 8
|
||||
#define STAT_ABANDONED 9
|
||||
|
||||
#define FREC_NOREBIND 1
|
||||
#define FREC_CHECKING_DISABLED 2
|
||||
@@ -575,7 +592,8 @@ struct hostsfile {
|
||||
#define FREC_AD_QUESTION 32
|
||||
#define FREC_DO_QUESTION 64
|
||||
#define FREC_ADDED_PHEADER 128
|
||||
#define FREC_CHECK_NOSIGN 256
|
||||
#define FREC_TEST_PKTSZ 256
|
||||
#define FREC_HAS_EXTRADATA 512
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
#define HASH_SIZE 20 /* SHA-1 digest size */
|
||||
@@ -593,7 +611,7 @@ struct frec {
|
||||
#endif
|
||||
unsigned int iface;
|
||||
unsigned short orig_id, new_id;
|
||||
int fd, forwardall, flags;
|
||||
int log_id, fd, forwardall, flags;
|
||||
time_t time;
|
||||
unsigned char *hash[HASH_SIZE];
|
||||
#ifdef HAVE_DNSSEC
|
||||
@@ -621,6 +639,8 @@ struct frec {
|
||||
#define ACTION_OLD 3
|
||||
#define ACTION_ADD 4
|
||||
#define ACTION_TFTP 5
|
||||
#define ACTION_ARP 6
|
||||
#define ACTION_ARP_DEL 7
|
||||
|
||||
#define LEASE_NEW 1 /* newly created */
|
||||
#define LEASE_CHANGED 2 /* modified */
|
||||
@@ -847,6 +867,7 @@ struct dhcp_context {
|
||||
#define CONTEXT_USED (1u<<15)
|
||||
#define CONTEXT_OLD (1u<<16)
|
||||
#define CONTEXT_V6 (1u<<17)
|
||||
#define CONTEXT_RA_OFF_LINK (1u<<18)
|
||||
|
||||
struct ping_result {
|
||||
struct in_addr addr;
|
||||
@@ -883,6 +904,7 @@ struct addr_list {
|
||||
struct tftp_prefix {
|
||||
char *interface;
|
||||
char *prefix;
|
||||
int missing;
|
||||
struct tftp_prefix *next;
|
||||
};
|
||||
|
||||
@@ -911,9 +933,9 @@ extern struct daemon {
|
||||
struct auth_zone *auth_zones;
|
||||
struct interface_name *int_names;
|
||||
char *mxtarget;
|
||||
int addr4_netmask;
|
||||
int addr6_netmask;
|
||||
char *lease_file;
|
||||
struct mysubnet *add_subnet4;
|
||||
struct mysubnet *add_subnet6;
|
||||
char *lease_file;
|
||||
char *username, *groupname, *scriptuser;
|
||||
char *luascript;
|
||||
char *authserver, *hostmaster;
|
||||
@@ -925,15 +947,16 @@ extern struct daemon {
|
||||
char *runfile;
|
||||
char *lease_change_command;
|
||||
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
|
||||
struct bogus_addr *bogus_addr;
|
||||
struct bogus_addr *bogus_addr, *ignore_addr;
|
||||
struct server *servers;
|
||||
struct ipsets *ipsets;
|
||||
int log_fac; /* log facility */
|
||||
char *log_file; /* optional log file */
|
||||
int max_logs; /* queue limit */
|
||||
int cachesize, ftabsize;
|
||||
int port, query_port, min_port;
|
||||
unsigned long local_ttl, neg_ttl, max_ttl, max_cache_ttl, auth_ttl;
|
||||
int port, query_port, min_port, max_port;
|
||||
unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, max_cache_ttl, auth_ttl, dhcp_ttl, use_dhcp_ttl;
|
||||
char *dns_client_id;
|
||||
struct hostsfile *addn_hosts;
|
||||
struct dhcp_context *dhcp, *dhcp6;
|
||||
struct ra_interface *ra_interfaces;
|
||||
@@ -951,8 +974,8 @@ extern struct daemon {
|
||||
int doing_ra, doing_dhcp6;
|
||||
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names;
|
||||
struct dhcp_netid_list *force_broadcast, *bootp_dynamic;
|
||||
struct hostsfile *dhcp_hosts_file, *dhcp_opts_file;
|
||||
int dhcp_max, tftp_max;
|
||||
struct hostsfile *dhcp_hosts_file, *dhcp_opts_file, *dynamic_dirs;
|
||||
int dhcp_max, tftp_max, tftp_mtu;
|
||||
int dhcp_server_port, dhcp_client_port;
|
||||
int start_tftp_port, end_tftp_port;
|
||||
unsigned int min_leasetime;
|
||||
@@ -969,6 +992,8 @@ extern struct daemon {
|
||||
#endif
|
||||
#ifdef HAVE_DNSSEC
|
||||
struct ds_config *ds;
|
||||
int back_to_the_future;
|
||||
char *timestamp_file;
|
||||
#endif
|
||||
|
||||
/* globally used stuff for DNS */
|
||||
@@ -994,9 +1019,14 @@ extern struct daemon {
|
||||
struct randfd randomsocks[RANDOM_SOCKS];
|
||||
int v6pktinfo;
|
||||
struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */
|
||||
int log_id, log_display_id; /* ids of transactions for logging */
|
||||
union mysockaddr *log_source_addr;
|
||||
|
||||
/* DHCP state */
|
||||
int dhcpfd, helperfd, pxefd;
|
||||
#ifdef HAVE_INOTIFY
|
||||
int inotifyfd;
|
||||
#endif
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
int netlinkfd;
|
||||
#elif defined(HAVE_BSD_NETWORK)
|
||||
@@ -1025,6 +1055,7 @@ extern struct daemon {
|
||||
|
||||
/* utility string buffer, hold max sized IP address as string */
|
||||
char *addrbuff;
|
||||
char *addrbuff2; /* only allocated when OPT_EXTRALOG */
|
||||
|
||||
} *daemon;
|
||||
|
||||
@@ -1051,6 +1082,8 @@ int cache_make_stat(struct txt_record *t);
|
||||
char *cache_get_name(struct crec *crecp);
|
||||
char *cache_get_cname_target(struct crec *crecp);
|
||||
struct crec *cache_enumerate(int init);
|
||||
int read_hostsfile(char *filename, unsigned int index, int cache_size,
|
||||
struct crec **rhash, int hashsz);
|
||||
|
||||
/* blockdata.c */
|
||||
#ifdef HAVE_DNSSEC
|
||||
@@ -1085,21 +1118,14 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff,
|
||||
int no_cache, int secure, int *doctored);
|
||||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask,
|
||||
time_t now, int *ad_reqd, int *do_bit);
|
||||
time_t now, int ad_reqd, int do_bit, int have_pseudoheader);
|
||||
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||
struct bogus_addr *addr, time_t now);
|
||||
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
|
||||
size_t *len, unsigned char **p, int *is_sign);
|
||||
int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
|
||||
int check_for_local_domain(char *name, time_t now);
|
||||
unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
|
||||
size_t resize_packet(struct dns_header *header, size_t plen,
|
||||
unsigned char *pheader, size_t hlen);
|
||||
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
|
||||
size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source);
|
||||
#ifdef HAVE_DNSSEC
|
||||
size_t add_do_bit(struct dns_header *header, size_t plen, char *limit);
|
||||
#endif
|
||||
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
|
||||
int add_resource_record(struct dns_header *header, char *limit, int *truncp,
|
||||
int nameoffset, unsigned char **pp, unsigned long ttl,
|
||||
int *offset, unsigned short type, unsigned short class, char *format, ...);
|
||||
@@ -1112,19 +1138,21 @@ int private_net(struct in_addr addr, int ban_localhost);
|
||||
/* auth.c */
|
||||
#ifdef HAVE_AUTH
|
||||
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen,
|
||||
time_t now, union mysockaddr *peer_addr, int local_query);
|
||||
time_t now, union mysockaddr *peer_addr, int local_query,
|
||||
int do_bit, int have_pseudoheader);
|
||||
int in_zone(struct auth_zone *zone, char *name, char **cut);
|
||||
#endif
|
||||
|
||||
/* dnssec.c */
|
||||
size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, int type, union mysockaddr *addr);
|
||||
size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class, int type, union mysockaddr *addr, int edns_pktsz);
|
||||
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t n, char *name, char *keyname, int class);
|
||||
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
|
||||
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class, int *neganswer);
|
||||
int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname);
|
||||
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class,
|
||||
int check_unsigned, int *neganswer, int *nons);
|
||||
int dnskey_keytag(int alg, int flags, unsigned char *rdata, int rdlen);
|
||||
size_t filter_rrsigs(struct dns_header *header, size_t plen);
|
||||
unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
|
||||
int setup_timestamp(void);
|
||||
|
||||
/* util.c */
|
||||
void rand_init(void);
|
||||
@@ -1148,7 +1176,7 @@ 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(ssize_t rc);
|
||||
void prettyprint_time(char *buf, unsigned int t);
|
||||
int prettyprint_addr(union mysockaddr *addr, char *buf);
|
||||
int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||
@@ -1157,7 +1185,6 @@ int memcmp_masked(unsigned char *a, unsigned char *b, int len,
|
||||
unsigned int mask);
|
||||
int expand_buf(struct iovec *iov, size_t size);
|
||||
char *print_mac(char *buff, unsigned char *mac, int len);
|
||||
void bump_maxfd(int fd, int *max);
|
||||
int read_write(int fd, unsigned char *packet, int size, int rw);
|
||||
|
||||
int wildcard_match(const char* wildcard, const char* match);
|
||||
@@ -1168,8 +1195,8 @@ void die(char *message, char *arg1, int exit_code);
|
||||
int log_start(struct passwd *ent_pw, int errfd);
|
||||
int log_reopen(char *log_file);
|
||||
void my_syslog(int priority, const char *format, ...);
|
||||
void set_log_writer(fd_set *set, int *maxfdp);
|
||||
void check_log_writer(fd_set *set);
|
||||
void set_log_writer(void);
|
||||
void check_log_writer(int force);
|
||||
void flush_log(void);
|
||||
|
||||
/* option.c */
|
||||
@@ -1183,6 +1210,7 @@ void reset_option_bool(unsigned int opt);
|
||||
struct hostsfile *expand_filelist(struct hostsfile *list);
|
||||
char *parse_server(char *arg, union mysockaddr *addr,
|
||||
union mysockaddr *source_addr, char *interface, int *flags);
|
||||
int option_read_dynfile(char *file, int flags);
|
||||
|
||||
/* forward.c */
|
||||
void reply_query(int fd, int family, time_t now);
|
||||
@@ -1271,9 +1299,10 @@ void lease_update_slaac(time_t now);
|
||||
void lease_set_iaid(struct dhcp_lease *lease, int iaid);
|
||||
void lease_make_duid(time_t now);
|
||||
#endif
|
||||
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||
unsigned char *clid, int hw_len, int hw_type, int clid_len, time_t now, int force);
|
||||
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain);
|
||||
void lease_set_hwaddr(struct dhcp_lease *lease, const unsigned char *hwaddr,
|
||||
const unsigned char *clid, int hw_len, int hw_type,
|
||||
int clid_len, time_t now, int force);
|
||||
void lease_set_hostname(struct dhcp_lease *lease, const char *name, int auth, char *domain, char *config_domain);
|
||||
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now);
|
||||
void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now);
|
||||
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
|
||||
@@ -1330,8 +1359,8 @@ int iface_enumerate(int family, void *parm, int (callback)());
|
||||
/* dbus.c */
|
||||
#ifdef HAVE_DBUS
|
||||
char *dbus_init(void);
|
||||
void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset);
|
||||
void set_dbus_listeners(int *maxfdp, fd_set *rset, fd_set *wset, fd_set *eset);
|
||||
void check_dbus_listeners(void);
|
||||
void set_dbus_listeners(void);
|
||||
# ifdef HAVE_DHCP
|
||||
void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
|
||||
# endif
|
||||
@@ -1352,13 +1381,15 @@ void queue_script(int action, struct dhcp_lease *lease,
|
||||
#ifdef HAVE_TFTP
|
||||
void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer);
|
||||
#endif
|
||||
void queue_arp(int action, unsigned char *mac, int maclen,
|
||||
int family, struct all_addr *addr);
|
||||
int helper_buf_empty(void);
|
||||
#endif
|
||||
|
||||
/* tftp.c */
|
||||
#ifdef HAVE_TFTP
|
||||
void tftp_request(struct listener *listen, time_t now);
|
||||
void check_tftp_listeners(fd_set *rset, time_t now);
|
||||
void check_tftp_listeners(time_t now);
|
||||
int do_tftp_script_run(void);
|
||||
#endif
|
||||
|
||||
@@ -1388,7 +1419,7 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
|
||||
void make_duid(time_t now);
|
||||
void dhcp_construct_contexts(time_t now);
|
||||
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac,
|
||||
unsigned int *maclenp, unsigned int *mactypep);
|
||||
unsigned int *maclenp, unsigned int *mactypep, time_t now);
|
||||
#endif
|
||||
|
||||
/* rfc3315.c */
|
||||
@@ -1396,7 +1427,8 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac,
|
||||
unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
|
||||
struct in6_addr *fallback, struct in6_addr *ll_addr, struct in6_addr *ula_addr,
|
||||
size_t sz, struct in6_addr *client_addr, time_t now);
|
||||
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id);
|
||||
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address,
|
||||
u32 scope_id, time_t now);
|
||||
|
||||
unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
|
||||
#endif
|
||||
@@ -1469,3 +1501,34 @@ void loop_send_probes();
|
||||
int detect_loop(char *query, int type);
|
||||
#endif
|
||||
|
||||
/* inotify.c */
|
||||
#ifdef HAVE_INOTIFY
|
||||
void inotify_dnsmasq_init();
|
||||
int inotify_check(time_t now);
|
||||
void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz);
|
||||
#endif
|
||||
|
||||
/* poll.c */
|
||||
void poll_reset(void);
|
||||
int poll_check(int fd, short event);
|
||||
void poll_listen(int fd, short event);
|
||||
int do_poll(int timeout);
|
||||
|
||||
/* rrfilter.c */
|
||||
size_t rrfilter(struct dns_header *header, size_t plen, int mode);
|
||||
u16 *rrfilter_desc(int type);
|
||||
int expand_workspace(unsigned char ***wkspc, int *szp, int new);
|
||||
|
||||
/* edns0.c */
|
||||
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
|
||||
size_t *len, unsigned char **p, int *is_sign, int *is_last);
|
||||
size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do, int replace);
|
||||
size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit);
|
||||
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
union mysockaddr *source, time_t now, int *check_subnet);
|
||||
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
|
||||
|
||||
/* arp.c */
|
||||
int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now);
|
||||
int do_arp_script_run(void);
|
||||
|
||||
1862
src/dnssec.c
1862
src/dnssec.c
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
429
src/edns0.c
Normal file
429
src/edns0.c
Normal file
@@ -0,0 +1,429 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t *len, unsigned char **p, int *is_sign, int *is_last)
|
||||
{
|
||||
/* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
|
||||
also return length of pseudoheader in *len and pointer to the UDP size in *p
|
||||
Finally, check to see if a packet is signed. If it is we cannot change a single bit before
|
||||
forwarding. We look for TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
|
||||
|
||||
int i, arcount = ntohs(header->arcount);
|
||||
unsigned char *ansp = (unsigned char *)(header+1);
|
||||
unsigned short rdlen, type, class;
|
||||
unsigned char *ret = NULL;
|
||||
|
||||
if (is_sign)
|
||||
{
|
||||
*is_sign = 0;
|
||||
|
||||
if (OPCODE(header) == QUERY)
|
||||
{
|
||||
for (i = ntohs(header->qdcount); i != 0; i--)
|
||||
{
|
||||
if (!(ansp = skip_name(ansp, header, plen, 4)))
|
||||
return NULL;
|
||||
|
||||
GETSHORT(type, ansp);
|
||||
GETSHORT(class, ansp);
|
||||
|
||||
if (class == C_IN && type == T_TKEY)
|
||||
*is_sign = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(ansp = skip_questions(header, plen)))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (arcount == 0)
|
||||
return NULL;
|
||||
|
||||
if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < arcount; i++)
|
||||
{
|
||||
unsigned char *save, *start = ansp;
|
||||
if (!(ansp = skip_name(ansp, header, plen, 10)))
|
||||
return NULL;
|
||||
|
||||
GETSHORT(type, ansp);
|
||||
save = ansp;
|
||||
GETSHORT(class, ansp);
|
||||
ansp += 4; /* TTL */
|
||||
GETSHORT(rdlen, ansp);
|
||||
if (!ADD_RDLEN(header, ansp, plen, rdlen))
|
||||
return NULL;
|
||||
if (type == T_OPT)
|
||||
{
|
||||
if (len)
|
||||
*len = ansp - start;
|
||||
|
||||
if (p)
|
||||
*p = save;
|
||||
|
||||
if (is_last)
|
||||
*is_last = (i == arcount-1);
|
||||
|
||||
ret = start;
|
||||
}
|
||||
else if (is_sign &&
|
||||
i == arcount - 1 &&
|
||||
class == C_ANY &&
|
||||
type == T_TSIG)
|
||||
*is_sign = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* replace == 2 ->delete existing option only. */
|
||||
size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do, int replace)
|
||||
{
|
||||
unsigned char *lenp, *datap, *p, *udp_len, *buff = NULL;
|
||||
int rdlen = 0, is_sign, is_last;
|
||||
unsigned short flags = set_do ? 0x8000 : 0, rcode = 0;
|
||||
|
||||
p = find_pseudoheader(header, plen, NULL, &udp_len, &is_sign, &is_last);
|
||||
|
||||
if (is_sign)
|
||||
return plen;
|
||||
|
||||
if (p)
|
||||
{
|
||||
/* Existing header */
|
||||
int i;
|
||||
unsigned short code, len;
|
||||
|
||||
p = udp_len;
|
||||
GETSHORT(udp_sz, p);
|
||||
GETSHORT(rcode, p);
|
||||
GETSHORT(flags, p);
|
||||
|
||||
if (set_do)
|
||||
{
|
||||
p -= 2;
|
||||
flags |= 0x8000;
|
||||
PUTSHORT(flags, p);
|
||||
}
|
||||
|
||||
lenp = p;
|
||||
GETSHORT(rdlen, p);
|
||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
return plen; /* bad packet */
|
||||
datap = p;
|
||||
|
||||
/* no option to add */
|
||||
if (optno == 0)
|
||||
return plen;
|
||||
|
||||
/* check if option already there */
|
||||
for (i = 0; i + 4 < rdlen;)
|
||||
{
|
||||
GETSHORT(code, p);
|
||||
GETSHORT(len, p);
|
||||
|
||||
/* malformed option, delete the whole OPT RR and start again. */
|
||||
if (i + len > rdlen)
|
||||
{
|
||||
rdlen = 0;
|
||||
is_last = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (code == optno)
|
||||
{
|
||||
if (replace == 0)
|
||||
return plen;
|
||||
|
||||
/* delete option if we're to replace it. */
|
||||
p -= 4;
|
||||
rdlen -= len + 4;
|
||||
memcpy(p, p+len+4, rdlen - i);
|
||||
PUTSHORT(rdlen, lenp);
|
||||
lenp -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
p += len;
|
||||
i += len + 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're going to extend the RR, it has to be the last RR in the packet */
|
||||
if (!is_last)
|
||||
{
|
||||
/* First, take a copy of the options. */
|
||||
if (rdlen != 0 && (buff = whine_malloc(rdlen)))
|
||||
memcpy(buff, datap, rdlen);
|
||||
|
||||
/* now, delete OPT RR */
|
||||
plen = rrfilter(header, plen, 0);
|
||||
|
||||
/* Now, force addition of a new one */
|
||||
p = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!p)
|
||||
{
|
||||
/* We are (re)adding the pseudoheader */
|
||||
if (!(p = skip_questions(header, plen)) ||
|
||||
!(p = skip_section(p,
|
||||
ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
|
||||
header, plen)))
|
||||
return plen;
|
||||
*p++ = 0; /* empty name */
|
||||
PUTSHORT(T_OPT, p);
|
||||
PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
|
||||
PUTSHORT(rcode, p); /* extended RCODE and version */
|
||||
PUTSHORT(flags, p); /* DO flag */
|
||||
lenp = p;
|
||||
PUTSHORT(rdlen, p); /* RDLEN */
|
||||
datap = p;
|
||||
/* Copy back any options */
|
||||
if (buff)
|
||||
{
|
||||
memcpy(p, buff, rdlen);
|
||||
free(buff);
|
||||
p += rdlen;
|
||||
}
|
||||
header->arcount = htons(ntohs(header->arcount) + 1);
|
||||
}
|
||||
|
||||
if (((ssize_t)optlen) > (limit - (p + 4)))
|
||||
return plen; /* Too big */
|
||||
|
||||
/* Add new option */
|
||||
if (optno != 0 && replace != 2)
|
||||
{
|
||||
PUTSHORT(optno, p);
|
||||
PUTSHORT(optlen, p);
|
||||
memcpy(p, opt, optlen);
|
||||
p += optlen;
|
||||
PUTSHORT(p - datap, lenp);
|
||||
}
|
||||
return p - (unsigned char *)header;
|
||||
}
|
||||
|
||||
size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit)
|
||||
{
|
||||
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1, 0);
|
||||
}
|
||||
|
||||
static unsigned char char64(unsigned char c)
|
||||
{
|
||||
return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[c & 0x3f];
|
||||
}
|
||||
|
||||
static void encoder(unsigned char *in, char *out)
|
||||
{
|
||||
out[0] = char64(in[0]>>2);
|
||||
out[1] = char64((in[0]<<4) | (in[1]>>4));
|
||||
out[2] = char64((in[1]<<2) | (in[2]>>6));
|
||||
out[3] = char64(in[2]);
|
||||
}
|
||||
|
||||
static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
|
||||
{
|
||||
int maclen, replace = 2; /* can't get mac address, just delete any incoming. */
|
||||
unsigned char mac[DHCP_CHADDR_MAX];
|
||||
char encode[18]; /* handle 6 byte MACs */
|
||||
|
||||
if ((maclen = find_mac(l3, mac, 1, now)) == 6)
|
||||
{
|
||||
replace = 1;
|
||||
|
||||
if (option_bool(OPT_MAC_HEX))
|
||||
print_mac(encode, mac, maclen);
|
||||
else
|
||||
{
|
||||
encoder(mac, encode);
|
||||
encoder(mac+3, encode+4);
|
||||
encode[8] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, strlen(encode), 0, replace);
|
||||
}
|
||||
|
||||
|
||||
static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
|
||||
{
|
||||
int maclen;
|
||||
unsigned char mac[DHCP_CHADDR_MAX];
|
||||
|
||||
if ((maclen = find_mac(l3, mac, 1, now)) != 0)
|
||||
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0);
|
||||
|
||||
return plen;
|
||||
}
|
||||
|
||||
struct subnet_opt {
|
||||
u16 family;
|
||||
u8 source_netmask, scope_netmask;
|
||||
#ifdef HAVE_IPV6
|
||||
u8 addr[IN6ADDRSZ];
|
||||
#else
|
||||
u8 addr[INADDRSZ];
|
||||
#endif
|
||||
};
|
||||
|
||||
static void *get_addrp(union mysockaddr *addr, const short family)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
if (family == AF_INET6)
|
||||
return &addr->in6.sin6_addr;
|
||||
#endif
|
||||
|
||||
return &addr->in.sin_addr;
|
||||
}
|
||||
|
||||
static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
{
|
||||
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
|
||||
|
||||
int len;
|
||||
void *addrp;
|
||||
int sa_family = source->sa.sa_family;
|
||||
|
||||
opt->source_netmask = 0;
|
||||
opt->scope_netmask = 0;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (source->sa.sa_family == AF_INET6 && daemon->add_subnet6)
|
||||
{
|
||||
opt->source_netmask = daemon->add_subnet6->mask;
|
||||
if (daemon->add_subnet6->addr_used)
|
||||
{
|
||||
sa_family = daemon->add_subnet6->addr.sa.sa_family;
|
||||
addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
|
||||
}
|
||||
else
|
||||
addrp = &source->in6.sin6_addr;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (source->sa.sa_family == AF_INET && daemon->add_subnet4)
|
||||
{
|
||||
opt->source_netmask = daemon->add_subnet4->mask;
|
||||
if (daemon->add_subnet4->addr_used)
|
||||
{
|
||||
sa_family = daemon->add_subnet4->addr.sa.sa_family;
|
||||
addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
|
||||
}
|
||||
else
|
||||
addrp = &source->in.sin_addr;
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
|
||||
#else
|
||||
opt->family = htons(1);
|
||||
#endif
|
||||
|
||||
len = 0;
|
||||
|
||||
if (opt->source_netmask != 0)
|
||||
{
|
||||
len = ((opt->source_netmask - 1) >> 3) + 1;
|
||||
memcpy(opt->addr, addrp, len);
|
||||
if (opt->source_netmask & 7)
|
||||
opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
|
||||
}
|
||||
|
||||
return len + 4;
|
||||
}
|
||||
|
||||
static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source)
|
||||
{
|
||||
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
|
||||
|
||||
int len;
|
||||
struct subnet_opt opt;
|
||||
|
||||
len = calc_subnet_opt(&opt, source);
|
||||
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, 0);
|
||||
}
|
||||
|
||||
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
|
||||
{
|
||||
/* Section 9.2, Check that subnet option in reply matches. */
|
||||
|
||||
int len, calc_len;
|
||||
struct subnet_opt opt;
|
||||
unsigned char *p;
|
||||
int code, i, rdlen;
|
||||
|
||||
calc_len = calc_subnet_opt(&opt, peer);
|
||||
|
||||
if (!(p = skip_name(pseudoheader, header, plen, 10)))
|
||||
return 1;
|
||||
|
||||
p += 8; /* skip UDP length and RCODE */
|
||||
|
||||
GETSHORT(rdlen, p);
|
||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
return 1; /* bad packet */
|
||||
|
||||
/* check if option there */
|
||||
for (i = 0; i + 4 < rdlen; i += len + 4)
|
||||
{
|
||||
GETSHORT(code, p);
|
||||
GETSHORT(len, p);
|
||||
if (code == EDNS0_OPTION_CLIENT_SUBNET)
|
||||
{
|
||||
/* make sure this doesn't mismatch. */
|
||||
opt.scope_netmask = p[3];
|
||||
if (len != calc_len || memcmp(p, &opt, len) != 0)
|
||||
return 0;
|
||||
}
|
||||
p += len;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
union mysockaddr *source, time_t now, int *check_subnet)
|
||||
{
|
||||
*check_subnet = 0;
|
||||
|
||||
if (option_bool(OPT_ADD_MAC))
|
||||
plen = add_mac(header, plen, limit, source, now);
|
||||
|
||||
if (option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX))
|
||||
plen = add_dns_client(header, plen, limit, source, now);
|
||||
|
||||
if (daemon->dns_client_id)
|
||||
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID,
|
||||
(unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1);
|
||||
|
||||
if (option_bool(OPT_CLIENT_SUBNET))
|
||||
{
|
||||
plen = add_source_addr(header, plen, limit, source);
|
||||
*check_subnet = 1;
|
||||
}
|
||||
|
||||
return plen;
|
||||
}
|
||||
1214
src/forward.c
1214
src/forward.c
File diff suppressed because it is too large
Load Diff
70
src/helper.c
70
src/helper.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -219,7 +219,18 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
action_str = "tftp";
|
||||
is6 = (data.flags != AF_INET);
|
||||
}
|
||||
else
|
||||
else if (data.action == ACTION_ARP)
|
||||
{
|
||||
action_str = "arp-add";
|
||||
is6 = (data.flags != AF_INET);
|
||||
}
|
||||
else if (data.action == ACTION_ARP_DEL)
|
||||
{
|
||||
action_str = "arp-del";
|
||||
is6 = (data.flags != AF_INET);
|
||||
data.action = ACTION_ARP;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
|
||||
@@ -289,7 +300,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
|
||||
if (!is6)
|
||||
inet_ntop(AF_INET, &data.addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
#ifdef HAVE_DHCP6
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
inet_ntop(AF_INET6, &data.addr6, daemon->addrbuff, ADDRSTRLEN);
|
||||
#endif
|
||||
@@ -321,6 +332,22 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
|
||||
}
|
||||
}
|
||||
else if (data.action == ACTION_ARP)
|
||||
{
|
||||
lua_getglobal(lua, "arp");
|
||||
if (lua_type(lua, -1) != LUA_TFUNCTION)
|
||||
lua_pop(lua, 1); /* arp function optional */
|
||||
else
|
||||
{
|
||||
lua_pushstring(lua, action_str); /* arg1 - action */
|
||||
lua_newtable(lua); /* arg2 - data table */
|
||||
lua_pushstring(lua, daemon->addrbuff);
|
||||
lua_setfield(lua, -2, "client_address");
|
||||
lua_pushstring(lua, daemon->dhcp_buff);
|
||||
lua_setfield(lua, -2, "mac_address");
|
||||
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_getglobal(lua, "lease"); /* function to call */
|
||||
@@ -478,7 +505,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (data.action != ACTION_TFTP)
|
||||
if (data.action != ACTION_TFTP && data.action != ACTION_ARP)
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
my_setenv("DNSMASQ_IAID", is6 ? daemon->dhcp_buff3 : NULL, &err);
|
||||
@@ -550,10 +577,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
my_setenv("DNSMASQ_OLD_HOSTNAME", data.action == ACTION_OLD_HOSTNAME ? hostname : NULL, &err);
|
||||
if (data.action == ACTION_OLD_HOSTNAME)
|
||||
hostname = NULL;
|
||||
}
|
||||
|
||||
my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
|
||||
|
||||
|
||||
my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
|
||||
}
|
||||
/* we need to have the event_fd around if exec fails */
|
||||
if ((i = fcntl(event_fd, F_GETFD)) != -1)
|
||||
fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
|
||||
@@ -563,8 +589,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
if (err == 0)
|
||||
{
|
||||
execl(daemon->lease_change_command,
|
||||
p ? p+1 : daemon->lease_change_command,
|
||||
action_str, is6 ? daemon->packet : daemon->dhcp_buff,
|
||||
p ? p+1 : daemon->lease_change_command, action_str,
|
||||
(is6 && data.action != ACTION_ARP) ? daemon->packet : daemon->dhcp_buff,
|
||||
daemon->addrbuff, hostname, (char*)NULL);
|
||||
err = errno;
|
||||
}
|
||||
@@ -760,6 +786,30 @@ void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
|
||||
}
|
||||
#endif
|
||||
|
||||
void queue_arp(int action, unsigned char *mac, int maclen, int family, struct all_addr *addr)
|
||||
{
|
||||
/* no script */
|
||||
if (daemon->helperfd == -1)
|
||||
return;
|
||||
|
||||
buff_alloc(sizeof(struct script_data));
|
||||
memset(buf, 0, sizeof(struct script_data));
|
||||
|
||||
buf->action = action;
|
||||
buf->hwaddr_len = maclen;
|
||||
buf->hwaddr_type = ARPHRD_ETHER;
|
||||
if ((buf->flags = family) == AF_INET)
|
||||
buf->addr = addr->addr.addr4;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
buf->addr6 = addr->addr.addr6;
|
||||
#endif
|
||||
|
||||
memcpy(buf->hwaddr, mac, maclen);
|
||||
|
||||
bytes_in_buf = sizeof(struct script_data);
|
||||
}
|
||||
|
||||
int helper_buf_empty(void)
|
||||
{
|
||||
return bytes_in_buf == 0;
|
||||
|
||||
296
src/inotify.c
Normal file
296
src/inotify.c
Normal file
@@ -0,0 +1,296 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
#ifdef HAVE_INOTIFY
|
||||
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/param.h> /* For MAXSYMLINKS */
|
||||
|
||||
/* the strategy is to set a inotify on the directories containing
|
||||
resolv files, for any files in the directory which are close-write
|
||||
or moved into the directory.
|
||||
|
||||
When either of those happen, we look to see if the file involved
|
||||
is actually a resolv-file, and if so, call poll-resolv with
|
||||
the "force" argument, to ensure it's read.
|
||||
|
||||
This adds one new error condition: the directories containing
|
||||
all specified resolv-files must exist at start-up, even if the actual
|
||||
files don't.
|
||||
*/
|
||||
|
||||
static char *inotify_buffer;
|
||||
#define INOTIFY_SZ (sizeof(struct inotify_event) + NAME_MAX + 1)
|
||||
|
||||
/* If path is a symbolic link, return the path it
|
||||
points to, made absolute if relative.
|
||||
If path doesn't exist or is not a symlink, return NULL.
|
||||
Return value is malloc'ed */
|
||||
static char *my_readlink(char *path)
|
||||
{
|
||||
ssize_t rc, size = 64;
|
||||
char *buf;
|
||||
|
||||
while (1)
|
||||
{
|
||||
buf = safe_malloc(size);
|
||||
rc = readlink(path, buf, (size_t)size);
|
||||
|
||||
if (rc == -1)
|
||||
{
|
||||
/* Not link or doesn't exist. */
|
||||
if (errno == EINVAL || errno == ENOENT)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
die(_("cannot access path %s: %s"), path, EC_MISC);
|
||||
}
|
||||
else if (rc < size-1)
|
||||
{
|
||||
char *d;
|
||||
|
||||
buf[rc] = 0;
|
||||
if (buf[0] != '/' && ((d = strrchr(path, '/'))))
|
||||
{
|
||||
/* Add path to relative link */
|
||||
char *new_buf = safe_malloc((d - path) + strlen(buf) + 2);
|
||||
*(d+1) = 0;
|
||||
strcpy(new_buf, path);
|
||||
strcat(new_buf, buf);
|
||||
free(buf);
|
||||
buf = new_buf;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Buffer too small, increase and retry */
|
||||
size += 64;
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void inotify_dnsmasq_init()
|
||||
{
|
||||
struct resolvc *res;
|
||||
inotify_buffer = safe_malloc(INOTIFY_SZ);
|
||||
daemon->inotifyfd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||
|
||||
if (daemon->inotifyfd == -1)
|
||||
die(_("failed to create inotify: %s"), NULL, EC_MISC);
|
||||
|
||||
if (option_bool(OPT_NO_RESOLV))
|
||||
return;
|
||||
|
||||
for (res = daemon->resolv_files; res; res = res->next)
|
||||
{
|
||||
char *d, *new_path, *path = safe_malloc(strlen(res->name) + 1);
|
||||
int links = MAXSYMLINKS;
|
||||
|
||||
strcpy(path, res->name);
|
||||
|
||||
/* Follow symlinks until we reach a non-symlink, or a non-existant file. */
|
||||
while ((new_path = my_readlink(path)))
|
||||
{
|
||||
if (links-- == 0)
|
||||
die(_("too many symlinks following %s"), res->name, EC_MISC);
|
||||
free(path);
|
||||
path = new_path;
|
||||
}
|
||||
|
||||
res->wd = -1;
|
||||
|
||||
if ((d = strrchr(path, '/')))
|
||||
{
|
||||
*d = 0; /* make path just directory */
|
||||
res->wd = inotify_add_watch(daemon->inotifyfd, path, IN_CLOSE_WRITE | IN_MOVED_TO);
|
||||
|
||||
res->file = d+1; /* pointer to filename */
|
||||
*d = '/';
|
||||
|
||||
if (res->wd == -1 && errno == ENOENT)
|
||||
die(_("directory %s for resolv-file is missing, cannot poll"), res->name, EC_MISC);
|
||||
}
|
||||
|
||||
if (res->wd == -1)
|
||||
die(_("failed to create inotify for %s: %s"), res->name, EC_MISC);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* initialisation for dynamic-dir. Set inotify watch for each directory, and read pre-existing files */
|
||||
void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz)
|
||||
{
|
||||
struct hostsfile *ah;
|
||||
|
||||
for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
|
||||
{
|
||||
DIR *dir_stream = NULL;
|
||||
struct dirent *ent;
|
||||
struct stat buf;
|
||||
|
||||
if (!(ah->flags & flag))
|
||||
continue;
|
||||
|
||||
if (stat(ah->fname, &buf) == -1 || !(S_ISDIR(buf.st_mode)))
|
||||
{
|
||||
my_syslog(LOG_ERR, _("bad dynamic directory %s: %s"),
|
||||
ah->fname, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(ah->flags & AH_WD_DONE))
|
||||
{
|
||||
ah->wd = inotify_add_watch(daemon->inotifyfd, ah->fname, IN_CLOSE_WRITE | IN_MOVED_TO);
|
||||
ah->flags |= AH_WD_DONE;
|
||||
}
|
||||
|
||||
/* Read contents of dir _after_ calling add_watch, in the hope of avoiding
|
||||
a race which misses files being added as we start */
|
||||
if (ah->wd == -1 || !(dir_stream = opendir(ah->fname)))
|
||||
{
|
||||
my_syslog(LOG_ERR, _("failed to create inotify for %s: %s"),
|
||||
ah->fname, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
while ((ent = readdir(dir_stream)))
|
||||
{
|
||||
size_t lendir = strlen(ah->fname);
|
||||
size_t lenfile = strlen(ent->d_name);
|
||||
char *path;
|
||||
|
||||
/* ignore emacs backups and dotfiles */
|
||||
if (lenfile == 0 ||
|
||||
ent->d_name[lenfile - 1] == '~' ||
|
||||
(ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
|
||||
ent->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
if ((path = whine_malloc(lendir + lenfile + 2)))
|
||||
{
|
||||
strcpy(path, ah->fname);
|
||||
strcat(path, "/");
|
||||
strcat(path, ent->d_name);
|
||||
|
||||
/* ignore non-regular files */
|
||||
if (stat(path, &buf) != -1 && S_ISREG(buf.st_mode))
|
||||
{
|
||||
if (ah->flags & AH_HOSTS)
|
||||
total_size = read_hostsfile(path, ah->index, total_size, rhash, revhashsz);
|
||||
#ifdef HAVE_DHCP
|
||||
else if (ah->flags & (AH_DHCP_HST | AH_DHCP_OPT))
|
||||
option_read_dynfile(path, ah->flags);
|
||||
#endif
|
||||
}
|
||||
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir_stream);
|
||||
}
|
||||
}
|
||||
|
||||
int inotify_check(time_t now)
|
||||
{
|
||||
int hit = 0;
|
||||
struct hostsfile *ah;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int rc;
|
||||
char *p;
|
||||
struct resolvc *res;
|
||||
struct inotify_event *in;
|
||||
|
||||
while ((rc = read(daemon->inotifyfd, inotify_buffer, INOTIFY_SZ)) == -1 && errno == EINTR);
|
||||
|
||||
if (rc <= 0)
|
||||
break;
|
||||
|
||||
for (p = inotify_buffer; rc - (p - inotify_buffer) >= (int)sizeof(struct inotify_event); p += sizeof(struct inotify_event) + in->len)
|
||||
{
|
||||
in = (struct inotify_event*)p;
|
||||
|
||||
for (res = daemon->resolv_files; res; res = res->next)
|
||||
if (res->wd == in->wd && in->len != 0 && strcmp(res->file, in->name) == 0)
|
||||
hit = 1;
|
||||
|
||||
/* ignore emacs backups and dotfiles */
|
||||
if (in->len == 0 ||
|
||||
in->name[in->len - 1] == '~' ||
|
||||
(in->name[0] == '#' && in->name[in->len - 1] == '#') ||
|
||||
in->name[0] == '.')
|
||||
continue;
|
||||
|
||||
for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
|
||||
if (ah->wd == in->wd)
|
||||
{
|
||||
size_t lendir = strlen(ah->fname);
|
||||
char *path;
|
||||
|
||||
if ((path = whine_malloc(lendir + in->len + 2)))
|
||||
{
|
||||
strcpy(path, ah->fname);
|
||||
strcat(path, "/");
|
||||
strcat(path, in->name);
|
||||
|
||||
my_syslog(LOG_INFO, _("inotify, new or changed file %s"), path);
|
||||
|
||||
if (ah->flags & AH_HOSTS)
|
||||
{
|
||||
read_hostsfile(path, ah->index, 0, NULL, 0);
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
{
|
||||
/* Propogate the consequences of loading a new dhcp-host */
|
||||
dhcp_update_configs(daemon->dhcp_conf);
|
||||
lease_update_from_configs();
|
||||
lease_update_file(now);
|
||||
lease_update_dns(1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_DHCP
|
||||
else if (ah->flags & AH_DHCP_HST)
|
||||
{
|
||||
if (option_read_dynfile(path, AH_DHCP_HST))
|
||||
{
|
||||
/* Propogate the consequences of loading a new dhcp-host */
|
||||
dhcp_update_configs(daemon->dhcp_conf);
|
||||
lease_update_from_configs();
|
||||
lease_update_file(now);
|
||||
lease_update_dns(1);
|
||||
}
|
||||
}
|
||||
else if (ah->flags & AH_DHCP_OPT)
|
||||
option_read_dynfile(path, AH_DHCP_OPT);
|
||||
#endif
|
||||
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
#endif /* INOTIFY */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -121,7 +121,6 @@ static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr,
|
||||
struct my_nlattr *nested[2];
|
||||
uint8_t proto;
|
||||
int addrsz = INADDRSZ;
|
||||
ssize_t rc;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (af == AF_INET6)
|
||||
@@ -162,9 +161,10 @@ static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr,
|
||||
nested[1]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[1];
|
||||
nested[0]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[0];
|
||||
|
||||
while ((rc = sendto(ipset_sock, buffer, nlh->nlmsg_len, 0,
|
||||
(struct sockaddr *)&snl, sizeof(snl))) == -1 && retry_send());
|
||||
return rc;
|
||||
while (retry_send(sendto(ipset_sock, buffer, nlh->nlmsg_len, 0,
|
||||
(struct sockaddr *)&snl, sizeof(snl))));
|
||||
|
||||
return errno == 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
30
src/lease.c
30
src/lease.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -813,9 +813,9 @@ void lease_set_iaid(struct dhcp_lease *lease, int iaid)
|
||||
}
|
||||
#endif
|
||||
|
||||
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||
unsigned char *clid, int hw_len, int hw_type, int clid_len,
|
||||
time_t now, int force)
|
||||
void lease_set_hwaddr(struct dhcp_lease *lease, const unsigned char *hwaddr,
|
||||
const unsigned char *clid, int hw_len, int hw_type,
|
||||
int clid_len, time_t now, int force)
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
int change = force;
|
||||
@@ -897,7 +897,7 @@ static void kill_name(struct dhcp_lease *lease)
|
||||
lease->hostname = lease->fqdn = NULL;
|
||||
}
|
||||
|
||||
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain)
|
||||
void lease_set_hostname(struct dhcp_lease *lease, const char *name, int auth, char *domain, char *config_domain)
|
||||
{
|
||||
struct dhcp_lease *lease_tmp;
|
||||
char *new_name = NULL, *new_fqdn = NULL;
|
||||
@@ -1110,18 +1110,22 @@ int do_script_run(time_t now)
|
||||
}
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
/* delim == -1 -> delim = 0, but embeded 0s, creating extra records, are OK. */
|
||||
void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* check for embeded NULLs */
|
||||
for (i = 0; i < len; i++)
|
||||
if (data[i] == 0)
|
||||
{
|
||||
len = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (delim == -1)
|
||||
delim = 0;
|
||||
else
|
||||
/* check for 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;
|
||||
|
||||
13
src/log.c
13
src/log.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -421,18 +421,15 @@ void my_syslog(int priority, const char *format, ...)
|
||||
}
|
||||
}
|
||||
|
||||
void set_log_writer(fd_set *set, int *maxfdp)
|
||||
void set_log_writer(void)
|
||||
{
|
||||
if (entries && log_fd != -1 && connection_good)
|
||||
{
|
||||
FD_SET(log_fd, set);
|
||||
bump_maxfd(log_fd, maxfdp);
|
||||
}
|
||||
poll_listen(log_fd, POLLOUT);
|
||||
}
|
||||
|
||||
void check_log_writer(fd_set *set)
|
||||
void check_log_writer(int force)
|
||||
{
|
||||
if (log_fd != -1 && (!set || FD_ISSET(log_fd, set)))
|
||||
if (log_fd != -1 && (force || poll_check(log_fd, POLLOUT)))
|
||||
log_write();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -45,8 +45,9 @@ void loop_send_probes()
|
||||
fd = rfd->fd;
|
||||
}
|
||||
|
||||
while (sendto(fd, daemon->packet, len, 0, &serv->addr.sa, sa_len(&serv->addr)) == -1 && retry_send());
|
||||
|
||||
while (retry_send(sendto(fd, daemon->packet, len, 0,
|
||||
&serv->addr.sa, sa_len(&serv->addr))));
|
||||
|
||||
free_rfd(rfd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -169,10 +169,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
req.g.rtgen_family = family;
|
||||
|
||||
/* Don't block in recvfrom if send fails */
|
||||
while((len = sendto(daemon->netlinkfd, (void *)&req, sizeof(req), 0,
|
||||
(struct sockaddr *)&addr, sizeof(addr))) == -1 && retry_send());
|
||||
|
||||
if (len == -1)
|
||||
while(retry_send(sendto(daemon->netlinkfd, (void *)&req, sizeof(req), 0,
|
||||
(struct sockaddr *)&addr, sizeof(addr))));
|
||||
|
||||
if (errno != 0)
|
||||
return 0;
|
||||
|
||||
while (1)
|
||||
@@ -288,7 +288,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
}
|
||||
|
||||
if (inaddr && mac && callback_ok)
|
||||
if (!(neigh->ndm_state & (NUD_NOARP | NUD_INCOMPLETE | NUD_FAILED)) &&
|
||||
inaddr && mac && callback_ok)
|
||||
if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
|
||||
callback_ok = 0;
|
||||
}
|
||||
|
||||
128
src/network.c
128
src/network.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -16,10 +16,6 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifndef IN6_IS_ADDR_ULA
|
||||
#define IN6_IS_ADDR_ULA(a) ((((__const uint32_t *) (a))[0] & htonl (0xfe00000)) == htonl (0xfc000000))
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
|
||||
int indextoname(int fd, int index, char *name)
|
||||
@@ -240,7 +236,7 @@ struct iface_param {
|
||||
};
|
||||
|
||||
static int iface_allowed(struct iface_param *param, int if_index, char *label,
|
||||
union mysockaddr *addr, struct in_addr netmask, int prefixlen, int dad)
|
||||
union mysockaddr *addr, struct in_addr netmask, int prefixlen, int iface_flags)
|
||||
{
|
||||
struct irec *iface;
|
||||
int mtu = 0, loopback;
|
||||
@@ -392,6 +388,10 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
|
||||
{
|
||||
al->addr.addr.addr6 = addr->in6.sin6_addr;
|
||||
al->flags = ADDRLIST_IPV6;
|
||||
/* Privacy addresses and addresses still undergoing DAD and deprecated addresses
|
||||
don't appear in forward queries, but will in reverse ones. */
|
||||
if (!(iface_flags & IFACE_PERMANENT) || (iface_flags & (IFACE_DEPRECATED | IFACE_TENTATIVE)))
|
||||
al->flags |= ADDRLIST_REVONLY;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -403,7 +403,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&iface->addr, addr))
|
||||
{
|
||||
iface->dad = dad;
|
||||
iface->dad = !!(iface_flags & IFACE_TENTATIVE);
|
||||
iface->found = 1; /* for garbage collection */
|
||||
return 1;
|
||||
}
|
||||
@@ -478,7 +478,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
|
||||
iface->dhcp_ok = dhcp_ok;
|
||||
iface->dns_auth = auth_dns;
|
||||
iface->mtu = mtu;
|
||||
iface->dad = dad;
|
||||
iface->dad = !!(iface_flags & IFACE_TENTATIVE);
|
||||
iface->found = 1;
|
||||
iface->done = iface->multicast_done = iface->warned = 0;
|
||||
iface->index = if_index;
|
||||
@@ -523,7 +523,7 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
|
||||
else
|
||||
addr.in6.sin6_scope_id = 0;
|
||||
|
||||
return iface_allowed((struct iface_param *)vparam, if_index, NULL, &addr, netmask, prefix, !!(flags & IFACE_TENTATIVE));
|
||||
return iface_allowed((struct iface_param *)vparam, if_index, NULL, &addr, netmask, prefix, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -532,13 +532,14 @@ static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
|
||||
{
|
||||
union mysockaddr addr;
|
||||
int prefix, bit;
|
||||
|
||||
(void)broadcast; /* warning */
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in.sin_len = sizeof(addr.in);
|
||||
#endif
|
||||
addr.in.sin_family = AF_INET;
|
||||
addr.in.sin_addr = broadcast; /* warning */
|
||||
addr.in.sin_addr = local;
|
||||
addr.in.sin_port = htons(daemon->port);
|
||||
|
||||
@@ -809,10 +810,11 @@ int tcp_interface(int fd, int af)
|
||||
int opt = 1;
|
||||
struct cmsghdr *cmptr;
|
||||
struct msghdr msg;
|
||||
socklen_t len;
|
||||
|
||||
/* use mshdr do that the CMSDG_* macros are available */
|
||||
/* use mshdr so that the CMSDG_* macros are available */
|
||||
msg.msg_control = daemon->packet;
|
||||
msg.msg_controllen = daemon->packet_buff_sz;
|
||||
msg.msg_controllen = len = daemon->packet_buff_sz;
|
||||
|
||||
/* we overwrote the buffer... */
|
||||
daemon->srv_save = NULL;
|
||||
@@ -820,18 +822,21 @@ int tcp_interface(int fd, int af)
|
||||
if (af == AF_INET)
|
||||
{
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) != -1 &&
|
||||
getsockopt(fd, IPPROTO_IP, IP_PKTOPTIONS, msg.msg_control, (socklen_t *)&msg.msg_controllen) != -1)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in_pktinfo *p;
|
||||
} p;
|
||||
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
if_index = p.p->ipi_ifindex;
|
||||
}
|
||||
getsockopt(fd, IPPROTO_IP, IP_PKTOPTIONS, msg.msg_control, &len) != -1)
|
||||
{
|
||||
msg.msg_controllen = len;
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in_pktinfo *p;
|
||||
} p;
|
||||
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
if_index = p.p->ipi_ifindex;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
@@ -849,9 +854,10 @@ int tcp_interface(int fd, int af)
|
||||
#endif
|
||||
|
||||
if (set_ipv6pktinfo(fd) &&
|
||||
getsockopt(fd, IPPROTO_IPV6, PKTOPTIONS, msg.msg_control, (socklen_t *)&msg.msg_controllen) != -1)
|
||||
getsockopt(fd, IPPROTO_IPV6, PKTOPTIONS, msg.msg_control, &len) != -1)
|
||||
{
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
msg.msg_controllen = len;
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||
{
|
||||
union {
|
||||
@@ -1076,23 +1082,30 @@ void join_multicast(int dienow)
|
||||
|
||||
if ((daemon->doing_dhcp6 || daemon->relay6) &&
|
||||
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||
err = 1;
|
||||
err = errno;
|
||||
|
||||
inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
|
||||
|
||||
if (daemon->doing_dhcp6 &&
|
||||
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||
err = 1;
|
||||
err = errno;
|
||||
|
||||
inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
|
||||
|
||||
if (daemon->doing_ra &&
|
||||
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||
err = 1;
|
||||
err = errno;
|
||||
|
||||
if (err)
|
||||
{
|
||||
char *s = _("interface %s failed to join DHCPv6 multicast group: %s");
|
||||
errno = err;
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
if (errno == ENOMEM)
|
||||
my_syslog(LOG_ERR, _("try increasing /proc/sys/net/core/optmem_max"));
|
||||
#endif
|
||||
|
||||
if (dienow)
|
||||
die(s, iface->name, EC_BADNET);
|
||||
else
|
||||
@@ -1112,7 +1125,7 @@ int random_sock(int family)
|
||||
if ((fd = socket(family, SOCK_DGRAM, 0)) != -1)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
unsigned int ports_avail = 65536u - (unsigned short)daemon->min_port;
|
||||
unsigned int ports_avail = ((unsigned short)daemon->max_port - (unsigned short)daemon->min_port) + 1;
|
||||
int tries = ports_avail < 30 ? 3 * ports_avail : 100;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
@@ -1125,8 +1138,8 @@ int random_sock(int family)
|
||||
{
|
||||
unsigned short port = rand16();
|
||||
|
||||
if (daemon->min_port != 0)
|
||||
port = htons(daemon->min_port + (port % ((unsigned short)ports_avail)));
|
||||
if (daemon->min_port != 0 || daemon->max_port != MAX_PORT)
|
||||
port = htons(daemon->min_port + (port % ((unsigned short)ports_avail)));
|
||||
|
||||
if (family == AF_INET)
|
||||
{
|
||||
@@ -1422,12 +1435,47 @@ void check_servers(void)
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
enumerate_interfaces(0);
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* Disable DNSSEC validation when using server=/domain/.... servers
|
||||
unless there's a configured trust anchor. */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
serv->flags |= SERV_DO_DNSSEC;
|
||||
#endif
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
{
|
||||
if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
|
||||
if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
|
||||
{
|
||||
port = prettyprint_addr(&serv->addr, daemon->namebuff);
|
||||
/* Init edns_pktsz for newly created server records. */
|
||||
if (serv->edns_pktsz == 0)
|
||||
serv->edns_pktsz = daemon->edns_pktsz;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
if (serv->flags & SERV_HAS_DOMAIN)
|
||||
{
|
||||
struct ds_config *ds;
|
||||
char *domain = serv->domain;
|
||||
|
||||
/* .example.com is valid */
|
||||
while (*domain == '.')
|
||||
domain++;
|
||||
|
||||
for (ds = daemon->ds; ds; ds = ds->next)
|
||||
if (ds->name[0] != 0 && hostname_isequal(domain, ds->name))
|
||||
break;
|
||||
|
||||
if (!ds)
|
||||
serv->flags &= ~SERV_DO_DNSSEC;
|
||||
}
|
||||
else if (serv->flags & SERV_FOR_NODOTS)
|
||||
serv->flags &= ~SERV_DO_DNSSEC;
|
||||
}
|
||||
#endif
|
||||
|
||||
port = prettyprint_addr(&serv->addr, daemon->namebuff);
|
||||
|
||||
/* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
|
||||
if (serv->addr.sa.sa_family == AF_INET &&
|
||||
serv->addr.in.sin_addr.s_addr == 0)
|
||||
@@ -1459,11 +1507,15 @@ void check_servers(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (!(serv->flags & SERV_NO_REBIND))
|
||||
if (!(serv->flags & SERV_NO_REBIND) && !(serv->flags & SERV_LITERAL_ADDRESS))
|
||||
{
|
||||
if (serv->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV))
|
||||
{
|
||||
char *s1, *s2;
|
||||
char *s1, *s2, *s3 = "";
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC))
|
||||
s3 = _("(no DNSSEC)");
|
||||
#endif
|
||||
if (!(serv->flags & SERV_HAS_DOMAIN))
|
||||
s1 = _("unqualified"), s2 = _("names");
|
||||
else if (strlen(serv->domain) == 0)
|
||||
@@ -1475,8 +1527,8 @@ void check_servers(void)
|
||||
my_syslog(LOG_INFO, _("using local addresses only for %s %s"), s1, s2);
|
||||
else if (serv->flags & SERV_USE_RESOLV)
|
||||
my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2);
|
||||
else if (!(serv->flags & SERV_LITERAL_ADDRESS))
|
||||
my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2);
|
||||
else
|
||||
my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s %s"), daemon->namebuff, port, s1, s2, s3);
|
||||
}
|
||||
#ifdef HAVE_LOOP
|
||||
else if (serv->flags & SERV_LOOP)
|
||||
|
||||
376
src/option.c
376
src/option.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -147,7 +147,19 @@ struct myoption {
|
||||
#define LOPT_LOCAL_SERVICE 335
|
||||
#define LOPT_DNSSEC_TIME 336
|
||||
#define LOPT_LOOP_DETECT 337
|
||||
|
||||
#define LOPT_IGNORE_ADDR 338
|
||||
#define LOPT_MINCTTL 339
|
||||
#define LOPT_DHCP_INOTIFY 340
|
||||
#define LOPT_DHOPT_INOTIFY 341
|
||||
#define LOPT_HOST_INOTIFY 342
|
||||
#define LOPT_DNSSEC_STAMP 343
|
||||
#define LOPT_TFTP_NO_FAIL 344
|
||||
#define LOPT_MAXPORT 345
|
||||
#define LOPT_CPE_ID 346
|
||||
#define LOPT_SCRIPT_ARP 347
|
||||
#define LOPT_DHCPTTL 348
|
||||
#define LOPT_TFTP_MTU 349
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
#else
|
||||
@@ -159,7 +171,7 @@ static const struct myoption opts[] =
|
||||
{ "no-poll", 0, 0, 'n' },
|
||||
{ "help", 0, 0, 'w' },
|
||||
{ "no-daemon", 0, 0, 'd' },
|
||||
{ "log-queries", 0, 0, 'q' },
|
||||
{ "log-queries", 2, 0, 'q' },
|
||||
{ "user", 2, 0, 'u' },
|
||||
{ "group", 2, 0, 'g' },
|
||||
{ "resolv-file", 2, 0, 'r' },
|
||||
@@ -181,6 +193,7 @@ static const struct myoption opts[] =
|
||||
{ "local-service", 0, 0, LOPT_LOCAL_SERVICE },
|
||||
{ "bogus-priv", 0, 0, 'b' },
|
||||
{ "bogus-nxdomain", 1, 0, 'B' },
|
||||
{ "ignore-address", 1, 0, LOPT_IGNORE_ADDR },
|
||||
{ "selfmx", 0, 0, 'e' },
|
||||
{ "filterwin2k", 0, 0, 'f' },
|
||||
{ "pid-file", 2, 0, 'x' },
|
||||
@@ -196,6 +209,7 @@ static const struct myoption opts[] =
|
||||
{ "local-ttl", 1, 0, 'T' },
|
||||
{ "no-negcache", 0, 0, 'N' },
|
||||
{ "addn-hosts", 1, 0, 'H' },
|
||||
{ "hostsdir", 1, 0, LOPT_HOST_INOTIFY },
|
||||
{ "query-port", 1, 0, 'Q' },
|
||||
{ "except-interface", 1, 0, 'I' },
|
||||
{ "no-dhcp-interface", 1, 0, '2' },
|
||||
@@ -227,9 +241,11 @@ static const struct myoption opts[] =
|
||||
{ "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
|
||||
{ "enable-tftp", 2, 0, LOPT_TFTP },
|
||||
{ "tftp-secure", 0, 0, LOPT_SECURE },
|
||||
{ "tftp-no-fail", 0, 0, LOPT_TFTP_NO_FAIL },
|
||||
{ "tftp-unique-root", 0, 0, LOPT_APREF },
|
||||
{ "tftp-root", 1, 0, LOPT_PREFIX },
|
||||
{ "tftp-max", 1, 0, LOPT_TFTP_MAX },
|
||||
{ "tftp-mtu", 1, 0, LOPT_TFTP_MTU },
|
||||
{ "tftp-lowercase", 0, 0, LOPT_TFTP_LC },
|
||||
{ "ptr-record", 1, 0, LOPT_PTR },
|
||||
{ "naptr-record", 1, 0, LOPT_NAPTR },
|
||||
@@ -244,6 +260,8 @@ static const struct myoption opts[] =
|
||||
{ "interface-name", 1, 0, LOPT_INTNAME },
|
||||
{ "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
|
||||
{ "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
|
||||
{ "dhcp-hostsdir", 1, 0, LOPT_DHCP_INOTIFY },
|
||||
{ "dhcp-optsdir", 1, 0, LOPT_DHOPT_INOTIFY },
|
||||
{ "dhcp-no-override", 0, 0, LOPT_OVERRIDE },
|
||||
{ "tftp-port-range", 1, 0, LOPT_TFTPPORTS },
|
||||
{ "stop-dns-rebind", 0, 0, LOPT_REBIND },
|
||||
@@ -253,10 +271,12 @@ static const struct myoption opts[] =
|
||||
{ "dhcp-broadcast", 2, 0, LOPT_BROADCAST },
|
||||
{ "neg-ttl", 1, 0, LOPT_NEGTTL },
|
||||
{ "max-ttl", 1, 0, LOPT_MAXTTL },
|
||||
{ "min-cache-ttl", 1, 0, LOPT_MINCTTL },
|
||||
{ "max-cache-ttl", 1, 0, LOPT_MAXCTTL },
|
||||
{ "dhcp-alternate-port", 2, 0, LOPT_ALTPORT },
|
||||
{ "dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },
|
||||
{ "min-port", 1, 0, LOPT_MINPORT },
|
||||
{ "max-port", 1, 0, LOPT_MAXPORT },
|
||||
{ "dhcp-fqdn", 0, 0, LOPT_DHCP_FQDN },
|
||||
{ "cname", 1, 0, LOPT_CNAME },
|
||||
{ "pxe-prompt", 1, 0, LOPT_PXE_PROMT },
|
||||
@@ -266,8 +286,9 @@ static const struct myoption opts[] =
|
||||
{ "dhcp-proxy", 2, 0, LOPT_PROXY },
|
||||
{ "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES },
|
||||
{ "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND },
|
||||
{ "add-mac", 0, 0, LOPT_ADD_MAC },
|
||||
{ "add-mac", 2, 0, LOPT_ADD_MAC },
|
||||
{ "add-subnet", 2, 0, LOPT_ADD_SBNET },
|
||||
{ "add-cpe-id", 1, 0 , LOPT_CPE_ID },
|
||||
{ "proxy-dnssec", 0, 0, LOPT_DNSSEC },
|
||||
{ "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR },
|
||||
{ "conntrack", 0, 0, LOPT_CONNTRACK },
|
||||
@@ -290,6 +311,7 @@ static const struct myoption opts[] =
|
||||
{ "dnssec-debug", 0, 0, LOPT_DNSSEC_DEBUG },
|
||||
{ "dnssec-check-unsigned", 0, 0, LOPT_DNSSEC_CHECK },
|
||||
{ "dnssec-no-timecheck", 0, 0, LOPT_DNSSEC_TIME },
|
||||
{ "dnssec-timestamp", 1, 0, LOPT_DNSSEC_STAMP },
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
{ "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
|
||||
#endif
|
||||
@@ -299,6 +321,8 @@ static const struct myoption opts[] =
|
||||
{ "quiet-dhcp6", 0, 0, LOPT_QUIET_DHCP6 },
|
||||
{ "quiet-ra", 0, 0, LOPT_QUIET_RA },
|
||||
{ "dns-loop-detect", 0, 0, LOPT_LOOP_DETECT },
|
||||
{ "script-arp", 0, 0, LOPT_SCRIPT_ARP },
|
||||
{ "dhcp-ttl", 1, 0 , LOPT_DHCPTTL },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -331,9 +355,12 @@ static struct {
|
||||
{ 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
|
||||
{ LOPT_DHCP_HOST, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from file."), NULL },
|
||||
{ LOPT_DHCP_OPTS, ARG_DUP, "<path>", gettext_noop("Read DHCP option specs from file."), NULL },
|
||||
{ LOPT_DHCP_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from a directory."), NULL },
|
||||
{ LOPT_DHOPT_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read DHCP options from a directory."), NULL },
|
||||
{ LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL },
|
||||
{ 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
|
||||
{ 'H', ARG_DUP, "<path>", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
|
||||
{ LOPT_HOST_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read hosts files from a directory."), NULL },
|
||||
{ 'i', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) to listen on."), NULL },
|
||||
{ 'I', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) NOT to listen on.") , NULL },
|
||||
{ 'j', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL },
|
||||
@@ -355,7 +382,7 @@ static struct {
|
||||
{ LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL},
|
||||
{ 'p', ARG_ONE, "<integer>", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
|
||||
{ 'P', ARG_ONE, "<integer>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
|
||||
{ 'q', OPT_LOG, NULL, gettext_noop("Log DNS queries."), NULL },
|
||||
{ 'q', ARG_DUP, NULL, gettext_noop("Log DNS queries."), NULL },
|
||||
{ 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
|
||||
{ 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },
|
||||
{ 'r', ARG_DUP, "<path>", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },
|
||||
@@ -368,6 +395,8 @@ static struct {
|
||||
{ 'T', ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
|
||||
{ LOPT_NEGTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
|
||||
{ LOPT_MAXTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for maximum TTL to send to clients."), NULL },
|
||||
{ LOPT_MAXCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live ceiling for cache."), NULL },
|
||||
{ LOPT_MINCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live floor for cache."), NULL },
|
||||
{ 'u', ARG_ONE, "<username>", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER },
|
||||
{ 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
|
||||
{ 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },
|
||||
@@ -391,6 +420,7 @@ static struct {
|
||||
{ '6', ARG_ONE, "<path>", gettext_noop("Shell script to run on DHCP lease creation and destruction."), NULL },
|
||||
{ LOPT_LUASCRIPT, ARG_DUP, "path", gettext_noop("Lua script to run on DHCP lease creation and destruction."), NULL },
|
||||
{ LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change scripts as this user."), NULL },
|
||||
{ LOPT_SCRIPT_ARP, OPT_SCRIPT_ARP, NULL, gettext_noop("Call dhcp-script with changes to local ARP table."), NULL },
|
||||
{ '7', ARG_DUP, "<path>", gettext_noop("Read configuration from all the files in this directory."), NULL },
|
||||
{ '8', ARG_ONE, "<facilty>|<file>", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL },
|
||||
{ '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL },
|
||||
@@ -402,7 +432,9 @@ static struct {
|
||||
{ LOPT_PREFIX, ARG_DUP, "<dir>[,<iface>]", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
|
||||
{ LOPT_APREF, OPT_TFTP_APREF, NULL, gettext_noop("Add client IP address to tftp-root."), NULL },
|
||||
{ LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
|
||||
{ LOPT_TFTP_NO_FAIL, OPT_TFTP_NO_FAIL, NULL, gettext_noop("Do not terminate the service if TFTP directories are inaccessible."), NULL },
|
||||
{ LOPT_TFTP_MAX, ARG_ONE, "<integer>", gettext_noop("Maximum number of conncurrent TFTP transfers (defaults to %s)."), "#" },
|
||||
{ LOPT_TFTP_MTU, ARG_ONE, "<integer>", gettext_noop("Maximum MTU to use for TFTP transfers."), NULL },
|
||||
{ LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },
|
||||
{ LOPT_TFTP_LC, OPT_TFTP_LC, NULL, gettext_noop("Convert TFTP filenames to lowercase"), NULL },
|
||||
{ LOPT_TFTPPORTS, ARG_ONE, "<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL },
|
||||
@@ -416,23 +448,25 @@ static struct {
|
||||
{ LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
|
||||
{ LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
|
||||
{ LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
|
||||
{ LOPT_MAXPORT, ARG_ONE, "<port>", gettext_noop("Specify highest port available for DNS query transmission."), NULL },
|
||||
{ LOPT_DHCP_FQDN, OPT_DHCP_FQDN, NULL, gettext_noop("Use only fully qualified domain names for DHCP clients."), NULL },
|
||||
{ LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},
|
||||
{ LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },
|
||||
{ LOPT_RELAY, ARG_DUP, "<local-addr>,<server>[,<interface>]", gettext_noop("Relay DHCP requests to a remote server"), NULL},
|
||||
{ LOPT_CNAME, ARG_DUP, "<alias>,<target>", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
|
||||
{ LOPT_CNAME, ARG_DUP, "<alias>,<target>[,<ttl>]", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
|
||||
{ LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
|
||||
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
|
||||
{ LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
|
||||
{ LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
|
||||
{ LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add requestor's IP subnet to forwarded DNS queries."), NULL },
|
||||
{ LOPT_ADD_MAC, ARG_DUP, "[=base64|text]", gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
|
||||
{ LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add specified IP subnet to forwarded DNS queries."), NULL },
|
||||
{ LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add client identification to forwarded DNS queries."), NULL },
|
||||
{ LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
|
||||
{ LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
|
||||
{ LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
|
||||
{ LOPT_FQDN, OPT_FQDN_UPDATE, NULL, gettext_noop("Allow DHCP clients to do their own DDNS updates."), NULL },
|
||||
{ LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL },
|
||||
{ LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
|
||||
{ LOPT_HOST_REC, ARG_DUP, "<name>,<address>", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
|
||||
{ LOPT_HOST_REC, ARG_DUP, "<name>,<address>[,<ttl>]", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
|
||||
{ LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
|
||||
{ LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL },
|
||||
{ LOPT_AUTHSERV, ARG_ONE, "<NS>,<interface>", gettext_noop("Export local names to global DNS"), NULL },
|
||||
@@ -448,6 +482,7 @@ static struct {
|
||||
{ LOPT_DNSSEC_DEBUG, OPT_DNSSEC_DEBUG, NULL, gettext_noop("Disable upstream checking for DNSSEC debugging."), NULL },
|
||||
{ LOPT_DNSSEC_CHECK, OPT_DNSSEC_NO_SIGN, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL },
|
||||
{ LOPT_DNSSEC_TIME, OPT_DNSSEC_TIME, NULL, gettext_noop("Don't check DNSSEC signature timestamps until first cache-reload"), NULL },
|
||||
{ LOPT_DNSSEC_STAMP, ARG_ONE, "<path>", gettext_noop("Timestamp file to verify system clock for DNSSEC"), NULL },
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
{ LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
|
||||
#endif
|
||||
@@ -455,8 +490,10 @@ static struct {
|
||||
{ LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
|
||||
{ LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
|
||||
{ LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },
|
||||
{ LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks"), NULL },
|
||||
{ LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops"), NULL },
|
||||
{ LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks."), NULL },
|
||||
{ LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops."), NULL },
|
||||
{ LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL },
|
||||
{ LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL },
|
||||
{ 0, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -700,6 +737,20 @@ static void do_usage(void)
|
||||
|
||||
#define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
|
||||
|
||||
static char *parse_mysockaddr(char *arg, union mysockaddr *addr)
|
||||
{
|
||||
if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
|
||||
addr->sa.sa_family = AF_INET;
|
||||
#ifdef HAVE_IPV6
|
||||
else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
|
||||
addr->sa.sa_family = AF_INET6;
|
||||
#endif
|
||||
else
|
||||
return _("bad address");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags)
|
||||
{
|
||||
int source_port = 0, serv_port = NAMESERVER_PORT;
|
||||
@@ -1148,7 +1199,8 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
cp = comma;
|
||||
comma = split(cp);
|
||||
slash = split_chr(cp, '/');
|
||||
inet_pton(AF_INET, cp, &in);
|
||||
if (!inet_pton(AF_INET, cp, &in))
|
||||
ret_err(_("bad IPv4 address"));
|
||||
if (!slash)
|
||||
{
|
||||
memcpy(op, &in, INADDRSZ);
|
||||
@@ -1474,22 +1526,31 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
for (arg = comma; arg; arg = comma)
|
||||
{
|
||||
comma = split(arg);
|
||||
li = opt_malloc(sizeof(struct list));
|
||||
if (*arg == '*')
|
||||
if (strlen(arg) != 0)
|
||||
{
|
||||
li->next = match_suffix;
|
||||
match_suffix = li;
|
||||
/* Have to copy: buffer is overwritten */
|
||||
li->suffix = opt_string_alloc(arg+1);
|
||||
li = opt_malloc(sizeof(struct list));
|
||||
if (*arg == '*')
|
||||
{
|
||||
/* "*" with no suffix is a no-op */
|
||||
if (arg[1] == 0)
|
||||
free(li);
|
||||
else
|
||||
{
|
||||
li->next = match_suffix;
|
||||
match_suffix = li;
|
||||
/* Have to copy: buffer is overwritten */
|
||||
li->suffix = opt_string_alloc(arg+1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
li->next = ignore_suffix;
|
||||
ignore_suffix = li;
|
||||
/* Have to copy: buffer is overwritten */
|
||||
li->suffix = opt_string_alloc(arg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
li->next = ignore_suffix;
|
||||
ignore_suffix = li;
|
||||
/* Have to copy: buffer is overwritten */
|
||||
li->suffix = opt_string_alloc(arg);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (!(dir_stream = opendir(directory)))
|
||||
die(_("cannot access directory %s: %s"), directory, EC_FILE);
|
||||
@@ -1555,7 +1616,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
free(ignore_suffix->suffix);
|
||||
free(ignore_suffix);
|
||||
}
|
||||
|
||||
for(; match_suffix; match_suffix = li)
|
||||
{
|
||||
li = match_suffix->next;
|
||||
free(match_suffix->suffix);
|
||||
free(match_suffix);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1563,10 +1629,46 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
set_option_bool(OPT_CLIENT_SUBNET);
|
||||
if (arg)
|
||||
{
|
||||
char *err, *end;
|
||||
comma = split(arg);
|
||||
if (!atoi_check(arg, &daemon->addr4_netmask) ||
|
||||
(comma && !atoi_check(comma, &daemon->addr6_netmask)))
|
||||
ret_err(gen_err);
|
||||
|
||||
struct mysubnet* new = opt_malloc(sizeof(struct mysubnet));
|
||||
if ((end = split_chr(arg, '/')))
|
||||
{
|
||||
/* has subnet+len */
|
||||
err = parse_mysockaddr(arg, &new->addr);
|
||||
if (err)
|
||||
ret_err(err);
|
||||
if (!atoi_check(end, &new->mask))
|
||||
ret_err(gen_err);
|
||||
new->addr_used = 1;
|
||||
}
|
||||
else if (!atoi_check(arg, &new->mask))
|
||||
ret_err(gen_err);
|
||||
|
||||
daemon->add_subnet4 = new;
|
||||
|
||||
if (comma)
|
||||
{
|
||||
new = opt_malloc(sizeof(struct mysubnet));
|
||||
if ((end = split_chr(comma, '/')))
|
||||
{
|
||||
/* has subnet+len */
|
||||
err = parse_mysockaddr(comma, &new->addr);
|
||||
if (err)
|
||||
ret_err(err);
|
||||
if (!atoi_check(end, &new->mask))
|
||||
ret_err(gen_err);
|
||||
new->addr_used = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!atoi_check(comma, &new->mask))
|
||||
ret_err(gen_err);
|
||||
}
|
||||
|
||||
daemon->add_subnet6 = new;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1694,9 +1796,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
break;
|
||||
#endif /* HAVE_DHCP */
|
||||
|
||||
case LOPT_DHCP_HOST: /* --dhcp-hostfile */
|
||||
case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
|
||||
case 'H': /* --addn-hosts */
|
||||
case LOPT_DHCP_HOST: /* --dhcp-hostsfile */
|
||||
case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
|
||||
case LOPT_DHCP_INOTIFY: /* --dhcp-hostsdir */
|
||||
case LOPT_DHOPT_INOTIFY: /* --dhcp-optsdir */
|
||||
case LOPT_HOST_INOTIFY: /* --hostsdir */
|
||||
case 'H': /* --addn-hosts */
|
||||
{
|
||||
struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
|
||||
static unsigned int hosts_index = SRC_AH;
|
||||
@@ -1718,6 +1823,18 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->next = daemon->dhcp_opts_file;
|
||||
daemon->dhcp_opts_file = new;
|
||||
}
|
||||
else
|
||||
{
|
||||
new->next = daemon->dynamic_dirs;
|
||||
daemon->dynamic_dirs = new;
|
||||
if (option == LOPT_DHCP_INOTIFY)
|
||||
new->flags |= AH_DHCP_HST;
|
||||
else if (option == LOPT_DHOPT_INOTIFY)
|
||||
new->flags |= AH_DHCP_OPT;
|
||||
else if (option == LOPT_HOST_INOTIFY)
|
||||
new->flags |= AH_HOSTS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1874,11 +1991,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
comma = split(arg);
|
||||
daemon->soa_retry = (u32)atoi(arg);
|
||||
if (comma)
|
||||
{
|
||||
arg = comma;
|
||||
comma = split(arg);
|
||||
daemon->soa_expiry = (u32)atoi(arg);
|
||||
}
|
||||
daemon->soa_expiry = (u32)atoi(comma);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1933,10 +2046,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
else
|
||||
{
|
||||
/* generate the equivalent of
|
||||
local=/<domain>/
|
||||
local=/xxx.yyy.zzz.in-addr.arpa/ */
|
||||
struct server *serv = add_rev4(new->start, msize);
|
||||
serv->flags |= SERV_NO_ADDR;
|
||||
|
||||
/* local=/<domain>/ */
|
||||
serv = opt_malloc(sizeof(struct server));
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
serv->domain = d;
|
||||
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = serv;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1970,10 +2090,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
else
|
||||
{
|
||||
/* generate the equivalent of
|
||||
local=/<domain>/
|
||||
local=/xxx.yyy.zzz.ip6.arpa/ */
|
||||
struct server *serv = add_rev6(&new->start6, msize);
|
||||
serv->flags |= SERV_NO_ADDR;
|
||||
|
||||
/* local=/<domain>/ */
|
||||
serv = opt_malloc(sizeof(struct server));
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
serv->domain = d;
|
||||
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = serv;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2036,6 +2163,26 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
break;
|
||||
|
||||
case LOPT_CPE_ID: /* --add-dns-client */
|
||||
if (arg)
|
||||
daemon->dns_client_id = opt_string_alloc(arg);
|
||||
break;
|
||||
|
||||
case LOPT_ADD_MAC: /* --add-mac */
|
||||
if (!arg)
|
||||
set_option_bool(OPT_ADD_MAC);
|
||||
else
|
||||
{
|
||||
unhide_metas(arg);
|
||||
if (strcmp(arg, "base64") == 0)
|
||||
set_option_bool(OPT_MAC_B64);
|
||||
else if (strcmp(arg, "text") == 0)
|
||||
set_option_bool(OPT_MAC_HEX);
|
||||
else
|
||||
ret_err(gen_err);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'u': /* --user */
|
||||
daemon->username = opt_string_alloc(arg);
|
||||
break;
|
||||
@@ -2097,14 +2244,23 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
break;
|
||||
|
||||
case 'B': /* --bogus-nxdomain */
|
||||
{
|
||||
case LOPT_IGNORE_ADDR: /* --ignore-address */
|
||||
{
|
||||
struct in_addr addr;
|
||||
unhide_metas(arg);
|
||||
if (arg && (inet_pton(AF_INET, arg, &addr) > 0))
|
||||
{
|
||||
struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
|
||||
baddr->next = daemon->bogus_addr;
|
||||
daemon->bogus_addr = baddr;
|
||||
if (option == 'B')
|
||||
{
|
||||
baddr->next = daemon->bogus_addr;
|
||||
daemon->bogus_addr = baddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
baddr->next = daemon->ignore_addr;
|
||||
daemon->ignore_addr = baddr;
|
||||
}
|
||||
baddr->addr = addr;
|
||||
}
|
||||
else
|
||||
@@ -2219,8 +2375,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
if (!(newlist->flags & SERV_NO_REBIND))
|
||||
newlist->flags |= SERV_NO_ADDR; /* no server */
|
||||
if (newlist->flags & SERV_LITERAL_ADDRESS)
|
||||
ret_err(gen_err);
|
||||
}
|
||||
|
||||
else if (strcmp(arg, "#") == 0)
|
||||
@@ -2382,11 +2536,22 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
ret_err(gen_err);
|
||||
break;
|
||||
|
||||
case LOPT_MAXPORT: /* --max-port */
|
||||
if (!atoi_check16(arg, &daemon->max_port))
|
||||
ret_err(gen_err);
|
||||
break;
|
||||
|
||||
case '0': /* --dns-forward-max */
|
||||
if (!atoi_check(arg, &daemon->ftabsize))
|
||||
ret_err(gen_err);
|
||||
break;
|
||||
|
||||
case 'q': /* --log-queries */
|
||||
set_option_bool(OPT_LOG);
|
||||
if (arg && strcmp(arg, "extra") == 0)
|
||||
set_option_bool(OPT_EXTRALOG);
|
||||
break;
|
||||
|
||||
case LOPT_MAX_LOGS: /* --log-async */
|
||||
daemon->max_logs = LOG_MAX; /* default */
|
||||
if (arg && !atoi_check(arg, &daemon->max_logs))
|
||||
@@ -2416,8 +2581,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
case 'T': /* --local-ttl */
|
||||
case LOPT_NEGTTL: /* --neg-ttl */
|
||||
case LOPT_MAXTTL: /* --max-ttl */
|
||||
case LOPT_MINCTTL: /* --min-cache-ttl */
|
||||
case LOPT_MAXCTTL: /* --max-cache-ttl */
|
||||
case LOPT_AUTHTTL: /* --auth-ttl */
|
||||
case LOPT_DHCPTTL: /* --dhcp-ttl */
|
||||
{
|
||||
int ttl;
|
||||
if (!atoi_check(arg, &ttl))
|
||||
@@ -2426,10 +2593,21 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
daemon->neg_ttl = (unsigned long)ttl;
|
||||
else if (option == LOPT_MAXTTL)
|
||||
daemon->max_ttl = (unsigned long)ttl;
|
||||
else if (option == LOPT_MINCTTL)
|
||||
{
|
||||
if (ttl > TTL_FLOOR_LIMIT)
|
||||
ttl = TTL_FLOOR_LIMIT;
|
||||
daemon->min_cache_ttl = (unsigned long)ttl;
|
||||
}
|
||||
else if (option == LOPT_MAXCTTL)
|
||||
daemon->max_cache_ttl = (unsigned long)ttl;
|
||||
else if (option == LOPT_AUTHTTL)
|
||||
daemon->auth_ttl = (unsigned long)ttl;
|
||||
else if (option == LOPT_DHCPTTL)
|
||||
{
|
||||
daemon->dhcp_ttl = (unsigned long)ttl;
|
||||
daemon->use_dhcp_ttl = 1;
|
||||
}
|
||||
else
|
||||
daemon->local_ttl = (unsigned long)ttl;
|
||||
break;
|
||||
@@ -2448,6 +2626,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
ret_err(gen_err);
|
||||
break;
|
||||
|
||||
case LOPT_TFTP_MTU: /* --tftp-mtu */
|
||||
if (!atoi_check(arg, &daemon->tftp_mtu))
|
||||
ret_err(gen_err);
|
||||
break;
|
||||
|
||||
case LOPT_PREFIX: /* --tftp-prefix */
|
||||
comma = split(arg);
|
||||
if (comma)
|
||||
@@ -2590,13 +2773,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
leasepos = 3;
|
||||
if (!is_same_net(new->start, new->end, new->netmask))
|
||||
ret_err(_("inconsistent DHCP range"));
|
||||
}
|
||||
|
||||
|
||||
if (k >= 4 && strchr(a[3], '.') &&
|
||||
(inet_pton(AF_INET, a[3], &new->broadcast) > 0))
|
||||
{
|
||||
new->flags |= CONTEXT_BRDCAST;
|
||||
leasepos = 4;
|
||||
if (k >= 4 && strchr(a[3], '.') &&
|
||||
(inet_pton(AF_INET, a[3], &new->broadcast) > 0))
|
||||
{
|
||||
new->flags |= CONTEXT_BRDCAST;
|
||||
leasepos = 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_DHCP6
|
||||
@@ -2620,6 +2804,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->flags |= CONTEXT_RA_ROUTER | CONTEXT_RA;
|
||||
else if (strcmp(a[leasepos], "ra-stateless") == 0)
|
||||
new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP | CONTEXT_RA;
|
||||
else if (strcmp(a[leasepos], "off-link") == 0)
|
||||
new->flags |= CONTEXT_RA_OFF_LINK;
|
||||
else if (leasepos == 1 && inet_pton(AF_INET6, a[leasepos], &new->end6))
|
||||
new->flags |= CONTEXT_DHCP;
|
||||
else if (strstr(a[leasepos], "constructor:") == a[leasepos])
|
||||
@@ -2684,6 +2870,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
if (leasepos < k)
|
||||
{
|
||||
if (leasepos != k-1)
|
||||
ret_err(_("bad dhcp-range"));
|
||||
|
||||
if (strcmp(a[leasepos], "infinite") == 0)
|
||||
new->lease_time = 0xffffffff;
|
||||
else if (strcmp(a[leasepos], "deprecated") == 0)
|
||||
@@ -2778,7 +2967,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
|
||||
if (len == -1)
|
||||
|
||||
ret_err(_("bad hex constant"));
|
||||
else if ((new->clid = opt_malloc(len)))
|
||||
{
|
||||
@@ -3471,8 +3659,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
(!(inet_pton(AF_INET, a[1], &new->out) > 0)))
|
||||
option = '?';
|
||||
|
||||
if (k == 3)
|
||||
inet_pton(AF_INET, a[2], &new->mask);
|
||||
if (k == 3 && !inet_pton(AF_INET, a[2], &new->mask))
|
||||
option = '?';
|
||||
|
||||
if (dash &&
|
||||
(!(inet_pton(AF_INET, dash, &new->end) > 0) ||
|
||||
@@ -3522,12 +3710,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
case LOPT_CNAME: /* --cname */
|
||||
{
|
||||
struct cname *new;
|
||||
char *alias;
|
||||
char *target;
|
||||
char *alias, *target, *ttls;
|
||||
int ttl = -1;
|
||||
|
||||
if (!(comma = split(arg)))
|
||||
ret_err(gen_err);
|
||||
|
||||
if ((ttls = split(comma)) && !atoi_check(ttls, &ttl))
|
||||
ret_err(_("bad TTL"));
|
||||
|
||||
alias = canonicalise_opt(arg);
|
||||
target = canonicalise_opt(comma);
|
||||
|
||||
@@ -3543,6 +3734,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
daemon->cnames = new;
|
||||
new->alias = alias;
|
||||
new->target = target;
|
||||
new->ttl = ttl;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -3608,7 +3800,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
case LOPT_RR: /* dns-rr */
|
||||
{
|
||||
struct txt_record *new;
|
||||
size_t len = len;
|
||||
size_t len = 0;
|
||||
char *data;
|
||||
int val;
|
||||
|
||||
@@ -3716,13 +3908,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
if (!atoi_check16(arg, &priority))
|
||||
ret_err(_("invalid priority"));
|
||||
|
||||
if (comma)
|
||||
{
|
||||
arg = comma;
|
||||
comma = split(arg);
|
||||
if (!atoi_check16(arg, &weight))
|
||||
ret_err(_("invalid weight"));
|
||||
}
|
||||
if (comma && !atoi_check16(comma, &weight))
|
||||
ret_err(_("invalid weight"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3743,14 +3930,22 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
struct host_record *new = opt_malloc(sizeof(struct host_record));
|
||||
memset(new, 0, sizeof(struct host_record));
|
||||
|
||||
new->ttl = -1;
|
||||
|
||||
if (!arg || !(comma = split(arg)))
|
||||
ret_err(_("Bad host-record"));
|
||||
|
||||
while (arg)
|
||||
{
|
||||
struct all_addr addr;
|
||||
if (inet_pton(AF_INET, arg, &addr))
|
||||
char *dig;
|
||||
|
||||
for (dig = arg; *dig != 0; dig++)
|
||||
if (*dig < '0' || *dig > '9')
|
||||
break;
|
||||
if (*dig == 0)
|
||||
new->ttl = atoi(arg);
|
||||
else if (inet_pton(AF_INET, arg, &addr))
|
||||
new->addr = addr.addr.addr4;
|
||||
#ifdef HAVE_IPV6
|
||||
else if (inet_pton(AF_INET6, arg, &addr))
|
||||
@@ -3792,6 +3987,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
case LOPT_DNSSEC_STAMP:
|
||||
daemon->timestamp_file = opt_string_alloc(arg);
|
||||
break;
|
||||
|
||||
case LOPT_TRUST_ANCHOR:
|
||||
{
|
||||
struct ds_config *new = opt_malloc(sizeof(struct ds_config));
|
||||
@@ -3990,6 +4189,20 @@ static void read_file(char *file, FILE *f, int hard_opt)
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
int option_read_dynfile(char *file, int flags)
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), file);
|
||||
|
||||
if (flags & AH_DHCP_HST)
|
||||
return one_file(file, LOPT_BANK);
|
||||
else if (flags & AH_DHCP_OPT)
|
||||
return one_file(file, LOPT_OPTS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int one_file(char *file, int hard_opt)
|
||||
{
|
||||
FILE *f;
|
||||
@@ -4087,7 +4300,7 @@ struct hostsfile *expand_filelist(struct hostsfile *list)
|
||||
|
||||
/* don't read this as a file */
|
||||
ah->flags |= AH_INACTIVE;
|
||||
|
||||
|
||||
if (!(dir_stream = opendir(ah->fname)))
|
||||
my_syslog(LOG_ERR, _("cannot access directory %s: %s"),
|
||||
ah->fname, strerror(errno));
|
||||
@@ -4299,6 +4512,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
daemon->soa_refresh = SOA_REFRESH;
|
||||
daemon->soa_retry = SOA_RETRY;
|
||||
daemon->soa_expiry = SOA_EXPIRY;
|
||||
daemon->max_port = MAX_PORT;
|
||||
|
||||
add_txt("version.bind", "dnsmasq-" VERSION, 0 );
|
||||
add_txt("authors.bind", "Simon Kelley", 0);
|
||||
@@ -4387,7 +4601,11 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
}
|
||||
|
||||
if (conffile)
|
||||
one_file(conffile, conffile_opt);
|
||||
{
|
||||
one_file(conffile, conffile_opt);
|
||||
if (conffile_opt == 0)
|
||||
free(conffile);
|
||||
}
|
||||
|
||||
/* port might not be known when the address is parsed - fill in here */
|
||||
if (daemon->servers)
|
||||
@@ -4402,9 +4620,27 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
else if (tmp->source_addr.sa.sa_family == AF_INET6)
|
||||
tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (daemon->host_records)
|
||||
{
|
||||
struct host_record *hr;
|
||||
|
||||
for (hr = daemon->host_records; hr; hr = hr->next)
|
||||
if (hr->ttl == -1)
|
||||
hr->ttl = daemon->local_ttl;
|
||||
}
|
||||
|
||||
if (daemon->cnames)
|
||||
{
|
||||
struct cname *cn;
|
||||
|
||||
for (cn = daemon->cnames; cn; cn = cn->next)
|
||||
if (cn->ttl == -1)
|
||||
cn->ttl = daemon->local_ttl;
|
||||
}
|
||||
|
||||
if (daemon->if_addrs)
|
||||
{
|
||||
struct iname *tmp;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
125
src/poll.c
Normal file
125
src/poll.c
Normal file
@@ -0,0 +1,125 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
/* Wrapper for poll(). Allocates and extends array of struct pollfds,
|
||||
keeps them in fd order so that we can set and test conditions on
|
||||
fd using a simple but efficient binary chop. */
|
||||
|
||||
/* poll_reset()
|
||||
poll_listen(fd, event)
|
||||
.
|
||||
.
|
||||
poll_listen(fd, event);
|
||||
|
||||
hits = do_poll(timeout);
|
||||
|
||||
if (poll_check(fd, event)
|
||||
.
|
||||
.
|
||||
|
||||
if (poll_check(fd, event)
|
||||
.
|
||||
.
|
||||
|
||||
event is OR of POLLIN, POLLOUT, POLLERR, etc
|
||||
*/
|
||||
|
||||
static struct pollfd *pollfds = NULL;
|
||||
static nfds_t nfds, arrsize = 0;
|
||||
|
||||
/* Binary search. Returns either the pollfd with fd, or
|
||||
if the fd doesn't match, or return equals nfds, the entry
|
||||
to the left of which a new record should be inserted. */
|
||||
static nfds_t fd_search(int fd)
|
||||
{
|
||||
nfds_t left, right, mid;
|
||||
|
||||
if ((right = nfds) == 0)
|
||||
return 0;
|
||||
|
||||
left = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (right == left + 1)
|
||||
return (pollfds[left].fd >= fd) ? left : right;
|
||||
|
||||
mid = (left + right)/2;
|
||||
|
||||
if (pollfds[mid].fd > fd)
|
||||
right = mid;
|
||||
else
|
||||
left = mid;
|
||||
}
|
||||
}
|
||||
|
||||
void poll_reset(void)
|
||||
{
|
||||
nfds = 0;
|
||||
}
|
||||
|
||||
int do_poll(int timeout)
|
||||
{
|
||||
return poll(pollfds, nfds, timeout);
|
||||
}
|
||||
|
||||
int poll_check(int fd, short event)
|
||||
{
|
||||
nfds_t i = fd_search(fd);
|
||||
|
||||
if (i < nfds && pollfds[i].fd == fd)
|
||||
return pollfds[i].revents & event;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void poll_listen(int fd, short event)
|
||||
{
|
||||
nfds_t i = fd_search(fd);
|
||||
|
||||
if (i < nfds && pollfds[i].fd == fd)
|
||||
pollfds[i].events |= event;
|
||||
else
|
||||
{
|
||||
if (arrsize != nfds)
|
||||
memmove(&pollfds[i+1], &pollfds[i], (nfds - i) * sizeof(struct pollfd));
|
||||
else
|
||||
{
|
||||
/* Array too small, extend. */
|
||||
struct pollfd *new;
|
||||
|
||||
arrsize = (arrsize == 0) ? 64 : arrsize * 2;
|
||||
|
||||
if (!(new = whine_malloc(arrsize * sizeof(struct pollfd))))
|
||||
return;
|
||||
|
||||
if (pollfds)
|
||||
{
|
||||
memcpy(new, pollfds, i * sizeof(struct pollfd));
|
||||
memcpy(&new[i+1], &pollfds[i], (nfds - i) * sizeof(struct pollfd));
|
||||
free(pollfds);
|
||||
}
|
||||
|
||||
pollfds = new;
|
||||
}
|
||||
|
||||
pollfds[i].fd = fd;
|
||||
pollfds[i].events = event;
|
||||
nfds++;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
170
src/radv.c
170
src/radv.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -28,11 +28,12 @@
|
||||
|
||||
struct ra_param {
|
||||
time_t now;
|
||||
int ind, managed, other, found_context, first, adv_router;
|
||||
int ind, managed, other, first, adv_router;
|
||||
char *if_name;
|
||||
struct dhcp_netid *tags;
|
||||
struct in6_addr link_local, link_global, ula;
|
||||
unsigned int glob_pref_time, link_pref_time, ula_pref_time, adv_interval, prio;
|
||||
struct dhcp_context *found_context;
|
||||
};
|
||||
|
||||
struct search_param {
|
||||
@@ -40,7 +41,18 @@ struct search_param {
|
||||
char name[IF_NAMESIZE+1];
|
||||
};
|
||||
|
||||
struct alias_param {
|
||||
int iface;
|
||||
struct dhcp_bridge *bridge;
|
||||
int num_alias_ifs;
|
||||
int max_alias_ifs;
|
||||
int *alias_ifs;
|
||||
};
|
||||
|
||||
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
|
||||
static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_addr *dest,
|
||||
int send_iface);
|
||||
static int send_ra_to_aliases(int index, unsigned int type, char *mac, size_t maclen, void *parm);
|
||||
static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int flags,
|
||||
unsigned int preferred, unsigned int valid, void *vparam);
|
||||
@@ -181,6 +193,7 @@ void icmp6_packet(time_t now)
|
||||
else if (packet[0] == ND_ROUTER_SOLICIT)
|
||||
{
|
||||
char *mac = "";
|
||||
struct dhcp_bridge *bridge, *alias;
|
||||
|
||||
/* look for link-layer address option for logging */
|
||||
if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz)
|
||||
@@ -191,12 +204,37 @@ void icmp6_packet(time_t now)
|
||||
|
||||
if (!option_bool(OPT_QUIET_RA))
|
||||
my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
|
||||
/* source address may not be valid in solicit request. */
|
||||
send_ra(now, if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
|
||||
|
||||
/* If the incoming interface is an alias of some other one (as
|
||||
specified by the --bridge-interface option), send an RA using
|
||||
the context of the aliased interface. */
|
||||
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
|
||||
{
|
||||
int bridge_index = if_nametoindex(bridge->iface);
|
||||
if (bridge_index)
|
||||
{
|
||||
for (alias = bridge->alias; alias; alias = alias->next)
|
||||
if (wildcard_matchn(alias->iface, interface, IF_NAMESIZE))
|
||||
{
|
||||
/* Send an RA on if_index with information from
|
||||
bridge_index. */
|
||||
send_ra_alias(now, bridge_index, bridge->iface, NULL, if_index);
|
||||
break;
|
||||
}
|
||||
if (alias)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the incoming interface wasn't an alias, send an RA using
|
||||
the context of the incoming interface. */
|
||||
if (!bridge)
|
||||
/* source address may not be valid in solicit request. */
|
||||
send_ra(now, if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
|
||||
static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_addr *dest, int send_iface)
|
||||
{
|
||||
struct ra_packet *ra;
|
||||
struct ra_param parm;
|
||||
@@ -214,7 +252,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
||||
parm.ind = iface;
|
||||
parm.managed = 0;
|
||||
parm.other = 0;
|
||||
parm.found_context = 0;
|
||||
parm.found_context = NULL;
|
||||
parm.adv_router = 0;
|
||||
parm.if_name = iface_name;
|
||||
parm.first = 1;
|
||||
@@ -271,8 +309,14 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
||||
unsigned int old = difftime(now, context->address_lost_time);
|
||||
|
||||
if (old > context->saved_valid)
|
||||
{
|
||||
{
|
||||
/* We've advertised this enough, time to go */
|
||||
|
||||
/* If this context held the timeout, and there's another context in use
|
||||
transfer the timeout there. */
|
||||
if (context->ra_time != 0 && parm.found_context && parm.found_context->ra_time == 0)
|
||||
new_timeout(parm.found_context, iface_name, now);
|
||||
|
||||
*up = context->next;
|
||||
free(context);
|
||||
}
|
||||
@@ -313,8 +357,10 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
||||
opt->type = ICMP6_OPT_PREFIX;
|
||||
opt->len = 4;
|
||||
opt->prefix_len = context->prefix;
|
||||
/* autonomous only if we're not doing dhcp, always set "on-link" */
|
||||
opt->flags = do_slaac ? 0xC0 : 0x80;
|
||||
/* autonomous only if we're not doing dhcp, set
|
||||
"on-link" unless "off-link" was specified */
|
||||
opt->flags = (do_slaac ? 0x40 : 0) |
|
||||
((context->flags & CONTEXT_RA_OFF_LINK) ? 0 : 0x80);
|
||||
opt->valid_lifetime = htonl(context->saved_valid - old);
|
||||
opt->preferred_lifetime = htonl(0);
|
||||
opt->reserved = 0;
|
||||
@@ -368,7 +414,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
||||
}
|
||||
#endif
|
||||
|
||||
iface_enumerate(AF_LOCAL, &iface, add_lla);
|
||||
iface_enumerate(AF_LOCAL, &send_iface, add_lla);
|
||||
|
||||
/* RDNSS, RFC 6106, use relevant DHCP6 options */
|
||||
(void)option_filter(parm.tags, NULL, daemon->dhcp_opts6);
|
||||
@@ -476,14 +522,22 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
||||
else
|
||||
{
|
||||
inet_pton(AF_INET6, ALL_NODES, &addr.sin6_addr);
|
||||
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &iface, sizeof(iface));
|
||||
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &send_iface, sizeof(send_iface));
|
||||
}
|
||||
|
||||
while (sendto(daemon->icmp6fd, daemon->outpacket.iov_base, save_counter(0), 0,
|
||||
(struct sockaddr *)&addr, sizeof(addr)) == -1 && retry_send());
|
||||
while (retry_send(sendto(daemon->icmp6fd, daemon->outpacket.iov_base,
|
||||
save_counter(0), 0, (struct sockaddr *)&addr,
|
||||
sizeof(addr))));
|
||||
|
||||
}
|
||||
|
||||
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
|
||||
{
|
||||
/* Send an RA on the same interface that the RA content is based
|
||||
on. */
|
||||
send_ra_alias(now, iface, iface_name, dest, iface);
|
||||
}
|
||||
|
||||
static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int flags,
|
||||
unsigned int preferred, unsigned int valid, void *vparam)
|
||||
@@ -513,6 +567,7 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
int deprecate = 0;
|
||||
int constructed = 0;
|
||||
int adv_router = 0;
|
||||
int off_link = 0;
|
||||
unsigned int time = 0xffffffff;
|
||||
struct dhcp_context *context;
|
||||
|
||||
@@ -585,10 +640,13 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
context->ra_time = 0;
|
||||
context->flags |= CONTEXT_RA_DONE;
|
||||
real_prefix = context->prefix;
|
||||
off_link = (context->flags & CONTEXT_RA_OFF_LINK);
|
||||
}
|
||||
|
||||
param->first = 0;
|
||||
param->found_context = 1;
|
||||
param->first = 0;
|
||||
/* found_context is the _last_ one we found, so if there's
|
||||
more than one, it's not the first. */
|
||||
param->found_context = context;
|
||||
}
|
||||
|
||||
/* configured time is ceiling */
|
||||
@@ -635,8 +693,9 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
opt->type = ICMP6_OPT_PREFIX;
|
||||
opt->len = 4;
|
||||
opt->prefix_len = real_prefix;
|
||||
/* autonomous only if we're not doing dhcp, always set "on-link" */
|
||||
opt->flags = 0x80;
|
||||
/* autonomous only if we're not doing dhcp, set
|
||||
"on-link" unless "off-link" was specified */
|
||||
opt->flags = (off_link ? 0 : 0x80);
|
||||
if (do_slaac)
|
||||
opt->flags |= 0x40;
|
||||
if (adv_router)
|
||||
@@ -682,6 +741,7 @@ time_t periodic_ra(time_t now)
|
||||
struct search_param param;
|
||||
struct dhcp_context *context;
|
||||
time_t next_event;
|
||||
struct alias_param aparam;
|
||||
|
||||
param.now = now;
|
||||
param.iface = 0;
|
||||
@@ -729,12 +789,84 @@ time_t periodic_ra(time_t now)
|
||||
if (tmp->name && wildcard_match(tmp->name, param.name))
|
||||
break;
|
||||
if (!tmp)
|
||||
send_ra(now, param.iface, param.name, NULL);
|
||||
{
|
||||
send_ra(now, param.iface, param.name, NULL);
|
||||
|
||||
/* Also send on all interfaces that are aliases of this
|
||||
one. */
|
||||
for (aparam.bridge = daemon->bridges;
|
||||
aparam.bridge;
|
||||
aparam.bridge = aparam.bridge->next)
|
||||
if ((int)if_nametoindex(aparam.bridge->iface) == param.iface)
|
||||
{
|
||||
/* Count the number of alias interfaces for this
|
||||
'bridge', by calling iface_enumerate with
|
||||
send_ra_to_aliases and NULL alias_ifs. */
|
||||
aparam.iface = param.iface;
|
||||
aparam.alias_ifs = NULL;
|
||||
aparam.num_alias_ifs = 0;
|
||||
iface_enumerate(AF_LOCAL, &aparam, send_ra_to_aliases);
|
||||
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s => %d alias(es)",
|
||||
param.name, daemon->addrbuff, aparam.num_alias_ifs);
|
||||
|
||||
/* Allocate memory to store the alias interface
|
||||
indices. */
|
||||
aparam.alias_ifs = (int *)whine_malloc(aparam.num_alias_ifs *
|
||||
sizeof(int));
|
||||
if (aparam.alias_ifs)
|
||||
{
|
||||
/* Use iface_enumerate again to get the alias
|
||||
interface indices, then send on each of
|
||||
those. */
|
||||
aparam.max_alias_ifs = aparam.num_alias_ifs;
|
||||
aparam.num_alias_ifs = 0;
|
||||
iface_enumerate(AF_LOCAL, &aparam, send_ra_to_aliases);
|
||||
for (; aparam.num_alias_ifs; aparam.num_alias_ifs--)
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s => i/f %d",
|
||||
param.name, daemon->addrbuff,
|
||||
aparam.alias_ifs[aparam.num_alias_ifs - 1]);
|
||||
send_ra_alias(now,
|
||||
param.iface,
|
||||
param.name,
|
||||
NULL,
|
||||
aparam.alias_ifs[aparam.num_alias_ifs - 1]);
|
||||
}
|
||||
free(aparam.alias_ifs);
|
||||
}
|
||||
|
||||
/* The source interface can only appear in at most
|
||||
one --bridge-interface. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return next_event;
|
||||
}
|
||||
|
||||
|
||||
static int send_ra_to_aliases(int index, unsigned int type, char *mac, size_t maclen, void *parm)
|
||||
{
|
||||
struct alias_param *aparam = (struct alias_param *)parm;
|
||||
char ifrn_name[IFNAMSIZ];
|
||||
struct dhcp_bridge *alias;
|
||||
|
||||
(void)type;
|
||||
(void)mac;
|
||||
(void)maclen;
|
||||
|
||||
if (if_indextoname(index, ifrn_name))
|
||||
for (alias = aparam->bridge->alias; alias; alias = alias->next)
|
||||
if (wildcard_matchn(alias->iface, ifrn_name, IFNAMSIZ))
|
||||
{
|
||||
if (aparam->alias_ifs && (aparam->num_alias_ifs < aparam->max_alias_ifs))
|
||||
aparam->alias_ifs[aparam->num_alias_ifs] = index;
|
||||
aparam->num_alias_ifs++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int iface_search(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int flags,
|
||||
int preferred, int valid, void *vparam)
|
||||
|
||||
781
src/rfc1035.c
781
src/rfc1035.c
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -52,7 +52,9 @@ static void do_options(struct dhcp_context *context,
|
||||
int null_term, int pxearch,
|
||||
unsigned char *uuid,
|
||||
int vendor_class_len,
|
||||
time_t now);
|
||||
time_t now,
|
||||
unsigned int lease_time,
|
||||
unsigned short fuzz);
|
||||
|
||||
|
||||
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
|
||||
@@ -610,7 +612,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
clear_packet(mess, end);
|
||||
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
|
||||
netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now);
|
||||
netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -803,9 +805,14 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
if (service->type == type)
|
||||
break;
|
||||
|
||||
if (!service || !service->basename)
|
||||
return 0;
|
||||
for (; context; context = context->current)
|
||||
if (match_netid(context->filter, tagif_netid, 1) &&
|
||||
is_same_net(mess->ciaddr, context->start, context->netmask))
|
||||
break;
|
||||
|
||||
if (!service || !service->basename || !context)
|
||||
return 0;
|
||||
|
||||
clear_packet(mess, end);
|
||||
|
||||
mess->yiaddr = mess->ciaddr;
|
||||
@@ -886,10 +893,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
|
||||
mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));
|
||||
pxe_misc(mess, end, uuid);
|
||||
prune_vendor_opts(tagif_netid);
|
||||
do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||
do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||
|
||||
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid);
|
||||
log_tags(tagif_netid, ntohl(mess->xid));
|
||||
@@ -1042,13 +1049,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
|
||||
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
|
||||
/* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
|
||||
if (time != 0xffffffff)
|
||||
{
|
||||
option_put(mess, end, OPTION_T1, 4, (time/2));
|
||||
option_put(mess, end, OPTION_T2, 4, (time*7)/8);
|
||||
}
|
||||
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
|
||||
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
|
||||
@@ -1306,7 +1308,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
/* If the user-class option started as counted strings, the first byte will be zero. */
|
||||
if (len != 0 && ucp[0] == 0)
|
||||
ucp++, len--;
|
||||
lease_add_extradata(lease, ucp, len, 0);
|
||||
lease_add_extradata(lease, ucp, len, -1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1367,15 +1369,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
|
||||
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
|
||||
if (time != 0xffffffff)
|
||||
{
|
||||
while (fuzz > (time/16))
|
||||
fuzz = fuzz/2;
|
||||
option_put(mess, end, OPTION_T1, 4, (time/2) - fuzz);
|
||||
option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
|
||||
}
|
||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
|
||||
}
|
||||
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
@@ -1440,7 +1435,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
}
|
||||
|
||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0);
|
||||
|
||||
*is_inform = 1; /* handle reply differently */
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
@@ -2137,7 +2132,9 @@ static void do_options(struct dhcp_context *context,
|
||||
int null_term, int pxe_arch,
|
||||
unsigned char *uuid,
|
||||
int vendor_class_len,
|
||||
time_t now)
|
||||
time_t now,
|
||||
unsigned int lease_time,
|
||||
unsigned short fuzz)
|
||||
{
|
||||
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
|
||||
struct dhcp_boot *boot;
|
||||
@@ -2261,7 +2258,42 @@ static void do_options(struct dhcp_context *context,
|
||||
/* rfc3011 says this doesn't need to be in the requested options list. */
|
||||
if (subnet_addr.s_addr)
|
||||
option_put(mess, end, OPTION_SUBNET_SELECT, INADDRSZ, ntohl(subnet_addr.s_addr));
|
||||
|
||||
|
||||
if (lease_time != 0xffffffff)
|
||||
{
|
||||
unsigned int t1val = lease_time/2;
|
||||
unsigned int t2val = (lease_time*7)/8;
|
||||
unsigned int hval;
|
||||
|
||||
/* If set by user, sanity check, so not longer than lease. */
|
||||
if ((opt = option_find2(OPTION_T1)))
|
||||
{
|
||||
hval = ntohl(*((unsigned int *)opt->val));
|
||||
if (hval < lease_time && hval > 2)
|
||||
t1val = hval;
|
||||
}
|
||||
|
||||
if ((opt = option_find2(OPTION_T2)))
|
||||
{
|
||||
hval = ntohl(*((unsigned int *)opt->val));
|
||||
if (hval < lease_time && hval > 2)
|
||||
t2val = hval;
|
||||
}
|
||||
|
||||
/* ensure T1 is still < T2 */
|
||||
if (t2val <= t1val)
|
||||
t1val = t2val - 1;
|
||||
|
||||
while (fuzz > (t1val/8))
|
||||
fuzz = fuzz/2;
|
||||
|
||||
t1val -= fuzz;
|
||||
t2val -= fuzz;
|
||||
|
||||
option_put(mess, end, OPTION_T1, 4, t1val);
|
||||
option_put(mess, end, OPTION_T2, 4, t2val);
|
||||
}
|
||||
|
||||
/* replies to DHCPINFORM may not have a valid context */
|
||||
if (context)
|
||||
{
|
||||
@@ -2356,12 +2388,14 @@ static void do_options(struct dhcp_context *context,
|
||||
if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
|
||||
continue;
|
||||
|
||||
/* prohibit some used-internally options */
|
||||
/* prohibit some used-internally options. T1 and T2 already handled. */
|
||||
if (optno == OPTION_CLIENT_FQDN ||
|
||||
optno == OPTION_MAXMESSAGE ||
|
||||
optno == OPTION_OVERLOAD ||
|
||||
optno == OPTION_PAD ||
|
||||
optno == OPTION_END)
|
||||
optno == OPTION_END ||
|
||||
optno == OPTION_T1 ||
|
||||
optno == OPTION_T2)
|
||||
continue;
|
||||
|
||||
if (optno == OPTION_SNAME && done_server)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -130,7 +130,7 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
|
||||
MAC address from the local ND cache. */
|
||||
|
||||
if (!state->link_address)
|
||||
get_client_mac(client_addr, state->interface, state->mac, &state->mac_len, &state->mac_type);
|
||||
get_client_mac(client_addr, state->interface, state->mac, &state->mac_len, &state->mac_type, now);
|
||||
else
|
||||
{
|
||||
struct dhcp_context *c;
|
||||
@@ -691,6 +691,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
#endif
|
||||
|
||||
o = build_ia(state, &t1cntr);
|
||||
if (address_assigned)
|
||||
address_assigned = 2;
|
||||
|
||||
for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
|
||||
{
|
||||
@@ -781,6 +783,27 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
address_assigned = 1;
|
||||
}
|
||||
|
||||
if (address_assigned != 1)
|
||||
{
|
||||
/* If the server will not assign any addresses to any IAs in a
|
||||
subsequent Request from the client, the server MUST send an Advertise
|
||||
message to the client that doesn't include any IA options. */
|
||||
if (!state->lease_allocate)
|
||||
{
|
||||
save_counter(o);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the server cannot assign any addresses to an IA in the message
|
||||
from the client, the server MUST include the IA in the Reply message
|
||||
with no addresses in the IA and a Status Code option in the IA
|
||||
containing status code NoAddrsAvail. */
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6NOADDRS);
|
||||
put_opt6_string(_("address unavailable"));
|
||||
end_opt6(o1);
|
||||
}
|
||||
|
||||
end_ia(t1cntr, min_time, 0);
|
||||
end_opt6(o);
|
||||
}
|
||||
@@ -806,7 +829,16 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
put_opt6_short(DHCP6NOADDRS);
|
||||
put_opt6_string(_("no addresses available"));
|
||||
end_opt6(o1);
|
||||
log6_packet(state, "DHCPADVERTISE", NULL, _("no addresses available"));
|
||||
|
||||
/* Some clients will ask repeatedly when we're not giving
|
||||
out addresses because we're in stateless mode. Avoid spamming
|
||||
the log in that case. */
|
||||
for (c = state->context; c; c = c->current)
|
||||
if (!(c->flags & CONTEXT_RA_STATELESS))
|
||||
{
|
||||
log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", NULL, _("no addresses available"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -862,7 +894,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
{
|
||||
/* Static range, not configured. */
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6UNSPEC);
|
||||
put_opt6_short(DHCP6NOADDRS);
|
||||
put_opt6_string(_("address unavailable"));
|
||||
end_opt6(o1);
|
||||
}
|
||||
@@ -1015,9 +1047,9 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
{
|
||||
preferred_time = valid_time = 0;
|
||||
message = _("address invalid");
|
||||
}
|
||||
}
|
||||
|
||||
if (message)
|
||||
if (message && (message != state->hostname))
|
||||
log6_packet(state, "DHCPREPLY", req_addr, message);
|
||||
else
|
||||
log6_quiet(state, "DHCPREPLY", req_addr, message);
|
||||
@@ -1057,7 +1089,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
{
|
||||
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
|
||||
|
||||
if (!address6_available(state->context, req_addr, tagif, 1))
|
||||
if (!address6_valid(state->context, req_addr, tagif, 1))
|
||||
{
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6NOTONLINK);
|
||||
@@ -1288,15 +1320,15 @@ static struct dhcp_netid *add_options(struct state *state, int do_refresh)
|
||||
|
||||
if (opt_cfg->opt == OPTION6_REFRESH_TIME)
|
||||
done_refresh = 1;
|
||||
|
||||
if (opt_cfg->opt == OPTION6_DNS_SERVER)
|
||||
done_dns = 1;
|
||||
|
||||
if (opt_cfg->flags & DHOPT_ADDR6)
|
||||
{
|
||||
int len, j;
|
||||
struct in6_addr *a;
|
||||
|
||||
if (opt_cfg->opt == OPTION6_DNS_SERVER)
|
||||
done_dns = 1;
|
||||
|
||||
for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, j = 0;
|
||||
j < opt_cfg->len; j += IN6ADDRSZ, a++)
|
||||
if ((IN6_IS_ADDR_ULA_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) ||
|
||||
@@ -2022,7 +2054,8 @@ static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id)
|
||||
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
|
||||
struct in6_addr *peer_address, u32 scope_id, time_t now)
|
||||
{
|
||||
/* ->local is same value for all relays on ->current chain */
|
||||
|
||||
@@ -2036,7 +2069,7 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer
|
||||
unsigned char mac[DHCP_CHADDR_MAX];
|
||||
|
||||
inet_pton(AF_INET6, ALL_SERVERS, &multicast);
|
||||
get_client_mac(peer_address, scope_id, mac, &maclen, &mactype);
|
||||
get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now);
|
||||
|
||||
/* source address == relay address */
|
||||
from.addr.addr6 = relay->local.addr.addr6;
|
||||
|
||||
339
src/rrfilter.c
Normal file
339
src/rrfilter.c
Normal file
@@ -0,0 +1,339 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Code to safely remove RRs from an DNS answer */
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
/* Go through a domain name, find "pointers" and fix them up based on how many bytes
|
||||
we've chopped out of the packet, or check they don't point into an elided part. */
|
||||
static int check_name(unsigned char **namep, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
|
||||
{
|
||||
unsigned char *ansp = *namep;
|
||||
|
||||
while(1)
|
||||
{
|
||||
unsigned int label_type;
|
||||
|
||||
if (!CHECK_LEN(header, ansp, plen, 1))
|
||||
return 0;
|
||||
|
||||
label_type = (*ansp) & 0xc0;
|
||||
|
||||
if (label_type == 0xc0)
|
||||
{
|
||||
/* pointer for compression. */
|
||||
unsigned int offset;
|
||||
int i;
|
||||
unsigned char *p;
|
||||
|
||||
if (!CHECK_LEN(header, ansp, plen, 2))
|
||||
return 0;
|
||||
|
||||
offset = ((*ansp++) & 0x3f) << 8;
|
||||
offset |= *ansp++;
|
||||
|
||||
p = offset + (unsigned char *)header;
|
||||
|
||||
for (i = 0; i < rr_count; i++)
|
||||
if (p < rrs[i])
|
||||
break;
|
||||
else
|
||||
if (i & 1)
|
||||
offset -= rrs[i] - rrs[i-1];
|
||||
|
||||
/* does the pointer end up in an elided RR? */
|
||||
if (i & 1)
|
||||
return 0;
|
||||
|
||||
/* No, scale the pointer */
|
||||
if (fixup)
|
||||
{
|
||||
ansp -= 2;
|
||||
*ansp++ = (offset >> 8) | 0xc0;
|
||||
*ansp++ = offset & 0xff;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (label_type == 0x80)
|
||||
return 0; /* reserved */
|
||||
else if (label_type == 0x40)
|
||||
{
|
||||
/* Extended label type */
|
||||
unsigned int count;
|
||||
|
||||
if (!CHECK_LEN(header, ansp, plen, 2))
|
||||
return 0;
|
||||
|
||||
if (((*ansp++) & 0x3f) != 1)
|
||||
return 0; /* we only understand bitstrings */
|
||||
|
||||
count = *(ansp++); /* Bits in bitstring */
|
||||
|
||||
if (count == 0) /* count == 0 means 256 bits */
|
||||
ansp += 32;
|
||||
else
|
||||
ansp += ((count-1)>>3)+1;
|
||||
}
|
||||
else
|
||||
{ /* label type == 0 Bottom six bits is length */
|
||||
unsigned int len = (*ansp++) & 0x3f;
|
||||
|
||||
if (!ADD_RDLEN(header, ansp, plen, len))
|
||||
return 0;
|
||||
|
||||
if (len == 0)
|
||||
break; /* zero length label marks the end. */
|
||||
}
|
||||
}
|
||||
|
||||
*namep = ansp;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Go through RRs and check or fixup the domain names contained within */
|
||||
static int check_rrs(unsigned char *p, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
|
||||
{
|
||||
int i, j, type, class, rdlen;
|
||||
unsigned char *pp;
|
||||
|
||||
for (i = 0; i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount); i++)
|
||||
{
|
||||
pp = p;
|
||||
|
||||
if (!(p = skip_name(p, header, plen, 10)))
|
||||
return 0;
|
||||
|
||||
GETSHORT(type, p);
|
||||
GETSHORT(class, p);
|
||||
p += 4; /* TTL */
|
||||
GETSHORT(rdlen, p);
|
||||
|
||||
/* If this RR is to be elided, don't fix up its contents */
|
||||
for (j = 0; j < rr_count; j += 2)
|
||||
if (rrs[j] == pp)
|
||||
break;
|
||||
|
||||
if (j >= rr_count)
|
||||
{
|
||||
/* fixup name of RR */
|
||||
if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
|
||||
return 0;
|
||||
|
||||
if (class == C_IN)
|
||||
{
|
||||
u16 *d;
|
||||
|
||||
for (pp = p, d = rrfilter_desc(type); *d != (u16)-1; d++)
|
||||
{
|
||||
if (*d != 0)
|
||||
pp += *d;
|
||||
else if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* mode is 0 to remove EDNS0, 1 to filter DNSSEC RRs */
|
||||
size_t rrfilter(struct dns_header *header, size_t plen, int mode)
|
||||
{
|
||||
static unsigned char **rrs;
|
||||
static int rr_sz = 0;
|
||||
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
int i, rdlen, qtype, qclass, rr_found, chop_an, chop_ns, chop_ar;
|
||||
|
||||
if (ntohs(header->qdcount) != 1 ||
|
||||
!(p = skip_name(p, header, plen, 4)))
|
||||
return plen;
|
||||
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
|
||||
/* First pass, find pointers to start and end of all the records we wish to elide:
|
||||
records added for DNSSEC, unless explicity queried for */
|
||||
for (rr_found = 0, chop_ns = 0, chop_an = 0, chop_ar = 0, i = 0;
|
||||
i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount);
|
||||
i++)
|
||||
{
|
||||
unsigned char *pstart = p;
|
||||
int type, class;
|
||||
|
||||
if (!(p = skip_name(p, header, plen, 10)))
|
||||
return plen;
|
||||
|
||||
GETSHORT(type, p);
|
||||
GETSHORT(class, p);
|
||||
p += 4; /* TTL */
|
||||
GETSHORT(rdlen, p);
|
||||
|
||||
if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||
return plen;
|
||||
|
||||
/* Don't remove the answer. */
|
||||
if (i < ntohs(header->ancount) && type == qtype && class == qclass)
|
||||
continue;
|
||||
|
||||
if (mode == 0) /* EDNS */
|
||||
{
|
||||
/* EDNS mode, remove T_OPT from additional section only */
|
||||
if (i < (ntohs(header->nscount) + ntohs(header->ancount)) || type != T_OPT)
|
||||
continue;
|
||||
}
|
||||
else if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG)
|
||||
/* DNSSEC mode, remove SIGs and NSECs from all three sections. */
|
||||
continue;
|
||||
|
||||
|
||||
if (!expand_workspace(&rrs, &rr_sz, rr_found + 1))
|
||||
return plen;
|
||||
|
||||
rrs[rr_found++] = pstart;
|
||||
rrs[rr_found++] = p;
|
||||
|
||||
if (i < ntohs(header->ancount))
|
||||
chop_an++;
|
||||
else if (i < (ntohs(header->nscount) + ntohs(header->ancount)))
|
||||
chop_ns++;
|
||||
else
|
||||
chop_ar++;
|
||||
}
|
||||
|
||||
/* Nothing to do. */
|
||||
if (rr_found == 0)
|
||||
return plen;
|
||||
|
||||
/* Second pass, look for pointers in names in the records we're keeping and make sure they don't
|
||||
point to records we're going to elide. This is theoretically possible, but unlikely. If
|
||||
it happens, we give up and leave the answer unchanged. */
|
||||
p = (unsigned char *)(header+1);
|
||||
|
||||
/* question first */
|
||||
if (!check_name(&p, header, plen, 0, rrs, rr_found))
|
||||
return plen;
|
||||
p += 4; /* qclass, qtype */
|
||||
|
||||
/* Now answers and NS */
|
||||
if (!check_rrs(p, header, plen, 0, rrs, rr_found))
|
||||
return plen;
|
||||
|
||||
/* Third pass, elide records */
|
||||
for (p = rrs[0], i = 1; i < rr_found; i += 2)
|
||||
{
|
||||
unsigned char *start = rrs[i];
|
||||
unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)header) + plen;
|
||||
|
||||
memmove(p, start, end-start);
|
||||
p += end-start;
|
||||
}
|
||||
|
||||
plen = p - (unsigned char *)header;
|
||||
header->ancount = htons(ntohs(header->ancount) - chop_an);
|
||||
header->nscount = htons(ntohs(header->nscount) - chop_ns);
|
||||
header->arcount = htons(ntohs(header->arcount) - chop_ar);
|
||||
|
||||
/* Fourth pass, fix up pointers in the remaining records */
|
||||
p = (unsigned char *)(header+1);
|
||||
|
||||
check_name(&p, header, plen, 1, rrs, rr_found);
|
||||
p += 4; /* qclass, qtype */
|
||||
|
||||
check_rrs(p, header, plen, 1, rrs, rr_found);
|
||||
|
||||
return plen;
|
||||
}
|
||||
|
||||
/* This is used in the DNSSEC code too, hence it's exported */
|
||||
u16 *rrfilter_desc(int type)
|
||||
{
|
||||
/* List of RRtypes which include domains in the data.
|
||||
0 -> domain
|
||||
integer -> no of plain bytes
|
||||
-1 -> end
|
||||
|
||||
zero is not a valid RRtype, so the final entry is returned for
|
||||
anything which needs no mangling.
|
||||
*/
|
||||
|
||||
static u16 rr_desc[] =
|
||||
{
|
||||
T_NS, 0, -1,
|
||||
T_MD, 0, -1,
|
||||
T_MF, 0, -1,
|
||||
T_CNAME, 0, -1,
|
||||
T_SOA, 0, 0, -1,
|
||||
T_MB, 0, -1,
|
||||
T_MG, 0, -1,
|
||||
T_MR, 0, -1,
|
||||
T_PTR, 0, -1,
|
||||
T_MINFO, 0, 0, -1,
|
||||
T_MX, 2, 0, -1,
|
||||
T_RP, 0, 0, -1,
|
||||
T_AFSDB, 2, 0, -1,
|
||||
T_RT, 2, 0, -1,
|
||||
T_SIG, 18, 0, -1,
|
||||
T_PX, 2, 0, 0, -1,
|
||||
T_NXT, 0, -1,
|
||||
T_KX, 2, 0, -1,
|
||||
T_SRV, 6, 0, -1,
|
||||
T_DNAME, 0, -1,
|
||||
0, -1 /* wildcard/catchall */
|
||||
};
|
||||
|
||||
u16 *p = rr_desc;
|
||||
|
||||
while (*p != type && *p != 0)
|
||||
while (*p++ != (u16)-1);
|
||||
|
||||
return p+1;
|
||||
}
|
||||
|
||||
int expand_workspace(unsigned char ***wkspc, int *szp, int new)
|
||||
{
|
||||
unsigned char **p;
|
||||
int old = *szp;
|
||||
|
||||
if (old >= new+1)
|
||||
return 1;
|
||||
|
||||
if (new >= 100)
|
||||
return 0;
|
||||
|
||||
new += 5;
|
||||
|
||||
if (!(p = whine_malloc(new * sizeof(unsigned char *))))
|
||||
return 0;
|
||||
|
||||
if (old != 0 && *wkspc)
|
||||
{
|
||||
memcpy(p, *wkspc, old * sizeof(unsigned char *));
|
||||
free(*wkspc);
|
||||
}
|
||||
|
||||
*wkspc = p;
|
||||
*szp = new;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
|
||||
#if defined(HAVE_IPSET) && defined(HAVE_BSD_NETWORK)
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
@@ -136,7 +140,7 @@ int add_to_ipset(const char *setname, const struct all_addr *ipaddr,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rc = pfr_add_tables(&table, 1, &n, 0))
|
||||
if ((rc = pfr_add_tables(&table, 1, &n, 0)))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("warning: pfr_add_tables: %s(%d)"),
|
||||
pfr_strerror(errno),rc);
|
||||
|
||||
29
src/tftp.c
29
src/tftp.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -103,8 +103,10 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if (listen->iface)
|
||||
{
|
||||
addr = listen->iface->addr;
|
||||
mtu = listen->iface->mtu;
|
||||
name = listen->iface->name;
|
||||
mtu = listen->iface->mtu;
|
||||
if (daemon->tftp_mtu != 0 && daemon->tftp_mtu < mtu)
|
||||
mtu = daemon->tftp_mtu;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -234,9 +236,17 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
|
||||
strncpy(ifr.ifr_name, name, IF_NAMESIZE);
|
||||
if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
|
||||
mtu = ifr.ifr_mtu;
|
||||
{
|
||||
mtu = ifr.ifr_mtu;
|
||||
if (daemon->tftp_mtu != 0 && daemon->tftp_mtu < mtu)
|
||||
mtu = daemon->tftp_mtu;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Failed to get interface mtu - can use configured value. */
|
||||
if (mtu == 0)
|
||||
mtu = daemon->tftp_mtu;
|
||||
|
||||
if (name)
|
||||
{
|
||||
/* check for per-interface prefix */
|
||||
@@ -336,14 +346,15 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
{
|
||||
if ((opt = next(&p, end)) && !option_bool(OPT_TFTP_NOBLOCK))
|
||||
{
|
||||
/* 32 bytes for IP, UDP and TFTP headers, 52 bytes for IPv6 */
|
||||
int overhead = (listen->family == AF_INET) ? 32 : 52;
|
||||
transfer->blocksize = atoi(opt);
|
||||
if (transfer->blocksize < 1)
|
||||
transfer->blocksize = 1;
|
||||
if (transfer->blocksize > (unsigned)daemon->packet_buff_sz - 4)
|
||||
transfer->blocksize = (unsigned)daemon->packet_buff_sz - 4;
|
||||
/* 32 bytes for IP, UDP and TFTP headers */
|
||||
if (mtu != 0 && transfer->blocksize > (unsigned)mtu - 32)
|
||||
transfer->blocksize = (unsigned)mtu - 32;
|
||||
if (mtu != 0 && transfer->blocksize > (unsigned)mtu - overhead)
|
||||
transfer->blocksize = (unsigned)mtu - overhead;
|
||||
transfer->opt_blocksize = 1;
|
||||
transfer->block = 0;
|
||||
}
|
||||
@@ -502,7 +513,7 @@ static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
void check_tftp_listeners(time_t now)
|
||||
{
|
||||
struct tftp_transfer *transfer, *tmp, **up;
|
||||
ssize_t len;
|
||||
@@ -518,7 +529,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
|
||||
prettyprint_addr(&transfer->peer, daemon->addrbuff);
|
||||
|
||||
if (FD_ISSET(transfer->sockfd, rset))
|
||||
if (poll_check(transfer->sockfd, POLLIN))
|
||||
{
|
||||
/* we overwrote the buffer... */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
79
src/util.c
79
src/util.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -226,7 +226,14 @@ unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
|
||||
{
|
||||
unsigned char *cp = p++;
|
||||
for (j = 0; *sval && (*sval != '.'); sval++, j++)
|
||||
*p++ = *sval;
|
||||
{
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE)
|
||||
*p++ = (*(++sval))-1;
|
||||
else
|
||||
#endif
|
||||
*p++ = *sval;
|
||||
}
|
||||
*cp = j;
|
||||
if (*sval)
|
||||
sval++;
|
||||
@@ -274,6 +281,7 @@ int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2)
|
||||
#ifdef HAVE_IPV6
|
||||
if (s1->sa.sa_family == AF_INET6 &&
|
||||
s1->in6.sin6_port == s2->in6.sin6_port &&
|
||||
s1->in6.sin6_scope_id == s2->in6.sin6_scope_id &&
|
||||
IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr))
|
||||
return 1;
|
||||
#endif
|
||||
@@ -562,23 +570,27 @@ char *print_mac(char *buff, unsigned char *mac, int len)
|
||||
return buff;
|
||||
}
|
||||
|
||||
void bump_maxfd(int fd, int *max)
|
||||
{
|
||||
if (fd > *max)
|
||||
*max = fd;
|
||||
}
|
||||
|
||||
int retry_send(void)
|
||||
/* rc is return from sendto and friends.
|
||||
Return 1 if we should retry.
|
||||
Set errno to zero if we succeeded. */
|
||||
int retry_send(ssize_t rc)
|
||||
{
|
||||
static int retries = 0;
|
||||
struct timespec waiter;
|
||||
|
||||
if (rc != -1)
|
||||
{
|
||||
retries = 0;
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Linux kernels can return EAGAIN in perpetuity when calling
|
||||
sendmsg() and the relevant interface has gone. Here we loop
|
||||
retrying in EAGAIN for 1 second max, to avoid this hanging
|
||||
dnsmasq. */
|
||||
|
||||
static int retries = 0;
|
||||
struct timespec waiter;
|
||||
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
{
|
||||
waiter.tv_sec = 0;
|
||||
waiter.tv_nsec = 10000;
|
||||
@@ -586,13 +598,13 @@ int retry_send(void)
|
||||
if (retries++ < 1000)
|
||||
return 1;
|
||||
}
|
||||
|
||||
retries = 0;
|
||||
|
||||
if (errno == EINTR)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
|
||||
retries = 0;
|
||||
|
||||
if (errno == EINTR)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_write(int fd, unsigned char *packet, int size, int rw)
|
||||
@@ -601,22 +613,21 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
|
||||
|
||||
for (done = 0; done < size; done += n)
|
||||
{
|
||||
retry:
|
||||
if (rw)
|
||||
n = read(fd, &packet[done], (size_t)(size - done));
|
||||
else
|
||||
n = write(fd, &packet[done], (size_t)(size - done));
|
||||
do {
|
||||
if (rw)
|
||||
n = read(fd, &packet[done], (size_t)(size - done));
|
||||
else
|
||||
n = write(fd, &packet[done], (size_t)(size - done));
|
||||
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
} while (retry_send(n) || errno == ENOMEM || errno == ENOBUFS);
|
||||
|
||||
if (n == 0)
|
||||
return 0;
|
||||
else if (n == -1)
|
||||
{
|
||||
if (retry_send() || errno == ENOMEM || errno == ENOBUFS)
|
||||
goto retry;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
if (errno != 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user