Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91dccd0958 | ||
|
|
0a852541d3 | ||
|
|
f6b7dc47c7 | ||
|
|
bb01cb9604 | ||
|
|
59353a6b56 | ||
|
|
26128d2747 | ||
|
|
fd9fa4811d | ||
|
|
36717eeefc | ||
|
|
3be34541c2 | ||
|
|
9c74ec03ca | ||
|
|
c1bb85048b | ||
|
|
dfa666f24b | ||
|
|
feba5c1d25 |
388
CHANGELOG
388
CHANGELOG
@@ -1056,3 +1056,391 @@ release 2.9
|
||||
Allow # as the argument to --domain, meaning "read the
|
||||
domain from the first search directive in
|
||||
/etc.resolv.conf". Feature suggested by Evan Jones.
|
||||
|
||||
release 2.10
|
||||
Allow --query-port to be set to a low port by creating and
|
||||
binding the socket before dropping root. (Suggestion from
|
||||
Jamie Lokier)
|
||||
|
||||
Support TCP queries. It turned out to be possible to do
|
||||
this with a couple of hundred lines of code, once I knew
|
||||
how. The executable size went up by a few K on i386.
|
||||
There are a few limitations: data obtained via TCP is not
|
||||
cached, and dynamically-created interfaces may break under
|
||||
certain circumstances. Source-address or query-port
|
||||
specifications are ignored for TCP.
|
||||
|
||||
NAK attempts to renew a DHCP lease where the DHCP range
|
||||
has changed and the lease is no longer in the allowed
|
||||
range. Jamie Lokier pointed out this bug.
|
||||
|
||||
NAK attempts to renew a pool DHCP lease when a statically
|
||||
allocated address has become available, forcing a host to
|
||||
move to it's allocated address. Lots of people have
|
||||
suggested this change and been rebuffed (they know who
|
||||
they are) the straws that broke the camel's back were Tim
|
||||
Cutts and Jamie Lokier.
|
||||
|
||||
Remove any nameserver records from answers which are
|
||||
modified by --alias flags. If the answer is modified, it
|
||||
cannot any longer be authoritative.
|
||||
|
||||
Change behaviour of "bogus-priv" option to return NXDOMAIN
|
||||
rather than a PTR record with the dotted-quad address as
|
||||
name. The new behaviour doesn't provoke tcpwrappers like
|
||||
the old behavior did.
|
||||
|
||||
Added a patch for the Suse rpm. That changes the default
|
||||
group to one suitable for Suse and disables inclusion of
|
||||
the ISC lease-file reader code. Thanks to Andy Cambeis for
|
||||
his ongoing work on Suse packaging.
|
||||
|
||||
Support forwarding of EDNS.0 The maximum UDP packet size
|
||||
defaults to 1280, but may be changed with the
|
||||
--edns-packet-max option. Detect queries with the do bit
|
||||
set and always forward them, since DNSSEC records are
|
||||
not cached. This behaviour is required to make
|
||||
DNSSECbis work properly though dnsmasq. Thanks to Simon
|
||||
Josefsson for help with this.
|
||||
|
||||
Move default config file location under OpenBSD from
|
||||
/usr/local/etc/dnsmasq.conf to /etc/dnsmasq.conf. Bug
|
||||
report from Jonathan Weiss.
|
||||
|
||||
Use a lease with matching MAC address for a host which
|
||||
doesn't present a client-id, even if there was a client ID
|
||||
at some point in the past. This reduces surprises when
|
||||
changing DHCP clients, adding id:* to a host, and from the
|
||||
semantics change of /etc/ethers in 2.9. Thanks to Bernard
|
||||
Sammer for finding that.
|
||||
|
||||
Added a "contrib" directory and in it the dnslist utility,
|
||||
from Thomas Tuttle.
|
||||
|
||||
Fixed "fail to start up" problems under Linux with IPv6
|
||||
enabled. It's not clear that these were an issue in
|
||||
released versions, but they manifested themselves when TCP
|
||||
support was added. Thanks to Michael Hamilton for
|
||||
assistance with this.
|
||||
|
||||
version 2.11
|
||||
Fixed DHCP problem which could result in two leases in the
|
||||
database with the same address. This looked much more
|
||||
alarming then it was, since it could only happen when a
|
||||
machine changes MAC address but kept the same name. The
|
||||
old lease would persist until it timed out but things
|
||||
would still work OK.
|
||||
|
||||
Check that IP addresses in all dhcp-host directives are
|
||||
unique and die horribly if they are not, since otherwise
|
||||
endless protocol loops can occur.
|
||||
|
||||
Use IPV6_RECVPKTINFO as socket option rather than
|
||||
IPV6_PKTINFO where available. This keeps late-model FreeBSD
|
||||
happy.
|
||||
|
||||
Set source interface when replying to IPv6 UDP
|
||||
queries. This is needed to cope with link-local addresses.
|
||||
|
||||
version 2.12
|
||||
Added extra checks to ensure that DHCP created DNS entries
|
||||
cannot generate multiple DNS address->name entries. Thanks to
|
||||
Stefan Monnier for finding the exact set of configuration
|
||||
options which could create this.
|
||||
|
||||
Don't set the the filterwin2k option in the example config
|
||||
file and add warnings that is breaks Kerberos. Thanks to
|
||||
Simon Josefsson and Timothy Folks for pointing that out.
|
||||
|
||||
Log types of incoming queries as well as source and domain.
|
||||
|
||||
Log NODATA replies generated as a result of the
|
||||
filterwin2k option.
|
||||
|
||||
version 2.13
|
||||
Fixed crash with un-named DHCP hosts introduced in 2.12.
|
||||
Thanks to Nicolo Wojewoda and Gregory Gathy for bug reports.
|
||||
|
||||
version 2.14
|
||||
Fix DHCP network detection for hosts which talk via a
|
||||
relay. This makes lease renewal for such hosts work
|
||||
correctly.
|
||||
|
||||
Support RFC3011 subnet selectors in the DHCP server.
|
||||
|
||||
Fix DHCP code to generate RFC-compliant responses
|
||||
to hosts in the INIT-REBOOT state.
|
||||
|
||||
In the DHCP server, set the receive buffer size on
|
||||
the transmit-only packet socket to zero, to avoid
|
||||
waste of kernel buffers.
|
||||
|
||||
Fix DHCP address allocation code to use the whole of
|
||||
the DHCP range, including the start and end addresses.
|
||||
|
||||
Attempt an ICMP "ping" on new addresses before allocating
|
||||
them to leases, to avoid allocating addresses which are in use.
|
||||
|
||||
Handle rfc951 BOOTP as well as DHCP for hosts which have
|
||||
MAC address to IP address mapping defined.
|
||||
|
||||
Fix compilation under MacOS X. Thanks to Chris Tomlinson.
|
||||
|
||||
Fix compilation under NetBSD. Thanks to Felix Deichmann.
|
||||
|
||||
Added "keep-in-foreground" option. Thanks to Sean
|
||||
MacLennan for the patch.
|
||||
|
||||
version 2.15
|
||||
Fixed NXDOMAIN/NODATA confusion for locally known
|
||||
names. We now return a NODATA reponse for names which are
|
||||
locally known. Now a query for (eg AAAA or MX) for a name
|
||||
with an IPv4 address in /etc/hosts which fails upstream
|
||||
will generate a NODATA response. Note that the query
|
||||
is still tried upstream, but a NXDOMAIN reply gets
|
||||
converted to NODATA. Thanks to Eric de Thouars, Eric
|
||||
Spakman and Mike Mestnik for bug reports/testing.
|
||||
|
||||
Allow multiple dhcp-ranges within the same network. The
|
||||
original intention was that there would be a dhcp-range
|
||||
option for each network served, but there's no real reason
|
||||
not to allow discontinuous ranges within a network so this
|
||||
release adds support for that.
|
||||
|
||||
Check for dhcp-ranges which are inconsistent with their
|
||||
netmask, and generate errors or warnings.
|
||||
|
||||
Improve error messages when there are problems with
|
||||
configuration.
|
||||
|
||||
version 2.16
|
||||
Fixed typo in OpenBSD-only code which stopped compilation
|
||||
under that OS. Chris Weinhaupl gets credit for reporting
|
||||
this.
|
||||
|
||||
Added dhcp-authoritative option which restores non-RFC
|
||||
compliant but desirable behaviour of pre-2.14 versions and
|
||||
avoids long timeouts while DHCP clients try to renew leases
|
||||
which are unknown to dnsmasq. Thanks to John Mastwijk for
|
||||
help with this.
|
||||
|
||||
Added support to the DHCP option code to allow RFC-3397
|
||||
domain search DHCP option (119) to be sent.
|
||||
|
||||
Set NONBLOCK on all listening sockets to workaround non-POSIX
|
||||
compliance in Linux 2.4 and 2.6. This fixes rare hangs which
|
||||
occured when corrupted packets were received. Thanks to
|
||||
Joris van Rantwijk for chasing that down.
|
||||
|
||||
Updated config.h for NetBSD. Thanks to Martin Lambers.
|
||||
|
||||
Do a better job of distinguishing between retransmissions
|
||||
and new queries when forwarding. This fixes a bug
|
||||
triggered by the polipo web cache which sends A and AAAA
|
||||
queries both with the same transaction-ID. Thanks to
|
||||
Joachim Berdal Haga and Juliusz Chroboczek for help with this.
|
||||
|
||||
Rewrote cache code to store CNAMES, rather then chasing
|
||||
them before storage. This eliminates bad situations when
|
||||
clients get inconsistent views depending on if data comes
|
||||
from the cache.
|
||||
|
||||
Allow for more than one --addn-hosts flag.
|
||||
|
||||
Clarify logged message when a DHCP lease clashes with an
|
||||
/etc/hosts entry. Thanks to Mat Swift for the suggestion.
|
||||
|
||||
Added dynamic-dnsmasq from Peter Willis to the contrib
|
||||
section.
|
||||
|
||||
version 2.17
|
||||
Correctly deduce the size of numeric dhcp-options, rather
|
||||
than making wild guesses. Also cope with negative values.
|
||||
|
||||
Fixed use of C library reserved symbol "index" which broke
|
||||
under certain combinations of library and compiler.
|
||||
|
||||
Make bind-interfaces work for IPv6 interfaces too.
|
||||
|
||||
Warn if an interface is given for listening which doesn't
|
||||
currently exist when not in bind-interfaces mode. (This is
|
||||
already a fatal error when bind-interfaces is set.)
|
||||
|
||||
Allow the --interface and --except-interface options to
|
||||
take a comma-separated list of interfaces.
|
||||
|
||||
Tweak --dhcp-userclass matching code to work with the
|
||||
ISC dhclient which violates RFC3004 unless its
|
||||
configuration is very warped. Thanks to Cedric Duval for
|
||||
the bug report.
|
||||
|
||||
Allow more than one network-id tag in a dhcp-option. All
|
||||
the tags must match to enable the option.
|
||||
|
||||
Added dhcp-ignore option to disable classes of hosts based
|
||||
on network-id tags. Also allow BOOTP options to be
|
||||
controlled by network tags.
|
||||
|
||||
Fill in sname, file and siaddr fields in replies to
|
||||
DHCPINFORM messages.
|
||||
|
||||
Don't send NAK replies to DHCPREQUEST packets for disabled
|
||||
clients. Credit to Cedric Duval for spotting this.
|
||||
|
||||
Fix rare crash associated with long DNS names and CNAME
|
||||
records. Thanks to Holger Hoffstatte and especially Steve
|
||||
Grecni for help chasing that one down.
|
||||
|
||||
version 2.18
|
||||
Reworked the Linux interface discovery code (again) to
|
||||
cope with interfaces which have only IPv6 addresses and
|
||||
interfaces with more than one IPv6 address. Thanks to
|
||||
Martin Pels for help with that.
|
||||
|
||||
Fix problems which occured when more than one dhcp-range
|
||||
was specified in the same subnet: sometimes parameters
|
||||
(lease time, network-id tag) from the wrong one would be
|
||||
used. Thanks to Rory Campbell-Lange for the bug report.
|
||||
|
||||
Reset cache statistics when clearing the cache.
|
||||
|
||||
Enable long command line options on FreeBSD when the
|
||||
C library supports them.
|
||||
|
||||
version 2.19
|
||||
Tweaked the Linux-only interface discovery code to cope
|
||||
with interface-indexes larger than 8 bits in
|
||||
/proc/net/if_inet6. This only affects Linux, obviously.
|
||||
Thanks to Richard Atterer for the bug report.
|
||||
|
||||
Check for under-length option fields in DHCP packets, a
|
||||
zero length client-id, in particluar, could seriously
|
||||
confuse dnsmasq 'till now. Thanks to Will Murname for help
|
||||
with that.
|
||||
|
||||
If a DHCP-allocated address has an associated name in
|
||||
/etc/hosts, and the client does not provide a hostname
|
||||
parameter and there is no hostname in a matching dhcp-host
|
||||
option, send the /etc/hosts name as the hostname in
|
||||
the DHCP lease. Thanks to Will Murname for the suggestion.
|
||||
|
||||
version 2.20
|
||||
Allow more than one instance of dnsmasq to run on a
|
||||
machine, each providing DHCP service on a different
|
||||
interface, provided that --bind-interfaces is set. This
|
||||
configuration used to work, but regressed in version 2.14
|
||||
|
||||
Fix compilation on Mac OS X. Thanks to Kevin Bullock.
|
||||
|
||||
Protect against overlong names and overlong
|
||||
labels in configuration and from DHCP.
|
||||
|
||||
Fix interesting corner case in CNAME handling. This occurs
|
||||
when a CNAME has a target which "shadowed" by a name in
|
||||
/etc/hosts or from DHCP. Resolving the CNAME would sneak
|
||||
the upstream value of the CNAME's target into the cache,
|
||||
alongside the local value. Now that doesn't happen, though
|
||||
resolving the CNAME still gives the unshadowed value. This
|
||||
is arguably wrong but rather difficult to fix. The main
|
||||
thing is to avoid getting strange results for the target
|
||||
due to the cache pollution when resolving the
|
||||
CNAME. Thanks to Pierre Habouzit for exploring the corner
|
||||
and submitting a very clear bug report.
|
||||
|
||||
Fix subtle bug in the DNS packet parsing code. It's almost
|
||||
impossible to describe this succinctly, but the one known
|
||||
manifestation is the inability to cache the A record for
|
||||
www.apple.com. Thanks to Bob Alexander for spotting that.
|
||||
|
||||
Support SRV records. Thanks to Robert Kean for the patches
|
||||
for this.
|
||||
|
||||
Fixed sign confusion in the vendor-id matching code which
|
||||
could cause crashes sometimes. (Credit to Mark Wiater for
|
||||
help finding this.)
|
||||
|
||||
Added the ability to match the netid tag in a
|
||||
dhcp-range. Combined with the ability to have multiple
|
||||
ranges in a single subnet, this provides a means to
|
||||
segregate hosts on different address ranges based on
|
||||
vendorclass or userclass. Thanks to Mark Wiater for
|
||||
prompting this enhancement.
|
||||
|
||||
Added preference values for MX records.
|
||||
|
||||
Added the --localise-queries option.
|
||||
|
||||
version 2.21
|
||||
Improve handling of SERVFAIL and REFUSED errors. Receiving
|
||||
these now initiates search for a new good server, and a
|
||||
server which returns them is not a candidate as a good
|
||||
server. Thanks to Istvan Varadi for pointing out the
|
||||
problem.
|
||||
|
||||
Tweak the time code in BROKEN_RTC mode.
|
||||
|
||||
Sanity check lease times in dhcp-range and dhcp-host
|
||||
configurations and force them to be at least two minutes
|
||||
(120s) leases shorter than a minute confuse some clients,
|
||||
notably Apple MacOS X. Rory Campbell-Lange found this
|
||||
problem.
|
||||
|
||||
Only warn once about an upstream server which is refusing to do
|
||||
recursive queries.
|
||||
|
||||
Fix DHCP address allocation problem when netid tags are in
|
||||
use. Thanks to Will Murnane for the bug report and
|
||||
subsequent testing.
|
||||
|
||||
Add an additional data section to the reply for MX and SRV
|
||||
queries. Add support for DNS TXT records. Thanks to Robert
|
||||
Kean and John Hampton for prompts and testing of these.
|
||||
|
||||
Apply address rewriting to records in the additional data section
|
||||
of DNS packets. This makes things like MX records work
|
||||
with the alias function. Thanks to Chad Skeeters for
|
||||
pointing out the need for this.
|
||||
|
||||
Added support for quoted strings in config file.
|
||||
|
||||
Detect and defeat cache-poisoning attacks which attempt to
|
||||
send (malicious) answers to questions we didn't
|
||||
send. These are ignored now even if the attacker manages
|
||||
to guess a random query-id.
|
||||
|
||||
Provide DHCP support for interfaces with multiple IP
|
||||
addresses or aliases. This in only enabled under Linux.
|
||||
See the FAQ entry for details.
|
||||
|
||||
Revisit the MAC-address and client-id matching code to
|
||||
provide saner behaviour with PXE boots, where some
|
||||
requests have a client-id and some don't.
|
||||
|
||||
Fixed off-by-one buffer overflow in lease file reading
|
||||
code. Thanks to Rob Holland for the bug report.
|
||||
|
||||
Added wildcard matching for MAC addresses in dhcp-host
|
||||
options. A sensible suggestion by Nathaniel McCallum.
|
||||
|
||||
version 2.22
|
||||
Fixed build problems on (many) systems with older libc
|
||||
headers where <linux/types.h> is required before
|
||||
<linux/netlink.h>. Enabled HAVE_RTNETLINK under uclibc now
|
||||
that this fix is in place.
|
||||
|
||||
Added support for encapsulated vendor-class-specific DHCP
|
||||
options. Thanks to Eric Shattow for help with this.
|
||||
|
||||
Fix regression in 2.21 which broke commas in filenames and
|
||||
corrupted argv. Thanks to Eric Scott for the bugreport.
|
||||
|
||||
Fixed stupid thinko which caused dnsmasq to wedge during
|
||||
startup with certain MX-record options. Another 2.21 regression.
|
||||
|
||||
Fixed broken-ness when reading /etc/ethers. 2.21 broke
|
||||
this too.
|
||||
|
||||
Fixed wedge with certain DHCP options. Yet another 2.21
|
||||
regression. Rob Holland and Roy Marples chased this one
|
||||
down.
|
||||
|
||||
|
||||
91
FAQ
91
FAQ
@@ -20,12 +20,9 @@ A: The high ports that dnsmasq opens is for replies from the upstream
|
||||
Q: Why doesn't dnsmasq support DNS queries over TCP? Don't the RFC's specify
|
||||
that?
|
||||
|
||||
A: Yes, they do, so technically dnsmasq is not RFC-compliant. In practice, the
|
||||
sorts of queries which dnsmasq is used for are always sent via UDP. Adding
|
||||
TCP support would make dnsmasq much more heavyweight for no practical
|
||||
benefit. If you really want to do zone transfers, forward port 53 TCP
|
||||
using in-kernel port-forwarding or a port-fowarder like rinetd.
|
||||
|
||||
A: Update: from version 2.10, it does. There are a few limitations:
|
||||
data obtained via TCP is not cached, and source-address
|
||||
or query-port specifications are ignored for TCP.
|
||||
|
||||
Q: When I send SIGUSR1 to dump the contents of the cache, some entries have
|
||||
no IP address and are for names like mymachine.mydomain.com.mydomain.com.
|
||||
@@ -74,6 +71,8 @@ A: Use the standard DNS convention of <reversed address>.in-addr.arpa.
|
||||
For instance to send reverse queries on the range 192.168.0.0 to
|
||||
192.168.0.255 to a nameserver at 10.0.0.1 do
|
||||
server=/0.168.192.in-addr.arpa/10.0.0.1
|
||||
Note that the "bogus-priv" option take priority over this option,
|
||||
so the above will not work when the bogus-priv option is set.
|
||||
|
||||
Q: Dnsmasq fails to start with an error like this: "dnsmasq: bind
|
||||
failed: Cannot assign requested address". What's the problem?
|
||||
@@ -112,10 +111,10 @@ A: Resolver code sometime does strange things when given names without
|
||||
resolver will attempt to look up "myhost.localnet" so you need to
|
||||
have dnsmasq reply to that name. The way to do that is to include
|
||||
the domain in each name on /etc/hosts and/or to use the
|
||||
--expand-hosts and --domain-suffix options.
|
||||
--expand-hosts and --domain options.
|
||||
|
||||
Q: Can I get dnsmasq to save the contents of its cache to disk when
|
||||
I shut my machine down and re-load when it starts again.
|
||||
I shut my machine down and re-load when it starts again?
|
||||
|
||||
A: No, that facility is not provided. Very few names in the DNS have
|
||||
their time-to-live set for longer than a few hours so most of the
|
||||
@@ -190,7 +189,8 @@ A: By default, none of the DHCP clients send the host-name when asking
|
||||
send with the "hostname" keyword in /etc/network/interfaces. (See
|
||||
"man interfaces" for details.) That doesn't work for dhclient, were
|
||||
you have to add something like "send host-name daisy" to
|
||||
/etc/dhclient.conf
|
||||
/etc/dhclient.conf [Update: the lastest dhcpcd packages _do_ send
|
||||
the hostname by default.
|
||||
|
||||
Q: I'm network booting my machines, and trying to give them static
|
||||
DHCP-assigned addresses. The machine gets its correct address
|
||||
@@ -268,4 +268,77 @@ A: The DNS spec says that the reply to a DNS query must come from the
|
||||
(address,port) pair when dnsmasq has bound (wildcard,port), hence
|
||||
the ability to explicitly turn off wildcard binding.
|
||||
|
||||
Q: Why doesn't Kerberos work/why can't I get sensible answers to
|
||||
queries for SRV records.
|
||||
|
||||
A: Probably because you have the "filterwin2k" option set. Note that
|
||||
it was on by default in example configuration files included in
|
||||
versions before 2.12, so you might have it set on without
|
||||
realising.
|
||||
|
||||
Q: Can I get email notification when a new version of dnsmasq is
|
||||
released?
|
||||
|
||||
A: Yes, new releases of dnsmasq are always announced through
|
||||
freshmeat.net, and they allow you to subcribe to email alerts when
|
||||
new versions of particular projects are released.
|
||||
|
||||
Q: What does the dhcp-authoritative option do?
|
||||
|
||||
A: See http://www.isc.org/index.pl?/sw/dhcp/authoritative.php - that's
|
||||
for the ISC daemon, but the same applies to dnsmasq.
|
||||
|
||||
Q: Why does my Gentoo box pause for a minute before getting a new
|
||||
lease?
|
||||
|
||||
A: Because when a Gentoo box shuts down, it releases its lease with
|
||||
the server but remembers it on the client; this seems to be a
|
||||
Gentoo-specific patch to dhcpcd. On restart it tries to renew
|
||||
a lease which is long gone, as far as dnsmasq is concerned, and
|
||||
dnsmasq ignores it until is times out and restarts the process.
|
||||
To fix this, set the dhcp-authoritative flag in dnsmasq.
|
||||
|
||||
Q: My laptop has two network interfaces, a wired one and a wireless
|
||||
one. I never use both interfaces at the same time, and I'd like the
|
||||
same IP and configuration to be used irrespcetive of which
|
||||
interface is in use. How can I do that.
|
||||
|
||||
A: By default, the identity of a machine is determined by using the
|
||||
MAC address, which is associated with interface hardware. Once an
|
||||
IP is bound to the MAC address of one interface, it cannot be
|
||||
associated with another MAC address until after the DHCP lease
|
||||
expires. The solution to this is to use a client-id as the machine
|
||||
identity rather than the MAC address. If you arrange for the same
|
||||
client-id to sent when either interface is in use, the DHCP server
|
||||
will recognise the same machine, and use the same address. The
|
||||
method for setting the client-id varies with DHCP client software,
|
||||
dhcpcd uses the "-I" flag. Windows uses a registry setting,
|
||||
see http://www.jsiinc.com/SUBF/TIP2800/rh2845.htm
|
||||
|
||||
Q: Can dnsmasq do DHCP on IP-alias interfaces?
|
||||
|
||||
A: Yes, from version-2.21. The support is only available running under
|
||||
Linux, on a kernel which provides the RT-netlink facility. All 2.4
|
||||
and 2.6 kernels provide RT-netlink and it's an option in 2.2
|
||||
kernels. If dnsmasq is built under uclibc, even on Linux, then
|
||||
the support is not included.
|
||||
|
||||
If a physical interface has more than one IP address or aliases
|
||||
with extra IP addresses, then any dhcp-ranges corresponding to
|
||||
these addresses can be used for address allocation. So is and
|
||||
interface has addresses 192.168.1.0/24 and 192.68.2.0/24 and there
|
||||
are DHCP ranges 192.168.1.100-192.168.1.200 and
|
||||
192.168.2.100-192.168.2.200 then both ranges would be used for host
|
||||
connected to the physical interface. A more typical use might be to
|
||||
have one of the address-ranges as static-only, and have known
|
||||
hosts allocated addresses on that subnet using dhcp-host options,
|
||||
while anonymous hosts go on the other.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
2
Makefile
2
Makefile
@@ -10,7 +10,7 @@ all :
|
||||
@cd $(SRC); $(MAKE) dnsmasq
|
||||
|
||||
clean :
|
||||
rm -f *~ */*~ $(SRC)/*.o $(SRC)/dnsmasq core build
|
||||
rm -f *~ contrib/*/*~ */*~ $(SRC)/*.o $(SRC)/dnsmasq core build
|
||||
|
||||
install : all
|
||||
install -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8
|
||||
|
||||
57
contrib/dnslist/dhcp.css
Normal file
57
contrib/dnslist/dhcp.css
Normal file
@@ -0,0 +1,57 @@
|
||||
body
|
||||
{
|
||||
font-family: sans-serif;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
h1
|
||||
{
|
||||
font-size: medium;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h1 .updated
|
||||
{
|
||||
color: #999;
|
||||
}
|
||||
|
||||
table
|
||||
{
|
||||
border-collapse: collapse;
|
||||
border-bottom: 2px solid #000;
|
||||
}
|
||||
|
||||
th
|
||||
{
|
||||
background: #DDD;
|
||||
border-top: 2px solid #000;
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Any row */
|
||||
|
||||
tr
|
||||
{
|
||||
border-top: 2px solid #000;
|
||||
}
|
||||
|
||||
/* Any row but the first or second (overrides above rule) */
|
||||
|
||||
tr + tr + tr
|
||||
{
|
||||
border-top: 2px solid #999;
|
||||
}
|
||||
|
||||
tr.offline td.hostname
|
||||
{
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.hostname { width: 10em; }
|
||||
.ip_addr { width: 10em; background: #DDD; }
|
||||
.ether_addr { width: 15em; }
|
||||
.client_id { width: 15em; background: #DDD; }
|
||||
.status { width: 5em; }
|
||||
.since { width: 10em; background: #DDD; }
|
||||
.lease { width: 10em; }
|
||||
608
contrib/dnslist/dnslist.pl
Executable file
608
contrib/dnslist/dnslist.pl
Executable file
@@ -0,0 +1,608 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# dnslist - Read state file from dnsmasq and create a nice web page to display
|
||||
# a list of DHCP clients.
|
||||
#
|
||||
# Copyright (C) 2004 Thomas Tuttle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program*; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# * The license is in fact included at the end of this file, and can
|
||||
# either be viewed by reading everything after "__DATA__" or by
|
||||
# running dnslist with the '-l' option.
|
||||
#
|
||||
# Version: 0.2
|
||||
# Author: Thomas Tuttle
|
||||
# Email: dnslist.20.thinkinginbinary@spamgourmet.org
|
||||
# License: GNU General Public License, version 2.0
|
||||
#
|
||||
# v. 0.0: Too ugly to publish, thrown out.
|
||||
#
|
||||
# v. 0.1: First rewrite.
|
||||
# Added master host list so offline hosts can still be displayed.
|
||||
# Fixed modification detection (a newer modification time is lower.)
|
||||
#
|
||||
# v. 0.2: Fixed Client ID = "*" => "None"
|
||||
# Fixed HTML entities (a client ID of ????<? screwed it up)
|
||||
# Fixed command-line argument processing (apparently, "shift @ARGV" !=
|
||||
# "$_ = shift @ARGV"...)
|
||||
# Added license information.
|
||||
|
||||
use Template;
|
||||
|
||||
# Location of state file. (This is the dnsmasq default.)
|
||||
# Change with -s <file>
|
||||
my $dnsmasq_state_file = '/var/lib/misc/dnsmasq.leases';
|
||||
# Location of template. (Assumed to be in current directory.)
|
||||
# Change with -t <file>
|
||||
my $html_template_file = 'dnslist.tt2';
|
||||
# File to write HTML page to. (This is where Slackware puts WWW pages. It may
|
||||
# be different on other systems. Make sure the permissions are set correctly
|
||||
# for it.)
|
||||
my $html_output_file = '/var/www/htdocs/dhcp.html';
|
||||
# Time to wait after each page update. (The state file is checked for changes
|
||||
# before each update but is not read in each time, in case it is very big. The
|
||||
# page is rewritten just so the "(updated __/__ __:__:__)" text changes ;-)
|
||||
my $wait_time = 2;
|
||||
|
||||
# Read command-line arguments.
|
||||
while ($_ = shift @ARGV) {
|
||||
if (/-s/) { $dnsmasq_state_file = shift; next; }
|
||||
if (/-t/) { $html_template_file = shift; next; }
|
||||
if (/-o/) { $html_output_file = shift; next; }
|
||||
if (/-d/) { $wait_time = shift; next; }
|
||||
if (/-l/) { show_license(); exit; }
|
||||
die "usage: dnslist [-s state_file] [-t template_file] [-o output_file] [-d delay_time]\n";
|
||||
}
|
||||
|
||||
# Master list of clients, offline and online.
|
||||
my $list = {};
|
||||
# Sorted host list. (It's actually sorted by IP--the sub &byip() compares two
|
||||
# IP addresses, octet by octet, and figures out which is higher.)
|
||||
my @hosts = ();
|
||||
# Last time the state file was changed.
|
||||
my $last_state_change;
|
||||
|
||||
# Check for a change to the state file.
|
||||
sub check_state {
|
||||
if (defined $last_state_change) {
|
||||
if (-M $dnsmasq_state_file < $last_state_change) {
|
||||
print "check_state: state file has been changed.\n";
|
||||
$last_state_change = -M $dnsmasq_state_file;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
# Last change undefined, so we are running for the first time.
|
||||
print "check_state: reading state file at startup.\n";
|
||||
read_state();
|
||||
$last_state_change = -M $dnsmasq_state_file;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
# Read data in state file.
|
||||
sub read_state {
|
||||
my $old;
|
||||
my $new;
|
||||
# Open file.
|
||||
unless (open STATE, $dnsmasq_state_file) {
|
||||
warn "read_state: can't open $dnsmasq_state_file!\n";
|
||||
return 0;
|
||||
}
|
||||
# Mark all hosts as offline, saving old state.
|
||||
foreach $ether (keys %{$list}) {
|
||||
$list->{$ether}->{'old_online'} = $list->{$ether}->{'online'};
|
||||
$list->{$ether}->{'online'} = 0;
|
||||
}
|
||||
# Read hosts.
|
||||
while (<STATE>) {
|
||||
chomp;
|
||||
@host{qw/raw_lease ether_addr ip_addr hostname raw_client_id/} = split /\s+/;
|
||||
$ether = $host{ether_addr};
|
||||
# Mark each online host as online.
|
||||
$list->{$ether}->{'online'} = 1;
|
||||
# Copy data to master list.
|
||||
foreach $key (keys %host) {
|
||||
$list->{$ether}->{$key} = $host{$key};
|
||||
}
|
||||
}
|
||||
close STATE;
|
||||
# Handle changes in offline/online state. (The sub &do_host() handles
|
||||
# all of the extra stuff to do with a host's data once it is read.
|
||||
foreach $ether (keys %{$list}) {
|
||||
$old = $list->{$ether}->{'old_online'};
|
||||
$new = $list->{$ether}->{'online'};
|
||||
if (not $old) {
|
||||
if (not $new) {
|
||||
do_host($ether, 'offline');
|
||||
} else {
|
||||
do_host($ether, 'join');
|
||||
}
|
||||
} else {
|
||||
if (not $new) {
|
||||
do_host($ether, 'leave');
|
||||
} else {
|
||||
do_host($ether, 'online');
|
||||
}
|
||||
}
|
||||
}
|
||||
# Sort hosts by IP ;-)
|
||||
@hosts = sort byip values %{$list};
|
||||
# Copy sorted list to template data store.
|
||||
$data->{'hosts'} = [ @hosts ];
|
||||
}
|
||||
|
||||
# Do stuff per host.
|
||||
sub do_host {
|
||||
my ($ether, $status) = @_;
|
||||
|
||||
# Find textual representation of DHCP client ID.
|
||||
if ($list->{$ether}->{'raw_client_id'} eq '*') {
|
||||
$list->{$ether}->{'text_client_id'} = 'None';
|
||||
} else {
|
||||
my $text = "";
|
||||
foreach $char (split /:/, $list->{$ether}->{'raw_client_id'}) {
|
||||
$char = pack('H2', $char);
|
||||
if (ord($char) >= 32 and ord($char) <= 127) {
|
||||
$text .= $char;
|
||||
} else {
|
||||
$text .= "?";
|
||||
}
|
||||
}
|
||||
$list->{$ether}->{'text_client_id'} = $text;
|
||||
}
|
||||
|
||||
# Convert lease expiration date/time to text.
|
||||
if ($list->{$ether}->{'raw_lease'} == 0) {
|
||||
$list->{$ether}->{'text_lease'} = 'Never';
|
||||
} else {
|
||||
$list->{$ether}->{'text_lease'} = nice_time($list->{$ether}->{'raw_lease'});
|
||||
}
|
||||
|
||||
if ($status eq 'offline') {
|
||||
# Nothing to do.
|
||||
} elsif ($status eq 'online') {
|
||||
# Nothing to do.
|
||||
} elsif ($status eq 'join') {
|
||||
# Update times for joining host.
|
||||
print "do_host: $ether joined the network.\n";
|
||||
$list->{$ether}->{'join_time'} = time;
|
||||
$list->{$ether}->{'since'} = nice_time(time);
|
||||
} elsif ($status eq 'leave') {
|
||||
# Update times for leaving host.
|
||||
print "do_host: $ether left the network.\n";
|
||||
$list->{$ether}->{'leave_time'} = time;
|
||||
$list->{$ether}->{'since'} = nice_time(time);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# Convert time to a string representation.
|
||||
sub nice_time {
|
||||
my $time = shift;
|
||||
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $dst) = localtime($time);
|
||||
$sec = pad($sec, '0', 2);
|
||||
$min = pad($min, '0', 2);
|
||||
$hour = pad($hour, '0', 2);
|
||||
$mon = pad($mon, '0', 2);
|
||||
$mday = pad($mday, '0', 2);
|
||||
return "$mon/$mday $hour:$min:$sec";
|
||||
}
|
||||
|
||||
# Pad string to a certain length by repeatedly prepending another string.
|
||||
sub pad {
|
||||
my ($text, $pad, $length) = @_;
|
||||
while (length($text) < $length) {
|
||||
$text = "$pad$text";
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
# Compare two IP addresses. (Uses $a and $b from sort.)
|
||||
sub byip {
|
||||
# Split into octets.
|
||||
my @a = split /\./, $a->{ip_addr};
|
||||
my @b = split /\./, $b->{ip_addr};
|
||||
# Compare octets.
|
||||
foreach $n (0..3) {
|
||||
return $a[$n] <=> $b[$n] if ($a[$n] != $b[$n]);
|
||||
}
|
||||
# If we get here there is no difference.
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Output HTML file.
|
||||
sub write_output {
|
||||
# Create new template object.
|
||||
my $template = Template->new(
|
||||
{
|
||||
ABSOLUTE => 1, # /var/www/... is an absolute path
|
||||
OUTPUT => $html_output_file # put it here, not STDOUT
|
||||
}
|
||||
);
|
||||
$data->{'updated'} = nice_time(time); # add "(updated ...)" to file
|
||||
unless ($template->process($html_template_file, $data)) { # do it
|
||||
warn "write_output: Template Toolkit error: " . $template->error() . "\n";
|
||||
return 0;
|
||||
}
|
||||
print "write_output: page updated.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub show_license {
|
||||
while (<DATA>) {
|
||||
print;
|
||||
$line++;
|
||||
if ($line == 24) { <>; $line = 1; }
|
||||
}
|
||||
}
|
||||
|
||||
# Main loop.
|
||||
while (1) {
|
||||
# Check for state change.
|
||||
if (check_state()) {
|
||||
read_state();
|
||||
sleep 1; # Sleep for a second just so we don't wear anything
|
||||
# out. (By not sleeping the whole time after a change
|
||||
# we can detect rapid changes more easily--like if 300
|
||||
# hosts all come back online, they show up quicker.)
|
||||
} else {
|
||||
sleep $wait_time; # Take a nap.
|
||||
}
|
||||
write_output(); # Write the file anyway.
|
||||
}
|
||||
__DATA__
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
32
contrib/dnslist/dnslist.tt2
Normal file
32
contrib/dnslist/dnslist.tt2
Normal file
@@ -0,0 +1,32 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>DHCP Clients</title>
|
||||
<link rel="stylesheet" href="dhcp.css"/>
|
||||
<meta http-equiv="Refresh" content="2"/>
|
||||
</head>
|
||||
<body>
|
||||
<h1>DHCP Clients <span class="updated">(updated [% updated %])</span></h1>
|
||||
<table cols="7">
|
||||
<tr>
|
||||
<th class="hostname">Hostname</th>
|
||||
<th class="ip_addr">IP Address</th>
|
||||
<th class="ether_addr">Ethernet Address</th>
|
||||
<th class="client_id">DHCP Client ID</th>
|
||||
<th class="status">Status</th>
|
||||
<th class="since">Since</th>
|
||||
<th class="lease">Lease Expires</th>
|
||||
</tr>
|
||||
[% FOREACH host IN hosts %]
|
||||
<tr class="[% IF host.online %]online[% ELSE %]offline[% END %]">
|
||||
<td class="hostname">[% host.hostname %]</td>
|
||||
<td class="ip_addr">[% host.ip_addr %]</td>
|
||||
<td class="ether_addr">[% host.ether_addr %]</td>
|
||||
<td class="client_id">[% host.text_client_id %] ([% host.raw_client_id %])</td>
|
||||
<td class="status">[% IF host.online %]Online[% ELSE %]Offline[% END %]</td>
|
||||
<td class="since">[% host.since %]</td>
|
||||
<td class="lease">[% host.text_lease %]</td>
|
||||
</tr>
|
||||
[% END %]
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
249
contrib/dynamic-dnsmasq/dynamic-dnsmasq.pl
Executable file
249
contrib/dynamic-dnsmasq/dynamic-dnsmasq.pl
Executable file
@@ -0,0 +1,249 @@
|
||||
#!/usr/bin/perl
|
||||
# dynamic-dnsmasq.pl - update dnsmasq's internal dns entries dynamically
|
||||
# Copyright (C) 2004 Peter Willis
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# the purpose of this script is to be able to update dnsmasq's dns
|
||||
# records from a remote dynamic dns client.
|
||||
#
|
||||
# basic use of this script:
|
||||
# dynamic-dnsmasq.pl add testaccount 1234 testaccount.mydomain.com
|
||||
# dynamic-dnsmasq.pl listen &
|
||||
#
|
||||
# this script tries to emulate DynDNS.org's dynamic dns service, so
|
||||
# technically you should be able to use any DynDNS.org client to
|
||||
# update the records here. tested and confirmed to work with ddnsu
|
||||
# 1.3.1. just point the client's host to the IP of this machine,
|
||||
# port 9020, and include the hostname, user and pass, and it should
|
||||
# work.
|
||||
#
|
||||
# make sure "addn-hosts=/etc/dyndns-hosts" is in your /etc/dnsmasq.conf
|
||||
# file and "nopoll" is commented out.
|
||||
|
||||
use strict;
|
||||
use IO::Socket;
|
||||
use MIME::Base64;
|
||||
use DB_File;
|
||||
use Fcntl;
|
||||
|
||||
my $accountdb = "accounts.db";
|
||||
my $recordfile = "/etc/dyndns-hosts";
|
||||
my $dnsmasqpidfile = "/var/run/dnsmasq.pid"; # if this doesn't exist, will look for process in /proc
|
||||
my $listenaddress = "0.0.0.0";
|
||||
my $listenport = 9020;
|
||||
|
||||
# no editing past this point should be necessary
|
||||
|
||||
if ( @ARGV < 1 ) {
|
||||
die "Usage: $0 ADD|DEL|LISTUSERS|WRITEHOSTSFILE|LISTEN\n";
|
||||
} elsif ( lc $ARGV[0] eq "add" ) {
|
||||
die "Usage: $0 ADD USER PASS HOSTNAME\n" unless @ARGV == 4;
|
||||
add_acct($ARGV[1], $ARGV[2], $ARGV[3]);
|
||||
} elsif ( lc $ARGV[0] eq "del" ) {
|
||||
die "Usage: $0 DEL USER\n" unless @ARGV == 2;
|
||||
print "Are you sure you want to delete user \"$ARGV[1]\"? [N/y] ";
|
||||
my $resp = <STDIN>;
|
||||
chomp $resp;
|
||||
if ( lc substr($resp,0,1) eq "y" ) {
|
||||
del_acct($ARGV[1]);
|
||||
}
|
||||
} elsif ( lc $ARGV[0] eq "listusers" or lc $ARGV[0] eq "writehostsfile" ) {
|
||||
my $X = tie my %h, "DB_File", $accountdb, O_RDWR|O_CREAT, 0600, $DB_HASH;
|
||||
my $fh;
|
||||
if ( lc $ARGV[0] eq "writehostsfile" ) {
|
||||
open($fh, ">$recordfile") || die "Couldn't open recordfile \"$recordfile\": $!\n";
|
||||
flock($fh, 2);
|
||||
seek($fh, 0, 0);
|
||||
truncate($fh, 0);
|
||||
}
|
||||
while ( my ($key, $val) = each %h ) {
|
||||
my ($pass, $domain, $ip) = split("\t",$val);
|
||||
if ( lc $ARGV[0] eq "listusers" ) {
|
||||
print "user $key, hostname $domain, ip $ip\n";
|
||||
} else {
|
||||
if ( defined $ip ) {
|
||||
print $fh "$ip\t$domain\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( lc $ARGV[0] eq "writehostsfile" ) {
|
||||
flock($fh, 8);
|
||||
close($fh);
|
||||
dnsmasq_rescan_configs();
|
||||
}
|
||||
undef $X;
|
||||
untie %h;
|
||||
} elsif ( lc $ARGV[0] eq "listen" ) {
|
||||
listen_for_updates();
|
||||
}
|
||||
|
||||
sub listen_for_updates {
|
||||
my $sock = IO::Socket::INET->new(Listen => 5,
|
||||
LocalAddr => $listenaddress, LocalPort => $listenport,
|
||||
Proto => 'tcp', ReuseAddr => 1,
|
||||
MultiHomed => 1) || die "Could not open listening socket: $!\n";
|
||||
$SIG{'CHLD'} = 'IGNORE';
|
||||
while ( my $client = $sock->accept() ) {
|
||||
my $p = fork();
|
||||
if ( $p != 0 ) {
|
||||
next;
|
||||
}
|
||||
$SIG{'CHLD'} = 'DEFAULT';
|
||||
my @headers;
|
||||
my %cgi;
|
||||
while ( <$client> ) {
|
||||
s/(\r|\n)//g;
|
||||
last if $_ eq "";
|
||||
push @headers, $_;
|
||||
}
|
||||
foreach my $header (@headers) {
|
||||
if ( $header =~ /^GET \/nic\/update\?([^\s].+) HTTP\/1\.[01]$/ ) {
|
||||
foreach my $element (split('&', $1)) {
|
||||
$cgi{(split '=', $element)[0]} = (split '=', $element)[1];
|
||||
}
|
||||
} elsif ( $header =~ /^Authorization: basic (.+)$/ ) {
|
||||
unless ( defined $cgi{'hostname'} ) {
|
||||
print_http_response($client, undef, "badsys");
|
||||
exit(1);
|
||||
}
|
||||
if ( !exists $cgi{'myip'} ) {
|
||||
$cgi{'myip'} = $client->peerhost();
|
||||
}
|
||||
my ($user,$pass) = split ":", MIME::Base64::decode($1);
|
||||
if ( authorize($user, $pass, $cgi{'hostname'}, $cgi{'myip'}) == 0 ) {
|
||||
print_http_response($client, $cgi{'myip'}, "good");
|
||||
update_dns(\%cgi);
|
||||
} else {
|
||||
print_http_response($client, undef, "badauth");
|
||||
exit(1);
|
||||
}
|
||||
last;
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
sub add_acct {
|
||||
my ($user, $pass, $hostname) = @_;
|
||||
my $X = tie my %h, "DB_File", $accountdb, O_RDWR|O_CREAT, 0600, $DB_HASH;
|
||||
$X->put($user, join("\t", ($pass, $hostname)));
|
||||
undef $X;
|
||||
untie %h;
|
||||
}
|
||||
|
||||
sub del_acct {
|
||||
my ($user, $pass, $hostname) = @_;
|
||||
my $X = tie my %h, "DB_File", $accountdb, O_RDWR|O_CREAT, 0600, $DB_HASH;
|
||||
$X->del($user);
|
||||
undef $X;
|
||||
untie %h;
|
||||
}
|
||||
|
||||
|
||||
sub authorize {
|
||||
my $user = shift;
|
||||
my $pass = shift;
|
||||
my $hostname = shift;
|
||||
my $ip = shift;;
|
||||
my $X = tie my %h, "DB_File", $accountdb, O_RDWR|O_CREAT, 0600, $DB_HASH;
|
||||
my ($spass, $shost) = split("\t", $h{$user});
|
||||
if ( defined $h{$user} and ($spass eq $pass) and ($shost eq $hostname) ) {
|
||||
$X->put($user, join("\t", $spass, $shost, $ip));
|
||||
undef $X;
|
||||
untie %h;
|
||||
return(0);
|
||||
}
|
||||
undef $X;
|
||||
untie %h;
|
||||
return(1);
|
||||
}
|
||||
|
||||
sub print_http_response {
|
||||
my $sock = shift;
|
||||
my $ip = shift;
|
||||
my $response = shift;
|
||||
print $sock "HTTP/1.0 200 OK\n";
|
||||
my @tmp = split /\s+/, scalar gmtime();
|
||||
print $sock "Date: $tmp[0], $tmp[2] $tmp[1] $tmp[4] $tmp[3] GMT\n";
|
||||
print $sock "Server: Peter's Fake DynDNS.org Server/1.0\n";
|
||||
print $sock "Content-Type: text/plain; charset=ISO-8859-1\n";
|
||||
print $sock "Connection: close\n";
|
||||
print $sock "Transfer-Encoding: chunked\n";
|
||||
print $sock "\n";
|
||||
#print $sock "12\n"; # this was part of the dyndns response but i'm not sure what it is
|
||||
print $sock "$response", defined($ip)? " $ip" : "" . "\n";
|
||||
}
|
||||
|
||||
sub update_dns {
|
||||
my $hashref = shift;
|
||||
my @records;
|
||||
my $found = 0;
|
||||
# update the addn-hosts file
|
||||
open(FILE, "+<$recordfile") || die "Couldn't open recordfile \"$recordfile\": $!\n";
|
||||
flock(FILE, 2);
|
||||
while ( <FILE> ) {
|
||||
if ( /^(\d+\.\d+\.\d+\.\d+)\s+$$hashref{'hostname'}\n$/si ) {
|
||||
if ( $1 ne $$hashref{'myip'} ) {
|
||||
push @records, "$$hashref{'myip'}\t$$hashref{'hostname'}\n";
|
||||
$found = 1;
|
||||
}
|
||||
} else {
|
||||
push @records, $_;
|
||||
}
|
||||
}
|
||||
unless ( $found ) {
|
||||
push @records, "$$hashref{'myip'}\t$$hashref{'hostname'}\n";
|
||||
}
|
||||
sysseek(FILE, 0, 0);
|
||||
truncate(FILE, 0);
|
||||
syswrite(FILE, join("", @records));
|
||||
flock(FILE, 8);
|
||||
close(FILE);
|
||||
dnsmasq_rescan_configs();
|
||||
return(0);
|
||||
}
|
||||
|
||||
sub dnsmasq_rescan_configs {
|
||||
# send the HUP signal to dnsmasq
|
||||
if ( -r $dnsmasqpidfile ) {
|
||||
open(PID,"<$dnsmasqpidfile") || die "Could not open PID file \"$dnsmasqpidfile\": $!\n";
|
||||
my $pid = <PID>;
|
||||
close(PID);
|
||||
chomp $pid;
|
||||
if ( kill(0, $pid) ) {
|
||||
kill(1, $pid);
|
||||
} else {
|
||||
goto LOOKFORDNSMASQ;
|
||||
}
|
||||
} else {
|
||||
LOOKFORDNSMASQ:
|
||||
opendir(DIR,"/proc") || die "Couldn't opendir /proc: $!\n";
|
||||
my @dirs = grep(/^\d+$/, readdir(DIR));
|
||||
closedir(DIR);
|
||||
foreach my $process (@dirs) {
|
||||
if ( open(FILE,"</proc/$process/cmdline") ) {
|
||||
my $cmdline = <FILE>;
|
||||
close(FILE);
|
||||
if ( (split(/\0/,$cmdline))[0] =~ /dnsmasq/ ) {
|
||||
kill(1, $process);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
###############################################################################
|
||||
|
||||
Name: dnsmasq
|
||||
Version: 2.9
|
||||
Version: 2.22
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: System Environment/Daemons
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
###############################################################################
|
||||
|
||||
Name: dnsmasq
|
||||
Version: 2.9
|
||||
Version: 2.22
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: Productivity/Networking/DNS/Servers
|
||||
@@ -16,7 +16,7 @@ Provides: dns_daemon
|
||||
Conflicts: bind bind8 bind9
|
||||
PreReq: %fillup_prereq %insserv_prereq
|
||||
Autoreqprov: on
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
Source0: %{name}-%{version}.tar.bz2
|
||||
BuildRoot: /var/tmp/%{name}-%{version}
|
||||
Summary: A lightweight caching nameserver
|
||||
|
||||
@@ -39,6 +39,8 @@ leases and BOOTP for network booting of diskless machines.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
patch -p0 <rpm/%{name}-SuSE.patch
|
||||
|
||||
%build
|
||||
%{?suse_update_config:%{suse_update_config -f}}
|
||||
make
|
||||
@@ -101,6 +103,7 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
%doc CHANGELOG COPYING FAQ doc.html setup.html UPGRADING_to_2.0 rpm/README.susefirewall
|
||||
%doc contrib
|
||||
%config /etc/init.d/dnsmasq
|
||||
%config /etc/dnsmasq.conf
|
||||
/usr/sbin/rcdnsmasq
|
||||
|
||||
296
dnsmasq.8
296
dnsmasq.8
@@ -15,12 +15,13 @@ contents of /etc/hosts so that local hostnames
|
||||
which do not appear in the global DNS can be resolved and also answers
|
||||
DNS queries for DHCP configured hosts.
|
||||
.PP
|
||||
.BR dnsmasq
|
||||
supports IPv6.
|
||||
The dnsmasq DHCP server supports static address assignments, multiple
|
||||
networks, DHCP-relay and RFC3011 subnet specifiers. It automatically
|
||||
sends a sensible default set of DHCP options, and can be configured to
|
||||
send any desired set of DHCP options. It also supports BOOTP.
|
||||
.PP
|
||||
.BR dnsmasq
|
||||
is lightweight and easy to configure. It is intended as be run on
|
||||
small router/firewalls and provide a DNS (and optionally, DHCP) service to a LAN.
|
||||
Dnsmasq
|
||||
supports IPv6.
|
||||
.SH OPTIONS
|
||||
Note that in general missing parameters are allowed and switch off
|
||||
functions, for instance "--pid-file=" disables writing a PID file. On
|
||||
@@ -33,8 +34,8 @@ Don't read the hostnames in /etc/hosts.
|
||||
.TP
|
||||
.B \-H, --addn-hosts=<file>
|
||||
Additional hosts file. Read the specified file as well as /etc/hosts. If -h is given, read
|
||||
only the specified file. At most one additional hosts file may be
|
||||
given.
|
||||
only the specified file. This option may be repeated for more than one
|
||||
additional hosts file.
|
||||
.TP
|
||||
.B \-T, --local-ttl=<time>
|
||||
When replying with information from /etc/hosts or the DHCP leases
|
||||
@@ -45,10 +46,15 @@ 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 \-k, --keep-in-foreground
|
||||
Do not go into the background at startup but otherwise run as
|
||||
normal. This is intended for use when dnsmasq is run under daemontools.
|
||||
.TP
|
||||
.B \-d, --no-daemon
|
||||
Debug mode: don't fork to the background, don't write a pid file,
|
||||
don't change user id, generate a complete cache dump on receipt on
|
||||
SIGUSR1, log to stderr as well as syslog.
|
||||
SIGUSR1, log to stderr as well as syslog, don't fork new processes
|
||||
to handle TCP queries.
|
||||
.TP
|
||||
.B \-q, --log-queries
|
||||
Log the results of DNS queries handled by dnsmasq. Enable a full cache dump on receipt of SIGUSR1.
|
||||
@@ -73,19 +79,29 @@ Print the version number.
|
||||
Listen on <port> instead of the standard DNS port (53). Useful mainly for
|
||||
debugging.
|
||||
.TP
|
||||
.B \-P, --edns-packet-max=<size>
|
||||
Specify the largest EDNS.0 UDP packet which is supported by the DNS
|
||||
forwarder. Defaults to 1280, which is the RFC2671-recommended maximum
|
||||
for ethernet.
|
||||
.TP
|
||||
.B \-Q, --query-port=<query_port>
|
||||
Send outbound DNS queries from, and listen for their replies on, the specific UDP port <query_port> instead of using one chosen at runtime. Useful to simplify your
|
||||
firewall rules; without this, your firewall would have to allow connections from outside DNS servers to a range of UDP ports, or dynamically adapt to the
|
||||
port being used by the current dnsmasq instance.
|
||||
.TP
|
||||
.B \-i, --interface=<interface name>
|
||||
Listen only on the specified interface. More than one interface may be specified. Dnsmasq always listens on the loopback (local) interface. If no
|
||||
.B \-i
|
||||
flags are given, dnsmasq listens on all available interfaces unless overridden by
|
||||
.B \-a
|
||||
Listen only on the specified interface(s). Dnsmasq automatically adds
|
||||
the loopback (local) interface to the list of interfaces to use when
|
||||
the
|
||||
.B \--interface
|
||||
option is used. If no
|
||||
.B \--interface
|
||||
or
|
||||
.B \-I
|
||||
flags. If IP alias interfaces (eg "eth1:0") are used with
|
||||
.B \--listen-address
|
||||
options are given dnsmasq listens on all available interfaces except any
|
||||
given in
|
||||
.B \--except-interface
|
||||
options. If IP alias interfaces (eg "eth1:0") are used with
|
||||
.B --interface
|
||||
or
|
||||
.B --except-interface
|
||||
@@ -95,21 +111,30 @@ option will be automatically set. This is required for deeply boring
|
||||
sockets-API reasons.
|
||||
.TP
|
||||
.B \-I, --except-interface=<interface name>
|
||||
Do not listen on the specified interface.
|
||||
Do not listen on the specified interface. Note that the order of
|
||||
.B \--listen-address
|
||||
.B --interface
|
||||
and
|
||||
.B --except-interface
|
||||
options does not matter and that
|
||||
.B --except-interface
|
||||
options always override the others.
|
||||
.TP
|
||||
.B \-a, --listen-address=<ipaddr>
|
||||
Listen only on the given IP address. As with
|
||||
.B \-i
|
||||
more than one address may be specified. Unlike
|
||||
.B \-i
|
||||
the loopback interface is not special: if dnsmasq is to listen on the loopback interface,
|
||||
it's IP, 127.0.0.1, must be explicitly given. If no
|
||||
.B \-a
|
||||
flags are given, dnsmasq listens on all available interfaces unless overridden by
|
||||
.B \-i
|
||||
or
|
||||
.B \-I
|
||||
flags.
|
||||
Listen on the given IP address(es). Both
|
||||
.B \--interface
|
||||
and
|
||||
.B \--listen-address
|
||||
options may be given, in which case the set of both interfaces and
|
||||
addresses is used. Note that if no
|
||||
.B \--interface
|
||||
option is given, but
|
||||
.B \--listen-address
|
||||
is, dnsmasq will not automatically listen on the loopback
|
||||
interface. To achieve this, its IP address, 127.0.0.1, must be
|
||||
explicitly given as a
|
||||
.B \--listen-address
|
||||
option.
|
||||
.TP
|
||||
.B \-z, --bind-interfaces
|
||||
On systems which support it, dnsmasq binds the wildcard address,
|
||||
@@ -118,15 +143,26 @@ requests that it shouldn't reply to. This has the advantage of
|
||||
working even when interfaces come and go and change address. This
|
||||
option forces dnsmasq to really bind only the interfaces it is
|
||||
listening on. About the only time when this is useful is when
|
||||
running another nameserver on the same machine or using IP
|
||||
running another nameserver (or another instance of dnsmasq) on the
|
||||
same machine or when using IP
|
||||
alias. Specifying interfaces with IP alias automatically turns this
|
||||
option on. Note that this only applies to the DNS part of dnsmasq, the
|
||||
DHCP server always binds the wildcard address in order to receive
|
||||
broadcast packets.
|
||||
option on. Setting this option also enables multiple instances of
|
||||
dnsmasq which provide DHCP service to run in the same machine.
|
||||
.TP
|
||||
.B \-y, --localise-queries
|
||||
Return answers to DNS queries from /etc/hosts which depend on the interface over which the query was
|
||||
recieved. If a name in /etc/hosts has more than one address associated with
|
||||
it, and at least one of those addresses is on the same subnet as the
|
||||
interface to which the query was sent, then return only the
|
||||
address(es) on that subnet. This allows for a server to have multiple
|
||||
addresses in /etc/hosts corresponding to each of its interfaces, and
|
||||
hosts will get the correct address based on which network they are
|
||||
attached to. Currently this facility is limited to IPv4.
|
||||
.TP
|
||||
.B \-b, --bogus-priv
|
||||
Bogus private reverse lookups. All reverse lookups for private IP ranges (ie 192.168.x.x, etc)
|
||||
which are not found in /etc/hosts or the DHCP leases file are resolved to the IP address in dotted-quad form.
|
||||
which are not found in /etc/hosts or the DHCP leases file are answered
|
||||
with "no such domain" rather than being forwarded upstream.
|
||||
.TP
|
||||
.B \-V, --alias=<old-ip>,<new-ip>[,<mask>]
|
||||
Modify IPv4 addresses returned from upstream nameservers; old-ip is
|
||||
@@ -188,7 +224,7 @@ and they are queried only using the specified server. This is
|
||||
intended for private nameservers: if you have a nameserver on your
|
||||
network which deals with names of the form
|
||||
xxx.internal.thekelleys.org.uk at 192.168.1.1 then giving the flag
|
||||
.B -S /internal.thekelleys.org.uk/192.168.1.1
|
||||
.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,
|
||||
@@ -232,18 +268,20 @@ additional facility that /#/ matches any domain. Thus
|
||||
answered from /etc/hosts or DHCP and not sent to an upstream
|
||||
nameserver by a more specific --server directive.
|
||||
.TP
|
||||
.B \-m, --mx-host=<mx name>[,<hostname>]
|
||||
.B \-m, --mx-host=<mx name>[[,<hostname>],<preference>]
|
||||
Return an MX record named <mx name> pointing to the given hostname (if
|
||||
given), or
|
||||
the host specified in the --mx-target switch
|
||||
or, if that switch is not given, the host on which dnsmasq
|
||||
is running. This is useful for directing mail from systems on a LAN
|
||||
to a central server.
|
||||
is running. The default is useful for directing mail from systems on a LAN
|
||||
to a central server. The preference value is optional, and defaults to
|
||||
1 if not given. More than one MX record may be given for a host.
|
||||
.TP
|
||||
.B \-t, --mx-target=<hostname>
|
||||
Specify target for the MX record returned by dnsmasq. See --mx-host. Note that to turn on the MX function,
|
||||
at least one of --mx-host and --mx-target must be set. If only one of --mx-host and --mx-target
|
||||
is set, the other defaults to the hostname of the machine on which dnsmasq is running.
|
||||
Specify the default target for the MX record returned by dnsmasq. See
|
||||
--mx-host. If --mx-target is given, but not --mx-host, then dnsmasq
|
||||
returns a MX record containing the MX target for MX queries on the
|
||||
hostname of the machine on which dnsmasq is running.
|
||||
.TP
|
||||
.B \-e, --selfmx
|
||||
Return an MX record pointing to itself for each local
|
||||
@@ -255,6 +293,27 @@ machine on which dnsmasq is running) for each
|
||||
local machine. Local machines are those in /etc/hosts or with DHCP
|
||||
leases.
|
||||
.TP
|
||||
.B \-W, --srv-host=<_service>.<_prot>.[<domain>],[<target>[,<port>[,<priority>[,<weight>]]]]
|
||||
Return a SRV DNS record. See RFC2782 for details. If not supplied, the
|
||||
domain defaults to that given by
|
||||
.B --domain.
|
||||
The default for the target domain is empty, and the default for port
|
||||
is one and the defaults for
|
||||
weight and priority are zero. Be careful if transposing data from BIND
|
||||
zone files: the port, weight and priority numbers are in a different
|
||||
order. More than one SRV record for a given service/domain is allowed,
|
||||
all that match are returned. Specifying at least one
|
||||
.B --srv-host
|
||||
option also turns on replies to SOA queries for the
|
||||
domain given by the
|
||||
.B --domain
|
||||
option. The data in these is stereotyped, but is enough for resolvers
|
||||
to deduce that the domain is a valid one for resolving SRV records.
|
||||
.TP
|
||||
.B \-Y, --txt-record=<name>[[,<text>],<text>]
|
||||
Return a TXT DNS record. The value of TXT record is a set of strings,
|
||||
so any number may be included, split by commas.
|
||||
.TP
|
||||
.B \-c, --cache-size=<cachesize>
|
||||
Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching.
|
||||
.TP
|
||||
@@ -264,7 +323,7 @@ Disable negative caching. Negative caching allows dnsmasq to remember
|
||||
identical queries without forwarding them again. This flag disables
|
||||
negative caching.
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[network-id,]<start-addr>,<end-addr>[[,<netmask>],<broadcast>][,<default lease time>]
|
||||
.B \-F, --dhcp-range=[[net:]network-id,]<start-addr>,<end-addr>[[,<netmask>],<broadcast>][,<default lease time>]
|
||||
Enable the DHCP server. Addresses will be given out from the range
|
||||
<start-addr> to <end-addr> and from statically defined addresses given
|
||||
in
|
||||
@@ -281,10 +340,13 @@ always optional. On some broken systems, dnsmasq can listen on only
|
||||
one interface when using DHCP, and the name of that interface must be
|
||||
given using the
|
||||
.B interface
|
||||
option. This limitation currently affects OpenBSD. The optional
|
||||
option. This limitation currently affects OpenBSD. It is always
|
||||
allowed to have more than one dhcp-range in a single subnet. The optional
|
||||
network-id is a alphanumeric label which marks this network so that
|
||||
dhcp options may be specified on a per-network basis. The end address
|
||||
may be replaced by the keyword
|
||||
dhcp options may be specified on a per-network basis.
|
||||
When it is prefixed with 'net:' then its meaning changes from setting
|
||||
a tag to matching it.
|
||||
The end address may be replaced by the keyword
|
||||
.B static
|
||||
which tells dnsmasq to enable DHCP for the network specified, but not
|
||||
to dynamically allocate IP addresses. Only hosts which have static
|
||||
@@ -331,6 +393,12 @@ useful when there is another DHCP server on the network which should
|
||||
be used by some machines. The net:<network-id> parameter enables DHCP options just
|
||||
for this host in the same way as the the network-id in
|
||||
.B dhcp-range.
|
||||
Ethernet addresses (but not client-ids) may have
|
||||
wildcard bytes, so for example
|
||||
.B --dhcp-host=00:20:e0:3b:13:*,ignore
|
||||
will cause dnsmasq to ignore a range of ethernet addresses. Note that
|
||||
the "*" will need to be escaped or quoted on a command line, but not
|
||||
in the configuration file.
|
||||
.TP
|
||||
.B \-Z, --read-ethers
|
||||
Read /etc/ethers for information about hosts for the DHCP server. The
|
||||
@@ -340,7 +408,7 @@ have exactly the same effect as
|
||||
.B --dhcp-host
|
||||
options containing the same information.
|
||||
.TP
|
||||
.B \-O, --dhcp-option=[network-id,]<opt>,[<value>[,<value>]]
|
||||
.B \-O, --dhcp-option=[<network-id>,[<network-id>,]][vendor:<vendor-class>]<opt>,[<value>[,<value>]]
|
||||
Specfify different or extra options to DHCP clients. By default,
|
||||
dnsmasq sends some standard options to DHCP clients, the netmask and
|
||||
broadcast address are set to the same as the host running dnsmasq, and
|
||||
@@ -354,16 +422,27 @@ specfied in RFC2132. For example, to set the default route option to
|
||||
and to set the time-server address to 192.168.0.4, do
|
||||
.B --dhcp-option=42,192.168.0.4
|
||||
The special address 0.0.0.0 is taken to mean "the address of the
|
||||
machine running dnsmasq". Data types allowed are comma seperated
|
||||
dotted-quad IP addresses, a decimal number, colon-seperated hex digits
|
||||
and a text string. If the optional network-id is given then
|
||||
this option is only sent to machines on the network whose dhcp-range
|
||||
contains a matching network-id.
|
||||
machine running dnsmasq". Data types allowed are comma separated
|
||||
dotted-quad IP addresses, a decimal number, colon-separated hex digits
|
||||
and a text string. If the optional network-ids are given then
|
||||
this option is only sent when all the network-ids are matched.
|
||||
|
||||
Be careful: no checking is done that the correct type of data for the
|
||||
option number is sent, and there are option numbers for which it is not
|
||||
possible to generate the correct data type; it is quite possible to
|
||||
option number is sent, it is quite possible to
|
||||
persuade dnsmasq to generate illegal DHCP packets with injudicious use
|
||||
of this flag.
|
||||
of this flag. When the value is a decimal number, dnsmasq must determine how
|
||||
large the data item is. It does this by examining the option number and/or the
|
||||
value, but can be overriden by appending a single letter flag as follows:
|
||||
b = one byte, s = two bytes, i = four bytes. This is mainly useful with
|
||||
encapsulated vendor class options (see below) where dnsmasq cannot determine data size from the option number.
|
||||
|
||||
Encapsulated Vendor-class options may also be specified using
|
||||
--dhcp-option: for instance
|
||||
.B --dhcp-option=vendor:PXEClient,1,0.0.0.0
|
||||
sends the vendor class "PXEClient" and the encapsulated vendor class-specific option "mftp-address=0.0.0.0" Only one vendor class is allowed for any
|
||||
host, but multiple options are allowed, provided they all have
|
||||
the same vendor class. The address 0.0.0.0 is not treated specially in
|
||||
encapsulated vendor class options.
|
||||
.TP
|
||||
.B \-U, --dhcp-vendorclass=<network-id>,<vendor-class>
|
||||
Map from a vendor-class string to a network id. Most DHCP clients provide a
|
||||
@@ -386,10 +465,17 @@ to different classes of hosts. It is possible, for instance to use
|
||||
this to set a different printer server for hosts in the class
|
||||
"accounts" than for hosts in the class "engineering".
|
||||
.TP
|
||||
.B \-M, --dhcp-boot=<filename>,[<servername>[,<server address>]]
|
||||
.B \ -J, --dhcp-ignore=<network-id>[,<network-id>]
|
||||
When all the given network-ids match the set of network-ids derived
|
||||
from the net, host, vendor and user classes, ignore the host and do
|
||||
not allocate it a DHCP lease.
|
||||
.TP
|
||||
.B \-M, --dhcp-boot=[net:<network-id>,]<filename>,[<servername>[,<server address>]]
|
||||
Set BOOTP options to be returned by the DHCP server. These are needed
|
||||
for machines which network boot, and tell the machine where to collect
|
||||
its initial configuration.
|
||||
its initial configuration. If the optional network-id(s) are given,
|
||||
they must match for this configuration to be sent. Note that
|
||||
network-ids are prefixed by "net:" to distinguish them.
|
||||
.TP
|
||||
.B \-X, --dhcp-lease-max=<number>
|
||||
Limits dnsmasq to the specified maximum number of DHCP leases. The
|
||||
@@ -397,6 +483,12 @@ default is 150. This limit is to prevent DoS attacks from hosts which
|
||||
create thousands of leases and use lots of memory in the dnsmasq
|
||||
process.
|
||||
.TP
|
||||
.B \-K, --dhcp-authoritative
|
||||
Should be set when dnsmasq is definatively the only DHCP server on a network.
|
||||
It changes the behaviour from strict RFC compliance so that DHCP requests on
|
||||
unknown leases from unknown hosts are not ignored. This allows new hosts
|
||||
to get a lease without a tedious timeout under all circumstances.
|
||||
.TP
|
||||
.B \-l, --dhcp-leasefile=<path>
|
||||
Use the specified file to store DHCP lease information. If this option
|
||||
is given but no dhcp-range option is given then dnsmasq version 1
|
||||
@@ -421,22 +513,33 @@ in /etc/resolv.conf (or equivalent).
|
||||
Add the domain-suffix to simple names (without a period) in /etc/hosts
|
||||
in the same way as for DHCP-derived names.
|
||||
.SH CONFIG FILE
|
||||
At startup, dnsmasq reads /etc/dnsmasq.conf, if it exists. (On
|
||||
FreeBSD and OpenBSD, the file is /usr/local/etc/dnsmasq.conf) The format of this
|
||||
At startup, dnsmasq reads
|
||||
.I /etc/dnsmasq.conf,
|
||||
if it exists. (On
|
||||
FreeBSD, the file is
|
||||
.I /usr/local/etc/dnsmasq.conf
|
||||
) The format of this
|
||||
file consists of one option per line, exactly as the long options detailed
|
||||
in the OPTIONS section but without the leading "--". Lines starting with # are comments and ignored. For
|
||||
options which may only be specified once, the configuration file overrides
|
||||
the command line. Use the --conf-file option to specify a different
|
||||
configuration file. The conf-file option is also allowed in
|
||||
configuration files, to include multiple configuration files. Only one
|
||||
level of nesting is allowed.
|
||||
level of nesting is allowed. Quoting is allowed in a config file:
|
||||
between " quotes the special meaning of , and # is removed and the
|
||||
following escapes are allowed: \\\\ \\" \\t and \\n. The later two
|
||||
corresponding to newline and tab.
|
||||
.SH NOTES
|
||||
When it receives a SIGHUP,
|
||||
.B dnsmasq
|
||||
clears its cache and then re-loads /etc/hosts. If
|
||||
clears its cache and then re-loads
|
||||
.I /etc/hosts.
|
||||
If
|
||||
.B
|
||||
--no-poll
|
||||
is set SIGHUP also re-reads /etc/resolv.conf. SIGHUP
|
||||
is set SIGHUP also re-reads
|
||||
.I /etc/resolv.conf.
|
||||
SIGHUP
|
||||
does NOT re-read the configuration file.
|
||||
.PP
|
||||
When it receives a SIGUSR1,
|
||||
@@ -452,25 +555,34 @@ Dnsmasq is a DNS query forwarder: it it not capable of recursively
|
||||
answering arbitrary queries starting from the root servers but
|
||||
forwards such queries to a fully recursive upstream DNS server which is
|
||||
typically provided by an ISP. By default, dnsmasq reads
|
||||
/etc/resolv.conf to discover the IP
|
||||
.I /etc/resolv.conf
|
||||
to discover the IP
|
||||
addresses of the upstream nameservers it should use, since the
|
||||
information is typically stored there. Unless
|
||||
.B --no-poll
|
||||
is used,
|
||||
.B dnsmasq
|
||||
checks the modification time of /etc/resolv.conf (or
|
||||
equivalent if
|
||||
checks the modification time of
|
||||
.I /etc/resolv.conf
|
||||
(or equivalent if
|
||||
.B \--resolv-file
|
||||
is used) and re-reads it if it changes. This allows the DNS servers to
|
||||
be set dynamically by PPP or DHCP since both protocols provide the
|
||||
information.
|
||||
Absence of /etc/resolv.conf is not an error
|
||||
Absence of
|
||||
.I /etc/resolv.conf
|
||||
is not an error
|
||||
since it may not have been created before a PPP connection exists. Dnsmasq
|
||||
simply keeps checking in case /etc/resolv.conf is created at any
|
||||
simply keeps checking in case
|
||||
.I /etc/resolv.conf
|
||||
is created at any
|
||||
time. Dnsmasq can be told to parse more than one resolv.conf
|
||||
file. This is useful on a laptop, where both PPP and DHCP may be used:
|
||||
dnsmasq can be set to poll both /etc/ppp/resolv.conf and
|
||||
/etc/dhcpc/resolv.conf and will use the contents of whichever changed
|
||||
dnsmasq can be set to poll both
|
||||
.I /etc/ppp/resolv.conf
|
||||
and
|
||||
.I /etc/dhcpc/resolv.conf
|
||||
and will use the contents of whichever changed
|
||||
last, giving automatic switching between DNS servers.
|
||||
.PP
|
||||
Upstream servers may also be specified on the command line or in
|
||||
@@ -490,6 +602,56 @@ and run dnsmasq with the
|
||||
.B \-r /etc/resolv.dnsmasq
|
||||
option. This second technique allows for dynamic update of the server
|
||||
addresses by PPP or DHCP.
|
||||
.PP
|
||||
Addresses in /etc/hosts will "shadow" different addresses for the same
|
||||
names in the upstream DNS, so "mycompany.com 1.2.3.4" in /etc/hosts will ensure that
|
||||
queries for "mycompany.com" always return 1.2.3.4 even if queries in
|
||||
the upstream DNS would otherwise return a different address. There is
|
||||
one exception to this: if the upstream DNS contains a CNAME which
|
||||
points to a shadowed name, then looking up the CNAME through dnsmasq
|
||||
will result in the unshadowed address associated with the target of
|
||||
the CNAME. To work around this, add the CNAME to /etc/hosts so that
|
||||
the CNAME is shadowed too.
|
||||
|
||||
.PP
|
||||
The network-id system works as follows: For each DHCP request, dnsmasq
|
||||
collects a set of valid network-id tags, one from the
|
||||
.B dhcp-range
|
||||
used to allocate the address, one from any matching
|
||||
.B dhcp-host
|
||||
and possibly many from matching vendor classes and user
|
||||
classes sent by the DHCP client. Any
|
||||
.B dhcp-option
|
||||
which has network-id tags will be used in preference to an untagged
|
||||
.B dhcp-option,
|
||||
provided that _all_ the tags match somewhere in the
|
||||
set collected as described above. The prefix '#' on a tag means 'not'
|
||||
so --dhcp=option=#purple,3,1.2.3.4 sends the option when the
|
||||
network-id tag purple is not in the set of valid tags.
|
||||
.PP
|
||||
If the network-id in a
|
||||
.B dhcp-range
|
||||
is prefixed with 'net:' then its meaning changes from setting a
|
||||
tag to matching it. Thus if there is more than dhcp-range on a subnet,
|
||||
and one is tagged with a network-id which is set (for instance
|
||||
from a vendorclass option) then hosts which set the netid tag will be
|
||||
allocated addresses in the tagged range.
|
||||
.PP
|
||||
The DHCP server in dnsmasq will function as a BOOTP server also,
|
||||
provided that the MAC address and IP address for clients are given,
|
||||
either using
|
||||
.B dhcp-host
|
||||
configurations or in
|
||||
.I /etc/ethers
|
||||
, and a
|
||||
.B dhcp-range
|
||||
configuration option is present to activate the DHCP server
|
||||
on a particular network. The filename
|
||||
parameter in a BOOTP request is matched against netids in
|
||||
.B dhcp-option
|
||||
configurations, allowing some control over the options returned to
|
||||
different classes of hosts.
|
||||
|
||||
.SH FILES
|
||||
.IR /etc/dnsmasq.conf
|
||||
|
||||
@@ -499,6 +661,8 @@ addresses by PPP or DHCP.
|
||||
|
||||
.IR /etc/hosts
|
||||
|
||||
.IR /etc/ethers
|
||||
|
||||
.IR /var/lib/misc/dnsmasq.leases
|
||||
|
||||
.IR /var/db/dnsmasq.leases
|
||||
|
||||
@@ -4,15 +4,7 @@
|
||||
# as the long options legal on the command line. See
|
||||
# "/usr/sbin/dnsmasq --help" or "man 8 dnsmasq" for details.
|
||||
|
||||
# Change these lines if you want dnsmasq to serve MX records.
|
||||
# Only one of mx-host and mx-target need be set, the other defaults
|
||||
# to the name of the host running dnsmasq.
|
||||
#mx-host=
|
||||
#mx-target=
|
||||
#selfmx
|
||||
#localmx
|
||||
|
||||
# The following three options make you a better netizen, since they
|
||||
# The following two options make you a better netizen, since they
|
||||
# tell dnsmasq to filter out queries which the public DNS cannot
|
||||
# answer, and which load the servers (especially the root servers)
|
||||
# uneccessarily. If you have a dial-on-demand link they also stop
|
||||
@@ -20,13 +12,18 @@
|
||||
|
||||
# Never forward plain names (with a dot or domain part)
|
||||
domain-needed
|
||||
# Reply to reverse queries for addresses in the non-routed address
|
||||
# space with the dotted.quad address
|
||||
# Never forward addresses in the non-routed address spaces.
|
||||
bogus-priv
|
||||
# Filter useless windows-originated DNS requests
|
||||
filterwin2k
|
||||
|
||||
|
||||
# Uncomment this to filter useless windows-originated DNS requests
|
||||
# which can trigger dial-on-demand links needlessly.
|
||||
# Note that (amongst other things) this blocks all SRV requests,
|
||||
# so don't use it if you use eg Kerberos.
|
||||
# This option only affects forwarding, SRV records originating for
|
||||
# dnsmasq (via srv-host= lines) are not suppressed by it.
|
||||
#filterwin2k
|
||||
|
||||
# Change this line if you want dns to get its upstream servers from
|
||||
# somewhere other that /etc/resolv.conf
|
||||
#resolv-file=
|
||||
@@ -60,9 +57,8 @@ filterwin2k
|
||||
# webserver.
|
||||
#address=/doubleclick.net/127.0.0.1
|
||||
|
||||
# You no longer (as of version 1.7) need to set these to enable
|
||||
# dnsmasq to read /etc/ppp/resolv.conf since dnsmasq now uses the
|
||||
# "dip" group to achieve this.
|
||||
# If you want dnsmasq to change uid and gid to something other
|
||||
# than the default, edit the following lines.
|
||||
#user=
|
||||
#group=
|
||||
|
||||
@@ -171,6 +167,10 @@ filterwin2k
|
||||
# the machine with ethernet address 11:22:33:44:55:66
|
||||
#dhcp-host=11:22:33:44:55:66,net:red
|
||||
|
||||
# Send extra options which are tagged as "red" to
|
||||
# any machine with ethernet address starting 11:22:33:
|
||||
#dhcp-host=11:22:33:*:*:*,net:red
|
||||
|
||||
# Send extra options which are tagged as "red" to any machine whose
|
||||
# DHCP vendorclass string includes the substring "Linux"
|
||||
#dhcp-vendorclass=red,Linux
|
||||
@@ -234,7 +234,17 @@ filterwin2k
|
||||
#dhcp-option=45,0.0.0.0 # netbios datagram distribution server
|
||||
#dhcp-option=46,8 # netbios node type
|
||||
#dhcp-option=47 # empty netbios scope.
|
||||
|
||||
|
||||
# Send RFC-3397 DNS domain search DHCP option. WARNING: Your DHCP client
|
||||
# probably doesn't support this......
|
||||
#dhcp-option=119,eng.apple.com,marketing.apple.com
|
||||
|
||||
# Send encapsulated vendor-class specific options. The vendor-class
|
||||
# is sent as DHCP option 60, and all the options marked with the
|
||||
# vendor class are send encapsulated in DHCP option 43. The meaning of
|
||||
# the options is defined by the vendor-class. This example sets the
|
||||
# mtftp address to 0.0.0.0 for PXEClients
|
||||
#dhcp-option=vendor:PXEClient,1,0.0.0.0
|
||||
|
||||
# Set the boot filename and tftpd server name and address
|
||||
# for BOOTP. You will only need this is you want to
|
||||
@@ -249,6 +259,16 @@ filterwin2k
|
||||
# the line below.
|
||||
#dhcp-leasefile=/var/lib/misc/dnsmasq.leases
|
||||
|
||||
# Set the DHCP server to authoritative mode. In this mode it will barge in
|
||||
# and take over the lease for any client which broadcasts on the network,
|
||||
# whether it has a record of the lease or not. This avoids long timeouts
|
||||
# when a machine wakes up on a new network. DO NOT enable this if there's
|
||||
# the slighest chance that you might end up accidentally configuring a DHCP
|
||||
# server for your campus/company accidentally. The ISC server uses the same
|
||||
# the same option, and this URL provides more information:
|
||||
# http://www.isc.org/index.pl?/sw/dhcp/authoritative.php
|
||||
#dhcp-authoritative
|
||||
|
||||
# Set the cachesize here.
|
||||
#cache-size=150
|
||||
|
||||
@@ -276,6 +296,64 @@ filterwin2k
|
||||
# and this maps 1.2.3.x to 5.6.7.x
|
||||
#alias=1.2.3.0,5.6.7.0,255.255.255.0
|
||||
|
||||
|
||||
# Change these lines if you want dnsmasq to serve MX records.
|
||||
|
||||
# Return an MX record named "maildomain.com" with target
|
||||
# servermachine.com and preference 50
|
||||
#mx-host=maildomain.com,servermachine.com,50
|
||||
|
||||
# Set the default target for MX records created using the localmx option.
|
||||
#mx-target=servermachine.com
|
||||
|
||||
# Return an MX record pointing to the mx-target for all local
|
||||
# machines.
|
||||
#localmx
|
||||
|
||||
# Return an MX record pointing to itself for all local machines.
|
||||
#selfmx
|
||||
|
||||
# Change the following lines if you want dnsmasq to serve SRV
|
||||
# records. These are useful if you want to serve ldap requests for
|
||||
# Active Directory and other windows-originated DNS requests.
|
||||
# See RFC 2782.
|
||||
# You may add multiple srv-host lines.
|
||||
# The fields are <name>,<target>,<port>,<priority>,<weight>
|
||||
# If the domain part if missing from the name (so that is just has the
|
||||
# service and protocol sections) then the domain given by the domain=
|
||||
# config option is used. (Note that expand-hosts does not need to be
|
||||
# set for this to work.)
|
||||
|
||||
# A SRV record sending LDAP for the example.com domain to
|
||||
# ldapserver.example.com port 289
|
||||
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389
|
||||
|
||||
# A SRV record sending LDAP for the example.com domain to
|
||||
# ldapserver.example.com port 289 (using domain=)
|
||||
#domain=example.com
|
||||
#srv-host=_ldap._tcp,ldapserver.example.com,389
|
||||
|
||||
# Two SRV records for LDAP, each with different priorities
|
||||
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,1
|
||||
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,2
|
||||
|
||||
# A SRV record indicating that there is no LDAP server for the domain
|
||||
# example.com
|
||||
#srv-host=_ldap._tcp.example.com
|
||||
|
||||
|
||||
# Change the following lines to enable dnsmasq to serve TXT records.
|
||||
# These are used for things like SPF and zeroconf. (Note that the
|
||||
# domain-name expansion done for SRV records _does_not
|
||||
# occur for TXT records.)
|
||||
|
||||
#Example SPF.
|
||||
#txt-record=example.com,v=spf1 a -all
|
||||
|
||||
#Example zeroconf
|
||||
#txt-record=_http._tcp.example.com,name=value,paper=A4
|
||||
|
||||
|
||||
# For debugging purposes, log each DNS query as it passes through
|
||||
# dnsmasq.
|
||||
#log-queries
|
||||
|
||||
52
doc.html
52
doc.html
@@ -18,10 +18,13 @@ connected to the internet via a modem, cable-modem or ADSL
|
||||
connection but would be a good choice for any small network where low
|
||||
resource use and ease of configuration are important.
|
||||
<P>
|
||||
Supported platforms include Linux (with glibc and uclibc), *BSD and
|
||||
Mac OS X.
|
||||
Dnsmasq is included in at least the following Linux distributions:
|
||||
Gentoo, Debian, Slackware, Suse,
|
||||
Smoothwall, IP-Cop, floppyfw, Firebox, Freesco, CoyoteLinux and
|
||||
Clarkconnect. It is also available as a FreeBSD port and is used in Linksys wireless routers.
|
||||
Smoothwall, IP-Cop, floppyfw, Firebox, LEAF, Freesco, CoyoteLinux and
|
||||
Clarkconnect. It is also available as a FreeBSD port and is used in
|
||||
Linksys wireless routers and the m0n0wall project.
|
||||
<P>
|
||||
Dnsmasq provides the following features:
|
||||
<DIR>
|
||||
@@ -39,22 +42,18 @@ machine: If the names of local machines are there, then they can all
|
||||
be addressed without having to maintain /etc/hosts on each machine.
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq will serve names from the DHCP leases file on the firewall machine:
|
||||
If machines specify a hostname when they take out a DHCP lease, then they are
|
||||
addressable in the local DNS. <B>UPDATE</B> Dnsmasq version 2 now offers an integrated DHCP server
|
||||
instead of the lease file reader. This gives better control of the
|
||||
interaction with new functions (for example fixed IP leasess and
|
||||
attaching names to ethernet addresses centrally) it's also much
|
||||
smaller than dnsmasq and ISC dhcpd which is important for router distros.
|
||||
The integrated DHCP server supports static and dynamic DHCP leases and
|
||||
multiple networks and IP ranges. It works across BOOTP relays and
|
||||
supports DHCP options including RFC3397 DNS search lists.
|
||||
Machines which are configured by DHCP have their names automatically
|
||||
included in the DNS and the names can specified by each machine or
|
||||
centrally by associating a name with a MAC address in the dnsmasq
|
||||
config file.
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq caches internet addresses (A records and AAAA records) and address-to-name
|
||||
mappings (PTR records), reducing the load on upstream servers and
|
||||
improving performance (especially on modem connections). From version
|
||||
0.95 the cache honours time-to-live information and removes old
|
||||
records as they expire. From version 0.996 dnsmasq does negative
|
||||
caching. From version 1.2 dnsmasq supports IPv6 addresses, both
|
||||
in its cache and in /etc/hosts.
|
||||
improving performance (especially on modem connections).
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq can be configured to automatically pick up the addresses of
|
||||
@@ -74,14 +73,8 @@ upstream servers handling only those domains. This makes integration
|
||||
with private DNS systems easy.
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq can be configured to return an MX record
|
||||
for the firewall host. This makes it easy to configure the mailer on the local
|
||||
machines to forward all mail to the central mailer on the firewall host. Never
|
||||
lose root messages from your machines again!
|
||||
</LI>
|
||||
<LI>
|
||||
For version 1.15 dnsmasq has a facility to work around Verisign's infamous wildcard A record
|
||||
in the .com and .net TLDs
|
||||
Dnsmasq supports MX records and can be configured to return MX records
|
||||
for any or all local machines.
|
||||
</LI>
|
||||
</DIR>
|
||||
|
||||
@@ -110,13 +103,22 @@ bzip2 dnsmasq-zzz.tar
|
||||
</PRE>
|
||||
|
||||
<H2>Links.</H2>
|
||||
Ulrich Ivens has a nice HOWTO in German on installing dnsmasq at <A HREF="http://howto.linux-hardware-shop.de/dnsmasq.html">http://howto.linux-hardware-shop.de/dnsmasq.html</A>
|
||||
|
||||
Ulrich Ivens has a nice HOWTO in German on installing dnsmasq at <A
|
||||
HREF="http://howto.linux-hardware-shop.de/dnsmasq.html">http://howto.linux-hardware-shop.de/dnsmasq.html</A>
|
||||
and Damien Raude-Morvan has one in French at <A HREF="http://www.drazzib.com/docs-dnsmasq.html">http://www.drazzib.com/docs-dnsmasq.html</A>
|
||||
There is a good article about dnsmasq at <A
|
||||
HREF="http://www.enterprisenetworkingplanet.com/netos/article.php/3377351">http://www.enterprisenetworkingplanet.com/netos/article.php/3377351</A>
|
||||
and Ilya Evseev has an article in Russian about dnsmasq to be found at <A HREF="http://ilya-evseev.narod.ru/articles/dnsmasq"> http://ilya-evseev.narod.ru/articles/dnsmasq</A>
|
||||
<H2>License.</H2>
|
||||
Dnsmasq is distributed under the GPL. See the file COPYING in the distribution
|
||||
for details.
|
||||
|
||||
<H2>Contact.</H2>
|
||||
Dnsmasq was written by Simon Kelley. You can contact me at <A HREF="mailto:simon@thekelleys.org.uk">simon@thekelleys.org.uk</A>. Bugreports, patches, and suggestions for improvements gratefully accepted.
|
||||
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.
|
||||
Dnsmasq was written by Simon Kelley. You can contact me at <A
|
||||
HREF="mailto:simon@thekelleys.org.uk">simon@thekelleys.org.uk</A>.
|
||||
</BODY>
|
||||
|
||||
|
||||
31
rpm/dnsmasq-SuSE.patch
Normal file
31
rpm/dnsmasq-SuSE.patch
Normal file
@@ -0,0 +1,31 @@
|
||||
--- dnsmasq.8 2004-08-08 20:57:56.000000000 +0200
|
||||
+++ dnsmasq.8 2004-08-12 00:40:01.000000000 +0200
|
||||
@@ -69,7 +69,7 @@
|
||||
.TP
|
||||
.B \-g, --group=<groupname>
|
||||
Specify the group which dnsmasq will run
|
||||
-as. The defaults to "dip", if available, to facilitate access to
|
||||
+as. The defaults to "dialout", if available, to facilitate access to
|
||||
/etc/ppp/resolv.conf which is not normally world readable.
|
||||
.TP
|
||||
.B \-v, --version
|
||||
--- src/config.h 2004-08-11 11:39:18.000000000 +0200
|
||||
+++ src/config.h 2004-08-12 00:40:01.000000000 +0200
|
||||
@@ -44,7 +44,7 @@
|
||||
#endif
|
||||
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||
#define CHUSER "nobody"
|
||||
-#define CHGRP "dip"
|
||||
+#define CHGRP "dialout"
|
||||
#define IP6INTERFACES "/proc/net/if_inet6"
|
||||
#define UPTIME "/proc/uptime"
|
||||
#define DHCP_SERVER_PORT 67
|
||||
@@ -195,7 +195,7 @@
|
||||
|
||||
/* platform independent options. */
|
||||
#undef HAVE_BROKEN_RTC
|
||||
-#define HAVE_ISC_READER
|
||||
+#undef HAVE_ISC_READER
|
||||
|
||||
#if defined(HAVE_BROKEN_RTC) && defined(HAVE_ISC_READER)
|
||||
# error HAVE_ISC_READER is not compatible with HAVE_BROKEN_RTC
|
||||
@@ -4,7 +4,7 @@
|
||||
CFLAGS?= -O2
|
||||
|
||||
OBJS = cache.o rfc1035.o util.o option.o forward.o isc.o \
|
||||
network.o dnsmasq.o dhcp.o lease.o rfc2131.o
|
||||
network.o dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o
|
||||
|
||||
.c.o: dnsmasq.h config.h
|
||||
$(CC) $(CFLAGS) $(RPM_OPT_FLAGS) -Wall -W -c $*.c
|
||||
|
||||
328
src/cache.c
328
src/cache.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2005 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,11 +17,12 @@ static struct crec *dhcp_inuse, *dhcp_spare, *new_chain;
|
||||
static int cache_inserted, cache_live_freed, insert_error;
|
||||
static union bigname *big_free;
|
||||
static int bignames_left, log_queries, cache_size, hash_size;
|
||||
static char *addn_file;
|
||||
static int uid;
|
||||
|
||||
static void cache_free(struct crec *crecp);
|
||||
static void cache_unlink(struct crec *crecp);
|
||||
static void cache_link(struct crec *crecp);
|
||||
static char *record_source(struct hostsfile *add_hosts, int index);
|
||||
|
||||
void cache_init(int size, int logq)
|
||||
{
|
||||
@@ -35,7 +36,7 @@ void cache_init(int size, int logq)
|
||||
cache_size = size;
|
||||
big_free = NULL;
|
||||
bignames_left = size/10;
|
||||
addn_file = NULL;
|
||||
uid = 0;
|
||||
|
||||
cache_inserted = cache_live_freed = 0;
|
||||
|
||||
@@ -47,6 +48,7 @@ void cache_init(int size, int logq)
|
||||
{
|
||||
cache_link(crecp);
|
||||
crecp->flags = 0;
|
||||
crecp->uid = uid++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +85,8 @@ static void cache_free(struct crec *crecp)
|
||||
{
|
||||
crecp->flags &= ~F_FORWARD;
|
||||
crecp->flags &= ~F_REVERSE;
|
||||
|
||||
crecp->uid = uid++; /* invalidate CNAMES pointing to this. */
|
||||
|
||||
if (cache_tail)
|
||||
cache_tail->next = crecp;
|
||||
else
|
||||
@@ -137,31 +140,68 @@ char *cache_get_name(struct crec *crecp)
|
||||
return crecp->name.sname;
|
||||
}
|
||||
|
||||
static void cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
|
||||
static int is_outdated_cname_pointer(struct crec *crecp)
|
||||
{
|
||||
struct crec *target = crecp->addr.cname.cache;
|
||||
|
||||
if (!(crecp->flags & F_CNAME))
|
||||
return 0;
|
||||
|
||||
if (!target)
|
||||
return 1;
|
||||
|
||||
if (crecp->addr.cname.uid == target->uid)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int is_expired(time_t now, struct crec *crecp)
|
||||
{
|
||||
if (crecp->flags & F_IMMORTAL)
|
||||
return 0;
|
||||
|
||||
if (difftime(now, crecp->ttd) < 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
|
||||
{
|
||||
/* Scan and remove old entries.
|
||||
If (flags & F_FORWARD) then remove any forward entries for name and any expired
|
||||
entries but only in the same hash bucket as name.
|
||||
If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
|
||||
entries in the whole cache.
|
||||
If (flags == 0) remove any expired entries in the whole cache. */
|
||||
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) */
|
||||
|
||||
#define F_CACHESTATUS (F_HOSTS | F_DHCP | F_FORWARD | F_REVERSE | F_IPV4 | F_IPV6)
|
||||
struct crec *crecp, **up;
|
||||
flags &= (F_FORWARD | F_REVERSE | F_IPV6 | F_IPV4);
|
||||
|
||||
if (flags & F_FORWARD)
|
||||
{
|
||||
for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
|
||||
if ((!(crecp->flags & F_IMMORTAL) && difftime(now, crecp->ttd) > 0) ||
|
||||
((flags == (crecp->flags & F_CACHESTATUS)) && hostname_isequal(cache_get_name(crecp), name)))
|
||||
{
|
||||
if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
{
|
||||
{
|
||||
cache_unlink(crecp);
|
||||
cache_free(crecp);
|
||||
}
|
||||
}
|
||||
else if ((crecp->flags & F_FORWARD) &&
|
||||
((flags & crecp->flags & (F_IPV4 | F_IPV6)) || (crecp->flags & F_CNAME)) &&
|
||||
hostname_isequal(cache_get_name(crecp), name))
|
||||
{
|
||||
if (crecp->flags & (F_HOSTS | F_DHCP))
|
||||
return 0;
|
||||
*up = crecp->hash_next;
|
||||
cache_unlink(crecp);
|
||||
cache_free(crecp);
|
||||
}
|
||||
else
|
||||
up = &crecp->hash_next;
|
||||
@@ -176,8 +216,7 @@ static void cache_scan_free(char *name, struct all_addr *addr, time_t now, unsig
|
||||
#endif
|
||||
for (i = 0; i < hash_size; i++)
|
||||
for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = crecp->hash_next)
|
||||
if ((!(crecp->flags & F_IMMORTAL) && difftime(now, crecp->ttd) > 0) ||
|
||||
((flags == (crecp->flags & F_CACHESTATUS)) && memcmp(&crecp->addr, addr, addrlen) == 0))
|
||||
if (is_expired(now, crecp))
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
@@ -186,9 +225,20 @@ static void cache_scan_free(char *name, struct all_addr *addr, time_t now, unsig
|
||||
cache_free(crecp);
|
||||
}
|
||||
}
|
||||
else if (!(crecp->flags & (F_HOSTS | F_DHCP)) &&
|
||||
(flags & crecp->flags & F_REVERSE) &&
|
||||
(flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
|
||||
memcmp(&crecp->addr.addr, addr, addrlen) == 0)
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
cache_unlink(crecp);
|
||||
cache_free(crecp);
|
||||
}
|
||||
else
|
||||
up = &crecp->hash_next;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Note: The normal calling sequence is
|
||||
@@ -214,8 +264,8 @@ void cache_start_insert(void)
|
||||
insert_error = 0;
|
||||
}
|
||||
|
||||
void cache_insert(char *name, struct all_addr *addr,
|
||||
time_t now, unsigned long ttl, unsigned short flags)
|
||||
struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
time_t now, unsigned long ttl, unsigned short flags)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
|
||||
@@ -226,7 +276,7 @@ void cache_insert(char *name, struct all_addr *addr,
|
||||
union bigname *big_name = NULL;
|
||||
int freed_all = flags & F_REVERSE;
|
||||
|
||||
log_query(flags | F_UPSTREAM, name, addr);
|
||||
log_query(flags | F_UPSTREAM, name, addr, 0, NULL, 0);
|
||||
|
||||
/* name is needed as workspace by log_query in this case */
|
||||
if ((flags & F_NEG) && (flags & F_REVERSE))
|
||||
@@ -237,18 +287,23 @@ void cache_insert(char *name, struct all_addr *addr,
|
||||
|
||||
/* if previous insertion failed give up now. */
|
||||
if (insert_error)
|
||||
return;
|
||||
return NULL;
|
||||
|
||||
/* First remove any expired entries and entries for the name/address we
|
||||
are currently inserting. */
|
||||
cache_scan_free(name, addr, now, flags);
|
||||
are currently inserting. Fail is we attempt to delete a name from
|
||||
/etc/hosts or DHCP. */
|
||||
if (!cache_scan_free(name, addr, now, flags))
|
||||
{
|
||||
insert_error = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Now get a cache entry from the end of the LRU list */
|
||||
while (1) {
|
||||
if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
|
||||
{
|
||||
insert_error = 1;
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* End of LRU list is still in use: if we didn't scan all the hash
|
||||
@@ -259,7 +314,7 @@ void cache_insert(char *name, struct all_addr *addr,
|
||||
{
|
||||
if (freed_all)
|
||||
{
|
||||
cache_scan_free(cache_get_name(new), &new->addr, now, new->flags);
|
||||
cache_scan_free(cache_get_name(new), &new->addr.addr, now, new->flags);
|
||||
cache_live_freed++;
|
||||
}
|
||||
else
|
||||
@@ -283,7 +338,7 @@ void cache_insert(char *name, struct all_addr *addr,
|
||||
!(big_name = (union bigname *)malloc(sizeof(union bigname))))
|
||||
{
|
||||
insert_error = 1;
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
bignames_left--;
|
||||
@@ -306,10 +361,15 @@ void cache_insert(char *name, struct all_addr *addr,
|
||||
else
|
||||
*cache_get_name(new) = 0;
|
||||
if (addr)
|
||||
memcpy(&new->addr, addr, addrlen);
|
||||
memcpy(&new->addr.addr, addr, addrlen);
|
||||
else
|
||||
new->addr.cname.cache = NULL;
|
||||
|
||||
new->ttd = now + (time_t)ttl;
|
||||
new->next = new_chain;
|
||||
new_chain = new;
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
/* after end of insertion, commit the new entries */
|
||||
@@ -321,10 +381,16 @@ void cache_end_insert(void)
|
||||
while (new_chain)
|
||||
{
|
||||
struct crec *tmp = new_chain->next;
|
||||
cache_hash(new_chain);
|
||||
cache_link(new_chain);
|
||||
/* drop CNAMEs which didn't find a target. */
|
||||
if (is_outdated_cname_pointer(new_chain))
|
||||
cache_free(new_chain);
|
||||
else
|
||||
{
|
||||
cache_hash(new_chain);
|
||||
cache_link(new_chain);
|
||||
cache_inserted++;
|
||||
}
|
||||
new_chain = tmp;
|
||||
cache_inserted++;
|
||||
}
|
||||
new_chain = NULL;
|
||||
}
|
||||
@@ -345,7 +411,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
{
|
||||
next = crecp->hash_next;
|
||||
|
||||
if ((crecp->flags & F_IMMORTAL) || difftime(now, crecp->ttd) < 0)
|
||||
if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
|
||||
{
|
||||
if ((crecp->flags & F_FORWARD) &&
|
||||
(crecp->flags & prot) &&
|
||||
@@ -426,11 +492,11 @@ struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
|
||||
|
||||
for(i=0; i<hash_size; i++)
|
||||
for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = crecp->hash_next)
|
||||
if ((crecp->flags & F_IMMORTAL) || difftime(now, crecp->ttd) < 0)
|
||||
if (!is_expired(now, crecp))
|
||||
{
|
||||
if ((crecp->flags & F_REVERSE) &&
|
||||
(crecp->flags & prot) &&
|
||||
memcmp(&crecp->addr, addr, addrlen) == 0)
|
||||
memcmp(&crecp->addr.addr, addr, addrlen) == 0)
|
||||
{
|
||||
if (crecp->flags & (F_HOSTS | F_DHCP))
|
||||
{
|
||||
@@ -461,19 +527,20 @@ struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
|
||||
if (ans &&
|
||||
(ans->flags & F_REVERSE) &&
|
||||
(ans->flags & prot) &&
|
||||
memcmp(&ans->addr, addr, addrlen) == 0)
|
||||
memcmp(&ans->addr.addr, addr, addrlen) == 0)
|
||||
return ans;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen, unsigned short flags)
|
||||
static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
|
||||
unsigned short flags, int index)
|
||||
{
|
||||
struct crec *lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6));
|
||||
|
||||
/* Remove duplicates in hosts files. */
|
||||
if (lookup && (lookup->flags & F_HOSTS) &&
|
||||
memcmp(&lookup->addr, addr, addrlen) == 0)
|
||||
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
|
||||
free(cache);
|
||||
else
|
||||
{
|
||||
@@ -481,12 +548,13 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
|
||||
if (cache_find_by_addr(NULL, addr, 0, flags & (F_IPV4 | F_IPV6)))
|
||||
flags &= ~F_REVERSE;
|
||||
cache->flags = flags;
|
||||
memcpy(&cache->addr, addr, addrlen);
|
||||
cache->uid = index;
|
||||
memcpy(&cache->addr.addr, addr, addrlen);
|
||||
cache_hash(cache);
|
||||
}
|
||||
}
|
||||
|
||||
static void read_hostsfile(char *filename, int opts, char *buff, char *domain_suffix, int is_addn)
|
||||
static void read_hostsfile(char *filename, int opts, char *buff, char *domain_suffix, int index)
|
||||
{
|
||||
FILE *f = fopen(filename, "r");
|
||||
char *line;
|
||||
@@ -531,9 +599,6 @@ static void read_hostsfile(char *filename, int opts, char *buff, char *domain_su
|
||||
else
|
||||
continue;
|
||||
|
||||
if (is_addn)
|
||||
flags |= F_ADDN;
|
||||
|
||||
while ((token = strtok(NULL, " \t\n\r")) && (*token != '#'))
|
||||
{
|
||||
struct crec *cache;
|
||||
@@ -548,12 +613,12 @@ static void read_hostsfile(char *filename, int opts, char *buff, char *domain_su
|
||||
strcpy(cache->name.sname, token);
|
||||
strcat(cache->name.sname, ".");
|
||||
strcat(cache->name.sname, domain_suffix);
|
||||
add_hosts_entry(cache, &addr, addrlen, flags);
|
||||
add_hosts_entry(cache, &addr, addrlen, flags, index);
|
||||
}
|
||||
if ((cache = malloc(sizeof(struct crec) + strlen(token)+1-SMALLDNAME)))
|
||||
{
|
||||
strcpy(cache->name.sname, token);
|
||||
add_hosts_entry(cache, &addr, addrlen, flags);
|
||||
add_hosts_entry(cache, &addr, addrlen, flags, index);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -566,11 +631,13 @@ static void read_hostsfile(char *filename, int opts, char *buff, char *domain_su
|
||||
syslog(LOG_INFO, "read %s - %d addresses", filename, count);
|
||||
}
|
||||
|
||||
void cache_reload(int opts, char *buff, char *domain_suffix, char *addn_hosts)
|
||||
void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *addn_hosts)
|
||||
{
|
||||
struct crec *cache, **up, *tmp;
|
||||
int i;
|
||||
|
||||
cache_inserted = cache_live_freed = 0;
|
||||
|
||||
for (i=0; i<hash_size; i++)
|
||||
for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
|
||||
{
|
||||
@@ -603,11 +670,11 @@ void cache_reload(int opts, char *buff, char *domain_suffix, char *addn_hosts)
|
||||
|
||||
if (!(opts & OPT_NO_HOSTS))
|
||||
read_hostsfile(HOSTSFILE, opts, buff, domain_suffix, 0);
|
||||
if (addn_hosts)
|
||||
while (addn_hosts)
|
||||
{
|
||||
read_hostsfile(addn_hosts, opts, buff, domain_suffix, 1);
|
||||
addn_file = addn_hosts;
|
||||
}
|
||||
read_hostsfile(addn_hosts->fname, opts, buff, domain_suffix, addn_hosts->index);
|
||||
addn_hosts = addn_hosts->next;
|
||||
}
|
||||
}
|
||||
|
||||
void cache_unhash_dhcp(void)
|
||||
@@ -633,36 +700,43 @@ void cache_unhash_dhcp(void)
|
||||
dhcp_inuse = NULL;
|
||||
}
|
||||
|
||||
void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd, unsigned short flags)
|
||||
void cache_add_dhcp_entry(struct daemon *daemon, char *host_name,
|
||||
struct in_addr *host_address, time_t ttd)
|
||||
{
|
||||
struct crec *crec;
|
||||
|
||||
if ((crec = cache_find_by_name(NULL, host_name, 0, F_IPV4)))
|
||||
unsigned short flags = F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
|
||||
|
||||
if (!host_name)
|
||||
return;
|
||||
|
||||
if ((crec = cache_find_by_name(NULL, host_name, 0, F_IPV4 | F_CNAME)))
|
||||
{
|
||||
if (crec->flags & F_HOSTS)
|
||||
{
|
||||
if (crec->addr.addr.addr4.s_addr != host_address->s_addr)
|
||||
syslog(LOG_WARNING, "not naming DHCP lease for %s because it clashes with an /etc/hosts entry.", host_name);
|
||||
if (crec->addr.addr.addr.addr4.s_addr != host_address->s_addr)
|
||||
{
|
||||
strcpy(daemon->namebuff, inet_ntoa(crec->addr.addr.addr.addr4));
|
||||
syslog(LOG_WARNING,
|
||||
"not giving name %s to the DHCP lease of %s because "
|
||||
"the name exists in %s with address %s",
|
||||
host_name, inet_ntoa(*host_address),
|
||||
record_source(daemon->addn_hosts, crec->uid), daemon->namebuff);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (!(crec->flags & F_DHCP))
|
||||
{
|
||||
if (crec->flags & F_NEG)
|
||||
{
|
||||
/* name may have been searched for before being allocated to DHCP and
|
||||
therefore got a negative cache entry. If so delete it and continue. */
|
||||
cache_scan_free(host_name, NULL, 0, F_IPV4 | F_FORWARD);
|
||||
goto newrec;
|
||||
}
|
||||
else
|
||||
syslog(LOG_WARNING, "not naming DHCP lease for %s because it clashes with a cached name.", cache_get_name(crec));
|
||||
}
|
||||
return;
|
||||
cache_scan_free(host_name, NULL, 0, crec->flags & (F_IPV4 | F_CNAME | F_FORWARD));
|
||||
}
|
||||
|
||||
if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, F_IPV4)) && (crec->flags & F_NEG))
|
||||
cache_scan_free(NULL, (struct all_addr *)host_address, 0, F_IPV4 | F_REVERSE);
|
||||
|
||||
newrec:
|
||||
if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, F_IPV4)))
|
||||
{
|
||||
if (crec->flags & F_NEG)
|
||||
cache_scan_free(NULL, (struct all_addr *)host_address, 0, F_IPV4 | F_REVERSE);
|
||||
else
|
||||
/* avoid multiple reverse mappings */
|
||||
flags &= ~F_REVERSE;
|
||||
}
|
||||
|
||||
if ((crec = dhcp_spare))
|
||||
dhcp_spare = dhcp_spare->prev;
|
||||
else /* need new one */
|
||||
@@ -670,12 +744,12 @@ void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t
|
||||
|
||||
if (crec) /* malloc may fail */
|
||||
{
|
||||
crec->flags = F_DHCP | F_FORWARD | F_IPV4 | flags;
|
||||
crec->flags = flags;
|
||||
if (ttd == 0)
|
||||
crec->flags |= F_IMMORTAL;
|
||||
else
|
||||
crec->ttd = ttd;
|
||||
crec->addr.addr.addr4 = *host_address;
|
||||
crec->addr.addr.addr.addr4 = *host_address;
|
||||
crec->name.namep = host_name;
|
||||
crec->prev = dhcp_inuse;
|
||||
dhcp_inuse = crec;
|
||||
@@ -685,12 +759,12 @@ void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t
|
||||
|
||||
|
||||
|
||||
void dump_cache(int debug, int cache_size)
|
||||
void dump_cache(struct daemon *daemon)
|
||||
{
|
||||
syslog(LOG_INFO, "cache size %d, %d/%d cache insertions re-used unexpired cache entries.",
|
||||
cache_size, cache_live_freed, cache_inserted);
|
||||
daemon->cachesize, cache_live_freed, cache_inserted);
|
||||
|
||||
if (debug)
|
||||
if (daemon->options & (OPT_DEBUG | OPT_LOG))
|
||||
{
|
||||
struct crec *cache ;
|
||||
char addrbuff[ADDRSTRLEN];
|
||||
@@ -702,14 +776,21 @@ void dump_cache(int debug, int cache_size)
|
||||
{
|
||||
if ((cache->flags & F_NEG) && (cache->flags & F_FORWARD))
|
||||
addrbuff[0] = 0;
|
||||
else if (cache->flags & F_CNAME)
|
||||
{
|
||||
addrbuff[0] = 0;
|
||||
addrbuff[ADDRSTRLEN-1] = 0;
|
||||
if (!is_outdated_cname_pointer(cache))
|
||||
strncpy(addrbuff, cache_get_name(cache->addr.cname.cache), ADDRSTRLEN);
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (cache->flags & F_IPV4)
|
||||
inet_ntop(AF_INET, &cache->addr, addrbuff, ADDRSTRLEN);
|
||||
inet_ntop(AF_INET, &cache->addr.addr, addrbuff, ADDRSTRLEN);
|
||||
else if (cache->flags & F_IPV6)
|
||||
inet_ntop(AF_INET6, &cache->addr, addrbuff, ADDRSTRLEN);
|
||||
inet_ntop(AF_INET6, &cache->addr.addr, addrbuff, ADDRSTRLEN);
|
||||
#else
|
||||
else
|
||||
strcpy(addrbuff, inet_ntoa(cache->addr.addr.addr4));
|
||||
strcpy(addrbuff, inet_ntoa(cache->addr.addr.addr.addr4));
|
||||
#endif
|
||||
syslog(LOG_DEBUG,
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
@@ -720,6 +801,7 @@ void dump_cache(int debug, int cache_size)
|
||||
cache_get_name(cache), addrbuff,
|
||||
cache->flags & F_IPV4 ? "4" : "",
|
||||
cache->flags & F_IPV6 ? "6" : "",
|
||||
cache->flags & F_CNAME ? "C" : "",
|
||||
cache->flags & F_FORWARD ? "F" : " ",
|
||||
cache->flags & F_REVERSE ? "R" : " ",
|
||||
cache->flags & F_IMMORTAL ? "I" : " ",
|
||||
@@ -727,24 +809,40 @@ void dump_cache(int debug, int cache_size)
|
||||
cache->flags & F_NEG ? "N" : " ",
|
||||
cache->flags & F_NXDOMAIN ? "X" : " ",
|
||||
cache->flags & F_HOSTS ? "H" : " ",
|
||||
cache->flags & F_ADDN ? "A" : " ",
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
cache->flags & F_IMMORTAL ? 0: (unsigned long)cache->ttd) ;
|
||||
cache->flags & F_IMMORTAL ? 0: (unsigned long)cache->ttd
|
||||
#else
|
||||
cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd))) ;
|
||||
cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd))
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *record_source(struct hostsfile *addn_hosts, int index)
|
||||
{
|
||||
char *source = HOSTSFILE;
|
||||
while (addn_hosts)
|
||||
{
|
||||
if (addn_hosts->index == index)
|
||||
{
|
||||
source = addn_hosts->fname;
|
||||
break;
|
||||
}
|
||||
addn_hosts = addn_hosts->next;
|
||||
}
|
||||
|
||||
void log_query(unsigned short flags, char *name, struct all_addr *addr)
|
||||
return source;
|
||||
}
|
||||
|
||||
void log_query(unsigned short flags, char *name, struct all_addr *addr,
|
||||
unsigned short type, struct hostsfile *addn_hosts, int index)
|
||||
{
|
||||
char *source;
|
||||
char *verb = "is";
|
||||
char types[20];
|
||||
char addrbuff[ADDRSTRLEN];
|
||||
|
||||
|
||||
if (!log_queries)
|
||||
return;
|
||||
|
||||
@@ -768,6 +866,18 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr)
|
||||
else if (flags & F_IPV6)
|
||||
strcat(addrbuff, "-IPv6");
|
||||
}
|
||||
else if (flags & F_CNAME)
|
||||
{
|
||||
/* nasty abuse of IPV4 and IPV6 flags */
|
||||
if (flags & F_IPV4)
|
||||
strcpy(addrbuff, "<MX>");
|
||||
else if (flags & F_IPV6)
|
||||
strcpy(addrbuff, "<SRV>");
|
||||
else if (flags & F_NXDOMAIN)
|
||||
strcpy(addrbuff, "<TXT>");
|
||||
else
|
||||
strcpy(addrbuff, "<CNAME>");
|
||||
}
|
||||
else
|
||||
#ifdef HAVE_IPV6
|
||||
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
||||
@@ -775,17 +885,12 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr)
|
||||
#else
|
||||
strcpy(addrbuff, inet_ntoa(addr->addr.addr4));
|
||||
#endif
|
||||
|
||||
|
||||
if (flags & F_DHCP)
|
||||
source = "DHCP";
|
||||
else if (flags & F_HOSTS)
|
||||
{
|
||||
if (flags & F_ADDN)
|
||||
source = addn_file;
|
||||
else
|
||||
source = HOSTSFILE;
|
||||
}
|
||||
else if (flags & F_CONFIG)
|
||||
source = record_source(addn_hosts, index);
|
||||
else if (flags & F_CONFIG)
|
||||
source = "config";
|
||||
else if (flags & F_UPSTREAM)
|
||||
source = "reply";
|
||||
@@ -796,7 +901,48 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr)
|
||||
}
|
||||
else if (flags & F_QUERY)
|
||||
{
|
||||
source = "query";
|
||||
unsigned int i;
|
||||
static struct {
|
||||
unsigned int type;
|
||||
char *name;
|
||||
} typestr[] = {
|
||||
{ 1, "A" },
|
||||
{ 2, "NS" },
|
||||
{ 5, "CNAME" },
|
||||
{ 6, "SOA" },
|
||||
{ 10, "NULL" },
|
||||
{ 11, "WKS" },
|
||||
{ 12, "PTR" },
|
||||
{ 13, "HINFO" },
|
||||
{ 15, "MX" },
|
||||
{ 16, "TXT" },
|
||||
{ 22, "NSAP" },
|
||||
{ 23, "NSAP_PTR" },
|
||||
{ 24, "SIG" },
|
||||
{ 25, "KEY" },
|
||||
{ 28, "AAAA" },
|
||||
{ 33, "SRV" },
|
||||
{ 36, "KX" },
|
||||
{ 37, "CERT" },
|
||||
{ 38, "A6" },
|
||||
{ 39, "DNAME" },
|
||||
{ 41, "OPT" },
|
||||
{ 250, "TSIG" },
|
||||
{ 251, "IXFR" },
|
||||
{ 252, "AXFR" },
|
||||
{ 253, "MAILB" },
|
||||
{ 254, "MAILA" },
|
||||
{ 255, "ANY" }
|
||||
};
|
||||
|
||||
if (type != 0)
|
||||
{
|
||||
sprintf(types, "query[type=%d]", type);
|
||||
for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
|
||||
if (typestr[i].type == type)
|
||||
sprintf(types,"query[%s]", typestr[i].name);
|
||||
}
|
||||
source = types;
|
||||
verb = "from";
|
||||
}
|
||||
else
|
||||
|
||||
78
src/config.h
78
src/config.h
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2005 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
|
||||
@@ -12,10 +12,13 @@
|
||||
|
||||
/* Author's email: simon@thekelleys.org.uk */
|
||||
|
||||
#define VERSION "2.9"
|
||||
#define VERSION "2.22"
|
||||
|
||||
#define FTABSIZ 150 /* max number of outstanding requests */
|
||||
#define TIMEOUT 20 /* drop queries after TIMEOUT seconds */
|
||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
|
||||
#define EDNS_PKTSZ 1280 /* default max EDNS.0 UDP packet from RFC2671 */
|
||||
#define TIMEOUT 20 /* drop UDP queries after TIMEOUT seconds */
|
||||
#define LOGRATE 120 /* log table overflows every LOGRATE seconds */
|
||||
#define CACHESIZ 150 /* default cache size */
|
||||
#define MAXTOK 50 /* token in DHCP leases */
|
||||
@@ -31,9 +34,12 @@
|
||||
#define RUNFILE "/var/run/dnsmasq.pid"
|
||||
#if defined(__FreeBSD__) || defined (__OpenBSD__)
|
||||
# define LEASEFILE "/var/db/dnsmasq.leases"
|
||||
# define CONFFILE "/usr/local/etc/dnsmasq.conf"
|
||||
#else
|
||||
# define LEASEFILE "/var/lib/misc/dnsmasq.leases"
|
||||
#endif
|
||||
#if defined(__FreeBSD__)
|
||||
# define CONFFILE "/usr/local/etc/dnsmasq.conf"
|
||||
#else
|
||||
# define CONFFILE "/etc/dnsmasq.conf"
|
||||
#endif
|
||||
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||
@@ -58,12 +64,21 @@
|
||||
# define DNSMASQ_LOG_FAC(debug) LOG_DAEMON
|
||||
#endif
|
||||
|
||||
/* A small collection of RR-types which are missing on some platforms */
|
||||
|
||||
#ifndef T_SRV
|
||||
# define T_SRV 33
|
||||
#endif
|
||||
|
||||
#ifndef T_OPT
|
||||
# define T_OPT 41
|
||||
#endif
|
||||
|
||||
/* Decide if we're going to support IPv6 */
|
||||
/* We assume that systems which don't have IPv6
|
||||
headers don't have ntop and pton either */
|
||||
|
||||
#if defined(INET6_ADDRSTRLEN) && !defined(NO_IPV6)
|
||||
#if defined(INET6_ADDRSTRLEN) && defined(IPV6_V6ONLY) && !defined(NO_IPV6)
|
||||
# define HAVE_IPV6
|
||||
# define ADDRSTRLEN INET6_ADDRSTRLEN
|
||||
# if defined(SOL_IPV6)
|
||||
@@ -89,7 +104,6 @@
|
||||
new system, you may want to edit these.
|
||||
May replace this with Autoconf one day.
|
||||
|
||||
|
||||
HAVE_LINUX_IPV6_PROC
|
||||
define this to do IPv6 interface discovery using
|
||||
proc/net/if_inet6 ala LINUX.
|
||||
@@ -142,7 +156,13 @@ HAVE_PSELECT
|
||||
If your C library implements pselect, define this.
|
||||
|
||||
HAVE_BPF
|
||||
If your OS implements Berkeley PAcket filter, define this.
|
||||
If your OS implements Berkeley Packet filter, define this.
|
||||
|
||||
HAVE_RTNETLINK
|
||||
If your OS has the Linux Routing netlink socket API and suitable
|
||||
C library headers, define this. Note that the code will fall
|
||||
back to the Berkley API at runtime if netlink support is not
|
||||
configured into the kernel.
|
||||
|
||||
NOTES:
|
||||
For Linux you should define
|
||||
@@ -151,6 +171,7 @@ NOTES:
|
||||
HAVE_RANDOM
|
||||
HAVE_DEV_RANDOM
|
||||
HAVE_DEV_URANDOM
|
||||
HAVE_RTNETLINK
|
||||
you should NOT define
|
||||
HAVE_ARC4RANDOM
|
||||
HAVE_SOCKADDR_SA_LEN
|
||||
@@ -161,11 +182,14 @@ NOTES:
|
||||
HAVE_BPF
|
||||
you should NOT define
|
||||
HAVE_LINUX_IPV6_PROC
|
||||
HAVE_RTNETLINK
|
||||
and you MAY define
|
||||
HAVE_ARC4RANDOM - OpenBSD and FreeBSD
|
||||
HAVE_DEV_URANDOM - OpenBSD and FreeBSD
|
||||
HAVE_DEV_RANDOM - FreeBSD (OpenBSD with hardware random number generator)
|
||||
HAVE_GETOPT_LONG - only if you link GNU getopt.
|
||||
HAVE_ARC4RANDOM - OpenBSD and FreeBSD and NetBSD version 2.0 or later
|
||||
HAVE_DEV_URANDOM - OpenBSD and FreeBSD and NetBSD
|
||||
HAVE_DEV_RANDOM - FreeBSD and NetBSD
|
||||
(OpenBSD with hardware random number generator)
|
||||
HAVE_GETOPT_LONG - NetBSD, later FreeBSD
|
||||
(FreeBSD and OpenBSD only if you link GNU getopt)
|
||||
|
||||
*/
|
||||
|
||||
@@ -183,14 +207,17 @@ NOTES:
|
||||
#if defined(__uClinux__) || defined(__UCLIBC__)
|
||||
#undef HAVE_LINUX_IPV6_PROC
|
||||
#define HAVE_GETOPT_LONG
|
||||
#define HAVE_RTNETLINK
|
||||
#undef HAVE_ARC4RANDOM
|
||||
#define HAVE_RANDOM
|
||||
#define HAVE_DEV_URANDOM
|
||||
#define HAVE_DEV_RANDOM
|
||||
#undef HAVE_SOCKADDR_SA_LEN
|
||||
#undef HAVE_PSELECT
|
||||
/* Don't fork into background on uClinux */
|
||||
#if defined(__uClinux__)
|
||||
/* Never use fork() on uClinux. Note that this is subtly different from the
|
||||
--keep-in-foreground option, since it also suppresses forking new
|
||||
processes for TCP connections. It's intended for use on MMU-less kernels. */
|
||||
# define NO_FORK
|
||||
#endif
|
||||
|
||||
@@ -205,6 +232,7 @@ NOTES:
|
||||
(_LINUX_C_LIB_VERSION_MAJOR == 5 )
|
||||
#undef HAVE_IPV6
|
||||
#undef HAVE_LINUX_IPV6_PROC
|
||||
#undef HAVE_RTNETLINK
|
||||
#define HAVE_GETOPT_LONG
|
||||
#undef HAVE_ARC4RANDOM
|
||||
#define HAVE_RANDOM
|
||||
@@ -213,13 +241,13 @@ NOTES:
|
||||
#undef HAVE_SOCKADDR_SA_LEN
|
||||
#undef HAVE_PSELECT
|
||||
/* Fix various misfeatures of libc5 headers */
|
||||
#define T_SRV 33
|
||||
typedef unsigned long in_addr_t;
|
||||
typedef size_t socklen_t;
|
||||
|
||||
/* This is for glibc 2.x */
|
||||
#elif defined(__linux__)
|
||||
#define HAVE_LINUX_IPV6_PROC
|
||||
#define HAVE_RTNETLINK
|
||||
#define HAVE_GETOPT_LONG
|
||||
#undef HAVE_ARC4RANDOM
|
||||
#define HAVE_RANDOM
|
||||
@@ -237,12 +265,15 @@ typedef unsigned long in_addr_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* #elif defined(__OpenBSD__)
|
||||
#error The sockets API in OpenBSD does not provide facilities required by dnsmasq
|
||||
*/
|
||||
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
#undef HAVE_LINUX_IPV6_PROC
|
||||
#undef HAVE_GETOPT_LONG
|
||||
#undef HAVE_RTNETLINK
|
||||
/* Later verions of FreeBSD have getopt_long() */
|
||||
#if defined(optional_argument) && defined(required_argument)
|
||||
# define HAVE_GETOPT_LONG
|
||||
#else
|
||||
# undef HAVE_GETOPT_LONG
|
||||
#endif
|
||||
#define HAVE_ARC4RANDOM
|
||||
#define HAVE_RANDOM
|
||||
#define HAVE_DEV_URANDOM
|
||||
@@ -252,6 +283,7 @@ typedef unsigned long in_addr_t;
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
#undef HAVE_LINUX_IPV6_PROC
|
||||
#undef HAVE_RTNETLINK
|
||||
#undef HAVE_GETOPT_LONG
|
||||
#define HAVE_ARC4RANDOM
|
||||
#define HAVE_RANDOM
|
||||
@@ -259,20 +291,19 @@ typedef unsigned long in_addr_t;
|
||||
#define HAVE_SOCKADDR_SA_LEN
|
||||
#undef HAVE_PSELECT
|
||||
#define HAVE_BPF
|
||||
#define BIND_8_COMPAT
|
||||
/* Define before sys/socket.h is included so we get socklen_t */
|
||||
#define _BSD_SOCKLEN_T_
|
||||
/* The two below are not defined in Mac OS X arpa/nameserv.h */
|
||||
/* This is not defined in Mac OS X arpa/nameserv.h */
|
||||
#define IN6ADDRSZ 16
|
||||
#define T_SRV 33
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
#undef HAVE_LINUX_IPV6_PROC
|
||||
#undef HAVE_GETOPT_LONG
|
||||
#undef HAVE_RTNETLINK
|
||||
#define HAVE_GETOPT_LONG
|
||||
#undef HAVE_ARC4RANDOM
|
||||
#define HAVE_RANDOM
|
||||
#undef HAVE_DEV_URANDOM
|
||||
#undef HAVE_DEV_RANDOM
|
||||
#define HAVE_DEV_URANDOM
|
||||
#define HAVE_DEV_RANDOM
|
||||
#define HAVE_SOCKADDR_SA_LEN
|
||||
#undef HAVE_PSELECT
|
||||
#define HAVE_BPF
|
||||
@@ -280,6 +311,7 @@ typedef unsigned long in_addr_t;
|
||||
/* env "LIBS=-lsocket -lnsl" make */
|
||||
#elif defined(__sun) || defined(__sun__)
|
||||
#undef HAVE_LINUX_IPV6_PROC
|
||||
#undef HAVE_RTNETLINK
|
||||
#undef HAVE_GETOPT_LONG
|
||||
#undef HAVE_ARC4RANDOM
|
||||
#define HAVE_RANDOM
|
||||
|
||||
571
src/dhcp.c
571
src/dhcp.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2003 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2005 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,61 +14,101 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
void dhcp_init(int *fdp, int* rfdp)
|
||||
void dhcp_init(struct daemon *daemon)
|
||||
{
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
struct sockaddr_in saddr;
|
||||
int opt = 1;
|
||||
|
||||
int flags, oneopt = 1, zeroopt = 0;
|
||||
struct dhcp_config *configs, *cp;
|
||||
|
||||
if (fd == -1)
|
||||
die ("cannot create DHCP socket : %s", NULL);
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
if ((flags = fcntl(fd, F_GETFL, 0)) == -1 ||
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||
#if defined(IP_PKTINFO)
|
||||
setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
|
||||
#elif defined(IP_RECVIF)
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
|
||||
#endif
|
||||
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)) == -1)
|
||||
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)
|
||||
die("failed to set options on DHCP socket: %s", NULL);
|
||||
|
||||
/* When bind-interfaces is set, there might be more than one dnmsasq
|
||||
instance binding port 67. That's Ok if they serve different networks.
|
||||
Need to set REUSEADDR to make this posible. */
|
||||
if ((daemon->options & OPT_NOWILD) &&
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt)) == -1)
|
||||
die("failed to set SO_REUSEADDR on DHCP socket: %s", NULL);
|
||||
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = htons(DHCP_SERVER_PORT);
|
||||
saddr.sin_addr.s_addr = INADDR_ANY;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
saddr.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)))
|
||||
die("failed to bind DHCP server socket: %s", NULL);
|
||||
|
||||
*fdp = fd;
|
||||
daemon->dhcpfd = fd;
|
||||
|
||||
if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1 ||
|
||||
(flags = fcntl(fd, F_GETFL, 0)) == -1 ||
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) ||
|
||||
setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
|
||||
die("cannot create ICMP raw socket: %s.", NULL);
|
||||
|
||||
daemon->dhcp_icmp_fd = fd;
|
||||
|
||||
#ifdef HAVE_BPF
|
||||
opt = 0;
|
||||
while (1)
|
||||
{
|
||||
char filename[50];
|
||||
sprintf(filename, "/dev/bpf%d", opt++);
|
||||
if ((fd = open(filename, O_RDWR, 0)) != -1)
|
||||
break;
|
||||
if (errno != EBUSY)
|
||||
die("cannot create DHCP BPF socket: %s", NULL);
|
||||
}
|
||||
{
|
||||
int i = 0;
|
||||
while (1)
|
||||
{
|
||||
char filename[50];
|
||||
sprintf(filename, "/dev/bpf%d", i++);
|
||||
if ((fd = open(filename, O_RDWR, 0)) != -1)
|
||||
break;
|
||||
if (errno != EBUSY)
|
||||
die("cannot create DHCP BPF socket: %s", NULL);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETHERTYPE_IP))) == -1)
|
||||
die("cannot create DHCP packet socket: %s", NULL);
|
||||
/* since we don't ever use the packet socket for reception,
|
||||
and it receives copies of _all_ IP packets, then that data
|
||||
will build up in kernel buffers, wasting memory. Set the
|
||||
socket receive buffer size to one to avoid that. (zero is
|
||||
rejected as non-sensical by some BSD kernels) */
|
||||
if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETHERTYPE_IP))) == -1 ||
|
||||
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1)
|
||||
die("cannot create DHCP packet socket: %s. "
|
||||
"Is CONFIG_PACKET enabled in your kernel?", NULL);
|
||||
#endif
|
||||
|
||||
*rfdp = fd;
|
||||
daemon->dhcp_raw_fd = fd;
|
||||
|
||||
/* If the same IP appears in more than one host config, then DISCOVER
|
||||
for one of the hosts will get the address, but REQUEST will be NAKed,
|
||||
since the address is reserved by the other one -> protocol loop. */
|
||||
for (configs = daemon->dhcp_conf; configs; configs = configs->next)
|
||||
for (cp = configs->next; cp; cp = cp->next)
|
||||
if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr)
|
||||
die("duplicate IP address %s in dhcp-config directive.", inet_ntoa(cp->addr));
|
||||
|
||||
daemon->dhcp_packet = safe_malloc(sizeof(struct udp_dhcp_packet));
|
||||
/* These two each hold a DHCP option max size 255
|
||||
and get a terminating zero added */
|
||||
daemon->dhcp_buff = safe_malloc(256);
|
||||
daemon->dhcp_buff2 = safe_malloc(256);
|
||||
|
||||
}
|
||||
|
||||
void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
|
||||
struct dhcp_vendor *vendors,
|
||||
time_t now, char *namebuff, char *domain_suffix,
|
||||
char *dhcp_file, char *dhcp_sname,
|
||||
struct in_addr dhcp_next_server, int dhcp_fd, int raw_fd,
|
||||
struct iname *names, struct iname *addrs, struct iname *except)
|
||||
void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
{
|
||||
struct udp_dhcp_packet *rawpacket = (struct udp_dhcp_packet *)packet;
|
||||
struct dhcp_packet *mess = (struct dhcp_packet *)&rawpacket->data;
|
||||
struct udp_dhcp_packet *rawpacket = daemon->dhcp_packet;
|
||||
struct dhcp_packet *mess = &rawpacket->data;
|
||||
struct dhcp_context *context;
|
||||
struct iname *tmp;
|
||||
struct ifreq ifr;
|
||||
@@ -76,8 +116,7 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
struct iovec iov[2];
|
||||
struct cmsghdr *cmptr;
|
||||
int sz, newlen, iface_index = 0;
|
||||
struct in_addr source, iface_netmask, iface_addr, iface_broadcast;
|
||||
struct in_addr netmask_save, broadcast_save, router;
|
||||
struct in_addr iface_addr;
|
||||
#ifdef HAVE_BPF
|
||||
unsigned char iface_hwaddr[ETHER_ADDR_LEN];
|
||||
#endif
|
||||
@@ -91,8 +130,8 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
#endif
|
||||
} control_u;
|
||||
|
||||
iov[0].iov_base = (char *)&rawpacket->data;
|
||||
iov[0].iov_len = DNSMASQ_PACKETSZ - (sizeof(struct ip) + sizeof(struct udphdr));
|
||||
iov[0].iov_base = (char *)mess;
|
||||
iov[0].iov_len = sizeof(struct dhcp_packet);
|
||||
|
||||
msg.msg_control = control_u.control;
|
||||
msg.msg_controllen = sizeof(control_u);
|
||||
@@ -102,7 +141,7 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
sz = recvmsg(dhcp_fd, &msg, 0);
|
||||
sz = recvmsg(daemon->dhcpfd, &msg, 0);
|
||||
|
||||
if (sz < (int)(sizeof(*mess) - sizeof(mess->options)))
|
||||
return;
|
||||
@@ -115,7 +154,7 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
iface_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
|
||||
|
||||
if (!(ifr.ifr_ifindex = iface_index) ||
|
||||
ioctl(dhcp_fd, SIOCGIFNAME, &ifr) == -1)
|
||||
ioctl(daemon->dhcpfd, SIOCGIFNAME, &ifr) == -1)
|
||||
return;
|
||||
|
||||
#elif defined(IP_RECVIF)
|
||||
@@ -129,35 +168,37 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
return;
|
||||
|
||||
#else
|
||||
while (names->isloop)
|
||||
names = names->next;
|
||||
strcpy(ifr.ifr_name, names->name);
|
||||
{
|
||||
struct iname *name;
|
||||
for (name = daemon->if_names; name->isloop; name = name->next);
|
||||
strcpy(ifr.ifr_name, name->name);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_BPF
|
||||
ifr.ifr_addr.sa_family = AF_LINK;
|
||||
if (ioctl(dhcp_fd, SIOCGIFADDR, &ifr) < 0)
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) < 0)
|
||||
return;
|
||||
memcpy(iface_hwaddr, LLADDR((struct sockaddr_dl *)&ifr.ifr_addr), ETHER_ADDR_LEN);
|
||||
#endif
|
||||
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
if (ioctl(dhcp_fd, SIOCGIFADDR, &ifr) < 0 )
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) < 0 )
|
||||
return;
|
||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
|
||||
/* enforce available interface configuration */
|
||||
for (tmp = except; tmp; tmp = tmp->next)
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
return;
|
||||
|
||||
if (names || addrs)
|
||||
if (daemon->if_names || daemon->if_addrs)
|
||||
{
|
||||
for (tmp = names; tmp; tmp = tmp->next)
|
||||
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
break;
|
||||
if (!tmp)
|
||||
for (tmp = addrs; tmp; tmp = tmp->next)
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
if (tmp->addr.sa.sa_family == AF_INET &&
|
||||
tmp->addr.in.sin_addr.s_addr == iface_addr.s_addr)
|
||||
break;
|
||||
@@ -165,90 +206,46 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the packet came via a relay, use that address to look up the context,
|
||||
else use the address of the interface is arrived on. */
|
||||
source = mess->giaddr.s_addr ? mess->giaddr : iface_addr;
|
||||
|
||||
iface_netmask.s_addr = 0;
|
||||
iface_broadcast.s_addr = 0;
|
||||
|
||||
if (ioctl(dhcp_fd, SIOCGIFNETMASK, &ifr) != -1)
|
||||
{
|
||||
iface_netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
/* we can use the interface netmask if either the packet came direct,
|
||||
or it came via a relay listening on the same network. This sounds unlikely,
|
||||
but it happens with win4lin. */
|
||||
if (!is_same_net(source, iface_addr, iface_netmask))
|
||||
iface_netmask.s_addr = 0;
|
||||
else if (ioctl(dhcp_fd, SIOCGIFBRDADDR, &ifr) != -1)
|
||||
iface_broadcast = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
|
||||
}
|
||||
|
||||
for (context = contexts; context; context = context->next)
|
||||
/* unlinked contexts are marked by context->current == context */
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
context->current = context;
|
||||
|
||||
#ifdef HAVE_RTNETLINK
|
||||
if (!netlink_process(daemon, iface_index, mess->giaddr, iface_addr, &context))
|
||||
#endif
|
||||
{
|
||||
struct in_addr netmask = context->netmask.s_addr ? context->netmask : iface_netmask;
|
||||
|
||||
if (netmask.s_addr &&
|
||||
is_same_net(source, context->start, netmask) &&
|
||||
is_same_net(source, context->end, netmask))
|
||||
break;
|
||||
}
|
||||
struct in_addr iface_netmask, iface_broadcast;
|
||||
|
||||
if (!context)
|
||||
{
|
||||
syslog(LOG_WARNING, "no address range available for DHCP request via %s", inet_ntoa(source));
|
||||
return;
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFNETMASK, &ifr) < 0)
|
||||
return;
|
||||
iface_netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) < 0)
|
||||
return;
|
||||
iface_broadcast = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
|
||||
context = complete_context(daemon, iface_addr, NULL, iface_netmask,
|
||||
iface_broadcast, mess->giaddr, iface_addr);
|
||||
}
|
||||
|
||||
netmask_save = context->netmask;
|
||||
broadcast_save = context->broadcast;
|
||||
|
||||
if (!context->netmask.s_addr)
|
||||
context->netmask = iface_netmask;
|
||||
|
||||
if (!context->broadcast.s_addr)
|
||||
{
|
||||
if (iface_broadcast.s_addr)
|
||||
context->broadcast = iface_broadcast;
|
||||
else
|
||||
context->broadcast.s_addr = (source.s_addr & context->netmask.s_addr) | ~context->netmask.s_addr;
|
||||
}
|
||||
|
||||
if (ioctl(dhcp_fd, SIOCGIFMTU, &ifr) == -1)
|
||||
ifr.ifr_mtu = ETHERMTU;
|
||||
|
||||
/* Normally, we set the default route to point to the machine which is getting the
|
||||
DHCP broadcast, either this machine or a relay. In the special case that the relay
|
||||
is on the same network as us, we set the default route to us, not the relay.
|
||||
This is the win4lin scenario again. */
|
||||
if (is_same_net(source, iface_addr, context->netmask))
|
||||
router = iface_addr;
|
||||
else
|
||||
router = source;
|
||||
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
newlen = dhcp_reply(context, iface_addr, ifr.ifr_name, ifr.ifr_mtu,
|
||||
rawpacket, sz, now, namebuff,
|
||||
dhcp_opts, dhcp_configs, vendors, domain_suffix,
|
||||
dhcp_file, dhcp_sname, dhcp_next_server, router);
|
||||
newlen = dhcp_reply(daemon, context, ifr.ifr_name, sz, now);
|
||||
lease_update_file(0, now);
|
||||
lease_update_dns();
|
||||
|
||||
context->netmask = netmask_save;
|
||||
context->broadcast = broadcast_save;
|
||||
lease_update_dns(daemon);
|
||||
|
||||
if (newlen == 0)
|
||||
return;
|
||||
|
||||
if (mess->giaddr.s_addr || mess->ciaddr.s_addr)
|
||||
{
|
||||
/* To send to BOOTP relay or configured client, use
|
||||
the IP packet */
|
||||
/* To send to BOOTP relay or configured client, use the IP packet */
|
||||
|
||||
struct sockaddr_in dest;
|
||||
dest.sin_family = AF_INET;
|
||||
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
dest.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
|
||||
if (mess->giaddr.s_addr)
|
||||
{
|
||||
dest.sin_port = htons(DHCP_SERVER_PORT);
|
||||
@@ -260,7 +257,9 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
dest.sin_addr = mess->ciaddr;
|
||||
}
|
||||
|
||||
sendto(dhcp_fd, mess, newlen, 0, (struct sockaddr *)&dest, sizeof(dest));
|
||||
while(sendto(daemon->dhcpfd, mess, newlen, 0,
|
||||
(struct sockaddr *)&dest, sizeof(dest)) == -1 &&
|
||||
retry_send());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -324,13 +323,13 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
memcpy(header.ether_shost, iface_hwaddr, ETHER_ADDR_LEN);
|
||||
memcpy(header.ether_dhost, hwdest, ETHER_ADDR_LEN);
|
||||
|
||||
ioctl(raw_fd, BIOCSETIF, &ifr);
|
||||
ioctl(daemon->dhcp_raw_fd, BIOCSETIF, &ifr);
|
||||
|
||||
iov[0].iov_base = (char *)&header;
|
||||
iov[0].iov_len = sizeof(struct ether_header);
|
||||
iov[1].iov_base = (char *)rawpacket;
|
||||
iov[1].iov_len = ntohs(rawpacket->ip.ip_len);
|
||||
writev(raw_fd, iov, 2);
|
||||
while (writev(daemon->dhcp_raw_fd, iov, 2) == -1 && retry_send());
|
||||
#else
|
||||
struct sockaddr_ll dest;
|
||||
|
||||
@@ -339,91 +338,225 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
dest.sll_ifindex = iface_index;
|
||||
dest.sll_protocol = htons(ETHERTYPE_IP);
|
||||
memcpy(dest.sll_addr, hwdest, ETHER_ADDR_LEN);
|
||||
sendto(raw_fd, rawpacket, ntohs(rawpacket->ip.ip_len),
|
||||
0, (struct sockaddr *)&dest, sizeof(dest));
|
||||
|
||||
while (sendto(daemon->dhcp_raw_fd, rawpacket, ntohs(rawpacket->ip.ip_len),
|
||||
0, (struct sockaddr *)&dest, sizeof(dest)) == -1 &&
|
||||
retry_send());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int address_available(struct dhcp_context *context, struct in_addr taddr)
|
||||
/* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
|
||||
of the interface on which a DHCP packet arrives (and any relay address) and does the
|
||||
following things:
|
||||
1) Fills in any netmask and broadcast addresses which have not been explicitly configured.
|
||||
2) Fills in local (this host) and router (this host or relay) addresses.
|
||||
3) Links contexts which are valid for hosts directly connected to the arrival interface on ->current.
|
||||
Note that the current chain may be superceded later for configured hosts or those coming via gateways. */
|
||||
struct dhcp_context *complete_context(struct daemon *daemon, struct in_addr local, struct dhcp_context *current,
|
||||
struct in_addr netmask, struct in_addr broadcast, struct in_addr relay,
|
||||
struct in_addr primary)
|
||||
{
|
||||
/* Check is an address is OK for this network, ie
|
||||
within allowable range and not in an existing lease */
|
||||
struct dhcp_context *context;
|
||||
|
||||
unsigned int addr, start, end;
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
{
|
||||
if (!(context->flags & CONTEXT_NETMASK) &&
|
||||
(is_same_net(local, context->start, netmask) ||
|
||||
is_same_net(local, context->end, netmask)))
|
||||
{
|
||||
if (context->netmask.s_addr != netmask.s_addr &&
|
||||
!(is_same_net(local, context->start, netmask) &&
|
||||
is_same_net(local, context->end, netmask)))
|
||||
{
|
||||
strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
|
||||
strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
|
||||
syslog(LOG_WARNING, "DHCP range %s -- %s is not consistent with netmask %s",
|
||||
daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
|
||||
}
|
||||
context->netmask = netmask;
|
||||
}
|
||||
|
||||
if (context->netmask.s_addr)
|
||||
{
|
||||
if (is_same_net(local, context->start, context->netmask) &&
|
||||
is_same_net(local, context->end, context->netmask))
|
||||
{
|
||||
/* link it onto the current chain if we've not seen it before */
|
||||
if (context->current == context)
|
||||
{
|
||||
context->router = local;
|
||||
context->local = local;
|
||||
context->current = current;
|
||||
current = context;
|
||||
}
|
||||
|
||||
if (!(context->flags & CONTEXT_BRDCAST))
|
||||
{
|
||||
if (is_same_net(broadcast, context->start, context->netmask))
|
||||
context->broadcast = broadcast;
|
||||
else
|
||||
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
|
||||
}
|
||||
}
|
||||
else if (relay.s_addr && is_same_net(relay, context->start, context->netmask))
|
||||
{
|
||||
context->router = relay;
|
||||
context->local = primary;
|
||||
/* fill in missing broadcast addresses for relayed ranges */
|
||||
if (!(context->flags & CONTEXT_BRDCAST))
|
||||
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
struct dhcp_context *address_available(struct dhcp_context *context, struct in_addr taddr)
|
||||
{
|
||||
/* Check is an address is OK for this network, check all
|
||||
possible ranges. */
|
||||
|
||||
addr = ntohl(taddr.s_addr);
|
||||
start = ntohl(context->start.s_addr);
|
||||
end = ntohl(context->end.s_addr);
|
||||
|
||||
/* static leases only. */
|
||||
if (start == end)
|
||||
return 0;
|
||||
|
||||
if (addr < start)
|
||||
return 0;
|
||||
|
||||
if (addr > end)
|
||||
return 0;
|
||||
|
||||
if (lease_find_by_addr(taddr))
|
||||
return 0;
|
||||
unsigned int start, end, addr = ntohl(taddr.s_addr);
|
||||
|
||||
for (; context; context = context->current)
|
||||
{
|
||||
start = ntohl(context->start.s_addr);
|
||||
end = ntohl(context->end.s_addr);
|
||||
|
||||
if (!(context->flags & CONTEXT_STATIC) &&
|
||||
addr >= start &&
|
||||
addr <= end)
|
||||
return context;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dhcp_context *narrow_context(struct dhcp_context *context, struct in_addr taddr)
|
||||
{
|
||||
/* We start of with a set of possible contexts, all on the current subnet.
|
||||
These are chained on ->current.
|
||||
Here we have an address, and return the actual context correponding to that
|
||||
address. Note that none may fit, if the address came a dhcp-host and is outside
|
||||
any dhcp-range. In that case we return a static range is possible, or failing that,
|
||||
any context on the subnet. (If there's more than one, this is a dodgy configuration:
|
||||
maybe there should be a warning.) */
|
||||
|
||||
struct dhcp_context *tmp = address_available(context, taddr);
|
||||
|
||||
if (tmp)
|
||||
return tmp;
|
||||
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if (tmp->flags & CONTEXT_STATIC)
|
||||
return tmp;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
|
||||
{
|
||||
struct dhcp_config *config;
|
||||
|
||||
for (config = configs; config; config = config->next)
|
||||
if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
|
||||
return config;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Is every member of check matched by a member of pool? */
|
||||
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool)
|
||||
{
|
||||
struct dhcp_netid *tmp1;
|
||||
|
||||
if (!check)
|
||||
return 0;
|
||||
|
||||
for (; check; check = check->next)
|
||||
{
|
||||
if (check->net[0] != '#')
|
||||
{
|
||||
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
||||
if (strcmp(check->net, tmp1->net) == 0)
|
||||
break;
|
||||
if (!tmp1)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
||||
if (strcmp((check->net)+1, tmp1->net) == 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
|
||||
struct in_addr *addrp, unsigned char *hwaddr)
|
||||
int address_allocate(struct dhcp_context *context, struct daemon *daemon,
|
||||
struct in_addr *addrp, unsigned char *hwaddr, struct dhcp_netid *netids)
|
||||
{
|
||||
/* Find a free address: exlude anything in use and anything allocated to
|
||||
a particular hwaddr/clientid/hostname in our configuration */
|
||||
/* Find a free address: exclude anything in use and anything allocated to
|
||||
a particular hwaddr/clientid/hostname in our configuration.
|
||||
Try to return from contexts which mathc netis first. */
|
||||
|
||||
struct dhcp_config *config;
|
||||
struct in_addr start, addr ;
|
||||
int i, j;
|
||||
|
||||
/* start == end means no dynamic leases. */
|
||||
if (context->end.s_addr == context->start.s_addr)
|
||||
return 0;
|
||||
struct dhcp_context *c;
|
||||
unsigned int i, j;
|
||||
|
||||
/* pick a seed based on hwaddr then iterate until we find a free address. */
|
||||
for (j = 0, i = 0; i < ETHER_ADDR_LEN; i++)
|
||||
j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
|
||||
|
||||
start.s_addr = addr.s_addr =
|
||||
htonl(ntohl(context->start.s_addr) +
|
||||
(j % (ntohl(context->end.s_addr) - ntohl(context->start.s_addr))));
|
||||
|
||||
do {
|
||||
if (addr.s_addr == context->end.s_addr)
|
||||
addr = context->start;
|
||||
for (c = context; c; c = c->current)
|
||||
if (c->flags & CONTEXT_STATIC)
|
||||
continue;
|
||||
else if (netids && !(c->flags & CONTEXT_FILTER))
|
||||
continue;
|
||||
else if (!netids && (c->flags & CONTEXT_FILTER))
|
||||
continue;
|
||||
else if (netids && (c->flags & CONTEXT_FILTER) && !match_netid(&c->netid, netids))
|
||||
continue;
|
||||
else
|
||||
addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
|
||||
|
||||
|
||||
if (!lease_find_by_addr(addr))
|
||||
{
|
||||
for (config = configs; config; config = config->next)
|
||||
if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
|
||||
break;
|
||||
/* pick a seed based on hwaddr then iterate until we find a free address. */
|
||||
for (j = c->addr_epoch, i = 0; i < ETHER_ADDR_LEN; i++)
|
||||
j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
|
||||
|
||||
if (!config)
|
||||
{
|
||||
*addrp = addr;
|
||||
return 1;
|
||||
}
|
||||
start.s_addr = addr.s_addr =
|
||||
htonl(ntohl(c->start.s_addr) +
|
||||
(j % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
|
||||
|
||||
do {
|
||||
if (!lease_find_by_addr(addr) &&
|
||||
!config_find_by_address(daemon->dhcp_conf, addr))
|
||||
{
|
||||
if (icmp_ping(daemon, addr))
|
||||
/* perturb address selection so that we are
|
||||
less likely to try this address again. */
|
||||
c->addr_epoch++;
|
||||
else
|
||||
{
|
||||
*addrp = addr;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
|
||||
|
||||
if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1))
|
||||
addr = c->start;
|
||||
|
||||
} while (addr.s_addr != start.s_addr);
|
||||
}
|
||||
} while (addr.s_addr != start.s_addr);
|
||||
|
||||
|
||||
if (netids)
|
||||
return address_allocate(context, daemon, addrp, hwaddr, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *config)
|
||||
{
|
||||
if (!context)
|
||||
return 1;
|
||||
return 1;
|
||||
if (!(config->flags & CONFIG_ADDR))
|
||||
return 1;
|
||||
if (is_same_net(config->addr, context->start, context->netmask))
|
||||
@@ -432,6 +565,7 @@ static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
struct dhcp_context *context,
|
||||
unsigned char *clid, int clid_len,
|
||||
@@ -439,7 +573,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
{
|
||||
struct dhcp_config *config;
|
||||
|
||||
if (clid_len)
|
||||
if (clid)
|
||||
for (config = configs; config; config = config->next)
|
||||
if (config->flags & CONFIG_CLID)
|
||||
{
|
||||
@@ -458,34 +592,51 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
|
||||
for (config = configs; config; config = config->next)
|
||||
if ((config->flags & CONFIG_HWADDR) &&
|
||||
config->wildcard_mask == 0 &&
|
||||
memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0 &&
|
||||
is_addr_in_context(context, config))
|
||||
return config;
|
||||
|
||||
if (hostname)
|
||||
|
||||
if (hostname && context)
|
||||
for (config = configs; config; config = config->next)
|
||||
if ((config->flags & CONFIG_NAME) &&
|
||||
hostname_isequal(config->hostname, hostname) &&
|
||||
is_addr_in_context(context, config))
|
||||
return config;
|
||||
|
||||
for (config = configs; config; config = config->next)
|
||||
if ((config->flags & CONFIG_HWADDR) &&
|
||||
config->wildcard_mask != 0 &&
|
||||
is_addr_in_context(context, config))
|
||||
{
|
||||
int i;
|
||||
unsigned int mask = config->wildcard_mask;
|
||||
for (i = ETHER_ADDR_LEN - 1; i >= 0; i--, mask = mask >> 1)
|
||||
if (mask & 1)
|
||||
config->hwaddr[i] = hwaddr[i];
|
||||
if (memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
|
||||
return config;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff)
|
||||
void dhcp_read_ethers(struct daemon *daemon)
|
||||
{
|
||||
FILE *f = fopen(ETHERSFILE, "r");
|
||||
unsigned int flags, e0, e1, e2, e3, e4, e5;
|
||||
unsigned int flags;
|
||||
char *buff = daemon->namebuff;
|
||||
char *ip, *cp;
|
||||
struct in_addr addr;
|
||||
unsigned char hwaddr[ETHER_ADDR_LEN];
|
||||
struct dhcp_config *config;
|
||||
struct dhcp_config *config, *configs = daemon->dhcp_conf;
|
||||
int count = 0;
|
||||
|
||||
if (!f)
|
||||
{
|
||||
syslog(LOG_ERR, "failed to read " ETHERSFILE ":%m");
|
||||
return configs;
|
||||
return;
|
||||
}
|
||||
|
||||
while (fgets(buff, MAXDNAME, f))
|
||||
@@ -502,16 +653,9 @@ struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff)
|
||||
if (!*ip)
|
||||
continue;
|
||||
|
||||
if (!sscanf(buff, "%x:%x:%x:%x:%x:%x", &e0, &e1, &e2, &e3, &e4, &e5))
|
||||
if (parse_hex(buff, hwaddr, 6, NULL) != 6)
|
||||
continue;
|
||||
|
||||
hwaddr[0] = e0;
|
||||
hwaddr[1] = e1;
|
||||
hwaddr[2] = e2;
|
||||
hwaddr[3] = e3;
|
||||
hwaddr[4] = e4;
|
||||
hwaddr[5] = e5;
|
||||
|
||||
/* check for name or dotted-quad */
|
||||
for (cp = ip; *cp; cp++)
|
||||
if (!(*cp == '.' || (*cp >='0' && *cp <= '9')))
|
||||
@@ -542,6 +686,7 @@ struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff)
|
||||
{
|
||||
for (config = configs; config; config = config->next)
|
||||
if ((config->flags & CONFIG_HWADDR) &&
|
||||
config->wildcard_mask == 0 &&
|
||||
memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
|
||||
break;
|
||||
|
||||
@@ -550,6 +695,7 @@ struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff)
|
||||
if (!(config = malloc(sizeof(struct dhcp_config))))
|
||||
continue;
|
||||
config->flags = 0;
|
||||
config->wildcard_mask = 0;
|
||||
config->next = configs;
|
||||
configs = config;
|
||||
}
|
||||
@@ -577,7 +723,8 @@ struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff)
|
||||
fclose(f);
|
||||
|
||||
syslog(LOG_INFO, "read " ETHERSFILE " - %d addresses", count);
|
||||
return configs;
|
||||
|
||||
daemon->dhcp_conf = configs;
|
||||
}
|
||||
|
||||
void dhcp_update_configs(struct dhcp_config *configs)
|
||||
@@ -595,8 +742,46 @@ void dhcp_update_configs(struct dhcp_config *configs)
|
||||
(crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
|
||||
(crec->flags & F_HOSTS))
|
||||
{
|
||||
config->addr = crec->addr.addr.addr4;
|
||||
config->addr = crec->addr.addr.addr.addr4;
|
||||
config->flags |= CONFIG_ADDR;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
|
||||
for this address. If it has a domain part, that must match the set domain and
|
||||
it gets stripped. */
|
||||
char *host_from_dns(struct daemon *daemon, struct in_addr addr)
|
||||
{
|
||||
struct crec *lookup = cache_find_by_addr(NULL, (struct all_addr *)&addr, 0, F_IPV4);
|
||||
char *hostname = NULL;
|
||||
|
||||
if (lookup && (lookup->flags & F_HOSTS))
|
||||
{
|
||||
hostname = daemon->dhcp_buff;
|
||||
hostname[256] = 0;
|
||||
strncpy(hostname, cache_get_name(lookup), 256);
|
||||
hostname = strip_hostname(daemon, hostname);
|
||||
}
|
||||
|
||||
return hostname;
|
||||
}
|
||||
|
||||
char *strip_hostname(struct daemon *daemon, char *hostname)
|
||||
{
|
||||
char *dot = strchr(hostname, '.');
|
||||
if (dot)
|
||||
{
|
||||
if (!daemon->domain_suffix || !hostname_isequal(dot+1, daemon->domain_suffix))
|
||||
{
|
||||
syslog(LOG_WARNING, "Ignoring DHCP host name %s because it has an illegal domain part", hostname);
|
||||
hostname = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dot = 0; /* truncate */
|
||||
if (strlen(hostname) == 0)
|
||||
hostname = NULL; /* nothing left */
|
||||
}
|
||||
}
|
||||
return hostname;
|
||||
}
|
||||
|
||||
606
src/dnsmasq.c
606
src/dnsmasq.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2003 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2005 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
|
||||
@@ -10,69 +10,27 @@
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
/* See RFC1035 for details of the protocol this code talks. */
|
||||
|
||||
/* Author's email: simon@thekelleys.org.uk */
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
static int sigterm, sighup, sigusr1, sigalarm;
|
||||
static volatile int sigterm, sighup, sigusr1, sigalarm, num_kids, in_child;
|
||||
|
||||
static void sig_handler(int sig)
|
||||
{
|
||||
if (sig == SIGTERM)
|
||||
sigterm = 1;
|
||||
else if (sig == SIGHUP)
|
||||
sighup = 1;
|
||||
else if (sig == SIGUSR1)
|
||||
sigusr1 = 1;
|
||||
else if (sig == SIGALRM)
|
||||
sigalarm = 1;
|
||||
}
|
||||
static int set_dns_listeners(struct daemon *daemon, fd_set *set, int maxfd);
|
||||
static void check_dns_listeners(struct daemon *daemon, fd_set *set, time_t now);
|
||||
static void sig_handler(int sig);
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
int cachesize = CACHESIZ;
|
||||
int port = NAMESERVER_PORT;
|
||||
int maxleases = MAXLEASES;
|
||||
int query_port = 0;
|
||||
struct daemon *daemon;
|
||||
int first_loop = 1;
|
||||
int bind_fallback = 0;
|
||||
unsigned long local_ttl = 0;
|
||||
unsigned int options, min_leasetime;
|
||||
char *runfile = RUNFILE;
|
||||
time_t resolv_changed = 0;
|
||||
time_t now, last = 0;
|
||||
struct irec *interfaces = NULL;
|
||||
struct listener *listener, *listeners = NULL;
|
||||
struct doctor *doctors = NULL;
|
||||
struct mx_record *mxnames = NULL;
|
||||
char *mxtarget = NULL;
|
||||
char *lease_file = NULL;
|
||||
char *addn_hosts = NULL;
|
||||
char *domain_suffix = NULL;
|
||||
char *username = CHUSER;
|
||||
char *groupname = CHGRP;
|
||||
struct iname *if_names = NULL;
|
||||
struct iname *if_addrs = NULL;
|
||||
struct iname *if_except = NULL;
|
||||
struct server *serv_addrs = NULL;
|
||||
char *dnamebuff, *packet;
|
||||
int uptime_fd = -1;
|
||||
struct server *servers, *last_server;
|
||||
struct resolvc default_resolv = { NULL, 1, 0, RESOLVFILE };
|
||||
struct resolvc *resolv = &default_resolv;
|
||||
struct bogus_addr *bogus_addr = NULL;
|
||||
struct serverfd *serverfdp, *sfds = NULL;
|
||||
struct dhcp_context *dhcp_tmp, *dhcp = NULL;
|
||||
struct dhcp_config *dhcp_configs = NULL;
|
||||
struct dhcp_opt *dhcp_options = NULL;
|
||||
struct dhcp_vendor *dhcp_vendors = NULL;
|
||||
char *dhcp_file = NULL, *dhcp_sname = NULL;
|
||||
struct in_addr dhcp_next_server;
|
||||
int leasefd = -1, dhcpfd = -1, dhcp_raw_fd = -1;
|
||||
struct irec *interfaces;
|
||||
struct sigaction sigact;
|
||||
sigset_t sigmask;
|
||||
struct iname *if_tmp;
|
||||
|
||||
sighup = 1; /* init cache the first time through */
|
||||
sigusr1 = 0; /* but don't dump */
|
||||
@@ -82,6 +40,8 @@ int main (int argc, char **argv)
|
||||
#else
|
||||
sigalarm = 0; /* or not */
|
||||
#endif
|
||||
num_kids = 0;
|
||||
in_child = 0;
|
||||
|
||||
sigact.sa_handler = sig_handler;
|
||||
sigact.sa_flags = 0;
|
||||
@@ -90,6 +50,11 @@ int main (int argc, char **argv)
|
||||
sigaction(SIGHUP, &sigact, NULL);
|
||||
sigaction(SIGTERM, &sigact, NULL);
|
||||
sigaction(SIGALRM, &sigact, NULL);
|
||||
sigaction(SIGCHLD, &sigact, NULL);
|
||||
|
||||
/* ignore SIGPIPE */
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
sigaction(SIGPIPE, &sigact, NULL);
|
||||
|
||||
/* now block all the signals, they stay that way except
|
||||
during the call to pselect */
|
||||
@@ -97,55 +62,49 @@ int main (int argc, char **argv)
|
||||
sigaddset(&sigact.sa_mask, SIGTERM);
|
||||
sigaddset(&sigact.sa_mask, SIGHUP);
|
||||
sigaddset(&sigact.sa_mask, SIGALRM);
|
||||
sigaddset(&sigact.sa_mask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &sigact.sa_mask, &sigmask);
|
||||
|
||||
/* These get allocated here to avoid overflowing the small stack
|
||||
on embedded systems. dnamebuff is big enough to hold one
|
||||
maximal sixed domain name and gets passed into all the processing
|
||||
code. We manage to get away with one buffer. */
|
||||
dnamebuff = safe_malloc(MAXDNAME);
|
||||
packet = safe_malloc(DNSMASQ_PACKETSZ);
|
||||
daemon = read_opts(argc, argv);
|
||||
|
||||
dhcp_next_server.s_addr = 0;
|
||||
options = read_opts(argc, argv, dnamebuff, &resolv, &mxnames, &mxtarget, &lease_file,
|
||||
&username, &groupname, &domain_suffix, &runfile,
|
||||
&if_names, &if_addrs, &if_except, &bogus_addr,
|
||||
&serv_addrs, &cachesize, &port, &query_port, &local_ttl, &addn_hosts,
|
||||
&dhcp, &dhcp_configs, &dhcp_options, &dhcp_vendors,
|
||||
&dhcp_file, &dhcp_sname, &dhcp_next_server, &maxleases, &min_leasetime,
|
||||
&doctors);
|
||||
|
||||
if (!lease_file)
|
||||
if (daemon->edns_pktsz < PACKETSZ)
|
||||
daemon->edns_pktsz = PACKETSZ;
|
||||
daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
|
||||
daemon->edns_pktsz : DNSMASQ_PACKETSZ;
|
||||
daemon->packet = safe_malloc(daemon->packet_buff_sz);
|
||||
|
||||
if (!daemon->lease_file)
|
||||
{
|
||||
if (dhcp)
|
||||
lease_file = LEASEFILE;
|
||||
if (daemon->dhcp)
|
||||
daemon->lease_file = LEASEFILE;
|
||||
}
|
||||
#ifndef HAVE_ISC_READER
|
||||
else if (!dhcp)
|
||||
else if (!daemon->dhcp)
|
||||
die("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h", NULL);
|
||||
#endif
|
||||
|
||||
interfaces = enumerate_interfaces(&if_names, &if_addrs, if_except, port);
|
||||
if (!enumerate_interfaces(daemon, &interfaces, NULL, NULL))
|
||||
die("failed to find list of interfaces: %s", NULL);
|
||||
|
||||
if (!(options & OPT_NOWILD) && !(listeners = create_wildcard_listeners(port)))
|
||||
if (!(daemon->options & OPT_NOWILD) &&
|
||||
!(daemon->listeners = create_wildcard_listeners(daemon->port)))
|
||||
{
|
||||
bind_fallback = 1;
|
||||
options |= OPT_NOWILD;
|
||||
daemon->options |= OPT_NOWILD;
|
||||
}
|
||||
|
||||
if (options & OPT_NOWILD)
|
||||
if (daemon->options & OPT_NOWILD)
|
||||
{
|
||||
struct iname *if_tmp;
|
||||
listeners = create_bound_listeners(interfaces);
|
||||
daemon->listeners = create_bound_listeners(interfaces, daemon->port);
|
||||
|
||||
for (if_tmp = if_names; if_tmp; if_tmp = if_tmp->next)
|
||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||
if (if_tmp->name && !if_tmp->used)
|
||||
die("unknown interface %s", if_tmp->name);
|
||||
|
||||
for (if_tmp = if_addrs; if_tmp; if_tmp = if_tmp->next)
|
||||
for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
|
||||
if (!if_tmp->used)
|
||||
{
|
||||
char addrbuff[ADDRSTRLEN];
|
||||
char *addrbuff = daemon->namebuff;
|
||||
#ifdef HAVE_IPV6
|
||||
if (if_tmp->addr.sa.sa_family == AF_INET)
|
||||
inet_ntop(AF_INET, &if_tmp->addr.in.sin_addr,
|
||||
@@ -161,35 +120,62 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
forward_init(1);
|
||||
cache_init(cachesize, options & OPT_LOG);
|
||||
cache_init(daemon->cachesize, daemon->options & OPT_LOG);
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
if ((uptime_fd = open(UPTIME, O_RDONLY)) == -1)
|
||||
if ((daemon->uptime_fd = open(UPTIME, O_RDONLY)) == -1)
|
||||
die("cannot open " UPTIME ":%s", NULL);
|
||||
#endif
|
||||
|
||||
now = dnsmasq_time(uptime_fd);
|
||||
now = dnsmasq_time(daemon->uptime_fd);
|
||||
|
||||
if (dhcp)
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
#if !defined(IP_PKTINFO) && !defined(IP_RECVIF)
|
||||
int c;
|
||||
struct iname *tmp;
|
||||
for (c = 0, tmp = if_names; tmp; tmp = tmp->next)
|
||||
for (c = 0, tmp = daemon->if_names; tmp; tmp = tmp->next)
|
||||
if (!tmp->isloop)
|
||||
c++;
|
||||
if (c != 1)
|
||||
die("must set exactly one interface on broken systems without IP_RECVIF", NULL);
|
||||
#endif
|
||||
dhcp_init(&dhcpfd, &dhcp_raw_fd);
|
||||
leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, now, maxleases);
|
||||
dhcp_init(daemon);
|
||||
lease_init(daemon, now);
|
||||
}
|
||||
|
||||
/* If query_port is set then create a socket now, before dumping root
|
||||
for use to access nameservers without more specific source addresses.
|
||||
This allows query_port to be a low port */
|
||||
if (daemon->query_port)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
addr.in.sin_family = AF_INET;
|
||||
addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.in.sin_port = htons(daemon->query_port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
allocate_sfd(&addr, &daemon->sfds);
|
||||
#ifdef HAVE_IPV6
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
addr.in6.sin6_addr = in6addr_any;
|
||||
addr.in6.sin6_port = htons(daemon->query_port);
|
||||
addr.in6.sin6_flowinfo = htonl(0);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
allocate_sfd(&addr, &daemon->sfds);
|
||||
#endif
|
||||
}
|
||||
|
||||
setbuf(stdout, NULL);
|
||||
|
||||
if (!(options & OPT_DEBUG))
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
{
|
||||
FILE *pidfile;
|
||||
struct serverfd *serverfdp;
|
||||
struct listener *listener;
|
||||
struct passwd *ent_pw;
|
||||
int i;
|
||||
|
||||
@@ -197,20 +183,23 @@ int main (int argc, char **argv)
|
||||
See Stevens section 12.4 */
|
||||
|
||||
#ifndef NO_FORK
|
||||
if (fork() != 0 )
|
||||
exit(0);
|
||||
|
||||
setsid();
|
||||
|
||||
if (fork() != 0)
|
||||
exit(0);
|
||||
if (!(daemon->options & OPT_NO_FORK))
|
||||
{
|
||||
if (fork() != 0 )
|
||||
exit(0);
|
||||
|
||||
setsid();
|
||||
|
||||
if (fork() != 0)
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
chdir("/");
|
||||
umask(022); /* make pidfile 0644 */
|
||||
|
||||
/* write pidfile _after_ forking ! */
|
||||
if (runfile && (pidfile = fopen(runfile, "w")))
|
||||
if (daemon->runfile && (pidfile = fopen(daemon->runfile, "w")))
|
||||
{
|
||||
fprintf(pidfile, "%d\n", (int) getpid());
|
||||
fclose(pidfile);
|
||||
@@ -220,23 +209,35 @@ int main (int argc, char **argv)
|
||||
|
||||
for (i=0; i<64; i++)
|
||||
{
|
||||
for (listener = listeners; listener; listener = listener->next)
|
||||
if (listener->fd == i)
|
||||
for (listener = daemon->listeners; listener; listener = listener->next)
|
||||
if (listener->fd == i || listener->tcpfd == i)
|
||||
break;
|
||||
if (listener)
|
||||
continue;
|
||||
|
||||
if (i == leasefd ||
|
||||
i == uptime_fd ||
|
||||
i == dhcpfd ||
|
||||
i == dhcp_raw_fd)
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
if (i == daemon->uptime_fd)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
if (daemon->dhcp &&
|
||||
(i == daemon->lease_fd ||
|
||||
i == daemon->dhcpfd ||
|
||||
i == daemon->dhcp_raw_fd ||
|
||||
i == daemon->dhcp_icmp_fd))
|
||||
continue;
|
||||
|
||||
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
if (serverfdp->fd == i)
|
||||
break;
|
||||
if (serverfdp)
|
||||
continue;
|
||||
|
||||
close(i);
|
||||
}
|
||||
|
||||
/* Change uid and gid for security */
|
||||
if (username && (ent_pw = getpwnam(username)))
|
||||
if (daemon->username && (ent_pw = getpwnam(daemon->username)))
|
||||
{
|
||||
gid_t dummy;
|
||||
struct group *gp;
|
||||
@@ -244,7 +245,7 @@ int main (int argc, char **argv)
|
||||
setgroups(0, &dummy);
|
||||
/* change group for /etc/ppp/resolv.conf
|
||||
otherwise get the group for "nobody" */
|
||||
if ((groupname && (gp = getgrnam(groupname))) ||
|
||||
if ((daemon->groupname && (gp = getgrnam(daemon->groupname))) ||
|
||||
(gp = getgrgid(ent_pw->pw_gid)))
|
||||
setgid(gp->gr_gid);
|
||||
/* finally drop root */
|
||||
@@ -253,80 +254,95 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
openlog("dnsmasq",
|
||||
DNSMASQ_LOG_OPT(options & OPT_DEBUG),
|
||||
DNSMASQ_LOG_FAC(options & OPT_DEBUG));
|
||||
DNSMASQ_LOG_OPT(daemon->options & OPT_DEBUG),
|
||||
DNSMASQ_LOG_FAC(daemon->options & OPT_DEBUG));
|
||||
|
||||
if (cachesize)
|
||||
syslog(LOG_INFO, "started, version %s cachesize %d", VERSION, cachesize);
|
||||
if (daemon->cachesize != 0)
|
||||
syslog(LOG_INFO, "started, version %s cachesize %d", VERSION, daemon->cachesize);
|
||||
else
|
||||
syslog(LOG_INFO, "started, version %s cache disabled", VERSION);
|
||||
|
||||
if (bind_fallback)
|
||||
syslog(LOG_WARNING, "setting --bind-interfaces option because if OS limitations");
|
||||
syslog(LOG_WARNING, "setting --bind-interfaces option because of OS limitations");
|
||||
|
||||
for (dhcp_tmp = dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
|
||||
if (!(daemon->options & OPT_NOWILD))
|
||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||
if (if_tmp->name && !if_tmp->used)
|
||||
syslog(LOG_WARNING, "warning: interface %s does not currently exist", if_tmp->name);
|
||||
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
strcpy(dnamebuff, inet_ntoa(dhcp_tmp->start));
|
||||
if (dhcp_tmp->lease_time == 0)
|
||||
sprintf(packet, "infinite");
|
||||
else
|
||||
sprintf(packet, "%ds", (int)dhcp_tmp->lease_time);
|
||||
syslog(LOG_INFO,
|
||||
dhcp_tmp->start.s_addr == dhcp_tmp->end.s_addr ?
|
||||
"DHCP, static leases only on %.0s%s, lease time %s" :
|
||||
"DHCP, IP range %s -- %s, lease time %s",
|
||||
dnamebuff, inet_ntoa(dhcp_tmp->end), packet);
|
||||
struct dhcp_context *dhcp_tmp;
|
||||
|
||||
#ifdef HAVE_RTNETLINK
|
||||
/* Must do this after daemonizing so that the pid is right */
|
||||
daemon->netlinkfd = netlink_init();
|
||||
#endif
|
||||
|
||||
for (dhcp_tmp = daemon->dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
|
||||
{
|
||||
prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time);
|
||||
strcpy(daemon->dhcp_buff, inet_ntoa(dhcp_tmp->start));
|
||||
syslog(LOG_INFO,
|
||||
(dhcp_tmp->flags & CONTEXT_STATIC) ?
|
||||
"DHCP, static leases only on %.0s%s, lease time %s" :
|
||||
"DHCP, IP range %s -- %s, lease time %s",
|
||||
daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), daemon->dhcp_buff2);
|
||||
}
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
daemon->min_leasetime = daemon->min_leasetime/3;
|
||||
if (daemon->min_leasetime > (60 * 60 * 24))
|
||||
daemon->min_leasetime = 60 * 60 * 24;
|
||||
if (daemon->min_leasetime < 60)
|
||||
daemon->min_leasetime = 60;
|
||||
prettyprint_time(daemon->dhcp_buff2, daemon->min_leasetime);
|
||||
syslog(LOG_INFO, "DHCP, %s will be written every %s", daemon->lease_file, daemon->dhcp_buff2);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
if (dhcp)
|
||||
syslog(LOG_INFO, "DHCP, %s will be written every %ds", lease_file, min_leasetime/3);
|
||||
#endif
|
||||
|
||||
if (getuid() == 0 || geteuid() == 0)
|
||||
syslog(LOG_WARNING, "failed to drop root privs");
|
||||
if (!(daemon->options & OPT_DEBUG) && (getuid() == 0 || geteuid() == 0))
|
||||
syslog(LOG_WARNING, "running as root");
|
||||
|
||||
check_servers(daemon, interfaces);
|
||||
|
||||
servers = check_servers(serv_addrs, interfaces, &sfds);
|
||||
last_server = NULL;
|
||||
|
||||
while (sigterm == 0)
|
||||
{
|
||||
fd_set rset;
|
||||
|
||||
if (sighup)
|
||||
{
|
||||
cache_reload(options, dnamebuff, domain_suffix, addn_hosts);
|
||||
if (dhcp)
|
||||
cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts);
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
if (options & OPT_ETHERS)
|
||||
dhcp_configs = dhcp_read_ethers(dhcp_configs, dnamebuff);
|
||||
dhcp_update_configs(dhcp_configs);
|
||||
lease_update_from_configs(dhcp_configs, domain_suffix);
|
||||
if (daemon->options & OPT_ETHERS)
|
||||
dhcp_read_ethers(daemon);
|
||||
dhcp_update_configs(daemon->dhcp_conf);
|
||||
lease_update_from_configs(daemon->dhcp_conf, daemon->domain_suffix);
|
||||
lease_update_file(0, now);
|
||||
lease_update_dns();
|
||||
lease_update_dns(daemon);
|
||||
}
|
||||
if (resolv && (options & OPT_NO_POLL))
|
||||
if (daemon->resolv_files && (daemon->options & OPT_NO_POLL))
|
||||
{
|
||||
servers = check_servers(reload_servers(resolv->name, dnamebuff, servers, query_port),
|
||||
interfaces, &sfds);
|
||||
last_server = NULL;
|
||||
reload_servers(daemon->resolv_files->name, daemon);
|
||||
check_servers(daemon, interfaces);
|
||||
}
|
||||
sighup = 0;
|
||||
}
|
||||
|
||||
if (sigusr1)
|
||||
{
|
||||
dump_cache(options & (OPT_DEBUG | OPT_LOG), cachesize);
|
||||
dump_cache(daemon);
|
||||
sigusr1 = 0;
|
||||
}
|
||||
|
||||
if (sigalarm)
|
||||
{
|
||||
if (dhcp)
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
lease_update_file(1, now);
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
alarm(min_leasetime/3);
|
||||
alarm(daemon->min_leasetime);
|
||||
#endif
|
||||
}
|
||||
sigalarm = 0;
|
||||
@@ -336,27 +352,13 @@ int main (int argc, char **argv)
|
||||
|
||||
if (!first_loop)
|
||||
{
|
||||
int maxfd = 0;
|
||||
|
||||
for (serverfdp = sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
int maxfd = set_dns_listeners(daemon, &rset, 0);
|
||||
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
FD_SET(serverfdp->fd, &rset);
|
||||
if (serverfdp->fd > maxfd)
|
||||
maxfd = serverfdp->fd;
|
||||
}
|
||||
|
||||
for (listener = listeners; listener; listener = listener->next)
|
||||
{
|
||||
FD_SET(listener->fd, &rset);
|
||||
if (listener->fd > maxfd)
|
||||
maxfd = listener->fd;
|
||||
}
|
||||
|
||||
if (dhcp)
|
||||
{
|
||||
FD_SET(dhcpfd, &rset);
|
||||
if (dhcpfd > maxfd)
|
||||
maxfd = dhcpfd;
|
||||
FD_SET(daemon->dhcpfd, &rset);
|
||||
if (daemon->dhcpfd > maxfd)
|
||||
maxfd = daemon->dhcpfd;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PSELECT
|
||||
@@ -371,11 +373,10 @@ int main (int argc, char **argv)
|
||||
sigprocmask(SIG_SETMASK, &save_mask, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
first_loop = 0;
|
||||
now = dnsmasq_time(uptime_fd);
|
||||
now = dnsmasq_time(daemon->uptime_fd);
|
||||
|
||||
/* Check for changes to resolv files once per second max. */
|
||||
if (last == 0 || difftime(now, last) > 1.0)
|
||||
@@ -383,13 +384,13 @@ int main (int argc, char **argv)
|
||||
last = now;
|
||||
|
||||
#ifdef HAVE_ISC_READER
|
||||
if (lease_file && !dhcp)
|
||||
load_dhcp(lease_file, domain_suffix, now, dnamebuff);
|
||||
if (daemon->lease_file && !daemon->dhcp)
|
||||
load_dhcp(daemon, now);
|
||||
#endif
|
||||
|
||||
if (!(options & OPT_NO_POLL))
|
||||
if (!(daemon->options & OPT_NO_POLL))
|
||||
{
|
||||
struct resolvc *res = resolv, *latest = NULL;
|
||||
struct resolvc *res = daemon->resolv_files, *latest = NULL;
|
||||
struct stat statbuf;
|
||||
time_t last_change = 0;
|
||||
/* There may be more than one possible file.
|
||||
@@ -418,45 +419,268 @@ int main (int argc, char **argv)
|
||||
if (latest && difftime(last_change, resolv_changed) > 0.0)
|
||||
{
|
||||
resolv_changed = last_change;
|
||||
servers = check_servers(reload_servers(latest->name, dnamebuff, servers, query_port),
|
||||
interfaces, &sfds);
|
||||
last_server = NULL;
|
||||
reload_servers(latest->name, daemon);
|
||||
check_servers(daemon, interfaces);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (serverfdp = sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
if (FD_ISSET(serverfdp->fd, &rset))
|
||||
last_server = reply_query(serverfdp, options, packet, now,
|
||||
dnamebuff, servers, last_server, bogus_addr, doctors);
|
||||
|
||||
if (dhcp && FD_ISSET(dhcpfd, &rset))
|
||||
dhcp_packet(dhcp, packet, dhcp_options, dhcp_configs, dhcp_vendors,
|
||||
now, dnamebuff, domain_suffix, dhcp_file,
|
||||
dhcp_sname, dhcp_next_server, dhcpfd, dhcp_raw_fd,
|
||||
if_names, if_addrs, if_except);
|
||||
check_dns_listeners(daemon, &rset, now);
|
||||
|
||||
for (listener = listeners; listener; listener = listener->next)
|
||||
if (FD_ISSET(listener->fd, &rset))
|
||||
last_server = receive_query(listener, packet,
|
||||
mxnames, mxtarget, options, now, local_ttl, dnamebuff,
|
||||
if_names, if_addrs, if_except, last_server, servers);
|
||||
if (daemon->dhcp && FD_ISSET(daemon->dhcpfd, &rset))
|
||||
dhcp_packet(daemon, now);
|
||||
}
|
||||
|
||||
syslog(LOG_INFO, "exiting on receipt of SIGTERM");
|
||||
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
if (dhcp)
|
||||
lease_update_file(1, now);
|
||||
lease_update_file(1, now);
|
||||
#endif
|
||||
|
||||
if (leasefd != -1)
|
||||
close(leasefd);
|
||||
close(daemon->lease_fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sig_handler(int sig)
|
||||
{
|
||||
if (sig == SIGTERM)
|
||||
sigterm = 1;
|
||||
else if (sig == SIGHUP)
|
||||
sighup = 1;
|
||||
else if (sig == SIGUSR1)
|
||||
sigusr1 = 1;
|
||||
else if (sig == SIGALRM)
|
||||
{
|
||||
/* alarm is used to kill children after a fixed time. */
|
||||
if (in_child)
|
||||
exit(0);
|
||||
else
|
||||
sigalarm = 1;
|
||||
}
|
||||
else if (sig == SIGCHLD)
|
||||
{
|
||||
/* See Stevens 5.10 */
|
||||
|
||||
while (waitpid(-1, NULL, WNOHANG) > 0)
|
||||
num_kids--;
|
||||
}
|
||||
}
|
||||
|
||||
static int set_dns_listeners(struct daemon *daemon, fd_set *set, int maxfd)
|
||||
{
|
||||
struct serverfd *serverfdp;
|
||||
struct listener *listener;
|
||||
|
||||
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
{
|
||||
FD_SET(serverfdp->fd, set);
|
||||
if (serverfdp->fd > maxfd)
|
||||
maxfd = serverfdp->fd;
|
||||
}
|
||||
|
||||
for (listener = daemon->listeners; listener; listener = listener->next)
|
||||
{
|
||||
FD_SET(listener->fd, set);
|
||||
if (listener->fd > maxfd)
|
||||
maxfd = listener->fd;
|
||||
FD_SET(listener->tcpfd, set);
|
||||
if (listener->tcpfd > maxfd)
|
||||
maxfd = listener->tcpfd;
|
||||
}
|
||||
|
||||
return maxfd;
|
||||
}
|
||||
|
||||
static void check_dns_listeners(struct daemon *daemon, fd_set *set, time_t now)
|
||||
{
|
||||
struct serverfd *serverfdp;
|
||||
struct listener *listener;
|
||||
|
||||
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
if (FD_ISSET(serverfdp->fd, set))
|
||||
reply_query(serverfdp, daemon, now);
|
||||
|
||||
for (listener = daemon->listeners; listener; listener = listener->next)
|
||||
{
|
||||
if (FD_ISSET(listener->fd, set))
|
||||
receive_query(listener, daemon, now);
|
||||
|
||||
if (FD_ISSET(listener->tcpfd, set))
|
||||
{
|
||||
int confd;
|
||||
struct in_addr netmask, dst_addr_4;
|
||||
|
||||
while((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
|
||||
|
||||
if (confd != -1)
|
||||
{
|
||||
union mysockaddr tcp_addr;
|
||||
socklen_t tcp_len = sizeof(union mysockaddr);
|
||||
|
||||
/* Check for allowed interfaces when binding the wildcard address:
|
||||
we do this by looking for an interface with the same address as
|
||||
the local address of the TCP connection, then looking to see if that's
|
||||
an allowed interface. As a side effect, we get the netmask of the
|
||||
interface too, for localisation. */
|
||||
|
||||
if ((num_kids >= MAX_PROCS) ||
|
||||
(!(daemon->options & OPT_NOWILD) &&
|
||||
(getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1 ||
|
||||
!enumerate_interfaces(daemon, NULL, &tcp_addr, &netmask))))
|
||||
close(confd);
|
||||
#ifndef NO_FORK
|
||||
else if (!(daemon->options & OPT_DEBUG) && fork())
|
||||
{
|
||||
num_kids++;
|
||||
close(confd);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
char *buff;
|
||||
struct server *s;
|
||||
int flags;
|
||||
|
||||
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to
|
||||
terminate the process. */
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
{
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGALRM);
|
||||
sigprocmask(SIG_UNBLOCK, &mask, NULL);
|
||||
alarm(CHILD_LIFETIME);
|
||||
in_child = 1;
|
||||
}
|
||||
|
||||
/* start with no upstream connections. */
|
||||
for (s = daemon->servers; s; s = s->next)
|
||||
s->tcpfd = -1;
|
||||
|
||||
/* The connected socket inherits non-blocking
|
||||
attribute from the listening socket.
|
||||
Reset that here. */
|
||||
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
||||
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
|
||||
if (listener->family == AF_INET)
|
||||
{
|
||||
if (daemon->options & OPT_NOWILD)
|
||||
{
|
||||
netmask = listener->iface->netmask;
|
||||
dst_addr_4 = listener->iface->addr.in.sin_addr;
|
||||
}
|
||||
else
|
||||
/* netmask already set by enumerate_interfaces */
|
||||
dst_addr_4 = tcp_addr.in.sin_addr;
|
||||
}
|
||||
else
|
||||
dst_addr_4.s_addr = 0;
|
||||
|
||||
buff = tcp_request(daemon, confd, now, dst_addr_4, netmask);
|
||||
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
exit(0);
|
||||
|
||||
close(confd);
|
||||
if (buff)
|
||||
free(buff);
|
||||
for (s = daemon->servers; s; s = s->next)
|
||||
if (s->tcpfd != -1)
|
||||
close(s->tcpfd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int icmp_ping(struct daemon *daemon, struct in_addr addr)
|
||||
{
|
||||
/* Try and get an ICMP echo from a machine.
|
||||
Note that we can't create the raw socket each time
|
||||
we do this, since that needs root. Therefore the socket has to hang
|
||||
around all the time. Since most of the time we won't read the
|
||||
socket, it will accumulate buffers full of ICMP messages,
|
||||
wasting memory. To avoid that we set the receive buffer
|
||||
length to zero except when we're actively pinging. */
|
||||
|
||||
/* Note that whilst in the three second wait, we check for
|
||||
(and service) events on the DNS sockets, (so doing that
|
||||
better not use any resources our caller has in use...)
|
||||
but we remain deaf to signals or further DHCP packets. */
|
||||
|
||||
struct sockaddr_in saddr;
|
||||
struct {
|
||||
struct ip ip;
|
||||
struct icmp icmp;
|
||||
} packet;
|
||||
unsigned short id = rand16();
|
||||
unsigned int i, j;
|
||||
int opt = 2000, gotreply = 0;
|
||||
time_t start, now;
|
||||
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = 0;
|
||||
saddr.sin_addr = addr;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
saddr.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
|
||||
memset(&packet.icmp, 0, sizeof(packet.icmp));
|
||||
packet.icmp.icmp_type = ICMP_ECHO;
|
||||
packet.icmp.icmp_id = id;
|
||||
for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
|
||||
j += ((u16 *)&packet.icmp)[i];
|
||||
while (j>>16)
|
||||
j = (j & 0xffff) + (j >> 16);
|
||||
packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
|
||||
|
||||
setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
|
||||
|
||||
while (sendto(daemon->dhcp_icmp_fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
|
||||
(struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
|
||||
retry_send());
|
||||
|
||||
for (now = start = dnsmasq_time(daemon->uptime_fd); difftime(now, start) < 3.0;)
|
||||
{
|
||||
struct timeval tv;
|
||||
fd_set rset;
|
||||
struct sockaddr_in faddr;
|
||||
int maxfd, len = sizeof(faddr);
|
||||
|
||||
tv.tv_usec = 250000;
|
||||
tv.tv_sec = 0;
|
||||
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(daemon->dhcp_icmp_fd, &rset);
|
||||
maxfd = set_dns_listeners(daemon, &rset, daemon->dhcp_icmp_fd);
|
||||
|
||||
if (select(maxfd+1, &rset, NULL, NULL, &tv) < 0)
|
||||
FD_ZERO(&rset);
|
||||
|
||||
now = dnsmasq_time(daemon->uptime_fd);
|
||||
check_dns_listeners(daemon, &rset, now);
|
||||
|
||||
if (FD_ISSET(daemon->dhcp_icmp_fd, &rset) &&
|
||||
recvfrom(daemon->dhcp_icmp_fd, &packet, sizeof(packet), 0,
|
||||
(struct sockaddr *)&faddr, &len) == sizeof(packet) &&
|
||||
saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
|
||||
packet.icmp.icmp_type == ICMP_ECHOREPLY &&
|
||||
packet.icmp.icmp_seq == 0 &&
|
||||
packet.icmp.icmp_id == id)
|
||||
{
|
||||
gotreply = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
opt = 1;
|
||||
setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
|
||||
|
||||
return gotreply;
|
||||
}
|
||||
|
||||
|
||||
|
||||
342
src/dnsmasq.h
342
src/dnsmasq.h
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2003 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2005 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
|
||||
@@ -11,11 +11,12 @@
|
||||
*/
|
||||
|
||||
/* Author's email: simon@thekelleys.org.uk */
|
||||
|
||||
|
||||
#define COPYRIGHT "Copyright (C) 2000-2005 Simon Kelley"
|
||||
|
||||
#ifdef __linux__
|
||||
/* for pselect.... */
|
||||
#define _XOPEN_SOURCE 600
|
||||
# define _XOPEN_SOURCE 600
|
||||
/* but then DNS headers don't compile without.... */
|
||||
#define _BSD_SOURCE
|
||||
#endif
|
||||
@@ -26,16 +27,23 @@
|
||||
|
||||
/* get this before config.h too. */
|
||||
#include <syslog.h>
|
||||
#ifdef __APPLE__
|
||||
/* need this before arpa/nameser.h */
|
||||
# define BIND_8_COMPAT
|
||||
#endif
|
||||
#include <arpa/nameser.h>
|
||||
|
||||
/* and this. */
|
||||
#include <getopt.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <arpa/nameser.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/wait.h>
|
||||
#if defined(__sun) || defined(__sun__)
|
||||
# include <sys/sockio.h>
|
||||
#endif
|
||||
@@ -49,13 +57,11 @@
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
# include <getopt.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <stdarg.h>
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
# include <netinet/if_ether.h>
|
||||
#else
|
||||
@@ -64,6 +70,7 @@
|
||||
#include <net/if_arp.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
#ifdef HAVE_BPF
|
||||
# include <net/bpf.h>
|
||||
# include <net/if_dl.h>
|
||||
@@ -72,9 +79,17 @@
|
||||
#endif
|
||||
#include <sys/uio.h>
|
||||
|
||||
/* Size: we check after adding each record, so there must be
|
||||
memory for the largest packet, and the largest record */
|
||||
#define DNSMASQ_PACKETSZ PACKETSZ+MAXDNAME+RRFIXEDSZ
|
||||
/* 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.
|
||||
The buffer is also used for NETLINK, which needs to be about 2000
|
||||
on systems with many interfaces/addresses. */
|
||||
#ifdef HAVE_RTNETLINK
|
||||
# define DNSMASQ_PACKETSZ PACKETSZ+MAXDNAME+RRFIXEDSZ
|
||||
#else
|
||||
# define DNSMASQ_PACKETSZ 2000
|
||||
#endif
|
||||
|
||||
#define OPT_BOGUSPRIV 1
|
||||
#define OPT_FILTER 2
|
||||
@@ -92,6 +107,9 @@
|
||||
#define OPT_NOWILD 8192
|
||||
#define OPT_ETHERS 16384
|
||||
#define OPT_RESOLV_DOMAIN 32768
|
||||
#define OPT_NO_FORK 65536
|
||||
#define OPT_AUTHORITATIVE 131072
|
||||
#define OPT_LOCALISE 262144
|
||||
|
||||
struct all_addr {
|
||||
union {
|
||||
@@ -113,9 +131,16 @@ struct doctor {
|
||||
struct doctor *next;
|
||||
};
|
||||
|
||||
struct mx_record {
|
||||
char *mxname, *mxtarget;
|
||||
struct mx_record *next;
|
||||
struct mx_srv_record {
|
||||
char *name, *target;
|
||||
int issrv, srvport, priority, weight, offset;
|
||||
struct mx_srv_record *next;
|
||||
};
|
||||
|
||||
struct txt_record {
|
||||
char *name, *txt;
|
||||
unsigned short class, len;
|
||||
struct txt_record *next;
|
||||
};
|
||||
|
||||
union bigname {
|
||||
@@ -126,7 +151,14 @@ union bigname {
|
||||
struct crec {
|
||||
struct crec *next, *prev, *hash_next;
|
||||
time_t ttd; /* time to die */
|
||||
struct all_addr addr;
|
||||
int uid;
|
||||
union {
|
||||
struct all_addr addr;
|
||||
struct {
|
||||
struct crec *cache;
|
||||
int uid;
|
||||
} cname;
|
||||
} addr;
|
||||
unsigned short flags;
|
||||
union {
|
||||
char sname[SMALLDNAME];
|
||||
@@ -136,7 +168,7 @@ struct crec {
|
||||
};
|
||||
|
||||
#define F_IMMORTAL 1
|
||||
#define F_CONFIG 2
|
||||
#define F_CONFIG 2
|
||||
#define F_REVERSE 4
|
||||
#define F_FORWARD 8
|
||||
#define F_DHCP 16
|
||||
@@ -149,7 +181,7 @@ struct crec {
|
||||
#define F_SERVER 2048
|
||||
#define F_NXDOMAIN 4096
|
||||
#define F_QUERY 8192
|
||||
#define F_ADDN 16384
|
||||
#define F_CNAME 16384
|
||||
#define F_NOERR 32768
|
||||
|
||||
/* struct sockaddr is not large enough to hold any address,
|
||||
@@ -175,14 +207,16 @@ union mysockaddr {
|
||||
#endif
|
||||
};
|
||||
|
||||
#define SERV_FROM_RESOLV 1 /* 1 for servers from resolv, 0 for command line. */
|
||||
#define SERV_NO_ADDR 2 /* no server, this domain is local only */
|
||||
#define SERV_LITERAL_ADDRESS 4 /* addr is the answer, not the server */
|
||||
#define SERV_HAS_SOURCE 8 /* source address specified */
|
||||
#define SERV_HAS_DOMAIN 16 /* server for one domain only */
|
||||
#define SERV_FOR_NODOTS 32 /* server for names with no domain part only */
|
||||
#define SERV_FROM_RESOLV 1 /* 1 for servers from resolv, 0 for command line. */
|
||||
#define SERV_NO_ADDR 2 /* no server, this domain is local only */
|
||||
#define SERV_LITERAL_ADDRESS 4 /* addr is the answer, not the server */
|
||||
#define SERV_HAS_SOURCE 8 /* source address specified */
|
||||
#define SERV_HAS_DOMAIN 16 /* server for one domain only */
|
||||
#define SERV_FOR_NODOTS 32 /* server for names with no domain part only */
|
||||
#define SERV_WARNED_RECURSIVE 64 /* avoid warning spam */
|
||||
#define SERV_TYPE (SERV_HAS_DOMAIN | SERV_FOR_NODOTS)
|
||||
|
||||
|
||||
struct serverfd {
|
||||
int fd;
|
||||
union mysockaddr source_addr;
|
||||
@@ -194,17 +228,19 @@ struct server {
|
||||
struct serverfd *sfd; /* non-NULL if this server has its own fd bound to
|
||||
a source port */
|
||||
char *domain; /* set if this server only handles a domain. */
|
||||
int flags;
|
||||
int flags, tcpfd;
|
||||
struct server *next;
|
||||
};
|
||||
|
||||
struct irec {
|
||||
union mysockaddr addr;
|
||||
struct in_addr netmask; /* only valid for IPv4 */
|
||||
struct irec *next;
|
||||
};
|
||||
|
||||
struct listener {
|
||||
int fd, family;
|
||||
int fd, tcpfd, family;
|
||||
struct irec *iface; /* only valid for non-wildcard */
|
||||
struct listener *next;
|
||||
};
|
||||
|
||||
@@ -224,12 +260,21 @@ struct resolvc {
|
||||
char *name;
|
||||
};
|
||||
|
||||
/* adn-hosts parms from command-line */
|
||||
struct hostsfile {
|
||||
struct hostsfile *next;
|
||||
char *fname;
|
||||
int index; /* matches to cache entries fro logging */
|
||||
};
|
||||
|
||||
struct frec {
|
||||
union mysockaddr source;
|
||||
struct all_addr dest;
|
||||
struct server *sentto;
|
||||
unsigned int iface;
|
||||
unsigned short orig_id, new_id;
|
||||
int fd;
|
||||
int fd, forwardall;
|
||||
unsigned int crc;
|
||||
time_t time;
|
||||
struct frec *next;
|
||||
};
|
||||
@@ -249,6 +294,10 @@ struct dhcp_netid {
|
||||
struct dhcp_netid *next;
|
||||
};
|
||||
|
||||
struct dhcp_netid_list {
|
||||
struct dhcp_netid *list;
|
||||
struct dhcp_netid_list *next;
|
||||
};
|
||||
struct dhcp_config {
|
||||
unsigned int flags;
|
||||
int clid_len; /* length of client identifier */
|
||||
@@ -257,41 +306,56 @@ struct dhcp_config {
|
||||
char *hostname;
|
||||
struct dhcp_netid netid;
|
||||
struct in_addr addr;
|
||||
unsigned int lease_time;
|
||||
unsigned int lease_time, wildcard_mask;
|
||||
struct dhcp_config *next;
|
||||
};
|
||||
|
||||
#define CONFIG_DISABLE 1
|
||||
#define CONFIG_CLID 2
|
||||
#define CONFIG_HWADDR 4
|
||||
#define CONFIG_TIME 8
|
||||
#define CONFIG_NAME 16
|
||||
#define CONFIG_ADDR 32
|
||||
#define CONFIG_NETID 64
|
||||
#define CONFIG_NOCLID 128
|
||||
#define CONFIG_DISABLE 1
|
||||
#define CONFIG_CLID 2
|
||||
#define CONFIG_HWADDR 4
|
||||
#define CONFIG_TIME 8
|
||||
#define CONFIG_NAME 16
|
||||
#define CONFIG_ADDR 32
|
||||
#define CONFIG_NETID 64
|
||||
#define CONFIG_NOCLID 128
|
||||
|
||||
struct dhcp_opt {
|
||||
int opt, len, is_addr;
|
||||
unsigned char *val;
|
||||
char *netid;
|
||||
unsigned char *val, *vendor_class;
|
||||
struct dhcp_netid *netid;
|
||||
struct dhcp_opt *next;
|
||||
};
|
||||
|
||||
struct dhcp_boot {
|
||||
char *file, *sname;
|
||||
struct in_addr next_server;
|
||||
struct dhcp_netid *netid;
|
||||
struct dhcp_boot *next;
|
||||
};
|
||||
|
||||
struct dhcp_vendor {
|
||||
int len, is_vendor, used;
|
||||
int len, is_vendor;
|
||||
char *data;
|
||||
struct dhcp_netid netid;
|
||||
struct dhcp_vendor *next;
|
||||
};
|
||||
|
||||
struct dhcp_context {
|
||||
unsigned int lease_time;
|
||||
unsigned int lease_time, addr_epoch;
|
||||
struct in_addr netmask, broadcast;
|
||||
struct in_addr local, router;
|
||||
struct in_addr start, end; /* range of available addresses */
|
||||
int flags;
|
||||
struct dhcp_netid netid;
|
||||
struct dhcp_context *next;
|
||||
struct dhcp_context *next, *current;
|
||||
};
|
||||
|
||||
#define CONTEXT_STATIC 1
|
||||
#define CONTEXT_FILTER 2
|
||||
#define CONTEXT_NETMASK 4
|
||||
#define CONTEXT_BRDCAST 8
|
||||
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
@@ -311,15 +375,65 @@ struct udp_dhcp_packet {
|
||||
u16 secs, flags;
|
||||
struct in_addr ciaddr, yiaddr, siaddr, giaddr;
|
||||
u8 chaddr[16], sname[64], file[128];
|
||||
u32 cookie;
|
||||
u8 options[308];
|
||||
u8 options[312];
|
||||
} data;
|
||||
};
|
||||
|
||||
|
||||
struct daemon {
|
||||
/* datastuctures representing the command-line and
|
||||
config file arguments. All set (including defaults)
|
||||
in option.c */
|
||||
|
||||
unsigned int options;
|
||||
struct resolvc default_resolv, *resolv_files;
|
||||
struct mx_srv_record *mxnames;
|
||||
struct txt_record *txt;
|
||||
char *mxtarget;
|
||||
char *lease_file;
|
||||
char *username, *groupname;
|
||||
char *domain_suffix;
|
||||
char *runfile;
|
||||
struct iname *if_names, *if_addrs, *if_except;
|
||||
struct bogus_addr *bogus_addr;
|
||||
struct server *servers;
|
||||
int cachesize;
|
||||
int port, query_port;
|
||||
unsigned long local_ttl;
|
||||
struct hostsfile *addn_hosts;
|
||||
struct dhcp_context *dhcp;
|
||||
struct dhcp_config *dhcp_conf;
|
||||
struct dhcp_opt *dhcp_opts, *vendor_opts;
|
||||
struct dhcp_vendor *dhcp_vendors;
|
||||
struct dhcp_boot *boot_config;
|
||||
struct dhcp_netid_list *dhcp_ignore;
|
||||
int dhcp_max;
|
||||
unsigned int min_leasetime;
|
||||
struct doctor *doctors;
|
||||
unsigned short edns_pktsz;
|
||||
|
||||
/* globally used stuff for DNS */
|
||||
char *packet; /* packet buffer */
|
||||
int packet_buff_sz; /* size of above */
|
||||
char *namebuff; /* MAXDNAME size buffer */
|
||||
struct serverfd *sfds;
|
||||
struct listener *listeners;
|
||||
struct server *last_server;
|
||||
int uptime_fd;
|
||||
|
||||
/* DHCP state */
|
||||
int dhcpfd, dhcp_raw_fd, dhcp_icmp_fd, lease_fd;
|
||||
#ifdef HAVE_RTNETLINK
|
||||
int netlinkfd;
|
||||
#endif
|
||||
struct udp_dhcp_packet *dhcp_packet;
|
||||
char *dhcp_buff, *dhcp_buff2;
|
||||
};
|
||||
|
||||
/* cache.c */
|
||||
void cache_init(int cachesize, int log);
|
||||
void log_query(unsigned short flags, char *name, struct all_addr *addr);
|
||||
void log_query(unsigned short flags, char *name, struct all_addr *addr,
|
||||
unsigned short type, struct hostsfile *addn_hosts, int index);
|
||||
struct crec *cache_find_by_addr(struct crec *crecp,
|
||||
struct all_addr *addr, time_t now,
|
||||
unsigned short prot);
|
||||
@@ -327,28 +441,32 @@ struct crec *cache_find_by_name(struct crec *crecp,
|
||||
char *name, time_t now, unsigned short prot);
|
||||
void cache_end_insert(void);
|
||||
void cache_start_insert(void);
|
||||
void cache_insert(char *name, struct all_addr *addr,
|
||||
time_t now, unsigned long ttl, unsigned short flags);
|
||||
void cache_reload(int opts, char *buff, char *domain_suffix, char *addn_hosts);
|
||||
void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address,
|
||||
time_t ttd, unsigned short flags);
|
||||
struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
time_t now, unsigned long ttl, unsigned short flags);
|
||||
void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *addn_hosts);
|
||||
void cache_add_dhcp_entry(struct daemon *daemon, char *host_name, struct in_addr *host_address, time_t ttd);
|
||||
void cache_unhash_dhcp(void);
|
||||
void dump_cache(int debug, int size);
|
||||
void dump_cache(struct daemon *daemon);
|
||||
char *cache_get_name(struct crec *crecp);
|
||||
|
||||
/* rfc1035.c */
|
||||
unsigned short extract_request(HEADER *header, unsigned int qlen, char *name);
|
||||
unsigned short extract_request(HEADER *header, unsigned int qlen,
|
||||
char *name, unsigned short *typep);
|
||||
int setup_reply(HEADER *header, unsigned int qlen,
|
||||
struct all_addr *addrp, unsigned short flags,
|
||||
unsigned long local_ttl);
|
||||
void extract_addresses(HEADER *header, unsigned int qlen, char *namebuff,
|
||||
time_t now, struct doctor *doctors);
|
||||
void extract_neg_addrs(HEADER *header, unsigned int qlen, char *namebuff, time_t now);
|
||||
int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_record *mxnames,
|
||||
char *mxtarget, unsigned int options, time_t now, unsigned long local_ttl,
|
||||
char *namebuff);
|
||||
time_t now, struct daemon *daemon);
|
||||
int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon *daemon,
|
||||
struct in_addr local_addr, struct in_addr local_netmask, time_t now);
|
||||
int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name,
|
||||
struct bogus_addr *addr, time_t now);
|
||||
unsigned char *find_pseudoheader(HEADER *header, unsigned int plen,
|
||||
unsigned int *len, unsigned char **p);
|
||||
int check_for_local_domain(char *name, time_t now, struct daemon *daemon);
|
||||
unsigned int questions_crc(HEADER *header, unsigned int plen, char *buff);
|
||||
int resize_packet(HEADER *header, unsigned int plen,
|
||||
unsigned char *pheader, unsigned int hlen);
|
||||
|
||||
/* util.c */
|
||||
unsigned short rand16(void);
|
||||
@@ -356,95 +474,93 @@ int legal_char(char c);
|
||||
int canonicalise(char *s);
|
||||
int atoi_check(char *a, int *res);
|
||||
void die(char *message, char *arg1);
|
||||
void complain(char *message, char *arg1);
|
||||
void *safe_malloc(int size);
|
||||
void complain(char *message, int lineno, char *file);
|
||||
void *safe_malloc(size_t size);
|
||||
char *safe_string_alloc(char *cp);
|
||||
int sa_len(union mysockaddr *addr);
|
||||
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
|
||||
int hostname_isequal(unsigned char *a, unsigned char *b);
|
||||
time_t dnsmasq_time(int fd);
|
||||
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
|
||||
int retry_send(void);
|
||||
void prettyprint_time(char *buf, unsigned int t);
|
||||
int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||
unsigned int *wildcard_mask);
|
||||
|
||||
/* option.c */
|
||||
unsigned int read_opts(int argc, char **argv, char *buff, struct resolvc **resolv_file,
|
||||
struct mx_record **mxnames, char **mxtarget, char **lease_file,
|
||||
char **username, char **groupname,
|
||||
char **domain_suffix, char **runfile,
|
||||
struct iname **if_names, struct iname **if_addrs, struct iname **if_except,
|
||||
struct bogus_addr **bogus_addr, struct server **serv_addrs, int *cachesize,
|
||||
int *port, int *query_port, unsigned long *local_ttl, char **addn_hosts,
|
||||
struct dhcp_context **dhcp, struct dhcp_config **dhcp_conf,
|
||||
struct dhcp_opt **opts, struct dhcp_vendor **dhcp_vendors,
|
||||
char **dhcp_file, char **dhcp_sname, struct in_addr *dhcp_next_server,
|
||||
int *maxleases, unsigned int *min_leasetime, struct doctor **doctors);
|
||||
struct daemon *read_opts (int argc, char **argv);
|
||||
|
||||
/* forward.c */
|
||||
void forward_init(int first);
|
||||
struct server *reply_query(struct serverfd *sfd, int options, char *packet, time_t now,
|
||||
char *dnamebuff, struct server *servers, struct server *last_server,
|
||||
struct bogus_addr *bogus_nxdomain, struct doctor *doctors);
|
||||
void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now);
|
||||
void receive_query(struct listener *listen, struct daemon *daemon, time_t now);
|
||||
char *tcp_request(struct daemon *daemon, int confd, time_t now,
|
||||
struct in_addr local_addr, struct in_addr netmask);
|
||||
|
||||
struct server *receive_query(struct listener *listen, char *packet, struct mx_record *mxnames,
|
||||
char *mxtarget, unsigned int options, time_t now,
|
||||
unsigned long local_ttl, char *namebuff,
|
||||
struct iname *names, struct iname *addrs, struct iname *except,
|
||||
struct server *last_server, struct server *servers);
|
||||
/* network.c */
|
||||
struct server *reload_servers(char *fname, char *buff, struct server *servers, int query_port);
|
||||
struct server *check_servers(struct server *new, struct irec *interfaces, struct serverfd **sfds);
|
||||
struct irec *enumerate_interfaces(struct iname **names,
|
||||
struct iname **addrs,
|
||||
struct iname *except,
|
||||
int port);
|
||||
struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds);
|
||||
void reload_servers(char *fname, struct daemon *daemon);
|
||||
void check_servers(struct daemon *daemon, struct irec *interfaces);
|
||||
int enumerate_interfaces(struct daemon *daemon, struct irec **chainp,
|
||||
union mysockaddr *test_addrp, struct in_addr *netmaskp);
|
||||
struct listener *create_wildcard_listeners(int port);
|
||||
struct listener *create_bound_listeners(struct irec *interfaces);
|
||||
struct listener *create_bound_listeners(struct irec *interfaces, int port);
|
||||
|
||||
/* dhcp.c */
|
||||
void dhcp_init(int *fdp, int* rfdp);
|
||||
void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
|
||||
struct dhcp_vendor *vendors,
|
||||
time_t now, char *namebuff, char *domain_suffix,
|
||||
char *dhcp_file, char *dhcp_sname,
|
||||
struct in_addr dhcp_next_server, int dhcp_fd, int raw_fd,
|
||||
struct iname *names, struct iname *addrs, struct iname *except);
|
||||
int address_available(struct dhcp_context *context, struct in_addr addr);
|
||||
int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
|
||||
struct in_addr *addrp, unsigned char *hwaddr);
|
||||
void dhcp_init(struct daemon *daemon);
|
||||
void dhcp_packet(struct daemon *daemon, time_t now);
|
||||
|
||||
struct dhcp_context *address_available(struct dhcp_context *context, struct in_addr addr);
|
||||
struct dhcp_context *narrow_context(struct dhcp_context *context, struct in_addr taddr);
|
||||
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool);
|
||||
int address_allocate(struct dhcp_context *context, struct daemon *daemon,
|
||||
struct in_addr *addrp, unsigned char *hwaddr,
|
||||
struct dhcp_netid *netids);
|
||||
struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
struct dhcp_context *context,
|
||||
unsigned char *clid, int clid_len,
|
||||
unsigned char *hwaddr, char *hostname);
|
||||
struct dhcp_config *read_ethers(struct dhcp_config *configs, char *buff);
|
||||
void dhcp_update_configs(struct dhcp_config *configs);
|
||||
struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff);
|
||||
void dhcp_read_ethers(struct daemon *daemon);
|
||||
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
|
||||
char *strip_hostname(struct daemon *daemon, char *hostname);
|
||||
char *host_from_dns(struct daemon *daemon, struct in_addr addr);
|
||||
struct dhcp_context *complete_context(struct daemon *daemon, struct in_addr local,
|
||||
struct dhcp_context *current, struct in_addr netmask,
|
||||
struct in_addr broadcast, struct in_addr relay,
|
||||
struct in_addr primary);
|
||||
|
||||
/* lease.c */
|
||||
void lease_update_file(int force, time_t now);
|
||||
void lease_update_dns(void);
|
||||
int lease_init(char *lease_file, char *domain, char *buff,
|
||||
char *buff2, time_t now, int maxleases);
|
||||
struct dhcp_lease *lease_allocate(unsigned char *clid, int clid_len, struct in_addr addr);
|
||||
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr);
|
||||
void lease_update_dns(struct daemon *daemon);
|
||||
void lease_init(struct daemon *daemon, time_t now);
|
||||
struct dhcp_lease *lease_allocate(unsigned char *hwaddr, unsigned char *clid,
|
||||
int clid_len, struct in_addr addr);
|
||||
int lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||
unsigned char *clid, int clid_len);
|
||||
void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix);
|
||||
void lease_set_expires(struct dhcp_lease *lease, time_t exp);
|
||||
struct dhcp_lease *lease_find_by_client(unsigned char *clid, int clid_len);
|
||||
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr,
|
||||
unsigned char *clid, int clid_len);
|
||||
struct dhcp_lease *lease_find_by_addr(struct in_addr addr);
|
||||
void lease_prune(struct dhcp_lease *target, time_t now);
|
||||
void lease_update_from_configs(struct dhcp_config *dhcp_configs, char *domain);
|
||||
|
||||
/* rfc2131.c */
|
||||
int dhcp_reply(struct dhcp_context *context,
|
||||
struct in_addr iface_addr,
|
||||
char *iface_name,
|
||||
int iface_mtu,
|
||||
struct udp_dhcp_packet *rawpacket,
|
||||
unsigned int sz, time_t now, char *namebuff,
|
||||
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
|
||||
struct dhcp_vendor *vendors,
|
||||
char *domain_suffix, char *dhcp_file, char *dhcp_sname,
|
||||
struct in_addr dhcp_next_server, struct in_addr router);
|
||||
int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_name, unsigned int sz, time_t now);
|
||||
|
||||
/* dnsmasq.c */
|
||||
int icmp_ping(struct daemon *daemon, struct in_addr addr);
|
||||
|
||||
/* isc.c */
|
||||
#ifdef HAVE_ISC_READER
|
||||
void load_dhcp(char *file, char *suffix, time_t now, char *hostname);
|
||||
void load_dhcp(struct daemon *daemon, time_t now);
|
||||
#endif
|
||||
|
||||
/* netlink.c */
|
||||
#ifdef HAVE_RTNETLINK
|
||||
int netlink_init(void);
|
||||
int netlink_process(struct daemon *daemon, int index,
|
||||
struct in_addr relay, struct in_addr primary,
|
||||
struct dhcp_context **retp);
|
||||
#endif
|
||||
|
||||
881
src/forward.c
881
src/forward.c
File diff suppressed because it is too large
Load Diff
33
src/isc.c
33
src/isc.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000 - 2004 by Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000 - 2005 by Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -55,8 +55,9 @@ static int next_token (char *token, int buffsize, FILE * fp)
|
||||
return count ? 1 : 0;
|
||||
}
|
||||
|
||||
void load_dhcp(char *file, char *suffix, time_t now, char *hostname)
|
||||
void load_dhcp(struct daemon *daemon, time_t now)
|
||||
{
|
||||
char *hostname = daemon->namebuff;
|
||||
char token[MAXTOK], *dot;
|
||||
struct in_addr host_address;
|
||||
time_t ttd, tts;
|
||||
@@ -64,10 +65,10 @@ void load_dhcp(char *file, char *suffix, time_t now, char *hostname)
|
||||
struct isc_lease *lease, *tmp, **up;
|
||||
struct stat statbuf;
|
||||
|
||||
if (stat(file, &statbuf) == -1)
|
||||
if (stat(daemon->lease_file, &statbuf) == -1)
|
||||
{
|
||||
if (!logged_lease)
|
||||
syslog(LOG_WARNING, "failed to access %s: %m", file);
|
||||
syslog(LOG_WARNING, "failed to access %s: %m", daemon->lease_file);
|
||||
logged_lease = 1;
|
||||
return;
|
||||
}
|
||||
@@ -81,13 +82,13 @@ void load_dhcp(char *file, char *suffix, time_t now, char *hostname)
|
||||
lease_file_size = statbuf.st_size;
|
||||
lease_file_inode = statbuf.st_ino;
|
||||
|
||||
if (!(fp = fopen (file, "r")))
|
||||
if (!(fp = fopen (daemon->lease_file, "r")))
|
||||
{
|
||||
syslog (LOG_ERR, "failed to load %s: %m", file);
|
||||
syslog (LOG_ERR, "failed to load %s: %m", daemon->lease_file);
|
||||
return;
|
||||
}
|
||||
|
||||
syslog (LOG_INFO, "reading %s", file);
|
||||
syslog (LOG_INFO, "reading %s", daemon->lease_file);
|
||||
|
||||
while ((next_token(token, MAXTOK, fp)))
|
||||
{
|
||||
@@ -109,7 +110,7 @@ void load_dhcp(char *file, char *suffix, time_t now, char *hostname)
|
||||
if (!canonicalise(hostname))
|
||||
{
|
||||
*hostname = 0;
|
||||
syslog(LOG_ERR, "bad name in %s", file);
|
||||
syslog(LOG_ERR, "bad name in %s", daemon->lease_file);
|
||||
}
|
||||
}
|
||||
else if ((strcmp(token, "ends") == 0) ||
|
||||
@@ -168,7 +169,7 @@ void load_dhcp(char *file, char *suffix, time_t now, char *hostname)
|
||||
|
||||
if ((dot = strchr(hostname, '.')))
|
||||
{
|
||||
if (!suffix || hostname_isequal(dot+1, suffix))
|
||||
if (!daemon->domain_suffix || hostname_isequal(dot+1, daemon->domain_suffix))
|
||||
{
|
||||
syslog(LOG_WARNING,
|
||||
"Ignoring DHCP lease for %s because it has an illegal domain part",
|
||||
@@ -198,11 +199,12 @@ void load_dhcp(char *file, char *suffix, time_t now, char *hostname)
|
||||
{
|
||||
leases = lease;
|
||||
strcpy(lease->name, hostname);
|
||||
if (suffix && (lease->fqdn = malloc(strlen(hostname) + strlen(suffix) + 2)))
|
||||
if (daemon->domain_suffix &&
|
||||
(lease->fqdn = malloc(strlen(hostname) + strlen(daemon->domain_suffix) + 2)))
|
||||
{
|
||||
strcpy(lease->fqdn, hostname);
|
||||
strcat(lease->fqdn, ".");
|
||||
strcat(lease->fqdn, suffix);
|
||||
strcat(lease->fqdn, daemon->domain_suffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -235,13 +237,8 @@ void load_dhcp(char *file, char *suffix, time_t now, char *hostname)
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
if (lease->fqdn)
|
||||
{
|
||||
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires, F_REVERSE);
|
||||
cache_add_dhcp_entry(lease->name, &lease->addr, lease->expires, 0);
|
||||
}
|
||||
else
|
||||
cache_add_dhcp_entry(lease->name, &lease->addr, lease->expires, F_REVERSE);
|
||||
cache_add_dhcp_entry(daemon, lease->fqdn, &lease->addr, lease->expires);
|
||||
cache_add_dhcp_entry(daemon, lease->name, &lease->addr, lease->expires);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
173
src/lease.c
173
src/lease.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2003 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2005 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
|
||||
@@ -15,14 +15,14 @@
|
||||
#include "dnsmasq.h"
|
||||
|
||||
static struct dhcp_lease *leases;
|
||||
FILE *lease_file;
|
||||
int dns_dirty, file_dirty, new_lease;
|
||||
int leases_left;
|
||||
static FILE *lease_file;
|
||||
static int dns_dirty;
|
||||
enum { no, yes, force } file_dirty;
|
||||
static int leases_left;
|
||||
|
||||
int lease_init(char *filename, char *domain, char *buff,
|
||||
char *buff2, time_t now, int maxleases)
|
||||
void lease_init(struct daemon *daemon, time_t now)
|
||||
{
|
||||
unsigned int e0, e1, e2, e3, e4, e5, a0, a1, a2, a3;
|
||||
unsigned int a0, a1, a2, a3;
|
||||
unsigned long ei;
|
||||
time_t expires;
|
||||
unsigned char hwaddr[ETHER_ADDR_LEN];
|
||||
@@ -32,17 +32,20 @@ int lease_init(char *filename, char *domain, char *buff,
|
||||
int has_old = 0;
|
||||
|
||||
leases = NULL;
|
||||
leases_left = maxleases;
|
||||
leases_left = daemon->dhcp_max;
|
||||
|
||||
/* NOTE: need a+ mode to create file if it doesn't exist */
|
||||
if (!(lease_file = fopen(filename, "a+")))
|
||||
if (!(lease_file = fopen(daemon->lease_file, "a+")))
|
||||
die("cannot open or create leases file: %s", NULL);
|
||||
|
||||
/* a+ mode lease pointer at end. */
|
||||
rewind(lease_file);
|
||||
|
||||
while (fscanf(lease_file, "%lu %x:%x:%x:%x:%x:%x %d.%d.%d.%d %256s %500s",
|
||||
&ei, &e0, &e1, &e2, &e3, &e4, &e5, &a0, &a1, &a2, &a3, buff, buff2) == 13)
|
||||
/* client-id max length is 255 which is 255*2 digits + 254 colons
|
||||
borrow DNS packet buffer which is always larger than 1000 bytes */
|
||||
while (fscanf(lease_file, "%lu %40s %d.%d.%d.%d %255s %764s",
|
||||
&ei, daemon->dhcp_buff2, &a0, &a1, &a2, &a3,
|
||||
daemon->dhcp_buff, daemon->packet) == 8)
|
||||
{
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
if (ei)
|
||||
@@ -61,43 +64,28 @@ int lease_init(char *filename, char *domain, char *buff,
|
||||
}
|
||||
#endif
|
||||
|
||||
hwaddr[0] = e0;
|
||||
hwaddr[1] = e1;
|
||||
hwaddr[2] = e2;
|
||||
hwaddr[3] = e3;
|
||||
hwaddr[4] = e4;
|
||||
hwaddr[5] = e5;
|
||||
|
||||
parse_hex(daemon->dhcp_buff2, hwaddr, ETHER_ADDR_LEN, NULL);
|
||||
addr.s_addr = htonl((a0<<24) + (a1<<16) + (a2<<8) + a3);
|
||||
|
||||
/* decode hex in place */
|
||||
if (strcmp(buff2, "*") == 0)
|
||||
if (strcmp(daemon->packet, "*") == 0)
|
||||
clid_len = 0;
|
||||
else
|
||||
{
|
||||
int s = (strlen(buff2)/3) + 1;
|
||||
for (clid_len = 0; clid_len < s; clid_len++)
|
||||
{
|
||||
buff2[(clid_len*3)+2] = 0;
|
||||
buff2[clid_len] = strtol(&buff2[clid_len*3], NULL, 16);
|
||||
}
|
||||
}
|
||||
clid_len = parse_hex(daemon->packet, daemon->packet, 255, NULL);
|
||||
|
||||
if (!(lease = lease_allocate(buff2, clid_len, addr)))
|
||||
if (!(lease = lease_allocate(hwaddr, daemon->packet, clid_len, addr)))
|
||||
die ("too many stored leases", NULL);
|
||||
|
||||
lease->expires = expires;
|
||||
memcpy(lease->hwaddr, hwaddr, ETHER_ADDR_LEN);
|
||||
|
||||
if (strcmp(buff, "*") != 0)
|
||||
lease_set_hostname(lease, buff, domain);
|
||||
if (strcmp(daemon->dhcp_buff, "*") != 0)
|
||||
lease_set_hostname(lease, daemon->dhcp_buff, daemon->domain_suffix);
|
||||
}
|
||||
|
||||
dns_dirty = 1;
|
||||
file_dirty = has_old;
|
||||
new_lease = 0;
|
||||
file_dirty = has_old ? yes: no;
|
||||
|
||||
return fileno(lease_file);
|
||||
daemon->lease_fd = fileno(lease_file);
|
||||
}
|
||||
|
||||
void lease_update_from_configs(struct dhcp_config *dhcp_configs, char *domain)
|
||||
@@ -113,18 +101,18 @@ void lease_update_from_configs(struct dhcp_config *dhcp_configs, char *domain)
|
||||
lease_set_hostname(lease, config->hostname, domain);
|
||||
}
|
||||
|
||||
void lease_update_file(int force, time_t now)
|
||||
void lease_update_file(int always, time_t now)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
int i = force; /* avoid warning */
|
||||
int i = always; /* avoid warning */
|
||||
unsigned long expires;
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
if (force || new_lease)
|
||||
if (always || file_dirty == force)
|
||||
{
|
||||
lease_prune(NULL, now);
|
||||
#else
|
||||
if (file_dirty)
|
||||
if (file_dirty != no)
|
||||
{
|
||||
#endif
|
||||
rewind(lease_file);
|
||||
@@ -147,7 +135,7 @@ void lease_update_file(int force, time_t now)
|
||||
lease->hwaddr[5], inet_ntoa(lease->addr),
|
||||
lease->hostname && strlen(lease->hostname) != 0 ? lease->hostname : "*");
|
||||
|
||||
if (lease->clid_len)
|
||||
if (lease->clid && lease->clid_len != 0)
|
||||
{
|
||||
for (i = 0; i < lease->clid_len - 1; i++)
|
||||
fprintf(lease_file, "%.2x:", lease->clid[i]);
|
||||
@@ -160,12 +148,11 @@ void lease_update_file(int force, time_t now)
|
||||
|
||||
fflush(lease_file);
|
||||
fsync(fileno(lease_file));
|
||||
file_dirty = 0;
|
||||
new_lease = 0;
|
||||
file_dirty = no;
|
||||
}
|
||||
}
|
||||
|
||||
void lease_update_dns(void)
|
||||
void lease_update_dns(struct daemon *daemon)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
@@ -175,13 +162,8 @@ void lease_update_dns(void)
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
if (lease->fqdn)
|
||||
{
|
||||
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires, F_REVERSE);
|
||||
cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires, 0);
|
||||
}
|
||||
else if (lease->hostname)
|
||||
cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires, F_REVERSE);
|
||||
cache_add_dhcp_entry(daemon, lease->fqdn, &lease->addr, lease->expires);
|
||||
cache_add_dhcp_entry(daemon, lease->hostname, &lease->addr, lease->expires);
|
||||
}
|
||||
|
||||
dns_dirty = 0;
|
||||
@@ -197,7 +179,7 @@ void lease_prune(struct dhcp_lease *target, time_t now)
|
||||
tmp = lease->next;
|
||||
if ((lease->expires != 0 && difftime(now, lease->expires) > 0) || lease == target)
|
||||
{
|
||||
file_dirty = 1;
|
||||
file_dirty = yes;
|
||||
|
||||
*up = lease->next; /* unlink */
|
||||
if (lease->hostname)
|
||||
@@ -218,27 +200,21 @@ void lease_prune(struct dhcp_lease *target, time_t now)
|
||||
}
|
||||
|
||||
|
||||
struct dhcp_lease *lease_find_by_client(unsigned char *clid, int clid_len)
|
||||
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr,
|
||||
unsigned char *clid, int clid_len)
|
||||
{
|
||||
/* zero length means clid from hwaddr: never match am option clid to
|
||||
a hardware-address derived clid */
|
||||
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
if (clid_len)
|
||||
{
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if (lease->clid && clid_len == lease->clid_len &&
|
||||
if (clid)
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if (lease->clid && clid_len == lease->clid_len &&
|
||||
memcmp(clid, lease->clid, clid_len) == 0)
|
||||
return lease;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if (!lease->clid &&
|
||||
memcmp(clid, lease->hwaddr, ETHER_ADDR_LEN) == 0)
|
||||
return lease;
|
||||
}
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if ((!lease->clid || !clid) &&
|
||||
memcmp(hwaddr, lease->hwaddr, ETHER_ADDR_LEN) == 0)
|
||||
return lease;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -255,35 +231,29 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
|
||||
}
|
||||
|
||||
|
||||
struct dhcp_lease *lease_allocate(unsigned char *clid, int clid_len, struct in_addr addr)
|
||||
struct dhcp_lease *lease_allocate(unsigned char *hwaddr, unsigned char *clid,
|
||||
int clid_len, struct in_addr addr)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
if (!leases_left || !(lease = malloc(sizeof(struct dhcp_lease))))
|
||||
return NULL;
|
||||
|
||||
lease->clid = NULL;
|
||||
lease->clid_len = clid_len;
|
||||
|
||||
if (clid_len)
|
||||
{
|
||||
if (!(lease->clid = malloc(clid_len)))
|
||||
{
|
||||
free(lease);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(lease->clid, clid, clid_len);
|
||||
}
|
||||
|
||||
lease->hostname = lease->fqdn = NULL;
|
||||
lease->hostname = lease->fqdn = NULL;
|
||||
lease->addr = addr;
|
||||
memset(lease->hwaddr, 0, ETHER_ADDR_LEN);
|
||||
lease->expires = 1;
|
||||
|
||||
if (!lease_set_hwaddr(lease, hwaddr, clid, clid_len))
|
||||
{
|
||||
free(lease);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lease->next = leases;
|
||||
leases = lease;
|
||||
|
||||
file_dirty = 1;
|
||||
new_lease = 1;
|
||||
file_dirty = force;
|
||||
leases_left--;
|
||||
|
||||
return lease;
|
||||
@@ -292,18 +262,46 @@ struct dhcp_lease *lease_allocate(unsigned char *clid, int clid_len, struct in_a
|
||||
void lease_set_expires(struct dhcp_lease *lease, time_t exp)
|
||||
{
|
||||
if (exp != lease->expires)
|
||||
file_dirty = dns_dirty = 1;
|
||||
|
||||
{
|
||||
file_dirty = yes;
|
||||
dns_dirty = 1;
|
||||
}
|
||||
lease->expires = exp;
|
||||
}
|
||||
|
||||
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr)
|
||||
int lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||
unsigned char *clid, int clid_len)
|
||||
{
|
||||
if (memcmp(lease->hwaddr, hwaddr, ETHER_ADDR_LEN) != 0)
|
||||
{
|
||||
file_dirty = 1;
|
||||
file_dirty = force;
|
||||
memcpy(lease->hwaddr, hwaddr, ETHER_ADDR_LEN);
|
||||
}
|
||||
|
||||
/* only update clid when one is available, stops packets
|
||||
without a clid removing the record. Lease init uses
|
||||
clid_len == 0 for no clid. */
|
||||
if (clid_len != 0 && clid)
|
||||
{
|
||||
if (!lease->clid)
|
||||
lease->clid_len = 0;
|
||||
|
||||
if (lease->clid_len != clid_len)
|
||||
{
|
||||
file_dirty = force;
|
||||
if (lease->clid)
|
||||
free(lease->clid);
|
||||
if (!(lease->clid = malloc(clid_len)))
|
||||
return 0;
|
||||
}
|
||||
else if (memcmp(lease->clid, clid, clid_len) != 0)
|
||||
file_dirty = force;
|
||||
|
||||
lease->clid_len = clid_len;
|
||||
memcpy(lease->clid, clid, clid_len);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix)
|
||||
@@ -354,7 +352,8 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix)
|
||||
lease->hostname = new_name;
|
||||
lease->fqdn = new_fqdn;
|
||||
|
||||
file_dirty = dns_dirty = 1;
|
||||
file_dirty = force;
|
||||
dns_dirty = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
154
src/netlink.c
Normal file
154
src/netlink.c
Normal file
@@ -0,0 +1,154 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2005 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
/* Author's email: simon@thekelleys.org.uk */
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_RTNETLINK
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
int netlink_init(void)
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
|
||||
if (sock < 0)
|
||||
return -1; /* no kernel support */
|
||||
|
||||
addr.nl_family = AF_NETLINK;
|
||||
addr.nl_pad = 0;
|
||||
addr.nl_pid = getpid();
|
||||
addr.nl_groups = 0;
|
||||
|
||||
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
|
||||
die("cannot bind netlink socket: %s", NULL);
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
|
||||
/* We borrow the DNS packet buffer here. (The DHCP one already has a packet in it)
|
||||
Since it's used only within this routine, that's fine, just remember
|
||||
that calling icmp_echo() will trash it */
|
||||
int netlink_process(struct daemon *daemon, int index, struct in_addr relay,
|
||||
struct in_addr primary, struct dhcp_context **retp)
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
struct nlmsghdr *h;
|
||||
int len, found_primary = 0;
|
||||
struct dhcp_context *ret = NULL;
|
||||
static unsigned int seq = 0;
|
||||
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct rtgenmsg g;
|
||||
} req;
|
||||
|
||||
if (daemon->netlinkfd == -1)
|
||||
return 0;
|
||||
|
||||
addr.nl_family = AF_NETLINK;
|
||||
addr.nl_pad = 0;
|
||||
addr.nl_groups = 0;
|
||||
addr.nl_pid = 0; /* address to kernel */
|
||||
|
||||
req.nlh.nlmsg_len = sizeof(req);
|
||||
req.nlh.nlmsg_type = RTM_GETADDR;
|
||||
req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
|
||||
req.nlh.nlmsg_pid = 0;
|
||||
req.nlh.nlmsg_seq = ++seq;
|
||||
req.g.rtgen_family = AF_INET;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
/* if RTnetlink not configured in the kernel, don't keep trying. */
|
||||
if (errno == ECONNREFUSED)
|
||||
{
|
||||
close(daemon->netlinkfd);
|
||||
daemon->netlinkfd = -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
get_next:
|
||||
while((len = recvfrom(daemon->netlinkfd, daemon->packet, daemon->packet_buff_sz,
|
||||
MSG_WAITALL, NULL, 0)) == -1 && retry_send());
|
||||
|
||||
if (len == -1)
|
||||
return 0;
|
||||
|
||||
h = (struct nlmsghdr *)daemon->packet;
|
||||
|
||||
while (NLMSG_OK(h, (unsigned int)len))
|
||||
{
|
||||
|
||||
if (h->nlmsg_seq != seq)
|
||||
goto get_next;
|
||||
|
||||
if (h->nlmsg_type == NLMSG_DONE)
|
||||
break;
|
||||
|
||||
if (h->nlmsg_type == NLMSG_ERROR)
|
||||
return 0;
|
||||
|
||||
if (h->nlmsg_type == RTM_NEWADDR)
|
||||
{
|
||||
struct ifaddrmsg *ifa = NLMSG_DATA(h);
|
||||
|
||||
if (ifa->ifa_index == index && ifa->ifa_family == AF_INET)
|
||||
{
|
||||
struct rtattr *rta = IFA_RTA(ifa);
|
||||
unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa));
|
||||
struct in_addr netmask, addr, broadcast;
|
||||
|
||||
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
|
||||
addr.s_addr = 0;
|
||||
broadcast.s_addr = 0;
|
||||
|
||||
while (RTA_OK(rta, len1))
|
||||
{
|
||||
if (rta->rta_type == IFA_LOCAL)
|
||||
addr = *((struct in_addr *)(rta+1));
|
||||
else if (rta->rta_type == IFA_BROADCAST)
|
||||
broadcast = *((struct in_addr *)(rta+1));
|
||||
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
}
|
||||
|
||||
if (addr.s_addr && broadcast.s_addr)
|
||||
{
|
||||
ret = complete_context(daemon, addr, ret, netmask, broadcast, relay, primary);
|
||||
if (addr.s_addr == primary.s_addr)
|
||||
found_primary = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h = NLMSG_NEXT(h, len);
|
||||
}
|
||||
|
||||
*retp = ret;
|
||||
|
||||
return found_primary;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
486
src/network.c
486
src/network.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000 - 2003 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000 - 2005 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,57 +14,83 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
static struct irec *add_iface(struct irec *list, char *name, union mysockaddr *addr,
|
||||
struct iname *names, struct iname *addrs,
|
||||
struct iname *except)
|
||||
static int iface_allowed(struct daemon *daemon, struct irec *iface,
|
||||
char *name, int is_loopback, union mysockaddr *addr)
|
||||
{
|
||||
struct irec *iface;
|
||||
struct iname *tmp;
|
||||
|
||||
/* check blacklist */
|
||||
if (except)
|
||||
for (tmp = except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && strcmp(tmp->name, name) == 0)
|
||||
return list;
|
||||
/* If we are restricting the set of interfaces to use, make
|
||||
sure that loopback interfaces are in that set. */
|
||||
if (daemon->if_names && is_loopback)
|
||||
{
|
||||
struct iname *lo;
|
||||
for (lo = daemon->if_names; lo; lo = lo->next)
|
||||
if (lo->name && strcmp(lo->name, name) == 0)
|
||||
{
|
||||
lo->isloop = 1;
|
||||
break;
|
||||
}
|
||||
if (!lo)
|
||||
{
|
||||
lo = safe_malloc(sizeof(struct iname));
|
||||
lo->name = safe_string_alloc(name);
|
||||
lo->isloop = lo->used = 1;
|
||||
lo->next = daemon->if_names;
|
||||
daemon->if_names = lo;
|
||||
}
|
||||
}
|
||||
|
||||
/* check blacklist */
|
||||
if (daemon->if_except)
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && strcmp(tmp->name, name) == 0)
|
||||
return 0;
|
||||
|
||||
/* we may need to check the whitelist */
|
||||
if (names || addrs)
|
||||
if (daemon->if_names || daemon->if_addrs)
|
||||
{
|
||||
int found = 0;
|
||||
|
||||
for (tmp = names; tmp; tmp = tmp->next)
|
||||
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
||||
found = tmp->used = 1;
|
||||
|
||||
for (tmp = addrs; tmp; tmp = tmp->next)
|
||||
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
if (sockaddr_isequal(&tmp->addr, addr))
|
||||
found = tmp->used = 1;
|
||||
|
||||
if (!found)
|
||||
return list;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check whether the interface IP has been added already
|
||||
it is possible to have multiple interfaces with the same address */
|
||||
for (iface = list; iface; iface = iface->next)
|
||||
for (; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&iface->addr, addr))
|
||||
break;
|
||||
if (iface)
|
||||
return list;
|
||||
return 0;
|
||||
|
||||
/* If OK, add it to the head of the list */
|
||||
iface = safe_malloc(sizeof(struct irec));
|
||||
iface->addr = *addr;
|
||||
iface->next = list;
|
||||
return iface;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This does two different jobs: if chainp is non-NULL, it puts
|
||||
a list of all the interfaces allowed by config into *chainp.
|
||||
If chainp is NULL, it returns 1 if addr is an address of an interface
|
||||
allowed by config and if that address is IPv4, it fills in the
|
||||
netmask of the interface.
|
||||
|
||||
If chainp is non-NULL, a zero return indicates a fatal error.
|
||||
|
||||
struct irec *enumerate_interfaces(struct iname **names,
|
||||
struct iname **addrs,
|
||||
struct iname *except,
|
||||
int port)
|
||||
If chainp is NULL, errors result in a match failure and zero return.
|
||||
*/
|
||||
int enumerate_interfaces(struct daemon *daemon, struct irec **chainp,
|
||||
union mysockaddr *test_addrp, struct in_addr *netmaskp)
|
||||
{
|
||||
#if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
|
||||
FILE *f;
|
||||
#endif
|
||||
union mysockaddr addr;
|
||||
struct irec *iface = NULL;
|
||||
char *buf, *ptr;
|
||||
struct ifreq *ifr = NULL;
|
||||
@@ -72,9 +98,16 @@ struct irec *enumerate_interfaces(struct iname **names,
|
||||
int lastlen = 0;
|
||||
int len = 20 * sizeof(struct ifreq);
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
struct in_addr netmask;
|
||||
int ret = 0;
|
||||
|
||||
if (fd == -1)
|
||||
die ("cannot create socket to enumerate interfaces: %s", NULL);
|
||||
return 0;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (test_addrp && test_addrp->sa.sa_family == AF_INET6)
|
||||
test_addrp->in6.sin6_flowinfo = htonl(0);
|
||||
#endif
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -85,7 +118,7 @@ struct irec *enumerate_interfaces(struct iname **names,
|
||||
if (ioctl(fd, SIOCGIFCONF, &ifc) < 0)
|
||||
{
|
||||
if (errno != EINVAL || lastlen != 0)
|
||||
die ("ioctl error while enumerating interfaces: %s", NULL);
|
||||
goto exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -97,16 +130,15 @@ struct irec *enumerate_interfaces(struct iname **names,
|
||||
free(buf);
|
||||
}
|
||||
|
||||
for (ptr = buf; ptr < buf + len; )
|
||||
for (ptr = buf; ptr < buf + ifc.ifc_len; )
|
||||
{
|
||||
union mysockaddr addr;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
/* subsequent entries may not be aligned, so copy into
|
||||
an aligned buffer to avoid nasty complaints about
|
||||
unaligned accesses. */
|
||||
int ifr_len = ((struct ifreq *)ptr)->ifr_addr.sa_len + IF_NAMESIZE;
|
||||
if (!(ifr = realloc(ifr, ifr_len)))
|
||||
die("cannot allocate buffer", NULL);
|
||||
goto exit;
|
||||
|
||||
memcpy(ifr, ptr, ifr_len);
|
||||
ptr += ifr_len;
|
||||
@@ -119,7 +151,10 @@ struct irec *enumerate_interfaces(struct iname **names,
|
||||
if (ifr->ifr_addr.sa_family == AF_INET)
|
||||
{
|
||||
addr.in = *((struct sockaddr_in *) &ifr->ifr_addr);
|
||||
addr.in.sin_port = htons(port);
|
||||
addr.in.sin_port = htons(daemon->port);
|
||||
if (ioctl(fd, SIOCGIFNETMASK, ifr) == -1)
|
||||
goto exit;
|
||||
netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (ifr->ifr_addr.sa_family == AF_INET6)
|
||||
@@ -129,7 +164,7 @@ struct irec *enumerate_interfaces(struct iname **names,
|
||||
#else
|
||||
addr.in6 = *((struct sockaddr_in6 *) &ifr->ifr_addr);
|
||||
#endif
|
||||
addr.in6.sin6_port = htons(port);
|
||||
addr.in6.sin6_port = htons(daemon->port);
|
||||
addr.in6.sin6_flowinfo = htonl(0);
|
||||
}
|
||||
#endif
|
||||
@@ -137,78 +172,85 @@ struct irec *enumerate_interfaces(struct iname **names,
|
||||
continue; /* unknown address family */
|
||||
|
||||
if (ioctl(fd, SIOCGIFFLAGS, ifr) < 0)
|
||||
die("ioctl error getting interface flags: %m", NULL);
|
||||
goto exit;
|
||||
|
||||
/* If we are restricting the set of interfaces to use, make
|
||||
sure that loopback interfaces are in that set. */
|
||||
if (*names && (ifr->ifr_flags & IFF_LOOPBACK))
|
||||
if (iface_allowed(daemon, iface, ifr->ifr_name, ifr->ifr_flags & IFF_LOOPBACK, &addr))
|
||||
{
|
||||
struct iname *lo;
|
||||
for (lo = *names; lo; lo = lo->next)
|
||||
if (lo->name && strcmp(lo->name, ifr->ifr_name) == 0)
|
||||
{
|
||||
lo->isloop = 1;
|
||||
break;
|
||||
}
|
||||
if (!lo)
|
||||
if (chainp)
|
||||
{
|
||||
lo = safe_malloc(sizeof(struct iname));
|
||||
lo->name = safe_string_alloc(ifr->ifr_name);
|
||||
lo->isloop = lo->used = 1;
|
||||
lo->next = *names;
|
||||
*names = lo;
|
||||
struct irec *new = safe_malloc(sizeof(struct irec));
|
||||
new->addr = addr;
|
||||
new->netmask = netmask;
|
||||
new->next = iface;
|
||||
iface = new;
|
||||
}
|
||||
else if (sockaddr_isequal(&addr, test_addrp))
|
||||
{
|
||||
*netmaskp = netmask;
|
||||
ret = 1;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
iface = add_iface(iface, ifr->ifr_name, &addr, *names, *addrs, except);
|
||||
|
||||
#if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
|
||||
/* IPv6 addresses don't seem to work with SIOCGIFCONF. Barf */
|
||||
/* This code snarfed from net-tools 1.60 and certainly linux specific, though
|
||||
it shouldn't break on other Unices, and their SIOGIFCONF might work. */
|
||||
{
|
||||
FILE *f = fopen(IP6INTERFACES, "r");
|
||||
int found = 0;
|
||||
union mysockaddr addr6;
|
||||
|
||||
if (f)
|
||||
{
|
||||
unsigned int plen, scope, flags, if_idx;
|
||||
char devname[20], addrstring[32];
|
||||
|
||||
while (fscanf(f, "%32s %02x %02x %02x %02x %20s\n",
|
||||
addrstring, &if_idx, &plen, &scope, &flags, devname) != EOF)
|
||||
{
|
||||
if (strcmp(devname, ifr->ifr_name) == 0)
|
||||
{
|
||||
int i;
|
||||
unsigned char *addr6p = (unsigned char *) &addr6.in6.sin6_addr;
|
||||
memset(&addr6, 0, sizeof(addr6));
|
||||
addr6.sa.sa_family = AF_INET6;
|
||||
for (i=0; i<16; i++)
|
||||
{
|
||||
unsigned int byte;
|
||||
sscanf(addrstring+i+i, "%02x", &byte);
|
||||
addr6p[i] = byte;
|
||||
}
|
||||
addr6.in6.sin6_port = htons(port);
|
||||
addr6.in6.sin6_flowinfo = htonl(0);
|
||||
addr6.in6.sin6_scope_id = htonl(scope);
|
||||
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
if (found)
|
||||
iface = add_iface(iface, ifr->ifr_name, &addr6, *names, *addrs, except);
|
||||
}
|
||||
#endif /* LINUX */
|
||||
}
|
||||
|
||||
#if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
|
||||
/* IPv6 addresses don't seem to work with SIOCGIFCONF. Barf */
|
||||
/* This code snarfed from net-tools 1.60 and certainly linux specific, though
|
||||
it shouldn't break on other Unices, and their SIOGIFCONF might work. */
|
||||
if ((f = fopen(IP6INTERFACES, "r")))
|
||||
{
|
||||
unsigned int plen, scope, flags, if_idx;
|
||||
char devname[21], addrstring[33];
|
||||
|
||||
while (fscanf(f, "%32s %x %x %x %x %20s\n",
|
||||
addrstring, &if_idx, &plen, &scope, &flags, devname) != EOF)
|
||||
{
|
||||
int i;
|
||||
struct ifreq sifr;
|
||||
unsigned char *addr6p = (unsigned char *) &addr.in6.sin6_addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sa.sa_family = AF_INET6;
|
||||
for (i=0; i<16; i++)
|
||||
{
|
||||
unsigned int byte;
|
||||
sscanf(addrstring+i+i, "%02x", &byte);
|
||||
addr6p[i] = byte;
|
||||
}
|
||||
addr.in6.sin6_port = htons(daemon->port);
|
||||
addr.in6.sin6_flowinfo = htonl(0);
|
||||
addr.in6.sin6_scope_id = htonl(scope);
|
||||
|
||||
strncpy(sifr.ifr_name, devname, IF_NAMESIZE);
|
||||
if (ioctl(fd, SIOCGIFFLAGS, &sifr) < 0)
|
||||
goto exit;
|
||||
|
||||
if (iface_allowed(daemon, iface, sifr.ifr_name, sifr.ifr_flags & IFF_LOOPBACK, &addr))
|
||||
{
|
||||
if (chainp)
|
||||
{
|
||||
struct irec *new = safe_malloc(sizeof(struct irec));
|
||||
new->addr = addr;
|
||||
new->next = iface;
|
||||
iface = new;
|
||||
}
|
||||
else if (sockaddr_isequal(&addr, test_addrp))
|
||||
{
|
||||
ret = 1;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
#endif /* LINUX */
|
||||
|
||||
if (chainp)
|
||||
{
|
||||
*chainp = iface;
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
exit:
|
||||
if (buf)
|
||||
free(buf);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
@@ -217,9 +259,74 @@ struct irec *enumerate_interfaces(struct iname **names,
|
||||
#endif
|
||||
close(fd);
|
||||
|
||||
return iface;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
static int create_ipv6_listener(struct listener **link, int port)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
int tcpfd, fd, flags, save;
|
||||
struct listener *l;
|
||||
int opt = 1;
|
||||
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
addr.in6.sin6_addr = in6addr_any;
|
||||
addr.in6.sin6_port = htons(port);
|
||||
addr.in6.sin6_flowinfo = htonl(0);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
|
||||
/* No error of the kernel doesn't support IPv6 */
|
||||
if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
|
||||
return (errno == EPROTONOSUPPORT ||
|
||||
errno == EAFNOSUPPORT ||
|
||||
errno == EINVAL);
|
||||
|
||||
if ((tcpfd = socket(AF_INET6, SOCK_STREAM, 0)) == -1)
|
||||
{
|
||||
save = errno;
|
||||
close(fd);
|
||||
errno = save;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
|
||||
(flags = fcntl(fd, F_GETFL, 0)) == -1 ||
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||
(flags = fcntl(tcpfd, F_GETFL, 0)) == -1 ||
|
||||
fcntl(tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||
#ifdef IPV6_RECVPKTINFO
|
||||
setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||
#else
|
||||
setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||
#endif
|
||||
bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
|
||||
listen(tcpfd, 5) == -1 ||
|
||||
bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
||||
{
|
||||
save = errno;
|
||||
close(fd);
|
||||
close(tcpfd);
|
||||
errno = save;
|
||||
return 0;
|
||||
}
|
||||
|
||||
l = safe_malloc(sizeof(struct listener));
|
||||
l->fd = fd;
|
||||
l->tcpfd = tcpfd;
|
||||
l->family = AF_INET6;
|
||||
l->next = NULL;
|
||||
*link = l;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct listener *create_wildcard_listeners(int port)
|
||||
{
|
||||
#if !(defined(IP_PKTINFO) || (defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR)))
|
||||
@@ -227,10 +334,9 @@ struct listener *create_wildcard_listeners(int port)
|
||||
#else
|
||||
union mysockaddr addr;
|
||||
int opt = 1;
|
||||
struct listener *listen;
|
||||
#ifdef HAVE_IPV6
|
||||
int fd;
|
||||
#endif
|
||||
struct listener *l, *l6 = NULL;
|
||||
int flags;
|
||||
int tcpfd, fd;
|
||||
|
||||
addr.in.sin_family = AF_INET;
|
||||
addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
@@ -238,97 +344,114 @@ struct listener *create_wildcard_listeners(int port)
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
listen = safe_malloc(sizeof(struct listener));
|
||||
if ((listen->fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return NULL;
|
||||
|
||||
if ((tcpfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
{
|
||||
free(listen);
|
||||
close (fd);
|
||||
return NULL;
|
||||
}
|
||||
if (setsockopt(listen->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
#if defined(IP_PKTINFO)
|
||||
setsockopt(listen->fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
setsockopt(listen->fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(listen->fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
|
||||
#endif
|
||||
bind(listen->fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
||||
{
|
||||
close(listen->fd);
|
||||
free(listen);
|
||||
return NULL;
|
||||
}
|
||||
listen->next = NULL;
|
||||
listen->family = AF_INET;
|
||||
|
||||
if (setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
|
||||
listen(tcpfd, 5) == -1 ||
|
||||
(flags = fcntl(tcpfd, F_GETFL, 0)) == -1 ||
|
||||
fcntl(tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||
#ifdef HAVE_IPV6
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
addr.in6.sin6_addr = in6addr_any;
|
||||
addr.in6.sin6_port = htons(port);
|
||||
addr.in6.sin6_flowinfo = htonl(0);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
!create_ipv6_listener(&l6, port) ||
|
||||
#endif
|
||||
if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
(flags = fcntl(fd, F_GETFL, 0)) == -1 ||
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||
#if defined(IP_PKTINFO)
|
||||
setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
|
||||
#endif
|
||||
bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
||||
{
|
||||
if (errno != EPROTONOSUPPORT &&
|
||||
errno != EAFNOSUPPORT &&
|
||||
errno != EINVAL)
|
||||
{
|
||||
close(listen->fd);
|
||||
free(listen);
|
||||
return NULL;
|
||||
}
|
||||
close(fd);
|
||||
close(tcpfd);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
listen->next = safe_malloc(sizeof(struct listener));
|
||||
listen->next->fd = fd;
|
||||
listen->next->family = AF_INET6;
|
||||
listen->next->next = NULL;
|
||||
if (setsockopt(listen->next->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(listen->next->fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||
bind(listen->next->fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
||||
{
|
||||
close(listen->next->fd);
|
||||
free(listen->next);
|
||||
close(listen->fd);
|
||||
free(listen);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return listen;
|
||||
|
||||
l = safe_malloc(sizeof(struct listener));
|
||||
l->family = AF_INET;
|
||||
l->fd = fd;
|
||||
l->tcpfd = tcpfd;
|
||||
l->next = l6;
|
||||
|
||||
return l;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
struct listener *create_bound_listeners(struct irec *interfaces)
|
||||
struct listener *create_bound_listeners(struct irec *interfaces, int port)
|
||||
{
|
||||
|
||||
struct listener *listeners = NULL;
|
||||
struct irec *iface;
|
||||
int opt = 1;
|
||||
|
||||
int flags = port, opt = 1;
|
||||
|
||||
for (iface = interfaces ;iface; iface = iface->next)
|
||||
{
|
||||
struct listener *new = safe_malloc(sizeof(struct listener));
|
||||
new->family = iface->addr.sa.sa_family;
|
||||
new->iface = iface;
|
||||
new->next = listeners;
|
||||
listeners = new;
|
||||
if ((new->fd = socket(iface->addr.sa.sa_family, SOCK_DGRAM, 0)) == -1)
|
||||
die("failed to create socket: %s", NULL);
|
||||
if (setsockopt(new->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
if ((new->tcpfd = socket(iface->addr.sa.sa_family, SOCK_STREAM, 0)) == -1 ||
|
||||
(new->fd = socket(iface->addr.sa.sa_family, SOCK_DGRAM, 0)) == -1 ||
|
||||
setsockopt(new->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(new->tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
/* See Stevens 16.6 */
|
||||
(flags = fcntl(new->tcpfd, F_GETFL, 0)) == -1 ||
|
||||
fcntl(new->tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||
(flags = fcntl(new->fd, F_GETFL, 0)) == -1 ||
|
||||
fcntl(new->fd, F_SETFL, flags | O_NONBLOCK) == -1)
|
||||
die("failed to create listening socket: %s", NULL);
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (iface->addr.sa.sa_family == AF_INET6)
|
||||
{
|
||||
if (setsockopt(new->fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(new->tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
|
||||
die("failed to set IPV6 options on listening socket: %s", NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
|
||||
bind(new->fd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
|
||||
die("failed to bind socket: %s", NULL);
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
if (iface->addr.sa.sa_family == AF_INET6 && errno == ENODEV)
|
||||
{
|
||||
close(new->tcpfd);
|
||||
close(new->fd);
|
||||
free(new);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
die("failed to bind listening socket: %s", NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
listeners = new;
|
||||
if (listen(new->tcpfd, 5) == -1)
|
||||
die("failed to listen on socket: %s", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return listeners;
|
||||
}
|
||||
|
||||
static struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds)
|
||||
struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds)
|
||||
{
|
||||
struct serverfd *sfd;
|
||||
|
||||
int flags;
|
||||
|
||||
/* may have a suitable one already */
|
||||
for (sfd = *sfds; sfd; sfd = sfd->next )
|
||||
if (sockaddr_isequal(&sfd->source_addr, addr))
|
||||
@@ -345,7 +468,9 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **s
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bind(sfd->fd, (struct sockaddr *)addr, sa_len(addr)) == -1)
|
||||
if (bind(sfd->fd, (struct sockaddr *)addr, sa_len(addr)) == -1 ||
|
||||
(flags = fcntl(sfd->fd, F_GETFL, 0)) == -1 ||
|
||||
fcntl(sfd->fd, F_SETFL, flags | O_NONBLOCK) == -1)
|
||||
{
|
||||
int errsave = errno; /* save error from bind. */
|
||||
close(sfd->fd);
|
||||
@@ -361,17 +486,19 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **s
|
||||
return sfd;
|
||||
}
|
||||
|
||||
struct server *check_servers(struct server *new, struct irec *interfaces, struct serverfd **sfds)
|
||||
void check_servers(struct daemon *daemon, struct irec *interfaces)
|
||||
{
|
||||
char addrbuff[ADDRSTRLEN];
|
||||
struct irec *iface;
|
||||
struct server *tmp, *ret = NULL;
|
||||
struct server *new, *tmp, *ret = NULL;
|
||||
int port = 0;
|
||||
|
||||
/* forward table rules reference servers, so have to blow them away */
|
||||
forward_init(0);
|
||||
|
||||
for (;new; new = tmp)
|
||||
daemon->last_server = NULL;
|
||||
|
||||
for (new = daemon->servers; new; new = tmp)
|
||||
{
|
||||
tmp = new->next;
|
||||
|
||||
@@ -403,7 +530,7 @@ struct server *check_servers(struct server *new, struct irec *interfaces, struct
|
||||
}
|
||||
|
||||
/* Do we need a socket set? */
|
||||
if (!new->sfd && !(new->sfd = allocate_sfd(&new->source_addr, sfds)))
|
||||
if (!new->sfd && !(new->sfd = allocate_sfd(&new->source_addr, &daemon->sfds)))
|
||||
{
|
||||
syslog(LOG_WARNING,
|
||||
"ignoring nameserver %s - cannot make/bind socket: %m", addrbuff);
|
||||
@@ -433,15 +560,16 @@ struct server *check_servers(struct server *new, struct irec *interfaces, struct
|
||||
syslog(LOG_INFO, "using nameserver %s#%d", addrbuff, port);
|
||||
}
|
||||
|
||||
return ret;
|
||||
daemon->servers = ret;
|
||||
}
|
||||
|
||||
struct server *reload_servers(char *fname, char *buff, struct server *serv, int query_port)
|
||||
void reload_servers(char *fname, struct daemon *daemon)
|
||||
{
|
||||
FILE *f;
|
||||
char *line;
|
||||
struct server *old_servers = NULL;
|
||||
struct server *new_servers = NULL;
|
||||
struct server *serv = daemon->servers;
|
||||
|
||||
/* move old servers to free list - we can reuse the memory
|
||||
and not risk malloc if there are the same or fewer new servers.
|
||||
@@ -471,7 +599,7 @@ struct server *reload_servers(char *fname, char *buff, struct server *serv, int
|
||||
else
|
||||
{
|
||||
syslog(LOG_INFO, "reading %s", fname);
|
||||
while ((line = fgets(buff, MAXDNAME, f)))
|
||||
while ((line = fgets(daemon->namebuff, MAXDNAME, f)))
|
||||
{
|
||||
union mysockaddr addr, source_addr;
|
||||
char *token = strtok(line, " \t\n\r");
|
||||
@@ -494,7 +622,7 @@ struct server *reload_servers(char *fname, char *buff, struct server *serv, int
|
||||
source_addr.in.sin_family = addr.in.sin_family = AF_INET;
|
||||
addr.in.sin_port = htons(NAMESERVER_PORT);
|
||||
source_addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
source_addr.in.sin_port = htons(query_port);
|
||||
source_addr.in.sin_port = htons(daemon->query_port);
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr))
|
||||
@@ -506,7 +634,7 @@ struct server *reload_servers(char *fname, char *buff, struct server *serv, int
|
||||
addr.in6.sin6_port = htons(NAMESERVER_PORT);
|
||||
source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = htonl(0);
|
||||
source_addr.in6.sin6_addr = in6addr_any;
|
||||
source_addr.in6.sin6_port = htons(query_port);
|
||||
source_addr.in6.sin6_port = htons(daemon->query_port);
|
||||
}
|
||||
#endif /* IPV6 */
|
||||
else
|
||||
@@ -542,7 +670,7 @@ struct server *reload_servers(char *fname, char *buff, struct server *serv, int
|
||||
old_servers = tmp;
|
||||
}
|
||||
|
||||
return new_servers;
|
||||
daemon->servers = new_servers;
|
||||
}
|
||||
|
||||
|
||||
|
||||
1208
src/option.c
1208
src/option.c
File diff suppressed because it is too large
Load Diff
1370
src/rfc1035.c
1370
src/rfc1035.c
File diff suppressed because it is too large
Load Diff
873
src/rfc2131.c
873
src/rfc2131.c
File diff suppressed because it is too large
Load Diff
92
src/util.c
92
src/util.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000 - 2005 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
|
||||
@@ -113,27 +113,29 @@ int legal_char(char c)
|
||||
int canonicalise(char *s)
|
||||
{
|
||||
/* check for legal chars and remove trailing .
|
||||
also fail empty string. */
|
||||
int l = strlen(s);
|
||||
also fail empty string and label > 63 chars */
|
||||
size_t dotgap = 0, l = strlen(s);
|
||||
char c;
|
||||
|
||||
if (l == 0) return 0;
|
||||
if (l == 0 || l > MAXDNAME) return 0;
|
||||
|
||||
if (s[l-1] == '.')
|
||||
{
|
||||
if (l == 1) return 0;
|
||||
s[l-1] = 0;
|
||||
}
|
||||
|
||||
|
||||
while ((c = *s++))
|
||||
if (c != '.' && !legal_char(c))
|
||||
if (c == '.')
|
||||
dotgap = 0;
|
||||
else if (!legal_char(c) || (++dotgap > MAXLABEL))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* for use during startup */
|
||||
void *safe_malloc(int size)
|
||||
void *safe_malloc(size_t size)
|
||||
{
|
||||
void *ret = malloc(size);
|
||||
|
||||
@@ -156,7 +158,7 @@ char *safe_string_alloc(char *cp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void complain(char *message, char *arg1)
|
||||
static void log_err(char *message, char *arg1)
|
||||
{
|
||||
char *errmess = strerror(errno);
|
||||
|
||||
@@ -170,9 +172,17 @@ void complain(char *message, char *arg1)
|
||||
syslog(LOG_CRIT, message, arg1, errmess);
|
||||
}
|
||||
|
||||
void complain(char *message, int lineno, char *file)
|
||||
{
|
||||
char buff[256];
|
||||
|
||||
sprintf(buff, "%s at line %d of %s", message, lineno, file);
|
||||
log_err(buff, NULL);
|
||||
}
|
||||
|
||||
void die(char *message, char *arg1)
|
||||
{
|
||||
complain(message, arg1);
|
||||
log_err(message, arg1);
|
||||
syslog(LOG_CRIT, "FAILED to start up");
|
||||
exit(1);
|
||||
}
|
||||
@@ -251,3 +261,67 @@ int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
|
||||
{
|
||||
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
|
||||
}
|
||||
|
||||
int retry_send(void)
|
||||
{
|
||||
struct timespec waiter;
|
||||
if (errno == EAGAIN)
|
||||
{
|
||||
waiter.tv_sec = 0;
|
||||
waiter.tv_nsec = 10000;
|
||||
nanosleep(&waiter, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (errno == EINTR)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void prettyprint_time(char *buf, unsigned int t)
|
||||
{
|
||||
if (t == 0xffffffff)
|
||||
sprintf(buf, "infinite");
|
||||
else
|
||||
{
|
||||
unsigned int x, p = 0;
|
||||
if ((x = t/3600))
|
||||
p += sprintf(&buf[p], "%dh", x);
|
||||
if ((x = (t/60)%60))
|
||||
p += sprintf(&buf[p], "%dm", x);
|
||||
if ((x = t%60))
|
||||
p += sprintf(&buf[p], "%ds", x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* in may equal out, when maxlen may be -1 (No max len). */
|
||||
int parse_hex(char *in, unsigned char *out, int maxlen, unsigned int *wildcard_mask)
|
||||
{
|
||||
int mask = 0, i = 0;
|
||||
char *r;
|
||||
|
||||
while (maxlen == -1 || i < maxlen)
|
||||
{
|
||||
for (r = in; *r != 0 && *r != ':' && *r != '-'; r++);
|
||||
if (*r == 0)
|
||||
maxlen = i;
|
||||
if (r != in )
|
||||
{
|
||||
*r = 0;
|
||||
mask = mask << 1;
|
||||
if (strcmp(in, "*") == 0)
|
||||
mask |= 1;
|
||||
else
|
||||
out[i] = strtol(in, NULL, 16);
|
||||
i++;
|
||||
}
|
||||
in = r+1;
|
||||
}
|
||||
|
||||
if (wildcard_mask)
|
||||
*wildcard_mask = mask;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user