mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-04 13:48:30 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5aabfc78bc | ||
|
|
f2621c7ff0 | ||
|
|
6b01084f8e | ||
|
|
1b7ecd111d |
No files matched your search
@@ -2086,4 +2086,262 @@ version 2.36
|
||||
as not to affect the validity of the signature. This
|
||||
should allow DDNS updates to be forwarded.
|
||||
|
||||
version 2.37
|
||||
Add better support for RFC-2855 DHCP-over-firewire and RFC
|
||||
-4390 DHCP-over-InfiniBand. A good suggestion from Karl Svec.
|
||||
|
||||
Some efficiency tweaks to the cache code for very large
|
||||
/etc/hosts files. Should improve reverse (address->name)
|
||||
lookups and garbage collection. Thanks to Jan 'RedBully'
|
||||
Seiffert for input on this.
|
||||
|
||||
Fix regression in 2.36 which made bogus-nxdomain
|
||||
and DNS caching unreliable. Thanks to Dennis DeDonatis
|
||||
and Jan Seiffert for bug reports.
|
||||
|
||||
Make DHCP encapsulated vendor-class options sane. Be
|
||||
warned that some conceivable existing configurations
|
||||
using these may break, but they work in a much
|
||||
simpler and more logical way now. Prepending
|
||||
"vendor:<client-id>" to an option encapsulates it
|
||||
in option 43, and the option is sent only if the
|
||||
client-supplied vendor-class substring-matches with
|
||||
the given client-id. Thanks to Dennis DeDonatis for
|
||||
help with this.
|
||||
|
||||
Apply patch from Jan Seiffert to tidy up tftp.c
|
||||
|
||||
Add support for overloading the filename and servername
|
||||
fields in DHCP packet. This gives extra option-space when
|
||||
these fields are not being used or with a modern client
|
||||
which supports moving them into options.
|
||||
|
||||
Added a LIMITS section to the man-page, with guidance on
|
||||
maximum numbers of clients, file sizes and tuning.
|
||||
|
||||
release 2.38
|
||||
Fix compilation on *BSD. Thanks to Tom Hensel.
|
||||
|
||||
Don't send length zero DHCP option 43 and cope with
|
||||
encapsulated options whose total length exceeds 255 octets
|
||||
by splitting them into multiple option 43 pieces.
|
||||
|
||||
Avoid queries being retried forever when --strict-order is
|
||||
set and an upstream server returns a SERVFAIL
|
||||
error. Thanks to Johannes Stezenbach for spotting this.
|
||||
|
||||
Fix BOOTP support, broken in version 2.37.
|
||||
|
||||
Add example dhcp-options for Etherboot.
|
||||
|
||||
Add \e (for ASCII ESCape) to the set of valid escapes
|
||||
in config-file strings.
|
||||
|
||||
Added --dhcp-option-force flag and examples in the
|
||||
configuration file which use this to control PXELinux.
|
||||
|
||||
Added --tftp-no-blocksize option.
|
||||
|
||||
Set netid tag "bootp" when BOOTP (rather than DHCP) is in
|
||||
use. This makes it easy to customise which options are
|
||||
sent to BOOTP clients. (BOOTP allows only 64 octets for
|
||||
options, so it can be necessary to trim things.)
|
||||
|
||||
Fix rare hang in cache code, a 2.37 regression. This
|
||||
probably needs an infinite DHCP lease and some bad luck to
|
||||
trigger. Thanks to Detlef Reichelt for bug reports and testing.
|
||||
|
||||
release 2.39
|
||||
Apply patch from Mike Baker/OpenWRT to ensure that names
|
||||
like "localhost." in /etc/hosts with trailing period
|
||||
are treated as fully-qualified.
|
||||
|
||||
Tolerate and ignore spaces around commas in the
|
||||
configuration file in all circumstances. Note that this
|
||||
may change the meaning of a few existing config files, for
|
||||
instance
|
||||
txt-record=mydomain.com, string
|
||||
would have a leading space in the string before, and now
|
||||
will not. To get the old behaviour back, use quotes:
|
||||
txt-record=mydomain.com," string"
|
||||
|
||||
/a is no longer a valid escape in quoted strings.
|
||||
|
||||
Added symbolic DHCP option names. Instead of
|
||||
dhcp-option = 3, 1.2.3.4
|
||||
it is now possible to do
|
||||
dhcp-option = option:router, 1.2.3.4
|
||||
To see the list of known DHCP options, use the
|
||||
command "dnsmasq --help dhcp"
|
||||
Thanks to Luigi Rizzo for a patch and good work on this.
|
||||
|
||||
Overhauled the log code so that logging can be asynchronous;
|
||||
dnsmasq then no longer blocks waiting for the syslog() library
|
||||
call. This is important on systems where syslog
|
||||
is being used to log over the network (and therefore doing
|
||||
DNS lookups) and syslog is using dnsmasq as its DNS
|
||||
server. Having dnsmasq block awaiting syslog under
|
||||
such circumstances can lead to syslog and dnsmasq
|
||||
deadlocking. The new behaviour is enabled with a new
|
||||
--log-async flag, which can also be used to tune the
|
||||
queue length. Paul Chambers found and diagnosed
|
||||
this trap for the unwary. He also did much testing of
|
||||
the solution along with Carlos Carvalho.
|
||||
|
||||
--log-facility can now take a file-name instead of a
|
||||
facility name. When this is done, dnsmasq logs to the
|
||||
file and not via syslog. (Failures early in startup,
|
||||
whilst reading configuration, will still go to syslog,
|
||||
and syslog is used as a log-of-last-resort if the file
|
||||
cannot be written.)
|
||||
|
||||
Added --log-dhcp flag. Suggestion from Carlos Carvalho.
|
||||
|
||||
Made BINDIR, MANDIR and LOCALEDIR independently
|
||||
over-rideable in the makefile. Suggestion from Thomas
|
||||
Klausner.
|
||||
|
||||
Added 127.0.0.0/8 and 169.254.0.0/16 to the address
|
||||
ranges affected by --bogus-priv. Thanks to Paul
|
||||
Chambers for the patch.
|
||||
|
||||
Fixed failure of TFTP server with --listen-address. Thanks
|
||||
to William Dinkel for the bug report.
|
||||
|
||||
Added --dhcp-circuitid and --dhcp-remoteid for RFC3046
|
||||
relay agent data matching.
|
||||
|
||||
Added --dhcp-subscrid for RFC3993 subscriber-id relay
|
||||
agent data matching.
|
||||
|
||||
Correctly garbage-collect connections when upstream
|
||||
servers go away as a result of DBus transactions.
|
||||
|
||||
Allow absolute paths for TFTP transfers even when
|
||||
--tftp-root is set, as long as the path matches the root,
|
||||
so /var/ftp/myfile is OK with tftp-root=/var/ftp.
|
||||
Thanks for Thomas Mizzi for the patch.
|
||||
|
||||
Updated Spanish translation - thanks to Chris Chatham.
|
||||
|
||||
Updated French translation - thanks to Gildas Le Nadan.
|
||||
|
||||
Added to example conf file example of routing PTR queries
|
||||
for a subnet to a different nameserver. Suggestion from
|
||||
Jon Nicholson.
|
||||
|
||||
Added --interface-name option. This provides a facility
|
||||
to add a domain name with a dynamic IP address taken from
|
||||
the address of a local network interface. Useful for
|
||||
networks with dynamic IPs.
|
||||
|
||||
version 2.40
|
||||
Make SIGUSR2 close-and-reopen the logfile when logging
|
||||
direct to a file. Thanks to Carlos Carvalho for
|
||||
suggesting this. When a logfile is created, change
|
||||
its ownership to the user dnsmasq will run as, don't
|
||||
leave it owned by root.
|
||||
|
||||
Set a special tag, "known" for hosts which are matched by
|
||||
a dhcp-host or /etc/ethers line. This is especially
|
||||
useful to be able to do --dhcp-ignore=#known, like ISCs
|
||||
"deny unknown-clients".
|
||||
|
||||
Explicitly set a umask before creating the leases file,
|
||||
rather than relying on whatever we inherited. The
|
||||
permissions are set to 644.
|
||||
|
||||
Fix handling of fully-qualified names in --dhcp-host
|
||||
directives and in /etc/ethers. These are now rejected
|
||||
if the domain doesn't match that given by --domain,
|
||||
and used correctly otherwise. Before, putting
|
||||
a FQDN here could cause the whole FQDN to be used as
|
||||
hostname. Thanks to Michael Heimpold for the bug report.
|
||||
|
||||
Massive but trivial edit to make the "daemon" variable
|
||||
global, instead of copying the same value around as the
|
||||
first argument to half the functions in the program.
|
||||
|
||||
Updated Spanish manpage and message catalog. Thanks
|
||||
to Chris Chatham.
|
||||
|
||||
Added patch for support of DNS LOC records in
|
||||
contrib/dns-loc. Thanks to Lorenz Schori.
|
||||
|
||||
Fixed error in manpage: dhcp-ignore-name ->
|
||||
dhcp-ignore-names. Thanks to Daniel Mentz for spotting
|
||||
this.
|
||||
|
||||
Use client-id as hash-seed for DHCP address allocation
|
||||
with Firewire and Infiniband, as these don't supply an MAC
|
||||
address.
|
||||
|
||||
Tweaked TFTP file-open code to make it behave sensibly
|
||||
when the filesystem changes under its feet.
|
||||
|
||||
Added DNSMASQ_TIME_REMAINING environment variable to the
|
||||
lease-script.
|
||||
|
||||
Always send replies to DHCPINFORM requests to the source
|
||||
of the request and not to the address in ciaddr. This
|
||||
allows third-party queries.
|
||||
|
||||
Return "lease time remaining" in the reply to a DHCPINFORM
|
||||
request if there exists a lease for the host sending the
|
||||
request.
|
||||
|
||||
Added --dhcp-hostsfile option. This gives a superset of
|
||||
the functionality provided by /etc/ethers. Thanks to
|
||||
Greg Kurtzer for the suggestion.
|
||||
|
||||
Accept keyword "server" as a synonym for "nameserver" in
|
||||
resolv.conf. Thanks to Andrew Bartlett for the report.
|
||||
|
||||
Add --tftp-unique-root option. Suggestion from Dermot
|
||||
Bradley.
|
||||
|
||||
Tweak TFTP retry timer to avoid problems with difficult
|
||||
clients. Thanks to Dermot Bradley for assistance with
|
||||
this.
|
||||
|
||||
Continue to use unqualified hostnames provided by DHCP
|
||||
clients, even if the domain part is illegal. (The domain
|
||||
is ignored, and an error logged.) Previously in this
|
||||
situation, the whole name whould have been
|
||||
rejected. Thanks to Jima for the patch.
|
||||
|
||||
Handle EINTR returns from wait() correctly and reap
|
||||
our children's children if necessary. This fixes
|
||||
a problem with zombie-creation under *BSD when using
|
||||
--dhcp-script.
|
||||
|
||||
Escape spaces in hostnames when they are stored in the
|
||||
leases file and passed to the lease-change
|
||||
script. Suggestion from Ben Voigt.
|
||||
|
||||
Re-run the lease chamge script with an "old" event for
|
||||
each lease when dnsmasq receives a SIGHUP.
|
||||
|
||||
Added more useful exit codes, including passing on a
|
||||
non-zero exit code from the lease-script "init" call when
|
||||
--leasefile-ro is set.
|
||||
|
||||
Log memory allocation failure whilst the daemon is
|
||||
running. Allocation failures during startup are fatal,
|
||||
but lack of memory whilst running is worked around.
|
||||
This used to be silent, but now is logged.
|
||||
|
||||
Fixed misaligned memory access which caused problems on
|
||||
Blackfin CPUs. Thanks to Alex Landau for the patch.
|
||||
|
||||
Don't include (useless) script-calling code when NO_FORK
|
||||
is set. Since this tends to be used on very small uclinux
|
||||
systems, it's worth-while to save some code-size.
|
||||
|
||||
Don't set REUSEADDR on TFTP listening socket. There's no
|
||||
need to do so, and it creates confusing behaviour when
|
||||
inetd is also listening on the same port. Thanks to Erik
|
||||
Brown for spotting the problem.
|
||||
|
||||
|
||||
|
||||
@@ -409,6 +409,27 @@ A: Yes, as a DNS server, dnsmasq will just work in a vserver.
|
||||
refer to the vserver documentation for more information).
|
||||
|
||||
|
||||
Q: What's the problem with syslog and dnsmasq?
|
||||
|
||||
A: In almost all cases: none. If you have the normal arrangement with
|
||||
local daemons logging to a local syslog, which then writes to disk,
|
||||
then there's never a problem. If you use network logging, then
|
||||
there's a potential problem with deadlock: the syslog daemon will
|
||||
do DNS lookups so that it can log the source of log messages,
|
||||
these lookups will (depending on exact configuration) go through
|
||||
dnsmasq, which also sends log messages. With bad timing, you can
|
||||
arrive at a situation where syslog is waiting for dnsmasq, and
|
||||
dnsmasq is waiting for syslog; they will both wait forever. This
|
||||
problem is fixed from dnsmasq-2.39, which introduces asynchronous
|
||||
logging: dnsmasq no longer waits for syslog and the deadlock is
|
||||
broken. There is a remaining problem in 2.39, where "log-queries"
|
||||
is in use. In this case most DNS queries generate two log lines, if
|
||||
these go to a syslog which is doing a DNS lookup for each log line,
|
||||
then those queries will in turn generate two more log lines, and a
|
||||
chain reaction runaway will occur. To avoid this, use syslog-ng
|
||||
and turn on syslog-ng's dns-cache function.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
PREFIX?=/usr/local
|
||||
BINDIR = ${PREFIX}/sbin
|
||||
MANDIR = ${PREFIX}/share/man
|
||||
LOCALEDIR = ${PREFIX}/share/locale
|
||||
PREFIX ?= /usr/local
|
||||
BINDIR ?= ${PREFIX}/sbin
|
||||
MANDIR ?= ${PREFIX}/share/man
|
||||
LOCALEDIR ?= ${PREFIX}/share/locale
|
||||
|
||||
SRC = src
|
||||
PO = po
|
||||
|
||||
+2
-1
@@ -3,7 +3,8 @@ PKG_CONFIG ?= pkg-config
|
||||
|
||||
|
||||
OBJS = cache.o rfc1035.o util.o option.o forward.o isc.o network.o \
|
||||
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o helper.o tftp.o
|
||||
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
|
||||
helper.o tftp.o log.o
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $(COPTS) $(I18N) `echo $(COPTS) | ../bld/pkg-wrapper $(PKG_CONFIG) --cflags dbus-1` $(RPM_OPT_FLAGS) -Wall -W -c $<
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
Hi Simon
|
||||
|
||||
Here is a patch against dnsmasq 2.39 which provides support for LOC
|
||||
entries in order to assign location information to dns records
|
||||
(rfc1876). I tested it on OSX and on OpenWRT.
|
||||
|
||||
Cheers
|
||||
Lorenz
|
||||
|
||||
More info:
|
||||
http://www.ckdhr.com/dns-loc/
|
||||
http://www.faqs.org/rfcs/rfc1876.html
|
||||
@@ -0,0 +1,522 @@
|
||||
diff -Nur dnsmasq-2.39-orig/bld/Makefile dnsmasq-2.39/bld/Makefile
|
||||
--- dnsmasq-2.39-orig/bld/Makefile 2007-02-17 14:37:06.000000000 +0100
|
||||
+++ dnsmasq-2.39/bld/Makefile 2007-05-20 18:23:44.000000000 +0200
|
||||
@@ -2,7 +2,7 @@
|
||||
PKG_CONFIG ?= pkg-config
|
||||
|
||||
|
||||
-OBJS = cache.o rfc1035.o util.o option.o forward.o isc.o network.o \
|
||||
+OBJS = cache.o rfc1035.o rfc1876.o util.o option.o forward.o isc.o network.o \
|
||||
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
|
||||
helper.o tftp.o log.o
|
||||
|
||||
diff -Nur dnsmasq-2.39-orig/src/dnsmasq.h dnsmasq-2.39/src/dnsmasq.h
|
||||
--- dnsmasq-2.39-orig/src/dnsmasq.h 2007-04-20 12:53:38.000000000 +0200
|
||||
+++ dnsmasq-2.39/src/dnsmasq.h 2007-05-20 19:50:37.000000000 +0200
|
||||
@@ -162,6 +162,12 @@
|
||||
struct interface_name *next;
|
||||
};
|
||||
|
||||
+struct loc_record {
|
||||
+ char *name, loc[16];
|
||||
+ unsigned short class;
|
||||
+ struct loc_record *next;
|
||||
+};
|
||||
+
|
||||
union bigname {
|
||||
char name[MAXDNAME];
|
||||
union bigname *next; /* freelist */
|
||||
@@ -476,6 +482,7 @@
|
||||
struct mx_srv_record *mxnames;
|
||||
struct txt_record *txt;
|
||||
struct ptr_record *ptr;
|
||||
+ struct loc_record *loc;
|
||||
struct interface_name *int_names;
|
||||
char *mxtarget;
|
||||
char *lease_file;
|
||||
@@ -725,3 +732,6 @@
|
||||
void tftp_request(struct listener *listen, struct daemon *daemon, time_t now);
|
||||
void check_tftp_listeners(struct daemon *daemon, fd_set *rset, time_t now);
|
||||
#endif
|
||||
+
|
||||
+/* rfc1876 */
|
||||
+u_int32_t loc_aton(const char *ascii, u_char *binary);
|
||||
diff -Nur dnsmasq-2.39-orig/src/option.c dnsmasq-2.39/src/option.c
|
||||
--- dnsmasq-2.39-orig/src/option.c 2007-04-19 23:34:49.000000000 +0200
|
||||
+++ dnsmasq-2.39/src/option.c 2007-05-20 20:15:15.000000000 +0200
|
||||
@@ -43,6 +43,7 @@
|
||||
#define LOPT_REMOTE 269
|
||||
#define LOPT_SUBSCR 270
|
||||
#define LOPT_INTNAME 271
|
||||
+#define LOPT_LOC 272
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -122,6 +123,7 @@
|
||||
{"tftp-root", 1, 0, LOPT_PREFIX },
|
||||
{"tftp-max", 1, 0, LOPT_TFTP_MAX },
|
||||
{"ptr-record", 1, 0, LOPT_PTR },
|
||||
+ {"loc-record", 1, 0, LOPT_LOC },
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
{"bridge-interface", 1, 0 , LOPT_BRIDGE },
|
||||
#endif
|
||||
@@ -235,6 +237,7 @@
|
||||
{ "-y, --localise-queries", gettext_noop("Answer DNS queries based on the interface a query was sent to."), NULL },
|
||||
{ "-Y --txt-record=name,txt....", gettext_noop("Specify TXT DNS record."), NULL },
|
||||
{ " --ptr-record=name,target", gettext_noop("Specify PTR DNS record."), NULL },
|
||||
+ { " --loc-record=name,lat lon alt", gettext_noop("Specify LOC DNS record."), NULL },
|
||||
{ " --interface-name=name,interface", gettext_noop("Give DNS name to IPv4 address of interface."), NULL },
|
||||
{ "-z, --bind-interfaces", gettext_noop("Bind only to interfaces in use."), NULL },
|
||||
{ "-Z, --read-ethers", gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
|
||||
@@ -1835,6 +1838,37 @@
|
||||
new->intr = safe_string_alloc(comma);
|
||||
break;
|
||||
}
|
||||
+
|
||||
+ case LOPT_LOC:
|
||||
+ {
|
||||
+ struct loc_record *new;
|
||||
+ unsigned char *p, *q;
|
||||
+
|
||||
+ comma = split(arg);
|
||||
+
|
||||
+ if (!canonicalise_opt(arg))
|
||||
+ {
|
||||
+ option = '?';
|
||||
+ problem = _("bad LOC record");
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ new = safe_malloc(sizeof(struct loc_record));
|
||||
+ new->next = daemon->loc;
|
||||
+ daemon->loc = new;
|
||||
+ new->class = C_IN;
|
||||
+ if (!comma || loc_aton(comma,new->loc)!=16)
|
||||
+ {
|
||||
+ option = '?';
|
||||
+ problem = _("bad LOC record");
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (comma)
|
||||
+ *comma = 0;
|
||||
+ new->name = safe_string_alloc(arg);
|
||||
+ break;
|
||||
+ }
|
||||
|
||||
case LOPT_PTR: /* --ptr-record */
|
||||
{
|
||||
diff -Nur dnsmasq-2.39-orig/src/rfc1035.c dnsmasq-2.39/src/rfc1035.c
|
||||
--- dnsmasq-2.39-orig/src/rfc1035.c 2007-04-20 12:54:26.000000000 +0200
|
||||
+++ dnsmasq-2.39/src/rfc1035.c 2007-05-20 18:22:46.000000000 +0200
|
||||
@@ -1112,6 +1112,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ if (qtype == T_LOC || qtype == T_ANY)
|
||||
+ {
|
||||
+ struct loc_record *t;
|
||||
+ for(t = daemon->loc; t ; t = t->next)
|
||||
+ {
|
||||
+ if (t->class == qclass && hostname_isequal(name, t->name))
|
||||
+ {
|
||||
+ ans = 1;
|
||||
+ if (!dryrun)
|
||||
+ {
|
||||
+ log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, 0, NULL, 0);
|
||||
+ if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
+ daemon->local_ttl, NULL,
|
||||
+ T_LOC, t->class, "t", 16, t->loc))
|
||||
+ anscount++;
|
||||
+
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (qclass == C_IN)
|
||||
{
|
||||
if (qtype == T_PTR || qtype == T_ANY)
|
||||
diff -Nur dnsmasq-2.39-orig/src/rfc1876.c dnsmasq-2.39/src/rfc1876.c
|
||||
--- dnsmasq-2.39-orig/src/rfc1876.c 1970-01-01 01:00:00.000000000 +0100
|
||||
+++ dnsmasq-2.39/src/rfc1876.c 2007-05-20 19:50:10.000000000 +0200
|
||||
@@ -0,0 +1,379 @@
|
||||
+/*
|
||||
+ * routines to convert between on-the-wire RR format and zone file
|
||||
+ * format. Does not contain conversion to/from decimal degrees;
|
||||
+ * divide or multiply by 60*60*1000 for that.
|
||||
+ */
|
||||
+
|
||||
+#include "dnsmasq.h"
|
||||
+
|
||||
+static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
|
||||
+ 1000000,10000000,100000000,1000000000};
|
||||
+
|
||||
+/* takes an XeY precision/size value, returns a string representation.*/
|
||||
+static const char *
|
||||
+precsize_ntoa(u_int8_t prec)
|
||||
+{
|
||||
+ static char retbuf[sizeof("90000000.00")];
|
||||
+ unsigned long val;
|
||||
+ int mantissa, exponent;
|
||||
+
|
||||
+ mantissa = (int)((prec >> 4) & 0x0f) % 10;
|
||||
+ exponent = (int)((prec >> 0) & 0x0f) % 10;
|
||||
+
|
||||
+ val = mantissa * poweroften[exponent];
|
||||
+
|
||||
+ (void) sprintf(retbuf,"%d.%.2d", val/100, val%100);
|
||||
+ return (retbuf);
|
||||
+}
|
||||
+
|
||||
+/* converts ascii size/precision X * 10**Y(cm) to 0xXY. moves pointer.*/
|
||||
+static u_int8_t
|
||||
+precsize_aton(char **strptr)
|
||||
+{
|
||||
+ unsigned int mval = 0, cmval = 0;
|
||||
+ u_int8_t retval = 0;
|
||||
+ register char *cp;
|
||||
+ register int exponent;
|
||||
+ register int mantissa;
|
||||
+
|
||||
+ cp = *strptr;
|
||||
+
|
||||
+ while (isdigit(*cp))
|
||||
+ mval = mval * 10 + (*cp++ - '0');
|
||||
+
|
||||
+ if (*cp == '.') { /* centimeters */
|
||||
+ cp++;
|
||||
+ if (isdigit(*cp)) {
|
||||
+ cmval = (*cp++ - '0') * 10;
|
||||
+ if (isdigit(*cp)) {
|
||||
+ cmval += (*cp++ - '0');
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ cmval = (mval * 100) + cmval;
|
||||
+
|
||||
+ for (exponent = 0; exponent < 9; exponent++)
|
||||
+ if (cmval < poweroften[exponent+1])
|
||||
+ break;
|
||||
+
|
||||
+ mantissa = cmval / poweroften[exponent];
|
||||
+ if (mantissa > 9)
|
||||
+ mantissa = 9;
|
||||
+
|
||||
+ retval = (mantissa << 4) | exponent;
|
||||
+
|
||||
+ *strptr = cp;
|
||||
+
|
||||
+ return (retval);
|
||||
+}
|
||||
+
|
||||
+/* converts ascii lat/lon to unsigned encoded 32-bit number.
|
||||
+ * moves pointer. */
|
||||
+static u_int32_t
|
||||
+latlon2ul(char **latlonstrptr,int *which)
|
||||
+{
|
||||
+ register char *cp;
|
||||
+ u_int32_t retval;
|
||||
+ int deg = 0, min = 0, secs = 0, secsfrac = 0;
|
||||
+
|
||||
+ cp = *latlonstrptr;
|
||||
+
|
||||
+ while (isdigit(*cp))
|
||||
+ deg = deg * 10 + (*cp++ - '0');
|
||||
+
|
||||
+ while (isspace(*cp))
|
||||
+ cp++;
|
||||
+
|
||||
+ if (!(isdigit(*cp)))
|
||||
+ goto fndhemi;
|
||||
+
|
||||
+ while (isdigit(*cp))
|
||||
+ min = min * 10 + (*cp++ - '0');
|
||||
+ while (isspace(*cp))
|
||||
+ cp++;
|
||||
+
|
||||
+ if (!(isdigit(*cp)))
|
||||
+ goto fndhemi;
|
||||
+
|
||||
+ while (isdigit(*cp))
|
||||
+ secs = secs * 10 + (*cp++ - '0');
|
||||
+
|
||||
+ if (*cp == '.') { /* decimal seconds */
|
||||
+ cp++;
|
||||
+ if (isdigit(*cp)) {
|
||||
+ secsfrac = (*cp++ - '0') * 100;
|
||||
+ if (isdigit(*cp)) {
|
||||
+ secsfrac += (*cp++ - '0') * 10;
|
||||
+ if (isdigit(*cp)) {
|
||||
+ secsfrac += (*cp++ - '0');
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ while (!isspace(*cp)) /* if any trailing garbage */
|
||||
+ cp++;
|
||||
+
|
||||
+ while (isspace(*cp))
|
||||
+ cp++;
|
||||
+
|
||||
+ fndhemi:
|
||||
+ switch (*cp) {
|
||||
+ case 'N': case 'n':
|
||||
+ case 'E': case 'e':
|
||||
+ retval = ((unsigned)1<<31)
|
||||
+ + (((((deg * 60) + min) * 60) + secs) * 1000)
|
||||
+ + secsfrac;
|
||||
+ break;
|
||||
+ case 'S': case 's':
|
||||
+ case 'W': case 'w':
|
||||
+ retval = ((unsigned)1<<31)
|
||||
+ - (((((deg * 60) + min) * 60) + secs) * 1000)
|
||||
+ - secsfrac;
|
||||
+ break;
|
||||
+ default:
|
||||
+ retval = 0; /* invalid value -- indicates error */
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ switch (*cp) {
|
||||
+ case 'N': case 'n':
|
||||
+ case 'S': case 's':
|
||||
+ *which = 1; /* latitude */
|
||||
+ break;
|
||||
+ case 'E': case 'e':
|
||||
+ case 'W': case 'w':
|
||||
+ *which = 2; /* longitude */
|
||||
+ break;
|
||||
+ default:
|
||||
+ *which = 0; /* error */
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ cp++; /* skip the hemisphere */
|
||||
+
|
||||
+ while (!isspace(*cp)) /* if any trailing garbage */
|
||||
+ cp++;
|
||||
+
|
||||
+ while (isspace(*cp)) /* move to next field */
|
||||
+ cp++;
|
||||
+
|
||||
+ *latlonstrptr = cp;
|
||||
+
|
||||
+ return (retval);
|
||||
+}
|
||||
+
|
||||
+/* converts a zone file representation in a string to an RDATA
|
||||
+ * on-the-wire representation. */
|
||||
+u_int32_t
|
||||
+loc_aton(const char *ascii, u_char *binary)
|
||||
+{
|
||||
+ const char *cp, *maxcp;
|
||||
+ u_char *bcp;
|
||||
+
|
||||
+ u_int32_t latit = 0, longit = 0, alt = 0;
|
||||
+ u_int32_t lltemp1 = 0, lltemp2 = 0;
|
||||
+ int altmeters = 0, altfrac = 0, altsign = 1;
|
||||
+ u_int8_t hp = 0x16; /* default = 1e6 cm = 10000.00m = 10km */
|
||||
+ u_int8_t vp = 0x13; /* default = 1e3 cm = 10.00m */
|
||||
+ u_int8_t siz = 0x12; /* default = 1e2 cm = 1.00m */
|
||||
+ int which1 = 0, which2 = 0;
|
||||
+
|
||||
+ cp = ascii;
|
||||
+ maxcp = cp + strlen(ascii);
|
||||
+
|
||||
+ lltemp1 = latlon2ul(&cp, &which1);
|
||||
+ lltemp2 = latlon2ul(&cp, &which2);
|
||||
+
|
||||
+ switch (which1 + which2) {
|
||||
+ case 3: /* 1 + 2, the only valid combination */
|
||||
+ if ((which1 == 1) && (which2 == 2)) { /* normal case */
|
||||
+ latit = lltemp1;
|
||||
+ longit = lltemp2;
|
||||
+ } else if ((which1 == 2) && (which2 == 1)) {/*reversed*/
|
||||
+ longit = lltemp1;
|
||||
+ latit = lltemp2;
|
||||
+ } else { /* some kind of brokenness */
|
||||
+ return 0;
|
||||
+ }
|
||||
+ break;
|
||||
+ default: /* we didn't get one of each */
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ /* altitude */
|
||||
+ if (*cp == '-') {
|
||||
+ altsign = -1;
|
||||
+ cp++;
|
||||
+ }
|
||||
+
|
||||
+ if (*cp == '+')
|
||||
+ cp++;
|
||||
+
|
||||
+ while (isdigit(*cp))
|
||||
+ altmeters = altmeters * 10 + (*cp++ - '0');
|
||||
+
|
||||
+ if (*cp == '.') { /* decimal meters */
|
||||
+ cp++;
|
||||
+ if (isdigit(*cp)) {
|
||||
+ altfrac = (*cp++ - '0') * 10;
|
||||
+ if (isdigit(*cp)) {
|
||||
+ altfrac += (*cp++ - '0');
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ alt = (10000000 + (altsign * (altmeters * 100 + altfrac)));
|
||||
+
|
||||
+ while (!isspace(*cp) && (cp < maxcp))
|
||||
+ /* if trailing garbage or m */
|
||||
+ cp++;
|
||||
+
|
||||
+ while (isspace(*cp) && (cp < maxcp))
|
||||
+ cp++;
|
||||
+ if (cp >= maxcp)
|
||||
+ goto defaults;
|
||||
+
|
||||
+ siz = precsize_aton(&cp);
|
||||
+
|
||||
+ while (!isspace(*cp) && (cp < maxcp))/*if trailing garbage or m*/
|
||||
+ cp++;
|
||||
+
|
||||
+ while (isspace(*cp) && (cp < maxcp))
|
||||
+ cp++;
|
||||
+
|
||||
+ if (cp >= maxcp)
|
||||
+ goto defaults;
|
||||
+
|
||||
+ hp = precsize_aton(&cp);
|
||||
+
|
||||
+ while (!isspace(*cp) && (cp < maxcp))/*if trailing garbage or m*/
|
||||
+ cp++;
|
||||
+
|
||||
+ while (isspace(*cp) && (cp < maxcp))
|
||||
+ cp++;
|
||||
+
|
||||
+ if (cp >= maxcp)
|
||||
+ goto defaults;
|
||||
+
|
||||
+ vp = precsize_aton(&cp);
|
||||
+
|
||||
+ defaults:
|
||||
+
|
||||
+ bcp = binary;
|
||||
+ *bcp++ = (u_int8_t) 0; /* version byte */
|
||||
+ *bcp++ = siz;
|
||||
+ *bcp++ = hp;
|
||||
+ *bcp++ = vp;
|
||||
+ PUTLONG(latit,bcp);
|
||||
+ PUTLONG(longit,bcp);
|
||||
+ PUTLONG(alt,bcp);
|
||||
+
|
||||
+ return (16); /* size of RR in octets */
|
||||
+}
|
||||
+
|
||||
+/* takes an on-the-wire LOC RR and prints it in zone file
|
||||
+ * (human readable) format. */
|
||||
+char *
|
||||
+loc_ntoa(const u_char *binary,char *ascii)
|
||||
+{
|
||||
+ static char tmpbuf[255*3];
|
||||
+
|
||||
+ register char *cp;
|
||||
+ register const u_char *rcp;
|
||||
+
|
||||
+ int latdeg, latmin, latsec, latsecfrac;
|
||||
+ int longdeg, longmin, longsec, longsecfrac;
|
||||
+ char northsouth, eastwest;
|
||||
+ int altmeters, altfrac, altsign;
|
||||
+
|
||||
+ const int referencealt = 100000 * 100;
|
||||
+
|
||||
+ int32_t latval, longval, altval;
|
||||
+ u_int32_t templ;
|
||||
+ u_int8_t sizeval, hpval, vpval, versionval;
|
||||
+
|
||||
+ char *sizestr, *hpstr, *vpstr;
|
||||
+
|
||||
+ rcp = binary;
|
||||
+ if (ascii)
|
||||
+ cp = ascii;
|
||||
+ else {
|
||||
+ cp = tmpbuf;
|
||||
+ }
|
||||
+
|
||||
+ versionval = *rcp++;
|
||||
+
|
||||
+ if (versionval) {
|
||||
+ sprintf(cp,"; error: unknown LOC RR version");
|
||||
+ return (cp);
|
||||
+ }
|
||||
+
|
||||
+ sizeval = *rcp++;
|
||||
+
|
||||
+ hpval = *rcp++;
|
||||
+ vpval = *rcp++;
|
||||
+
|
||||
+ GETLONG(templ,rcp);
|
||||
+ latval = (templ - ((unsigned)1<<31));
|
||||
+
|
||||
+ GETLONG(templ,rcp);
|
||||
+ longval = (templ - ((unsigned)1<<31));
|
||||
+
|
||||
+ GETLONG(templ,rcp);
|
||||
+ if (templ < referencealt) { /* below WGS 84 spheroid */
|
||||
+ altval = referencealt - templ;
|
||||
+ altsign = -1;
|
||||
+ } else {
|
||||
+ altval = templ - referencealt;
|
||||
+ altsign = 1;
|
||||
+ }
|
||||
+
|
||||
+ if (latval < 0) {
|
||||
+ northsouth = 'S';
|
||||
+ latval = -latval;
|
||||
+ }
|
||||
+ else
|
||||
+ northsouth = 'N';
|
||||
+
|
||||
+ latsecfrac = latval % 1000;
|
||||
+ latval = latval / 1000;
|
||||
+ latsec = latval % 60;
|
||||
+ latval = latval / 60;
|
||||
+ latmin = latval % 60;
|
||||
+ latval = latval / 60;
|
||||
+ latdeg = latval;
|
||||
+
|
||||
+ if (longval < 0) {
|
||||
+ eastwest = 'W';
|
||||
+ longval = -longval;
|
||||
+ }
|
||||
+ else
|
||||
+ eastwest = 'E';
|
||||
+
|
||||
+ longsecfrac = longval % 1000;
|
||||
+ longval = longval / 1000;
|
||||
+ longsec = longval % 60;
|
||||
+ longval = longval / 60;
|
||||
+ longmin = longval % 60;
|
||||
+ longval = longval / 60;
|
||||
+ longdeg = longval;
|
||||
+
|
||||
+ altfrac = altval % 100;
|
||||
+ altmeters = (altval / 100) * altsign;
|
||||
+
|
||||
+ sizestr = strdup(precsize_ntoa(sizeval));
|
||||
+ hpstr = strdup(precsize_ntoa(hpval));
|
||||
+ vpstr = strdup(precsize_ntoa(vpval));
|
||||
+
|
||||
+ sprintf(cp,
|
||||
+ "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %d.%.2dm %sm %sm %sm",
|
||||
+ latdeg, latmin, latsec, latsecfrac, northsouth,
|
||||
+ longdeg, longmin, longsec, longsecfrac, eastwest,
|
||||
+ altmeters, altfrac, sizestr, hpstr, vpstr);
|
||||
+ free(sizestr);
|
||||
+ free(hpstr);
|
||||
+ free(vpstr);
|
||||
+
|
||||
+ return (cp);
|
||||
+}
|
||||
@@ -23,6 +23,6 @@
|
||||
# will port forward port 53 UDP and TCP from this host to port 53 on dnsserver.
|
||||
#
|
||||
# Port forwards will recreated when dnsmasq restarts after a reboot, and
|
||||
# removed when DHCP leases expire. After editing this file, restart dnsmasq
|
||||
# to install new iptables entries in the kernel.
|
||||
# removed when DHCP leases expire. After editing this file, send
|
||||
# SIGHUP to dnsmasq to install new iptables entries in the kernel.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
CFLAGS?= -O2
|
||||
CFLAGS?= -O2 -Wall -W
|
||||
|
||||
all: dhcp_release.c
|
||||
$(CC) $(CFLAGS) $(RPM_OPT_FLAGS) -Wall -W dhcp_release.c -o dhcp_release
|
||||
all: dhcp_release dhcp_lease_time
|
||||
|
||||
clean:
|
||||
rm -f *~ *.o core dhcp_release
|
||||
rm -f *~ *.o core dhcp_release dhcp_lease_time
|
||||
@@ -0,0 +1,214 @@
|
||||
/* Copyright (c) 2007 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.
|
||||
*/
|
||||
|
||||
/* dhcp_lease_time <address> */
|
||||
|
||||
/* Send a DHCPINFORM message to a dnsmasq server running on the local host
|
||||
and print (to stdout) the time remaining in any lease for the given
|
||||
address. The time is given as string printed to stdout.
|
||||
|
||||
If an error occurs or no lease exists for the given address,
|
||||
nothing is sent to stdout a message is sent to stderr and a
|
||||
non-zero error code is returned.
|
||||
|
||||
Requires dnsmasq 2.40 or later.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define DHCP_CHADDR_MAX 16
|
||||
#define BOOTREQUEST 1
|
||||
#define DHCP_COOKIE 0x63825363
|
||||
#define OPTION_PAD 0
|
||||
#define OPTION_LEASE_TIME 51
|
||||
#define OPTION_OVERLOAD 52
|
||||
#define OPTION_MESSAGE_TYPE 53
|
||||
#define OPTION_END 255
|
||||
#define DHCPINFORM 8
|
||||
#define DHCP_SERVER_PORT 67
|
||||
|
||||
#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
|
||||
#define option_ptr(opt) ((void *)&(((unsigned char *)(opt))[2]))
|
||||
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
struct dhcp_packet {
|
||||
u8 op, htype, hlen, hops;
|
||||
u32 xid;
|
||||
u16 secs, flags;
|
||||
struct in_addr ciaddr, yiaddr, siaddr, giaddr;
|
||||
u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
|
||||
u32 cookie;
|
||||
unsigned char options[308];
|
||||
};
|
||||
|
||||
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize)
|
||||
{
|
||||
while (*p != OPTION_END)
|
||||
{
|
||||
if (p >= end)
|
||||
return NULL; /* malformed packet */
|
||||
else if (*p == OPTION_PAD)
|
||||
p++;
|
||||
else
|
||||
{
|
||||
int opt_len;
|
||||
if (p >= end - 2)
|
||||
return NULL; /* malformed packet */
|
||||
opt_len = option_len(p);
|
||||
if (p >= end - (2 + opt_len))
|
||||
return NULL; /* malformed packet */
|
||||
if (*p == opt && opt_len >= minsize)
|
||||
return p;
|
||||
p += opt_len + 2;
|
||||
}
|
||||
}
|
||||
|
||||
return opt == OPTION_END ? p : NULL;
|
||||
}
|
||||
|
||||
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize)
|
||||
{
|
||||
unsigned char *ret, *overload;
|
||||
|
||||
/* skip over DHCP cookie; */
|
||||
if ((ret = option_find1(&mess->options[0], ((unsigned char *)mess) + size, opt_type, minsize)))
|
||||
return ret;
|
||||
|
||||
/* look for overload option. */
|
||||
if (!(overload = option_find1(&mess->options[0], ((unsigned char *)mess) + size, OPTION_OVERLOAD, 1)))
|
||||
return NULL;
|
||||
|
||||
/* Can we look in filename area ? */
|
||||
if ((overload[2] & 1) &&
|
||||
(ret = option_find1(&mess->file[0], &mess->file[128], opt_type, minsize)))
|
||||
return ret;
|
||||
|
||||
/* finally try sname area */
|
||||
if ((overload[2] & 2) &&
|
||||
(ret = option_find1(&mess->sname[0], &mess->sname[64], opt_type, minsize)))
|
||||
return ret;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned int option_uint(unsigned char *opt, int size)
|
||||
{
|
||||
/* this worries about unaligned data and byte order */
|
||||
unsigned int ret = 0;
|
||||
int i;
|
||||
unsigned char *p = option_ptr(opt);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
ret = (ret << 8) | *p++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct in_addr lease;
|
||||
struct dhcp_packet packet;
|
||||
unsigned char *p = packet.options;
|
||||
struct sockaddr_in dest;
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
ssize_t rc;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf(stderr, "usage: dhcp_lease_time <address>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
perror("cannot create socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
lease.s_addr = inet_addr(argv[1]);
|
||||
|
||||
memset(&packet, 0, sizeof(packet));
|
||||
|
||||
packet.hlen = 0;
|
||||
packet.htype = 0;
|
||||
|
||||
packet.op = BOOTREQUEST;
|
||||
packet.ciaddr = lease;
|
||||
packet.cookie = htonl(DHCP_COOKIE);
|
||||
|
||||
*(p++) = OPTION_MESSAGE_TYPE;
|
||||
*(p++) = 1;
|
||||
*(p++) = DHCPINFORM;
|
||||
|
||||
*(p++) = OPTION_END;
|
||||
|
||||
dest.sin_family = AF_INET;
|
||||
dest.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
dest.sin_port = ntohs(DHCP_SERVER_PORT);
|
||||
|
||||
if (sendto(fd, &packet, sizeof(packet), 0,
|
||||
(struct sockaddr *)&dest, sizeof(dest)) == -1)
|
||||
{
|
||||
perror("sendto failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
alarm(3); /* noddy timeout. */
|
||||
|
||||
rc = recv(fd, &packet, sizeof(packet), 0);
|
||||
|
||||
if (rc < (ssize_t)(sizeof(packet) - sizeof(packet.options)))
|
||||
{
|
||||
perror("recv failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((p = option_find(&packet, (size_t)rc, OPTION_LEASE_TIME, 4)))
|
||||
{
|
||||
unsigned int t = option_uint(p, 4);
|
||||
if (t == 0xffffffff)
|
||||
printf("infinite");
|
||||
else
|
||||
{
|
||||
unsigned int x;
|
||||
if ((x = t/86400))
|
||||
printf("%dd", x);
|
||||
if ((x = (t/3600)%24))
|
||||
printf("%dh", x);
|
||||
if ((x = (t/60)%60))
|
||||
printf("%dm", x);
|
||||
if ((x = t%60))
|
||||
printf("%ds", x);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1; /* no lease */
|
||||
}
|
||||
+53
-16
@@ -48,6 +48,10 @@
|
||||
# non-public domains.
|
||||
#server=/localnet/192.168.0.1
|
||||
|
||||
# Example of routing PTR queries to nameservers: this will send all
|
||||
# address->name queries for 192.168.3/24 to nameserver 10.1.2.3
|
||||
#server=/3.168.192.in-addr.arpa/10.1.2.3
|
||||
|
||||
# Add local-only domains here, queries in these domains are answered
|
||||
# from /etc/hosts or DHCP only.
|
||||
#local=/localnet/
|
||||
@@ -176,6 +180,12 @@
|
||||
# any machine with ethernet address starting 11:22:33:
|
||||
#dhcp-host=11:22:33:*:*:*,net:red
|
||||
|
||||
# Ignore any clients which are specified in dhcp-host lines
|
||||
# or /etc/ethers. Equivalent to ISC "deny unkown-clients".
|
||||
# This relies on the special "known" tag which is set when
|
||||
# a host is matched.
|
||||
#dhcp-ignore=#known
|
||||
|
||||
# Send extra options which are tagged as "red" to any machine whose
|
||||
# DHCP vendorclass string includes the substring "Linux"
|
||||
#dhcp-vendorclass=red,Linux
|
||||
@@ -196,23 +206,22 @@
|
||||
|
||||
# Send options to hosts which ask for a DHCP lease.
|
||||
# See RFC 2132 for details of available options.
|
||||
# Common options can be given to dnsmasq by name:
|
||||
# run "dnsmasq --help dhcp" to get a list.
|
||||
# Note that all the common settings, such as netmask and
|
||||
# broadcast address, DNS server and default route, are given
|
||||
# sane defaults by dnsmasq. You very likely will not need any
|
||||
# sane defaults by dnsmasq. You very likely will not need
|
||||
# any dhcp-options. If you use Windows clients and Samba, there
|
||||
# are some options which are recommended, they are detailed at the
|
||||
# end of this section.
|
||||
# For reference, the common options are:
|
||||
# subnet mask - 1
|
||||
# default router - 3
|
||||
# DNS server - 6
|
||||
# hostname - 12
|
||||
# broadcast address - 28
|
||||
|
||||
# Override the default route supplied by dnsmasq, which assumes the
|
||||
# router is the same machine as the one running dnsmasq.
|
||||
#dhcp-option=3,1.2.3.4
|
||||
|
||||
# Do the same thing, but using the option name
|
||||
#dhcp-option=option:router,1.2.3.4
|
||||
|
||||
# Override the default route supplied by dnsmasq and send no default
|
||||
# route at all. Note that this only works for the options sent by
|
||||
# default (1, 3, 6, 12, 28) the same line will send a zero-length option
|
||||
@@ -220,7 +229,7 @@
|
||||
#dhcp-option=3
|
||||
|
||||
# Set the NTP time server addresses to 192.168.0.4 and 10.10.0.5
|
||||
#dhcp-option=42,192.168.0.4,10.10.0.5
|
||||
#dhcp-option=option:ntp-server,192.168.0.4,10.10.0.5
|
||||
|
||||
# Set the NTP time server address to be the same machine as
|
||||
# is running dnsmasq
|
||||
@@ -241,7 +250,8 @@
|
||||
|
||||
# Specify an option which will only be sent to the "red" network
|
||||
# (see dhcp-range for the declaration of the "red" network)
|
||||
#dhcp-option=red,42,192.168.1.1
|
||||
# Note that the net: part must precede the option: part.
|
||||
#dhcp-option = net:red, option:ntp-server, 192.168.1.1
|
||||
|
||||
# The following DHCP options set up dnsmasq in the same way as is specified
|
||||
# for the ISC dhcpcd in
|
||||
@@ -257,18 +267,42 @@
|
||||
|
||||
# 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
|
||||
#dhcp-option=option:domain-search,eng.apple.com,marketing.apple.com
|
||||
|
||||
# Send RFC-3442 classless static routes (note the netmask encoding)
|
||||
#dhcp-option=121,192.168.1.0/24,1.2.3.4,10.0.0.0/8,5.6.7.8
|
||||
|
||||
# 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
|
||||
# Send vendor-class specific options encapsulated in DHCP option 43.
|
||||
# The meaning of the options is defined by the vendor-class so
|
||||
# options are sent only when the client supplied vendor class
|
||||
# matches the class given here. (A substring match is OK, so "MSFT"
|
||||
# matches "MSFT" and "MSFT 5.0"). This example sets the
|
||||
# mtftp address to 0.0.0.0 for PXEClients.
|
||||
#dhcp-option=vendor:PXEClient,1,0.0.0.0
|
||||
|
||||
# Send microsoft-specific option to tell windows to release the DHCP lease
|
||||
# when it shuts down. Note the "i" flag, to tell dnsmasq to send the
|
||||
# value as a four-byte integer - that's what microsoft wants. See
|
||||
# http://technet2.microsoft.com/WindowsServer/en/library/a70f1bb7-d2d4-49f0-96d6-4b7414ecfaae1033.mspx?mfr=true
|
||||
#dhcp-option=vendor:MSFT,2,1i
|
||||
|
||||
# Send the Encapsulated-vendor-class ID needed by some configurations of
|
||||
# Etherboot to allow is to recognise the DHCP server.
|
||||
#dhcp-option=vendor:Etherboot,60,"Etherboot"
|
||||
|
||||
# Send options to PXELinux. Note that we need to send the options even
|
||||
# though they don't appear in the parameter request list, so we need
|
||||
# to use dhcp-option-force here.
|
||||
# See http://syslinux.zytor.com/pxe.php#special for details.
|
||||
# Magic number - needed before anything else is recognised
|
||||
#dhcp-option-force=208,f1:00:74:7e
|
||||
# Configuration file name
|
||||
#dhcp-option-force=209,configs/common
|
||||
# Path prefix
|
||||
#dhcp-option-force=210,/tftpboot/pxelinux/files/
|
||||
# Reboot time. (Note 'i' to send 32-bit value)
|
||||
#dhcp-option-force=211,30i
|
||||
|
||||
# Set the boot filename for BOOTP. You will only need
|
||||
# this is you want to boot machines over the network and you will need
|
||||
# a TFTP server; either dnsmasq's built in TFTP server or an
|
||||
@@ -305,7 +339,7 @@
|
||||
# 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
|
||||
# server for your campus/company accidentally. The ISC server uses
|
||||
# the same option, and this URL provides more information:
|
||||
# http://www.isc.org/index.pl?/sw/dhcp/authoritative.php
|
||||
#dhcp-authoritative
|
||||
@@ -410,6 +444,9 @@
|
||||
# dnsmasq.
|
||||
#log-queries
|
||||
|
||||
# Log lots of extra information about DHCP transactions.
|
||||
#log-dhcp
|
||||
|
||||
# Include a another lot of configuration options.
|
||||
#conf-file=/etc/dnsmasq.more.conf
|
||||
#conf-dir=/etc/dnsmasq.d
|
||||
@@ -15,7 +15,8 @@ Dnsmasq is a lightweight, easy to configure DNS forwarder and DHCP
|
||||
<P>
|
||||
Dnsmasq is targeted at home networks using NAT and
|
||||
connected to the internet via a modem, cable-modem or ADSL
|
||||
connection but would be a good choice for any small network where low
|
||||
connection but would be a good choice for any smallish network (up to
|
||||
1000 clients is known to work) where low
|
||||
resource use and ease of configuration are important.
|
||||
<P>
|
||||
Supported platforms include Linux (with glibc and uclibc), *BSD and
|
||||
|
||||
+236
-42
@@ -6,8 +6,8 @@ dnsmasq \- A lightweight DHCP and caching DNS server.
|
||||
.I [OPTION]...
|
||||
.SH "DESCRIPTION"
|
||||
.BR dnsmasq
|
||||
is a lightweight DNS and DHCP server. It is intended to provide coupled DNS and DHCP service to a
|
||||
LAN.
|
||||
is a lightweight DNS, TFTP and DHCP server. It is intended to provide
|
||||
coupled DNS and DHCP service to a LAN.
|
||||
.PP
|
||||
Dnsmasq accepts DNS queries and either answers them from a small, local,
|
||||
cache or forwards them to a real, recursive, DNS server. It loads the
|
||||
@@ -18,10 +18,12 @@ DNS queries for DHCP configured hosts.
|
||||
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.
|
||||
send any desired set of DHCP options, including vendor-encapsulated
|
||||
options. It includes a secure, read-only,
|
||||
TFTP server to allow net/PXE boot of DHCP hosts and also supports BOOTP.
|
||||
.PP
|
||||
Dnsmasq
|
||||
supports IPv6.
|
||||
supports IPv6 for DNS, but not DHCP.
|
||||
.SH OPTIONS
|
||||
Note that in general missing parameters are allowed and switch off
|
||||
functions, for instance "--pid-file" disables writing a PID file. On
|
||||
@@ -66,7 +68,25 @@ Log the results of DNS queries handled by dnsmasq. Enable a full cache dump on r
|
||||
.TP
|
||||
.B \-8, --log-facility=<facility>
|
||||
Set the facility to which dnsmasq will send syslog entries, this
|
||||
defaults to DAEMON, and to LOCAL0 when debug mode is in operation.
|
||||
defaults to DAEMON, and to LOCAL0 when debug mode is in operation. If
|
||||
the facilty given contains at least one '/' character, it is taken to
|
||||
be a filename, and dnsmasq logs to the given file, instead of
|
||||
syslog. (Errors whilst reading configuration will still go to syslog,
|
||||
but all output from a successful startup, and all output whilst
|
||||
running, will go exclusively to the file.) When logging to a file,
|
||||
dnsmasq will close and reopen the file when it receives SIGUSR2. This
|
||||
allows the log file to be rotated without stopping dnsmasq.
|
||||
.TP
|
||||
.B --log-async[=<lines>]
|
||||
Enable asynchronous logging and optionally set the limit on the
|
||||
number of lines
|
||||
which will be queued by dnsmasq when writing to the syslog is slow.
|
||||
Dnsmasq can log asynchronously: this
|
||||
allows it to continue functioning without being blocked by syslog, and
|
||||
allows syslog to use dnsmasq for DNS queries without risking deadlock.
|
||||
If the queue of log-lines becomes full, dnsmasq will log the
|
||||
overflow, and the number of messages lost. The default queue length is
|
||||
5, a sane value would be 5-25, and a maximum limit of 100 is imposed.
|
||||
.TP
|
||||
.B \-x, --pid-file=<path>
|
||||
Specify an alternate path for dnsmasq to record its process-id in. Normally /var/run/dnsmasq.pid.
|
||||
@@ -233,8 +253,8 @@ Tells dnsmasq to never forward queries for plain names, without dots
|
||||
or domain parts, to upstream nameservers. If the name is not known
|
||||
from /etc/hosts or DHCP then a "not found" answer is returned.
|
||||
.TP
|
||||
.B \-S, ,--local, --server=[/[<domain>]/[domain/]][<ipaddr>[#<port>][@<source>[#<port>]]]
|
||||
Specify IP address of upstream severs directly. Setting this flag does
|
||||
.B \-S, --local, --server=[/[<domain>]/[domain/]][<ipaddr>[#<port>][@<source>[#<port>]]]
|
||||
Specify IP address of upstream servers directly. Setting this flag does
|
||||
not suppress reading of /etc/resolv.conf, use -R to do that. If one or
|
||||
more
|
||||
optional domains are given, that server is used only for those domains
|
||||
@@ -329,14 +349,24 @@ so any number may be included, split by commas.
|
||||
.B --ptr-record=<name>[,<target>]
|
||||
Return a PTR DNS record.
|
||||
.TP
|
||||
.B --interface-name=<name>,<interface>
|
||||
Return a DNS record associating the name with the primary address on
|
||||
the given interface. This flag specifies an A record for the given
|
||||
name in the same way as an /etc/hosts line, except that the address is
|
||||
not constant, but taken from the given interface. If the interface is
|
||||
down, not configured or non-existant, an empty record is returned. The
|
||||
matching PTR record is also created, mapping the interface address to
|
||||
the name. More than one name may be associated with an interface
|
||||
address by repeating the flag; in that case the first instance is used
|
||||
for the reverse address-to-name mapping.
|
||||
.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
|
||||
.B \-N, --no-negcache
|
||||
Disable negative caching. Negative caching allows dnsmasq to remember
|
||||
"no such domain" answers from upstream nameservers and answer
|
||||
identical queries without forwarding them again. This flag disables
|
||||
negative caching.
|
||||
identical queries without forwarding them again.
|
||||
.TP
|
||||
.B \-0, --dns-forward-max=<queries>
|
||||
Set the maximum number of concurrent DNS queries. The default value is
|
||||
@@ -412,9 +442,12 @@ instance
|
||||
This is
|
||||
useful when there is another DHCP server on the network which should
|
||||
be used by some machines. The net:<network-id> sets the network-id tag
|
||||
whenever this dhcp-host directive is in use.
|
||||
This can be used to selectively send DHCP options just
|
||||
for this host.
|
||||
whenever this dhcp-host directive is in use.This can be used to
|
||||
selectively send DHCP options just for this host. When a host matches any
|
||||
dhcp-host directive (or one implied by /etc/ethers) then the special
|
||||
network-id tag "known" is set. This allows dnsmasq to be configured to
|
||||
ignore requests from unknown machines using
|
||||
.B --dhcp-ignore=#known
|
||||
Ethernet addresses (but not client-ids) may have
|
||||
wildcard bytes, so for example
|
||||
.B --dhcp-host=00:20:e0:3b:13:*,ignore
|
||||
@@ -427,6 +460,13 @@ ARP type by preceding them with the ARP-type (in HEX) and "-". so
|
||||
will only match a
|
||||
Token-Ring hardware address, since the ARP-address type for token ring
|
||||
is 6.
|
||||
.TP
|
||||
.B --dhcp-hostsfile=<file>
|
||||
Read DHCP host information from the specified file. The file contains
|
||||
information about one host per line. The format of a line is the same
|
||||
as text to the right of '=' in --dhcp-host. The advantage of storing DHCP host information
|
||||
in this file is that it can be changed without re-starting dnsmasq:
|
||||
the file will be re-read when dnsmasq receives SIGHUP.
|
||||
.TP
|
||||
.B \-Z, --read-ethers
|
||||
Read /etc/ethers for information about hosts for the DHCP server. The
|
||||
@@ -434,21 +474,29 @@ format of /etc/ethers is a hardware address, followed by either a
|
||||
hostname or dotted-quad IP address. When read by dnsmasq these lines
|
||||
have exactly the same effect as
|
||||
.B --dhcp-host
|
||||
options containing the same information.
|
||||
options containing the same information. /etc/ethers is re-read when
|
||||
dnsmasq receives SIGHUP.
|
||||
.TP
|
||||
.B \-O, --dhcp-option=[<network-id>,[<network-id>,]][vendor:<vendor-class>]<opt>,[<value>[,<value>]]
|
||||
.B \-O, --dhcp-option=[<network-id>,[<network-id>,]][vendor:[<vendor-class>],][<opt>|option:<opt-name>],[<value>[,<value>]]
|
||||
Specify 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
|
||||
the DNS server and default route are set to the address of the machine
|
||||
running dnsmasq. If the domain name option has been set, that is sent.
|
||||
This option allows these defaults to be overridden,
|
||||
or other options specified. The <opt> is the number of the option, as
|
||||
specified in RFC2132. For example, to set the default route option to
|
||||
This configuration allows these defaults to be overridden,
|
||||
or other options specified. The option, to be sent may be given as a
|
||||
decimal number or as "option:<option-name>" The option numbers are
|
||||
specified in RFC2132 and subsequent RFCs. The set of option-names
|
||||
known by dnsmasq can be discovered by running "dnsmasq --help dhcp".
|
||||
For example, to set the default route option to
|
||||
192.168.4.4, do
|
||||
.B --dhcp-option=3,192.168.4.4
|
||||
.B --dhcp-option=3,192.168.4.4
|
||||
or
|
||||
.B --dhcp-option = option:router, 192.168.4.4
|
||||
and to set the time-server address to 192.168.0.4, do
|
||||
.B --dhcp-option=42,192.168.0.4
|
||||
.B --dhcp-option = 42,192.168.0.4
|
||||
or
|
||||
.B --dhcp-option = option:ntp-server, 192.168.0.4
|
||||
The special address 0.0.0.0 is taken to mean "the address of the
|
||||
machine running dnsmasq". Data types allowed are comma separated
|
||||
dotted-quad IP addresses, a decimal number, colon-separated hex digits
|
||||
@@ -478,16 +526,31 @@ a literal IP address as TFTP server name, it is necessary to do
|
||||
|
||||
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
|
||||
.B --dhcp-option=vendor:PXEClient,1,0.0.0.0
|
||||
sends the encapsulated vendor
|
||||
class-specific option "mftp-address=0.0.0.0" to any client whose
|
||||
vendor-class matches "PXEClient". The vendor-class matching is
|
||||
substring based (see --dhcp-vendorclass for details). If a
|
||||
vendor-class option (number 60) is sent by dnsmasq, then that is used
|
||||
for selecting encapsulated options in preference to any sent by the
|
||||
client. It is
|
||||
possible to omit the vendorclass completely;
|
||||
.B --dhcp-option=vendor:,1,0.0.0.0
|
||||
in which case the encapsulated option is always sent.
|
||||
The address 0.0.0.0 is not treated specially in
|
||||
encapsulated vendor class options.
|
||||
.TP
|
||||
.B --dhcp-option-force=[<network-id>,[<network-id>,]][vendor:[<vendor-class>],]<opt>,[<value>[,<value>]]
|
||||
This works in exactly the same way as
|
||||
.B --dhcp-option
|
||||
except that the option will always be sent, even if the client does
|
||||
not ask for it in the parameter request list. This is sometimes
|
||||
needed, for example when sending options to PXELinux.
|
||||
.TP
|
||||
.B \-U, --dhcp-vendorclass=<network-id>,<vendor-class>
|
||||
Map from a vendor-class string to a network id. Most DHCP clients provide a
|
||||
Map from a vendor-class string to a network id tag. Most DHCP clients provide a
|
||||
"vendor class" which represents, in some sense, the type of host. This option
|
||||
maps vendor classes to network ids, so that DHCP options may be selectively delivered
|
||||
maps vendor classes to tags, so that DHCP options may be selectively delivered
|
||||
to different classes of hosts. For example
|
||||
.B dhcp-vendorclass=printers,Hewlett-Packard JetDirect
|
||||
will allow options to be set only for HP printers like so:
|
||||
@@ -497,26 +560,36 @@ substring matched against the vendor-class supplied by the client, to
|
||||
allow fuzzy matching.
|
||||
.TP
|
||||
.B \-j, --dhcp-userclass=<network-id>,<user-class>
|
||||
Map from a user-class string to a network id (with substring
|
||||
Map from a user-class string to a network id tag (with substring
|
||||
matching, like vendor classes). Most DHCP clients provide a
|
||||
"user class" which is configurable. This option
|
||||
maps user classes to network ids, so that DHCP options may be selectively delivered
|
||||
maps user classes to tags, so that DHCP options may be selectively delivered
|
||||
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 \-4, --dhcp-mac=<network-id>,<MAC address>
|
||||
Map from a MAC address to a network-id. The MAC address may include
|
||||
Map from a MAC address to a network-id tag. The MAC address may include
|
||||
wildcards. For example
|
||||
.B --dhcp-mac=3com,01:34:23:*:*:*
|
||||
will set the tag "3com" for any host whose MAC address matches the pattern.
|
||||
.TP
|
||||
.B --dhcp-circuitid=<network-id>,<circuit-id>, --dhcp-remoteid=<network-id>,<remote-id>
|
||||
Map from RFC3046 relay agent options to network-id tags. This data may
|
||||
be provided by DHCP relay agents. The circuit-id or remote-id is
|
||||
normally given as colon-separated hex, but is also allowed to be a
|
||||
simple string. If an exact match is achieved between the circuit or
|
||||
agent ID and one provided by a relay agent, the network-id tag is set.
|
||||
.TP
|
||||
.B --dhcp-subscrid=<network-id>,<subscriber-id>
|
||||
Map from RFC3993 subscriber-d relay agent options to network-id tags.
|
||||
.TP
|
||||
.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 --dhcp-ignore-name[=<network-id>[,<network-id>]]
|
||||
.B --dhcp-ignore-names[=<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 any hostname
|
||||
provided by the host. Note that, unlike dhcp-ignore, it is permissable
|
||||
@@ -543,7 +616,7 @@ create thousands of leases and use lots of memory in the dnsmasq
|
||||
process.
|
||||
.TP
|
||||
.B \-K, --dhcp-authoritative
|
||||
Should be set when dnsmasq is definately the only DHCP server on a network.
|
||||
Should be set when dnsmasq is definitely the only DHCP server on a network.
|
||||
It changes the behaviour from strict RFC compliance so that DHCP requests on
|
||||
unknown leases from unknown hosts are not ignored. This allows new hosts
|
||||
to get a lease without a tedious timeout under all circumstances. It also
|
||||
@@ -563,6 +636,10 @@ ICMP echo request (aka "ping") to the address in question. If it gets
|
||||
a reply, then the address must already be in use, and another is
|
||||
tried. This flag disables this check. Use with caution.
|
||||
.TP
|
||||
.B --log-dhcp
|
||||
Extra logging for DHCP: log all the options sent to DHCP clients and
|
||||
the netid tags used to determine them.
|
||||
.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
|
||||
@@ -589,13 +666,15 @@ The environment is inherited from the invoker of dnsmasq, and if the
|
||||
host provided a client-id, this is stored in the environment variable
|
||||
DNSMASQ_CLIENT_ID. If the client provides vendor-class or user-class
|
||||
information, these are provided in DNSMASQ_VENDOR_CLASS and
|
||||
DNSMASQ_USER_CLASS0..DNSMASQ_USER_CLASSn variables, but only fory
|
||||
DNSMASQ_USER_CLASS0..DNSMASQ_USER_CLASSn variables, but only for
|
||||
"add" actions or "old" actions when a host resumes an existing lease,
|
||||
since these data are not held in dnsmasq's lease
|
||||
database. If dnsmasq was compiled with HAVE_BROKEN_RTC, then
|
||||
the length of the lease (in seconds) is stored in
|
||||
DNSMASQ_LEASE_LENGTH, otherwise the time of lease expiry is stored in
|
||||
DNSMASQ_LEASE_EXPIRES. If a lease used to have a hostname, which is
|
||||
DNSMASQ_LEASE_EXPIRES. The number of seconds until lease expiry is
|
||||
always stored in DNSMASQ_TIME_REMAINING.
|
||||
If a lease used to have a hostname, which is
|
||||
removed, an "old" event is generated with the new state of the lease,
|
||||
ie no name, and the former name is provided in the environment
|
||||
variable DNSMASQ_OLD_HOSTNAME.
|
||||
@@ -604,17 +683,19 @@ closed except stdin, stdout and stderr which are open to /dev/null
|
||||
(except in debug mode).
|
||||
The script is not invoked concurrently: if subsequent lease
|
||||
changes occur, the script is not invoked again until any existing
|
||||
invokation exits. At dnsmasq startup, the script will be invoked for
|
||||
invocation exits. At dnsmasq startup, the script will be invoked for
|
||||
all existing leases as they are read from the lease file. Expired
|
||||
leases will be called with "del" and others with "old". <path>
|
||||
must be an absolute pathname, no PATH search occurs.
|
||||
must be an absolute pathname, no PATH search occurs. When dnsmasq
|
||||
receives a HUP signal, the script will be invoked for existing leases
|
||||
with an "old " event.
|
||||
.TP
|
||||
.B \-9, --leasefile-ro
|
||||
Completely suppress use of the lease database file. The file will not
|
||||
be created, read, or written. Change the way the lease-change
|
||||
script (if one is provided) is called, so that the lease database may
|
||||
be maintained in external storage by the script. In addition to the
|
||||
invokations given in
|
||||
invocations given in
|
||||
.B --dhcp-script
|
||||
the lease-change script is called once, at dnsmasq startup, with the
|
||||
single argument "init". When called like this the script should write
|
||||
@@ -633,7 +714,15 @@ packets arrive at tap interfaces which don't have an IP address.
|
||||
Specifies the domain for the DHCP server. This has two effects;
|
||||
firstly it causes the DHCP server to return the domain to any hosts
|
||||
which request it, and secondly it sets the domain which it is legal
|
||||
for DHCP-configured hosts to claim. The intention is to constrain hostnames so that an untrusted host on the LAN cannot advertise it's name via dhcp as e.g. "microsoft.com" and capture traffic not meant for it. If no domain suffix is specified, then any DHCP hostname with a domain part (ie with a period) will be disallowed and logged. If suffix is specified, then hostnames with a domain part are allowed, provided the domain part matches the suffix. In addition, when a suffix is set then hostnames without a domain part have the suffix added as an optional domain part. Eg on my network I can set
|
||||
for DHCP-configured hosts to claim. The intention is to constrain
|
||||
hostnames so that an untrusted host on the LAN cannot advertise
|
||||
its name via dhcp as e.g. "microsoft.com" and capture traffic not
|
||||
meant for it. If no domain suffix is specified, then any DHCP
|
||||
hostname with a domain part (ie with a period) will be disallowed
|
||||
and logged. If suffix is specified, then hostnames with a domain
|
||||
part are allowed, provided the domain part matches the suffix. In
|
||||
addition, when a suffix is set then hostnames without a domain
|
||||
part have the suffix added as an optional domain part. Eg on my network I can set
|
||||
.B --domain=thekelleys.org.uk
|
||||
and have a machine whose DHCP hostname is "laptop". The IP address for that machine is available from
|
||||
.B dnsmasq
|
||||
@@ -650,14 +739,23 @@ binary/octet mode. The tsize and blksize extensions are supported.
|
||||
Look for files to transfer using TFTP relative to the given
|
||||
directory. When this is set, TFTP paths which include ".." are
|
||||
rejected, to stop clients getting outside the specified root.
|
||||
Absolute paths (starting with /) are allowed, but they must be within
|
||||
the tftp-root.
|
||||
.TP
|
||||
.B --tftp-unique-root
|
||||
Add the IP address of the TFTP client as a path component on the end
|
||||
of the TFTP-root (in standard dotted-quad format). Only valid if a
|
||||
tftp-root is set and the directory exists. For instance, if tftp-root is "/tftp" and client
|
||||
1.2.3.4 requests file "myfile" then the effective path will be
|
||||
"/tftp/1.2.3.4/myfile" if /tftp/1.2.3.4 exists or /tftp/myfile otherwise.
|
||||
.TP
|
||||
.B --tftp-secure
|
||||
Enable TFTP secure mode: without this, any file which is readble by
|
||||
Enable TFTP secure mode: without this, any file which is readable by
|
||||
the dnsmasq process under normal unix access-control rules is
|
||||
available via TFTP. When the --tftp-secure flag is given, only files
|
||||
owned by the user running the dnsmasq process are accessible. If
|
||||
dnsmasq is being run as root, different rules apply: --tftp-secure
|
||||
has not effect, but only files which have the world-readable bit set
|
||||
has no effect, but only files which have the world-readable bit set
|
||||
are accessible. It is not recommended to run dnsmasq as root with TFTP
|
||||
enabled, and certainly not without specifying --tftp-root. Doing so
|
||||
can expose any world-readable file on the server to any host on the net.
|
||||
@@ -671,6 +769,11 @@ file descriptor per unique file (plus a few others). So serving the
|
||||
same file simultaneously to n clients will use require about n + 10 file
|
||||
descriptors, serving different files simultaneously to n clients will
|
||||
require about (2*n) + 10 descriptors.
|
||||
.TP
|
||||
.B --tftp-no-blocksize
|
||||
Stop the TFTP server from negotiating the "blocksize" option with a
|
||||
client. Some buggy clients request this option but then behave badly
|
||||
when it is granted.
|
||||
.TP
|
||||
.B \-C, --conf-file=<file>
|
||||
Specify a different configuration file. The conf-file option is also allowed in
|
||||
@@ -703,8 +806,12 @@ corresponding to tab, bell, backspace, return and newline.
|
||||
When it receives a SIGHUP,
|
||||
.B dnsmasq
|
||||
clears its cache and then re-loads
|
||||
.I /etc/hosts.
|
||||
If
|
||||
.I /etc/hosts
|
||||
and
|
||||
.I /etc/ethers
|
||||
and any file given by --dhcp-hostsfile.
|
||||
The dhcp lease change script is called for all
|
||||
existing DHCP leases. If
|
||||
.B
|
||||
--no-poll
|
||||
is set SIGHUP also re-reads
|
||||
@@ -719,7 +826,29 @@ the number of names which have had to removed from the cache before
|
||||
they expired in order to make room for new names and the total number
|
||||
of names that have been inserted into the cache. In
|
||||
.B --no-daemon
|
||||
mode or when full logging is enabled (-q), a complete dump of the contents of the cache is made.
|
||||
mode or when full logging is enabled (-q), a complete dump of the
|
||||
contents of the cache is made.
|
||||
.PP
|
||||
When it receives SIGUSR2 and it is logging direct to a file (see
|
||||
.B --log-facility
|
||||
)
|
||||
.B dnsmasq
|
||||
will close and reopen the log file. Note that during this operation,
|
||||
dnsmasq will not be running as root. When it first creates the logfile
|
||||
dnsmasq changes the ownership of the file to the non-root user it will run
|
||||
as. Logrotate should be configured to create a new log file with
|
||||
the ownership which matches the exising one before sending SIGUSR2.
|
||||
If TCP DNS queries are in progress, the old logfile will remain open in
|
||||
child processes which are handling TCP queries and may continue to be
|
||||
written. There is a limit of 150 seconds, after which all existing TCP
|
||||
processes will have expired: for this reason, it is not wise to
|
||||
configure logfile compression for logfiles which have just been
|
||||
rotated. Using logrotate, the required options are
|
||||
.B create
|
||||
and
|
||||
.B delaycompress.
|
||||
|
||||
|
||||
.PP
|
||||
Dnsmasq is a DNS query forwarder: it it not capable of recursively
|
||||
answering arbitrary queries starting from the root servers but
|
||||
@@ -820,9 +949,74 @@ on a particular network. (Setting --bootp-dynamic removes the need for
|
||||
static address mappings.) The filename
|
||||
parameter in a BOOTP request is matched against netids in
|
||||
.B dhcp-option
|
||||
configurations, allowing some control over the options returned to
|
||||
configurations, as is the tag "bootp", allowing some control over the options returned to
|
||||
different classes of hosts.
|
||||
|
||||
.SH EXIT CODES
|
||||
.PP
|
||||
0 - Dnsmasq successfully forked into the background, or terminated
|
||||
normally if backgrounding is not enabled.
|
||||
.PP
|
||||
1 - A problem with configuration was detected.
|
||||
.PP
|
||||
2 - A problem with network access occurred (address in use, attempt
|
||||
to use privileged ports without permission).
|
||||
.PP
|
||||
3 - A problem occured with a filesystem operation (missing
|
||||
file/directory, permissions).
|
||||
.PP
|
||||
4 - Memory allocation failure.
|
||||
.PP
|
||||
5 - Other miscellaneous problem.
|
||||
.PP
|
||||
11 or greater - a non zero return code was received from the
|
||||
lease-script process "init" call. The exit code from dnsmasq is the
|
||||
script's exit code with 10 added.
|
||||
|
||||
.SH LIMITS
|
||||
The default values for resource limits in dnsmasq are generally
|
||||
conservative, and appropriate for embedded router type devices with
|
||||
slow processors and limited memory. On more capable hardware, it is
|
||||
possible to increase the limits, and handle many more clients. The
|
||||
following applies to dnsmasq-2.37: earlier versions did not scale as well.
|
||||
|
||||
.PP
|
||||
Dnsmasq is capable of handling DNS and DHCP for at least a thousand
|
||||
clients. Clearly to do this the value of
|
||||
.B --dhcp-lease-max
|
||||
must be increased,
|
||||
and lease times should not be very short (less than one hour). The
|
||||
value of
|
||||
.B --dns-forward-max
|
||||
can be increased: start with it equal to
|
||||
the number of clients and increase if DNS seems slow. Note that DNS
|
||||
performance depends too on the performance of the upstream
|
||||
nameservers. The size of the DNS cache may be increased: the hard
|
||||
limit is 10000 names and the default (150) is very low. Sending
|
||||
SIGUSR1 to dnsmasq makes it log information which is useful for tuning
|
||||
the cache size. See the
|
||||
.B NOTES
|
||||
section for details.
|
||||
|
||||
.PP
|
||||
The built-in TFTP server is capable of many simultaneous file
|
||||
transfers: the absolute limit is related to the number of file-handles
|
||||
allowed to a process and the ability of the select() system call to
|
||||
cope with large numbers of file handles. If the limit is set too high
|
||||
using
|
||||
.B --tftp-max
|
||||
it will be scaled down and the actual limit logged at
|
||||
start-up. Note that more transfers are possible when the same file is
|
||||
being sent than when each transfer sends a different file.
|
||||
|
||||
.PP
|
||||
It is possible to use dnsmasq to block Web advertising by using a list
|
||||
of known banner-ad servers, all resolving to 127.0.0.1 or 0.0.0.0, in
|
||||
.B /etc/hosts
|
||||
or an additional hosts file. The list can be very long,
|
||||
dnsmasq has been tested successfully with one million names. That size
|
||||
file needs a 1GHz processor and about 60Mb of RAM.
|
||||
|
||||
.SH FILES
|
||||
.IR /etc/dnsmasq.conf
|
||||
|
||||
|
||||
+440
-163
File diff suppressed because it is too large.
Load diff
+529
-364
File diff suppressed because it is too large.
Load diff
@@ -26,7 +26,7 @@ static struct iovec ifreq = {
|
||||
.iov_len = 0
|
||||
};
|
||||
|
||||
void init_bpf(struct daemon *daemon)
|
||||
void init_bpf(void)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
@@ -37,19 +37,14 @@ void init_bpf(struct daemon *daemon)
|
||||
{
|
||||
sprintf(ifreq.iov_base, "/dev/bpf%d", i++);
|
||||
if ((daemon->dhcp_raw_fd = open(ifreq.iov_base, O_RDWR, 0)) != -1)
|
||||
{
|
||||
int flags = fcntl(daemon->dhcp_raw_fd, F_GETFD);
|
||||
if (flags != -1)
|
||||
fcntl(daemon->dhcp_raw_fd, F_SETFD, flags | FD_CLOEXEC);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (errno != EBUSY)
|
||||
die(_("cannot create DHCP BPF socket: %s"), NULL);
|
||||
die(_("cannot create DHCP BPF socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
}
|
||||
|
||||
void send_via_bpf(struct daemon *daemon, struct dhcp_packet *mess, size_t len,
|
||||
void send_via_bpf(struct dhcp_packet *mess, size_t len,
|
||||
struct in_addr iface_addr, struct ifreq *ifr)
|
||||
{
|
||||
/* Hairy stuff, packet either has to go to the
|
||||
@@ -73,8 +68,8 @@ void send_via_bpf(struct daemon *daemon, struct dhcp_packet *mess, size_t len,
|
||||
/* Only know how to do ethernet on *BSD */
|
||||
if (mess->htype != ARPHRD_ETHER || mess->hlen != ETHER_ADDR_LEN)
|
||||
{
|
||||
syslog(LOG_WARNING, _("DHCP request for unsupported hardware type (%d) received on %s"),
|
||||
mess->htype, ifr->ifr_name);
|
||||
my_syslog(LOG_WARNING, _("DHCP request for unsupported hardware type (%d) received on %s"),
|
||||
mess->htype, ifr->ifr_name);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -145,7 +140,7 @@ void send_via_bpf(struct daemon *daemon, struct dhcp_packet *mess, size_t len,
|
||||
while (writev(daemon->dhcp_raw_fd, iov, 4) == -1 && retry_send());
|
||||
}
|
||||
|
||||
int iface_enumerate(struct daemon *daemon, void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
{
|
||||
char *ptr;
|
||||
struct ifreq *ifr;
|
||||
@@ -206,7 +201,7 @@ int iface_enumerate(struct daemon *daemon, void *parm, int (*ipv4_callback)(), i
|
||||
netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (ioctl(fd, SIOCGIFBRDADDR, ifr) != -1)
|
||||
broadcast = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (!((*ipv4_callback)(daemon, addr,
|
||||
if (!((*ipv4_callback)(addr,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
netmask, broadcast,
|
||||
parm)))
|
||||
@@ -222,7 +217,7 @@ int iface_enumerate(struct daemon *daemon, void *parm, int (*ipv4_callback)(), i
|
||||
addr->s6_addr[2] = 0;
|
||||
addr->s6_addr[3] = 0;
|
||||
}
|
||||
if (!((*ipv6_callback)(daemon, addr,
|
||||
if (!((*ipv6_callback)(addr,
|
||||
(int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
parm)))
|
||||
|
||||
+159
-164
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2005 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2007 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,13 +12,13 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
static struct crec *cache_head, *cache_tail, **hash_table;
|
||||
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 int uid;
|
||||
static char *addrbuff;
|
||||
static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL;
|
||||
static struct crec *dhcp_spare = NULL, *new_chain = NULL;
|
||||
static int cache_inserted = 0, cache_live_freed = 0, insert_error;
|
||||
static union bigname *big_free = NULL;
|
||||
static int bignames_left, hash_size;
|
||||
static int uid = 0;
|
||||
static char *addrbuff = NULL;
|
||||
|
||||
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
|
||||
static const struct {
|
||||
@@ -63,32 +63,21 @@ static char *record_source(struct hostsfile *add_hosts, int index);
|
||||
static void rehash(int size);
|
||||
static void cache_hash(struct crec *crecp);
|
||||
|
||||
void cache_init(int size, int logq)
|
||||
void cache_init(void)
|
||||
{
|
||||
struct crec *crecp;
|
||||
int i;
|
||||
|
||||
if ((log_queries = logq))
|
||||
if (daemon->options & OPT_LOG)
|
||||
addrbuff = safe_malloc(ADDRSTRLEN);
|
||||
else
|
||||
addrbuff = NULL;
|
||||
|
||||
cache_head = cache_tail = NULL;
|
||||
dhcp_inuse = dhcp_spare = NULL;
|
||||
new_chain = NULL;
|
||||
hash_table = NULL;
|
||||
cache_size = size;
|
||||
big_free = NULL;
|
||||
bignames_left = size/10;
|
||||
uid = 0;
|
||||
|
||||
cache_inserted = cache_live_freed = 0;
|
||||
|
||||
if (cache_size > 0)
|
||||
|
||||
bignames_left = daemon->cachesize/10;
|
||||
|
||||
if (daemon->cachesize > 0)
|
||||
{
|
||||
crecp = safe_malloc(size*sizeof(struct crec));
|
||||
crecp = safe_malloc(daemon->cachesize*sizeof(struct crec));
|
||||
|
||||
for (i=0; i<size; i++, crecp++)
|
||||
for (i=0; i < daemon->cachesize; i++, crecp++)
|
||||
{
|
||||
cache_link(crecp);
|
||||
crecp->flags = 0;
|
||||
@@ -97,7 +86,7 @@ void cache_init(int size, int logq)
|
||||
}
|
||||
|
||||
/* create initial hash table*/
|
||||
rehash(cache_size);
|
||||
rehash(daemon->cachesize);
|
||||
}
|
||||
|
||||
/* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
|
||||
@@ -115,7 +104,7 @@ static void rehash(int size)
|
||||
/* must succeed in getting first instance, failure later is non-fatal */
|
||||
if (!hash_table)
|
||||
new = safe_malloc(new_size * sizeof(struct crec *));
|
||||
else if (new_size <= hash_size || !(new = malloc(new_size * sizeof(struct crec *))))
|
||||
else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *))))
|
||||
return;
|
||||
|
||||
for(i = 0; i < new_size; i++)
|
||||
@@ -157,9 +146,24 @@ static struct crec **hash_bucket(char *name)
|
||||
|
||||
static void cache_hash(struct crec *crecp)
|
||||
{
|
||||
struct crec **bucket = hash_bucket(cache_get_name(crecp));
|
||||
crecp->hash_next = *bucket;
|
||||
*bucket = crecp;
|
||||
/* maintain an invariant that all entries with F_REVERSE set
|
||||
are at the start of the hash-chain and all non-reverse
|
||||
immortal entries are at the end of the hash-chain.
|
||||
This allows reverse searches and garbage collection to be optimised */
|
||||
|
||||
struct crec **up = hash_bucket(cache_get_name(crecp));
|
||||
|
||||
if (!(crecp->flags & F_REVERSE))
|
||||
{
|
||||
while (*up && ((*up)->flags & F_REVERSE))
|
||||
up = &((*up)->hash_next);
|
||||
|
||||
if (crecp->flags & F_IMMORTAL)
|
||||
while (*up && !((*up)->flags & F_IMMORTAL))
|
||||
up = &((*up)->hash_next);
|
||||
}
|
||||
crecp->hash_next = *up;
|
||||
*up = crecp;
|
||||
}
|
||||
|
||||
static void cache_free(struct crec *crecp)
|
||||
@@ -223,17 +227,12 @@ char *cache_get_name(struct crec *crecp)
|
||||
|
||||
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)
|
||||
|
||||
if (crecp->addr.cname.cache && crecp->addr.cname.uid == crecp->addr.cname.cache->uid)
|
||||
return 0;
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -258,10 +257,13 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
|
||||
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) */
|
||||
|
||||
struct crec *crecp, **up;
|
||||
name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
|
||||
|
||||
We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
|
||||
so that when we hit an entry which isn't reverse and is immortal, we're done. */
|
||||
|
||||
struct crec *crecp, **up;
|
||||
|
||||
if (flags & F_FORWARD)
|
||||
{
|
||||
for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
|
||||
@@ -296,7 +298,9 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
|
||||
int addrlen = INADDRSZ;
|
||||
#endif
|
||||
for (i = 0; i < hash_size; i++)
|
||||
for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = crecp->hash_next)
|
||||
for (crecp = hash_table[i], up = &hash_table[i];
|
||||
crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
|
||||
crecp = crecp->hash_next)
|
||||
if (is_expired(now, crecp))
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
@@ -348,21 +352,12 @@ void cache_start_insert(void)
|
||||
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;
|
||||
#else
|
||||
int addrlen = INADDRSZ;
|
||||
#endif
|
||||
struct crec *new;
|
||||
union bigname *big_name = NULL;
|
||||
int freed_all = flags & F_REVERSE;
|
||||
|
||||
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))
|
||||
name = NULL;
|
||||
|
||||
/* CONFIG bit no needed except for logging */
|
||||
flags &= ~F_CONFIG;
|
||||
|
||||
@@ -416,7 +411,7 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
big_free = big_free->next;
|
||||
}
|
||||
else if (!bignames_left ||
|
||||
!(big_name = (union bigname *)malloc(sizeof(union bigname))))
|
||||
!(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
|
||||
{
|
||||
insert_error = 1;
|
||||
return NULL;
|
||||
@@ -437,12 +432,14 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
new->name.bname = big_name;
|
||||
new->flags |= F_BIGNAME;
|
||||
}
|
||||
|
||||
if (name)
|
||||
strcpy(cache_get_name(new), name);
|
||||
else
|
||||
*cache_get_name(new) = 0;
|
||||
|
||||
if (addr)
|
||||
memcpy(&new->addr.addr, addr, addrlen);
|
||||
new->addr.addr = *addr;
|
||||
else
|
||||
new->addr.cname.cache = NULL;
|
||||
|
||||
@@ -567,16 +564,19 @@ struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
|
||||
else
|
||||
{
|
||||
/* first search, look for relevant entries and push to top of list
|
||||
also free anything which has expired */
|
||||
also free anything which has expired. All the reverse entries are at the
|
||||
start of the hash chain, so we can give up when we find the first
|
||||
non-REVERSE one. */
|
||||
int i;
|
||||
struct crec **up, **chainp = &ans;
|
||||
|
||||
for(i=0; i<hash_size; i++)
|
||||
for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = crecp->hash_next)
|
||||
for (i=0; i<hash_size; i++)
|
||||
for (crecp = hash_table[i], up = &hash_table[i];
|
||||
crecp && (crecp->flags & F_REVERSE);
|
||||
crecp = crecp->hash_next)
|
||||
if (!is_expired(now, crecp))
|
||||
{
|
||||
if ((crecp->flags & F_REVERSE) &&
|
||||
(crecp->flags & prot) &&
|
||||
if ((crecp->flags & prot) &&
|
||||
memcmp(&crecp->addr.addr, addr, addrlen) == 0)
|
||||
{
|
||||
if (crecp->flags & (F_HOSTS | F_DHCP))
|
||||
@@ -668,7 +668,7 @@ static int read_hostsfile(char *filename, int opts, char *buff, char *domain_suf
|
||||
|
||||
if (!f)
|
||||
{
|
||||
syslog(LOG_ERR, _("failed to load names from %s: %m"), filename);
|
||||
my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -702,7 +702,7 @@ static int read_hostsfile(char *filename, int opts, char *buff, char *domain_suf
|
||||
#endif
|
||||
else
|
||||
{
|
||||
syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
|
||||
my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -726,12 +726,13 @@ static int read_hostsfile(char *filename, int opts, char *buff, char *domain_suf
|
||||
while ((token = strtok(NULL, " \t\n\r")) && (*token != '#'))
|
||||
{
|
||||
struct crec *cache;
|
||||
int fqdn = !!strchr(token, '.');
|
||||
if (canonicalise(token))
|
||||
{
|
||||
/* If set, add a version of the name with a default domain appended */
|
||||
if ((opts & OPT_EXPAND) && domain_suffix && !strchr(token, '.') &&
|
||||
(cache = malloc(sizeof(struct crec) +
|
||||
strlen(token)+2+strlen(domain_suffix)-SMALLDNAME)))
|
||||
if ((opts & OPT_EXPAND) && domain_suffix && !fqdn &&
|
||||
(cache = whine_malloc(sizeof(struct crec) +
|
||||
strlen(token)+2+strlen(domain_suffix)-SMALLDNAME)))
|
||||
{
|
||||
strcpy(cache->name.sname, token);
|
||||
strcat(cache->name.sname, ".");
|
||||
@@ -740,7 +741,7 @@ static int read_hostsfile(char *filename, int opts, char *buff, char *domain_suf
|
||||
addr_dup = 1;
|
||||
name_count++;
|
||||
}
|
||||
if ((cache = malloc(sizeof(struct crec) + strlen(token)+1-SMALLDNAME)))
|
||||
if ((cache = whine_malloc(sizeof(struct crec) + strlen(token)+1-SMALLDNAME)))
|
||||
{
|
||||
strcpy(cache->name.sname, token);
|
||||
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
|
||||
@@ -748,14 +749,14 @@ static int read_hostsfile(char *filename, int opts, char *buff, char *domain_suf
|
||||
}
|
||||
}
|
||||
else
|
||||
syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
|
||||
my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
rehash(name_count);
|
||||
|
||||
syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
|
||||
my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
|
||||
|
||||
return name_count;
|
||||
}
|
||||
@@ -763,7 +764,7 @@ static int read_hostsfile(char *filename, int opts, char *buff, char *domain_suf
|
||||
void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *addn_hosts)
|
||||
{
|
||||
struct crec *cache, **up, *tmp;
|
||||
int i, total_size = cache_size;
|
||||
int i, total_size = daemon->cachesize;
|
||||
|
||||
cache_inserted = cache_live_freed = 0;
|
||||
|
||||
@@ -792,8 +793,8 @@ void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *a
|
||||
|
||||
if ((opts & OPT_NO_HOSTS) && !addn_hosts)
|
||||
{
|
||||
if (cache_size > 0)
|
||||
syslog(LOG_INFO, _("cleared cache"));
|
||||
if (daemon->cachesize > 0)
|
||||
my_syslog(LOG_INFO, _("cleared cache"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -808,28 +809,22 @@ void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *a
|
||||
|
||||
void cache_unhash_dhcp(void)
|
||||
{
|
||||
struct crec *tmp, *cache, **up;
|
||||
struct crec *cache, **up;
|
||||
int i;
|
||||
|
||||
for (i=0; i<hash_size; i++)
|
||||
for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
|
||||
if (cache->flags & F_DHCP)
|
||||
*up = cache->hash_next;
|
||||
{
|
||||
*up = cache->hash_next;
|
||||
cache->next = dhcp_spare;
|
||||
dhcp_spare = cache;
|
||||
}
|
||||
else
|
||||
up = &cache->hash_next;
|
||||
|
||||
/* prev field links all dhcp entries */
|
||||
for (cache = dhcp_inuse; cache; cache = tmp)
|
||||
{
|
||||
tmp = cache->prev;
|
||||
cache->prev = dhcp_spare;
|
||||
dhcp_spare = cache;
|
||||
}
|
||||
|
||||
dhcp_inuse = NULL;
|
||||
}
|
||||
|
||||
void cache_add_dhcp_entry(struct daemon *daemon, char *host_name,
|
||||
void cache_add_dhcp_entry(char *host_name,
|
||||
struct in_addr *host_address, time_t ttd)
|
||||
{
|
||||
struct crec *crec;
|
||||
@@ -845,11 +840,11 @@ void cache_add_dhcp_entry(struct daemon *daemon, char *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);
|
||||
my_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;
|
||||
}
|
||||
@@ -867,9 +862,9 @@ void cache_add_dhcp_entry(struct daemon *daemon, char *host_name,
|
||||
}
|
||||
|
||||
if ((crec = dhcp_spare))
|
||||
dhcp_spare = dhcp_spare->prev;
|
||||
dhcp_spare = dhcp_spare->next;
|
||||
else /* need new one */
|
||||
crec = malloc(sizeof(struct crec));
|
||||
crec = whine_malloc(sizeof(struct crec));
|
||||
|
||||
if (crec) /* malloc may fail */
|
||||
{
|
||||
@@ -880,72 +875,69 @@ void cache_add_dhcp_entry(struct daemon *daemon, char *host_name,
|
||||
crec->ttd = ttd;
|
||||
crec->addr.addr.addr.addr4 = *host_address;
|
||||
crec->name.namep = host_name;
|
||||
crec->prev = dhcp_inuse;
|
||||
dhcp_inuse = crec;
|
||||
cache_hash(crec);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void dump_cache(struct daemon *daemon, time_t now)
|
||||
void dump_cache(time_t now)
|
||||
{
|
||||
syslog(LOG_INFO, _("time %lu, cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
|
||||
(unsigned long)now, daemon->cachesize, cache_live_freed, cache_inserted);
|
||||
my_syslog(LOG_INFO, _("time %lu, cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
|
||||
(unsigned long)now, daemon->cachesize, cache_live_freed, cache_inserted);
|
||||
|
||||
if ((daemon->options & (OPT_DEBUG | OPT_LOG)) &&
|
||||
(addrbuff || (addrbuff = malloc(ADDRSTRLEN))))
|
||||
(addrbuff || (addrbuff = whine_malloc(ADDRSTRLEN))))
|
||||
{
|
||||
struct crec *cache ;
|
||||
int i;
|
||||
syslog(LOG_DEBUG, "Host Address Flags Expires");
|
||||
my_syslog(LOG_DEBUG, "Host Address Flags Expires");
|
||||
|
||||
for (i=0; i<hash_size; i++)
|
||||
for (cache = hash_table[i]; cache; cache = cache->hash_next)
|
||||
{
|
||||
char *a, *p = daemon->namebuff;
|
||||
p += sprintf(p, "%-40.40s ", cache_get_name(cache));
|
||||
if ((cache->flags & F_NEG) && (cache->flags & F_FORWARD))
|
||||
addrbuff[0] = 0;
|
||||
a = "";
|
||||
else if (cache->flags & F_CNAME)
|
||||
{
|
||||
addrbuff[0] = 0;
|
||||
addrbuff[ADDRSTRLEN-1] = 0;
|
||||
a = "";
|
||||
if (!is_outdated_cname_pointer(cache))
|
||||
strncpy(addrbuff, cache_get_name(cache->addr.cname.cache), ADDRSTRLEN);
|
||||
a = cache_get_name(cache->addr.cname.cache);
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (cache->flags & F_IPV4)
|
||||
inet_ntop(AF_INET, &cache->addr.addr, addrbuff, ADDRSTRLEN);
|
||||
else if (cache->flags & F_IPV6)
|
||||
inet_ntop(AF_INET6, &cache->addr.addr, addrbuff, ADDRSTRLEN);
|
||||
else
|
||||
{
|
||||
a = addrbuff;
|
||||
if (cache->flags & F_IPV4)
|
||||
inet_ntop(AF_INET, &cache->addr.addr, addrbuff, ADDRSTRLEN);
|
||||
else if (cache->flags & F_IPV6)
|
||||
inet_ntop(AF_INET6, &cache->addr.addr, addrbuff, ADDRSTRLEN);
|
||||
}
|
||||
#else
|
||||
else
|
||||
strcpy(addrbuff, inet_ntoa(cache->addr.addr.addr.addr4));
|
||||
a = inet_ntoa(cache->addr.addr.addr.addr4);
|
||||
#endif
|
||||
syslog(LOG_DEBUG,
|
||||
p += sprintf(p, "%-30.30s %s%s%s%s%s%s%s%s%s%s ", a,
|
||||
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" : " ",
|
||||
cache->flags & F_DHCP ? "D" : " ",
|
||||
cache->flags & F_NEG ? "N" : " ",
|
||||
cache->flags & F_NXDOMAIN ? "X" : " ",
|
||||
cache->flags & F_HOSTS ? "H" : " ");
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
"%-40.40s %-30.30s %s%s%s%s%s%s%s%s%s%s %lu",
|
||||
p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
|
||||
#else
|
||||
"%-40.40s %-30.30s %s%s%s%s%s%s%s%s%s%s %s",
|
||||
p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
|
||||
/* ctime includes trailing \n - eat it */
|
||||
*(p-1) = 0;
|
||||
#endif
|
||||
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" : " ",
|
||||
cache->flags & F_DHCP ? "D" : " ",
|
||||
cache->flags & F_NEG ? "N" : " ",
|
||||
cache->flags & F_NXDOMAIN ? "X" : " ",
|
||||
cache->flags & F_HOSTS ? "H" : " ",
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now)
|
||||
#else
|
||||
cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd))
|
||||
#endif
|
||||
);
|
||||
}
|
||||
}
|
||||
my_syslog(LOG_DEBUG, daemon->namebuff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *record_source(struct hostsfile *addn_hosts, int index)
|
||||
@@ -967,54 +959,60 @@ static char *record_source(struct hostsfile *addn_hosts, int index)
|
||||
void log_query(unsigned short flags, char *name, struct all_addr *addr,
|
||||
unsigned short type, struct hostsfile *addn_hosts, int index)
|
||||
{
|
||||
char *source;
|
||||
char *source, *dest = addrbuff;
|
||||
char *verb = "is";
|
||||
char types[20];
|
||||
|
||||
if (!log_queries)
|
||||
if (!(daemon->options & OPT_LOG))
|
||||
return;
|
||||
|
||||
if (addr)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
||||
addr, addrbuff, ADDRSTRLEN);
|
||||
#else
|
||||
strncpy(addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (flags & F_REVERSE)
|
||||
{
|
||||
dest = name;
|
||||
name = addrbuff;
|
||||
}
|
||||
|
||||
if (flags & F_NEG)
|
||||
{
|
||||
if (flags & F_REVERSE)
|
||||
#ifdef HAVE_IPV6
|
||||
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
||||
addr, name, MAXDNAME);
|
||||
#else
|
||||
strcpy(name, inet_ntoa(addr->addr.addr4));
|
||||
#endif
|
||||
|
||||
if (flags & F_NXDOMAIN)
|
||||
strcpy(addrbuff, "<NXDOMAIN>");
|
||||
{
|
||||
if (flags & F_IPV4)
|
||||
dest = "NXDOMAIN-IPv4";
|
||||
else
|
||||
dest = "NXDOMAIN-IPv6";
|
||||
}
|
||||
else
|
||||
strcpy(addrbuff, "<NODATA>");
|
||||
|
||||
if (flags & F_IPV4)
|
||||
strcat(addrbuff, "-IPv4");
|
||||
else if (flags & F_IPV6)
|
||||
strcat(addrbuff, "-IPv6");
|
||||
{
|
||||
if (flags & F_IPV4)
|
||||
dest = "NODATA-IPv4";
|
||||
else
|
||||
dest = "NODATA-IPv6";
|
||||
}
|
||||
}
|
||||
else if (flags & F_CNAME)
|
||||
{
|
||||
/* nasty abuse of IPV4 and IPV6 flags */
|
||||
if (flags & F_IPV4)
|
||||
strcpy(addrbuff, "<MX>");
|
||||
dest = "<MX>";
|
||||
else if (flags & F_IPV6)
|
||||
strcpy(addrbuff, "<SRV>");
|
||||
dest = "<SRV>";
|
||||
else if (flags & F_NXDOMAIN)
|
||||
strcpy(addrbuff, "<TXT>");
|
||||
dest = "<TXT>";
|
||||
else if (flags & F_BIGNAME)
|
||||
strcpy(addrbuff, "<PTR>");
|
||||
dest = "<PTR>";
|
||||
else
|
||||
strcpy(addrbuff, "<CNAME>");
|
||||
dest = "<CNAME>";
|
||||
}
|
||||
else
|
||||
#ifdef HAVE_IPV6
|
||||
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
||||
addr, addrbuff, ADDRSTRLEN);
|
||||
#else
|
||||
strcpy(addrbuff, inet_ntoa(addr->addr.addr4));
|
||||
#endif
|
||||
|
||||
if (flags & F_DHCP)
|
||||
source = "DHCP";
|
||||
@@ -1049,9 +1047,6 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr,
|
||||
if (strlen(name) == 0)
|
||||
name = ".";
|
||||
|
||||
if ((flags & F_FORWARD) | (flags & F_NEG))
|
||||
syslog(LOG_DEBUG, "%s %s %s %s", source, name, verb, addrbuff);
|
||||
else if (flags & F_REVERSE)
|
||||
syslog(LOG_DEBUG, "%s %s is %s", source, addrbuff, name);
|
||||
my_syslog(LOG_DEBUG, "%s %s %s %s", source, name, verb, dest);
|
||||
}
|
||||
|
||||
+7
-4
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2006 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2007 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,7 +10,7 @@
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define VERSION "2.36"
|
||||
#define VERSION "2.40"
|
||||
|
||||
#define FTABSIZ 150 /* max number of outstanding requests (default) */
|
||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||
@@ -50,6 +50,7 @@
|
||||
#define DHCP_CLIENT_PORT 68
|
||||
#define TFTP_PORT 69
|
||||
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
|
||||
#define LOG_MAX 5 /* log-queue length */
|
||||
|
||||
/* DBUS interface specifics */
|
||||
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"
|
||||
@@ -180,7 +181,7 @@ NOTES:
|
||||
# error HAVE_ISC_READER is not compatible with HAVE_BROKEN_RTC
|
||||
#endif
|
||||
|
||||
/* Allow TFTP to be disabled with CFLAGS=-DNO_TFTP */
|
||||
/* Allow TFTP to be disabled with COPT=-DNO_TFTP */
|
||||
#ifdef NO_TFTP
|
||||
#undef HAVE_TFTP
|
||||
#endif
|
||||
@@ -198,7 +199,8 @@ NOTES:
|
||||
#undef HAVE_SOCKADDR_SA_LEN
|
||||
/* 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. */
|
||||
processes for TCP connections and disables the call-a-script on leasechange
|
||||
system. It's intended for use on MMU-less kernels. */
|
||||
#define NO_FORK
|
||||
|
||||
#elif defined(__UCLIBC__)
|
||||
@@ -276,6 +278,7 @@ typedef unsigned long in_addr_t;
|
||||
|
||||
#endif
|
||||
/* Decide if we're going to support IPv6 */
|
||||
/* IPv6 can be forced off with "make COPTS=-DNO_IPV6" */
|
||||
/* We assume that systems which don't have IPv6
|
||||
headers don't have ntop and pton either */
|
||||
|
||||
|
||||
+21
-21
@@ -25,28 +25,25 @@ struct watch {
|
||||
|
||||
static dbus_bool_t add_watch(DBusWatch *watch, void *data)
|
||||
{
|
||||
struct daemon *daemon = data;
|
||||
struct watch *w;
|
||||
|
||||
for (w = daemon->watches; w; w = w->next)
|
||||
if (w->watch == watch)
|
||||
return TRUE;
|
||||
|
||||
if (!(w = malloc(sizeof(struct watch))))
|
||||
if (!(w = whine_malloc(sizeof(struct watch))))
|
||||
return FALSE;
|
||||
|
||||
w->watch = watch;
|
||||
w->next = daemon->watches;
|
||||
daemon->watches = w;
|
||||
|
||||
dbus_watch_set_data (watch, (void *)daemon, NULL);
|
||||
|
||||
w = data; /* no warning */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void remove_watch(DBusWatch *watch, void *data)
|
||||
{
|
||||
struct daemon *daemon = data;
|
||||
struct watch **up, *w;
|
||||
|
||||
for (up = &(daemon->watches), w = daemon->watches; w; w = w->next)
|
||||
@@ -57,9 +54,11 @@ static void remove_watch(DBusWatch *watch, void *data)
|
||||
}
|
||||
else
|
||||
up = &(w->next);
|
||||
|
||||
w = data; /* no warning */
|
||||
}
|
||||
|
||||
static void dbus_read_servers(struct daemon *daemon, DBusMessage *message)
|
||||
static void dbus_read_servers(DBusMessage *message)
|
||||
{
|
||||
struct server *serv, *tmp, **up;
|
||||
DBusMessageIter iter;
|
||||
@@ -109,7 +108,7 @@ static void dbus_read_servers(struct daemon *daemon, DBusMessage *message)
|
||||
}
|
||||
|
||||
#ifndef HAVE_IPV6
|
||||
syslog(LOG_WARNING, _("attempt to set an IPv6 server address via DBus - no IPv6 support"));
|
||||
my_syslog(LOG_WARNING, _("attempt to set an IPv6 server address via DBus - no IPv6 support"));
|
||||
#else
|
||||
if (i == sizeof(struct in6_addr)-1)
|
||||
{
|
||||
@@ -161,11 +160,11 @@ static void dbus_read_servers(struct daemon *daemon, DBusMessage *message)
|
||||
}
|
||||
}
|
||||
|
||||
if (!serv && (serv = malloc(sizeof (struct server))))
|
||||
if (!serv && (serv = whine_malloc(sizeof (struct server))))
|
||||
{
|
||||
/* Not found, create a new one. */
|
||||
if (domain)
|
||||
serv->domain = malloc(strlen(domain)+1);
|
||||
serv->domain = whine_malloc(strlen(domain)+1);
|
||||
if (domain && !serv->domain)
|
||||
{
|
||||
free(serv);
|
||||
@@ -208,6 +207,7 @@ static void dbus_read_servers(struct daemon *daemon, DBusMessage *message)
|
||||
tmp = serv->next;
|
||||
if (serv->flags & SERV_MARK)
|
||||
{
|
||||
server_gone(serv);
|
||||
*up = serv->next;
|
||||
free(serv);
|
||||
}
|
||||
@@ -222,8 +222,7 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
void *user_data)
|
||||
{
|
||||
char *method = (char *)dbus_message_get_member(message);
|
||||
struct daemon *daemon = (struct daemon *)user_data;
|
||||
|
||||
|
||||
if (strcmp(method, "GetVersion") == 0)
|
||||
{
|
||||
char *v = VERSION;
|
||||
@@ -235,22 +234,24 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
}
|
||||
else if (strcmp(method, "SetServers") == 0)
|
||||
{
|
||||
syslog(LOG_INFO, _("setting upstream servers from DBus"));
|
||||
dbus_read_servers(daemon, message);
|
||||
check_servers(daemon);
|
||||
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
|
||||
dbus_read_servers(message);
|
||||
check_servers();
|
||||
}
|
||||
else if (strcmp(method, "ClearCache") == 0)
|
||||
clear_cache_and_reload(daemon, dnsmasq_time());
|
||||
clear_cache_and_reload(dnsmasq_time());
|
||||
else
|
||||
return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
|
||||
|
||||
method = user_data; /* no warning */
|
||||
|
||||
return (DBUS_HANDLER_RESULT_HANDLED);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* returns NULL or error message, may fail silently if dbus daemon not yet up. */
|
||||
char *dbus_init(struct daemon *daemon)
|
||||
char *dbus_init(void)
|
||||
{
|
||||
DBusConnection *connection = NULL;
|
||||
DBusObjectPathVTable dnsmasq_vtable = {NULL, &message_handler, NULL, NULL, NULL, NULL };
|
||||
@@ -263,14 +264,14 @@ char *dbus_init(struct daemon *daemon)
|
||||
|
||||
dbus_connection_set_exit_on_disconnect(connection, FALSE);
|
||||
dbus_connection_set_watch_functions(connection, add_watch, remove_watch,
|
||||
NULL, (void *)daemon, NULL);
|
||||
NULL, NULL, NULL);
|
||||
dbus_error_init (&dbus_error);
|
||||
dbus_bus_request_name (connection, DNSMASQ_SERVICE, 0, &dbus_error);
|
||||
if (dbus_error_is_set (&dbus_error))
|
||||
return (char *)dbus_error.message;
|
||||
|
||||
if (!dbus_connection_register_object_path(connection, DNSMASQ_PATH,
|
||||
&dnsmasq_vtable, daemon))
|
||||
&dnsmasq_vtable, NULL))
|
||||
return _("could not register a DBus message handler");
|
||||
|
||||
daemon->dbus = connection;
|
||||
@@ -282,7 +283,7 @@ char *dbus_init(struct daemon *daemon)
|
||||
}
|
||||
|
||||
|
||||
void set_dbus_listeners(struct daemon *daemon, int *maxfdp,
|
||||
void set_dbus_listeners(int *maxfdp,
|
||||
fd_set *rset, fd_set *wset, fd_set *eset)
|
||||
{
|
||||
struct watch *w;
|
||||
@@ -305,8 +306,7 @@ void set_dbus_listeners(struct daemon *daemon, int *maxfdp,
|
||||
}
|
||||
}
|
||||
|
||||
void check_dbus_listeners(struct daemon *daemon,
|
||||
fd_set *rset, fd_set *wset, fd_set *eset)
|
||||
void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset)
|
||||
{
|
||||
DBusConnection *connection = (DBusConnection *)daemon->dbus;
|
||||
struct watch *w;
|
||||
|
||||
+124
-70
@@ -18,10 +18,10 @@ struct iface_param {
|
||||
int ind;
|
||||
};
|
||||
|
||||
static int complete_context(struct daemon *daemon, struct in_addr local, int if_index,
|
||||
static int complete_context(struct in_addr local, int if_index,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
||||
|
||||
void dhcp_init(struct daemon *daemon)
|
||||
void dhcp_init(void)
|
||||
{
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
struct sockaddr_in saddr;
|
||||
@@ -29,7 +29,7 @@ void dhcp_init(struct daemon *daemon)
|
||||
struct dhcp_config *configs, *cp;
|
||||
|
||||
if (fd == -1)
|
||||
die (_("cannot create DHCP socket : %s"), NULL);
|
||||
die (_("cannot create DHCP socket : %s"), NULL, EC_BADNET);
|
||||
|
||||
if (!fix_fd(fd) ||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
@@ -38,7 +38,7 @@ void dhcp_init(struct daemon *daemon)
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
|
||||
#endif
|
||||
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)
|
||||
die(_("failed to set options on DHCP socket: %s"), NULL);
|
||||
die(_("failed to set options on DHCP socket: %s"), NULL, EC_BADNET);
|
||||
|
||||
/* When bind-interfaces is set, there might be more than one dnmsasq
|
||||
instance binding port 67. That's OK if they serve different networks.
|
||||
@@ -56,7 +56,7 @@ void dhcp_init(struct daemon *daemon)
|
||||
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
|
||||
#endif
|
||||
if (rc == -1)
|
||||
die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL);
|
||||
die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -69,7 +69,7 @@ void dhcp_init(struct daemon *daemon)
|
||||
#endif
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)))
|
||||
die(_("failed to bind DHCP server socket: %s"), NULL);
|
||||
die(_("failed to bind DHCP server socket: %s"), NULL, EC_BADNET);
|
||||
|
||||
daemon->dhcpfd = fd;
|
||||
|
||||
@@ -82,30 +82,32 @@ void dhcp_init(struct daemon *daemon)
|
||||
daemon->dhcp_icmp_fd = -1;
|
||||
else if ((daemon->dhcp_icmp_fd = make_icmp_sock()) == -1 ||
|
||||
setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1 )
|
||||
die(_("cannot create ICMP raw socket: %s."), NULL);
|
||||
die(_("cannot create ICMP raw socket: %s."), NULL, EC_BADNET);
|
||||
|
||||
/* Make BPF raw send socket */
|
||||
init_bpf(daemon);
|
||||
init_bpf();
|
||||
#endif
|
||||
|
||||
/* 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. */
|
||||
since the address is reserved by the other one -> protocol loop.
|
||||
Also check that FQDNs match the domain we are using. */
|
||||
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));
|
||||
{
|
||||
char *domain;
|
||||
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), EC_BADCONF);
|
||||
|
||||
if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
|
||||
die(_("illegal domain %s in dhcp-config directive."), domain, EC_BADCONF);
|
||||
}
|
||||
|
||||
daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet);
|
||||
daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
|
||||
/* 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);
|
||||
daemon->ping_results = NULL;
|
||||
}
|
||||
|
||||
void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
void dhcp_packet(time_t now)
|
||||
{
|
||||
struct dhcp_packet *mess;
|
||||
struct dhcp_context *context;
|
||||
@@ -116,7 +118,7 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
struct cmsghdr *cmptr;
|
||||
struct iovec iov;
|
||||
ssize_t sz;
|
||||
int iface_index = 0, unicast_dest = 0;
|
||||
int iface_index = 0, unicast_dest = 0, is_inform = 0;
|
||||
struct in_addr iface_addr, *addrp = NULL;
|
||||
struct iface_param parm;
|
||||
|
||||
@@ -204,7 +206,7 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
}
|
||||
|
||||
if (!iface_check(daemon, AF_INET, (struct all_addr *)addrp, &ifr, &iface_index))
|
||||
if (!iface_check(AF_INET, (struct all_addr *)addrp, &ifr, &iface_index))
|
||||
return;
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
@@ -216,7 +218,7 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
{
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1)
|
||||
{
|
||||
syslog(LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
|
||||
my_syslog(LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
|
||||
return;
|
||||
}
|
||||
else
|
||||
@@ -232,12 +234,13 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
parm.current = NULL;
|
||||
parm.ind = iface_index;
|
||||
|
||||
if (!iface_enumerate(daemon, &parm, complete_context, NULL))
|
||||
if (!iface_enumerate(&parm, complete_context, NULL))
|
||||
return;
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
iov.iov_len = dhcp_reply(daemon, parm.current, ifr.ifr_name, (size_t)sz, now, unicast_dest);
|
||||
lease_update_file(daemon, now);
|
||||
lease_update_dns(daemon);
|
||||
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, (size_t)sz,
|
||||
now, unicast_dest, &is_inform);
|
||||
lease_update_file(now);
|
||||
lease_update_dns();
|
||||
|
||||
if (iov.iov_len == 0)
|
||||
return;
|
||||
@@ -266,8 +269,10 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
{
|
||||
/* If the client's idea of its own address tallys with
|
||||
the source address in the request packet, we believe the
|
||||
source port too, and send back to that. */
|
||||
if (dest.sin_addr.s_addr != mess->ciaddr.s_addr || !dest.sin_port)
|
||||
source port too, and send back to that. If we're replying
|
||||
to a DHCPINFORM, trust the source address always. */
|
||||
if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
|
||||
dest.sin_port == 0 || dest.sin_addr.s_addr == 0)
|
||||
{
|
||||
dest.sin_port = htons(DHCP_CLIENT_PORT);
|
||||
dest.sin_addr = mess->ciaddr;
|
||||
@@ -308,7 +313,7 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
#else
|
||||
else
|
||||
{
|
||||
send_via_bpf(daemon, mess, iov.iov_len, iface_addr, &ifr);
|
||||
send_via_bpf(mess, iov.iov_len, iface_addr, &ifr);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -326,15 +331,12 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
|
||||
Note that the current chain may be superceded later for configured hosts or those coming via gateways. */
|
||||
|
||||
static int complete_context(struct daemon *daemon, struct in_addr local, int if_index,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||
static int complete_context(struct in_addr local, int if_index,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
struct iface_param *param = vparam;
|
||||
|
||||
if (if_index != param->ind)
|
||||
return 1; /* no for us. */
|
||||
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
{
|
||||
if (!(context->flags & CONTEXT_NETMASK) &&
|
||||
@@ -347,8 +349,8 @@ static int complete_context(struct daemon *daemon, struct in_addr local, int if_
|
||||
{
|
||||
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));
|
||||
my_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;
|
||||
}
|
||||
@@ -359,7 +361,7 @@ static int complete_context(struct daemon *daemon, struct in_addr local, int if_
|
||||
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)
|
||||
if (if_index == param->ind && context->current == context)
|
||||
{
|
||||
context->router = local;
|
||||
context->local = local;
|
||||
@@ -482,7 +484,7 @@ int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int address_allocate(struct dhcp_context *context, struct daemon *daemon,
|
||||
int address_allocate(struct dhcp_context *context,
|
||||
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
|
||||
struct dhcp_netid *netids, time_t now)
|
||||
{
|
||||
@@ -543,7 +545,7 @@ int address_allocate(struct dhcp_context *context, struct daemon *daemon,
|
||||
else if (++count == max || r->addr.s_addr == addr.s_addr)
|
||||
return 1;
|
||||
|
||||
if (icmp_ping(daemon, addr))
|
||||
if (icmp_ping(addr))
|
||||
/* address in use: perturb address selection so that we are
|
||||
less likely to try this address again. */
|
||||
c->addr_epoch++;
|
||||
@@ -552,7 +554,7 @@ int address_allocate(struct dhcp_context *context, struct daemon *daemon,
|
||||
/* at this point victim may hold an expired record */
|
||||
if (!victim)
|
||||
{
|
||||
if ((victim = malloc(sizeof(struct ping_result))))
|
||||
if ((victim = whine_malloc(sizeof(struct ping_result))))
|
||||
{
|
||||
victim->next = daemon->ping_results;
|
||||
daemon->ping_results = victim;
|
||||
@@ -648,7 +650,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void dhcp_read_ethers(struct daemon *daemon)
|
||||
void dhcp_read_ethers(void)
|
||||
{
|
||||
FILE *f = fopen(ETHERSFILE, "r");
|
||||
unsigned int flags;
|
||||
@@ -664,7 +666,7 @@ void dhcp_read_ethers(struct daemon *daemon)
|
||||
|
||||
if (!f)
|
||||
{
|
||||
syslog(LOG_ERR, _("failed to read %s:%m"), ETHERSFILE);
|
||||
my_syslog(LOG_ERR, _("failed to read %s:%s"), ETHERSFILE, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -699,7 +701,7 @@ void dhcp_read_ethers(struct daemon *daemon)
|
||||
*ip = 0;
|
||||
if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
|
||||
{
|
||||
syslog(LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno);
|
||||
my_syslog(LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -712,7 +714,7 @@ void dhcp_read_ethers(struct daemon *daemon)
|
||||
{
|
||||
if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
|
||||
{
|
||||
syslog(LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno);
|
||||
my_syslog(LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -724,12 +726,12 @@ void dhcp_read_ethers(struct daemon *daemon)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!canonicalise(ip))
|
||||
if (!canonicalise(ip) || strip_hostname(ip))
|
||||
{
|
||||
syslog(LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
|
||||
my_syslog(LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
flags = CONFIG_NAME;
|
||||
|
||||
for (config = daemon->dhcp_conf; config; config = config->next)
|
||||
@@ -749,7 +751,7 @@ void dhcp_read_ethers(struct daemon *daemon)
|
||||
|
||||
if (!config)
|
||||
{
|
||||
if (!(config = malloc(sizeof(struct dhcp_config))))
|
||||
if (!(config = whine_malloc(sizeof(struct dhcp_config))))
|
||||
continue;
|
||||
config->flags = CONFIG_FROM_ETHERS;
|
||||
config->wildcard_mask = 0;
|
||||
@@ -761,7 +763,7 @@ void dhcp_read_ethers(struct daemon *daemon)
|
||||
|
||||
if (flags & CONFIG_NAME)
|
||||
{
|
||||
if ((config->hostname = malloc(strlen(ip)+1)))
|
||||
if ((config->hostname = whine_malloc(strlen(ip)+1)))
|
||||
strcpy(config->hostname, ip);
|
||||
else
|
||||
config->flags &= ~CONFIG_NAME;
|
||||
@@ -780,7 +782,62 @@ void dhcp_read_ethers(struct daemon *daemon)
|
||||
|
||||
fclose(f);
|
||||
|
||||
syslog(LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
|
||||
my_syslog(LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
|
||||
}
|
||||
|
||||
void dhcp_read_hosts(void)
|
||||
{
|
||||
struct dhcp_config *configs, *cp, **up;
|
||||
int count;
|
||||
|
||||
/* remove existing... */
|
||||
for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
|
||||
{
|
||||
cp = configs->next;
|
||||
|
||||
if (configs->flags & CONFIG_BANK)
|
||||
{
|
||||
if (configs->flags & CONFIG_CLID)
|
||||
free(configs->clid);
|
||||
if (configs->flags & CONFIG_NETID)
|
||||
free(configs->netid.net);
|
||||
if (configs->flags & CONFIG_NAME)
|
||||
free(configs->hostname);
|
||||
|
||||
*up = configs->next;
|
||||
free(configs);
|
||||
}
|
||||
else
|
||||
up = &configs->next;
|
||||
}
|
||||
|
||||
one_file(daemon->dhcp_hosts_file, 1, 1);
|
||||
|
||||
for (count = 0, configs = daemon->dhcp_conf; configs; configs = configs->next)
|
||||
{
|
||||
if (configs->flags & CONFIG_BANK)
|
||||
{
|
||||
char *domain;
|
||||
count++;
|
||||
|
||||
for (cp = configs->next; cp; cp = cp->next)
|
||||
if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("duplicate IP address %s in %s."), inet_ntoa(cp->addr), daemon->dhcp_hosts_file);
|
||||
configs->flags &= ~CONFIG_ADDR;
|
||||
}
|
||||
|
||||
if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
|
||||
{
|
||||
my_syslog(LOG_ERR, _("illegal domain %s in %s."), domain, daemon->dhcp_hosts_file);
|
||||
free(configs->hostname);
|
||||
configs->flags &= ~CONFIG_NAME;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my_syslog(LOG_INFO, _("read %s - %d hosts"), daemon->dhcp_hosts_file, count);
|
||||
|
||||
}
|
||||
|
||||
void dhcp_update_configs(struct dhcp_config *configs)
|
||||
@@ -806,8 +863,8 @@ void dhcp_update_configs(struct dhcp_config *configs)
|
||||
(crec->flags & F_HOSTS))
|
||||
{
|
||||
if (config_find_by_address(configs, crec->addr.addr.addr.addr4))
|
||||
syslog(LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
|
||||
inet_ntoa(crec->addr.addr.addr.addr4), config->hostname);
|
||||
my_syslog(LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
|
||||
inet_ntoa(crec->addr.addr.addr.addr4), config->hostname);
|
||||
else
|
||||
{
|
||||
config->addr = crec->addr.addr.addr.addr4;
|
||||
@@ -819,7 +876,7 @@ void dhcp_update_configs(struct dhcp_config *configs)
|
||||
/* 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)
|
||||
char *host_from_dns(struct in_addr addr)
|
||||
{
|
||||
struct crec *lookup = cache_find_by_addr(NULL, (struct all_addr *)&addr, 0, F_IPV4);
|
||||
char *hostname = NULL;
|
||||
@@ -829,28 +886,25 @@ char *host_from_dns(struct daemon *daemon, struct in_addr addr)
|
||||
hostname = daemon->dhcp_buff;
|
||||
strncpy(hostname, cache_get_name(lookup), 256);
|
||||
hostname[255] = 0;
|
||||
hostname = strip_hostname(daemon, hostname);
|
||||
if (strip_hostname(hostname))
|
||||
hostname = NULL;
|
||||
}
|
||||
|
||||
|
||||
return hostname;
|
||||
}
|
||||
|
||||
char *strip_hostname(struct daemon *daemon, char *hostname)
|
||||
/* return illegal domain or NULL if OK */
|
||||
char *strip_hostname(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;
|
||||
|
||||
if (!dot)
|
||||
return NULL;
|
||||
|
||||
*dot = 0; /* truncate */
|
||||
|
||||
if (*(dot+1) && (!daemon->domain_suffix || !hostname_isequal(dot+1, daemon->domain_suffix)))
|
||||
return dot+1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
+375
-301
File diff suppressed because it is too large.
Load diff
+131
-66
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2005 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2007 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,7 +10,7 @@
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define COPYRIGHT "Copyright (C) 2000-2006 Simon Kelley"
|
||||
#define COPYRIGHT "Copyright (C) 2000-2007 Simon Kelley"
|
||||
|
||||
/* get these before config.h for IPv6 stuff... */
|
||||
#include <sys/types.h>
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <sys/select.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/un.h>
|
||||
#include <limits.h>
|
||||
#include <net/if.h>
|
||||
#include <unistd.h>
|
||||
@@ -81,6 +82,34 @@ extern int capset(cap_user_header_t header, cap_user_data_t data);
|
||||
#include <sys/prctl.h>
|
||||
#endif
|
||||
|
||||
/* daemon is function in teh C library.... */
|
||||
#define daemon dnsmasq_daemon
|
||||
|
||||
/* Async event queue */
|
||||
struct event_desc {
|
||||
int event, data;
|
||||
};
|
||||
|
||||
#define EVENT_RELOAD 1
|
||||
#define EVENT_DUMP 2
|
||||
#define EVENT_ALARM 3
|
||||
#define EVENT_TERM 4
|
||||
#define EVENT_CHILD 5
|
||||
#define EVENT_REOPEN 6
|
||||
#define EVENT_EXITED 7
|
||||
#define EVENT_KILLED 8
|
||||
#define EVENT_EXEC_ERR 9
|
||||
#define EVENT_PIPE_ERR 10
|
||||
|
||||
/* Exit codes. */
|
||||
#define EC_GOOD 0
|
||||
#define EC_BADCONF 1
|
||||
#define EC_BADNET 2
|
||||
#define EC_FILE 3
|
||||
#define EC_NOMEM 4
|
||||
#define EC_MISC 5
|
||||
#define EC_INIT_OFFSET 10
|
||||
|
||||
/* Min buffer size: we check after adding each record, so there must be
|
||||
memory for the largest packet, and the largest record so the
|
||||
min for DNS is PACKETSZ+MAXDNAME+RRFIXEDSZ which is < 1000.
|
||||
@@ -114,6 +143,9 @@ extern int capset(cap_user_header_t header, cap_user_data_t data);
|
||||
#define OPT_RELOAD (1<<24)
|
||||
#define OPT_TFTP (1<<25)
|
||||
#define OPT_TFTP_SECURE (1<<26)
|
||||
#define OPT_TFTP_NOBLOCK (1<<27)
|
||||
#define OPT_LOG_OPTS (1<<28)
|
||||
#define OPT_TFTP_APREF (1<<29)
|
||||
|
||||
struct all_addr {
|
||||
union {
|
||||
@@ -153,6 +185,12 @@ struct ptr_record {
|
||||
struct ptr_record *next;
|
||||
};
|
||||
|
||||
struct interface_name {
|
||||
char *name; /* domain name */
|
||||
char *intr; /* interface name */
|
||||
struct interface_name *next;
|
||||
};
|
||||
|
||||
union bigname {
|
||||
char name[MAXDNAME];
|
||||
union bigname *next; /* freelist */
|
||||
@@ -220,15 +258,14 @@ union mysockaddr {
|
||||
#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_HAS_DOMAIN 8 /* server for one domain only */
|
||||
#define SERV_HAS_SOURCE 16 /* source address defined */
|
||||
#define SERV_FOR_NODOTS 32 /* server for names with no domain part only */
|
||||
#define SERV_WARNED_RECURSIVE 64 /* avoid warning spam */
|
||||
#define SERV_FROM_DBUS 128 /* 1 if source is DBus */
|
||||
#define SERV_MARK 256 /* for mark-and-delete */
|
||||
#define SERV_TYPE (SERV_HAS_DOMAIN | SERV_FOR_NODOTS)
|
||||
|
||||
|
||||
struct serverfd {
|
||||
int fd;
|
||||
union mysockaddr source_addr;
|
||||
@@ -355,6 +392,7 @@ struct dhcp_config {
|
||||
#define CONFIG_FROM_ETHERS 256 /* entry created by /etc/ethers */
|
||||
#define CONFIG_ADDR_HOSTS 512 /* address added by from /etc/hosts */
|
||||
#define CONFIG_DECLINED 1024 /* address declined by client */
|
||||
#define CONFIG_BANK 2048 /* from dhcp hosts file */
|
||||
|
||||
struct dhcp_opt {
|
||||
int opt, len, flags;
|
||||
@@ -365,6 +403,9 @@ struct dhcp_opt {
|
||||
|
||||
#define DHOPT_ADDR 1
|
||||
#define DHOPT_STRING 2
|
||||
#define DHOPT_ENCAPSULATE 4
|
||||
#define DHOPT_VENDOR_MATCH 8
|
||||
#define DHOPT_FORCE 16
|
||||
|
||||
struct dhcp_boot {
|
||||
char *file, *sname;
|
||||
@@ -373,8 +414,15 @@ struct dhcp_boot {
|
||||
struct dhcp_boot *next;
|
||||
};
|
||||
|
||||
#define MATCH_VENDOR 1
|
||||
#define MATCH_USER 2
|
||||
#define MATCH_CIRCUIT 3
|
||||
#define MATCH_REMOTE 4
|
||||
#define MATCH_SUBSCRIBER 5
|
||||
|
||||
/* vendorclass, userclass, remote-id or cicuit-id */
|
||||
struct dhcp_vendor {
|
||||
int len, is_vendor;
|
||||
int len, match_type;
|
||||
char *data;
|
||||
struct dhcp_netid netid;
|
||||
struct dhcp_vendor *next;
|
||||
@@ -433,6 +481,8 @@ struct ping_result {
|
||||
struct tftp_file {
|
||||
int refcount, fd;
|
||||
off_t size;
|
||||
dev_t dev;
|
||||
ino_t inode;
|
||||
char filename[];
|
||||
};
|
||||
|
||||
@@ -447,7 +497,7 @@ struct tftp_transfer {
|
||||
struct tftp_transfer *next;
|
||||
};
|
||||
|
||||
struct daemon {
|
||||
extern struct daemon {
|
||||
/* datastuctures representing the command-line and
|
||||
config file arguments. All set (including defaults)
|
||||
in option.c */
|
||||
@@ -457,6 +507,7 @@ struct daemon {
|
||||
struct mx_srv_record *mxnames;
|
||||
struct txt_record *txt;
|
||||
struct ptr_record *ptr;
|
||||
struct interface_name *int_names;
|
||||
char *mxtarget;
|
||||
char *lease_file;
|
||||
char *username, *groupname;
|
||||
@@ -467,17 +518,20 @@ struct daemon {
|
||||
struct bogus_addr *bogus_addr;
|
||||
struct server *servers;
|
||||
int log_fac; /* log facility */
|
||||
char *log_file; /* optional log file */
|
||||
int max_logs; /* queue limit */
|
||||
int cachesize, ftabsize;
|
||||
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_opt *dhcp_opts;
|
||||
struct dhcp_vendor *dhcp_vendors;
|
||||
struct dhcp_mac *dhcp_macs;
|
||||
struct dhcp_boot *boot_config;
|
||||
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names;
|
||||
char *dhcp_hosts_file;
|
||||
int dhcp_max, tftp_max;
|
||||
unsigned int min_leasetime;
|
||||
struct doctor *doctors;
|
||||
@@ -520,10 +574,10 @@ struct daemon {
|
||||
/* TFTP stuff */
|
||||
struct tftp_transfer *tftp_trans;
|
||||
char *tftp_prefix;
|
||||
};
|
||||
} *daemon;
|
||||
|
||||
/* cache.c */
|
||||
void cache_init(int cachesize, int log);
|
||||
void cache_init(void);
|
||||
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,
|
||||
@@ -536,9 +590,9 @@ void cache_start_insert(void);
|
||||
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_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd);
|
||||
void cache_unhash_dhcp(void);
|
||||
void dump_cache(struct daemon *daemon, time_t now);
|
||||
void dump_cache(time_t now);
|
||||
char *cache_get_name(struct crec *crecp);
|
||||
|
||||
/* rfc1035.c */
|
||||
@@ -547,15 +601,14 @@ unsigned short extract_request(HEADER *header, size_t qlen,
|
||||
size_t setup_reply(HEADER *header, size_t qlen,
|
||||
struct all_addr *addrp, unsigned short flags,
|
||||
unsigned long local_ttl);
|
||||
void extract_addresses(HEADER *header, size_t qlen, char *namebuff,
|
||||
time_t now, struct daemon *daemon);
|
||||
size_t answer_request(HEADER *header, char *limit, size_t qlen, struct daemon *daemon,
|
||||
void extract_addresses(HEADER *header, size_t qlen, char *namebuff, time_t now);
|
||||
size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask, time_t now);
|
||||
int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
|
||||
struct bogus_addr *addr, time_t now);
|
||||
unsigned char *find_pseudoheader(HEADER *header, size_t plen,
|
||||
size_t *len, unsigned char **p, int *is_sign);
|
||||
int check_for_local_domain(char *name, time_t now, struct daemon *daemon);
|
||||
int check_for_local_domain(char *name, time_t now);
|
||||
unsigned int questions_crc(HEADER *header, size_t plen, char *buff);
|
||||
size_t resize_packet(HEADER *header, size_t plen,
|
||||
unsigned char *pheader, size_t hlen);
|
||||
@@ -565,9 +618,8 @@ unsigned short rand16(void);
|
||||
int legal_char(char c);
|
||||
int canonicalise(char *s);
|
||||
unsigned char *do_rfc1035_name(unsigned char *p, char *sval);
|
||||
void die(char *message, char *arg1);
|
||||
void complain(char *message, int lineno, char *file);
|
||||
void *safe_malloc(size_t size);
|
||||
void *whine_malloc(size_t size);
|
||||
int sa_len(union mysockaddr *addr);
|
||||
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
|
||||
int hostname_isequal(char *a, char *b);
|
||||
@@ -581,41 +633,52 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||
int memcmp_masked(unsigned char *a, unsigned char *b, int len,
|
||||
unsigned int mask);
|
||||
int expand_buf(struct iovec *iov, size_t size);
|
||||
char *print_mac(struct daemon *daemon, unsigned char *mac, int len);
|
||||
char *print_mac(char *buff, unsigned char *mac, int len);
|
||||
void bump_maxfd(int fd, int *max);
|
||||
void log_start(struct daemon *daemon);
|
||||
int read_write(int fd, unsigned char *packet, int size, int rw);
|
||||
|
||||
/* log.c */
|
||||
void die(char *message, char *arg1, int exit_code);
|
||||
void log_start(struct passwd *ent_pw);
|
||||
int log_reopen(char *log_file);
|
||||
void my_syslog(int priority, const char *format, ...);
|
||||
void set_log_writer(fd_set *set, int *maxfdp);
|
||||
void check_log_writer(fd_set *set);
|
||||
void flush_log(void);
|
||||
|
||||
/* option.c */
|
||||
struct daemon *read_opts (int argc, char **argv, char *compile_opts);
|
||||
void read_opts (int argc, char **argv, char *compile_opts);
|
||||
char *option_string(unsigned char opt);
|
||||
void one_file(char *file, int nest, int hosts);
|
||||
|
||||
/* forward.c */
|
||||
void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now);
|
||||
void receive_query(struct listener *listen, struct daemon *daemon, time_t now);
|
||||
unsigned char *tcp_request(struct daemon *daemon, int confd, time_t now,
|
||||
void reply_query(struct serverfd *sfd, time_t now);
|
||||
void receive_query(struct listener *listen, time_t now);
|
||||
unsigned char *tcp_request(int confd, time_t now,
|
||||
struct in_addr local_addr, struct in_addr netmask);
|
||||
void server_gone(struct daemon *daemon, struct server *server);
|
||||
struct frec *get_new_frec(struct daemon *daemon, time_t now, int *wait);
|
||||
void server_gone(struct server *server);
|
||||
struct frec *get_new_frec(time_t now, int *wait);
|
||||
|
||||
/* network.c */
|
||||
struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds);
|
||||
int reload_servers(char *fname, struct daemon *daemon);
|
||||
void check_servers(struct daemon *daemon);
|
||||
int enumerate_interfaces(struct daemon *daemon);
|
||||
struct listener *create_wildcard_listeners(int port, int have_tftp);
|
||||
struct listener *create_bound_listeners(struct daemon *daemon);
|
||||
int iface_check(struct daemon *daemon, int family, struct all_addr *addr,
|
||||
int reload_servers(char *fname);
|
||||
void check_servers(void);
|
||||
int enumerate_interfaces();
|
||||
struct listener *create_wildcard_listeners(void);
|
||||
struct listener *create_bound_listeners(void);
|
||||
int iface_check(int family, struct all_addr *addr,
|
||||
struct ifreq *ifr, int *indexp);
|
||||
int fix_fd(int fd);
|
||||
struct in_addr get_ifaddr(char *intr);
|
||||
|
||||
/* dhcp.c */
|
||||
void dhcp_init(struct daemon *daemon);
|
||||
void dhcp_packet(struct daemon *daemon, time_t now);
|
||||
void dhcp_init(void);
|
||||
void dhcp_packet(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 negonly);
|
||||
int address_allocate(struct dhcp_context *context, struct daemon *daemon,
|
||||
int address_allocate(struct dhcp_context *context,
|
||||
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
|
||||
struct dhcp_netid *netids, time_t now);
|
||||
struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
@@ -624,15 +687,16 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
unsigned char *hwaddr, int hw_len,
|
||||
int hw_type, char *hostname);
|
||||
void dhcp_update_configs(struct dhcp_config *configs);
|
||||
void dhcp_read_ethers(struct daemon *daemon);
|
||||
void dhcp_read_ethers(void);
|
||||
void dhcp_read_hosts(void);
|
||||
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);
|
||||
char *strip_hostname(char *hostname);
|
||||
char *host_from_dns(struct in_addr addr);
|
||||
|
||||
/* lease.c */
|
||||
void lease_update_file(struct daemon *daemon, time_t now);
|
||||
void lease_update_dns(struct daemon *daemon);
|
||||
void lease_init(struct daemon *daemon, time_t now);
|
||||
void lease_update_file(time_t now);
|
||||
void lease_update_dns();
|
||||
void lease_init(time_t now);
|
||||
struct dhcp_lease *lease_allocate(struct in_addr addr);
|
||||
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||
unsigned char *clid, int hw_len, int hw_type, int clid_len);
|
||||
@@ -643,57 +707,58 @@ struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int h
|
||||
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 daemon *daemon);
|
||||
int do_script_run(struct daemon *daemon);
|
||||
void lease_update_from_configs(void);
|
||||
int do_script_run(time_t now);
|
||||
void rerun_scripts(void);
|
||||
|
||||
/* rfc2131.c */
|
||||
size_t dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_name, size_t sz, time_t now, int unicast_dest);
|
||||
size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
size_t sz, time_t now, int unicast_dest, int *is_inform);
|
||||
|
||||
/* dnsmasq.c */
|
||||
int make_icmp_sock(void);
|
||||
int icmp_ping(struct daemon *daemon, struct in_addr addr);
|
||||
void clear_cache_and_reload(struct daemon *daemon, time_t now);
|
||||
int icmp_ping(struct in_addr addr);
|
||||
void send_event(int fd, int event, int data);
|
||||
void clear_cache_and_reload(time_t now);
|
||||
|
||||
/* isc.c */
|
||||
#ifdef HAVE_ISC_READER
|
||||
void load_dhcp(struct daemon *daemon, time_t now);
|
||||
void load_dhcp(time_t now);
|
||||
#endif
|
||||
|
||||
/* netlink.c */
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
void netlink_init(struct daemon *daemon);
|
||||
int iface_enumerate(struct daemon *daemon, void *parm,
|
||||
int (*ipv4_callback)(), int (*ipv6_callback)());
|
||||
void netlink_multicast(struct daemon *daemon);
|
||||
void netlink_init(void);
|
||||
int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)());
|
||||
void netlink_multicast(void);
|
||||
#endif
|
||||
|
||||
/* bpf.c */
|
||||
#ifndef HAVE_LINUX_NETWORK
|
||||
void init_bpf(struct daemon *daemon);
|
||||
void send_via_bpf(struct daemon *daemon, struct dhcp_packet *mess, size_t len,
|
||||
void init_bpf(void);
|
||||
void send_via_bpf(struct dhcp_packet *mess, size_t len,
|
||||
struct in_addr iface_addr, struct ifreq *ifr);
|
||||
int iface_enumerate(struct daemon *daemon, void *parm,
|
||||
int (*ipv4_callback)(), int (*ipv6_callback)());
|
||||
int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)());
|
||||
#endif
|
||||
|
||||
/* dbus.c */
|
||||
#ifdef HAVE_DBUS
|
||||
char *dbus_init(struct daemon *daemon);
|
||||
void check_dbus_listeners(struct daemon *daemon,
|
||||
fd_set *rset, fd_set *wset, fd_set *eset);
|
||||
void set_dbus_listeners(struct daemon *daemon, int *maxfdp,
|
||||
fd_set *rset, fd_set *wset, fd_set *eset);
|
||||
char *dbus_init(void);
|
||||
void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset);
|
||||
void set_dbus_listeners(int *maxfdp, fd_set *rset, fd_set *wset, fd_set *eset);
|
||||
#endif
|
||||
|
||||
/* helper.c */
|
||||
int create_helper(struct daemon *daemon);
|
||||
void helper_write(struct daemon *daemon);
|
||||
void queue_script(struct daemon *daemon, int action,
|
||||
struct dhcp_lease *lease, char *hostname);
|
||||
#ifndef NO_FORK
|
||||
int create_helper(int log_fd, long max_fd);
|
||||
void helper_write(void);
|
||||
void queue_script(int action, struct dhcp_lease *lease,
|
||||
char *hostname, time_t now);
|
||||
int helper_buf_empty(void);
|
||||
#endif
|
||||
|
||||
/* tftp.c */
|
||||
#ifdef HAVE_TFTP
|
||||
void tftp_request(struct listener *listen, struct daemon *daemon, time_t now);
|
||||
void check_tftp_listeners(struct daemon *daemon, fd_set *rset, time_t now);
|
||||
void tftp_request(struct listener *listen, time_t now);
|
||||
void check_tftp_listeners(fd_set *rset, time_t now);
|
||||
#endif
|
||||
+33
-26
@@ -107,7 +107,7 @@ static void send_from(int fd, int nowild, char *packet, size_t len,
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned short search_servers(struct daemon *daemon, time_t now, struct all_addr **addrpp,
|
||||
static unsigned short search_servers(time_t now, struct all_addr **addrpp,
|
||||
unsigned short qtype, char *qdomain, int *type, char **domain)
|
||||
|
||||
{
|
||||
@@ -189,7 +189,7 @@ static unsigned short search_servers(struct daemon *daemon, time_t now, struct a
|
||||
/* don't forward simple names, make exception from NS queries and empty name. */
|
||||
flags = F_NXDOMAIN;
|
||||
|
||||
if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now, daemon))
|
||||
if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
|
||||
flags = F_NOERR;
|
||||
|
||||
if (flags == F_NXDOMAIN || flags == F_NOERR)
|
||||
@@ -199,7 +199,7 @@ static unsigned short search_servers(struct daemon *daemon, time_t now, struct a
|
||||
}
|
||||
|
||||
/* returns new last_server */
|
||||
static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *udpaddr,
|
||||
static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
struct all_addr *dst_addr, unsigned int dst_iface,
|
||||
HEADER *header, size_t plen, time_t now, struct frec *forward)
|
||||
{
|
||||
@@ -231,9 +231,9 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud
|
||||
else
|
||||
{
|
||||
if (gotname)
|
||||
flags = search_servers(daemon, now, &addrp, gotname, daemon->namebuff, &type, &domain);
|
||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain);
|
||||
|
||||
if (!flags && !(forward = get_new_frec(daemon, now, NULL)))
|
||||
if (!flags && !(forward = get_new_frec(now, NULL)))
|
||||
/* table full - server failure. */
|
||||
flags = F_NEG;
|
||||
|
||||
@@ -344,7 +344,7 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud
|
||||
return;
|
||||
}
|
||||
|
||||
static size_t process_reply(struct daemon *daemon, HEADER *header, time_t now,
|
||||
static size_t process_reply(HEADER *header, time_t now,
|
||||
struct server *server, size_t n)
|
||||
{
|
||||
unsigned char *pheader, *sizep;
|
||||
@@ -365,7 +365,7 @@ static size_t process_reply(struct daemon *daemon, HEADER *header, time_t now,
|
||||
PUTSHORT(daemon->edns_pktsz, psave);
|
||||
}
|
||||
|
||||
if (is_sign || header->opcode != QUERY || (header->rcode != NOERROR && header->rcode != NXDOMAIN))
|
||||
if (header->opcode != QUERY || (header->rcode != NOERROR && header->rcode != NXDOMAIN))
|
||||
return n;
|
||||
|
||||
/* Complain loudly if the upstream server is non-recursive. */
|
||||
@@ -373,7 +373,7 @@ static size_t process_reply(struct daemon *daemon, HEADER *header, time_t now,
|
||||
server && !(server->flags & SERV_WARNED_RECURSIVE))
|
||||
{
|
||||
prettyprint_addr(&server->addr, daemon->namebuff);
|
||||
syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
|
||||
my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
|
||||
if (!(daemon->options & OPT_LOG))
|
||||
server->flags |= SERV_WARNED_RECURSIVE;
|
||||
}
|
||||
@@ -389,7 +389,7 @@ static size_t process_reply(struct daemon *daemon, HEADER *header, time_t now,
|
||||
{
|
||||
if (header->rcode == NXDOMAIN &&
|
||||
extract_request(header, n, daemon->namebuff, NULL) &&
|
||||
check_for_local_domain(daemon->namebuff, now, daemon))
|
||||
check_for_local_domain(daemon->namebuff, now))
|
||||
{
|
||||
/* if we forwarded a query for a locally known name (because it was for
|
||||
an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
|
||||
@@ -399,7 +399,7 @@ static size_t process_reply(struct daemon *daemon, HEADER *header, time_t now,
|
||||
header->rcode = NOERROR;
|
||||
}
|
||||
|
||||
extract_addresses(header, n, daemon->namebuff, now, daemon);
|
||||
extract_addresses(header, n, daemon->namebuff, now);
|
||||
}
|
||||
|
||||
/* do this after extract_addresses. Ensure NODATA reply and remove
|
||||
@@ -419,7 +419,7 @@ static size_t process_reply(struct daemon *daemon, HEADER *header, time_t now,
|
||||
}
|
||||
|
||||
/* sets new last_server */
|
||||
void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now)
|
||||
void reply_query(struct serverfd *sfd, time_t now)
|
||||
{
|
||||
/* packet from peer server, extract data for cache, and send to
|
||||
original requester */
|
||||
@@ -447,7 +447,9 @@ void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now)
|
||||
{
|
||||
struct server *server = forward->sentto;
|
||||
|
||||
if ((header->rcode == SERVFAIL || header->rcode == REFUSED) && forward->forwardall == 0)
|
||||
if ((header->rcode == SERVFAIL || header->rcode == REFUSED) &&
|
||||
!(daemon->options & OPT_ORDER) &&
|
||||
forward->forwardall == 0)
|
||||
/* for broken servers, attempt to send to another one. */
|
||||
{
|
||||
unsigned char *pheader;
|
||||
@@ -465,7 +467,7 @@ void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now)
|
||||
{
|
||||
header->qr = 0;
|
||||
header->tc = 0;
|
||||
forward_query(daemon, -1, NULL, NULL, 0, header, nn, now, forward);
|
||||
forward_query(-1, NULL, NULL, 0, header, nn, now, forward);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -497,7 +499,7 @@ void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now)
|
||||
if (forward->forwardall == 0 || --forward->forwardall == 1 ||
|
||||
(header->rcode != REFUSED && header->rcode != SERVFAIL))
|
||||
{
|
||||
if ((nn = process_reply(daemon, header, now, server, (size_t)n)))
|
||||
if ((nn = process_reply(header, now, server, (size_t)n)))
|
||||
{
|
||||
header->id = htons(forward->orig_id);
|
||||
header->ra = 1; /* recursion if available */
|
||||
@@ -509,7 +511,7 @@ void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
void receive_query(struct listener *listen, time_t now)
|
||||
{
|
||||
HEADER *header = (HEADER *)daemon->packet;
|
||||
union mysockaddr source_addr;
|
||||
@@ -626,7 +628,7 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (!iface_check(daemon, listen->family, &dst_addr, &ifr, &if_index))
|
||||
if (!iface_check(listen->family, &dst_addr, &ifr, &if_index))
|
||||
return;
|
||||
|
||||
if (listen->family == AF_INET &&
|
||||
@@ -649,12 +651,12 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
#endif
|
||||
}
|
||||
|
||||
m = answer_request (header, ((char *) header) + PACKETSZ, (size_t)n, daemon,
|
||||
m = answer_request (header, ((char *) header) + PACKETSZ, (size_t)n,
|
||||
dst_addr_4, netmask, now);
|
||||
if (m >= 1)
|
||||
send_from(listen->fd, daemon->options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr, if_index);
|
||||
else
|
||||
forward_query(daemon, listen->fd, &source_addr, &dst_addr, if_index,
|
||||
forward_query(listen->fd, &source_addr, &dst_addr, if_index,
|
||||
header, (size_t)n, now, NULL);
|
||||
}
|
||||
|
||||
@@ -662,7 +664,7 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
blocking as neccessary, and then return. Note, need to be a bit careful
|
||||
about resources for debug mode, when the fork is suppressed: that's
|
||||
done by the caller. */
|
||||
unsigned char *tcp_request(struct daemon *daemon, int confd, time_t now,
|
||||
unsigned char *tcp_request(int confd, time_t now,
|
||||
struct in_addr local_addr, struct in_addr netmask)
|
||||
{
|
||||
int size = 0;
|
||||
@@ -670,7 +672,7 @@ unsigned char *tcp_request(struct daemon *daemon, int confd, time_t now,
|
||||
unsigned short qtype, gotname;
|
||||
unsigned char c1, c2;
|
||||
/* Max TCP packet + slop */
|
||||
unsigned char *packet = malloc(65536 + MAXDNAME + RRFIXEDSZ);
|
||||
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ);
|
||||
HEADER *header;
|
||||
struct server *last_server;
|
||||
|
||||
@@ -706,8 +708,11 @@ unsigned char *tcp_request(struct daemon *daemon, int confd, time_t now,
|
||||
}
|
||||
|
||||
/* m > 0 if answered from cache */
|
||||
m = answer_request(header, ((char *) header) + 65536, (unsigned int)size, daemon,
|
||||
m = answer_request(header, ((char *) header) + 65536, (unsigned int)size,
|
||||
local_addr, netmask, now);
|
||||
|
||||
/* Do this by steam now we're not in the select() loop */
|
||||
check_log_writer(NULL);
|
||||
|
||||
if (m == 0)
|
||||
{
|
||||
@@ -717,7 +722,7 @@ unsigned char *tcp_request(struct daemon *daemon, int confd, time_t now,
|
||||
char *domain = NULL;
|
||||
|
||||
if (gotname)
|
||||
flags = search_servers(daemon, now, &addrp, gotname, daemon->namebuff, &type, &domain);
|
||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain);
|
||||
|
||||
if (type != 0 || (daemon->options & OPT_ORDER) || !daemon->last_server)
|
||||
last_server = daemon->servers;
|
||||
@@ -797,7 +802,7 @@ unsigned char *tcp_request(struct daemon *daemon, int confd, time_t now,
|
||||
someone might be attempting to insert bogus values into the cache by
|
||||
sending replies containing questions and bogus answers. */
|
||||
if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff))
|
||||
m = process_reply(daemon, header, now, last_server, (unsigned int)m);
|
||||
m = process_reply(header, now, last_server, (unsigned int)m);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -807,6 +812,8 @@ unsigned char *tcp_request(struct daemon *daemon, int confd, time_t now,
|
||||
if (m == 0)
|
||||
m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
|
||||
}
|
||||
|
||||
check_log_writer(NULL);
|
||||
|
||||
c1 = m>>8;
|
||||
c2 = m;
|
||||
@@ -821,7 +828,7 @@ static struct frec *allocate_frec(time_t now)
|
||||
{
|
||||
struct frec *f;
|
||||
|
||||
if ((f = (struct frec *)malloc(sizeof(struct frec))))
|
||||
if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
|
||||
{
|
||||
f->next = frec_list;
|
||||
f->time = now;
|
||||
@@ -835,7 +842,7 @@ static struct frec *allocate_frec(time_t now)
|
||||
/* if wait==NULL return a free or older than TIMEOUT record.
|
||||
else return *wait zero if one available, or *wait is delay to
|
||||
when the oldest in-use record will expire. */
|
||||
struct frec *get_new_frec(struct daemon *daemon, time_t now, int *wait)
|
||||
struct frec *get_new_frec(time_t now, int *wait)
|
||||
{
|
||||
struct frec *f, *oldest;
|
||||
int count;
|
||||
@@ -916,7 +923,7 @@ static struct frec *lookup_frec_by_sender(unsigned short id,
|
||||
}
|
||||
|
||||
/* A server record is going away, remove references to it */
|
||||
void server_gone(struct daemon *daemon, struct server *server)
|
||||
void server_gone(struct server *server)
|
||||
{
|
||||
struct frec *f;
|
||||
|
||||
|
||||
+78
-50
@@ -24,11 +24,14 @@
|
||||
main process.
|
||||
*/
|
||||
|
||||
#ifndef NO_FORK
|
||||
|
||||
struct script_data
|
||||
{
|
||||
unsigned char action, hwaddr_len, hwaddr_type;
|
||||
unsigned char clid_len, hostname_len, uclass_len, vclass_len;
|
||||
struct in_addr addr;
|
||||
unsigned int remaining_time;
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
unsigned int length;
|
||||
#else
|
||||
@@ -37,51 +40,47 @@ struct script_data
|
||||
unsigned char hwaddr[DHCP_CHADDR_MAX];
|
||||
};
|
||||
|
||||
static struct script_data *buf;
|
||||
static size_t bytes_in_buf, buf_size;
|
||||
static struct script_data *buf = NULL;
|
||||
static size_t bytes_in_buf = 0, buf_size = 0;
|
||||
|
||||
int create_helper(struct daemon *daemon)
|
||||
int create_helper(int event_fd, long max_fd)
|
||||
{
|
||||
pid_t pid;
|
||||
int i, pipefd[2];
|
||||
struct sigaction sigact;
|
||||
|
||||
buf = NULL;
|
||||
buf_size = bytes_in_buf = 0;
|
||||
|
||||
if (!daemon->dhcp || !daemon->lease_change_command)
|
||||
return -1;
|
||||
|
||||
/* create the pipe through which the main program sends us commands,
|
||||
then fork our process. */
|
||||
if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
|
||||
return -1;
|
||||
|
||||
/* create the pipe through which the main program sends us commands,
|
||||
then fork our process. By now it's too late to die(), we just log
|
||||
any failure via the main process. */
|
||||
if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
|
||||
{
|
||||
send_event(event_fd, EVENT_PIPE_ERR, errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pid != 0)
|
||||
{
|
||||
close(pipefd[0]); /* close reader side */
|
||||
return pipefd[1];
|
||||
}
|
||||
|
||||
/* ignore SIGTERM, so that we can clean up when the main process gets hit */
|
||||
/* ignore SIGTERM, so that we can clean up when the main process gets hit
|
||||
and SIGALRM so that we can use sleep() */
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
sigact.sa_flags = 0;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigaction(SIGTERM, &sigact, NULL);
|
||||
sigaction(SIGALRM, &sigact, NULL);
|
||||
|
||||
/* close all the sockets etc, we don't need them here */
|
||||
for (i = 0; i < 64; i++)
|
||||
if (i != STDOUT_FILENO && i != STDERR_FILENO &&
|
||||
i != STDIN_FILENO && i != pipefd[0])
|
||||
close(i);
|
||||
|
||||
/* we open our own log connection. */
|
||||
log_start(daemon);
|
||||
for (max_fd--; max_fd > 0; max_fd--)
|
||||
if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO &&
|
||||
max_fd != STDIN_FILENO && max_fd != pipefd[0] && max_fd != event_fd)
|
||||
close(max_fd);
|
||||
|
||||
/* don't give our end of the pipe to our children */
|
||||
if ((i = fcntl(pipefd[0], F_GETFD)) != -1)
|
||||
fcntl(pipefd[0], F_SETFD, i | FD_CLOEXEC);
|
||||
|
||||
/* loop here */
|
||||
while(1)
|
||||
{
|
||||
@@ -133,18 +132,36 @@ int create_helper(struct daemon *daemon)
|
||||
if (!read_write(pipefd[0], buf, data.hostname_len + data.uclass_len + data.vclass_len, 1))
|
||||
continue;
|
||||
|
||||
if ((pid = fork()) == -1)
|
||||
continue;
|
||||
/* possible fork errors are all temporary resource problems */
|
||||
while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
|
||||
sleep(2);
|
||||
|
||||
if (pid == -1)
|
||||
continue;
|
||||
|
||||
/* wait for child to complete */
|
||||
if (pid != 0)
|
||||
{
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
if (WIFSIGNALED(status))
|
||||
syslog(LOG_WARNING, _("child process killed by signal %d"), WTERMSIG(status));
|
||||
else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
|
||||
syslog(LOG_WARNING, _("child process exited with status %d"), WEXITSTATUS(status));
|
||||
/* reap our children's children, if necessary */
|
||||
while (1)
|
||||
{
|
||||
int status;
|
||||
pid_t rc = wait(&status);
|
||||
|
||||
if (rc == pid)
|
||||
{
|
||||
/* On error send event back to main process for logging */
|
||||
if (WIFSIGNALED(status))
|
||||
send_event(event_fd, EVENT_KILLED, WTERMSIG(status));
|
||||
else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
|
||||
send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status));
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc == -1 && errno != EINTR)
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -192,11 +209,15 @@ int create_helper(struct daemon *daemon)
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(daemon->dhcp_buff2, "%u ", data.remaining_time);
|
||||
setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, 1);
|
||||
|
||||
if (data.hostname_len != 0)
|
||||
{
|
||||
hostname = (char *)buf;
|
||||
hostname[data.hostname_len - 1] = 0;
|
||||
canonicalise(hostname);
|
||||
if (!canonicalise(hostname))
|
||||
hostname = NULL;
|
||||
}
|
||||
|
||||
if (data.action == ACTION_OLD_HOSTNAME && hostname)
|
||||
@@ -206,25 +227,29 @@ int create_helper(struct daemon *daemon)
|
||||
}
|
||||
else
|
||||
unsetenv("DNSMASQ_OLD_HOSTNAME");
|
||||
|
||||
|
||||
/* we need to have the event_fd around if exec fails */
|
||||
if ((i = fcntl(event_fd, F_GETFD)) != -1)
|
||||
fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
|
||||
close(pipefd[0]);
|
||||
|
||||
p = strrchr(daemon->lease_change_command, '/');
|
||||
execl(daemon->lease_change_command,
|
||||
p ? p+1 : daemon->lease_change_command,
|
||||
action_str, daemon->dhcp_buff, inet_ntoa(data.addr), hostname, (char*)NULL);
|
||||
|
||||
/* log socket should still be open, right? */
|
||||
syslog(LOG_ERR, _("failed to execute %s: %m"),
|
||||
daemon->lease_change_command);
|
||||
/* failed, send event so the main process logs the problem */
|
||||
send_event(event_fd, EVENT_EXEC_ERR, errno);
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* pack up lease data into a buffer */
|
||||
void queue_script(struct daemon *daemon, int action, struct dhcp_lease *lease, char *hostname)
|
||||
void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
|
||||
{
|
||||
unsigned char *p;
|
||||
size_t size;
|
||||
unsigned int hostname_len = 0, clid_len = 0, vclass_len = 0, uclass_len = 0;
|
||||
unsigned int i, hostname_len = 0, clid_len = 0, vclass_len = 0, uclass_len = 0;
|
||||
|
||||
/* no script */
|
||||
if (daemon->helperfd == -1)
|
||||
@@ -249,7 +274,7 @@ void queue_script(struct daemon *daemon, int action, struct dhcp_lease *lease, c
|
||||
if (size < sizeof(struct script_data) + 200)
|
||||
size = sizeof(struct script_data) + 200;
|
||||
|
||||
if (!(new = malloc(size)))
|
||||
if (!(new = whine_malloc(size)))
|
||||
return;
|
||||
if (buf)
|
||||
free(buf);
|
||||
@@ -271,29 +296,31 @@ void queue_script(struct daemon *daemon, int action, struct dhcp_lease *lease, c
|
||||
#else
|
||||
buf->expires = lease->expires;
|
||||
#endif
|
||||
|
||||
buf->remaining_time = (unsigned int)difftime(lease->expires, now);
|
||||
|
||||
p = (unsigned char *)(buf+1);
|
||||
if (buf->clid_len != 0)
|
||||
if (clid_len != 0)
|
||||
{
|
||||
memcpy(p, lease->clid, clid_len);
|
||||
p += clid_len;
|
||||
}
|
||||
if (buf->vclass_len != 0)
|
||||
if (vclass_len != 0)
|
||||
{
|
||||
memcpy(p, lease->vendorclass, vclass_len);
|
||||
p += vclass_len;
|
||||
}
|
||||
if (buf->uclass_len != 0)
|
||||
if (uclass_len != 0)
|
||||
{
|
||||
memcpy(p, lease->userclass, uclass_len);
|
||||
p += uclass_len;
|
||||
}
|
||||
if (buf->hostname_len != 0)
|
||||
{
|
||||
memcpy(p, hostname, hostname_len);
|
||||
p += hostname_len;
|
||||
}
|
||||
|
||||
/* substitute * for space */
|
||||
for (i = 0; i < hostname_len; i++)
|
||||
if ((daemon->options & OPT_LEASE_RO) && hostname[i] == ' ')
|
||||
*(p++) = '*';
|
||||
else
|
||||
*(p++) = hostname[i];
|
||||
|
||||
bytes_in_buf = p - (unsigned char *)buf;
|
||||
}
|
||||
|
||||
@@ -302,7 +329,7 @@ int helper_buf_empty(void)
|
||||
return bytes_in_buf == 0;
|
||||
}
|
||||
|
||||
void helper_write(struct daemon *daemon)
|
||||
void helper_write(void)
|
||||
{
|
||||
ssize_t rc;
|
||||
|
||||
@@ -323,5 +350,6 @@ void helper_write(struct daemon *daemon)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ static int next_token (char *token, int buffsize, FILE * fp)
|
||||
return count ? 1 : 0;
|
||||
}
|
||||
|
||||
void load_dhcp(struct daemon *daemon, time_t now)
|
||||
void load_dhcp(time_t now)
|
||||
{
|
||||
char *hostname = daemon->namebuff;
|
||||
char token[MAXTOK], *dot;
|
||||
@@ -70,7 +70,7 @@ void load_dhcp(struct daemon *daemon, time_t now)
|
||||
if (stat(daemon->lease_file, &statbuf) == -1)
|
||||
{
|
||||
if (!logged_lease)
|
||||
syslog(LOG_WARNING, _("failed to access %s: %m"), daemon->lease_file);
|
||||
my_syslog(LOG_WARNING, _("failed to access %s: %s"), daemon->lease_file, strerror(errno));
|
||||
logged_lease = 1;
|
||||
return;
|
||||
}
|
||||
@@ -86,11 +86,11 @@ void load_dhcp(struct daemon *daemon, time_t now)
|
||||
|
||||
if (!(fp = fopen (daemon->lease_file, "r")))
|
||||
{
|
||||
syslog (LOG_ERR, _("failed to load %s: %m"), daemon->lease_file);
|
||||
my_syslog (LOG_ERR, _("failed to load %s: %s"), daemon->lease_file, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
syslog (LOG_INFO, _("reading %s"), daemon->lease_file);
|
||||
my_syslog (LOG_INFO, _("reading %s"), daemon->lease_file);
|
||||
|
||||
while ((next_token(token, MAXTOK, fp)))
|
||||
{
|
||||
@@ -112,7 +112,7 @@ void load_dhcp(struct daemon *daemon, time_t now)
|
||||
if (!canonicalise(hostname))
|
||||
{
|
||||
*hostname = 0;
|
||||
syslog(LOG_ERR, _("bad name in %s"), daemon->lease_file);
|
||||
my_syslog(LOG_ERR, _("bad name in %s"), daemon->lease_file);
|
||||
}
|
||||
}
|
||||
else if ((strcmp(token, "ends") == 0) ||
|
||||
@@ -173,9 +173,9 @@ void load_dhcp(struct daemon *daemon, time_t now)
|
||||
{
|
||||
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"),
|
||||
hostname);
|
||||
my_syslog(LOG_WARNING,
|
||||
_("Ignoring DHCP lease for %s because it has an illegal domain part"),
|
||||
hostname);
|
||||
continue;
|
||||
}
|
||||
*dot = 0;
|
||||
@@ -189,20 +189,20 @@ void load_dhcp(struct daemon *daemon, time_t now)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!lease && (lease = malloc(sizeof(struct isc_lease))))
|
||||
if (!lease && (lease = whine_malloc(sizeof(struct isc_lease))))
|
||||
{
|
||||
lease->expires = ttd;
|
||||
lease->addr = host_address;
|
||||
lease->fqdn = NULL;
|
||||
lease->next = leases;
|
||||
if (!(lease->name = malloc(strlen(hostname)+1)))
|
||||
if (!(lease->name = whine_malloc(strlen(hostname)+1)))
|
||||
free(lease);
|
||||
else
|
||||
{
|
||||
leases = lease;
|
||||
strcpy(lease->name, hostname);
|
||||
if (daemon->domain_suffix &&
|
||||
(lease->fqdn = malloc(strlen(hostname) + strlen(daemon->domain_suffix) + 2)))
|
||||
(lease->fqdn = whine_malloc(strlen(hostname) + strlen(daemon->domain_suffix) + 2)))
|
||||
{
|
||||
strcpy(lease->fqdn, hostname);
|
||||
strcat(lease->fqdn, ".");
|
||||
@@ -239,8 +239,8 @@ void load_dhcp(struct daemon *daemon, time_t now)
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
cache_add_dhcp_entry(daemon, lease->fqdn, &lease->addr, lease->expires);
|
||||
cache_add_dhcp_entry(daemon, lease->name, &lease->addr, lease->expires);
|
||||
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
|
||||
cache_add_dhcp_entry(lease->name, &lease->addr, lease->expires);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+93
-74
@@ -12,18 +12,22 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
static struct dhcp_lease *leases, *old_leases;
|
||||
static struct dhcp_lease *leases = NULL, *old_leases = NULL;
|
||||
static int dns_dirty, file_dirty, leases_left;
|
||||
|
||||
void lease_init(struct daemon *daemon, time_t now)
|
||||
void lease_init(time_t now)
|
||||
{
|
||||
unsigned long ei;
|
||||
struct in_addr addr;
|
||||
struct dhcp_lease *lease;
|
||||
int flags, clid_len, hw_len, hw_type;
|
||||
int clid_len, hw_len, hw_type;
|
||||
FILE *leasestream;
|
||||
|
||||
leases = old_leases = NULL;
|
||||
/* 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);
|
||||
|
||||
leases_left = daemon->dhcp_max;
|
||||
|
||||
if (daemon->options & OPT_LEASE_RO)
|
||||
@@ -47,11 +51,7 @@ void lease_init(struct daemon *daemon, time_t now)
|
||||
leasestream = daemon->lease_stream = fopen(daemon->lease_file, "a+");
|
||||
|
||||
if (!leasestream)
|
||||
die(_("cannot open or create lease file %s: %s"), daemon->lease_file);
|
||||
|
||||
flags = fcntl(fileno(leasestream), F_GETFD);
|
||||
if (flags != -1)
|
||||
fcntl(fileno(leasestream), F_SETFD, flags | FD_CLOEXEC);
|
||||
die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE);
|
||||
|
||||
/* a+ mode lease pointer at end. */
|
||||
rewind(leasestream);
|
||||
@@ -77,10 +77,8 @@ void lease_init(struct daemon *daemon, time_t now)
|
||||
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
|
||||
|
||||
if (!(lease = lease_allocate(addr)))
|
||||
die (_("too many stored leases"), NULL);
|
||||
/* not actually new */
|
||||
lease->new = 0;
|
||||
|
||||
die (_("too many stored leases"), NULL, EC_MISC);
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
if (ei != 0)
|
||||
lease->expires = (time_t)ei + now;
|
||||
@@ -96,7 +94,17 @@ void lease_init(struct daemon *daemon, time_t now)
|
||||
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len);
|
||||
|
||||
if (strcmp(daemon->dhcp_buff, "*") != 0)
|
||||
lease_set_hostname(lease, daemon->dhcp_buff, daemon->domain_suffix, 0);
|
||||
{
|
||||
char *p;
|
||||
/* unprotect spaces */
|
||||
for (p = strchr(daemon->dhcp_buff, '*'); p; p = strchr(p, '*'))
|
||||
*p = ' ';
|
||||
lease_set_hostname(lease, daemon->dhcp_buff, daemon->domain_suffix, 0);
|
||||
}
|
||||
|
||||
/* set these correctly: the "old" events are generated later from
|
||||
the startup synthesised SIGHUP. */
|
||||
lease->new = lease->changed = 0;
|
||||
}
|
||||
|
||||
if (!daemon->lease_stream)
|
||||
@@ -110,13 +118,13 @@ void lease_init(struct daemon *daemon, time_t now)
|
||||
errno = ENOENT;
|
||||
else if (WEXITSTATUS(rc) == 126)
|
||||
errno = EACCES;
|
||||
die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command);
|
||||
die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command, EC_FILE);
|
||||
}
|
||||
|
||||
if (WEXITSTATUS(rc) != 0)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff, "%d", WEXITSTATUS(rc));
|
||||
die(_("lease-init script returned exit code %s"), daemon->dhcp_buff);
|
||||
die(_("lease-init script returned exit code %s"), daemon->dhcp_buff, WEXITSTATUS(rc) + EC_INIT_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +134,7 @@ void lease_init(struct daemon *daemon, time_t now)
|
||||
dns_dirty = 1;
|
||||
}
|
||||
|
||||
void lease_update_from_configs(struct daemon *daemon)
|
||||
void lease_update_from_configs(void)
|
||||
{
|
||||
/* changes to the config may change current leases. */
|
||||
|
||||
@@ -140,11 +148,11 @@ void lease_update_from_configs(struct daemon *daemon)
|
||||
(config->flags & CONFIG_NAME) &&
|
||||
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
|
||||
lease_set_hostname(lease, config->hostname, daemon->domain_suffix, 1);
|
||||
else if ((name = host_from_dns(daemon, lease->addr)))
|
||||
else if ((name = host_from_dns(lease->addr)))
|
||||
lease_set_hostname(lease, name, daemon->domain_suffix, 1); /* updates auth flag only */
|
||||
}
|
||||
|
||||
static void ourprintf(struct daemon *daemon, int *errp, char *format, ...)
|
||||
static void ourprintf(int *errp, char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
@@ -154,11 +162,12 @@ static void ourprintf(struct daemon *daemon, int *errp, char *format, ...)
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void lease_update_file(struct daemon *daemon, time_t now)
|
||||
void lease_update_file(time_t now)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
time_t next_event;
|
||||
int i, err = 0;
|
||||
char *p;
|
||||
|
||||
if (file_dirty != 0 && daemon->lease_stream)
|
||||
{
|
||||
@@ -170,29 +179,37 @@ void lease_update_file(struct daemon *daemon, time_t now)
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
ourprintf(daemon, &err, "%u ", lease->length);
|
||||
ourprintf(&err, "%u ", lease->length);
|
||||
#else
|
||||
ourprintf(daemon, &err, "%lu ", (unsigned long)lease->expires);
|
||||
ourprintf(&err, "%lu ", (unsigned long)lease->expires);
|
||||
#endif
|
||||
if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0)
|
||||
ourprintf(daemon, &err, "%.2x-", lease->hwaddr_type);
|
||||
ourprintf(&err, "%.2x-", lease->hwaddr_type);
|
||||
for (i = 0; i < lease->hwaddr_len; i++)
|
||||
{
|
||||
ourprintf(daemon, &err, "%.2x", lease->hwaddr[i]);
|
||||
ourprintf(&err, "%.2x", lease->hwaddr[i]);
|
||||
if (i != lease->hwaddr_len - 1)
|
||||
ourprintf(daemon, &err, ":");
|
||||
ourprintf(&err, ":");
|
||||
}
|
||||
ourprintf(daemon, &err, " %s %s ", inet_ntoa(lease->addr),
|
||||
lease->hostname && strlen(lease->hostname) != 0 ? lease->hostname : "*");
|
||||
|
||||
ourprintf(&err, " %s ", inet_ntoa(lease->addr));
|
||||
|
||||
/* substitute * for space: "*" is an illegal name, as is " " */
|
||||
if (lease->hostname)
|
||||
for (p = lease->hostname; *p; p++)
|
||||
ourprintf(&err, "%c", *p == ' ' ? '*' : *p);
|
||||
else
|
||||
ourprintf(&err, "*");
|
||||
ourprintf(&err, " ");
|
||||
|
||||
if (lease->clid && lease->clid_len != 0)
|
||||
{
|
||||
for (i = 0; i < lease->clid_len - 1; i++)
|
||||
ourprintf(daemon, &err, "%.2x:", lease->clid[i]);
|
||||
ourprintf(daemon, &err, "%.2x\n", lease->clid[i]);
|
||||
ourprintf(&err, "%.2x:", lease->clid[i]);
|
||||
ourprintf(&err, "%.2x\n", lease->clid[i]);
|
||||
}
|
||||
else
|
||||
ourprintf(daemon, &err, "*\n");
|
||||
ourprintf(&err, "*\n");
|
||||
}
|
||||
|
||||
if (fflush(daemon->lease_stream) != 0 ||
|
||||
@@ -214,16 +231,16 @@ void lease_update_file(struct daemon *daemon, time_t now)
|
||||
if (next_event == 0 || difftime(next_event, LEASE_RETRY + now) > 0.0)
|
||||
next_event = LEASE_RETRY + now;
|
||||
|
||||
syslog(LOG_ERR, _("failed to write %s: %s (retry in %us)"),
|
||||
daemon->lease_file, strerror(err),
|
||||
(unsigned int)difftime(next_event, now));
|
||||
my_syslog(LOG_ERR, _("failed to write %s: %s (retry in %us)"),
|
||||
daemon->lease_file, strerror(err),
|
||||
(unsigned int)difftime(next_event, now));
|
||||
}
|
||||
|
||||
if (next_event != 0)
|
||||
alarm((unsigned)difftime(next_event, now));
|
||||
}
|
||||
|
||||
void lease_update_dns(struct daemon *daemon)
|
||||
void lease_update_dns(void)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
@@ -233,8 +250,8 @@ void lease_update_dns(struct daemon *daemon)
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
cache_add_dhcp_entry(daemon, lease->fqdn, &lease->addr, lease->expires);
|
||||
cache_add_dhcp_entry(daemon, lease->hostname, &lease->addr, lease->expires);
|
||||
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
|
||||
cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires);
|
||||
}
|
||||
|
||||
dns_dirty = 0;
|
||||
@@ -306,13 +323,13 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
|
||||
struct dhcp_lease *lease_allocate(struct in_addr addr)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
if (!leases_left || !(lease = malloc(sizeof(struct dhcp_lease))))
|
||||
if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
|
||||
return NULL;
|
||||
|
||||
memset(lease, 0, sizeof(struct dhcp_lease));
|
||||
lease->new = 1;
|
||||
lease->addr = addr;
|
||||
lease->hwaddr_len = 225; /* illegal value */
|
||||
lease->hwaddr_len = 256; /* illegal value */
|
||||
lease->expires = 1;
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
lease->length = 0xffffffff; /* illegal value */
|
||||
@@ -378,9 +395,8 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||
if (lease->clid_len != clid_len)
|
||||
{
|
||||
lease->aux_changed = file_dirty = 1;
|
||||
if (lease->clid)
|
||||
free(lease->clid);
|
||||
if (!(lease->clid = malloc(clid_len)))
|
||||
free(lease->clid);
|
||||
if (!(lease->clid = whine_malloc(clid_len)))
|
||||
return;
|
||||
}
|
||||
else if (memcmp(lease->clid, clid, clid_len) != 0)
|
||||
@@ -420,8 +436,7 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix, int
|
||||
return;
|
||||
/* this shouldn't happen unless updates are very quick and the
|
||||
script very slow, we just avoid a memory leak if it does. */
|
||||
if (lease_tmp->old_hostname)
|
||||
free(lease_tmp->old_hostname);
|
||||
free(lease_tmp->old_hostname);
|
||||
lease_tmp->old_hostname = lease_tmp->hostname;
|
||||
lease_tmp->hostname = NULL;
|
||||
if (lease_tmp->fqdn)
|
||||
@@ -432,10 +447,10 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix, int
|
||||
break;
|
||||
}
|
||||
|
||||
if (!new_name && (new_name = malloc(strlen(name) + 1)))
|
||||
if (!new_name && (new_name = whine_malloc(strlen(name) + 1)))
|
||||
strcpy(new_name, name);
|
||||
|
||||
if (suffix && !new_fqdn && (new_fqdn = malloc(strlen(name) + strlen(suffix) + 2)))
|
||||
if (suffix && !new_fqdn && (new_fqdn = whine_malloc(strlen(name) + strlen(suffix) + 2)))
|
||||
{
|
||||
strcpy(new_fqdn, name);
|
||||
strcat(new_fqdn, ".");
|
||||
@@ -446,13 +461,11 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix, int
|
||||
if (lease->hostname)
|
||||
{
|
||||
/* run script to say we lost our old name */
|
||||
if (lease->old_hostname)
|
||||
free(lease->old_hostname);
|
||||
free(lease->old_hostname);
|
||||
lease->old_hostname = lease->hostname;
|
||||
}
|
||||
|
||||
if (lease->fqdn)
|
||||
free(lease->fqdn);
|
||||
free(lease->fqdn);
|
||||
|
||||
lease->hostname = new_name;
|
||||
lease->fqdn = new_fqdn;
|
||||
@@ -463,12 +476,20 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix, int
|
||||
lease->changed = 1; /* run script on change */
|
||||
}
|
||||
|
||||
void rerun_scripts(void)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
lease->changed = 1;
|
||||
}
|
||||
|
||||
/* deleted leases get transferred to the old_leases list.
|
||||
remove them here, after calling the lease change
|
||||
script. Also run the lease change script on new/modified leases.
|
||||
|
||||
Return zero if nothing to do. */
|
||||
int do_script_run(struct daemon *daemon)
|
||||
int do_script_run(time_t now)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
@@ -479,26 +500,25 @@ int do_script_run(struct daemon *daemon)
|
||||
/* If the lease still has an old_hostname, do the "old" action on that first */
|
||||
if (lease->old_hostname)
|
||||
{
|
||||
queue_script(daemon, ACTION_OLD_HOSTNAME, lease, lease->old_hostname);
|
||||
#ifndef NO_FORK
|
||||
queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
|
||||
#endif
|
||||
free(lease->old_hostname);
|
||||
lease->old_hostname = NULL;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
queue_script(daemon, ACTION_DEL, lease, lease->hostname);
|
||||
#ifndef NO_FORK
|
||||
queue_script(ACTION_DEL, lease, lease->hostname, now);
|
||||
#endif
|
||||
old_leases = lease->next;
|
||||
|
||||
if (lease->hostname)
|
||||
free(lease->hostname);
|
||||
if (lease->fqdn)
|
||||
free(lease->fqdn);
|
||||
if (lease->clid)
|
||||
free(lease->clid);
|
||||
if (lease->vendorclass)
|
||||
free(lease->vendorclass);
|
||||
if (lease->userclass)
|
||||
free(lease->userclass);
|
||||
free(lease->hostname);
|
||||
free(lease->fqdn);
|
||||
free(lease->clid);
|
||||
free(lease->vendorclass);
|
||||
free(lease->userclass);
|
||||
free(lease);
|
||||
|
||||
return 1;
|
||||
@@ -509,7 +529,9 @@ int do_script_run(struct daemon *daemon)
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if (lease->old_hostname)
|
||||
{
|
||||
queue_script(daemon, ACTION_OLD_HOSTNAME, lease, lease->old_hostname);
|
||||
#ifndef NO_FORK
|
||||
queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
|
||||
#endif
|
||||
free(lease->old_hostname);
|
||||
lease->old_hostname = NULL;
|
||||
return 1;
|
||||
@@ -519,21 +541,18 @@ int do_script_run(struct daemon *daemon)
|
||||
if (lease->new || lease->changed ||
|
||||
(lease->aux_changed && (daemon->options & OPT_LEASE_RO)))
|
||||
{
|
||||
queue_script(daemon, lease->new ? ACTION_ADD : ACTION_OLD, lease, lease->hostname);
|
||||
#ifndef NO_FORK
|
||||
queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease, lease->hostname, now);
|
||||
#endif
|
||||
lease->new = lease->changed = lease->aux_changed = 0;
|
||||
|
||||
/* these are used for the "add" call, then junked, since they're not in the database */
|
||||
if (lease->vendorclass)
|
||||
{
|
||||
free(lease->vendorclass);
|
||||
lease->vendorclass = NULL;
|
||||
}
|
||||
if (lease->userclass)
|
||||
{
|
||||
free(lease->userclass);
|
||||
lease->userclass = NULL;
|
||||
}
|
||||
free(lease->vendorclass);
|
||||
lease->vendorclass = NULL;
|
||||
|
||||
free(lease->userclass);
|
||||
lease->userclass = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,382 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2007 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.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
/* Implement logging to /dev/log asynchronously. If syslogd is
|
||||
making DNS lookups through dnsmasq, and dnsmasq blocks awaiting
|
||||
syslogd, then the two daemons can deadlock. We get around this
|
||||
by not blocking when talking to syslog, instead we queue up to
|
||||
MAX_LOGS messages. If more are queued, they will be dropped,
|
||||
and the drop event itself logged. */
|
||||
|
||||
/* The "wire" protocol for logging is defined in RFC 3164 */
|
||||
|
||||
/* From RFC 3164 */
|
||||
#define MAX_MESSAGE 1024
|
||||
|
||||
/* defaults in case we die() before we log_start() */
|
||||
static int log_fac = LOG_DAEMON;
|
||||
static int log_stderr = 0;
|
||||
static int log_fd = -1;
|
||||
static int log_to_file = 0;
|
||||
static int entries_alloced = 0;
|
||||
static int entries_lost = 0;
|
||||
static int connection_good = 1;
|
||||
static int max_logs = 0;
|
||||
static int connection_type = SOCK_DGRAM;
|
||||
|
||||
struct log_entry {
|
||||
int offset, length;
|
||||
pid_t pid; /* to avoid duplicates over a fork */
|
||||
struct log_entry *next;
|
||||
char payload[MAX_MESSAGE];
|
||||
};
|
||||
|
||||
static struct log_entry *entries = NULL;
|
||||
static struct log_entry *free_entries = NULL;
|
||||
|
||||
|
||||
void log_start(struct passwd *ent_pw)
|
||||
{
|
||||
log_stderr = !!(daemon->options & OPT_DEBUG);
|
||||
|
||||
if (daemon->log_fac != -1)
|
||||
log_fac = daemon->log_fac;
|
||||
#ifdef LOG_LOCAL0
|
||||
else if (daemon->options & OPT_DEBUG)
|
||||
log_fac = LOG_LOCAL0;
|
||||
#endif
|
||||
|
||||
if (daemon->log_file)
|
||||
{
|
||||
log_to_file = 1;
|
||||
daemon->max_logs = 0;
|
||||
}
|
||||
|
||||
max_logs = daemon->max_logs;
|
||||
|
||||
if (!log_reopen(daemon->log_file))
|
||||
die(_("cannot open %s: %s"), daemon->log_file ? daemon->log_file : "log", EC_FILE);
|
||||
|
||||
/* If we're running as root and going to change uid later,
|
||||
change the ownership here so that the file is always owned by
|
||||
the dnsmasq user. Then logrotate can just copy the owner.
|
||||
Failure of the chown call is OK, (for instance when started as non-root) */
|
||||
if (log_to_file && ent_pw && ent_pw->pw_uid != 0)
|
||||
fchown(log_fd, ent_pw->pw_uid, -1);
|
||||
|
||||
/* if queuing is inhibited, make sure we allocate
|
||||
the one required buffer now. */
|
||||
if (max_logs == 0)
|
||||
{
|
||||
free_entries = safe_malloc(sizeof(struct log_entry));
|
||||
free_entries->next = NULL;
|
||||
entries_alloced = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int log_reopen(char *log_file)
|
||||
{
|
||||
int flags;
|
||||
|
||||
if (log_fd != -1)
|
||||
close(log_fd);
|
||||
|
||||
/* NOTE: umask is set to 022 by the time this gets called */
|
||||
|
||||
if (log_file)
|
||||
log_fd = open(log_file, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
|
||||
else
|
||||
log_fd = socket(AF_UNIX, connection_type, 0);
|
||||
|
||||
if (log_fd == -1)
|
||||
return 0;
|
||||
|
||||
/* if max_logs is zero, leave the socket blocking */
|
||||
if (max_logs != 0 && (flags = fcntl(log_fd, F_GETFL)) != -1)
|
||||
fcntl(log_fd, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void free_entry(void)
|
||||
{
|
||||
struct log_entry *tmp = entries;
|
||||
entries = tmp->next;
|
||||
tmp->next = free_entries;
|
||||
free_entries = tmp;
|
||||
}
|
||||
|
||||
static void log_write(void)
|
||||
{
|
||||
ssize_t rc;
|
||||
|
||||
while (entries)
|
||||
{
|
||||
/* Avoid duplicates over a fork() */
|
||||
if (entries->pid != getpid())
|
||||
{
|
||||
free_entry();
|
||||
continue;
|
||||
}
|
||||
|
||||
connection_good = 1;
|
||||
|
||||
if ((rc = write(log_fd, entries->payload + entries->offset, entries->length)) != -1)
|
||||
{
|
||||
entries->length -= rc;
|
||||
entries->offset += rc;
|
||||
if (entries->length == 0)
|
||||
{
|
||||
free_entry();
|
||||
if (entries_lost != 0)
|
||||
{
|
||||
int e = entries_lost;
|
||||
entries_lost = 0; /* avoid wild recursion */
|
||||
my_syslog(LOG_WARNING, _("overflow: %d log entries lost"), e);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (errno == EAGAIN)
|
||||
return; /* syslogd busy, go again when select() or poll() says so */
|
||||
|
||||
if (errno == ENOBUFS)
|
||||
{
|
||||
connection_good = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* errors handling after this assumes sockets */
|
||||
if (!log_to_file)
|
||||
{
|
||||
/* Once a stream socket hits EPIPE, we have to close and re-open
|
||||
(we ignore SIGPIPE) */
|
||||
if (errno == EPIPE)
|
||||
{
|
||||
if (log_reopen(NULL))
|
||||
continue;
|
||||
}
|
||||
else if (errno == ECONNREFUSED ||
|
||||
errno == ENOTCONN ||
|
||||
errno == EDESTADDRREQ ||
|
||||
errno == ECONNRESET)
|
||||
{
|
||||
/* socket went (syslogd down?), try and reconnect. If we fail,
|
||||
stop trying until the next call to my_syslog()
|
||||
ECONNREFUSED -> connection went down
|
||||
ENOTCONN -> nobody listening
|
||||
(ECONNRESET, EDESTADDRREQ are *BSD equivalents) */
|
||||
|
||||
struct sockaddr_un logaddr;
|
||||
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
logaddr.sun_len = sizeof(logaddr) - sizeof(logaddr.sun_path) + strlen(_PATH_LOG) + 1;
|
||||
#endif
|
||||
logaddr.sun_family = AF_LOCAL;
|
||||
strncpy(logaddr.sun_path, _PATH_LOG, sizeof(logaddr.sun_path));
|
||||
|
||||
/* Got connection back? try again. */
|
||||
if (connect(log_fd, (struct sockaddr *)&logaddr, sizeof(logaddr)) != -1)
|
||||
continue;
|
||||
|
||||
/* errors from connect which mean we should keep trying */
|
||||
if (errno == ENOENT ||
|
||||
errno == EALREADY ||
|
||||
errno == ECONNREFUSED ||
|
||||
errno == EISCONN ||
|
||||
errno == EINTR ||
|
||||
errno == EAGAIN)
|
||||
{
|
||||
/* try again on next syslog() call */
|
||||
connection_good = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* try the other sort of socket... */
|
||||
if (errno == EPROTOTYPE)
|
||||
{
|
||||
connection_type = connection_type == SOCK_DGRAM ? SOCK_STREAM : SOCK_DGRAM;
|
||||
if (log_reopen(NULL))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* give up - fall back to syslog() - this handles out-of-space
|
||||
when logging to a file, for instance. */
|
||||
log_fd = -1;
|
||||
my_syslog(LOG_CRIT, _("log failed: %s"), strerror(errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void my_syslog(int priority, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
struct log_entry *entry;
|
||||
time_t time_now;
|
||||
char *p;
|
||||
size_t len;
|
||||
pid_t pid = getpid();
|
||||
|
||||
va_start(ap, format);
|
||||
|
||||
if (log_stderr)
|
||||
{
|
||||
fprintf(stderr, "dnsmasq: ");
|
||||
vfprintf(stderr, format, ap);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
if (log_fd == -1)
|
||||
{
|
||||
/* fall-back to syslog if we die during startup or fail during running. */
|
||||
static int isopen = 0;
|
||||
if (!isopen)
|
||||
{
|
||||
openlog("dnsmasq", LOG_PID, log_fac);
|
||||
isopen = 1;
|
||||
}
|
||||
vsyslog(priority, format, ap);
|
||||
va_end(ap);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((entry = free_entries))
|
||||
free_entries = entry->next;
|
||||
else if (entries_alloced < max_logs && (entry = malloc(sizeof(struct log_entry))))
|
||||
entries_alloced++;
|
||||
|
||||
if (!entry)
|
||||
entries_lost++;
|
||||
else
|
||||
{
|
||||
/* add to end of list, consumed from the start */
|
||||
entry->next = NULL;
|
||||
if (!entries)
|
||||
entries = entry;
|
||||
else
|
||||
{
|
||||
struct log_entry *tmp;
|
||||
for (tmp = entries; tmp->next; tmp = tmp->next);
|
||||
tmp->next = entry;
|
||||
}
|
||||
|
||||
time(&time_now);
|
||||
p = entry->payload;
|
||||
if (!log_to_file)
|
||||
p += sprintf(p, "<%d>", priority | log_fac);
|
||||
|
||||
p += sprintf(p, "%.15s dnsmasq[%d]: ", ctime(&time_now) + 4, pid);
|
||||
len = p - entry->payload;
|
||||
len += vsnprintf(p, MAX_MESSAGE - len, format, ap) + 1; /* include zero-terminator */
|
||||
entry->length = len > MAX_MESSAGE ? MAX_MESSAGE : len;
|
||||
entry->offset = 0;
|
||||
entry->pid = pid;
|
||||
|
||||
/* replace terminator with \n */
|
||||
if (log_to_file)
|
||||
entry->payload[entry->length - 1] = '\n';
|
||||
}
|
||||
|
||||
/* almost always, logging won't block, so try and write this now,
|
||||
to save collecting too many log messages during a select loop. */
|
||||
log_write();
|
||||
|
||||
/* Since we're doing things asynchronously, a cache-dump, for instance,
|
||||
can now generate log lines very fast. With a small buffer (desirable),
|
||||
that means it can overflow the log-buffer very quickly,
|
||||
so that the cache dump becomes mainly a count of how many lines
|
||||
overflowed. To avoid this, we delay here, the delay is controlled
|
||||
by queue-occupancy, and grows exponentially. The delay is limited to (2^8)ms.
|
||||
The scaling stuff ensures that when the queue is bigger than 8, the delay
|
||||
only occurs for the last 8 entries. Once the queue is full, we stop delaying
|
||||
to preserve performance.
|
||||
*/
|
||||
|
||||
if (entries && max_logs != 0)
|
||||
{
|
||||
int d;
|
||||
|
||||
for (d = 0,entry = entries; entry; entry = entry->next, d++);
|
||||
|
||||
if (d == max_logs)
|
||||
d = 0;
|
||||
else if (max_logs > 8)
|
||||
d -= max_logs - 8;
|
||||
|
||||
if (d > 0)
|
||||
{
|
||||
struct timespec waiter;
|
||||
waiter.tv_sec = 0;
|
||||
waiter.tv_nsec = 1000000 << (d - 1); /* 1 ms */
|
||||
nanosleep(&waiter, NULL);
|
||||
|
||||
/* Have another go now */
|
||||
log_write();
|
||||
}
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void set_log_writer(fd_set *set, int *maxfdp)
|
||||
{
|
||||
if (entries && log_fd != -1 && connection_good)
|
||||
{
|
||||
FD_SET(log_fd, set);
|
||||
bump_maxfd(log_fd, maxfdp);
|
||||
}
|
||||
}
|
||||
|
||||
void check_log_writer(fd_set *set)
|
||||
{
|
||||
if (log_fd != -1 && (!set || FD_ISSET(log_fd, set)))
|
||||
log_write();
|
||||
}
|
||||
|
||||
void flush_log(void)
|
||||
{
|
||||
/* block until queue empty */
|
||||
if (log_fd != -1)
|
||||
{
|
||||
int flags;
|
||||
if ((flags = fcntl(log_fd, F_GETFL)) != -1)
|
||||
fcntl(log_fd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
log_write();
|
||||
close(log_fd);
|
||||
}
|
||||
}
|
||||
|
||||
void die(char *message, char *arg1, int exit_code)
|
||||
{
|
||||
char *errmess = strerror(errno);
|
||||
|
||||
if (!arg1)
|
||||
arg1 = errmess;
|
||||
|
||||
log_stderr = 1; /* print as well as log when we die.... */
|
||||
fputc('\n', stderr); /* prettyfy startup-script message */
|
||||
my_syslog(LOG_CRIT, message, arg1, errmess);
|
||||
|
||||
log_stderr = 0;
|
||||
my_syslog(LOG_CRIT, _("FAILED to start up"));
|
||||
flush_log();
|
||||
|
||||
exit(exit_code);
|
||||
}
|
||||
+15
-21
@@ -29,9 +29,9 @@
|
||||
static struct iovec iov;
|
||||
|
||||
static void nl_err(struct nlmsghdr *h);
|
||||
static void nl_routechange(struct daemon *daemon, struct nlmsghdr *h);
|
||||
static void nl_routechange(struct nlmsghdr *h);
|
||||
|
||||
void netlink_init(struct daemon *daemon)
|
||||
void netlink_init(void)
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
|
||||
@@ -56,19 +56,13 @@ void netlink_init(struct daemon *daemon)
|
||||
}
|
||||
|
||||
if (daemon->netlinkfd == -1)
|
||||
die(_("cannot create netlink socket: %s"), NULL);
|
||||
else
|
||||
{
|
||||
int flags = fcntl(daemon->netlinkfd, F_GETFD);
|
||||
if (flags != -1)
|
||||
fcntl(daemon->netlinkfd, F_SETFD, flags | FD_CLOEXEC);
|
||||
}
|
||||
|
||||
die(_("cannot create netlink socket: %s"), NULL, EC_MISC);
|
||||
|
||||
iov.iov_len = 200;
|
||||
iov.iov_base = safe_malloc(iov.iov_len);
|
||||
}
|
||||
|
||||
static ssize_t netlink_recv(struct daemon *daemon)
|
||||
static ssize_t netlink_recv(void)
|
||||
{
|
||||
struct msghdr msg;
|
||||
ssize_t rc;
|
||||
@@ -107,7 +101,7 @@ static ssize_t netlink_recv(struct daemon *daemon)
|
||||
return rc;
|
||||
}
|
||||
|
||||
int iface_enumerate(struct daemon *daemon, void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
struct nlmsghdr *h;
|
||||
@@ -142,14 +136,14 @@ int iface_enumerate(struct daemon *daemon, void *parm, int (*ipv4_callback)(), i
|
||||
|
||||
while (1)
|
||||
{
|
||||
if ((len = netlink_recv(daemon)) == -1)
|
||||
if ((len = netlink_recv()) == -1)
|
||||
return 0;
|
||||
|
||||
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
|
||||
if (h->nlmsg_type == NLMSG_ERROR)
|
||||
nl_err(h);
|
||||
else if (h->nlmsg_seq != seq)
|
||||
nl_routechange(daemon, h); /* May be multicast arriving async */
|
||||
nl_routechange(h); /* May be multicast arriving async */
|
||||
else if (h->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -186,7 +180,7 @@ int iface_enumerate(struct daemon *daemon, void *parm, int (*ipv4_callback)(), i
|
||||
}
|
||||
|
||||
if (addr.s_addr && ipv4_callback)
|
||||
if (!((*ipv4_callback)(daemon, addr, ifa->ifa_index, netmask, broadcast, parm)))
|
||||
if (!((*ipv4_callback)(addr, ifa->ifa_index, netmask, broadcast, parm)))
|
||||
return 0;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -202,7 +196,7 @@ int iface_enumerate(struct daemon *daemon, void *parm, int (*ipv4_callback)(), i
|
||||
}
|
||||
|
||||
if (addrp && ipv6_callback)
|
||||
if (!((*ipv6_callback)(daemon, addrp, ifa->ifa_index, ifa->ifa_index, parm)))
|
||||
if (!((*ipv6_callback)(addrp, ifa->ifa_index, ifa->ifa_index, parm)))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -210,18 +204,18 @@ int iface_enumerate(struct daemon *daemon, void *parm, int (*ipv4_callback)(), i
|
||||
}
|
||||
}
|
||||
|
||||
void netlink_multicast(struct daemon *daemon)
|
||||
void netlink_multicast(void)
|
||||
{
|
||||
ssize_t len;
|
||||
struct nlmsghdr *h;
|
||||
|
||||
if ((len = netlink_recv(daemon)) != -1)
|
||||
if ((len = netlink_recv()) != -1)
|
||||
{
|
||||
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
|
||||
if (h->nlmsg_type == NLMSG_ERROR)
|
||||
nl_err(h);
|
||||
else
|
||||
nl_routechange(daemon, h);
|
||||
nl_routechange(h);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +223,7 @@ static void nl_err(struct nlmsghdr *h)
|
||||
{
|
||||
struct nlmsgerr *err = NLMSG_DATA(h);
|
||||
if (err->error != 0)
|
||||
syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
|
||||
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
|
||||
}
|
||||
|
||||
/* We arrange to receive netlink multicast messages whenever the network route is added.
|
||||
@@ -237,7 +231,7 @@ static void nl_err(struct nlmsghdr *h)
|
||||
This helps on DoD links, where frequently the packet which triggers dialling is
|
||||
a DNS query, which then gets lost. By re-sending, we can avoid the lookup
|
||||
failing. */
|
||||
static void nl_routechange(struct daemon *daemon, struct nlmsghdr *h)
|
||||
static void nl_routechange(struct nlmsghdr *h)
|
||||
{
|
||||
if (h->nlmsg_type == RTM_NEWROUTE && daemon->srv_save)
|
||||
{
|
||||
|
||||
+66
-49
@@ -12,7 +12,7 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
int iface_check(struct daemon *daemon, int family, struct all_addr *addr,
|
||||
int iface_check(int family, struct all_addr *addr,
|
||||
struct ifreq *ifr, int *indexp)
|
||||
{
|
||||
struct iname *tmp;
|
||||
@@ -38,7 +38,7 @@ int iface_check(struct daemon *daemon, int family, struct all_addr *addr,
|
||||
|
||||
if (!(newindex = if_nametoindex(bridge->iface)))
|
||||
{
|
||||
syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), ifr->ifr_name);
|
||||
my_syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), ifr->ifr_name);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
@@ -84,7 +84,7 @@ int iface_check(struct daemon *daemon, int family, struct all_addr *addr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iface_allowed(struct daemon *daemon, struct irec **irecp, int if_index,
|
||||
static int iface_allowed(struct irec **irecp, int if_index,
|
||||
union mysockaddr *addr, struct in_addr netmask)
|
||||
{
|
||||
struct irec *iface;
|
||||
@@ -134,9 +134,10 @@ static int iface_allowed(struct daemon *daemon, struct irec **irecp, int if_inde
|
||||
break;
|
||||
}
|
||||
|
||||
if (!lo && (lo = malloc(sizeof(struct iname))))
|
||||
if (!lo &&
|
||||
(lo = whine_malloc(sizeof(struct iname))) &&
|
||||
(lo->name = whine_malloc(strlen(ifr.ifr_name)+1)))
|
||||
{
|
||||
lo->name = safe_malloc(strlen(ifr.ifr_name)+1);
|
||||
strcpy(lo->name, ifr.ifr_name);
|
||||
lo->isloop = lo->used = 1;
|
||||
lo->next = daemon->if_names;
|
||||
@@ -145,7 +146,7 @@ static int iface_allowed(struct daemon *daemon, struct irec **irecp, int if_inde
|
||||
}
|
||||
|
||||
if (addr->sa.sa_family == AF_INET &&
|
||||
!iface_check(daemon, AF_INET, (struct all_addr *)&addr->in.sin_addr, &ifr, NULL))
|
||||
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, &ifr, NULL))
|
||||
return 1;
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
@@ -154,12 +155,12 @@ static int iface_allowed(struct daemon *daemon, struct irec **irecp, int if_inde
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (addr->sa.sa_family == AF_INET6 &&
|
||||
!iface_check(daemon, AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, &ifr, NULL))
|
||||
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, &ifr, NULL))
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
/* add to list */
|
||||
if ((iface = malloc(sizeof(struct irec))))
|
||||
if ((iface = whine_malloc(sizeof(struct irec))))
|
||||
{
|
||||
iface->addr = *addr;
|
||||
iface->netmask = netmask;
|
||||
@@ -174,7 +175,7 @@ static int iface_allowed(struct daemon *daemon, struct irec **irecp, int if_inde
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
static int iface_allowed_v6(struct daemon *daemon, struct in6_addr *local,
|
||||
static int iface_allowed_v6(struct in6_addr *local,
|
||||
int scope, int if_index, void *vparam)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
@@ -191,11 +192,11 @@ static int iface_allowed_v6(struct daemon *daemon, struct in6_addr *local,
|
||||
addr.in6.sin6_port = htons(daemon->port);
|
||||
addr.in6.sin6_scope_id = scope;
|
||||
|
||||
return iface_allowed(daemon, (struct irec **)vparam, if_index, &addr, netmask);
|
||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int iface_allowed_v4(struct daemon *daemon, struct in_addr local, int if_index,
|
||||
static int iface_allowed_v4(struct in_addr local, int if_index,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
@@ -209,30 +210,28 @@ static int iface_allowed_v4(struct daemon *daemon, struct in_addr local, int if_
|
||||
addr.in.sin_addr = local;
|
||||
addr.in.sin_port = htons(daemon->port);
|
||||
|
||||
return iface_allowed(daemon, (struct irec **)vparam, if_index, &addr, netmask);
|
||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask);
|
||||
}
|
||||
|
||||
|
||||
int enumerate_interfaces(struct daemon *daemon)
|
||||
int enumerate_interfaces(void)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
return iface_enumerate(daemon, &daemon->interfaces, iface_allowed_v4, iface_allowed_v6);
|
||||
return iface_enumerate(&daemon->interfaces, iface_allowed_v4, iface_allowed_v6);
|
||||
#else
|
||||
return iface_enumerate(daemon, &daemon->interfaces, iface_allowed_v4, NULL);
|
||||
return iface_enumerate(&daemon->interfaces, iface_allowed_v4, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* set NONBLOCK and CLOEXEC bits on fd: See Stevens 16.6 */
|
||||
/* set NONBLOCK bit on fd: See Stevens 16.6 */
|
||||
int fix_fd(int fd)
|
||||
{
|
||||
int flags;
|
||||
|
||||
if ((flags = fcntl(fd, F_GETFL)) == -1 ||
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||
(flags = fcntl(fd, F_GETFD)) == -1 ||
|
||||
fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
|
||||
return 0;
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -289,7 +288,7 @@ static int create_ipv6_listener(struct listener **link, int port)
|
||||
}
|
||||
#endif
|
||||
|
||||
struct listener *create_wildcard_listeners(int port, int have_tftp)
|
||||
struct listener *create_wildcard_listeners(void)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
int opt = 1;
|
||||
@@ -299,7 +298,7 @@ struct listener *create_wildcard_listeners(int port, int have_tftp)
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.in.sin_family = AF_INET;
|
||||
addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.in.sin_port = htons(port);
|
||||
addr.in.sin_port = htons(daemon->port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
@@ -313,7 +312,7 @@ struct listener *create_wildcard_listeners(int port, int have_tftp)
|
||||
listen(tcpfd, 5) == -1 ||
|
||||
!fix_fd(tcpfd) ||
|
||||
#ifdef HAVE_IPV6
|
||||
!create_ipv6_listener(&l6, port) ||
|
||||
!create_ipv6_listener(&l6, daemon->port) ||
|
||||
#endif
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
!fix_fd(fd) ||
|
||||
@@ -327,14 +326,13 @@ struct listener *create_wildcard_listeners(int port, int have_tftp)
|
||||
return NULL;
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if (have_tftp)
|
||||
if (daemon->options & OPT_TFTP)
|
||||
{
|
||||
addr.in.sin_port = htons(TFTP_PORT);
|
||||
if ((tftpfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return NULL;
|
||||
|
||||
if (setsockopt(tftpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
!fix_fd(tftpfd) ||
|
||||
if (!fix_fd(tftpfd) ||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
setsockopt(tftpfd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
@@ -356,7 +354,7 @@ struct listener *create_wildcard_listeners(int port, int have_tftp)
|
||||
return l;
|
||||
}
|
||||
|
||||
struct listener *create_bound_listeners(struct daemon *daemon)
|
||||
struct listener *create_bound_listeners(void)
|
||||
{
|
||||
struct listener *listeners = NULL;
|
||||
struct irec *iface;
|
||||
@@ -376,14 +374,14 @@ struct listener *create_bound_listeners(struct daemon *daemon)
|
||||
setsockopt(new->tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
!fix_fd(new->tcpfd) ||
|
||||
!fix_fd(new->fd))
|
||||
die(_("failed to create listening socket: %s"), NULL);
|
||||
die(_("failed to create listening socket: %s"), NULL, EC_BADNET);
|
||||
|
||||
#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);
|
||||
die(_("failed to set IPV6 options on listening socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -402,14 +400,14 @@ struct listener *create_bound_listeners(struct daemon *daemon)
|
||||
{
|
||||
prettyprint_addr(&iface->addr, daemon->namebuff);
|
||||
die(_("failed to bind listening socket for %s: %s"),
|
||||
daemon->namebuff);
|
||||
daemon->namebuff, EC_BADNET);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
listeners = new;
|
||||
if (listen(new->tcpfd, 5) == -1)
|
||||
die(_("failed to listen on socket: %s"), NULL);
|
||||
die(_("failed to listen on socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
|
||||
if ((daemon->options & OPT_TFTP) && iface->addr.sa.sa_family == AF_INET && iface->dhcp_ok)
|
||||
@@ -420,7 +418,7 @@ struct listener *create_bound_listeners(struct daemon *daemon)
|
||||
setsockopt(new->tftpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
!fix_fd(new->tftpfd) ||
|
||||
bind(new->tftpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
|
||||
die(_("failed to create TFTP socket: %s"), NULL);
|
||||
die(_("failed to create TFTP socket: %s"), NULL, EC_BADNET);
|
||||
iface->addr.in.sin_port = save;
|
||||
}
|
||||
}
|
||||
@@ -439,7 +437,7 @@ struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds)
|
||||
|
||||
/* need to make a new one. */
|
||||
errno = ENOMEM; /* in case malloc fails. */
|
||||
if (!(sfd = malloc(sizeof(struct serverfd))))
|
||||
if (!(sfd = whine_malloc(sizeof(struct serverfd))))
|
||||
return NULL;
|
||||
|
||||
if ((sfd->fd = socket(addr->sa.sa_family, SOCK_DGRAM, 0)) == -1)
|
||||
@@ -465,7 +463,7 @@ struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds)
|
||||
return sfd;
|
||||
}
|
||||
|
||||
void check_servers(struct daemon *daemon)
|
||||
void check_servers(void)
|
||||
{
|
||||
struct irec *iface;
|
||||
struct server *new, *tmp, *ret = NULL;
|
||||
@@ -492,7 +490,7 @@ void check_servers(struct daemon *daemon)
|
||||
break;
|
||||
if (iface)
|
||||
{
|
||||
syslog(LOG_WARNING, _("ignoring nameserver %s - local interface"), daemon->namebuff);
|
||||
my_syslog(LOG_WARNING, _("ignoring nameserver %s - local interface"), daemon->namebuff);
|
||||
free(new);
|
||||
continue;
|
||||
}
|
||||
@@ -500,8 +498,9 @@ void check_servers(struct daemon *daemon)
|
||||
/* Do we need a socket set? */
|
||||
if (!new->sfd && !(new->sfd = allocate_sfd(&new->source_addr, &daemon->sfds)))
|
||||
{
|
||||
syslog(LOG_WARNING,
|
||||
_("ignoring nameserver %s - cannot make/bind socket: %m"), daemon->namebuff);
|
||||
my_syslog(LOG_WARNING,
|
||||
_("ignoring nameserver %s - cannot make/bind socket: %s"),
|
||||
daemon->namebuff, strerror(errno));
|
||||
free(new);
|
||||
continue;
|
||||
}
|
||||
@@ -514,18 +513,20 @@ void check_servers(struct daemon *daemon)
|
||||
if (new->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS))
|
||||
{
|
||||
char *s1, *s2;
|
||||
if (new->flags & SERV_HAS_DOMAIN)
|
||||
s1 = _("domain"), s2 = new->domain;
|
||||
if (!(new->flags & SERV_HAS_DOMAIN))
|
||||
s1 = _("unqualified"), s2 = _("names");
|
||||
else if (strlen(new->domain) == 0)
|
||||
s1 = _("default"), s2 = "";
|
||||
else
|
||||
s1 = _("unqualified"), s2 = _("domains");
|
||||
s1 = _("domain"), s2 = new->domain;
|
||||
|
||||
if (new->flags & SERV_NO_ADDR)
|
||||
syslog(LOG_INFO, _("using local addresses only for %s %s"), s1, s2);
|
||||
my_syslog(LOG_INFO, _("using local addresses only for %s %s"), s1, s2);
|
||||
else if (!(new->flags & SERV_LITERAL_ADDRESS))
|
||||
syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2);
|
||||
my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2);
|
||||
}
|
||||
else
|
||||
syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port);
|
||||
my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port);
|
||||
}
|
||||
|
||||
daemon->servers = ret;
|
||||
@@ -533,7 +534,7 @@ void check_servers(struct daemon *daemon)
|
||||
|
||||
/* Return zero if no servers found, in that case we keep polling.
|
||||
This is a protection against an update-time/write race on resolv.conf */
|
||||
int reload_servers(char *fname, struct daemon *daemon)
|
||||
int reload_servers(char *fname)
|
||||
{
|
||||
FILE *f;
|
||||
char *line;
|
||||
@@ -545,7 +546,7 @@ int reload_servers(char *fname, struct daemon *daemon)
|
||||
/* buff happens to be MAXDNAME long... */
|
||||
if (!(f = fopen(fname, "r")))
|
||||
{
|
||||
syslog(LOG_ERR, _("failed to read %s: %m"), fname);
|
||||
my_syslog(LOG_ERR, _("failed to read %s: %s"), fname, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -560,7 +561,7 @@ int reload_servers(char *fname, struct daemon *daemon)
|
||||
serv->next = old_servers;
|
||||
old_servers = serv;
|
||||
/* forward table rules reference servers, so have to blow them away */
|
||||
server_gone(daemon, serv);
|
||||
server_gone(serv);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -575,7 +576,9 @@ int reload_servers(char *fname, struct daemon *daemon)
|
||||
union mysockaddr addr, source_addr;
|
||||
char *token = strtok(line, " \t\n\r");
|
||||
|
||||
if (!token || strcmp(token, "nameserver") != 0)
|
||||
if (!token)
|
||||
continue;
|
||||
if (strcmp(token, "nameserver") != 0 && strcmp(token, "server") != 0)
|
||||
continue;
|
||||
if (!(token = strtok(NULL, " \t\n\r")))
|
||||
continue;
|
||||
@@ -613,7 +616,7 @@ int reload_servers(char *fname, struct daemon *daemon)
|
||||
serv = old_servers;
|
||||
old_servers = old_servers->next;
|
||||
}
|
||||
else if (!(serv = malloc(sizeof (struct server))))
|
||||
else if (!(serv = whine_malloc(sizeof (struct server))))
|
||||
continue;
|
||||
|
||||
/* this list is reverse ordered:
|
||||
@@ -644,8 +647,22 @@ int reload_servers(char *fname, struct daemon *daemon)
|
||||
}
|
||||
|
||||
|
||||
/* Use an IPv4 listener socket for ioctling */
|
||||
struct in_addr get_ifaddr(char *intr)
|
||||
{
|
||||
struct listener *l;
|
||||
struct ifreq ifr;
|
||||
|
||||
|
||||
for (l = daemon->listeners; l && l->family != AF_INET; l = l->next);
|
||||
|
||||
strncpy(ifr.ifr_name, intr, IF_NAMESIZE);
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
|
||||
if (!l || ioctl(l->fd, SIOCGIFADDR, &ifr) == -1)
|
||||
((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = -1;
|
||||
|
||||
return ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+583
-365
File diff suppressed because it is too large.
Load diff
+197
-120
@@ -304,10 +304,10 @@ static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen
|
||||
|
||||
static unsigned char *skip_questions(HEADER *header, size_t plen)
|
||||
{
|
||||
int q, qdcount = ntohs(header->qdcount);
|
||||
int q;
|
||||
unsigned char *ansp = (unsigned char *)(header+1);
|
||||
|
||||
for (q = 0; q<qdcount; q++)
|
||||
for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
{
|
||||
if (!(ansp = skip_name(ansp, header, plen)))
|
||||
return NULL;
|
||||
@@ -349,7 +349,7 @@ unsigned int questions_crc(HEADER *header, size_t plen, char *name)
|
||||
unsigned int crc = 0xffffffff;
|
||||
unsigned char *p1, *p = (unsigned char *)(header+1);
|
||||
|
||||
for (q = 0; q < ntohs(header->qdcount); q++)
|
||||
for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
{
|
||||
if (!extract_name(header, plen, &p, name, 1))
|
||||
return crc; /* bad packet */
|
||||
@@ -419,19 +419,24 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
|
||||
unsigned char *ansp = (unsigned char *)(header+1);
|
||||
unsigned short rdlen, type, class;
|
||||
unsigned char *ret = NULL;
|
||||
|
||||
if (is_sign && header->opcode == QUERY)
|
||||
|
||||
if (is_sign)
|
||||
{
|
||||
for (i = 0; i < ntohs(header->qdcount); i++)
|
||||
*is_sign = 0;
|
||||
|
||||
if (header->opcode == QUERY)
|
||||
{
|
||||
if (!(ansp = skip_name(ansp, header, plen)))
|
||||
return NULL;
|
||||
|
||||
GETSHORT(type, ansp);
|
||||
GETSHORT(class, ansp);
|
||||
|
||||
if (class == C_IN && type == T_TKEY)
|
||||
*is_sign = 1;
|
||||
for (i = ntohs(header->qdcount); i != 0; i--)
|
||||
{
|
||||
if (!(ansp = skip_name(ansp, header, plen)))
|
||||
return NULL;
|
||||
|
||||
GETSHORT(type, ansp);
|
||||
GETSHORT(class, ansp);
|
||||
|
||||
if (class == C_IN && type == T_TKEY)
|
||||
*is_sign = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -480,31 +485,19 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
|
||||
|
||||
|
||||
/* is addr in the non-globally-routed IP space? */
|
||||
static int private_net(struct all_addr *addrp)
|
||||
static int private_net(struct in_addr addr)
|
||||
{
|
||||
struct in_addr addr = *(struct in_addr *)addrp;
|
||||
if (inet_netof(addr) == 0xA ||
|
||||
(inet_netof(addr) >= 0xAC10 && inet_netof(addr) < 0xAC20) ||
|
||||
(inet_netof(addr) >> 8) == 0xC0A8)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dns_doctor(HEADER *header, struct doctor *doctor, struct in_addr *addr)
|
||||
{
|
||||
for (; doctor; doctor = doctor->next)
|
||||
if (is_same_net(doctor->in, *addr, doctor->mask))
|
||||
{
|
||||
addr->s_addr &= ~doctor->mask.s_addr;
|
||||
addr->s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
|
||||
/* Since we munged the data, the server it came from is no longer authoritative */
|
||||
header->aa = 0;
|
||||
break;
|
||||
}
|
||||
in_addr_t ip_addr = ntohl(addr.s_addr);
|
||||
|
||||
return
|
||||
((ip_addr & 0xFF000000) == 0x7F000000) /* 127.0.0.0/8 (loopback) */ ||
|
||||
((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
|
||||
((ip_addr & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
|
||||
((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
|
||||
((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ;
|
||||
}
|
||||
|
||||
static int find_soa(HEADER *header, struct doctor *doctor, size_t qlen)
|
||||
static int find_soa(HEADER *header, size_t qlen)
|
||||
{
|
||||
unsigned char *p;
|
||||
int qtype, qclass, rdlen;
|
||||
@@ -516,7 +509,7 @@ static int find_soa(HEADER *header, struct doctor *doctor, size_t qlen)
|
||||
!(p = skip_section(p, ntohs(header->ancount), header, qlen)))
|
||||
return 0; /* bad packet */
|
||||
|
||||
for (i=0; i<ntohs(header->nscount); i++)
|
||||
for (i = ntohs(header->nscount); i != 0; i--)
|
||||
{
|
||||
if (!(p = skip_name(p, header, qlen)))
|
||||
return 0; /* bad packet */
|
||||
@@ -551,8 +544,8 @@ static int find_soa(HEADER *header, struct doctor *doctor, size_t qlen)
|
||||
return 0; /* bad packet */
|
||||
}
|
||||
|
||||
if (doctor)
|
||||
for (i=0; i<ntohs(header->arcount); i++)
|
||||
if (daemon->doctors)
|
||||
for (i = ntohs(header->arcount); i != 0; i--)
|
||||
{
|
||||
if (!(p = skip_name(p, header, qlen)))
|
||||
return 0; /* bad packet */
|
||||
@@ -563,7 +556,24 @@ static int find_soa(HEADER *header, struct doctor *doctor, size_t qlen)
|
||||
GETSHORT(rdlen, p);
|
||||
|
||||
if ((qclass == C_IN) && (qtype == T_A))
|
||||
dns_doctor(header, doctor, (struct in_addr *)p);
|
||||
{
|
||||
struct doctor *doctor;
|
||||
struct in_addr addr;
|
||||
|
||||
/* alignment */
|
||||
memcpy(&addr, p, INADDRSZ);
|
||||
|
||||
for (doctor = daemon->doctors; doctor; doctor = doctor->next)
|
||||
if (is_same_net(doctor->in, addr, doctor->mask))
|
||||
{
|
||||
addr.s_addr &= ~doctor->mask.s_addr;
|
||||
addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
|
||||
/* Since we munged the data, the server it came from is no longer authoritative */
|
||||
header->aa = 0;
|
||||
memcpy(p, &addr, INADDRSZ);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p += rdlen;
|
||||
|
||||
@@ -577,11 +587,12 @@ static int find_soa(HEADER *header, struct doctor *doctor, size_t qlen)
|
||||
/* Note that the following code can create CNAME chains that don't point to a real record,
|
||||
either because of lack of memory, or lack of SOA records. These are treated by the cache code as
|
||||
expired and cleaned out that way. */
|
||||
void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, struct daemon *daemon)
|
||||
void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
|
||||
{
|
||||
unsigned char *p, *p1, *endrr;
|
||||
int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
|
||||
unsigned long ttl = 0;
|
||||
struct all_addr addr;
|
||||
|
||||
cache_start_insert();
|
||||
|
||||
@@ -589,13 +600,13 @@ void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, stru
|
||||
if (daemon->doctors)
|
||||
{
|
||||
searched_soa = 1;
|
||||
ttl = find_soa(header, daemon->doctors, qlen);
|
||||
ttl = find_soa(header, qlen);
|
||||
}
|
||||
|
||||
/* go through the questions. */
|
||||
p = (unsigned char *)(header+1);
|
||||
|
||||
for (i = 0; i<ntohs(header->qdcount); i++)
|
||||
for (i = ntohs(header->qdcount); i != 0; i--)
|
||||
{
|
||||
int found = 0, cname_count = 5;
|
||||
struct crec *cpp = NULL;
|
||||
@@ -615,7 +626,6 @@ void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, stru
|
||||
represent them in the cache. */
|
||||
if (qtype == T_PTR)
|
||||
{
|
||||
struct all_addr addr;
|
||||
int name_encoding = in_arpa_name_2_addr(name, &addr);
|
||||
|
||||
if (!name_encoding)
|
||||
@@ -627,7 +637,7 @@ void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, stru
|
||||
if (!(p1 = skip_questions(header, qlen)))
|
||||
return;
|
||||
|
||||
for (j = 0; j<ntohs(header->ancount); j++)
|
||||
for (j = ntohs(header->ancount); j != 0; j--)
|
||||
{
|
||||
if (!(res = extract_name(header, qlen, &p1, name, 0)))
|
||||
return; /* bad packet */
|
||||
@@ -669,22 +679,29 @@ void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, stru
|
||||
if (!searched_soa)
|
||||
{
|
||||
searched_soa = 1;
|
||||
ttl = find_soa(header, NULL, qlen);
|
||||
ttl = find_soa(header, qlen);
|
||||
}
|
||||
if (ttl)
|
||||
cache_insert(name, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags);
|
||||
cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* everything other than PTR */
|
||||
struct crec *newc;
|
||||
|
||||
int addrlen;
|
||||
|
||||
if (qtype == T_A)
|
||||
flags |= F_IPV4;
|
||||
{
|
||||
addrlen = INADDRSZ;
|
||||
flags |= F_IPV4;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (qtype == T_AAAA)
|
||||
flags |= F_IPV6;
|
||||
{
|
||||
addrlen = IN6ADDRSZ;
|
||||
flags |= F_IPV6;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
continue;
|
||||
@@ -695,7 +712,7 @@ void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, stru
|
||||
if (!(p1 = skip_questions(header, qlen)))
|
||||
return;
|
||||
|
||||
for (j = 0; j<ntohs(header->ancount); j++)
|
||||
for (j = ntohs(header->ancount); j != 0; j--)
|
||||
{
|
||||
if (!(res = extract_name(header, qlen, &p1, name, 0)))
|
||||
return; /* bad packet */
|
||||
@@ -730,9 +747,9 @@ void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, stru
|
||||
else
|
||||
{
|
||||
found = 1;
|
||||
if (aqtype == T_A)
|
||||
dns_doctor(header, daemon->doctors, (struct in_addr *)p1);
|
||||
newc = cache_insert(name, (struct all_addr *)p1, now, attl, flags | F_FORWARD);
|
||||
/* copy address into aligned storage */
|
||||
memcpy(&addr, p1, addrlen);
|
||||
newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD);
|
||||
if (newc && cpp)
|
||||
{
|
||||
cpp->addr.cname.cache = newc;
|
||||
@@ -753,13 +770,13 @@ void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, stru
|
||||
if (!searched_soa)
|
||||
{
|
||||
searched_soa = 1;
|
||||
ttl = find_soa(header, NULL, qlen);
|
||||
ttl = find_soa(header, qlen);
|
||||
}
|
||||
/* If there's no SOA to get the TTL from, but there is a CNAME
|
||||
pointing at this, inherit it's TTL */
|
||||
if (ttl || cpp)
|
||||
{
|
||||
newc = cache_insert(name, (struct all_addr *)p, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags);
|
||||
newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags);
|
||||
if (newc && cpp)
|
||||
{
|
||||
cpp->addr.cname.cache = newc;
|
||||
@@ -854,12 +871,14 @@ size_t setup_reply(HEADER *header, size_t qlen,
|
||||
}
|
||||
|
||||
/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
|
||||
int check_for_local_domain(char *name, time_t now, struct daemon *daemon)
|
||||
int check_for_local_domain(char *name, time_t now)
|
||||
{
|
||||
struct crec *crecp;
|
||||
struct mx_srv_record *mx;
|
||||
struct txt_record *txt;
|
||||
|
||||
struct interface_name *intr;
|
||||
struct ptr_record *ptr;
|
||||
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)) &&
|
||||
(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
return 1;
|
||||
@@ -871,7 +890,15 @@ int check_for_local_domain(char *name, time_t now, struct daemon *daemon)
|
||||
for (txt = daemon->txt; txt; txt = txt->next)
|
||||
if (hostname_isequal(name, txt->name))
|
||||
return 1;
|
||||
|
||||
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
if (hostname_isequal(name, intr->name))
|
||||
return 1;
|
||||
|
||||
for (ptr = daemon->ptr; ptr; ptr = ptr->next)
|
||||
if (hostname_isequal(name, ptr->name))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -890,7 +917,7 @@ int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
|
||||
if (!(p = skip_questions(header, qlen)))
|
||||
return 0; /* bad packet */
|
||||
|
||||
for (i=0; i<ntohs(header->ancount); i++)
|
||||
for (i = ntohs(header->ancount); i != 0; i--)
|
||||
{
|
||||
if (!extract_name(header, qlen, &p, name, 1))
|
||||
return 0; /* bad packet */
|
||||
@@ -1003,7 +1030,7 @@ static int add_resource_record(HEADER *header, char *limit, int *truncp, unsigne
|
||||
}
|
||||
|
||||
/* return zero if we can't answer from cache, or packet size if we can */
|
||||
size_t answer_request(HEADER *header, char *limit, size_t qlen, struct daemon *daemon,
|
||||
size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask, time_t now)
|
||||
{
|
||||
char *name = daemon->namebuff;
|
||||
@@ -1012,7 +1039,6 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen, struct daemon *d
|
||||
struct all_addr addr;
|
||||
unsigned int nameoffset;
|
||||
unsigned short flag;
|
||||
int qdcount = ntohs(header->qdcount);
|
||||
int q, ans, anscount = 0, addncount = 0;
|
||||
int dryrun = 0, sec_reqd = 0;
|
||||
int is_sign;
|
||||
@@ -1047,7 +1073,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen, struct daemon *d
|
||||
dryrun = 1;
|
||||
}
|
||||
|
||||
if (!qdcount || header->opcode != QUERY )
|
||||
if (ntohs(header->qdcount) == 0 || header->opcode != QUERY )
|
||||
return 0;
|
||||
|
||||
for (rec = daemon->mxnames; rec; rec = rec->next)
|
||||
@@ -1061,7 +1087,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen, struct daemon *d
|
||||
/* now process each question, answers go in RRs after the question */
|
||||
p = (unsigned char *)(header+1);
|
||||
|
||||
for (q=0; q<qdcount; q++)
|
||||
for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
{
|
||||
/* save pointer to name for copying into answers */
|
||||
nameoffset = p - (unsigned char *)header;
|
||||
@@ -1103,21 +1129,32 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen, struct daemon *d
|
||||
/* see if it's w.z.y.z.in-addr.arpa format */
|
||||
int is_arpa = in_arpa_name_2_addr(name, &addr);
|
||||
struct ptr_record *ptr;
|
||||
struct interface_name* intr = NULL;
|
||||
|
||||
for (ptr = daemon->ptr; ptr; ptr = ptr->next)
|
||||
if (hostname_isequal(name, ptr->name))
|
||||
break;
|
||||
|
||||
if (!ptr &&
|
||||
!(crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
|
||||
{
|
||||
if (is_arpa == F_IPV4 && (daemon->options & OPT_BOGUSPRIV) && private_net(&addr))
|
||||
if (is_arpa == F_IPV4)
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
{
|
||||
if (addr.addr.addr4.s_addr == get_ifaddr(intr->intr).s_addr)
|
||||
break;
|
||||
else
|
||||
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
|
||||
intr = intr->next;
|
||||
}
|
||||
|
||||
if (intr)
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
/* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
|
||||
ans = 1;
|
||||
nxdomain = 1;
|
||||
if (!dryrun)
|
||||
log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN, name, &addr, 0, NULL, 0);
|
||||
log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, 0, NULL, 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL,
|
||||
T_PTR, C_IN, "d", intr->name))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
else if (ptr)
|
||||
@@ -1127,59 +1164,71 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen, struct daemon *d
|
||||
{
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_BIGNAME, name, NULL, 0, NULL, 0);
|
||||
for (ptr = daemon->ptr; ptr; ptr = ptr->next)
|
||||
if (hostname_isequal(name, ptr->name))
|
||||
{
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
|
||||
T_PTR, C_IN, "d", ptr->ptr))
|
||||
anscount++;
|
||||
}
|
||||
if (hostname_isequal(name, ptr->name) &&
|
||||
add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL,
|
||||
T_PTR, C_IN, "d", ptr->ptr))
|
||||
anscount++;
|
||||
|
||||
}
|
||||
}
|
||||
else do
|
||||
{
|
||||
/* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
|
||||
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
continue;
|
||||
|
||||
if (crecp->flags & F_NEG)
|
||||
{
|
||||
ans = 1;
|
||||
auth = 0;
|
||||
if (crecp->flags & F_NXDOMAIN)
|
||||
nxdomain = 1;
|
||||
if (!dryrun)
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, 0, NULL, 0);
|
||||
}
|
||||
else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
|
||||
{
|
||||
ans = 1;
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
|
||||
do
|
||||
{
|
||||
/* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
|
||||
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
continue;
|
||||
|
||||
if (crecp->flags & F_NEG)
|
||||
{
|
||||
ans = 1;
|
||||
auth = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
unsigned long ttl;
|
||||
/* Return 0 ttl for DHCP entries, which might change
|
||||
before the lease expires. */
|
||||
if (crecp->flags & (F_IMMORTAL | F_DHCP))
|
||||
ttl = daemon->local_ttl;
|
||||
else
|
||||
ttl = crecp->ttd - now;
|
||||
|
||||
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
|
||||
0, daemon->addn_hosts, crecp->uid);
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL,
|
||||
T_PTR, C_IN, "d", cache_get_name(crecp)))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
} while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
|
||||
if (crecp->flags & F_NXDOMAIN)
|
||||
nxdomain = 1;
|
||||
if (!dryrun)
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, 0, NULL, 0);
|
||||
}
|
||||
else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
|
||||
{
|
||||
ans = 1;
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
auth = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
unsigned long ttl;
|
||||
/* Return 0 ttl for DHCP entries, which might change
|
||||
before the lease expires. */
|
||||
if (crecp->flags & (F_IMMORTAL | F_DHCP))
|
||||
ttl = daemon->local_ttl;
|
||||
else
|
||||
ttl = crecp->ttd - now;
|
||||
|
||||
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
|
||||
0, daemon->addn_hosts, crecp->uid);
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL,
|
||||
T_PTR, C_IN, "d", cache_get_name(crecp)))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
} while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
|
||||
else if (is_arpa == F_IPV4 &&
|
||||
(daemon->options & OPT_BOGUSPRIV) &&
|
||||
private_net(addr.addr.addr4))
|
||||
{
|
||||
/* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
|
||||
ans = 1;
|
||||
nxdomain = 1;
|
||||
if (!dryrun)
|
||||
log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
|
||||
name, &addr, 0, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
|
||||
{
|
||||
unsigned short type = T_A;
|
||||
|
||||
|
||||
if (flag == F_IPV6)
|
||||
#ifdef HAVE_IPV6
|
||||
type = T_AAAA;
|
||||
@@ -1190,7 +1239,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen, struct daemon *d
|
||||
if (qtype != type && qtype != T_ANY)
|
||||
continue;
|
||||
|
||||
/* Check for "A for A" queries. */
|
||||
/* Check for "A for A" queries */
|
||||
if (qtype == T_A && (addr.addr.addr4.s_addr = inet_addr(name)) != (in_addr_t) -1)
|
||||
{
|
||||
ans = 1;
|
||||
@@ -1204,6 +1253,34 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen, struct daemon *d
|
||||
continue;
|
||||
}
|
||||
|
||||
/* interface name stuff */
|
||||
if (qtype == T_A)
|
||||
{
|
||||
struct interface_name *intr;
|
||||
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
if (hostname_isequal(name, intr->name))
|
||||
break;
|
||||
|
||||
if (intr)
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
if ((addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr == (in_addr_t) -1)
|
||||
log_query(F_FORWARD | F_CONFIG | F_IPV4 | F_NEG, name, NULL, 0, NULL, 0);
|
||||
else
|
||||
{
|
||||
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, 0, NULL, 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL, type, C_IN, "4", &addr))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
cname_restart:
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME)))
|
||||
{
|
||||
|
||||
+765
-377
File diff suppressed because it is too large.
Load diff
+181
-150
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2006 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2007 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,8 +14,10 @@
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
|
||||
static struct tftp_file *check_tftp_fileperm(ssize_t *len);
|
||||
static void free_transfer(struct tftp_transfer *transfer);
|
||||
static ssize_t tftp_err(int err, char *packet, char *mess, char *file);
|
||||
static ssize_t tftp_err_oops(char *packet, char *file);
|
||||
static ssize_t get_block(char *packet, struct tftp_transfer *transfer);
|
||||
static char *next(char **p, char *end);
|
||||
|
||||
@@ -32,12 +34,11 @@ static char *next(char **p, char *end);
|
||||
#define ERR_FULL 3
|
||||
#define ERR_ILL 4
|
||||
|
||||
void tftp_request(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
void tftp_request(struct listener *listen, time_t now)
|
||||
{
|
||||
ssize_t len;
|
||||
char *packet = daemon->packet;
|
||||
char *filename, *mode, *p, *end, *opt;
|
||||
struct stat statbuf;
|
||||
struct sockaddr_in addr, peer;
|
||||
struct msghdr msg;
|
||||
struct cmsghdr *cmptr;
|
||||
@@ -45,8 +46,7 @@ void tftp_request(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
struct ifreq ifr;
|
||||
int is_err = 1, if_index = 0;
|
||||
struct iname *tmp;
|
||||
struct tftp_transfer *transfer, *t;
|
||||
struct tftp_file *file;
|
||||
struct tftp_transfer *transfer;
|
||||
|
||||
union {
|
||||
struct cmsghdr align; /* this ensures alignment */
|
||||
@@ -74,56 +74,57 @@ void tftp_request(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)
|
||||
return;
|
||||
|
||||
if (daemon->options & OPT_NOWILD)
|
||||
addr = listen->iface->addr.in;
|
||||
else
|
||||
{
|
||||
addr.sin_addr.s_addr = 0;
|
||||
|
||||
if (daemon->options & OPT_NOWILD)
|
||||
addr = listen->iface->addr.in;
|
||||
else
|
||||
{
|
||||
addr.sin_addr.s_addr = 0;
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
{
|
||||
addr.sin_addr = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
|
||||
if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
|
||||
}
|
||||
if (!(ifr.ifr_ifindex = if_index) ||
|
||||
ioctl(listen->tftpfd, SIOCGIFNAME, &ifr) == -1)
|
||||
return;
|
||||
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
{
|
||||
addr.sin_addr = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
|
||||
if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
|
||||
}
|
||||
if (!(ifr.ifr_ifindex = if_index) ||
|
||||
ioctl(listen->tftpfd, SIOCGIFNAME, &ifr) == -1)
|
||||
return;
|
||||
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||
addr.sin_addr = *((struct in_addr *)CMSG_DATA(cmptr));
|
||||
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
|
||||
|
||||
if (if_index == 0 || !if_indextoname(if_index, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||
addr.sin_addr = *((struct in_addr *)CMSG_DATA(cmptr));
|
||||
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
|
||||
|
||||
if (if_index == 0 || !if_indextoname(if_index, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
#endif
|
||||
|
||||
if (addr.sin_addr.s_addr == 0)
|
||||
return;
|
||||
|
||||
if (!iface_check(daemon, AF_INET, (struct all_addr *)&addr, &ifr, &if_index))
|
||||
return;
|
||||
|
||||
/* allowed interfaces are the same as for DHCP */
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (addr.sin_addr.s_addr == 0)
|
||||
return;
|
||||
|
||||
if (!iface_check(AF_INET, (struct all_addr *)&addr.sin_addr,
|
||||
&ifr, &if_index))
|
||||
return;
|
||||
|
||||
/* allowed interfaces are the same as for DHCP */
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* tell kernel to use ephemeral port */
|
||||
addr.sin_port = 0;
|
||||
addr.sin_family = AF_INET;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.sin_len = sizeof(addr);
|
||||
#endif
|
||||
|
||||
if (!(transfer = malloc(sizeof(struct tftp_transfer))))
|
||||
|
||||
if (!(transfer = whine_malloc(sizeof(struct tftp_transfer))))
|
||||
return;
|
||||
|
||||
if ((transfer->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
@@ -133,7 +134,7 @@ void tftp_request(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
}
|
||||
|
||||
transfer->peer = peer;
|
||||
transfer->timeout = now + 1;
|
||||
transfer->timeout = now + 2;
|
||||
transfer->backoff = 1;
|
||||
transfer->block = 1;
|
||||
transfer->blocksize = 512;
|
||||
@@ -160,7 +161,8 @@ void tftp_request(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
while ((opt = next(&p, end)))
|
||||
{
|
||||
if (strcasecmp(opt, "blksize") == 0 &&
|
||||
(opt = next(&p, end)))
|
||||
(opt = next(&p, end)) &&
|
||||
!(daemon->options & OPT_TFTP_NOBLOCK))
|
||||
{
|
||||
transfer->blocksize = atoi(opt);
|
||||
if (transfer->blocksize < 1)
|
||||
@@ -178,108 +180,49 @@ void tftp_request(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
strcpy(daemon->namebuff, "/");
|
||||
if (daemon->tftp_prefix)
|
||||
{
|
||||
strncpy(daemon->namebuff, daemon->tftp_prefix, MAXDNAME);
|
||||
if (daemon->tftp_prefix[strlen(daemon->tftp_prefix)-1] != '/' &&
|
||||
filename[0] != '/')
|
||||
if (daemon->tftp_prefix[0] == '/')
|
||||
daemon->namebuff[0] = 0;
|
||||
strncat(daemon->namebuff, daemon->tftp_prefix, MAXDNAME);
|
||||
if (daemon->tftp_prefix[strlen(daemon->tftp_prefix)-1] != '/')
|
||||
strncat(daemon->namebuff, "/", MAXDNAME);
|
||||
|
||||
if (daemon->options & OPT_TFTP_APREF)
|
||||
{
|
||||
size_t oldlen = strlen(daemon->namebuff);
|
||||
struct stat statbuf;
|
||||
|
||||
strncat(daemon->namebuff, inet_ntoa(peer.sin_addr), MAXDNAME);
|
||||
strncat(daemon->namebuff, "/", MAXDNAME);
|
||||
|
||||
/* remove unique-directory if it doesn't exist */
|
||||
if (stat(daemon->namebuff, &statbuf) == -1 || !S_ISDIR(statbuf.st_mode))
|
||||
daemon->namebuff[oldlen] = 0;
|
||||
}
|
||||
|
||||
/* Absolute pathnames OK if they match prefix */
|
||||
if (filename[0] == '/')
|
||||
{
|
||||
if (strstr(filename, daemon->namebuff) == filename)
|
||||
daemon->namebuff[0] = 0;
|
||||
else
|
||||
filename++;
|
||||
}
|
||||
}
|
||||
else if (filename[0] != '/')
|
||||
strncpy(daemon->namebuff, "/", MAXDNAME);
|
||||
else
|
||||
else if (filename[0] == '/')
|
||||
daemon->namebuff[0] = 0;
|
||||
|
||||
strncat(daemon->namebuff, filename, MAXDNAME);
|
||||
daemon->namebuff[MAXDNAME-1] = 0;
|
||||
|
||||
/* If we're doing many tranfers from the same file, only
|
||||
open it once this saves lots of file descriptors
|
||||
when mass-booting a big cluster, for instance. */
|
||||
for (t = daemon->tftp_trans; t; t = t->next)
|
||||
if (strcmp(t->file->filename, daemon->namebuff) == 0)
|
||||
break;
|
||||
|
||||
if (t)
|
||||
/* check permissions and open file */
|
||||
if ((transfer->file = check_tftp_fileperm(&len)))
|
||||
{
|
||||
/* file already open */
|
||||
transfer->file = t->file;
|
||||
transfer->file->refcount++;
|
||||
if ((len = get_block(packet, transfer)) == -1)
|
||||
goto oops;
|
||||
is_err = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* check permissions and open file */
|
||||
|
||||
/* trick to ban moving out of the subtree */
|
||||
if (daemon->tftp_prefix && strstr(daemon->namebuff, "/../"))
|
||||
{
|
||||
errno = EACCES;
|
||||
goto perm;
|
||||
}
|
||||
|
||||
if (stat(daemon->namebuff, &statbuf) == -1)
|
||||
{
|
||||
if (errno == ENOENT || errno == ENOTDIR)
|
||||
len = tftp_err(ERR_FNF, packet, _("file %s not found"), daemon->namebuff);
|
||||
else if (errno == EACCES)
|
||||
{
|
||||
perm:
|
||||
len = tftp_err(ERR_PERM, packet, _("cannot access %s: %s"), daemon->namebuff);
|
||||
}
|
||||
else
|
||||
{
|
||||
oops:
|
||||
len = tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), daemon->namebuff);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uid_t uid = geteuid();
|
||||
/* running as root, must be world-readable */
|
||||
if (uid == 0)
|
||||
{
|
||||
if (!(statbuf.st_mode & S_IROTH))
|
||||
{
|
||||
errno = EACCES;
|
||||
goto perm;
|
||||
}
|
||||
}
|
||||
/* in secure mode, must be owned by user running dnsmasq */
|
||||
else if ((daemon->options & OPT_TFTP_SECURE) && uid != statbuf.st_uid)
|
||||
{
|
||||
errno = EACCES;
|
||||
goto perm;
|
||||
}
|
||||
|
||||
if (!(file = malloc(sizeof(struct tftp_file) + strlen(daemon->namebuff) + 1)))
|
||||
{
|
||||
errno = ENOMEM;
|
||||
goto oops;
|
||||
}
|
||||
|
||||
if ((file->fd = open(daemon->namebuff, O_RDONLY)) == -1)
|
||||
{
|
||||
free(file);
|
||||
|
||||
if (errno == EACCES || errno == EISDIR)
|
||||
goto perm;
|
||||
else
|
||||
goto oops;
|
||||
}
|
||||
else
|
||||
{
|
||||
transfer->file = file;
|
||||
file->refcount = 1;
|
||||
file->size = statbuf.st_size;
|
||||
strcpy(file->filename, daemon->namebuff);
|
||||
if ((len = get_block(packet, transfer)) == -1)
|
||||
goto oops;
|
||||
is_err = 0;
|
||||
}
|
||||
}
|
||||
len = tftp_err_oops(packet, daemon->namebuff);
|
||||
else
|
||||
is_err = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,13 +233,96 @@ void tftp_request(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
free_transfer(transfer);
|
||||
else
|
||||
{
|
||||
syslog(LOG_INFO, _("TFTP sent %s to %s"), daemon->namebuff, inet_ntoa(peer.sin_addr));
|
||||
my_syslog(LOG_INFO, _("TFTP sent %s to %s"), daemon->namebuff, inet_ntoa(peer.sin_addr));
|
||||
transfer->next = daemon->tftp_trans;
|
||||
daemon->tftp_trans = transfer;
|
||||
}
|
||||
}
|
||||
|
||||
static struct tftp_file *check_tftp_fileperm(ssize_t *len)
|
||||
{
|
||||
char *packet = daemon->packet, *namebuff = daemon->namebuff;
|
||||
struct tftp_file *file;
|
||||
struct tftp_transfer *t;
|
||||
uid_t uid = geteuid();
|
||||
struct stat statbuf;
|
||||
int fd = -1;
|
||||
|
||||
/* trick to ban moving out of the subtree */
|
||||
if (daemon->tftp_prefix && strstr(namebuff, "/../"))
|
||||
goto perm;
|
||||
|
||||
void check_tftp_listeners(struct daemon *daemon, fd_set *rset, time_t now)
|
||||
if ((fd = open(namebuff, O_RDONLY)) == -1)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
*len = tftp_err(ERR_FNF, packet, _("file %s not found"), namebuff);
|
||||
return NULL;
|
||||
}
|
||||
else if (errno == EACCES)
|
||||
goto perm;
|
||||
else
|
||||
goto oops;
|
||||
}
|
||||
|
||||
/* stat the file descriptor to avoid stat->open races */
|
||||
if (fstat(fd, &statbuf) == -1)
|
||||
goto oops;
|
||||
|
||||
/* running as root, must be world-readable */
|
||||
if (uid == 0)
|
||||
{
|
||||
if (!(statbuf.st_mode & S_IROTH))
|
||||
goto perm;
|
||||
}
|
||||
/* in secure mode, must be owned by user running dnsmasq */
|
||||
else if ((daemon->options & OPT_TFTP_SECURE) && uid != statbuf.st_uid)
|
||||
goto perm;
|
||||
|
||||
/* If we're doing many tranfers from the same file, only
|
||||
open it once this saves lots of file descriptors
|
||||
when mass-booting a big cluster, for instance.
|
||||
Be conservative and only share when inode and name match
|
||||
this keeps error messages sane. */
|
||||
for (t = daemon->tftp_trans; t; t = t->next)
|
||||
if (t->file->dev == statbuf.st_dev &&
|
||||
t->file->inode == statbuf.st_ino &&
|
||||
strcmp(t->file->filename, namebuff) == 0)
|
||||
{
|
||||
close(fd);
|
||||
t->file->refcount++;
|
||||
return t->file;
|
||||
}
|
||||
|
||||
if (!(file = whine_malloc(sizeof(struct tftp_file) + strlen(namebuff) + 1)))
|
||||
{
|
||||
errno = ENOMEM;
|
||||
goto oops;
|
||||
}
|
||||
|
||||
file->fd = fd;
|
||||
file->size = statbuf.st_size;
|
||||
file->dev = statbuf.st_dev;
|
||||
file->inode = statbuf.st_ino;
|
||||
file->refcount = 1;
|
||||
strcpy(file->filename, namebuff);
|
||||
return file;
|
||||
|
||||
perm:
|
||||
errno = EACCES;
|
||||
*len = tftp_err(ERR_PERM, packet, _("cannot access %s: %s"), namebuff);
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
return NULL;
|
||||
|
||||
oops:
|
||||
*len = tftp_err_oops(packet, namebuff);
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
{
|
||||
struct tftp_transfer *transfer, *tmp, **up;
|
||||
ssize_t len;
|
||||
@@ -340,9 +366,9 @@ void check_tftp_listeners(struct daemon *daemon, fd_set *rset, time_t now)
|
||||
*(q++) = *r;
|
||||
*q = 0;
|
||||
}
|
||||
syslog(LOG_ERR, _("TFTP error %d %s received from %s"),
|
||||
(int)ntohs(mess->block), err,
|
||||
inet_ntoa(transfer->peer.sin_addr));
|
||||
my_syslog(LOG_ERR, _("TFTP error %d %s received from %s"),
|
||||
(int)ntohs(mess->block), err,
|
||||
inet_ntoa(transfer->peer.sin_addr));
|
||||
|
||||
/* Got err, ensure we take abort */
|
||||
transfer->timeout = now;
|
||||
@@ -356,14 +382,14 @@ void check_tftp_listeners(struct daemon *daemon, fd_set *rset, time_t now)
|
||||
int endcon = 0;
|
||||
|
||||
/* timeout, retransmit */
|
||||
transfer->timeout += 1<<(transfer->backoff);
|
||||
transfer->timeout += 1 + (1<<transfer->backoff);
|
||||
|
||||
/* we overwrote the buffer... */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
if ((len = get_block(daemon->packet, transfer)) == -1)
|
||||
{
|
||||
len = tftp_err(ERR_NOTDEF, daemon->packet, _("cannot read %s: %s"), transfer->file->filename);
|
||||
len = tftp_err_oops(daemon->packet, transfer->file->filename);
|
||||
endcon = 1;
|
||||
}
|
||||
else if (++transfer->backoff > 5)
|
||||
@@ -371,8 +397,8 @@ void check_tftp_listeners(struct daemon *daemon, fd_set *rset, time_t now)
|
||||
/* don't complain about timeout when we're awaiting the last
|
||||
ACK, some clients never send it */
|
||||
if (len != 0)
|
||||
syslog(LOG_ERR, _("TFTP failed sending %s to %s"),
|
||||
transfer->file->filename, inet_ntoa(transfer->peer.sin_addr));
|
||||
my_syslog(LOG_ERR, _("TFTP failed sending %s to %s"),
|
||||
transfer->file->filename, inet_ntoa(transfer->peer.sin_addr));
|
||||
len = 0;
|
||||
}
|
||||
|
||||
@@ -431,11 +457,16 @@ static ssize_t tftp_err(int err, char *packet, char *message, char *file)
|
||||
mess->err = htons(err);
|
||||
ret += (snprintf(mess->message, 500, message, file, errstr) + 1);
|
||||
if (err != ERR_FNF)
|
||||
syslog(LOG_ERR, "TFTP %s", mess->message);
|
||||
my_syslog(LOG_ERR, "TFTP %s", mess->message);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t tftp_err_oops(char *packet, char *file)
|
||||
{
|
||||
return tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), file);
|
||||
}
|
||||
|
||||
/* return -1 for error, zero for done. */
|
||||
static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
|
||||
{
|
||||
|
||||
+29
-59
@@ -109,6 +109,7 @@ int canonicalise(char *s)
|
||||
also fail empty string and label > 63 chars */
|
||||
size_t dotgap = 0, l = strlen(s);
|
||||
char c;
|
||||
int nowhite = 0;
|
||||
|
||||
if (l == 0 || l > MAXDNAME) return 0;
|
||||
|
||||
@@ -124,9 +125,11 @@ int canonicalise(char *s)
|
||||
dotgap = 0;
|
||||
else if (!legal_char(c) || (++dotgap > MAXLABEL))
|
||||
return 0;
|
||||
else if (c != ' ')
|
||||
nowhite = 1;
|
||||
s++;
|
||||
}
|
||||
return 1;
|
||||
return nowhite;
|
||||
}
|
||||
|
||||
unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
|
||||
@@ -151,38 +154,19 @@ void *safe_malloc(size_t size)
|
||||
void *ret = malloc(size);
|
||||
|
||||
if (!ret)
|
||||
die(_("could not get memory"), NULL);
|
||||
die(_("could not get memory"), NULL, EC_NOMEM);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void log_err(char *message, char *arg1)
|
||||
void *whine_malloc(size_t size)
|
||||
{
|
||||
char *errmess = strerror(errno);
|
||||
|
||||
if (!arg1)
|
||||
arg1 = errmess;
|
||||
|
||||
fprintf(stderr, "dnsmasq: ");
|
||||
fprintf(stderr, message, arg1, errmess);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
syslog(LOG_CRIT, message, arg1, errmess);
|
||||
}
|
||||
void *ret = malloc(size);
|
||||
|
||||
void complain(char *message, int lineno, char *file)
|
||||
{
|
||||
char buff[256];
|
||||
|
||||
sprintf(buff, _("%s at line %d of %%s"), message, lineno);
|
||||
log_err(buff, file);
|
||||
}
|
||||
if (!ret)
|
||||
my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
|
||||
|
||||
void die(char *message, char *arg1)
|
||||
{
|
||||
log_err(message, arg1);
|
||||
syslog(LOG_CRIT, _("FAILED to start up"));
|
||||
exit(1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2)
|
||||
@@ -258,23 +242,6 @@ 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;
|
||||
}
|
||||
|
||||
/* returns port number from address */
|
||||
int prettyprint_addr(union mysockaddr *addr, char *buf)
|
||||
{
|
||||
@@ -380,7 +347,7 @@ int expand_buf(struct iovec *iov, size_t size)
|
||||
if (size <= iov->iov_len)
|
||||
return 1;
|
||||
|
||||
if (!(new = malloc(size)))
|
||||
if (!(new = whine_malloc(size)))
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return 0;
|
||||
@@ -398,9 +365,9 @@ int expand_buf(struct iovec *iov, size_t size)
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *print_mac(struct daemon *daemon, unsigned char *mac, int len)
|
||||
char *print_mac(char *buff, unsigned char *mac, int len)
|
||||
{
|
||||
char *p = daemon->namebuff;
|
||||
char *p = buff;
|
||||
int i;
|
||||
|
||||
if (len == 0)
|
||||
@@ -409,7 +376,7 @@ char *print_mac(struct daemon *daemon, unsigned char *mac, int len)
|
||||
for (i = 0; i < len; i++)
|
||||
p += sprintf(p, "%.2x%s", mac[i], (i == len - 1) ? "" : ":");
|
||||
|
||||
return daemon->namebuff;
|
||||
return buff;
|
||||
}
|
||||
|
||||
void bump_maxfd(int fd, int *max)
|
||||
@@ -418,18 +385,21 @@ void bump_maxfd(int fd, int *max)
|
||||
*max = fd;
|
||||
}
|
||||
|
||||
void log_start(struct daemon *daemon)
|
||||
int retry_send(void)
|
||||
{
|
||||
if (daemon->options & OPT_DEBUG)
|
||||
{
|
||||
#ifdef LOG_PERROR
|
||||
openlog("dnsmasq", LOG_PERROR, daemon->log_fac);
|
||||
#else
|
||||
openlog("dnsmasq", 0, daemon->log_fac);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
openlog("dnsmasq", LOG_PID, daemon->log_fac);
|
||||
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;
|
||||
}
|
||||
|
||||
int read_write(int fd, unsigned char *packet, int size, int rw)
|
||||
@@ -448,7 +418,7 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
|
||||
return 0;
|
||||
else if (n == -1)
|
||||
{
|
||||
if (errno == EINTR || errno == ENOMEM || errno == ENOBUFS)
|
||||
if (retry_send() || errno == ENOMEM || errno == ENOBUFS)
|
||||
goto retry;
|
||||
else
|
||||
return 0;
|
||||
|
||||
Reference in new issue
Block a user