Commit 0a852541 authored by Simon Kelley's avatar Simon Kelley

import of dnsmasq-2.21.tar.gz

parent f6b7dc47
...@@ -1369,5 +1369,56 @@ version 2.20 ...@@ -1369,5 +1369,56 @@ version 2.20
Added preference values for MX records. Added preference values for MX records.
Added the --localise-queries option. Added the --localise-queries option.
version 2.21
Improve handling of SERVFAIL and REFUSED errors. Receiving
these now initiates search for a new good server, and a
server which returns them is not a candidate as a good
server. Thanks to Istvan Varadi for pointing out the
problem.
Tweak the time code in BROKEN_RTC mode.
Sanity check lease times in dhcp-range and dhcp-host
configurations and force them to be at least two minutes
(120s) leases shorter than a minute confuse some clients,
notably Apple MacOS X. Rory Campbell-Lange found this
problem.
Only warn once about an upstream server which is refusing to do
recursive queries.
Fix DHCP address allocation problem when netid tags are in
use. Thanks to Will Murnane for the bug report and
subsequent testing.
Add an additional data section to the reply for MX and SRV
queries. Add support for DNS TXT records. Thanks to Robert
Kean and John Hampton for prompts and testing of these.
Apply address rewriting to records in the additional data section
of DNS packets. This makes things like MX records work
with the alias function. Thanks to Chad Skeeters for
pointing out the need for this.
Added support for quoted strings in config file.
Detect and defeat cache-poisoning attacks which attempt to
send (malicious) answers to questions we didn't
send. These are ignored now even if the attacker manages
to guess a random query-id.
Provide DHCP support for interfaces with multiple IP
addresses or aliases. This in only enabled under Linux.
See the FAQ entry for details.
Revisit the MAC-address and client-id matching code to
provide saner behaviour with PXE boots, where some
requests have a client-id and some don't.
Fixed off-by-one buffer overflow in lease file reading
code. Thanks to Rob Holland for the bug report.
Added wildcard matching for MAC addresses in dhcp-host
options. A sensible suggestion by Nathaniel McCallum.
...@@ -21,8 +21,7 @@ Q: Why doesn't dnsmasq support DNS queries over TCP? Don't the RFC's specify ...@@ -21,8 +21,7 @@ Q: Why doesn't dnsmasq support DNS queries over TCP? Don't the RFC's specify
that? that?
A: Update: from version 2.10, it does. There are a few limitations: A: Update: from version 2.10, it does. There are a few limitations:
data obtained via TCP is not cached, and dynamically-created data obtained via TCP is not cached, and source-address
interfaces may break under certain circumstances. Source-address
or query-port specifications are ignored for TCP. or query-port specifications are ignored for TCP.
Q: When I send SIGUSR1 to dump the contents of the cache, some entries have Q: When I send SIGUSR1 to dump the contents of the cache, some entries have
...@@ -112,7 +111,7 @@ A: Resolver code sometime does strange things when given names without ...@@ -112,7 +111,7 @@ A: Resolver code sometime does strange things when given names without
resolver will attempt to look up "myhost.localnet" so you need to resolver will attempt to look up "myhost.localnet" so you need to
have dnsmasq reply to that name. The way to do that is to include have dnsmasq reply to that name. The way to do that is to include
the domain in each name on /etc/hosts and/or to use the the domain in each name on /etc/hosts and/or to use the
--expand-hosts and --domain-suffix options. --expand-hosts and --domain options.
Q: Can I get dnsmasq to save the contents of its cache to disk when Q: Can I get dnsmasq to save the contents of its cache to disk when
I shut my machine down and re-load when it starts again? I shut my machine down and re-load when it starts again?
...@@ -316,5 +315,30 @@ A: By default, the identity of a machine is determined by using the ...@@ -316,5 +315,30 @@ A: By default, the identity of a machine is determined by using the
dhcpcd uses the "-I" flag. Windows uses a registry setting, dhcpcd uses the "-I" flag. Windows uses a registry setting,
see http://www.jsiinc.com/SUBF/TIP2800/rh2845.htm see http://www.jsiinc.com/SUBF/TIP2800/rh2845.htm
Q: Can dnsmasq do DHCP on IP-alias interfaces?
A: Yes, from version-2.21. The support is only available running under
Linux, on a kernel which provides the RT-netlink facility. All 2.4
and 2.6 kernels provide RT-netlink and it's an option in 2.2
kernels. If dnsmasq is built under uclibc, even on Linux, then
the support is not included.
If a physical interface has more than one IP address or aliases
with extra IP addresses, then any dhcp-ranges corresponding to
these addresses can be used for address allocation. So is and
interface has addresses 192.168.1.0/24 and 192.68.2.0/24 and there
are DHCP ranges 192.168.1.100-192.168.1.200 and
192.168.2.100-192.168.2.200 then both ranges would be used for host
connected to the physical interface. A more typical use might be to
have one of the address-ranges as static-only, and have known
hosts allocated addresses on that subnet using dhcp-host options,
while anonymous hosts go on the other.
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
############################################################################### ###############################################################################
Name: dnsmasq Name: dnsmasq
Version: 2.20 Version: 2.21
Release: 1 Release: 1
Copyright: GPL Copyright: GPL
Group: System Environment/Daemons Group: System Environment/Daemons
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
############################################################################### ###############################################################################
Name: dnsmasq Name: dnsmasq
Version: 2.20 Version: 2.21
Release: 1 Release: 1
Copyright: GPL Copyright: GPL
Group: Productivity/Networking/DNS/Servers Group: Productivity/Networking/DNS/Servers
......
...@@ -310,6 +310,10 @@ domain given by the ...@@ -310,6 +310,10 @@ domain given by the
option. The data in these is stereotyped, but is enough for resolvers option. The data in these is stereotyped, but is enough for resolvers
to deduce that the domain is a valid one for resolving SRV records. to deduce that the domain is a valid one for resolving SRV records.
.TP .TP
.B \-Y, --txt-record=<name>[[,<text>],<text>]
Return a TXT DNS record. The value of TXT record is a set of strings,
so any number may be included, split by commas.
.TP
.B \-c, --cache-size=<cachesize> .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. Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching.
.TP .TP
...@@ -319,7 +323,7 @@ Disable negative caching. Negative caching allows dnsmasq to remember ...@@ -319,7 +323,7 @@ Disable negative caching. Negative caching allows dnsmasq to remember
identical queries without forwarding them again. This flag disables identical queries without forwarding them again. This flag disables
negative caching. negative caching.
.TP .TP
.B \-F, --dhcp-range=[network-id,]<start-addr>,<end-addr>[[,<netmask>],<broadcast>][,<default lease time>] .B \-F, --dhcp-range=[[net:]network-id,]<start-addr>,<end-addr>[[,<netmask>],<broadcast>][,<default lease time>]
Enable the DHCP server. Addresses will be given out from the range Enable the DHCP server. Addresses will be given out from the range
<start-addr> to <end-addr> and from statically defined addresses given <start-addr> to <end-addr> and from statically defined addresses given
in in
...@@ -339,8 +343,10 @@ given using the ...@@ -339,8 +343,10 @@ given using the
option. This limitation currently affects OpenBSD. It is always option. This limitation currently affects OpenBSD. It is always
allowed to have more than one dhcp-range in a single subnet. The optional allowed to have more than one dhcp-range in a single subnet. The optional
network-id is a alphanumeric label which marks this network so that network-id is a alphanumeric label which marks this network so that
dhcp options may be specified on a per-network basis. The end address dhcp options may be specified on a per-network basis.
may be replaced by the keyword When it is prefixed with 'net:' then its meaning changes from setting
a tag to matching it.
The end address may be replaced by the keyword
.B static .B static
which tells dnsmasq to enable DHCP for the network specified, but not which tells dnsmasq to enable DHCP for the network specified, but not
to dynamically allocate IP addresses. Only hosts which have static to dynamically allocate IP addresses. Only hosts which have static
...@@ -387,6 +393,12 @@ useful when there is another DHCP server on the network which should ...@@ -387,6 +393,12 @@ useful when there is another DHCP server on the network which should
be used by some machines. The net:<network-id> parameter enables DHCP options just be used by some machines. The net:<network-id> parameter enables DHCP options just
for this host in the same way as the the network-id in for this host in the same way as the the network-id in
.B dhcp-range. .B dhcp-range.
Ethernet addresses (but not client-ids) may have
wildcard bytes, so for example
.B --dhcp-host=00:20:e0:3b:13:*,ignore
will cause dnsmasq to ignore a range of ethernet addresses. Note that
the "*" will need to be escaped or quoted on a command line, but not
in the configuration file.
.TP .TP
.B \-Z, --read-ethers .B \-Z, --read-ethers
Read /etc/ethers for information about hosts for the DHCP server. The Read /etc/ethers for information about hosts for the DHCP server. The
...@@ -500,7 +512,10 @@ options which may only be specified once, the configuration file overrides ...@@ -500,7 +512,10 @@ options which may only be specified once, the configuration file overrides
the command line. Use the --conf-file option to specify a different the command line. Use the --conf-file option to specify a different
configuration file. The conf-file option is also allowed in configuration file. The conf-file option is also allowed in
configuration files, to include multiple configuration files. Only one configuration files, to include multiple configuration files. Only one
level of nesting is allowed. level of nesting is allowed. Quoting is allowed in a config file:
between " quotes the special meaning of , and # is removed and the
following escapes are allowed: \\\\ \\" \\t and \\n. The later two
corresponding to newline and tab.
.SH NOTES .SH NOTES
When it receives a SIGHUP, When it receives a SIGHUP,
.B dnsmasq .B dnsmasq
......
...@@ -167,6 +167,10 @@ bogus-priv ...@@ -167,6 +167,10 @@ bogus-priv
# the machine with ethernet address 11:22:33:44:55:66 # the machine with ethernet address 11:22:33:44:55:66
#dhcp-host=11:22:33:44:55:66,net:red #dhcp-host=11:22:33:44:55:66,net:red
# Send extra options which are tagged as "red" to
# any machine with ethernet address starting 11:22:33:
#dhcp-host=11:22:33:*:*:*,net:red
# Send extra options which are tagged as "red" to any machine whose # Send extra options which are tagged as "red" to any machine whose
# DHCP vendorclass string includes the substring "Linux" # DHCP vendorclass string includes the substring "Linux"
#dhcp-vendorclass=red,Linux #dhcp-vendorclass=red,Linux
...@@ -310,7 +314,8 @@ bogus-priv ...@@ -310,7 +314,8 @@ bogus-priv
# The fields are <name>,<target>,<port>,<priority>,<weight> # The fields are <name>,<target>,<port>,<priority>,<weight>
# If the domain part if missing from the name (so that is just has the # If the domain part if missing from the name (so that is just has the
# service and protocol sections) then the domain given by the domain= # service and protocol sections) then the domain given by the domain=
# config option is used. # config option is used. (Note that expand-hosts does not need to be
# set for this to work.)
# A SRV record sending LDAP for the example.com domain to # A SRV record sending LDAP for the example.com domain to
# ldapserver.example.com port 289 # ldapserver.example.com port 289
...@@ -329,6 +334,19 @@ bogus-priv ...@@ -329,6 +334,19 @@ bogus-priv
# example.com # example.com
#srv-host=_ldap._tcp.example.com #srv-host=_ldap._tcp.example.com
# Change the following lines to enable dnsmasq to serve TXT records.
# These are used for things like SPF and zeroconf. (Note that the
# domain-name expansion done for SRV records _does_not
# occur for TXT records.)
#Example SPF.
#txt-record=example.com,v=spf1 a -all
#Example zeroconf
#txt-record=_http._tcp.example.com,name=value,paper=A4
# For debugging purposes, log each DNS query as it passes through # For debugging purposes, log each DNS query as it passes through
# dnsmasq. # dnsmasq.
#log-queries #log-queries
......
...@@ -108,7 +108,7 @@ HREF="http://howto.linux-hardware-shop.de/dnsmasq.html">http://howto.linux-hardw ...@@ -108,7 +108,7 @@ HREF="http://howto.linux-hardware-shop.de/dnsmasq.html">http://howto.linux-hardw
and Damien Raude-Morvan has one in French at <A HREF="http://www.drazzib.com/docs-dnsmasq.html">http://www.drazzib.com/docs-dnsmasq.html</A> and Damien Raude-Morvan has one in French at <A HREF="http://www.drazzib.com/docs-dnsmasq.html">http://www.drazzib.com/docs-dnsmasq.html</A>
There is a good article about dnsmasq at <A There is a good article about dnsmasq at <A
HREF="http://www.enterprisenetworkingplanet.com/netos/article.php/3377351">http://www.enterprisenetworkingplanet.com/netos/article.php/3377351</A> HREF="http://www.enterprisenetworkingplanet.com/netos/article.php/3377351">http://www.enterprisenetworkingplanet.com/netos/article.php/3377351</A>
and Ilya Evseev has an article in Russian about dnsmasq to be found at <A HREF="http://ilya-evseev.narod.ru/articles/dnsmasq"> http://ilya-evseev.narod.ru/articles/dnsmasq</A>
<H2>License.</H2> <H2>License.</H2>
Dnsmasq is distributed under the GPL. See the file COPYING in the distribution Dnsmasq is distributed under the GPL. See the file COPYING in the distribution
for details. for details.
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
CFLAGS?= -O2 CFLAGS?= -O2
OBJS = cache.o rfc1035.o util.o option.o forward.o isc.o \ OBJS = cache.o rfc1035.o util.o option.o forward.o isc.o \
network.o dnsmasq.o dhcp.o lease.o rfc2131.o network.o dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o
.c.o: dnsmasq.h config.h .c.o: dnsmasq.h config.h
$(CC) $(CFLAGS) $(RPM_OPT_FLAGS) -Wall -W -c $*.c $(CC) $(CFLAGS) $(RPM_OPT_FLAGS) -Wall -W -c $*.c
......
...@@ -846,8 +846,6 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr, ...@@ -846,8 +846,6 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr,
if (!log_queries) if (!log_queries)
return; return;
strcpy(types, " ");
if (flags & F_NEG) if (flags & F_NEG)
{ {
if (flags & F_REVERSE) if (flags & F_REVERSE)
...@@ -875,6 +873,8 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr, ...@@ -875,6 +873,8 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr,
strcpy(addrbuff, "<MX>"); strcpy(addrbuff, "<MX>");
else if (flags & F_IPV6) else if (flags & F_IPV6)
strcpy(addrbuff, "<SRV>"); strcpy(addrbuff, "<SRV>");
else if (flags & F_NXDOMAIN)
strcpy(addrbuff, "<TXT>");
else else
strcpy(addrbuff, "<CNAME>"); strcpy(addrbuff, "<CNAME>");
} }
...@@ -937,19 +937,19 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr, ...@@ -937,19 +937,19 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr,
if (type != 0) if (type != 0)
{ {
sprintf(types, "[type=%d] ", type); sprintf(types, "query[type=%d]", type);
for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++) for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
if (typestr[i].type == type) if (typestr[i].type == type)
sprintf(types,"[%s] ", typestr[i].name); sprintf(types,"query[%s]", typestr[i].name);
} }
source = "query"; source = types;
verb = "from"; verb = "from";
} }
else else
source = "cached"; source = "cached";
if ((flags & F_FORWARD) | (flags & F_NEG)) if ((flags & F_FORWARD) | (flags & F_NEG))
syslog(LOG_DEBUG, "%s %s%s%s %s", source, name, types, verb, addrbuff); syslog(LOG_DEBUG, "%s %s %s %s", source, name, verb, addrbuff);
else if (flags & F_REVERSE) else if (flags & F_REVERSE)
syslog(LOG_DEBUG, "%s %s is %s", source, addrbuff, name); syslog(LOG_DEBUG, "%s %s is %s", source, addrbuff, name);
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
/* Author's email: simon@thekelleys.org.uk */ /* Author's email: simon@thekelleys.org.uk */
#define VERSION "2.20" #define VERSION "2.21"
#define FTABSIZ 150 /* max number of outstanding requests */ #define FTABSIZ 150 /* max number of outstanding requests */
#define MAX_PROCS 20 /* max no children for TCP requests */ #define MAX_PROCS 20 /* max no children for TCP requests */
...@@ -158,6 +158,12 @@ HAVE_PSELECT ...@@ -158,6 +158,12 @@ HAVE_PSELECT
HAVE_BPF HAVE_BPF
If your OS implements Berkeley Packet filter, define this. If your OS implements Berkeley Packet filter, define this.
HAVE_RTNETLINK
If your OS has the Linux Routing netlink socket API and suitable
C library headers, define this. Note that the code will fall
back to the Berkley API at runtime if netlink support is not
configured into the kernel.
NOTES: NOTES:
For Linux you should define For Linux you should define
HAVE_LINUX_IPV6_PROC HAVE_LINUX_IPV6_PROC
...@@ -165,6 +171,7 @@ NOTES: ...@@ -165,6 +171,7 @@ NOTES:
HAVE_RANDOM HAVE_RANDOM
HAVE_DEV_RANDOM HAVE_DEV_RANDOM
HAVE_DEV_URANDOM HAVE_DEV_URANDOM
HAVE_RTNETLINK
you should NOT define you should NOT define
HAVE_ARC4RANDOM HAVE_ARC4RANDOM
HAVE_SOCKADDR_SA_LEN HAVE_SOCKADDR_SA_LEN
...@@ -175,6 +182,7 @@ NOTES: ...@@ -175,6 +182,7 @@ NOTES:
HAVE_BPF HAVE_BPF
you should NOT define you should NOT define
HAVE_LINUX_IPV6_PROC HAVE_LINUX_IPV6_PROC
HAVE_RTNETLINK
and you MAY define and you MAY define
HAVE_ARC4RANDOM - OpenBSD and FreeBSD and NetBSD version 2.0 or later HAVE_ARC4RANDOM - OpenBSD and FreeBSD and NetBSD version 2.0 or later
HAVE_DEV_URANDOM - OpenBSD and FreeBSD and NetBSD HAVE_DEV_URANDOM - OpenBSD and FreeBSD and NetBSD
...@@ -199,6 +207,7 @@ NOTES: ...@@ -199,6 +207,7 @@ NOTES:
#if defined(__uClinux__) || defined(__UCLIBC__) #if defined(__uClinux__) || defined(__UCLIBC__)
#undef HAVE_LINUX_IPV6_PROC #undef HAVE_LINUX_IPV6_PROC
#define HAVE_GETOPT_LONG #define HAVE_GETOPT_LONG
#undef HAVE_RTNETLINK /* headers broken */
#undef HAVE_ARC4RANDOM #undef HAVE_ARC4RANDOM
#define HAVE_RANDOM #define HAVE_RANDOM
#define HAVE_DEV_URANDOM #define HAVE_DEV_URANDOM
...@@ -223,6 +232,7 @@ NOTES: ...@@ -223,6 +232,7 @@ NOTES:
(_LINUX_C_LIB_VERSION_MAJOR == 5 ) (_LINUX_C_LIB_VERSION_MAJOR == 5 )
#undef HAVE_IPV6 #undef HAVE_IPV6
#undef HAVE_LINUX_IPV6_PROC #undef HAVE_LINUX_IPV6_PROC
#undef HAVE_RTNETLINK
#define HAVE_GETOPT_LONG #define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM #undef HAVE_ARC4RANDOM
#define HAVE_RANDOM #define HAVE_RANDOM
...@@ -237,6 +247,7 @@ typedef size_t socklen_t; ...@@ -237,6 +247,7 @@ typedef size_t socklen_t;
/* This is for glibc 2.x */ /* This is for glibc 2.x */
#elif defined(__linux__) #elif defined(__linux__)
#define HAVE_LINUX_IPV6_PROC #define HAVE_LINUX_IPV6_PROC
#define HAVE_RTNETLINK
#define HAVE_GETOPT_LONG #define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM #undef HAVE_ARC4RANDOM
#define HAVE_RANDOM #define HAVE_RANDOM
...@@ -256,6 +267,7 @@ typedef unsigned long in_addr_t; ...@@ -256,6 +267,7 @@ typedef unsigned long in_addr_t;
#elif defined(__FreeBSD__) || defined(__OpenBSD__) #elif defined(__FreeBSD__) || defined(__OpenBSD__)
#undef HAVE_LINUX_IPV6_PROC #undef HAVE_LINUX_IPV6_PROC
#undef HAVE_RTNETLINK
/* Later verions of FreeBSD have getopt_long() */ /* Later verions of FreeBSD have getopt_long() */
#if defined(optional_argument) && defined(required_argument) #if defined(optional_argument) && defined(required_argument)
# define HAVE_GETOPT_LONG # define HAVE_GETOPT_LONG
...@@ -271,6 +283,7 @@ typedef unsigned long in_addr_t; ...@@ -271,6 +283,7 @@ typedef unsigned long in_addr_t;
#elif defined(__APPLE__) #elif defined(__APPLE__)
#undef HAVE_LINUX_IPV6_PROC #undef HAVE_LINUX_IPV6_PROC
#undef HAVE_RTNETLINK
#undef HAVE_GETOPT_LONG #undef HAVE_GETOPT_LONG
#define HAVE_ARC4RANDOM #define HAVE_ARC4RANDOM
#define HAVE_RANDOM #define HAVE_RANDOM
...@@ -285,6 +298,7 @@ typedef unsigned long in_addr_t; ...@@ -285,6 +298,7 @@ typedef unsigned long in_addr_t;
#elif defined(__NetBSD__) #elif defined(__NetBSD__)
#undef HAVE_LINUX_IPV6_PROC #undef HAVE_LINUX_IPV6_PROC
#undef HAVE_RTNETLINK
#define HAVE_GETOPT_LONG #define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM #undef HAVE_ARC4RANDOM
#define HAVE_RANDOM #define HAVE_RANDOM
...@@ -297,6 +311,7 @@ typedef unsigned long in_addr_t; ...@@ -297,6 +311,7 @@ typedef unsigned long in_addr_t;
/* env "LIBS=-lsocket -lnsl" make */ /* env "LIBS=-lsocket -lnsl" make */
#elif defined(__sun) || defined(__sun__) #elif defined(__sun) || defined(__sun__)
#undef HAVE_LINUX_IPV6_PROC #undef HAVE_LINUX_IPV6_PROC
#undef HAVE_RTNETLINK
#undef HAVE_GETOPT_LONG #undef HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM #undef HAVE_ARC4RANDOM
#define HAVE_RANDOM #define HAVE_RANDOM
......
This diff is collapsed.
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include "dnsmasq.h" #include "dnsmasq.h"
static int sigterm, sighup, sigusr1, sigalarm, num_kids, in_child; static volatile int sigterm, sighup, sigusr1, sigalarm, num_kids, in_child;
static int set_dns_listeners(struct daemon *daemon, fd_set *set, int maxfd); static int set_dns_listeners(struct daemon *daemon, fd_set *set, int maxfd);
static void check_dns_listeners(struct daemon *daemon, fd_set *set, time_t now); static void check_dns_listeners(struct daemon *daemon, fd_set *set, time_t now);
...@@ -69,8 +69,9 @@ int main (int argc, char **argv) ...@@ -69,8 +69,9 @@ int main (int argc, char **argv)
if (daemon->edns_pktsz < PACKETSZ) if (daemon->edns_pktsz < PACKETSZ)
daemon->edns_pktsz = PACKETSZ; daemon->edns_pktsz = PACKETSZ;
daemon->packet = safe_malloc(daemon->edns_pktsz > DNSMASQ_PACKETSZ ? daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
daemon->edns_pktsz : DNSMASQ_PACKETSZ); daemon->edns_pktsz : DNSMASQ_PACKETSZ;
daemon->packet = safe_malloc(daemon->packet_buff_sz);
if (!daemon->lease_file) if (!daemon->lease_file)
{ {
...@@ -272,31 +273,31 @@ int main (int argc, char **argv) ...@@ -272,31 +273,31 @@ int main (int argc, char **argv)
if (daemon->dhcp) if (daemon->dhcp)
{ {
struct dhcp_context *dhcp_tmp; struct dhcp_context *dhcp_tmp;
#ifdef HAVE_RTNETLINK
/* Must do this after daemonizing so that the pid is right */
daemon->netlinkfd = netlink_init();
#endif
for (dhcp_tmp = daemon->dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next) for (dhcp_tmp = daemon->dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
{ {
char *time = daemon->dhcp_buff2; prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time);
strcpy(daemon->dhcp_buff, inet_ntoa(dhcp_tmp->start)); strcpy(daemon->dhcp_buff, inet_ntoa(dhcp_tmp->start));
if (dhcp_tmp->lease_time == 0)
sprintf(time, "infinite");
else
{
unsigned int x, p = 0, t = (unsigned int)dhcp_tmp->lease_time;
if ((x = t/3600))
p += sprintf(&time[p], "%dh", x);
if ((x = (t/60)%60))
p += sprintf(&time[p], "%dm", x);
if ((x = t%60))
p += sprintf(&time[p], "%ds", x);
}
syslog(LOG_INFO, syslog(LOG_INFO,
dhcp_tmp->static_only ? (dhcp_tmp->flags & CONTEXT_STATIC) ?
"DHCP, static leases only on %.0s%s, lease time %s" : "DHCP, static leases only on %.0s%s, lease time %s" :
"DHCP, IP range %s -- %s, lease time %s", "DHCP, IP range %s -- %s, lease time %s",
daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), time); daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), daemon->dhcp_buff2);
} }
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
syslog(LOG_INFO, "DHCP, %s will be written every %ds", daemon->lease_file, daemon->min_leasetime/3); daemon->min_leasetime = daemon->min_leasetime/3;
if (daemon->min_leasetime > (60 * 60 * 24))
daemon->min_leasetime = 60 * 60 * 24;
if (daemon->min_leasetime < 60)
daemon->min_leasetime = 60;
prettyprint_time(daemon->dhcp_buff2, daemon->min_leasetime);
syslog(LOG_INFO, "DHCP, %s will be written every %s", daemon->lease_file, daemon->dhcp_buff2);
#endif #endif
} }
...@@ -341,7 +342,7 @@ int main (int argc, char **argv) ...@@ -341,7 +342,7 @@ int main (int argc, char **argv)
{ {
lease_update_file(1, now); lease_update_file(1, now);
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
alarm(daemon->min_leasetime/3); alarm(daemon->min_leasetime);
#endif #endif
} }
sigalarm = 0; sigalarm = 0;
...@@ -681,3 +682,5 @@ int icmp_ping(struct daemon *daemon, struct in_addr addr) ...@@ -681,3 +682,5 @@ int icmp_ping(struct daemon *daemon, struct in_addr addr)
return gotreply; return gotreply;
} }
...@@ -79,9 +79,17 @@ ...@@ -79,9 +79,17 @@
#endif #endif
#include <sys/uio.h> #include <sys/uio.h>
/* Size: we check after adding each record, so there must be /* Min buffer size: we check after adding each record, so there must be
memory for the largest packet, and the largest record */ memory for the largest packet, and the largest record so the
#define DNSMASQ_PACKETSZ PACKETSZ+MAXDNAME+RRFIXEDSZ min for DNS is PACKETSZ+MAXDNAME+RRFIXEDSZ which is < 1000.
This might be increased is EDNS packet size if greater than the minimum.
The buffer is also used for NETLINK, which needs to be about 2000
on systems with many interfaces/addresses. */
#ifdef HAVE_RTNETLINK
# define DNSMASQ_PACKETSZ PACKETSZ+MAXDNAME+RRFIXEDSZ
#else
# define DNSMASQ_PACKETSZ 2000
#endif
#define OPT_BOGUSPRIV 1 #define OPT_BOGUSPRIV 1
#define OPT_FILTER 2 #define OPT_FILTER 2
...@@ -123,16 +131,16 @@ struct doctor { ...@@ -123,16 +131,16 @@ struct doctor {
struct doctor *next; struct doctor *next;
}; };
struct mx_record { struct mx_srv_record {
char *mxname, *mxtarget; char *name, *target;
int preference; int issrv, srvport, priority, weight, offset;
struct mx_record *next; struct mx_srv_record *next;
}; };
struct srv_record { struct txt_record {
char *srvname, *srvtarget; char *name, *txt;
int srvport, priority, weight; unsigned short class, len;
struct srv_record *next; struct txt_record *next;
}; };
union bigname { union bigname {
...@@ -199,14 +207,16 @@ union mysockaddr { ...@@ -199,14 +207,16 @@ union mysockaddr {
#endif #endif
}; };
#define SERV_FROM_RESOLV 1 /* 1 for servers from resolv, 0 for command line. */ #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_NO_ADDR 2 /* no server, this domain is local only */
#define SERV_LITERAL_ADDRESS 4 /* addr is the answer, not the server */ #define SERV_LITERAL_ADDRESS 4 /* addr is the answer, not the server */
#define SERV_HAS_SOURCE 8 /* source address specified */ #define SERV_HAS_SOURCE 8 /* source address specified */
#define SERV_HAS_DOMAIN 16 /* server for one domain only */ #define SERV_HAS_DOMAIN 16 /* server for one domain only */
#define SERV_FOR_NODOTS 32 /* server for names with no domain part only */ #define SERV_FOR_NODOTS 32 /* server for names with no domain part only */
#define SERV_WARNED_RECURSIVE 64 /* avoid warning spam */
#define SERV_TYPE (SERV_HAS_DOMAIN | SERV_FOR_NODOTS) #define SERV_TYPE (SERV_HAS_DOMAIN | SERV_FOR_NODOTS)
struct serverfd { struct serverfd {
int fd; int fd;
union mysockaddr source_addr; union mysockaddr source_addr;
...@@ -263,7 +273,7 @@ struct frec { ...@@ -263,7 +273,7 @@ struct frec {
struct server *sentto; struct server *sentto;
unsigned int iface; unsigned int iface;
unsigned short orig_id, new_id; unsigned short orig_id, new_id;
int fd; int fd, forwardall;
unsigned int crc; unsigned int crc;
time_t time; time_t time;
struct frec *next; struct frec *next;
...@@ -296,18 +306,18 @@ struct dhcp_config { ...@@ -296,18 +306,18 @@ struct dhcp_config {
char *hostname; char *hostname;
struct dhcp_netid netid; struct dhcp_netid netid;
struct in_addr addr; struct in_addr addr;
unsigned int lease_time; unsigned int lease_time, wildcard_mask;
struct dhcp_config *next; struct dhcp_config *next;
}; };
#define CONFIG_DISABLE 1 #define CONFIG_DISABLE 1
#define CONFIG_CLID 2 #define CONFIG_CLID 2
#define CONFIG_HWADDR 4 #define CONFIG_HWADDR 4
#define CONFIG_TIME 8 #define CONFIG_TIME 8
#define CONFIG_NAME 16 #define CONFIG_NAME 16
#define CONFIG_ADDR 32 #define CONFIG_ADDR 32
#define CONFIG_NETID 64 #define CONFIG_NETID 64
#define CONFIG_NOCLID 128 #define CONFIG_NOCLID 128
struct dhcp_opt { struct dhcp_opt {
int opt, len, is_addr; int opt, len, is_addr;
...@@ -332,13 +342,20 @@ struct dhcp_vendor { ...@@ -332,13 +342,20 @@ struct dhcp_vendor {
struct dhcp_context { struct dhcp_context {
unsigned int lease_time, addr_epoch; unsigned int lease_time, addr_epoch;
struct in_addr netmask, broadcast, router; struct in_addr netmask, broadcast;
struct in_addr local, router;
struct in_addr start, end; /* range of available addresses */ struct in_addr start, end; /* range of available addresses */
int static_only, filter_netid; int flags;
struct dhcp_netid netid; struct dhcp_netid netid;
struct dhcp_context *next, *current; struct dhcp_context *next, *current;
}; };
#define CONTEXT_STATIC 1
#define CONTEXT_FILTER 2
#define CONTEXT_NETMASK 4
#define CONTEXT_BRDCAST 8
typedef unsigned char u8; typedef unsigned char u8;
typedef unsigned short u16; typedef unsigned short u16;
typedef unsigned int u32; typedef unsigned int u32;
...@@ -370,12 +387,12 @@ struct daemon { ...@@ -370,12 +387,12 @@ struct daemon {
unsigned int options; unsigned int options;
struct resolvc default_resolv, *resolv_files; struct resolvc default_resolv, *resolv_files;
struct mx_record *mxnames; struct mx_srv_record *mxnames;
struct txt_record *txt;
char *mxtarget; char *mxtarget;
char *lease_file; char *lease_file;
char *username, *groupname; char *username, *groupname;
char *domain_suffix; char *domain_suffix;
struct srv_record *srvnames;
char *runfile; char *runfile;
struct iname *if_names, *if_addrs, *if_except; struct iname *if_names, *if_addrs, *if_except;
struct bogus_addr *bogus_addr; struct bogus_addr *bogus_addr;
...@@ -397,6 +414,7 @@ struct daemon { ...@@ -397,6 +414,7 @@ struct daemon {
/* globally used stuff for DNS */ /* globally used stuff for DNS */
char *packet; /* packet buffer */ char *packet; /* packet buffer */
int packet_buff_sz; /* size of above */
char *namebuff; /* MAXDNAME size buffer */ char *namebuff; /* MAXDNAME size buffer */
struct serverfd *sfds; struct serverfd *sfds;
struct listener *listeners; struct listener *listeners;
...@@ -405,6 +423,9 @@ struct daemon { ...@@ -405,6 +423,9 @@ struct daemon {
/* DHCP state */ /* DHCP state */
int dhcpfd, dhcp_raw_fd, dhcp_icmp_fd, lease_fd; int dhcpfd, dhcp_raw_fd, dhcp_icmp_fd, lease_fd;
#ifdef HAVE_RTNETLINK
int netlinkfd;
#endif
struct udp_dhcp_packet *dhcp_packet; struct udp_dhcp_packet *dhcp_packet;
char *dhcp_buff, *dhcp_buff2; char *dhcp_buff, *dhcp_buff2;
}; };
...@@ -443,7 +464,7 @@ int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name, ...@@ -443,7 +464,7 @@ int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name,
unsigned char *find_pseudoheader(HEADER *header, unsigned int plen, unsigned char *find_pseudoheader(HEADER *header, unsigned int plen,
unsigned int *len, unsigned char **p); unsigned int *len, unsigned char **p);
int check_for_local_domain(char *name, time_t now, struct daemon *daemon); int check_for_local_domain(char *name, time_t now, struct daemon *daemon);
unsigned int questions_crc(HEADER *header, unsigned int plen); unsigned int questions_crc(HEADER *header, unsigned int plen, char *buff);
int resize_packet(HEADER *header, unsigned int plen, int resize_packet(HEADER *header, unsigned int plen,
unsigned char *pheader, unsigned int hlen); unsigned char *pheader, unsigned int hlen);
...@@ -453,8 +474,8 @@ int legal_char(char c); ...@@ -453,8 +474,8 @@ int legal_char(char c);
int canonicalise(char *s); int canonicalise(char *s);
int atoi_check(char *a, int *res); int atoi_check(char *a, int *res);
void die(char *message, char *arg1); void die(char *message, char *arg1);
void complain(char *message, char *arg1); void complain(char *message, int lineno, char *file);
void *safe_malloc(int size); void *safe_malloc(size_t size);
char *safe_string_alloc(char *cp); char *safe_string_alloc(char *cp);
int sa_len(union mysockaddr *addr); int sa_len(union mysockaddr *addr);
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2); int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
...@@ -462,6 +483,9 @@ int hostname_isequal(unsigned char *a, unsigned char *b); ...@@ -462,6 +483,9 @@ int hostname_isequal(unsigned char *a, unsigned char *b);
time_t dnsmasq_time(int fd); time_t dnsmasq_time(int fd);
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask); int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
int retry_send(void); int retry_send(void);
void prettyprint_time(char *buf, unsigned int t);
int parse_hex(char *in, unsigned char *out, int maxlen,
unsigned int *wildcard_mask);
/* option.c */ /* option.c */
struct daemon *read_opts (int argc, char **argv); struct daemon *read_opts (int argc, char **argv);
...@@ -501,22 +525,29 @@ void dhcp_read_ethers(struct daemon *daemon); ...@@ -501,22 +525,29 @@ void dhcp_read_ethers(struct daemon *daemon);
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr); struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
char *strip_hostname(struct daemon *daemon, char *hostname); char *strip_hostname(struct daemon *daemon, char *hostname);
char *host_from_dns(struct daemon *daemon, struct in_addr addr); char *host_from_dns(struct daemon *daemon, struct in_addr addr);
struct dhcp_context *complete_context(struct daemon *daemon, struct in_addr local,
struct dhcp_context *current, struct in_addr netmask,
struct in_addr broadcast, struct in_addr relay,
struct in_addr primary);
/* lease.c */ /* lease.c */
void lease_update_file(int force, time_t now); void lease_update_file(int force, time_t now);
void lease_update_dns(struct daemon *daemon); void lease_update_dns(struct daemon *daemon);
void lease_init(struct daemon *daemon, time_t now); void lease_init(struct daemon *daemon, time_t now);
struct dhcp_lease *lease_allocate(unsigned char *clid, int clid_len, struct in_addr addr); struct dhcp_lease *lease_allocate(unsigned char *hwaddr, unsigned char *clid,
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr); int clid_len, struct in_addr addr);
int lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
unsigned char *clid, int clid_len);
void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix); void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix);
void lease_set_expires(struct dhcp_lease *lease, time_t exp); void lease_set_expires(struct dhcp_lease *lease, time_t exp);
struct dhcp_lease *lease_find_by_client(unsigned char *clid, int clid_len); struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr,
unsigned char *clid, int clid_len);
struct dhcp_lease *lease_find_by_addr(struct in_addr addr); struct dhcp_lease *lease_find_by_addr(struct in_addr addr);
void lease_prune(struct dhcp_lease *target, time_t now); void lease_prune(struct dhcp_lease *target, time_t now);
void lease_update_from_configs(struct dhcp_config *dhcp_configs, char *domain); void lease_update_from_configs(struct dhcp_config *dhcp_configs, char *domain);
/* rfc2131.c */ /* rfc2131.c */
int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_name, unsigned int sz, time_t now); int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_name, unsigned int sz, time_t now);
/* dnsmasq.c */ /* dnsmasq.c */
int icmp_ping(struct daemon *daemon, struct in_addr addr); int icmp_ping(struct daemon *daemon, struct in_addr addr);
...@@ -526,3 +557,10 @@ int icmp_ping(struct daemon *daemon, struct in_addr addr); ...@@ -526,3 +557,10 @@ int icmp_ping(struct daemon *daemon, struct in_addr addr);
void load_dhcp(struct daemon *daemon, time_t now); void load_dhcp(struct daemon *daemon, time_t now);
#endif #endif
/* netlink.c */
#ifdef HAVE_RTNETLINK
int netlink_init(void);
int netlink_process(struct daemon *daemon, int index,
struct in_addr relay, struct in_addr primary,
struct dhcp_context **retp);
#endif
...@@ -213,12 +213,12 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud ...@@ -213,12 +213,12 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud
{ {
struct frec *forward; struct frec *forward;
char *domain = NULL; char *domain = NULL;
int forwardall = 0, type = 0; int type = 0;
struct all_addr *addrp = NULL; struct all_addr *addrp = NULL;
unsigned short flags = 0; unsigned short flags = 0;
unsigned short gotname = extract_request(header, (unsigned int)plen, daemon->namebuff, NULL); unsigned short gotname = extract_request(header, (unsigned int)plen, daemon->namebuff, NULL);
struct server *start = NULL; struct server *start = NULL;
unsigned int crc = questions_crc(header,(unsigned int)plen); unsigned int crc = questions_crc(header,(unsigned int)plen, daemon->namebuff);
/* may be recursion not speced or no servers available. */ /* may be recursion not speced or no servers available. */
if (!header->rd || !daemon->servers) if (!header->rd || !daemon->servers)
...@@ -229,7 +229,7 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud ...@@ -229,7 +229,7 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud
domain = forward->sentto->domain; domain = forward->sentto->domain;
if (!(daemon->options & OPT_ORDER)) if (!(daemon->options & OPT_ORDER))
{ {
forwardall = 1; forward->forwardall = 1;
daemon->last_server = NULL; daemon->last_server = NULL;
} }
type = forward->sentto->flags & SERV_TYPE; type = forward->sentto->flags & SERV_TYPE;
...@@ -248,6 +248,16 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud ...@@ -248,6 +248,16 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud
if (forward) if (forward)
{ {
forward->source = *udpaddr;
forward->dest = *dst_addr;
forward->iface = dst_iface;
forward->new_id = get_id();
forward->fd = udpfd;
forward->orig_id = ntohs(header->id);
forward->crc = crc;
forward->forwardall = 0;
header->id = htons(forward->new_id);
/* In strict_order mode, or when using domain specific servers /* In strict_order mode, or when using domain specific servers
always try servers in the order specified in resolv.conf, always try servers in the order specified in resolv.conf,
otherwise, use the one last known to work. */ otherwise, use the one last known to work. */
...@@ -257,17 +267,8 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud ...@@ -257,17 +267,8 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud
else if (!(start = daemon->last_server)) else if (!(start = daemon->last_server))
{ {
start = daemon->servers; start = daemon->servers;
forwardall = 1; forward->forwardall = 1;
} }
forward->source = *udpaddr;
forward->dest = *dst_addr;
forward->iface = dst_iface;
forward->new_id = get_id();
forward->fd = udpfd;
forward->orig_id = ntohs(header->id);
forward->crc = crc;
header->id = htons(forward->new_id);
} }
} }
...@@ -313,8 +314,9 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud ...@@ -313,8 +314,9 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud
#endif #endif
forwarded = 1; forwarded = 1;
forward->sentto = start; forward->sentto = start;
if (!forwardall) if (!forward->forwardall)
break; break;
forward->forwardall++;
} }
} }
...@@ -341,7 +343,7 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud ...@@ -341,7 +343,7 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud
} }
static int process_reply(struct daemon *daemon, HEADER *header, time_t now, static int process_reply(struct daemon *daemon, HEADER *header, time_t now,
union mysockaddr *serveraddr, unsigned int n) unsigned int query_crc, struct server *server, unsigned int n)
{ {
unsigned char *pheader, *sizep; unsigned char *pheader, *sizep;
unsigned int plen, munged = 0; unsigned int plen, munged = 0;
...@@ -360,25 +362,27 @@ static int process_reply(struct daemon *daemon, HEADER *header, time_t now, ...@@ -360,25 +362,27 @@ static int process_reply(struct daemon *daemon, HEADER *header, time_t now,
PUTSHORT(daemon->edns_pktsz, psave); PUTSHORT(daemon->edns_pktsz, psave);
} }
if (header->opcode != QUERY || (header->rcode != NOERROR && header->rcode != NXDOMAIN))
return n;
/* Complain loudly if the upstream server is non-recursive. */ /* Complain loudly if the upstream server is non-recursive. */
if (!header->ra && header->rcode == NOERROR && ntohs(header->ancount) == 0) if (!header->ra && header->rcode == NOERROR && ntohs(header->ancount) == 0 &&
server && !(server->flags & SERV_WARNED_RECURSIVE))
{ {
char addrbuff[ADDRSTRLEN]; char addrbuff[ADDRSTRLEN];
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (serveraddr->sa.sa_family == AF_INET) if (server->addr.sa.sa_family == AF_INET)
inet_ntop(AF_INET, &serveraddr->in.sin_addr, addrbuff, ADDRSTRLEN); inet_ntop(AF_INET, &server->addr.in.sin_addr, addrbuff, ADDRSTRLEN);
else if (serveraddr->sa.sa_family == AF_INET6) else if (server->addr.sa.sa_family == AF_INET6)
inet_ntop(AF_INET6, &serveraddr->in6.sin6_addr, addrbuff, ADDRSTRLEN); inet_ntop(AF_INET6, &server->addr.in6.sin6_addr, addrbuff, ADDRSTRLEN);
#else #else
strcpy(addrbuff, inet_ntoa(serveraddr->in.sin_addr)); strcpy(addrbuff, inet_ntoa(server->addr.in.sin_addr));
#endif #endif
syslog(LOG_WARNING, "nameserver %s refused to do a recursive query", addrbuff); syslog(LOG_WARNING, "nameserver %s refused to do a recursive query", addrbuff);
return 0; if (!(daemon->options & OPT_LOG))
} server->flags |= SERV_WARNED_RECURSIVE;
}
if (header->opcode != QUERY || (header->rcode != NOERROR && header->rcode != NXDOMAIN))
return n;
if (daemon->bogus_addr && header->rcode != NXDOMAIN && if (daemon->bogus_addr && header->rcode != NXDOMAIN &&
check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now)) check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
{ {
...@@ -400,7 +404,11 @@ static int process_reply(struct daemon *daemon, HEADER *header, time_t now, ...@@ -400,7 +404,11 @@ static int process_reply(struct daemon *daemon, HEADER *header, time_t now,
header->rcode = NOERROR; header->rcode = NOERROR;
} }
extract_addresses(header, n, daemon->namebuff, now, daemon); /* If the crc of the question section doesn't match the crc we sent, then
someone might be attempting to insert bogus values into the cache by
sending replies containing questions and bogus answers. */
if (query_crc == questions_crc(header, n, daemon->namebuff))
extract_addresses(header, n, daemon->namebuff, now, daemon);
} }
/* do this after extract_addresses. Ensure NODATA reply and remove /* do this after extract_addresses. Ensure NODATA reply and remove
...@@ -442,28 +450,42 @@ void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now) ...@@ -442,28 +450,42 @@ void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now)
if (n >= (int)sizeof(HEADER) && header->qr && forward) if (n >= (int)sizeof(HEADER) && header->qr && forward)
{ {
/* find good server by address if possible, otherwise assume the last one we sent to */ struct server *server = forward->sentto;
if ((forward->sentto->flags & SERV_TYPE) == 0)
{ if ((forward->sentto->flags & SERV_TYPE) == 0)
struct server *last_server; {
daemon->last_server = forward->sentto; if (header->rcode == SERVFAIL || header->rcode == REFUSED)
for (last_server = daemon->servers; last_server; last_server = last_server->next) server = NULL;
if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) && else
sockaddr_isequal(&last_server->addr, &serveraddr)) {
{ /* find good server by address if possible, otherwise assume the last one we sent to */
daemon->last_server = last_server; struct server *last_server;
break; for (last_server = daemon->servers; last_server; last_server = last_server->next)
} if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
} sockaddr_isequal(&last_server->addr, &serveraddr))
{
if ((n = process_reply(daemon, header, now, &serveraddr, (unsigned int)n))) server = last_server;
break;
}
}
daemon->last_server = server;
}
if ((n = process_reply(daemon, header, now, forward->crc, server, (unsigned int)n)))
{ {
header->id = htons(forward->orig_id); header->id = htons(forward->orig_id);
header->ra = 1; /* recursion if available */ header->ra = 1; /* recursion if available */
send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, n, send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, n,
&forward->source, &forward->dest, forward->iface); &forward->source, &forward->dest, forward->iface);
forward->new_id = 0; /* cancel */
} }
/* If the answer is an error, keep the forward record in place in case
we get a good reply from another server. Kill it when we've
had replies from all to avoid filling the forwarding table when
everything is broken */
if (forward->forwardall == 0 || --forward->forwardall == 1 ||
(header->rcode != REFUSED && header->rcode != SERVFAIL))
forward->new_id = 0; /* cancel */
} }
} }
...@@ -728,7 +750,8 @@ char *tcp_request(struct daemon *daemon, int confd, time_t now, ...@@ -728,7 +750,8 @@ char *tcp_request(struct daemon *daemon, int confd, time_t now,
if (!flags && last_server) if (!flags && last_server)
{ {
struct server *firstsendto = NULL; struct server *firstsendto = NULL;
unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);
/* Loop round available servers until we succeed in connecting to one. /* Loop round available servers until we succeed in connecting to one.
Note that this code subtley ensures that consecutive queries on this connection Note that this code subtley ensures that consecutive queries on this connection
which can go to the same server, do so. */ which can go to the same server, do so. */
...@@ -793,7 +816,7 @@ char *tcp_request(struct daemon *daemon, int confd, time_t now, ...@@ -793,7 +816,7 @@ char *tcp_request(struct daemon *daemon, int confd, time_t now,
/* There's no point in updating the cache, since this process will exit and /* There's no point in updating the cache, since this process will exit and
lose the information after one query. We make this call for the alias and lose the information after one query. We make this call for the alias and
bogus-nxdomain side-effects. */ bogus-nxdomain side-effects. */
m = process_reply(daemon, header, now, &last_server->addr, (unsigned int)m); m = process_reply(daemon, header, now, crc, last_server, (unsigned int)m);
break; break;
} }
......
...@@ -16,12 +16,13 @@ ...@@ -16,12 +16,13 @@
static struct dhcp_lease *leases; static struct dhcp_lease *leases;
static FILE *lease_file; static FILE *lease_file;
static int dns_dirty, file_dirty, new_lease; static int dns_dirty;
enum { no, yes, force } file_dirty;
static int leases_left; static int leases_left;
void lease_init(struct daemon *daemon, time_t now) void lease_init(struct daemon *daemon, time_t now)
{ {
unsigned int e0, e1, e2, e3, e4, e5, a0, a1, a2, a3; unsigned int a0, a1, a2, a3;
unsigned long ei; unsigned long ei;
time_t expires; time_t expires;
unsigned char hwaddr[ETHER_ADDR_LEN]; unsigned char hwaddr[ETHER_ADDR_LEN];
...@@ -29,9 +30,7 @@ void lease_init(struct daemon *daemon, time_t now) ...@@ -29,9 +30,7 @@ void lease_init(struct daemon *daemon, time_t now)
struct dhcp_lease *lease; struct dhcp_lease *lease;
int clid_len = 0; int clid_len = 0;
int has_old = 0; int has_old = 0;
char *buff = daemon->dhcp_buff;
char *buff2 = daemon->dhcp_buff2;
leases = NULL; leases = NULL;
leases_left = daemon->dhcp_max; leases_left = daemon->dhcp_max;
...@@ -42,9 +41,11 @@ void lease_init(struct daemon *daemon, time_t now) ...@@ -42,9 +41,11 @@ void lease_init(struct daemon *daemon, time_t now)
/* a+ mode lease pointer at end. */ /* a+ mode lease pointer at end. */
rewind(lease_file); rewind(lease_file);
while (fscanf(lease_file, "%lu %x:%x:%x:%x:%x:%x %d.%d.%d.%d %257s %257s", /* client-id max length is 255 which is 255*2 digits + 254 colons
&ei, &e0, &e1, &e2, &e3, &e4, &e5, &a0, &a1, &a2, &a3, borrow DNS packet buffer which is always larger than 1000 bytes */
buff, buff2) == 13) while (fscanf(lease_file, "%lu %40s %d.%d.%d.%d %255s %764s",
&ei, daemon->dhcp_buff2, &a0, &a1, &a2, &a3,
daemon->dhcp_buff, daemon->packet) == 8)
{ {
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
if (ei) if (ei)
...@@ -63,41 +64,26 @@ void lease_init(struct daemon *daemon, time_t now) ...@@ -63,41 +64,26 @@ void lease_init(struct daemon *daemon, time_t now)
} }
#endif #endif
hwaddr[0] = e0; parse_hex(daemon->dhcp_buff2, hwaddr, ETHER_ADDR_LEN, NULL);
hwaddr[1] = e1;
hwaddr[2] = e2;
hwaddr[3] = e3;
hwaddr[4] = e4;
hwaddr[5] = e5;
addr.s_addr = htonl((a0<<24) + (a1<<16) + (a2<<8) + a3); addr.s_addr = htonl((a0<<24) + (a1<<16) + (a2<<8) + a3);
/* decode hex in place */ /* decode hex in place */
if (strcmp(buff2, "*") == 0) if (strcmp(daemon->packet, "*") == 0)
clid_len = 0; clid_len = 0;
else else
{ clid_len = parse_hex(daemon->packet, daemon->packet, 255, NULL);
int s = (strlen(buff2)/3) + 1;
for (clid_len = 0; clid_len < s; clid_len++)
{
buff2[(clid_len*3)+2] = 0;
buff2[clid_len] = strtol(&buff2[clid_len*3], NULL, 16);
}
}
if (!(lease = lease_allocate(buff2, clid_len, addr))) if (!(lease = lease_allocate(hwaddr, daemon->packet, clid_len, addr)))
die ("too many stored leases", NULL); die ("too many stored leases", NULL);
lease->expires = expires; lease->expires = expires;
memcpy(lease->hwaddr, hwaddr, ETHER_ADDR_LEN);
if (strcmp(buff, "*") != 0) if (strcmp(daemon->dhcp_buff, "*") != 0)
lease_set_hostname(lease, buff, daemon->domain_suffix); lease_set_hostname(lease, daemon->dhcp_buff, daemon->domain_suffix);
} }
dns_dirty = 1; dns_dirty = 1;
file_dirty = has_old; file_dirty = has_old ? yes: no;
new_lease = 0;
daemon->lease_fd = fileno(lease_file); daemon->lease_fd = fileno(lease_file);
} }
...@@ -115,18 +101,18 @@ void lease_update_from_configs(struct dhcp_config *dhcp_configs, char *domain) ...@@ -115,18 +101,18 @@ void lease_update_from_configs(struct dhcp_config *dhcp_configs, char *domain)
lease_set_hostname(lease, config->hostname, domain); lease_set_hostname(lease, config->hostname, domain);
} }
void lease_update_file(int force, time_t now) void lease_update_file(int always, time_t now)
{ {
struct dhcp_lease *lease; struct dhcp_lease *lease;
int i = force; /* avoid warning */ int i = always; /* avoid warning */
unsigned long expires; unsigned long expires;
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
if (force || new_lease) if (always || file_dirty == force)
{ {
lease_prune(NULL, now); lease_prune(NULL, now);
#else #else
if (file_dirty) if (file_dirty != no)
{ {
#endif #endif
rewind(lease_file); rewind(lease_file);
...@@ -149,7 +135,7 @@ void lease_update_file(int force, time_t now) ...@@ -149,7 +135,7 @@ void lease_update_file(int force, time_t now)
lease->hwaddr[5], inet_ntoa(lease->addr), lease->hwaddr[5], inet_ntoa(lease->addr),
lease->hostname && strlen(lease->hostname) != 0 ? lease->hostname : "*"); lease->hostname && strlen(lease->hostname) != 0 ? lease->hostname : "*");
if (lease->clid_len) if (lease->clid && lease->clid_len != 0)
{ {
for (i = 0; i < lease->clid_len - 1; i++) for (i = 0; i < lease->clid_len - 1; i++)
fprintf(lease_file, "%.2x:", lease->clid[i]); fprintf(lease_file, "%.2x:", lease->clid[i]);
...@@ -162,8 +148,7 @@ void lease_update_file(int force, time_t now) ...@@ -162,8 +148,7 @@ void lease_update_file(int force, time_t now)
fflush(lease_file); fflush(lease_file);
fsync(fileno(lease_file)); fsync(fileno(lease_file));
file_dirty = 0; file_dirty = no;
new_lease = 0;
} }
} }
...@@ -194,7 +179,7 @@ void lease_prune(struct dhcp_lease *target, time_t now) ...@@ -194,7 +179,7 @@ void lease_prune(struct dhcp_lease *target, time_t now)
tmp = lease->next; tmp = lease->next;
if ((lease->expires != 0 && difftime(now, lease->expires) > 0) || lease == target) if ((lease->expires != 0 && difftime(now, lease->expires) > 0) || lease == target)
{ {
file_dirty = 1; file_dirty = yes;
*up = lease->next; /* unlink */ *up = lease->next; /* unlink */
if (lease->hostname) if (lease->hostname)
...@@ -215,23 +200,21 @@ void lease_prune(struct dhcp_lease *target, time_t now) ...@@ -215,23 +200,21 @@ void lease_prune(struct dhcp_lease *target, time_t now)
} }
struct dhcp_lease *lease_find_by_client(unsigned char *clid, int clid_len) struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr,
unsigned char *clid, int clid_len)
{ {
struct dhcp_lease *lease; struct dhcp_lease *lease;
if (clid_len) if (clid)
{ for (lease = leases; lease; lease = lease->next)
for (lease = leases; lease; lease = lease->next) if (lease->clid && clid_len == lease->clid_len &&
if (lease->clid && clid_len == lease->clid_len &&
memcmp(clid, lease->clid, clid_len) == 0) memcmp(clid, lease->clid, clid_len) == 0)
return lease; return lease;
}
else for (lease = leases; lease; lease = lease->next)
{ if ((!lease->clid || !clid) &&
for (lease = leases; lease; lease = lease->next) memcmp(hwaddr, lease->hwaddr, ETHER_ADDR_LEN) == 0)
if (memcmp(clid, lease->hwaddr, ETHER_ADDR_LEN) == 0) return lease;
return lease;
}
return NULL; return NULL;
} }
...@@ -248,35 +231,29 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr) ...@@ -248,35 +231,29 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
} }
struct dhcp_lease *lease_allocate(unsigned char *clid, int clid_len, struct in_addr addr) struct dhcp_lease *lease_allocate(unsigned char *hwaddr, unsigned char *clid,
int clid_len, struct in_addr addr)
{ {
struct dhcp_lease *lease; struct dhcp_lease *lease;
if (!leases_left || !(lease = malloc(sizeof(struct dhcp_lease)))) if (!leases_left || !(lease = malloc(sizeof(struct dhcp_lease))))
return NULL; return NULL;
lease->clid = NULL; lease->clid = NULL;
lease->clid_len = clid_len; lease->hostname = lease->fqdn = NULL;
if (clid_len)
{
if (!(lease->clid = malloc(clid_len)))
{
free(lease);
return NULL;
}
memcpy(lease->clid, clid, clid_len);
}
lease->hostname = lease->fqdn = NULL;
lease->addr = addr; lease->addr = addr;
memset(lease->hwaddr, 0, ETHER_ADDR_LEN); memset(lease->hwaddr, 0, ETHER_ADDR_LEN);
lease->expires = 1; lease->expires = 1;
if (!lease_set_hwaddr(lease, hwaddr, clid, clid_len))
{
free(lease);
return NULL;
}
lease->next = leases; lease->next = leases;
leases = lease; leases = lease;
file_dirty = 1; file_dirty = force;
new_lease = 1;
leases_left--; leases_left--;
return lease; return lease;
...@@ -285,18 +262,46 @@ struct dhcp_lease *lease_allocate(unsigned char *clid, int clid_len, struct in_a ...@@ -285,18 +262,46 @@ struct dhcp_lease *lease_allocate(unsigned char *clid, int clid_len, struct in_a
void lease_set_expires(struct dhcp_lease *lease, time_t exp) void lease_set_expires(struct dhcp_lease *lease, time_t exp)
{ {
if (exp != lease->expires) if (exp != lease->expires)
file_dirty = dns_dirty = 1; {
file_dirty = yes;
dns_dirty = 1;
}
lease->expires = exp; lease->expires = exp;
} }
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr) int lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
unsigned char *clid, int clid_len)
{ {
if (memcmp(lease->hwaddr, hwaddr, ETHER_ADDR_LEN) != 0) if (memcmp(lease->hwaddr, hwaddr, ETHER_ADDR_LEN) != 0)
{ {
file_dirty = 1; file_dirty = force;
memcpy(lease->hwaddr, hwaddr, ETHER_ADDR_LEN); memcpy(lease->hwaddr, hwaddr, ETHER_ADDR_LEN);
} }
/* only update clid when one is available, stops packets
without a clid removing the record. Lease init uses
clid_len == 0 for no clid. */
if (clid_len != 0 && clid)
{
if (!lease->clid)
lease->clid_len = 0;
if (lease->clid_len != clid_len)
{
file_dirty = force;
if (lease->clid)
free(lease->clid);
if (!(lease->clid = malloc(clid_len)))
return 0;
}
else if (memcmp(lease->clid, clid, clid_len) != 0)
file_dirty = force;
lease->clid_len = clid_len;
memcpy(lease->clid, clid, clid_len);
}
return 1;
} }
void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix) void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix)
...@@ -347,7 +352,8 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix) ...@@ -347,7 +352,8 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix)
lease->hostname = new_name; lease->hostname = new_name;
lease->fqdn = new_fqdn; lease->fqdn = new_fqdn;
file_dirty = dns_dirty = 1; file_dirty = force;
dns_dirty = 1;
} }
......
/* dnsmasq is Copyright (c) 2000-2005 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
/* Author's email: simon@thekelleys.org.uk */
#include "dnsmasq.h"
#ifdef HAVE_RTNETLINK
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
int netlink_init(void)
{
struct sockaddr_nl addr;
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (sock < 0)
return -1; /* no kernel support */
addr.nl_family = AF_NETLINK;
addr.nl_pad = 0;
addr.nl_pid = getpid();
addr.nl_groups = 0;
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
die("cannot bind netlink socket: %s", NULL);
return sock;
}
/* We borrow the DNS packet buffer here. (The DHCP one already has a packet in it)
Since it's used only within this routine, that's fine, just remember
that calling icmp_echo() will trash it */
int netlink_process(struct daemon *daemon, int index, struct in_addr relay,
struct in_addr primary, struct dhcp_context **retp)
{
struct sockaddr_nl addr;
struct nlmsghdr *h;
int len, found_primary = 0;
struct dhcp_context *ret = NULL;
static unsigned int seq = 0;
struct {
struct nlmsghdr nlh;
struct rtgenmsg g;
} req;
if (daemon->netlinkfd == -1)
return 0;
addr.nl_family = AF_NETLINK;
addr.nl_pad = 0;
addr.nl_groups = 0;
addr.nl_pid = 0; /* address to kernel */
req.nlh.nlmsg_len = sizeof(req);
req.nlh.nlmsg_type = RTM_GETADDR;
req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
req.nlh.nlmsg_pid = 0;
req.nlh.nlmsg_seq = ++seq;
req.g.rtgen_family = AF_INET;
/* Don't block in recvfrom if send fails */
while((len = sendto(daemon->netlinkfd, (void *)&req, sizeof(req), 0,
(struct sockaddr *)&addr, sizeof(addr))) == -1 && retry_send());
if (len == -1)
{
/* if RTnetlink not configured in the kernel, don't keep trying. */
if (errno == ECONNREFUSED)
{
close(daemon->netlinkfd);
daemon->netlinkfd = -1;
}
return 0;
}
get_next:
while((len = recvfrom(daemon->netlinkfd, daemon->packet, daemon->packet_buff_sz,
MSG_WAITALL, NULL, 0)) == -1 && retry_send());
if (len == -1)
return 0;
h = (struct nlmsghdr *)daemon->packet;
while (NLMSG_OK(h, (unsigned int)len))
{
if (h->nlmsg_seq != seq)
goto get_next;
if (h->nlmsg_type == NLMSG_DONE)
break;
if (h->nlmsg_type == NLMSG_ERROR)
return 0;
if (h->nlmsg_type == RTM_NEWADDR)
{
struct ifaddrmsg *ifa = NLMSG_DATA(h);
if (ifa->ifa_index == index && ifa->ifa_family == AF_INET)
{
struct rtattr *rta = IFA_RTA(ifa);
unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa));
struct in_addr netmask, addr, broadcast;
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
addr.s_addr = 0;
broadcast.s_addr = 0;
while (RTA_OK(rta, len1))
{
if (rta->rta_type == IFA_LOCAL)
addr = *((struct in_addr *)(rta+1));
else if (rta->rta_type == IFA_BROADCAST)
broadcast = *((struct in_addr *)(rta+1));
rta = RTA_NEXT(rta, len1);
}
if (addr.s_addr && broadcast.s_addr)
{
ret = complete_context(daemon, addr, ret, netmask, broadcast, relay, primary);
if (addr.s_addr == primary.s_addr)
found_primary = 1;
}
}
}
h = NLMSG_NEXT(h, len);
}
*retp = ret;
return found_primary;
}
#endif
...@@ -200,7 +200,7 @@ int enumerate_interfaces(struct daemon *daemon, struct irec **chainp, ...@@ -200,7 +200,7 @@ int enumerate_interfaces(struct daemon *daemon, struct irec **chainp,
if ((f = fopen(IP6INTERFACES, "r"))) if ((f = fopen(IP6INTERFACES, "r")))
{ {
unsigned int plen, scope, flags, if_idx; unsigned int plen, scope, flags, if_idx;
char devname[20], addrstring[32]; char devname[21], addrstring[33];
while (fscanf(f, "%32s %x %x %x %x %20s\n", while (fscanf(f, "%32s %x %x %x %x %20s\n",
addrstring, &if_idx, &plen, &scope, &flags, devname) != EOF) addrstring, &if_idx, &plen, &scope, &flags, devname) != EOF)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* dnsmasq is Copyright (c) 2000 Simon Kelley /* dnsmasq is Copyright (c) 2000 - 2005 Simon Kelley
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -114,7 +114,7 @@ int canonicalise(char *s) ...@@ -114,7 +114,7 @@ int canonicalise(char *s)
{ {
/* check for legal chars and remove trailing . /* check for legal chars and remove trailing .
also fail empty string and label > 63 chars */ also fail empty string and label > 63 chars */
int dotgap = 0, l = strlen(s); size_t dotgap = 0, l = strlen(s);
char c; char c;
if (l == 0 || l > MAXDNAME) return 0; if (l == 0 || l > MAXDNAME) return 0;
...@@ -135,7 +135,7 @@ int canonicalise(char *s) ...@@ -135,7 +135,7 @@ int canonicalise(char *s)
} }
/* for use during startup */ /* for use during startup */
void *safe_malloc(int size) void *safe_malloc(size_t size)
{ {
void *ret = malloc(size); void *ret = malloc(size);
...@@ -158,7 +158,7 @@ char *safe_string_alloc(char *cp) ...@@ -158,7 +158,7 @@ char *safe_string_alloc(char *cp)
return ret; return ret;
} }
void complain(char *message, char *arg1) static void log_err(char *message, char *arg1)
{ {
char *errmess = strerror(errno); char *errmess = strerror(errno);
...@@ -172,9 +172,17 @@ void complain(char *message, char *arg1) ...@@ -172,9 +172,17 @@ void complain(char *message, char *arg1)
syslog(LOG_CRIT, message, arg1, errmess); syslog(LOG_CRIT, message, arg1, errmess);
} }
void complain(char *message, int lineno, char *file)
{
char buff[256];
sprintf(buff, "%s at line %d of %s", message, lineno, file);
log_err(buff, NULL);
}
void die(char *message, char *arg1) void die(char *message, char *arg1)
{ {
complain(message, arg1); log_err(message, arg1);
syslog(LOG_CRIT, "FAILED to start up"); syslog(LOG_CRIT, "FAILED to start up");
exit(1); exit(1);
} }
...@@ -270,3 +278,50 @@ int retry_send(void) ...@@ -270,3 +278,50 @@ int retry_send(void)
return 0; return 0;
} }
void prettyprint_time(char *buf, unsigned int t)
{
if (t == 0xffffffff)
sprintf(buf, "infinite");
else
{
unsigned int x, p = 0;
if ((x = t/3600))
p += sprintf(&buf[p], "%dh", x);
if ((x = (t/60)%60))
p += sprintf(&buf[p], "%dm", x);
if ((x = t%60))
p += sprintf(&buf[p], "%ds", x);
}
}
/* in may equal out, when maxlen may be -1 (No max len). */
int parse_hex(char *in, unsigned char *out, int maxlen, unsigned int *wildcard_mask)
{
int mask = 0, i = 0;
char *r;
while (maxlen == -1 || i < maxlen)
{
for (r = in; *r != 0 && *r != ':' && *r != '-'; r++);
if (*r == 0)
maxlen = i;
if (r != in )
{
*r = 0;
mask = mask << 1;
if (strcmp(in, "*") == 0)
mask |= 1;
else
out[i] = strtol(in, NULL, 16);
i++;
}
in = r+1;
}
if (wildcard_mask)
*wildcard_mask = mask;
return i;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment