mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-11 16:40:27 +00:00
Compare commits
19
Commits
v2.85
...
v2.86test2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c9f136b57 | ||
|
|
5ab7e4a475 | ||
|
|
3236f358f8 | ||
|
|
4a6550d69a | ||
|
|
ff523d0c67 | ||
|
|
3c93e8eb41 | ||
|
|
88a482fdb9 | ||
|
|
12a9aa7c62 | ||
|
|
50ccf9c585 | ||
|
|
d100eb05a3 | ||
|
|
10d8b5f001 | ||
|
|
ffd3ceb856 | ||
|
|
d942aa9321 | ||
|
|
6469fefe89 | ||
|
|
b082842ee7 | ||
|
|
3573ca0eec | ||
|
|
ad90eb075d | ||
|
|
d55e2d086d | ||
|
|
fe9c966a49 |
No files matched your search
@@ -1,3 +1,70 @@
|
|||||||
|
version 2.86
|
||||||
|
Handle DHCPREBIND requests in the DHCPv6 server code.
|
||||||
|
Thanks to Aichun Li for spotting this ommision, and the initial
|
||||||
|
patch.
|
||||||
|
|
||||||
|
Fix bug which caused dnsmasq to lose track of processes forked
|
||||||
|
to handle TCP DNS connections under heavy load. The code
|
||||||
|
checked that at least one free process table slot was
|
||||||
|
available before listening on TCP sockets, but didn't take
|
||||||
|
into account that more than one TCP connection could
|
||||||
|
arrive, so that check was not sufficient to ensure that
|
||||||
|
there would be slots for all new processes. It compounded
|
||||||
|
this error by silently failing to store the process when
|
||||||
|
it did run out of slots. Even when this bug is triggered,
|
||||||
|
all the right things happen, and answers are still returned.
|
||||||
|
Only under very exceptional circumstances, does the bug
|
||||||
|
manifest itself: see
|
||||||
|
https://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2021q2/014976.html
|
||||||
|
Thanks to Tijs Van Buggenhout for finding the conditions under
|
||||||
|
which the bug manifests itself, and then working out
|
||||||
|
exactly what was going on.
|
||||||
|
|
||||||
|
Major rewrite of the DNS server and domain handling code.
|
||||||
|
This should be largely transparent, but it drastically
|
||||||
|
improves performance and reduces memory foot-print when
|
||||||
|
configuring large numbers domains of the form
|
||||||
|
local=/adserver.com/
|
||||||
|
or
|
||||||
|
local=/adserver.com/#
|
||||||
|
Lookup times now grow as log-to-base-2 of the number of domains,
|
||||||
|
rather than greater than linearly, as before.
|
||||||
|
The change makes multiple addresses associated with a domain work
|
||||||
|
address=/example.com/1.2.3.4
|
||||||
|
address=/example.com/5.6.7.8
|
||||||
|
It also handles multiple upstream servers for a domain better; using
|
||||||
|
the same try/retry alogrithms as non domain-specific servers. This
|
||||||
|
also applies to DNSSEC-generated queries.
|
||||||
|
Finally, some of the oldest and gnarliest code in dnsmasq has had
|
||||||
|
a significant clean-up. It's far from perfect, but it _is_ better.
|
||||||
|
|
||||||
|
Revise resource handling for number of concurrent DNS queries. This
|
||||||
|
used to have a global limit, but that has a problem when using
|
||||||
|
different servers for different upstream domains. Queries which are
|
||||||
|
routed by domain to an upstream server which is not responding will
|
||||||
|
build up and trigger the limit, which breaks DNS service for
|
||||||
|
all other domains which could be handled by other servers. The
|
||||||
|
change is to make the limit per server-group, where a server group
|
||||||
|
is the set of servers configured for a particular domain. In the
|
||||||
|
common case, where only default servers are declared, there is
|
||||||
|
no effective change.
|
||||||
|
|
||||||
|
Improve efficiency of DNSSEC. The sharing point for DNSSEC RR data
|
||||||
|
used to be when it entered the cache, having been validated. After
|
||||||
|
that queries requiring the KEY or DS records would share the cached
|
||||||
|
values. There is a common case in dual-stack hosts that queries for
|
||||||
|
A and AAAA records for the same domain are made simultaneously.
|
||||||
|
If required keys were not in the cache, this would result in two
|
||||||
|
requests being sent upstream for the same key data (and all the
|
||||||
|
subsequent chain-of-trust queries.) Now we combine these requests
|
||||||
|
and elide the duplicates, resulting in fewer queries upstream
|
||||||
|
and better performance. To keep a better handle on what's
|
||||||
|
going on, the "extra" logging mode has been modified to associate
|
||||||
|
queries and answers for DNSSEC queries in the same way as ordinary
|
||||||
|
queries. The requesting address and port have been removed from
|
||||||
|
DNSSEC logging lines, since this is no longer strictly defined.
|
||||||
|
|
||||||
|
|
||||||
version 2.85
|
version 2.85
|
||||||
Fix problem with DNS retries in 2.83/2.84.
|
Fix problem with DNS retries in 2.83/2.84.
|
||||||
The new logic in 2.83/2.84 which merges distinct requests
|
The new logic in 2.83/2.84 which merges distinct requests
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
|
|||||||
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
|
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
|
||||||
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
|
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
|
||||||
poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o \
|
poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o \
|
||||||
metrics.o hash_questions.o
|
metrics.o hash-questions.o domain-match.o
|
||||||
|
|
||||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||||
dns-protocol.h radv-protocol.h ip6addr.h metrics.h
|
dns-protocol.h radv-protocol.h ip6addr.h metrics.h
|
||||||
|
|||||||
+2
-1
@@ -11,7 +11,8 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
|||||||
radv.c slaac.c auth.c ipset.c domain.c \
|
radv.c slaac.c auth.c ipset.c domain.c \
|
||||||
dnssec.c dnssec-openssl.c blockdata.c tables.c \
|
dnssec.c dnssec-openssl.c blockdata.c tables.c \
|
||||||
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c \
|
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c \
|
||||||
crypto.c dump.c ubus.c metrics.c hash_questions.c
|
crypto.c dump.c ubus.c metrics.c hash-questions.c \
|
||||||
|
domain-match.c
|
||||||
|
|
||||||
LOCAL_MODULE := dnsmasq
|
LOCAL_MODULE := dnsmasq
|
||||||
|
|
||||||
|
|||||||
Vendored
+7
-1
@@ -1,3 +1,9 @@
|
|||||||
|
dnsmasq (2.86-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* Fix debian/changelog format error. (closes: #986626)
|
||||||
|
|
||||||
|
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 08 Apr 2021 22:39:00 +0100
|
||||||
|
|
||||||
dnsmasq (2.85-1) unstable; urgency=low
|
dnsmasq (2.85-1) unstable; urgency=low
|
||||||
|
|
||||||
* New upstream.
|
* New upstream.
|
||||||
@@ -1075,7 +1081,7 @@ dnsmasq (2.6-2) unstable; urgency=low
|
|||||||
* Added note about the --bind-interfaces option to
|
* Added note about the --bind-interfaces option to
|
||||||
readme.Debian (closes: #241700)
|
readme.Debian (closes: #241700)
|
||||||
|
|
||||||
-- Simon Kelley <simon@thekelleys.org.uk> Tues, 13 Apr 2004 18:37:55 +0000
|
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 13 Apr 2004 18:37:55 +0000
|
||||||
|
|
||||||
dnsmasq (2.6-1) unstable; urgency=low
|
dnsmasq (2.6-1) unstable; urgency=low
|
||||||
|
|
||||||
|
|||||||
+11
-5
@@ -510,7 +510,7 @@ To include multiple IP addresses for a single query, use
|
|||||||
Note that /etc/hosts and DHCP leases override this for individual
|
Note that /etc/hosts and DHCP leases override this for individual
|
||||||
names. A common use of this is to redirect the entire doubleclick.net
|
names. A common use of this is to redirect the entire doubleclick.net
|
||||||
domain to some friendly local web server to avoid banner ads. The
|
domain to some friendly local web server to avoid banner ads. The
|
||||||
domain specification works in the same was as for \fB--server\fP, with
|
domain specification works in the same way as for \fB--server\fP, with
|
||||||
the additional facility that \fB/#/\fP matches any domain. Thus
|
the additional facility that \fB/#/\fP matches any domain. Thus
|
||||||
\fB--address=/#/1.2.3.4\fP will always return \fB1.2.3.4\fP for any
|
\fB--address=/#/1.2.3.4\fP will always return \fB1.2.3.4\fP for any
|
||||||
query not answered from \fB/etc/hosts\fP or DHCP and not sent to an
|
query not answered from \fB/etc/hosts\fP or DHCP and not sent to an
|
||||||
@@ -711,7 +711,13 @@ will add the /24 and /96 subnets of the requestor for IPv4 and IPv6 requestors,
|
|||||||
will add 1.2.3.0/24 for IPv4 requestors and ::/0 for IPv6 requestors.
|
will add 1.2.3.0/24 for IPv4 requestors and ::/0 for IPv6 requestors.
|
||||||
.B --add-subnet=1.2.3.4/24,1.2.3.4/24
|
.B --add-subnet=1.2.3.4/24,1.2.3.4/24
|
||||||
will add 1.2.3.0/24 for both IPv4 and IPv6 requestors.
|
will add 1.2.3.0/24 for both IPv4 and IPv6 requestors.
|
||||||
|
.TP
|
||||||
|
.B --umbrella[=deviceid:<deviceid>[,orgid:<orgid>]]
|
||||||
|
Embeds the requestor's IP address in DNS queries forwarded upstream.
|
||||||
|
If device id or organization id are specified, the information is
|
||||||
|
included in the forwarded queries and may be able to be used in
|
||||||
|
filtering policies and reporting. The order of the deviceid and orgid
|
||||||
|
attributes is irrelevant, but must be separated by a comma.
|
||||||
.TP
|
.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. Note: huge cache size impacts performance.
|
Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching. Note: huge cache size impacts performance.
|
||||||
@@ -725,7 +731,8 @@ identical queries without forwarding them again.
|
|||||||
Set the maximum number of concurrent DNS queries. The default value is
|
Set the maximum number of concurrent DNS queries. The default value is
|
||||||
150, which should be fine for most setups. The only known situation
|
150, which should be fine for most setups. The only known situation
|
||||||
where this needs to be increased is when using web-server log file
|
where this needs to be increased is when using web-server log file
|
||||||
resolvers, which can generate large numbers of concurrent queries.
|
resolvers, which can generate large numbers of concurrent queries. This
|
||||||
|
parameter actually controls the number of concurrent queries per server group, where a server group is the set of server(s) associated with a single domain. So if a domain has it's own server via --server=/example.com/1.2.3.4 and 1.2.3.4 is not responding, but queries for *.example.com cannot go elsewhere, then other queries will not be affected. On configurations with many such server groups and tight resources, this value may need to be reduced.
|
||||||
.TP
|
.TP
|
||||||
.B --dnssec
|
.B --dnssec
|
||||||
Validate DNS replies and cache DNSSEC data. When forwarding DNS queries, dnsmasq requests the
|
Validate DNS replies and cache DNSSEC data. When forwarding DNS queries, dnsmasq requests the
|
||||||
@@ -869,7 +876,7 @@ in
|
|||||||
.B --dhcp-host
|
.B --dhcp-host
|
||||||
options. If the lease time is given, then leases
|
options. If the lease time is given, then leases
|
||||||
will be given for that length of time. The lease time is in seconds,
|
will be given for that length of time. The lease time is in seconds,
|
||||||
or minutes (eg 45m) or hours (eg 1h) or "infinite". If not given,
|
or minutes (eg 45m) or hours (eg 1h) or days (2d) or weeks (1w) or "infinite". If not given,
|
||||||
the default lease time is one hour for IPv4 and one day for IPv6. The
|
the default lease time is one hour for IPv4 and one day for IPv6. The
|
||||||
minimum lease time is two minutes. For IPv6 ranges, the lease time
|
minimum lease time is two minutes. For IPv6 ranges, the lease time
|
||||||
maybe "deprecated"; this sets the preferred lifetime sent in a DHCP
|
maybe "deprecated"; this sets the preferred lifetime sent in a DHCP
|
||||||
@@ -1517,7 +1524,6 @@ instance
|
|||||||
will enable dnsmasq to also provide proxy PXE service to those PXE clients with
|
will enable dnsmasq to also provide proxy PXE service to those PXE clients with
|
||||||
.I HW-Client
|
.I HW-Client
|
||||||
in as their identifier.
|
in as their identifier.
|
||||||
>>>>>>> 907def3... pxe: support pxe clients with custom vendor-class
|
|
||||||
.TP
|
.TP
|
||||||
.B \-X, --dhcp-lease-max=<number>
|
.B \-X, --dhcp-lease-max=<number>
|
||||||
Limits dnsmasq to the specified maximum number of DHCP leases. The
|
Limits dnsmasq to the specified maximum number of DHCP leases. The
|
||||||
|
|||||||
@@ -867,6 +867,3 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -174,4 +174,3 @@ struct blockdata *blockdata_read(int fd, size_t len)
|
|||||||
{
|
{
|
||||||
return blockdata_alloc_real(fd, NULL, len);
|
return blockdata_alloc_real(fd, NULL, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,5 +440,3 @@ void route_sock(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif /* HAVE_BSD_NETWORK */
|
#endif /* HAVE_BSD_NETWORK */
|
||||||
|
|
||||||
|
|
||||||
+8
-14
@@ -1605,16 +1605,13 @@ int cache_make_stat(struct txt_record *t)
|
|||||||
serv->flags &= ~SERV_COUNTED;
|
serv->flags &= ~SERV_COUNTED;
|
||||||
|
|
||||||
for (serv = daemon->servers; serv; serv = serv->next)
|
for (serv = daemon->servers; serv; serv = serv->next)
|
||||||
if (!(serv->flags &
|
if (!(serv->flags & SERV_COUNTED))
|
||||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
|
|
||||||
{
|
{
|
||||||
char *new, *lenp;
|
char *new, *lenp;
|
||||||
int port, newlen, bytes_avail, bytes_needed;
|
int port, newlen, bytes_avail, bytes_needed;
|
||||||
unsigned int queries = 0, failed_queries = 0;
|
unsigned int queries = 0, failed_queries = 0;
|
||||||
for (serv1 = serv; serv1; serv1 = serv1->next)
|
for (serv1 = serv; serv1; serv1 = serv1->next)
|
||||||
if (!(serv1->flags &
|
if (!(serv1->flags & SERV_COUNTED) && sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
|
|
||||||
sockaddr_isequal(&serv->addr, &serv1->addr))
|
|
||||||
{
|
{
|
||||||
serv1->flags |= SERV_COUNTED;
|
serv1->flags |= SERV_COUNTED;
|
||||||
queries += serv1->queries;
|
queries += serv1->queries;
|
||||||
@@ -1689,15 +1686,12 @@ void dump_cache(time_t now)
|
|||||||
serv->flags &= ~SERV_COUNTED;
|
serv->flags &= ~SERV_COUNTED;
|
||||||
|
|
||||||
for (serv = daemon->servers; serv; serv = serv->next)
|
for (serv = daemon->servers; serv; serv = serv->next)
|
||||||
if (!(serv->flags &
|
if (!(serv->flags & SERV_COUNTED))
|
||||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
|
|
||||||
{
|
{
|
||||||
int port;
|
int port;
|
||||||
unsigned int queries = 0, failed_queries = 0;
|
unsigned int queries = 0, failed_queries = 0;
|
||||||
for (serv1 = serv; serv1; serv1 = serv1->next)
|
for (serv1 = serv; serv1; serv1 = serv1->next)
|
||||||
if (!(serv1->flags &
|
if (!(serv1->flags & SERV_COUNTED) && sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
|
|
||||||
sockaddr_isequal(&serv->addr, &serv1->addr))
|
|
||||||
{
|
{
|
||||||
serv1->flags |= SERV_COUNTED;
|
serv1->flags |= SERV_COUNTED;
|
||||||
queries += serv1->queries;
|
queries += serv1->queries;
|
||||||
@@ -1971,14 +1965,14 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
|||||||
|
|
||||||
if (option_bool(OPT_EXTRALOG))
|
if (option_bool(OPT_EXTRALOG))
|
||||||
{
|
{
|
||||||
int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
|
|
||||||
if (flags & F_NOEXTRA)
|
if (flags & F_NOEXTRA)
|
||||||
my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
|
my_syslog(LOG_INFO, "%u %s %s %s %s", daemon->log_display_id, source, name, verb, dest);
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
|
||||||
my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest);
|
my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
|
my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
+2
-4
@@ -143,6 +143,7 @@ NO_SCRIPT
|
|||||||
NO_LARGEFILE
|
NO_LARGEFILE
|
||||||
NO_AUTH
|
NO_AUTH
|
||||||
NO_DUMPFILE
|
NO_DUMPFILE
|
||||||
|
NO_LOOP
|
||||||
NO_INOTIFY
|
NO_INOTIFY
|
||||||
these are available to explicitly disable compile time options which would
|
these are available to explicitly disable compile time options which would
|
||||||
otherwise be enabled automatically or which are enabled by default
|
otherwise be enabled automatically or which are enabled by default
|
||||||
@@ -447,7 +448,4 @@ static char *compile_opts =
|
|||||||
#endif
|
#endif
|
||||||
"dumpfile";
|
"dumpfile";
|
||||||
|
|
||||||
#endif
|
#endif /* defined(HAVE_DHCP) */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+1
-4
@@ -82,7 +82,4 @@ static int callback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, vo
|
|||||||
return NFCT_CB_CONTINUE;
|
return NFCT_CB_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif /* HAVE_CONNTRACK */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+50
-43
@@ -16,30 +16,34 @@
|
|||||||
|
|
||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
|
||||||
|
|
||||||
/* Minimal version of nettle */
|
/* Minimal version of nettle */
|
||||||
#define MIN_VERSION(major, minor) (NETTLE_VERSION_MAJOR == (major) && NETTLE_VERSION_MINOR >= (minor)) || \
|
|
||||||
(NETTLE_VERSION_MAJOR > (major))
|
|
||||||
|
|
||||||
|
/* bignum.h includes version.h and works on
|
||||||
|
earlier releases of nettle which don't have version.h */
|
||||||
|
#include <nettle/bignum.h>
|
||||||
|
#if !defined(NETTLE_VERSION_MAJOR)
|
||||||
|
# define NETTLE_VERSION_MAJOR 2
|
||||||
|
# define NETTLE_VERSION_MINOR 0
|
||||||
|
#endif
|
||||||
|
#define MIN_VERSION(major, minor) ((NETTLE_VERSION_MAJOR == (major) && NETTLE_VERSION_MINOR >= (minor)) || \
|
||||||
|
(NETTLE_VERSION_MAJOR > (major)))
|
||||||
|
|
||||||
|
#endif /* defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH) */
|
||||||
|
|
||||||
|
#if defined(HAVE_DNSSEC)
|
||||||
#include <nettle/rsa.h>
|
#include <nettle/rsa.h>
|
||||||
#include <nettle/ecdsa.h>
|
#include <nettle/ecdsa.h>
|
||||||
#include <nettle/ecc-curve.h>
|
#include <nettle/ecc-curve.h>
|
||||||
#if !defined(NETTLE_VERSION_MAJOR)
|
|
||||||
#define NETTLE_VERSION_MAJOR 2
|
|
||||||
#endif
|
|
||||||
#if MIN_VERSION(3, 1)
|
#if MIN_VERSION(3, 1)
|
||||||
#include <nettle/eddsa.h>
|
#include <nettle/eddsa.h>
|
||||||
#endif
|
#endif
|
||||||
#if MIN_VERSION(3, 6)
|
#if MIN_VERSION(3, 6)
|
||||||
# include <nettle/gostdsa.h>
|
# include <nettle/gostdsa.h>
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
|
|
||||||
#include <nettle/nettle-meta.h>
|
|
||||||
#include <nettle/bignum.h>
|
|
||||||
|
|
||||||
|
#if MIN_VERSION(3, 1)
|
||||||
/* Implement a "hash-function" to the nettle API, which simply returns
|
/* Implement a "hash-function" to the nettle API, which simply returns
|
||||||
the input data, concatenated into a single, statically maintained, buffer.
|
the input data, concatenated into a single, statically maintained, buffer.
|
||||||
|
|
||||||
@@ -93,7 +97,6 @@ static void null_hash_update(void *ctxv, size_t length, const uint8_t *src)
|
|||||||
ctx->len += length;
|
ctx->len += length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void null_hash_digest(void *ctx, size_t length, uint8_t *dst)
|
static void null_hash_digest(void *ctx, size_t length, uint8_t *dst)
|
||||||
{
|
{
|
||||||
(void)length;
|
(void)length;
|
||||||
@@ -112,33 +115,7 @@ static struct nettle_hash null_hash = {
|
|||||||
(nettle_hash_digest_func *) null_hash_digest
|
(nettle_hash_digest_func *) null_hash_digest
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Find pointer to correct hash function in nettle library */
|
#endif /* MIN_VERSION(3, 1) */
|
||||||
const struct nettle_hash *hash_find(char *name)
|
|
||||||
{
|
|
||||||
if (!name)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* We provide a "null" hash which returns the input data as digest. */
|
|
||||||
if (strcmp(null_hash.name, name) == 0)
|
|
||||||
return &null_hash;
|
|
||||||
|
|
||||||
/* libnettle >= 3.4 provides nettle_lookup_hash() which avoids nasty ABI
|
|
||||||
incompatibilities if sizeof(nettle_hashes) changes between library
|
|
||||||
versions. */
|
|
||||||
#if MIN_VERSION(3, 4)
|
|
||||||
return nettle_lookup_hash(name);
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; nettle_hashes[i]; i++)
|
|
||||||
if (strcmp(nettle_hashes[i]->name, name) == 0)
|
|
||||||
return nettle_hashes[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* expand ctx and digest memory allocations if necessary and init hash function */
|
/* expand ctx and digest memory allocations if necessary and init hash function */
|
||||||
int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
|
int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
|
||||||
@@ -178,10 +155,6 @@ int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **diges
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH) */
|
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
|
||||||
|
|
||||||
static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||||
unsigned char *digest, size_t digest_len, int algo)
|
unsigned char *digest, size_t digest_len, int algo)
|
||||||
{
|
{
|
||||||
@@ -415,6 +388,7 @@ static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key
|
|||||||
|
|
||||||
case 13: case 14:
|
case 13: case 14:
|
||||||
return dnsmasq_ecdsa_verify;
|
return dnsmasq_ecdsa_verify;
|
||||||
|
|
||||||
#if MIN_VERSION(3, 1)
|
#if MIN_VERSION(3, 1)
|
||||||
case 15: case 16:
|
case 15: case 16:
|
||||||
return dnsmasq_eddsa_verify;
|
return dnsmasq_eddsa_verify;
|
||||||
@@ -489,4 +463,37 @@ char *nsec3_digest_name(int digest)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* defined(HAVE_DNSSEC) */
|
||||||
|
|
||||||
|
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
|
||||||
|
/* Find pointer to correct hash function in nettle library */
|
||||||
|
const struct nettle_hash *hash_find(char *name)
|
||||||
|
{
|
||||||
|
if (!name)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
#if MIN_VERSION(3,1) && defined(HAVE_DNSSEC)
|
||||||
|
/* We provide a "null" hash which returns the input data as digest. */
|
||||||
|
if (strcmp(null_hash.name, name) == 0)
|
||||||
|
return &null_hash;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* libnettle >= 3.4 provides nettle_lookup_hash() which avoids nasty ABI
|
||||||
|
incompatibilities if sizeof(nettle_hashes) changes between library
|
||||||
|
versions. */
|
||||||
|
#if MIN_VERSION(3, 4)
|
||||||
|
return nettle_lookup_hash(name);
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; nettle_hashes[i]; i++)
|
||||||
|
if (strcmp(nettle_hashes[i]->name, name) == 0)
|
||||||
|
return nettle_hashes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH) */
|
||||||
+1
-1
@@ -377,7 +377,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
|||||||
/* 0.0.0.0 for server address == NULL, for Dbus */
|
/* 0.0.0.0 for server address == NULL, for Dbus */
|
||||||
if (addr.in.sin_family == AF_INET &&
|
if (addr.in.sin_family == AF_INET &&
|
||||||
addr.in.sin_addr.s_addr == 0)
|
addr.in.sin_addr.s_addr == 0)
|
||||||
flags |= SERV_NO_ADDR;
|
flags |= SERV_LITERAL_ADDRESS;
|
||||||
|
|
||||||
if (strings)
|
if (strings)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -72,4 +72,3 @@
|
|||||||
#define DHCP6NOBINDING 3
|
#define DHCP6NOBINDING 3
|
||||||
#define DHCP6NOTONLINK 4
|
#define DHCP6NOTONLINK 4
|
||||||
#define DHCP6USEMULTI 5
|
#define DHCP6USEMULTI 5
|
||||||
|
|
||||||
+1
-3
@@ -825,6 +825,4 @@ void dhcp_construct_contexts(time_t now)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif /* HAVE_DHCP6 */
|
||||||
|
|
||||||
|
|
||||||
@@ -82,6 +82,7 @@
|
|||||||
#define EDNS0_OPTION_CLIENT_SUBNET 8 /* IANA */
|
#define EDNS0_OPTION_CLIENT_SUBNET 8 /* IANA */
|
||||||
#define EDNS0_OPTION_NOMDEVICEID 65073 /* Nominum temporary assignment */
|
#define EDNS0_OPTION_NOMDEVICEID 65073 /* Nominum temporary assignment */
|
||||||
#define EDNS0_OPTION_NOMCPEID 65074 /* Nominum temporary assignment */
|
#define EDNS0_OPTION_NOMCPEID 65074 /* Nominum temporary assignment */
|
||||||
|
#define EDNS0_OPTION_UMBRELLA 20292 /* Cisco Umbrella temporary assignment */
|
||||||
|
|
||||||
struct dns_header {
|
struct dns_header {
|
||||||
u16 id;
|
u16 id;
|
||||||
|
|||||||
+38
-42
@@ -24,7 +24,7 @@ struct daemon *daemon;
|
|||||||
static volatile pid_t pid = 0;
|
static volatile pid_t pid = 0;
|
||||||
static volatile int pipewrite;
|
static volatile int pipewrite;
|
||||||
|
|
||||||
static int set_dns_listeners(time_t now);
|
static void set_dns_listeners(void);
|
||||||
static void check_dns_listeners(time_t now);
|
static void check_dns_listeners(time_t now);
|
||||||
static void sig_handler(int sig);
|
static void sig_handler(int sig);
|
||||||
static void async_event(int pipe, time_t now);
|
static void async_event(int pipe, time_t now);
|
||||||
@@ -442,8 +442,10 @@ int main (int argc, char **argv)
|
|||||||
if (option_bool(OPT_UBUS))
|
if (option_bool(OPT_UBUS))
|
||||||
#ifdef HAVE_UBUS
|
#ifdef HAVE_UBUS
|
||||||
{
|
{
|
||||||
|
char *err;
|
||||||
daemon->ubus = NULL;
|
daemon->ubus = NULL;
|
||||||
ubus_init();
|
if ((err = ubus_init()))
|
||||||
|
die(_("UBus error: %s"), err, EC_MISC);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
die(_("UBus not available: set HAVE_UBUS in src/config.h"), NULL, EC_BADCONF);
|
die(_("UBus not available: set HAVE_UBUS in src/config.h"), NULL, EC_BADCONF);
|
||||||
@@ -1040,16 +1042,10 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
int t, timeout = -1;
|
int timeout = -1;
|
||||||
|
|
||||||
poll_reset();
|
poll_reset();
|
||||||
|
|
||||||
/* if we are out of resources, find how long we have to wait
|
|
||||||
for some to come free, we'll loop around then and restart
|
|
||||||
listening for queries */
|
|
||||||
if ((t = set_dns_listeners(now)) != 0)
|
|
||||||
timeout = t * 1000;
|
|
||||||
|
|
||||||
/* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
|
/* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
|
||||||
if (daemon->tftp_trans ||
|
if (daemon->tftp_trans ||
|
||||||
(option_bool(OPT_DBUS) && !daemon->dbus))
|
(option_bool(OPT_DBUS) && !daemon->dbus))
|
||||||
@@ -1059,6 +1055,8 @@ int main (int argc, char **argv)
|
|||||||
else if (is_dad_listeners())
|
else if (is_dad_listeners())
|
||||||
timeout = 1000;
|
timeout = 1000;
|
||||||
|
|
||||||
|
set_dns_listeners();
|
||||||
|
|
||||||
#ifdef HAVE_DBUS
|
#ifdef HAVE_DBUS
|
||||||
set_dbus_listeners();
|
set_dbus_listeners();
|
||||||
#endif
|
#endif
|
||||||
@@ -1199,16 +1197,16 @@ int main (int argc, char **argv)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_UBUS
|
#ifdef HAVE_UBUS
|
||||||
if (option_bool(OPT_UBUS))
|
|
||||||
{
|
|
||||||
/* if we didn't create a UBus connection, retry now. */
|
/* if we didn't create a UBus connection, retry now. */
|
||||||
if (!daemon->ubus)
|
if (option_bool(OPT_UBUS) && !daemon->ubus)
|
||||||
{
|
{
|
||||||
ubus_init();
|
char *err;
|
||||||
|
if ((err = ubus_init()))
|
||||||
|
my_syslog(LOG_WARNING, _("UBus error: %s"), err);
|
||||||
|
if (daemon->ubus)
|
||||||
|
my_syslog(LOG_INFO, _("connected to system UBus"));
|
||||||
}
|
}
|
||||||
|
|
||||||
check_ubus_listeners();
|
check_ubus_listeners();
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
check_dns_listeners(now);
|
check_dns_listeners(now);
|
||||||
@@ -1683,12 +1681,12 @@ void clear_cache_and_reload(time_t now)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_dns_listeners(time_t now)
|
static void set_dns_listeners(void)
|
||||||
{
|
{
|
||||||
struct serverfd *serverfdp;
|
struct serverfd *serverfdp;
|
||||||
struct listener *listener;
|
struct listener *listener;
|
||||||
struct randfd_list *rfl;
|
struct randfd_list *rfl;
|
||||||
int wait = 0, i;
|
int i;
|
||||||
|
|
||||||
#ifdef HAVE_TFTP
|
#ifdef HAVE_TFTP
|
||||||
int tftp = 0;
|
int tftp = 0;
|
||||||
@@ -1701,10 +1699,6 @@ static int set_dns_listeners(time_t now)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* will we be able to get memory? */
|
|
||||||
if (daemon->port != 0)
|
|
||||||
get_new_frec(now, &wait, NULL);
|
|
||||||
|
|
||||||
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
||||||
poll_listen(serverfdp->fd, POLLIN);
|
poll_listen(serverfdp->fd, POLLIN);
|
||||||
|
|
||||||
@@ -1716,36 +1710,34 @@ static int set_dns_listeners(time_t now)
|
|||||||
for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next)
|
for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next)
|
||||||
poll_listen(rfl->rfd->fd, POLLIN);
|
poll_listen(rfl->rfd->fd, POLLIN);
|
||||||
|
|
||||||
|
/* check to see if we have free tcp process slots. */
|
||||||
|
for (i = MAX_PROCS - 1; i >= 0; i--)
|
||||||
|
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
for (listener = daemon->listeners; listener; listener = listener->next)
|
for (listener = daemon->listeners; listener; listener = listener->next)
|
||||||
{
|
{
|
||||||
/* only listen for queries if we have resources */
|
if (listener->fd != -1)
|
||||||
if (listener->fd != -1 && wait == 0)
|
|
||||||
poll_listen(listener->fd, POLLIN);
|
poll_listen(listener->fd, POLLIN);
|
||||||
|
|
||||||
/* death of a child goes through the select loop, so
|
/* Only listen for TCP connections when a process slot
|
||||||
we don't need to explicitly arrange to wake up here */
|
is available. Death of a child goes through the select loop, so
|
||||||
if (listener->tcpfd != -1)
|
we don't need to explicitly arrange to wake up here,
|
||||||
for (i = 0; i < MAX_PROCS; i++)
|
we'll be called again when a slot becomes available. */
|
||||||
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
|
if (listener->tcpfd != -1 && i >= 0)
|
||||||
{
|
|
||||||
poll_listen(listener->tcpfd, POLLIN);
|
poll_listen(listener->tcpfd, POLLIN);
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_TFTP
|
#ifdef HAVE_TFTP
|
||||||
/* tftp == 0 in single-port mode. */
|
/* tftp == 0 in single-port mode. */
|
||||||
if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
|
if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
|
||||||
poll_listen(listener->tftpfd, POLLIN);
|
poll_listen(listener->tftpfd, POLLIN);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!option_bool(OPT_DEBUG))
|
if (!option_bool(OPT_DEBUG))
|
||||||
for (i = 0; i < MAX_PROCS; i++)
|
for (i = 0; i < MAX_PROCS; i++)
|
||||||
if (daemon->tcp_pipes[i] != -1)
|
if (daemon->tcp_pipes[i] != -1)
|
||||||
poll_listen(daemon->tcp_pipes[i], POLLIN);
|
poll_listen(daemon->tcp_pipes[i], POLLIN);
|
||||||
|
|
||||||
return wait;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check_dns_listeners(time_t now)
|
static void check_dns_listeners(time_t now)
|
||||||
@@ -1797,7 +1789,16 @@ static void check_dns_listeners(time_t now)
|
|||||||
tftp_request(listener, now);
|
tftp_request(listener, now);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (listener->tcpfd != -1 && poll_check(listener->tcpfd, POLLIN))
|
/* check to see if we have a free tcp process slot.
|
||||||
|
Note that we can't assume that because we had
|
||||||
|
at least one a poll() time, that we still do.
|
||||||
|
There may be more waiting connections after
|
||||||
|
poll() returns then free process slots. */
|
||||||
|
for (i = MAX_PROCS - 1; i >= 0; i--)
|
||||||
|
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (listener->tcpfd != -1 && i >= 0 && poll_check(listener->tcpfd, POLLIN))
|
||||||
{
|
{
|
||||||
int confd, client_ok = 1;
|
int confd, client_ok = 1;
|
||||||
struct irec *iface = NULL;
|
struct irec *iface = NULL;
|
||||||
@@ -1887,7 +1888,6 @@ static void check_dns_listeners(time_t now)
|
|||||||
close(pipefd[0]);
|
close(pipefd[0]);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
/* The child process inherits the netlink socket,
|
/* The child process inherits the netlink socket,
|
||||||
which it never uses, but when the parent (us)
|
which it never uses, but when the parent (us)
|
||||||
@@ -1907,13 +1907,9 @@ static void check_dns_listeners(time_t now)
|
|||||||
read_write(pipefd[0], &a, 1, 1);
|
read_write(pipefd[0], &a, 1, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (i = 0; i < MAX_PROCS; i++)
|
/* i holds index of free slot */
|
||||||
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
|
|
||||||
{
|
|
||||||
daemon->tcp_pids[i] = p;
|
daemon->tcp_pids[i] = p;
|
||||||
daemon->tcp_pipes[i] = pipefd[0];
|
daemon->tcp_pipes[i] = pipefd[0];
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
close(confd);
|
close(confd);
|
||||||
|
|
||||||
@@ -2092,7 +2088,7 @@ int delay_dhcp(time_t start, int sec, int fd, uint32_t addr, unsigned short id)
|
|||||||
poll_reset();
|
poll_reset();
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
poll_listen(fd, POLLIN);
|
poll_listen(fd, POLLIN);
|
||||||
set_dns_listeners(now);
|
set_dns_listeners();
|
||||||
set_log_writer();
|
set_log_writer();
|
||||||
|
|
||||||
#ifdef HAVE_DHCP6
|
#ifdef HAVE_DHCP6
|
||||||
|
|||||||
+61
-19
@@ -270,7 +270,9 @@ struct event_desc {
|
|||||||
#define OPT_SINGLE_PORT 60
|
#define OPT_SINGLE_PORT 60
|
||||||
#define OPT_LEASE_RENEW 61
|
#define OPT_LEASE_RENEW 61
|
||||||
#define OPT_LOG_DEBUG 62
|
#define OPT_LOG_DEBUG 62
|
||||||
#define OPT_LAST 63
|
#define OPT_UMBRELLA 63
|
||||||
|
#define OPT_UMBRELLA_DEVID 64
|
||||||
|
#define OPT_LAST 65
|
||||||
|
|
||||||
#define OPTION_BITS (sizeof(unsigned int)*8)
|
#define OPTION_BITS (sizeof(unsigned int)*8)
|
||||||
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
|
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
|
||||||
@@ -496,7 +498,7 @@ struct crec {
|
|||||||
#define F_NO_RR (1u<<25)
|
#define F_NO_RR (1u<<25)
|
||||||
#define F_IPSET (1u<<26)
|
#define F_IPSET (1u<<26)
|
||||||
#define F_NOEXTRA (1u<<27)
|
#define F_NOEXTRA (1u<<27)
|
||||||
#define F_SERVFAIL (1u<<28) /* currently unused. */
|
#define F_DOMAINSRV (1u<<28)
|
||||||
#define F_RCODE (1u<<29)
|
#define F_RCODE (1u<<29)
|
||||||
#define F_SRV (1u<<30)
|
#define F_SRV (1u<<30)
|
||||||
|
|
||||||
@@ -522,19 +524,20 @@ union mysockaddr {
|
|||||||
#define IFACE_PERMANENT 4
|
#define IFACE_PERMANENT 4
|
||||||
|
|
||||||
|
|
||||||
#define SERV_FROM_RESOLV 1 /* 1 for servers from resolv, 0 for command line. */
|
/* The actual values here matter, since we sort on them to get records in the order
|
||||||
#define SERV_NO_ADDR 2 /* no server, this domain is local only */
|
IPv6 addr, IPv4 addr, all zero return, no-data return, send upstream. */
|
||||||
#define SERV_LITERAL_ADDRESS 4 /* addr is the answer, not the server */
|
#define SERV_LITERAL_ADDRESS 1 /* addr is the answer, or NoDATA is the answer, depending on the next three flags */
|
||||||
#define SERV_HAS_DOMAIN 8 /* server for one domain only */
|
#define SERV_ALL_ZEROS 2 /* return all zeros for A and AAAA */
|
||||||
|
#define SERV_4ADDR 4 /* addr is IPv4 */
|
||||||
|
#define SERV_6ADDR 8 /* addr is IPv6 */
|
||||||
#define SERV_HAS_SOURCE 16 /* source address defined */
|
#define SERV_HAS_SOURCE 16 /* source address defined */
|
||||||
#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_WARNED_RECURSIVE 64 /* avoid warning spam */
|
||||||
#define SERV_FROM_DBUS 128 /* 1 if source is DBus */
|
#define SERV_FROM_DBUS 128 /* 1 if source is DBus */
|
||||||
#define SERV_MARK 256 /* for mark-and-delete */
|
#define SERV_MARK 256 /* for mark-and-delete */
|
||||||
#define SERV_TYPE (SERV_HAS_DOMAIN | SERV_FOR_NODOTS)
|
|
||||||
#define SERV_COUNTED 512 /* workspace for log code */
|
#define SERV_COUNTED 512 /* workspace for log code */
|
||||||
#define SERV_USE_RESOLV 1024 /* forward this domain in the normal way */
|
#define SERV_USE_RESOLV 1024 /* forward this domain in the normal way */
|
||||||
#define SERV_NO_REBIND 2048 /* inhibit dns-rebind protection */
|
#define SERV_FROM_RESOLV 2048 /* 1 for servers from resolv, 0 for command line. */
|
||||||
#define SERV_FROM_FILE 4096 /* read from --servers-file */
|
#define SERV_FROM_FILE 4096 /* read from --servers-file */
|
||||||
#define SERV_LOOP 8192 /* server causes forwarding loop */
|
#define SERV_LOOP 8192 /* server causes forwarding loop */
|
||||||
#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */
|
#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */
|
||||||
@@ -559,18 +562,45 @@ struct randfd_list {
|
|||||||
struct randfd_list *next;
|
struct randfd_list *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct server {
|
struct server {
|
||||||
|
int flags;
|
||||||
|
char *domain;
|
||||||
|
struct server *next;
|
||||||
|
int serial, arrayposn;
|
||||||
|
int last_server;
|
||||||
union mysockaddr addr, source_addr;
|
union mysockaddr addr, source_addr;
|
||||||
char interface[IF_NAMESIZE+1];
|
char interface[IF_NAMESIZE+1];
|
||||||
unsigned int ifindex; /* corresponding to interface, above */
|
unsigned int ifindex; /* corresponding to interface, above */
|
||||||
struct serverfd *sfd;
|
struct serverfd *sfd;
|
||||||
char *domain; /* set if this server only handles a domain. */
|
int tcpfd, edns_pktsz;
|
||||||
int flags, tcpfd, edns_pktsz;
|
|
||||||
time_t pktsz_reduced;
|
time_t pktsz_reduced;
|
||||||
unsigned int queries, failed_queries;
|
unsigned int queries, failed_queries;
|
||||||
|
time_t forwardtime;
|
||||||
|
int forwardcount;
|
||||||
#ifdef HAVE_LOOP
|
#ifdef HAVE_LOOP
|
||||||
u32 uid;
|
u32 uid;
|
||||||
#endif
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/* First three fields must match struct server in next three definitions.. */
|
||||||
|
struct serv_addr4 {
|
||||||
|
int flags;
|
||||||
|
char *domain;
|
||||||
|
struct server *next;
|
||||||
|
struct in_addr addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct serv_addr6 {
|
||||||
|
int flags;
|
||||||
|
char *domain;
|
||||||
|
struct server *next;
|
||||||
|
struct in6_addr addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct serv_local {
|
||||||
|
int flags;
|
||||||
|
char *domain;
|
||||||
struct server *next;
|
struct server *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -696,6 +726,7 @@ struct frec {
|
|||||||
struct blockdata *stash; /* Saved reply, whilst we validate */
|
struct blockdata *stash; /* Saved reply, whilst we validate */
|
||||||
size_t stash_len;
|
size_t stash_len;
|
||||||
struct frec *dependent; /* Query awaiting internally-generated DNSKEY or DS query */
|
struct frec *dependent; /* Query awaiting internally-generated DNSKEY or DS query */
|
||||||
|
struct frec *next_dependent; /* list of above. */
|
||||||
struct frec *blocking_query; /* Query which is blocking us. */
|
struct frec *blocking_query; /* Query which is blocking us. */
|
||||||
#endif
|
#endif
|
||||||
struct frec *next;
|
struct frec *next;
|
||||||
@@ -1052,7 +1083,8 @@ extern struct daemon {
|
|||||||
char *lease_change_command;
|
char *lease_change_command;
|
||||||
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
|
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
|
||||||
struct bogus_addr *bogus_addr, *ignore_addr;
|
struct bogus_addr *bogus_addr, *ignore_addr;
|
||||||
struct server *servers;
|
struct server *servers, *local_domains, **serverarray, *no_rebind;
|
||||||
|
int serverarraysz;
|
||||||
struct ipsets *ipsets;
|
struct ipsets *ipsets;
|
||||||
int log_fac; /* log facility */
|
int log_fac; /* log facility */
|
||||||
char *log_file; /* optional log file */
|
char *log_file; /* optional log file */
|
||||||
@@ -1061,6 +1093,9 @@ extern struct daemon {
|
|||||||
int port, query_port, min_port, max_port;
|
int port, query_port, min_port, max_port;
|
||||||
unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, max_cache_ttl, auth_ttl, dhcp_ttl, use_dhcp_ttl;
|
unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, max_cache_ttl, auth_ttl, dhcp_ttl, use_dhcp_ttl;
|
||||||
char *dns_client_id;
|
char *dns_client_id;
|
||||||
|
u32 umbrella_org;
|
||||||
|
u32 umbrella_asset;
|
||||||
|
u8 umbrella_device[8];
|
||||||
struct hostsfile *addn_hosts;
|
struct hostsfile *addn_hosts;
|
||||||
struct dhcp_context *dhcp, *dhcp6;
|
struct dhcp_context *dhcp, *dhcp6;
|
||||||
struct ra_interface *ra_interfaces;
|
struct ra_interface *ra_interfaces;
|
||||||
@@ -1121,9 +1156,6 @@ extern struct daemon {
|
|||||||
struct serverfd *sfds;
|
struct serverfd *sfds;
|
||||||
struct irec *interfaces;
|
struct irec *interfaces;
|
||||||
struct listener *listeners;
|
struct listener *listeners;
|
||||||
struct server *last_server;
|
|
||||||
time_t forwardtime;
|
|
||||||
int forwardcount;
|
|
||||||
struct server *srv_save; /* Used for resend on DoD */
|
struct server *srv_save; /* Used for resend on DoD */
|
||||||
size_t packet_len; /* " " */
|
size_t packet_len; /* " " */
|
||||||
int fd_save; /* " " */
|
int fd_save; /* " " */
|
||||||
@@ -1239,9 +1271,7 @@ unsigned char *skip_questions(struct dns_header *header, size_t plen);
|
|||||||
unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen);
|
unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen);
|
||||||
unsigned int extract_request(struct dns_header *header, size_t qlen,
|
unsigned int extract_request(struct dns_header *header, size_t qlen,
|
||||||
char *name, unsigned short *typep);
|
char *name, unsigned short *typep);
|
||||||
size_t setup_reply(struct dns_header *header, size_t qlen,
|
void setup_reply(struct dns_header *header, unsigned int flags);
|
||||||
union all_addr *addrp, unsigned int flags,
|
|
||||||
unsigned long ttl);
|
|
||||||
int extract_addresses(struct dns_header *header, size_t qlen, char *name,
|
int extract_addresses(struct dns_header *header, size_t qlen, char *name,
|
||||||
time_t now, char **ipsets, int is_sign, int check_rebind,
|
time_t now, char **ipsets, int is_sign, int check_rebind,
|
||||||
int no_cache_dnssec, int secure, int *doctored);
|
int no_cache_dnssec, int secure, int *doctored);
|
||||||
@@ -1360,7 +1390,6 @@ void receive_query(struct listener *listen, time_t now);
|
|||||||
unsigned char *tcp_request(int confd, time_t now,
|
unsigned char *tcp_request(int confd, time_t now,
|
||||||
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns);
|
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns);
|
||||||
void server_gone(struct server *server);
|
void server_gone(struct server *server);
|
||||||
struct frec *get_new_frec(time_t now, int *wait, struct frec *force);
|
|
||||||
int send_from(int fd, int nowild, char *packet, size_t len,
|
int send_from(int fd, int nowild, char *packet, size_t len,
|
||||||
union mysockaddr *to, union all_addr *source,
|
union mysockaddr *to, union all_addr *source,
|
||||||
unsigned int iface);
|
unsigned int iface);
|
||||||
@@ -1513,7 +1542,7 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
|
|||||||
|
|
||||||
/* ubus.c */
|
/* ubus.c */
|
||||||
#ifdef HAVE_UBUS
|
#ifdef HAVE_UBUS
|
||||||
void ubus_init(void);
|
char *ubus_init(void);
|
||||||
void set_ubus_listeners(void);
|
void set_ubus_listeners(void);
|
||||||
void check_ubus_listeners(void);
|
void check_ubus_listeners(void);
|
||||||
void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface);
|
void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface);
|
||||||
@@ -1690,3 +1719,16 @@ int do_arp_script_run(void);
|
|||||||
void dump_init(void);
|
void dump_init(void);
|
||||||
void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, union mysockaddr *dst);
|
void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, union mysockaddr *dst);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* domain-match.c */
|
||||||
|
void build_server_array(void);
|
||||||
|
int lookup_domain(char *qdomain, int flags, int *lowout, int *highout);
|
||||||
|
int filter_servers(int seed, int flags, int *lowout, int *highout);
|
||||||
|
int is_local_answer(time_t now, int first, char *name);
|
||||||
|
size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header *header,
|
||||||
|
char *name, int first, int last);
|
||||||
|
int server_samegroup(struct server *a, struct server *b);
|
||||||
|
#ifdef HAVE_DNSSEC
|
||||||
|
int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp);
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,435 @@
|
|||||||
|
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 dated June, 1991, or
|
||||||
|
(at your option) version 3 dated 29 June, 2007.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
|
static int order(char *qdomain, int leading_dot, size_t qlen, struct server *serv);
|
||||||
|
static int order_qsort(const void *a, const void *b);
|
||||||
|
static int order_servers(struct server *s, struct server *s2);
|
||||||
|
|
||||||
|
void build_server_array(void)
|
||||||
|
{
|
||||||
|
struct server *serv;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (serv = daemon->servers; serv; serv = serv->next)
|
||||||
|
count++;
|
||||||
|
|
||||||
|
for (serv = daemon->local_domains; serv; serv = serv->next)
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (count > daemon->serverarraysz)
|
||||||
|
{
|
||||||
|
struct server **new;
|
||||||
|
|
||||||
|
if ((new = whine_malloc(count * sizeof(struct server *))))
|
||||||
|
{
|
||||||
|
if (daemon->serverarray)
|
||||||
|
free(daemon->serverarray);
|
||||||
|
|
||||||
|
daemon->serverarray = new;
|
||||||
|
daemon->serverarraysz = count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
for (serv = daemon->servers; serv; serv = serv->next, count++)
|
||||||
|
{
|
||||||
|
daemon->serverarray[count] = serv;
|
||||||
|
serv->serial = count;
|
||||||
|
serv->last_server = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (serv = daemon->local_domains; serv; serv = serv->next, count++)
|
||||||
|
daemon->serverarray[count] = serv;
|
||||||
|
|
||||||
|
qsort(daemon->serverarray, daemon->serverarraysz, sizeof(struct server *), order_qsort);
|
||||||
|
|
||||||
|
/* servers need the location in the array to find all the whole
|
||||||
|
set of equivalent servers from a pointer to a single one. */
|
||||||
|
for (count = 0; count < daemon->serverarraysz; count++)
|
||||||
|
if (!(daemon->serverarray[count]->flags & SERV_LITERAL_ADDRESS))
|
||||||
|
daemon->serverarray[count]->arrayposn = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we're looking for the server whose domain is the longest exact match
|
||||||
|
to the RH end of qdomain, or a local address if the flags match.
|
||||||
|
Add '.' to the LHS of the query string so
|
||||||
|
server=/.example.com/ works.
|
||||||
|
|
||||||
|
A flag of F_SERVER returns an upstream server only.
|
||||||
|
A flag of F_DNSSECOK returns a DNSSEC capable server only and
|
||||||
|
also disables NODOTS servers from consideration.
|
||||||
|
A flag of F_DOMAINSRV returns a domain-specific server only.
|
||||||
|
return 0 if nothing found, 1 otherwise.
|
||||||
|
*/
|
||||||
|
int lookup_domain(char *qdomain, int flags, int *lowout, int *highout)
|
||||||
|
{
|
||||||
|
int rc, nodots, leading_dot = 1;
|
||||||
|
ssize_t qlen, maxlen;
|
||||||
|
int try, high, low = 0;
|
||||||
|
int nlow = 0, nhigh = 0;
|
||||||
|
char *cp;
|
||||||
|
|
||||||
|
/* may be no configured servers. */
|
||||||
|
if (daemon->serverarraysz == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
maxlen = strlen(daemon->serverarray[0]->domain);
|
||||||
|
|
||||||
|
/* find query length and presence of '.' */
|
||||||
|
for (cp = qdomain, nodots = 1, qlen = 0; *cp; qlen++, cp++)
|
||||||
|
if (*cp == '.')
|
||||||
|
nodots = 0;
|
||||||
|
|
||||||
|
/* Handle empty name, and searches for DNSSEC queries without
|
||||||
|
diverting to NODOTS servers. */
|
||||||
|
if (qlen == 0 || flags & F_DNSSECOK)
|
||||||
|
nodots = 0;
|
||||||
|
|
||||||
|
/* No point trying to match more than the largest server domain */
|
||||||
|
if (qlen > maxlen)
|
||||||
|
{
|
||||||
|
qdomain += qlen - maxlen;
|
||||||
|
qlen = maxlen;
|
||||||
|
leading_dot = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search shorter and shorter RHS substrings for a match */
|
||||||
|
while (qlen >= 0)
|
||||||
|
{
|
||||||
|
/* Note that when we chop off a character, all the possible matches
|
||||||
|
MUST be at a larger index than the nearest failing match with one more
|
||||||
|
character, since the array is sorted longest to smallest. Hence
|
||||||
|
we don't reset low here. */
|
||||||
|
high = daemon->serverarraysz;
|
||||||
|
|
||||||
|
/* binary search */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
try = (low + high)/2;
|
||||||
|
|
||||||
|
if ((rc = order(qdomain, leading_dot, qlen, daemon->serverarray[try])) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
if (high == try)
|
||||||
|
break;
|
||||||
|
high = try;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (low == try)
|
||||||
|
break;
|
||||||
|
low = try;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (low != high);
|
||||||
|
|
||||||
|
if (rc == 0)
|
||||||
|
{
|
||||||
|
/* We've matched a setting which says to use servers without a domain.
|
||||||
|
Continue the search with empty query (the last character gets stripped
|
||||||
|
by the loop. */
|
||||||
|
if (daemon->serverarray[try]->flags & SERV_USE_RESOLV)
|
||||||
|
{
|
||||||
|
qdomain += qlen - 1;
|
||||||
|
qlen = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* We have a match, but it may only be (say) an IPv6 address, and
|
||||||
|
if the query wasn't for an AAAA record, it's no good, and we need
|
||||||
|
to continue generalising */
|
||||||
|
if (filter_servers(try, flags, &nlow, &nhigh))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leading_dot)
|
||||||
|
leading_dot = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qlen--;
|
||||||
|
qdomain++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* domain has no dots, and we have at least one server configured to handle such,
|
||||||
|
These servers always sort to the very end of the array.
|
||||||
|
A configured server eg server=/lan/ will take precdence. */
|
||||||
|
if (nodots &&
|
||||||
|
(daemon->serverarray[daemon->serverarraysz-1]->flags & SERV_FOR_NODOTS) &&
|
||||||
|
(nlow == nhigh || strlen(daemon->serverarray[nlow]->domain) == 0))
|
||||||
|
filter_servers(daemon->serverarraysz-1, flags, &nlow, &nhigh);
|
||||||
|
|
||||||
|
/* F_DOMAINSRV returns only domain-specific servers, so if we got to a
|
||||||
|
general server, return empty set. */
|
||||||
|
if (nlow != nhigh && (flags & F_DOMAINSRV) && strlen(daemon->serverarray[nlow]->domain) == 0)
|
||||||
|
nlow = nhigh;
|
||||||
|
|
||||||
|
if (lowout)
|
||||||
|
*lowout = nlow;
|
||||||
|
|
||||||
|
if (highout)
|
||||||
|
*highout = nhigh;
|
||||||
|
|
||||||
|
if (nlow == nhigh)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return first server in group of equivalent servers; this is the "master" record. */
|
||||||
|
int server_samegroup(struct server *a, struct server *b)
|
||||||
|
{
|
||||||
|
return order_servers(a, b) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filter_servers(int seed, int flags, int *lowout, int *highout)
|
||||||
|
{
|
||||||
|
int nlow = seed, nhigh = seed;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* expand nlow and nhigh to cover all the records with the same domain
|
||||||
|
nlow is the first, nhigh - 1 is the last. nlow=nhigh means no servers,
|
||||||
|
which can happen below. */
|
||||||
|
while (nlow > 0 && order_servers(daemon->serverarray[nlow-1], daemon->serverarray[nlow]) == 0)
|
||||||
|
nlow--;
|
||||||
|
|
||||||
|
while (nhigh < daemon->serverarraysz-1 && order_servers(daemon->serverarray[nhigh], daemon->serverarray[nhigh+1]) == 0)
|
||||||
|
nhigh++;
|
||||||
|
|
||||||
|
nhigh++;
|
||||||
|
|
||||||
|
/* Now the servers are on order between low and high, in the order
|
||||||
|
return zero for both, IPv6 addr, IPv4 addr, no-data return, send upstream.
|
||||||
|
|
||||||
|
See which of those match our query in that priority order and narrow (low, high) */
|
||||||
|
|
||||||
|
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_6ADDR); i++);
|
||||||
|
|
||||||
|
if (i != nlow && (flags & F_IPV6))
|
||||||
|
nhigh = i;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nlow = i;
|
||||||
|
|
||||||
|
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_4ADDR); i++);
|
||||||
|
|
||||||
|
if (i != nlow && (flags & F_IPV4))
|
||||||
|
nhigh = i;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nlow = i;
|
||||||
|
|
||||||
|
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_ALL_ZEROS); i++);
|
||||||
|
|
||||||
|
if (i != nlow && (flags & (F_IPV4 | F_IPV6)))
|
||||||
|
nhigh = i;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nlow = i;
|
||||||
|
|
||||||
|
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
|
||||||
|
|
||||||
|
/* --local=/domain/, only return if we don't need a server. */
|
||||||
|
if (i != nlow && !(flags & (F_DNSSECOK | F_DOMAINSRV | F_SERVER)))
|
||||||
|
nhigh = i;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nlow = i;
|
||||||
|
/* If we want a server that can do DNSSEC, and this one can't,
|
||||||
|
return nothing. */
|
||||||
|
if ((flags & F_DNSSECOK) && !(daemon->serverarray[nlow]->flags & SERV_DO_DNSSEC))
|
||||||
|
nlow = nhigh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*lowout = nlow;
|
||||||
|
*highout = nhigh;
|
||||||
|
|
||||||
|
return (nlow != nhigh);
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_local_answer(time_t now, int first, char *name)
|
||||||
|
{
|
||||||
|
int flags = 0;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if ((flags = daemon->serverarray[first]->flags) & SERV_LITERAL_ADDRESS)
|
||||||
|
{
|
||||||
|
if (flags & SERV_4ADDR)
|
||||||
|
rc = F_IPV4;
|
||||||
|
else if (flags & SERV_6ADDR)
|
||||||
|
rc = F_IPV6;
|
||||||
|
else if (flags & SERV_ALL_ZEROS)
|
||||||
|
rc = F_IPV4 | F_IPV6;
|
||||||
|
else
|
||||||
|
rc = check_for_local_domain(name, now) ? F_NOERR : F_NXDOMAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header *header, char *name, int first, int last)
|
||||||
|
{
|
||||||
|
int trunc = 0;
|
||||||
|
unsigned char *p;
|
||||||
|
int start;
|
||||||
|
union all_addr addr;
|
||||||
|
|
||||||
|
if (flags & (F_NXDOMAIN | F_NOERR))
|
||||||
|
log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL);
|
||||||
|
|
||||||
|
setup_reply(header, flags);
|
||||||
|
|
||||||
|
if (!(p = skip_questions(header, size)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (flags & gotname & F_IPV4)
|
||||||
|
for (start = first; start != last; start++)
|
||||||
|
{
|
||||||
|
struct serv_addr4 *srv = (struct serv_addr4 *)daemon->serverarray[start];
|
||||||
|
|
||||||
|
if (srv->flags & SERV_ALL_ZEROS)
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
else
|
||||||
|
addr.addr4 = srv->addr;
|
||||||
|
|
||||||
|
header->ancount = htons(ntohs(header->ancount) + 1);
|
||||||
|
add_resource_record(header, ((char *)header) + 65536, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr);
|
||||||
|
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, name, (union all_addr *)&addr, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & gotname & F_IPV6)
|
||||||
|
for (start = first; start != last; start++)
|
||||||
|
{
|
||||||
|
struct serv_addr6 *srv = (struct serv_addr6 *)daemon->serverarray[start];
|
||||||
|
|
||||||
|
if (srv->flags & SERV_ALL_ZEROS)
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
else
|
||||||
|
addr.addr6 = srv->addr;
|
||||||
|
|
||||||
|
header->ancount = htons(ntohs(header->ancount) + 1);
|
||||||
|
add_resource_record(header, ((char *)header) + 65536, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_AAAA, C_IN, "6", &addr);
|
||||||
|
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, name, (union all_addr *)&addr, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trunc)
|
||||||
|
header->hb3 |= HB3_TC;
|
||||||
|
|
||||||
|
return p - (unsigned char *)header;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DNSSEC
|
||||||
|
int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp)
|
||||||
|
{
|
||||||
|
int first, last, index;
|
||||||
|
|
||||||
|
/* Find server to send DNSSEC query to. This will normally be the
|
||||||
|
same as for the original query, but may be another if
|
||||||
|
servers for domains are involved. */
|
||||||
|
if (!lookup_domain(keyname, F_DNSSECOK, &first, &last))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (index = first; index != last; index++)
|
||||||
|
if (daemon->serverarray[index] == server)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* No match to server used for original query.
|
||||||
|
Use newly looked up set. */
|
||||||
|
if (index == last)
|
||||||
|
index = daemon->serverarray[first]->last_server == -1 ?
|
||||||
|
first : daemon->serverarray[first]->last_server;
|
||||||
|
|
||||||
|
if (firstp)
|
||||||
|
*firstp = first;
|
||||||
|
|
||||||
|
if (lastp)
|
||||||
|
*lastp = last;
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* order by size, then by dictionary order */
|
||||||
|
static int order(char *qdomain, int leading_dot, size_t qlen, struct server *serv)
|
||||||
|
{
|
||||||
|
size_t dlen = 0;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* servers for dotless names always sort last
|
||||||
|
searched for name is never dotless. */
|
||||||
|
if (serv->flags & SERV_FOR_NODOTS)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (leading_dot)
|
||||||
|
qlen++;
|
||||||
|
|
||||||
|
dlen = strlen(serv->domain);
|
||||||
|
|
||||||
|
if (qlen < dlen)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (qlen > dlen)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (leading_dot && (rc = '.' - serv->domain[0]) != 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return strcmp(qdomain, leading_dot ? &serv->domain[1] : serv->domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int order_servers(struct server *s1, struct server *s2)
|
||||||
|
{
|
||||||
|
size_t dlen = strlen(s1->domain);
|
||||||
|
|
||||||
|
/* need full comparison of dotless servers in
|
||||||
|
order_qsort() and filter_servers() */
|
||||||
|
if (s1->flags & SERV_FOR_NODOTS)
|
||||||
|
return (s2->flags & SERV_FOR_NODOTS) ? 0 : 1;
|
||||||
|
|
||||||
|
return order(s1->domain, 0, dlen, s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int order_qsort(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
struct server *s1 = *((struct server **)a);
|
||||||
|
struct server *s2 = *((struct server **)b);
|
||||||
|
|
||||||
|
rc = order_servers(s1, s2);
|
||||||
|
|
||||||
|
/* Sort all literal NODATA and local IPV4 or IPV6 responses together,
|
||||||
|
in a very specific order. */
|
||||||
|
if (rc == 0)
|
||||||
|
rc = (s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS)) -
|
||||||
|
(s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS));
|
||||||
|
|
||||||
|
/* Finally, order by appearance in /etc/resolv.conf etc, for --strict-order */
|
||||||
|
if (rc == 0)
|
||||||
|
if (!(s1->flags & SERV_LITERAL_ADDRESS))
|
||||||
|
rc = s1->serial - s2->serial;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
+63
@@ -427,6 +427,66 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See https://docs.umbrella.com/umbrella-api/docs/identifying-dns-traffic for
|
||||||
|
* detailed information on packet formating.
|
||||||
|
*/
|
||||||
|
#define UMBRELLA_VERSION 1
|
||||||
|
#define UMBRELLA_TYPESZ 2
|
||||||
|
|
||||||
|
#define UMBRELLA_ASSET 0x0004
|
||||||
|
#define UMBRELLA_ASSETSZ sizeof(daemon->umbrella_asset)
|
||||||
|
#define UMBRELLA_ORG 0x0008
|
||||||
|
#define UMBRELLA_ORGSZ sizeof(daemon->umbrella_org)
|
||||||
|
#define UMBRELLA_IPV4 0x0010
|
||||||
|
#define UMBRELLA_IPV6 0x0020
|
||||||
|
#define UMBRELLA_DEVICE 0x0040
|
||||||
|
#define UMBRELLA_DEVICESZ sizeof(daemon->umbrella_device)
|
||||||
|
|
||||||
|
struct umbrella_opt {
|
||||||
|
u8 magic[4];
|
||||||
|
u8 version;
|
||||||
|
u8 flags;
|
||||||
|
/* We have 4 possible fields since we'll never send both IPv4 and
|
||||||
|
* IPv6, so using the larger of the two to calculate max buffer size.
|
||||||
|
* Each field also has a type header. So the following accounts for
|
||||||
|
* the type headers and each field size to get a max buffer size.
|
||||||
|
*/
|
||||||
|
u8 fields[4 * UMBRELLA_TYPESZ + UMBRELLA_ORGSZ + IN6ADDRSZ + UMBRELLA_DEVICESZ + UMBRELLA_ASSETSZ];
|
||||||
|
};
|
||||||
|
|
||||||
|
static size_t add_umbrella_opt(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable)
|
||||||
|
{
|
||||||
|
*cacheable = 0;
|
||||||
|
|
||||||
|
struct umbrella_opt opt = {{"ODNS"}, UMBRELLA_VERSION, 0, {}};
|
||||||
|
u8 *u = &opt.fields[0];
|
||||||
|
|
||||||
|
if (daemon->umbrella_org) {
|
||||||
|
PUTSHORT(UMBRELLA_ORG, u);
|
||||||
|
PUTLONG(daemon->umbrella_org, u);
|
||||||
|
}
|
||||||
|
|
||||||
|
int family = source->sa.sa_family;
|
||||||
|
PUTSHORT(family == AF_INET ? UMBRELLA_IPV4 : UMBRELLA_IPV6, u);
|
||||||
|
int size = family == AF_INET ? INADDRSZ : IN6ADDRSZ;
|
||||||
|
memcpy(u, get_addrp(source, family), size);
|
||||||
|
u += size;
|
||||||
|
|
||||||
|
if (option_bool(OPT_UMBRELLA_DEVID)) {
|
||||||
|
PUTSHORT(UMBRELLA_DEVICE, u);
|
||||||
|
memcpy(u, (char *)&daemon->umbrella_device, UMBRELLA_DEVICESZ);
|
||||||
|
u += UMBRELLA_DEVICESZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (daemon->umbrella_asset) {
|
||||||
|
PUTSHORT(UMBRELLA_ASSET, u);
|
||||||
|
PUTLONG(daemon->umbrella_asset, u);
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = u - &opt.magic[0];
|
||||||
|
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_UMBRELLA, (unsigned char *)&opt, len, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Set *check_subnet if we add a client subnet option, which needs to checked
|
/* Set *check_subnet if we add a client subnet option, which needs to checked
|
||||||
in the reply. Set *cacheable to zero if we add an option which the answer
|
in the reply. Set *cacheable to zero if we add an option which the answer
|
||||||
may depend on. */
|
may depend on. */
|
||||||
@@ -446,6 +506,9 @@ size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *l
|
|||||||
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID,
|
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID,
|
||||||
(unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1);
|
(unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1);
|
||||||
|
|
||||||
|
if (option_bool(OPT_UMBRELLA))
|
||||||
|
plen = add_umbrella_opt(header, plen, limit, source, cacheable);
|
||||||
|
|
||||||
if (option_bool(OPT_CLIENT_SUBNET))
|
if (option_bool(OPT_CLIENT_SUBNET))
|
||||||
{
|
{
|
||||||
plen = add_source_addr(header, plen, limit, source, cacheable);
|
plen = add_source_addr(header, plen, limit, source, cacheable);
|
||||||
|
|||||||
+666
-881
File diff suppressed because it is too large.
Load diff
File renamed without changes.
+1
-4
@@ -882,7 +882,4 @@ void helper_write(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif /* HAVE_SCRIPT */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -295,4 +295,3 @@ int inotify_check(time_t now)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif /* INOTIFY */
|
#endif /* INOTIFY */
|
||||||
|
|
||||||
@@ -31,4 +31,3 @@
|
|||||||
&& ((__const uint32_t *) (a))[1] == 0 \
|
&& ((__const uint32_t *) (a))[1] == 0 \
|
||||||
&& ((__const uint32_t *) (a))[2] == 0 \
|
&& ((__const uint32_t *) (a))[2] == 0 \
|
||||||
&& ((__const uint32_t *) (a))[3] == 0)
|
&& ((__const uint32_t *) (a))[3] == 0)
|
||||||
|
|
||||||
+1
-5
@@ -1201,8 +1201,4 @@ void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif /* HAVE_DHCP */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+4
-4
@@ -30,8 +30,8 @@ void loop_send_probes()
|
|||||||
/* Loop through all upstream servers not for particular domains, and send a query to that server which is
|
/* Loop through all upstream servers not for particular domains, and send a query to that server which is
|
||||||
identifiable, via the uid. If we see that query back again, then the server is looping, and we should not use it. */
|
identifiable, via the uid. If we see that query back again, then the server is looping, and we should not use it. */
|
||||||
for (serv = daemon->servers; serv; serv = serv->next)
|
for (serv = daemon->servers; serv; serv = serv->next)
|
||||||
if (!(serv->flags &
|
if (strlen(serv->domain) == 0 &&
|
||||||
(SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_LOOP)))
|
!(serv->flags & (SERV_FOR_NODOTS | SERV_LOOP)))
|
||||||
{
|
{
|
||||||
ssize_t len = loop_make_probe(serv->uid);
|
ssize_t len = loop_make_probe(serv->uid);
|
||||||
int fd;
|
int fd;
|
||||||
@@ -96,8 +96,8 @@ int detect_loop(char *query, int type)
|
|||||||
uid = strtol(query, NULL, 16);
|
uid = strtol(query, NULL, 16);
|
||||||
|
|
||||||
for (serv = daemon->servers; serv; serv = serv->next)
|
for (serv = daemon->servers; serv; serv = serv->next)
|
||||||
if (!(serv->flags &
|
if (strlen(serv->domain) == 0 &&
|
||||||
(SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_LOOP)) &&
|
!(serv->flags & SERV_LOOP) &&
|
||||||
uid == serv->uid)
|
uid == serv->uid)
|
||||||
{
|
{
|
||||||
serv->flags |= SERV_LOOP;
|
serv->flags |= SERV_LOOP;
|
||||||
|
|||||||
+1
-3
@@ -402,6 +402,4 @@ static unsigned nl_async(struct nlmsghdr *h, unsigned state)
|
|||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* HAVE_LINUX_NETWORK */
|
||||||
|
|
||||||
|
|
||||||
+71
-52
@@ -1479,8 +1479,7 @@ void pre_allocate_sfds(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (srv = daemon->servers; srv; srv = srv->next)
|
for (srv = daemon->servers; srv; srv = srv->next)
|
||||||
if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
|
if (!allocate_sfd(&srv->source_addr, srv->interface, srv->ifindex) &&
|
||||||
!allocate_sfd(&srv->source_addr, srv->interface, srv->ifindex) &&
|
|
||||||
errno != 0 &&
|
errno != 0 &&
|
||||||
option_bool(OPT_NOWILD))
|
option_bool(OPT_NOWILD))
|
||||||
{
|
{
|
||||||
@@ -1509,6 +1508,10 @@ void mark_servers(int flag)
|
|||||||
serv->flags &= ~SERV_LOOP;
|
serv->flags &= ~SERV_LOOP;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (serv = daemon->local_domains; serv; serv = serv->next)
|
||||||
|
if (serv->flags & flag)
|
||||||
|
serv->flags |= SERV_MARK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_servers(void)
|
void cleanup_servers(void)
|
||||||
@@ -1523,7 +1526,6 @@ void cleanup_servers(void)
|
|||||||
{
|
{
|
||||||
server_gone(serv);
|
server_gone(serv);
|
||||||
*up = serv->next;
|
*up = serv->next;
|
||||||
if (serv->domain)
|
|
||||||
free(serv->domain);
|
free(serv->domain);
|
||||||
free(serv);
|
free(serv);
|
||||||
}
|
}
|
||||||
@@ -1531,6 +1533,20 @@ void cleanup_servers(void)
|
|||||||
up = &serv->next;
|
up = &serv->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (serv = daemon->local_domains, up = &daemon->local_domains; serv; serv = tmp)
|
||||||
|
{
|
||||||
|
tmp = serv->next;
|
||||||
|
if (serv->flags & SERV_MARK)
|
||||||
|
{
|
||||||
|
*up = serv->next;
|
||||||
|
free(serv->domain);
|
||||||
|
free(serv);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
up = &serv->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_LOOP
|
#ifdef HAVE_LOOP
|
||||||
/* Now we have a new set of servers, test for loops. */
|
/* Now we have a new set of servers, test for loops. */
|
||||||
loop_send_probes();
|
loop_send_probes();
|
||||||
@@ -1543,40 +1559,40 @@ void add_update_server(int flags,
|
|||||||
const char *interface,
|
const char *interface,
|
||||||
const char *domain)
|
const char *domain)
|
||||||
{
|
{
|
||||||
struct server *serv, *next = NULL;
|
struct server *serv;
|
||||||
char *domain_str = NULL;
|
char *domain_str;
|
||||||
|
|
||||||
|
if (!domain)
|
||||||
|
domain = "";
|
||||||
|
|
||||||
|
/* If the server is USE_RESOLV or LITERAL_ADDRES, it lives on the local_domains chain.
|
||||||
|
NOTE that we can get local=/domain/ here, but NOT address=/domain/1.2.3.4 */
|
||||||
|
#define SERV_IS_LOCAL (SERV_USE_RESOLV | SERV_LITERAL_ADDRESS)
|
||||||
|
|
||||||
/* See if there is a suitable candidate, and unmark */
|
/* See if there is a suitable candidate, and unmark */
|
||||||
for (serv = daemon->servers; serv; serv = serv->next)
|
for (serv = (flags & SERV_IS_LOCAL) ? daemon->local_domains : daemon->servers; serv; serv = serv->next)
|
||||||
if (serv->flags & SERV_MARK)
|
if ((serv->flags & SERV_MARK) && hostname_isequal(domain, serv->domain))
|
||||||
{
|
|
||||||
if (domain)
|
|
||||||
{
|
|
||||||
if (!(serv->flags & SERV_HAS_DOMAIN) || !hostname_isequal(domain, serv->domain))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (serv->flags & SERV_HAS_DOMAIN)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
if (serv)
|
if (serv)
|
||||||
{
|
|
||||||
domain_str = serv->domain;
|
domain_str = serv->domain;
|
||||||
next = serv->next;
|
|
||||||
}
|
|
||||||
else if ((serv = whine_malloc(sizeof (struct server))))
|
else if ((serv = whine_malloc(sizeof (struct server))))
|
||||||
{
|
{
|
||||||
/* Not found, create a new one. */
|
/* Not found, create a new one. */
|
||||||
if (domain && !(domain_str = whine_malloc(strlen(domain)+1)))
|
if (!(domain_str = whine_malloc(strlen(domain)+1)))
|
||||||
{
|
{
|
||||||
free(serv);
|
free(serv);
|
||||||
serv = NULL;
|
serv = NULL;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcpy(domain_str, domain);
|
||||||
|
|
||||||
|
if (flags & SERV_IS_LOCAL)
|
||||||
|
{
|
||||||
|
serv->next = daemon->local_domains;
|
||||||
|
daemon->local_domains = serv;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct server *s;
|
struct server *s;
|
||||||
@@ -1588,25 +1604,28 @@ void add_update_server(int flags,
|
|||||||
for (s = daemon->servers; s->next; s = s->next);
|
for (s = daemon->servers; s->next; s = s->next);
|
||||||
s->next = serv;
|
s->next = serv;
|
||||||
}
|
}
|
||||||
if (domain)
|
|
||||||
strcpy(domain_str, domain);
|
serv->next = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serv)
|
if (serv)
|
||||||
{
|
{
|
||||||
|
if (!(flags & SERV_IS_LOCAL))
|
||||||
memset(serv, 0, sizeof(struct server));
|
memset(serv, 0, sizeof(struct server));
|
||||||
|
|
||||||
serv->flags = flags;
|
serv->flags = flags;
|
||||||
serv->domain = domain_str;
|
serv->domain = domain_str;
|
||||||
serv->next = next;
|
|
||||||
|
|
||||||
|
if (!(flags & SERV_IS_LOCAL))
|
||||||
|
{
|
||||||
serv->queries = serv->failed_queries = 0;
|
serv->queries = serv->failed_queries = 0;
|
||||||
#ifdef HAVE_LOOP
|
#ifdef HAVE_LOOP
|
||||||
serv->uid = rand32();
|
serv->uid = rand32();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (domain)
|
|
||||||
serv->flags |= SERV_HAS_DOMAIN;
|
|
||||||
|
|
||||||
if (interface)
|
if (interface)
|
||||||
safe_strncpy(serv->interface, interface, sizeof(serv->interface));
|
safe_strncpy(serv->interface, interface, sizeof(serv->interface));
|
||||||
if (addr)
|
if (addr)
|
||||||
@@ -1614,6 +1633,7 @@ void add_update_server(int flags,
|
|||||||
if (source_addr)
|
if (source_addr)
|
||||||
serv->source_addr = *source_addr;
|
serv->source_addr = *source_addr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_servers(void)
|
void check_servers(void)
|
||||||
@@ -1633,8 +1653,6 @@ void check_servers(void)
|
|||||||
sfd->used = sfd->preallocated;
|
sfd->used = sfd->preallocated;
|
||||||
|
|
||||||
for (count = 0, serv = daemon->servers; serv; serv = serv->next)
|
for (count = 0, serv = daemon->servers; serv; serv = serv->next)
|
||||||
{
|
|
||||||
if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
|
|
||||||
{
|
{
|
||||||
/* Init edns_pktsz for newly created server records. */
|
/* Init edns_pktsz for newly created server records. */
|
||||||
if (serv->edns_pktsz == 0)
|
if (serv->edns_pktsz == 0)
|
||||||
@@ -1648,7 +1666,7 @@ void check_servers(void)
|
|||||||
|
|
||||||
/* Disable DNSSEC validation when using server=/domain/.... servers
|
/* Disable DNSSEC validation when using server=/domain/.... servers
|
||||||
unless there's a configured trust anchor. */
|
unless there's a configured trust anchor. */
|
||||||
if (serv->flags & SERV_HAS_DOMAIN)
|
if (strlen(serv->domain) != 0)
|
||||||
{
|
{
|
||||||
struct ds_config *ds;
|
struct ds_config *ds;
|
||||||
char *domain = serv->domain;
|
char *domain = serv->domain;
|
||||||
@@ -1701,36 +1719,25 @@ void check_servers(void)
|
|||||||
|
|
||||||
if (serv->sfd)
|
if (serv->sfd)
|
||||||
serv->sfd->used = 1;
|
serv->sfd->used = 1;
|
||||||
}
|
|
||||||
|
|
||||||
if (!(serv->flags & SERV_NO_REBIND) && !(serv->flags & SERV_LITERAL_ADDRESS))
|
|
||||||
{
|
|
||||||
if (++count > SERVERS_LOGGED)
|
if (++count > SERVERS_LOGGED)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (serv->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV))
|
if (strlen(serv->domain) != 0 || (serv->flags & SERV_FOR_NODOTS))
|
||||||
{
|
{
|
||||||
char *s1, *s2, *s3 = "";
|
char *s1, *s2, *s3 = "";
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC))
|
if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC))
|
||||||
s3 = _("(no DNSSEC)");
|
s3 = _("(no DNSSEC)");
|
||||||
#endif
|
#endif
|
||||||
if (!(serv->flags & SERV_HAS_DOMAIN))
|
if (serv->flags & SERV_FOR_NODOTS)
|
||||||
s1 = _("unqualified"), s2 = _("names");
|
s1 = _("unqualified"), s2 = _("names");
|
||||||
else if (strlen(serv->domain) == 0)
|
else if (strlen(serv->domain) == 0)
|
||||||
s1 = _("default"), s2 = "";
|
s1 = _("default"), s2 = "";
|
||||||
else
|
else
|
||||||
s1 = _("domain"), s2 = serv->domain;
|
s1 = _("domain"), s2 = serv->domain;
|
||||||
|
|
||||||
if (serv->flags & SERV_NO_ADDR)
|
|
||||||
{
|
|
||||||
count--;
|
|
||||||
if (++locals <= LOCALS_LOGGED)
|
|
||||||
my_syslog(LOG_INFO, _("using only locally-known addresses for %s %s"), s1, s2);
|
|
||||||
}
|
|
||||||
else if (serv->flags & SERV_USE_RESOLV)
|
|
||||||
my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2);
|
|
||||||
else
|
|
||||||
my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s %s"), daemon->namebuff, port, s1, s2, s3);
|
my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s %s"), daemon->namebuff, port, s1, s2, s3);
|
||||||
}
|
}
|
||||||
#ifdef HAVE_LOOP
|
#ifdef HAVE_LOOP
|
||||||
@@ -1741,7 +1748,23 @@ void check_servers(void)
|
|||||||
my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, serv->interface);
|
my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, serv->interface);
|
||||||
else
|
else
|
||||||
my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port);
|
my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (count = 0, serv = daemon->local_domains; serv; serv = serv->next)
|
||||||
|
{
|
||||||
|
if (++count > SERVERS_LOGGED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((serv->flags & SERV_LITERAL_ADDRESS) &&
|
||||||
|
!(serv->flags & (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)))
|
||||||
|
{
|
||||||
|
count--;
|
||||||
|
if (++locals <= LOCALS_LOGGED)
|
||||||
|
my_syslog(LOG_INFO, _("using only locally-known addresses for %s"), serv->domain);
|
||||||
|
}
|
||||||
|
else if (serv->flags & SERV_USE_RESOLV)
|
||||||
|
my_syslog(LOG_INFO, _("using standard nameservers for %s"), serv->domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locals > LOCALS_LOGGED)
|
if (locals > LOCALS_LOGGED)
|
||||||
@@ -1764,6 +1787,7 @@ void check_servers(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cleanup_servers();
|
cleanup_servers();
|
||||||
|
build_server_array();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return zero if no servers found, in that case we keep polling.
|
/* Return zero if no servers found, in that case we keep polling.
|
||||||
@@ -1869,8 +1893,3 @@ void newaddress(time_t now)
|
|||||||
lease_find_interfaces(now);
|
lease_find_interfaces(now);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+221
-131
@@ -170,6 +170,7 @@ struct myoption {
|
|||||||
#define LOPT_PXE_VENDOR 361
|
#define LOPT_PXE_VENDOR 361
|
||||||
#define LOPT_DYNHOST 362
|
#define LOPT_DYNHOST 362
|
||||||
#define LOPT_LOG_DEBUG 363
|
#define LOPT_LOG_DEBUG 363
|
||||||
|
#define LOPT_UMBRELLA 364
|
||||||
|
|
||||||
#ifdef HAVE_GETOPT_LONG
|
#ifdef HAVE_GETOPT_LONG
|
||||||
static const struct option opts[] =
|
static const struct option opts[] =
|
||||||
@@ -345,6 +346,7 @@ static const struct myoption opts[] =
|
|||||||
{ "dhcp-ignore-clid", 0, 0, LOPT_IGNORE_CLID },
|
{ "dhcp-ignore-clid", 0, 0, LOPT_IGNORE_CLID },
|
||||||
{ "dynamic-host", 1, 0, LOPT_DYNHOST },
|
{ "dynamic-host", 1, 0, LOPT_DYNHOST },
|
||||||
{ "log-debug", 0, 0, LOPT_LOG_DEBUG },
|
{ "log-debug", 0, 0, LOPT_LOG_DEBUG },
|
||||||
|
{ "umbrella", 2, 0, LOPT_UMBRELLA },
|
||||||
{ NULL, 0, 0, 0 }
|
{ NULL, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -527,6 +529,7 @@ static struct {
|
|||||||
{ LOPT_DUMPFILE, ARG_ONE, "<path>", gettext_noop("Path to debug packet dump file"), NULL },
|
{ LOPT_DUMPFILE, ARG_ONE, "<path>", gettext_noop("Path to debug packet dump file"), NULL },
|
||||||
{ LOPT_DUMPMASK, ARG_ONE, "<hex>", gettext_noop("Mask which packets to dump"), NULL },
|
{ LOPT_DUMPMASK, ARG_ONE, "<hex>", gettext_noop("Mask which packets to dump"), NULL },
|
||||||
{ LOPT_SCRIPT_TIME, OPT_LEASE_RENEW, NULL, gettext_noop("Call dhcp-script when lease expiry changes."), NULL },
|
{ LOPT_SCRIPT_TIME, OPT_LEASE_RENEW, NULL, gettext_noop("Call dhcp-script when lease expiry changes."), NULL },
|
||||||
|
{ LOPT_UMBRELLA, ARG_ONE, "[=<optspec>]", gettext_noop("Send Cisco Umbrella identifiers including remote IP."), NULL },
|
||||||
{ 0, 0, NULL, NULL, NULL }
|
{ 0, 0, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -641,6 +644,9 @@ static char *canonicalise_opt(char *s)
|
|||||||
if (!s)
|
if (!s)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (strlen(s) == 0)
|
||||||
|
return "";
|
||||||
|
|
||||||
unhide_metas(s);
|
unhide_metas(s);
|
||||||
if (!(ret = canonicalise(s, &nomem)) && nomem)
|
if (!(ret = canonicalise(s, &nomem)) && nomem)
|
||||||
{
|
{
|
||||||
@@ -653,7 +659,7 @@ static char *canonicalise_opt(char *s)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int atoi_check(char *a, int *res)
|
static int numeric_check(char *a)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
@@ -666,10 +672,29 @@ static int atoi_check(char *a, int *res)
|
|||||||
if (*p < '0' || *p > '9')
|
if (*p < '0' || *p > '9')
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int atoi_check(char *a, int *res)
|
||||||
|
{
|
||||||
|
if (!numeric_check(a))
|
||||||
|
return 0;
|
||||||
*res = atoi(a);
|
*res = atoi(a);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int strtoul_check(char *a, u32 *res)
|
||||||
|
{
|
||||||
|
if (!numeric_check(a))
|
||||||
|
return 0;
|
||||||
|
*res = strtoul(a, NULL, 10);
|
||||||
|
if (errno == ERANGE) {
|
||||||
|
errno = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int atoi_check16(char *a, int *res)
|
static int atoi_check16(char *a, int *res)
|
||||||
{
|
{
|
||||||
if (!(atoi_check(a, res)) ||
|
if (!(atoi_check(a, res)) ||
|
||||||
@@ -795,10 +820,10 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
|
|||||||
int scope_index = 0;
|
int scope_index = 0;
|
||||||
char *scope_id;
|
char *scope_id;
|
||||||
|
|
||||||
if (!arg || strlen(arg) == 0)
|
if (strcmp(arg, "#") == 0)
|
||||||
{
|
{
|
||||||
*flags |= SERV_NO_ADDR;
|
if (flags)
|
||||||
*interface = 0;
|
*flags |= SERV_USE_RESOLV;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -927,10 +952,6 @@ static struct server *add_rev4(struct in_addr addr, int msize)
|
|||||||
|
|
||||||
p += sprintf(p, "in-addr.arpa");
|
p += sprintf(p, "in-addr.arpa");
|
||||||
|
|
||||||
serv->flags = SERV_HAS_DOMAIN;
|
|
||||||
serv->next = daemon->servers;
|
|
||||||
daemon->servers = serv;
|
|
||||||
|
|
||||||
return serv;
|
return serv;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -951,10 +972,6 @@ static struct server *add_rev6(struct in6_addr *addr, int msize)
|
|||||||
}
|
}
|
||||||
p += sprintf(p, "ip6.arpa");
|
p += sprintf(p, "ip6.arpa");
|
||||||
|
|
||||||
serv->flags = SERV_HAS_DOMAIN;
|
|
||||||
serv->next = daemon->servers;
|
|
||||||
daemon->servers = serv;
|
|
||||||
|
|
||||||
return serv;
|
return serv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1045,6 +1062,8 @@ static void dhcp_config_free(struct dhcp_config *config)
|
|||||||
|
|
||||||
if (config->flags & CONFIG_CLID)
|
if (config->flags & CONFIG_CLID)
|
||||||
free(config->clid);
|
free(config->clid);
|
||||||
|
if (config->flags & CONFIG_NAME)
|
||||||
|
free(config->hostname);
|
||||||
|
|
||||||
#ifdef HAVE_DHCP6
|
#ifdef HAVE_DHCP6
|
||||||
if (config->flags & CONFIG_ADDR6)
|
if (config->flags & CONFIG_ADDR6)
|
||||||
@@ -1640,16 +1659,6 @@ void reset_option_bool(unsigned int opt)
|
|||||||
option_var(opt) &= ~(option_val(opt));
|
option_var(opt) &= ~(option_val(opt));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void server_list_free(struct server *list)
|
|
||||||
{
|
|
||||||
while (list)
|
|
||||||
{
|
|
||||||
struct server *tmp = list;
|
|
||||||
list = list->next;
|
|
||||||
free(tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only)
|
static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -2285,15 +2294,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|||||||
if (!serv)
|
if (!serv)
|
||||||
ret_err_free(_("bad prefix"), new);
|
ret_err_free(_("bad prefix"), new);
|
||||||
|
|
||||||
serv->flags |= SERV_NO_ADDR;
|
serv->flags |= SERV_LITERAL_ADDRESS;
|
||||||
|
serv->next = daemon->local_domains;
|
||||||
|
daemon->local_domains = serv;
|
||||||
|
|
||||||
/* local=/<domain>/ */
|
/* local=/<domain>/ */
|
||||||
serv = opt_malloc(sizeof(struct server));
|
serv = opt_malloc(sizeof(struct server));
|
||||||
memset(serv, 0, sizeof(struct server));
|
memset(serv, 0, sizeof(struct server));
|
||||||
serv->domain = d;
|
serv->domain = d;
|
||||||
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
|
serv->flags = SERV_LITERAL_ADDRESS;
|
||||||
serv->next = daemon->servers;
|
serv->next = daemon->local_domains;
|
||||||
daemon->servers = serv;
|
daemon->local_domains = serv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2328,15 +2339,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|||||||
/* generate the equivalent of
|
/* generate the equivalent of
|
||||||
local=/xxx.yyy.zzz.ip6.arpa/ */
|
local=/xxx.yyy.zzz.ip6.arpa/ */
|
||||||
struct server *serv = add_rev6(&new->start6, msize);
|
struct server *serv = add_rev6(&new->start6, msize);
|
||||||
serv->flags |= SERV_NO_ADDR;
|
serv->flags |= SERV_LITERAL_ADDRESS;
|
||||||
|
serv->next = daemon->local_domains;
|
||||||
|
daemon->local_domains = serv;
|
||||||
|
|
||||||
/* local=/<domain>/ */
|
/* local=/<domain>/ */
|
||||||
serv = opt_malloc(sizeof(struct server));
|
serv = opt_malloc(sizeof(struct server));
|
||||||
memset(serv, 0, sizeof(struct server));
|
memset(serv, 0, sizeof(struct server));
|
||||||
serv->domain = d;
|
serv->domain = d;
|
||||||
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
|
serv->flags = SERV_LITERAL_ADDRESS;
|
||||||
serv->next = daemon->servers;
|
serv->next = daemon->local_domains;
|
||||||
daemon->servers = serv;
|
daemon->local_domains = serv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2409,6 +2422,41 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|||||||
daemon->dns_client_id = opt_string_alloc(arg);
|
daemon->dns_client_id = opt_string_alloc(arg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case LOPT_UMBRELLA: /* --umbrella */
|
||||||
|
set_option_bool(OPT_UMBRELLA);
|
||||||
|
while (arg) {
|
||||||
|
comma = split(arg);
|
||||||
|
if (strstr(arg, "deviceid:")) {
|
||||||
|
arg += 9;
|
||||||
|
if (strlen(arg) != 16)
|
||||||
|
ret_err(gen_err);
|
||||||
|
for (char *p = arg; *p; p++) {
|
||||||
|
if (!isxdigit((int)*p))
|
||||||
|
ret_err(gen_err);
|
||||||
|
}
|
||||||
|
set_option_bool(OPT_UMBRELLA_DEVID);
|
||||||
|
|
||||||
|
u8 *u = daemon->umbrella_device;
|
||||||
|
char word[3];
|
||||||
|
for (u8 i = 0; i < sizeof(daemon->umbrella_device); i++, arg+=2) {
|
||||||
|
memcpy(word, &(arg[0]), 2);
|
||||||
|
*u++ = strtoul(word, NULL, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strstr(arg, "orgid:")) {
|
||||||
|
if (!strtoul_check(arg+6, &daemon->umbrella_org)) {
|
||||||
|
ret_err(gen_err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strstr(arg, "assetid:")) {
|
||||||
|
if (!strtoul_check(arg+8, &daemon->umbrella_asset)) {
|
||||||
|
ret_err(gen_err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arg = comma;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case LOPT_ADD_MAC: /* --add-mac */
|
case LOPT_ADD_MAC: /* --add-mac */
|
||||||
if (!arg)
|
if (!arg)
|
||||||
set_option_bool(OPT_ADD_MAC);
|
set_option_bool(OPT_ADD_MAC);
|
||||||
@@ -2556,97 +2604,165 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|||||||
} while (arg);
|
} while (arg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'S': /* --server */
|
|
||||||
case LOPT_LOCAL: /* --local */
|
|
||||||
case 'A': /* --address */
|
|
||||||
case LOPT_NO_REBIND: /* --rebind-domain-ok */
|
case LOPT_NO_REBIND: /* --rebind-domain-ok */
|
||||||
{
|
{
|
||||||
struct server *serv, *newlist = NULL;
|
struct server *new;
|
||||||
|
|
||||||
unhide_metas(arg);
|
unhide_metas(arg);
|
||||||
|
|
||||||
if (arg && (*arg == '/' || option == LOPT_NO_REBIND))
|
if (*arg == '/')
|
||||||
{
|
|
||||||
int rebind = !(*arg == '/');
|
|
||||||
char *end = NULL;
|
|
||||||
if (!rebind)
|
|
||||||
arg++;
|
arg++;
|
||||||
while (rebind || (end = split_chr(arg, '/')))
|
|
||||||
{
|
do {
|
||||||
char *domain = NULL;
|
comma = split_chr(arg, '/');
|
||||||
/* elide leading dots - they are implied in the search algorithm */
|
new = opt_malloc(sizeof(struct serv_local));
|
||||||
while (*arg == '.') arg++;
|
new->domain = opt_string_alloc(arg);
|
||||||
/* # matches everything and becomes a zero length domain string */
|
new->flags = strlen(arg);
|
||||||
if (strcmp(arg, "#") == 0)
|
new->next = daemon->no_rebind;
|
||||||
domain = "";
|
daemon->no_rebind = new;
|
||||||
else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))
|
arg = comma;
|
||||||
ret_err(gen_err);
|
} while (arg && *arg);
|
||||||
serv = opt_malloc(sizeof(struct server));
|
|
||||||
memset(serv, 0, sizeof(struct server));
|
|
||||||
serv->next = newlist;
|
|
||||||
newlist = serv;
|
|
||||||
serv->domain = domain;
|
|
||||||
serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
|
|
||||||
arg = end;
|
|
||||||
if (rebind)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!newlist)
|
|
||||||
ret_err(gen_err);
|
case 'S': /* --server */
|
||||||
}
|
case LOPT_LOCAL: /* --local */
|
||||||
else
|
case 'A': /* --address */
|
||||||
{
|
{
|
||||||
newlist = opt_malloc(sizeof(struct server));
|
struct server *new;
|
||||||
memset(newlist, 0, sizeof(struct server));
|
size_t size;
|
||||||
#ifdef HAVE_LOOP
|
char *lastdomain = NULL, *domain = "";
|
||||||
newlist->uid = rand32();
|
char *alloc_domain;
|
||||||
#endif
|
int flags = 0;
|
||||||
|
char *err;
|
||||||
|
struct in_addr addr4;
|
||||||
|
struct in6_addr addr6;
|
||||||
|
|
||||||
|
unhide_metas(arg);
|
||||||
|
|
||||||
|
/* split the domain args, if any and skip to the end of them. */
|
||||||
|
if (arg && *arg == '/')
|
||||||
|
{
|
||||||
|
char *last;
|
||||||
|
|
||||||
|
arg++;
|
||||||
|
domain = lastdomain = arg;
|
||||||
|
|
||||||
|
while ((last = split_chr(arg, '/')))
|
||||||
|
{
|
||||||
|
lastdomain = arg;
|
||||||
|
arg = last;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (servers_only && option == 'S')
|
if (servers_only && option == 'S')
|
||||||
newlist->flags |= SERV_FROM_FILE;
|
flags |= SERV_FROM_FILE;
|
||||||
|
|
||||||
if (option == 'A')
|
|
||||||
{
|
|
||||||
newlist->flags |= SERV_LITERAL_ADDRESS;
|
|
||||||
if (!(newlist->flags & SERV_TYPE))
|
|
||||||
{
|
|
||||||
server_list_free(newlist);
|
|
||||||
ret_err(gen_err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (option == LOPT_NO_REBIND)
|
|
||||||
newlist->flags |= SERV_NO_REBIND;
|
|
||||||
|
|
||||||
if (!arg || !*arg)
|
if (!arg || !*arg)
|
||||||
|
flags = SERV_LITERAL_ADDRESS;
|
||||||
|
else if (option == 'A')
|
||||||
{
|
{
|
||||||
if (!(newlist->flags & SERV_NO_REBIND))
|
/* # as literal address means return zero address for 4 and 6 */
|
||||||
newlist->flags |= SERV_NO_ADDR; /* no server */
|
if (strcmp(arg, "#") == 0)
|
||||||
|
flags |= SERV_ALL_ZEROS | SERV_LITERAL_ADDRESS;
|
||||||
|
else if (inet_pton(AF_INET, arg, &addr4) > 0)
|
||||||
|
flags |= SERV_4ADDR | SERV_LITERAL_ADDRESS;
|
||||||
|
else if (inet_pton(AF_INET6, arg, &addr6) > 0)
|
||||||
|
flags |= SERV_6ADDR | SERV_LITERAL_ADDRESS;
|
||||||
|
else
|
||||||
|
ret_err(_("Bad address in --address"));
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (strcmp(arg, "#") == 0)
|
if (!(alloc_domain = canonicalise_opt(domain)))
|
||||||
newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
|
ret_err(gen_err);
|
||||||
|
|
||||||
|
|
||||||
|
if (flags & SERV_LITERAL_ADDRESS)
|
||||||
|
{
|
||||||
|
if (flags & SERV_6ADDR)
|
||||||
|
{
|
||||||
|
size = sizeof(struct serv_addr6);
|
||||||
|
new = opt_malloc(sizeof(struct serv_addr6));
|
||||||
|
((struct serv_addr6*)new)->addr = addr6;
|
||||||
|
}
|
||||||
|
else if (flags & SERV_4ADDR)
|
||||||
|
{
|
||||||
|
size = sizeof(struct serv_addr4);
|
||||||
|
new = opt_malloc(sizeof(struct serv_addr4));
|
||||||
|
((struct serv_addr4*)new)->addr = addr4;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
|
size = sizeof(struct serv_local);
|
||||||
if (err)
|
new = opt_malloc(sizeof(struct serv_local));
|
||||||
|
}
|
||||||
|
|
||||||
|
new->next = daemon->local_domains;
|
||||||
|
daemon->local_domains = new;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
server_list_free(newlist);
|
size = sizeof(struct server);
|
||||||
|
new = opt_malloc(sizeof(struct server));
|
||||||
|
|
||||||
|
#ifdef HAVE_LOOP
|
||||||
|
new->uid = rand32();
|
||||||
|
#endif
|
||||||
|
if ((err = parse_server(arg, &new->addr, &new->source_addr, new->interface, &flags)))
|
||||||
|
{
|
||||||
|
free(new);
|
||||||
ret_err(err);
|
ret_err(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Since domains that use standard servers don't have the
|
||||||
|
network stuff, it's easier to treat them as local. */
|
||||||
|
if (flags & SERV_USE_RESOLV)
|
||||||
|
{
|
||||||
|
new->next = daemon->local_domains;
|
||||||
|
daemon->local_domains = new;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new->next = daemon->servers;
|
||||||
|
daemon->servers = new;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serv = newlist;
|
new->domain = alloc_domain;
|
||||||
while (serv->next)
|
|
||||||
|
/* server=//1.2.3.4 is special. */
|
||||||
|
if (strlen(domain) == 0 && lastdomain)
|
||||||
|
flags |= SERV_FOR_NODOTS;
|
||||||
|
|
||||||
|
new->flags = flags;
|
||||||
|
|
||||||
|
/* If we have more than one domain, copy and iterate */
|
||||||
|
if (lastdomain)
|
||||||
|
while (domain != lastdomain)
|
||||||
{
|
{
|
||||||
serv->next->flags |= serv->flags & ~(SERV_HAS_DOMAIN | SERV_FOR_NODOTS);
|
struct server *last = new;
|
||||||
serv->next->addr = serv->addr;
|
|
||||||
serv->next->source_addr = serv->source_addr;
|
domain += strlen(domain) + 1;
|
||||||
strcpy(serv->next->interface, serv->interface);
|
|
||||||
serv = serv->next;
|
if (!(alloc_domain = canonicalise_opt(domain)))
|
||||||
|
ret_err(gen_err);
|
||||||
|
|
||||||
|
new = opt_malloc(size);
|
||||||
|
memcpy(new, last, size);
|
||||||
|
new->domain = alloc_domain;
|
||||||
|
if (flags & (SERV_USE_RESOLV | SERV_LITERAL_ADDRESS))
|
||||||
|
{
|
||||||
|
new->next = daemon->local_domains;
|
||||||
|
daemon->local_domains = new;
|
||||||
}
|
}
|
||||||
serv->next = daemon->servers;
|
else
|
||||||
daemon->servers = newlist;
|
{
|
||||||
|
new->next = daemon->servers;
|
||||||
|
daemon->servers = new;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2672,9 +2788,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|||||||
serv = add_rev4(addr4, size);
|
serv = add_rev4(addr4, size);
|
||||||
if (!serv)
|
if (!serv)
|
||||||
ret_err(_("bad prefix"));
|
ret_err(_("bad prefix"));
|
||||||
|
serv->next = daemon->servers;
|
||||||
|
daemon->servers = serv;
|
||||||
}
|
}
|
||||||
else if (inet_pton(AF_INET6, arg, &addr6))
|
else if (inet_pton(AF_INET6, arg, &addr6))
|
||||||
|
{
|
||||||
serv = add_rev6(&addr6, size);
|
serv = add_rev6(&addr6, size);
|
||||||
|
serv->next = daemon->servers;
|
||||||
|
daemon->servers = serv;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
ret_err(gen_err);
|
ret_err(gen_err);
|
||||||
|
|
||||||
@@ -4945,30 +5067,8 @@ static void clear_dynamic_conf(void)
|
|||||||
|
|
||||||
if (configs->flags & CONFIG_BANK)
|
if (configs->flags & CONFIG_BANK)
|
||||||
{
|
{
|
||||||
struct hwaddr_config *mac, *tmp;
|
*up = cp;
|
||||||
struct dhcp_netid_list *list, *tmplist;
|
dhcp_config_free(configs);
|
||||||
|
|
||||||
for (mac = configs->hwaddr; mac; mac = tmp)
|
|
||||||
{
|
|
||||||
tmp = mac->next;
|
|
||||||
free(mac);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (configs->flags & CONFIG_CLID)
|
|
||||||
free(configs->clid);
|
|
||||||
|
|
||||||
for (list = configs->netid; list; list = tmplist)
|
|
||||||
{
|
|
||||||
free(list->list);
|
|
||||||
tmplist = list->next;
|
|
||||||
free(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (configs->flags & CONFIG_NAME)
|
|
||||||
free(configs->hostname);
|
|
||||||
|
|
||||||
*up = configs->next;
|
|
||||||
free(configs);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
up = &configs->next;
|
up = &configs->next;
|
||||||
@@ -4978,7 +5078,6 @@ static void clear_dynamic_conf(void)
|
|||||||
static void clear_dynamic_opt(void)
|
static void clear_dynamic_opt(void)
|
||||||
{
|
{
|
||||||
struct dhcp_opt *opts, *cp, **up;
|
struct dhcp_opt *opts, *cp, **up;
|
||||||
struct dhcp_netid *id, *next;
|
|
||||||
|
|
||||||
for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
|
for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
|
||||||
{
|
{
|
||||||
@@ -4986,17 +5085,8 @@ static void clear_dynamic_opt(void)
|
|||||||
|
|
||||||
if (opts->flags & DHOPT_BANK)
|
if (opts->flags & DHOPT_BANK)
|
||||||
{
|
{
|
||||||
if ((opts->flags & DHOPT_VENDOR))
|
*up = cp;
|
||||||
free(opts->u.vendor_class);
|
dhcp_opt_free(opts);
|
||||||
free(opts->val);
|
|
||||||
for (id = opts->netid; id; id = next)
|
|
||||||
{
|
|
||||||
next = id->next;
|
|
||||||
free(id->net);
|
|
||||||
free(id);
|
|
||||||
}
|
|
||||||
*up = opts->next;
|
|
||||||
free(opts);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
up = &opts->next;
|
up = &opts->next;
|
||||||
|
|||||||
@@ -53,6 +53,3 @@ struct prefix_opt {
|
|||||||
#define ICMP6_OPT_RT_INFO 24
|
#define ICMP6_OPT_RT_INFO 24
|
||||||
#define ICMP6_OPT_RDNSS 25
|
#define ICMP6_OPT_RDNSS 25
|
||||||
#define ICMP6_OPT_DNSSL 31
|
#define ICMP6_OPT_DNSSL 31
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+6
-58
@@ -894,6 +894,8 @@ unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
|
|||||||
if (typep)
|
if (typep)
|
||||||
*typep = 0;
|
*typep = 0;
|
||||||
|
|
||||||
|
*name = 0; /* return empty name if no query found. */
|
||||||
|
|
||||||
if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
|
if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
|
||||||
return 0; /* must be exactly one query. */
|
return 0; /* must be exactly one query. */
|
||||||
|
|
||||||
@@ -926,14 +928,8 @@ unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
|
|||||||
return F_QUERY;
|
return F_QUERY;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t setup_reply(struct dns_header *header, size_t qlen,
|
void setup_reply(struct dns_header *header, unsigned int flags)
|
||||||
union all_addr *addrp, unsigned int flags, unsigned long ttl)
|
|
||||||
{
|
{
|
||||||
unsigned char *p;
|
|
||||||
|
|
||||||
if (!(p = skip_questions(header, qlen)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* clear authoritative and truncated flags, set QR flag */
|
/* clear authoritative and truncated flags, set QR flag */
|
||||||
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC )) | HB3_QR;
|
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC )) | HB3_QR;
|
||||||
/* clear AD flag, set RA flag */
|
/* clear AD flag, set RA flag */
|
||||||
@@ -946,30 +942,10 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
|
|||||||
SET_RCODE(header, NOERROR); /* empty domain */
|
SET_RCODE(header, NOERROR); /* empty domain */
|
||||||
else if (flags == F_NXDOMAIN)
|
else if (flags == F_NXDOMAIN)
|
||||||
SET_RCODE(header, NXDOMAIN);
|
SET_RCODE(header, NXDOMAIN);
|
||||||
else if (flags == F_SERVFAIL)
|
|
||||||
{
|
|
||||||
union all_addr a;
|
|
||||||
a.log.rcode = SERVFAIL;
|
|
||||||
log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
|
|
||||||
SET_RCODE(header, SERVFAIL);
|
|
||||||
}
|
|
||||||
else if (flags & ( F_IPV4 | F_IPV6))
|
else if (flags & ( F_IPV4 | F_IPV6))
|
||||||
{
|
{
|
||||||
if (flags & F_IPV4)
|
|
||||||
{ /* we know the address */
|
|
||||||
SET_RCODE(header, NOERROR);
|
SET_RCODE(header, NOERROR);
|
||||||
header->ancount = htons(1);
|
|
||||||
header->hb3 |= HB3_AA;
|
header->hb3 |= HB3_AA;
|
||||||
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & F_IPV6)
|
|
||||||
{
|
|
||||||
SET_RCODE(header, NOERROR);
|
|
||||||
header->ancount = htons(ntohs(header->ancount) + 1);
|
|
||||||
header->hb3 |= HB3_AA;
|
|
||||||
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else /* nowhere to forward to */
|
else /* nowhere to forward to */
|
||||||
{
|
{
|
||||||
@@ -978,8 +954,6 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
|
|||||||
log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
|
log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
|
||||||
SET_RCODE(header, REFUSED);
|
SET_RCODE(header, REFUSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
return p - (unsigned char *)header;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
|
/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
|
||||||
@@ -1553,36 +1527,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
anscount++;
|
anscount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (option_bool(OPT_BOGUSPRIV) && (
|
else if (option_bool(OPT_BOGUSPRIV) &&
|
||||||
(is_arpa == F_IPV6 && private_net6(&addr.addr6)) ||
|
((is_arpa == F_IPV6 && private_net6(&addr.addr6)) || (is_arpa == F_IPV4 && private_net(addr.addr4, 1))) &&
|
||||||
(is_arpa == F_IPV4 && private_net(addr.addr4, 1))))
|
!lookup_domain(name, F_DOMAINSRV, NULL, NULL))
|
||||||
{
|
{
|
||||||
struct server *serv;
|
|
||||||
unsigned int namelen = strlen(name);
|
|
||||||
char *nameend = name + namelen;
|
|
||||||
|
|
||||||
/* see if have rev-server set */
|
|
||||||
for (serv = daemon->servers; serv; serv = serv->next)
|
|
||||||
{
|
|
||||||
unsigned int domainlen;
|
|
||||||
char *matchstart;
|
|
||||||
|
|
||||||
if ((serv->flags & (SERV_HAS_DOMAIN | SERV_NO_ADDR)) != SERV_HAS_DOMAIN)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
domainlen = strlen(serv->domain);
|
|
||||||
if (domainlen == 0 || domainlen > namelen)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
matchstart = nameend - domainlen;
|
|
||||||
if (hostname_isequal(matchstart, serv->domain) &&
|
|
||||||
(namelen == domainlen || *(matchstart-1) == '.' ))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if no configured server, not in cache, enabled and private IPV4 address, return NXDOMAIN */
|
/* if no configured server, not in cache, enabled and private IPV4 address, return NXDOMAIN */
|
||||||
if (!serv)
|
|
||||||
{
|
|
||||||
ans = 1;
|
ans = 1;
|
||||||
sec_data = 0;
|
sec_data = 0;
|
||||||
nxdomain = 1;
|
nxdomain = 1;
|
||||||
@@ -1591,7 +1540,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
name, &addr, NULL);
|
name, &addr, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
|
for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-8
@@ -2785,11 +2785,4 @@ static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif /* HAVE_DHCP */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+27
-3
@@ -919,11 +919,14 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
|||||||
|
|
||||||
|
|
||||||
case DHCP6RENEW:
|
case DHCP6RENEW:
|
||||||
|
case DHCP6REBIND:
|
||||||
{
|
{
|
||||||
|
int address_assigned = 0;
|
||||||
|
|
||||||
/* set reply message type */
|
/* set reply message type */
|
||||||
*outmsgtypep = DHCP6REPLY;
|
*outmsgtypep = DHCP6REPLY;
|
||||||
|
|
||||||
log6_quiet(state, "DHCPRENEW", NULL, NULL);
|
log6_quiet(state, msg_type == DHCP6RENEW ? "DHCPRENEW" : "DHCPREBIND", NULL, NULL);
|
||||||
|
|
||||||
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
|
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
|
||||||
{
|
{
|
||||||
@@ -951,6 +954,17 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
|||||||
if (!(lease = lease6_find(state->clid, state->clid_len,
|
if (!(lease = lease6_find(state->clid, state->clid_len,
|
||||||
state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
|
state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
|
||||||
state->iaid, &req_addr)))
|
state->iaid, &req_addr)))
|
||||||
|
{
|
||||||
|
if (msg_type == DHCP6REBIND)
|
||||||
|
{
|
||||||
|
/* When rebinding, we can create a lease if it doesn't exist. */
|
||||||
|
lease = lease6_allocate(&req_addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA);
|
||||||
|
if (lease)
|
||||||
|
lease_set_iaid(lease, state->iaid);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
/* If the server cannot find a client entry for the IA the server
|
/* If the server cannot find a client entry for the IA the server
|
||||||
returns the IA containing no addresses with a Status Code option set
|
returns the IA containing no addresses with a Status Code option set
|
||||||
@@ -968,7 +982,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
|||||||
preferred_time = valid_time = 0;
|
preferred_time = valid_time = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) ||
|
if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) ||
|
||||||
(this_context = address6_valid(state->context, &req_addr, tagif, 1)))
|
(this_context = address6_valid(state->context, &req_addr, tagif, 1)))
|
||||||
@@ -1000,6 +1014,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
|||||||
|
|
||||||
if (preferred_time == 0)
|
if (preferred_time == 0)
|
||||||
message = _("deprecated");
|
message = _("deprecated");
|
||||||
|
|
||||||
|
address_assigned = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1023,9 +1039,17 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
|||||||
end_opt6(o);
|
end_opt6(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!address_assigned && msg_type == DHCP6REBIND)
|
||||||
|
{
|
||||||
|
/* can't create lease for any address, return error */
|
||||||
|
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||||
|
put_opt6_short(DHCP6NOADDRS);
|
||||||
|
put_opt6_string(_("no addresses available"));
|
||||||
|
end_opt6(o1);
|
||||||
|
}
|
||||||
|
|
||||||
tagif = add_options(state, 0);
|
tagif = add_options(state, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case DHCP6CONFIRM:
|
case DHCP6CONFIRM:
|
||||||
|
|||||||
+5
-20
@@ -76,42 +76,27 @@ static void ubus_disconnect_cb(struct ubus_context *ubus)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ubus_init()
|
char *ubus_init()
|
||||||
{
|
{
|
||||||
struct ubus_context *ubus = NULL;
|
struct ubus_context *ubus = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
ubus = ubus_connect(NULL);
|
if (!(ubus = ubus_connect(NULL)))
|
||||||
if (!ubus)
|
return NULL;
|
||||||
{
|
|
||||||
if (!error_logged)
|
|
||||||
{
|
|
||||||
my_syslog(LOG_ERR, _("Cannot initialize UBus: connection failed"));
|
|
||||||
error_logged = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ubus_destroy(ubus);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ubus_object.name = daemon->ubus_name;
|
ubus_object.name = daemon->ubus_name;
|
||||||
ret = ubus_add_object(ubus, &ubus_object);
|
ret = ubus_add_object(ubus, &ubus_object);
|
||||||
if (ret)
|
if (ret)
|
||||||
{
|
{
|
||||||
if (!error_logged)
|
|
||||||
{
|
|
||||||
my_syslog(LOG_ERR, _("Cannot add object to UBus: %s"), ubus_strerror(ret));
|
|
||||||
error_logged = 1;
|
|
||||||
}
|
|
||||||
ubus_destroy(ubus);
|
ubus_destroy(ubus);
|
||||||
return;
|
return ubus_strerror(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
ubus->connection_lost = ubus_disconnect_cb;
|
ubus->connection_lost = ubus_disconnect_cb;
|
||||||
daemon->ubus = ubus;
|
daemon->ubus = ubus;
|
||||||
error_logged = 0;
|
error_logged = 0;
|
||||||
|
|
||||||
my_syslog(LOG_INFO, _("Connected to system UBus"));
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_ubus_listeners()
|
void set_ubus_listeners()
|
||||||
|
|||||||
Reference in new issue
Block a user