Compare commits
57 Commits
v2.86test7
...
v2.87test3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed4e7defd7 | ||
|
|
267ab619c4 | ||
|
|
0140454ba2 | ||
|
|
2c60441239 | ||
|
|
cbbd56c965 | ||
|
|
2561f9fe0e | ||
|
|
47aefca5e4 | ||
|
|
981fb03710 | ||
|
|
ef2f8d70d2 | ||
|
|
d9995a1add | ||
|
|
ea7a05ad43 | ||
|
|
26bbf5a314 | ||
|
|
c147329823 | ||
|
|
eb88eed1fc | ||
|
|
8312a3ba4f | ||
|
|
35f93081dc | ||
|
|
de372d6914 | ||
|
|
4ac517e4ac | ||
|
|
e3651367b3 | ||
|
|
02ea41ddd1 | ||
|
|
51ffae4eab | ||
|
|
afe84f37f8 | ||
|
|
0afeef0e00 | ||
|
|
94a17fd97f | ||
|
|
5b5ec55445 | ||
|
|
1e6565c1a5 | ||
|
|
fc522515b9 | ||
|
|
9881b0736d | ||
|
|
e52b4b1466 | ||
|
|
2f45670951 | ||
|
|
50d75ae514 | ||
|
|
dea69a12aa | ||
|
|
e0ce3c12f2 | ||
|
|
93cf516bf1 | ||
|
|
6f4de018af | ||
|
|
6e91cf3172 | ||
|
|
9cb7f8a655 | ||
|
|
5d8d1ad14b | ||
|
|
cac9ca38f6 | ||
|
|
c4523639d5 | ||
|
|
1ce1c6beae | ||
|
|
51d56df7a3 | ||
|
|
860a9a57d6 | ||
|
|
c83e33d608 | ||
|
|
7b80c75d9d | ||
|
|
79337f99ae | ||
|
|
a42ee397f3 | ||
|
|
e58f8bb8c1 | ||
|
|
58cf958e41 | ||
|
|
06d01f7ae4 | ||
|
|
1a33eec0ba | ||
|
|
82de7a1e96 | ||
|
|
8e9bde57c5 | ||
|
|
1bb70e08be | ||
|
|
9afcb7ae61 | ||
|
|
545c4955e6 | ||
|
|
2f2d59b35c |
23
CHANGELOG
23
CHANGELOG
@@ -1,3 +1,14 @@
|
||||
version 2.87
|
||||
Allow arbitrary prefix lengths in --rev-server and
|
||||
--domain=....,local
|
||||
|
||||
Replace --address=/#/..... functionality which got
|
||||
missed in the 2.86 domain search rewrite.
|
||||
|
||||
Add --nftset option, like --ipset but for the newer nftables.
|
||||
Thanks to Chen Zhenge for the patch.
|
||||
|
||||
|
||||
version 2.86
|
||||
Handle DHCPREBIND requests in the DHCPv6 server code.
|
||||
Thanks to Aichun Li for spotting this omission, and the initial
|
||||
@@ -86,6 +97,15 @@ version 2.86
|
||||
conntrack is configured. Thanks to Yick Xie for spotting
|
||||
the lack of this.
|
||||
|
||||
When --dhcp-hostsfile --dhcp-optsfile and --addn-hosts are
|
||||
given a directory as argument, define the order in which
|
||||
files within that directory are read (alphabetical order
|
||||
of filename). Thanks to Ed Wildgoose for the initial patch
|
||||
and motivation for this.
|
||||
|
||||
Allow adding IP address to nftables set in addition to
|
||||
ipset.
|
||||
|
||||
|
||||
version 2.85
|
||||
Fix problem with DNS retries in 2.83/2.84.
|
||||
@@ -157,6 +177,9 @@ version 2.85
|
||||
Tweak TFTP code to check sender of all received packets, as
|
||||
specified in RFC 1350 para 4.
|
||||
|
||||
Support some wildcard matching of input tags to --tag-if.
|
||||
Thanks to Geoff Back for the idea and the patch.
|
||||
|
||||
|
||||
version 2.84
|
||||
Fix a problem, introduced in 2.83, which could see DNS replies
|
||||
|
||||
14
Makefile
14
Makefile
@@ -70,7 +70,9 @@ nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CO
|
||||
HAVE_NETTLEHASH $(PKG_CONFIG) --libs nettle`
|
||||
gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC NO_GMP --copy -lgmp`
|
||||
sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
|
||||
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
|
||||
nft_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_NFTSET $(PKG_CONFIG) --cflags libnftables`
|
||||
nft_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_NFTSET $(PKG_CONFIG) --libs libnftables`
|
||||
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
|
||||
|
||||
sum?=$(shell $(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' ')
|
||||
sum!=$(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' '
|
||||
@@ -82,7 +84,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 pattern.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 \
|
||||
metrics.o hash-questions.o domain-match.o
|
||||
metrics.o hash-questions.o domain-match.o nftset.o
|
||||
|
||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
dns-protocol.h radv-protocol.h ip6addr.h metrics.h
|
||||
@@ -90,8 +92,8 @@ hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
all : $(BUILDDIR)
|
||||
@cd $(BUILDDIR) && $(MAKE) \
|
||||
top="$(top)" \
|
||||
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
|
||||
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs)" \
|
||||
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags) $(nft_cflags)" \
|
||||
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs) $(nft_libs)" \
|
||||
-f $(top)/Makefile dnsmasq
|
||||
|
||||
mostly_clean :
|
||||
@@ -115,8 +117,8 @@ all-i18n : $(BUILDDIR)
|
||||
@cd $(BUILDDIR) && $(MAKE) \
|
||||
top="$(top)" \
|
||||
i18n=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
|
||||
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
|
||||
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs)" \
|
||||
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags) $(nft_cflags)" \
|
||||
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs) $(nft_libs)" \
|
||||
-f $(top)/Makefile dnsmasq
|
||||
for f in `cd $(PO); echo *.po`; do \
|
||||
cd $(top) && cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile $${f%.po}.mo; \
|
||||
|
||||
@@ -280,6 +280,7 @@ int main(int argc, char **argv)
|
||||
|
||||
/* This voodoo fakes up a packet coming from the correct interface, which really matters for
|
||||
a DHCP server */
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)-1);
|
||||
ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1)
|
||||
|
||||
@@ -318,6 +318,12 @@ void usage(const char* arg, FILE* stream)
|
||||
fprintf (stream, "Usage: %s %s\n", arg, usage_string);
|
||||
}
|
||||
|
||||
static void fail_fatal(const char *errstr, int exitcode)
|
||||
{
|
||||
perror(errstr);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
int send_release_packet(const char* iface, struct dhcp6_packet* packet)
|
||||
{
|
||||
struct sockaddr_in6 server_addr, client_addr;
|
||||
@@ -343,18 +349,19 @@ int send_release_packet(const char* iface, struct dhcp6_packet* packet)
|
||||
client_addr.sin6_port = htons(DHCP6_CLIENT_PORT);
|
||||
client_addr.sin6_flowinfo = 0;
|
||||
client_addr.sin6_scope_id =0;
|
||||
inet_pton(AF_INET6, "::", &client_addr.sin6_addr);
|
||||
bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6));
|
||||
inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr);
|
||||
if (inet_pton(AF_INET6, "::", &client_addr.sin6_addr) <= 0)
|
||||
fail_fatal("inet_pton", 5);
|
||||
if (bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6)) != 0)
|
||||
perror("bind"); /* continue on bind error */
|
||||
if (inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr) <= 0)
|
||||
fail_fatal("inet_pton", 5);
|
||||
server_addr.sin6_port = htons(DHCP6_SERVER_PORT);
|
||||
int16_t recv_size = 0;
|
||||
ssize_t recv_size = 0;
|
||||
int result;
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
if (sendto(sock, packet->buf, packet->len, 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
|
||||
{
|
||||
perror("sendto failed");
|
||||
exit(4);
|
||||
}
|
||||
fail_fatal("sendto failed", 4);
|
||||
|
||||
recv_size = recvfrom(sock, response, sizeof(response), MSG_DONTWAIT, NULL, 0);
|
||||
if (recv_size == -1)
|
||||
@@ -367,16 +374,18 @@ int send_release_packet(const char* iface, struct dhcp6_packet* packet)
|
||||
else
|
||||
{
|
||||
perror("recvfrom");
|
||||
result = UNSPEC_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t result = parse_packet(response, recv_size);
|
||||
if (result == NOT_REPLY_CODE)
|
||||
else
|
||||
{
|
||||
sleep(1);
|
||||
continue;
|
||||
result = parse_packet(response, recv_size);
|
||||
if (result == NOT_REPLY_CODE)
|
||||
{
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
close(sock);
|
||||
return result;
|
||||
}
|
||||
|
||||
7
debian/changelog
vendored
7
debian/changelog
vendored
@@ -1,3 +1,10 @@
|
||||
dnsmasq (2.87-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* Include new NFTset support in the build.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 08 Sep 2021 23:11:25 +0000
|
||||
|
||||
dnsmasq (2.86-1) unstable; urgency=low
|
||||
|
||||
* Fix debian/changelog format error. (closes: #986626)
|
||||
|
||||
2
debian/control
vendored
2
debian/control
vendored
@@ -5,7 +5,7 @@ Build-depends: gettext, libnetfilter-conntrack-dev [linux-any],
|
||||
libidn2-dev, libdbus-1-dev (>=0.61), libgmp-dev,
|
||||
nettle-dev (>=2.4-3), libbsd-dev [kfreebsd-any],
|
||||
liblua5.2-dev, dh-runit, debhelper-compat (= 10),
|
||||
pkg-config
|
||||
pkg-config, libnftables-dev
|
||||
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Homepage: http://www.thekelleys.org.uk/dnsmasq/doc.html
|
||||
Vcs-Git: http://thekelleys.org.uk/git/dnsmasq.git
|
||||
|
||||
1
debian/readme
vendored
1
debian/readme
vendored
@@ -60,6 +60,7 @@ Notes on configuring dnsmasq as packaged for Debian.
|
||||
nodbus : omit DBus support.
|
||||
noconntrack : omit connection tracking support.
|
||||
noipset : omit IPset support.
|
||||
nonftset : omit nftset support.
|
||||
nortc : compile alternate mode suitable for systems without an RTC.
|
||||
noi18n : omit translations and internationalisation support.
|
||||
noidn : omit international domain name support, must be
|
||||
|
||||
4
debian/rules
vendored
4
debian/rules
vendored
@@ -52,6 +52,10 @@ ifeq (,$(filter noidn, $(DEB_BUILD_OPTIONS)))
|
||||
DEB_COPTS += -DHAVE_LIBIDN2
|
||||
endif
|
||||
|
||||
ifeq (,$(filter nonftset, $(DEB_BUILD_OPTIONS)))
|
||||
DEB_COPTS += -DHAVE_NFTSET
|
||||
endif
|
||||
|
||||
ifeq (,$(filter noconntrack,$(DEB_BUILD_OPTIONS)))
|
||||
ifeq ($(DEB_HOST_ARCH_OS),linux)
|
||||
DEB_COPTS += -DHAVE_CONNTRACK
|
||||
|
||||
@@ -85,6 +85,16 @@
|
||||
# subdomains to the vpn and search ipsets:
|
||||
#ipset=/yahoo.com/google.com/vpn,search
|
||||
|
||||
# Add the IPs of all queries to yahoo.com, google.com, and their
|
||||
# subdomains to netfilters sets, which is equivalent to
|
||||
# 'nft add element ip test vpn { ... }; nft add element ip test search { ... }'
|
||||
#nftset=/yahoo.com/google.com/ip#test#vpn,ip#test#search
|
||||
|
||||
# Use netfilters sets for both IPv4 and IPv6:
|
||||
# This adds all addresses in *.yahoo.com to vpn4 and vpn6 for IPv4 and IPv6 addresses.
|
||||
#nftset=/yahoo.com/4#ip#test#vpn4
|
||||
#nftset=/yahoo.com/6#ip#test#vpn6
|
||||
|
||||
# You can control how dnsmasq talks to a server: this forces
|
||||
# queries to 10.1.2.3 to be routed via eth1
|
||||
# server=10.1.2.3@eth1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.TH DNSMASQ 8 2020-04-05
|
||||
.TH DNSMASQ 8 2021-08-16
|
||||
.SH NAME
|
||||
dnsmasq \- A lightweight DHCP and caching DNS server.
|
||||
.SH SYNOPSIS
|
||||
@@ -55,7 +55,8 @@ Don't read the hostnames in /etc/hosts.
|
||||
.B \-H, --addn-hosts=<file>
|
||||
Additional hosts file. Read the specified file as well as /etc/hosts. If \fB--no-hosts\fP is given, read
|
||||
only the specified file. This option may be repeated for more than one
|
||||
additional hosts file. If a directory is given, then read all the files contained in that directory.
|
||||
additional hosts file. If a directory is given, then read all the files contained in that directory
|
||||
in alphabetical order.
|
||||
.TP
|
||||
.B --hostsdir=<path>
|
||||
Read all the hosts files contained in the directory. New or changed files
|
||||
@@ -504,13 +505,14 @@ source address specified but the port may be specified directly as
|
||||
part of the source address. Forcing queries to an interface is not
|
||||
implemented on all platforms supported by dnsmasq.
|
||||
.TP
|
||||
.B --rev-server=<ip-address>/<prefix-len>[,<ipaddr>][#<port>][@<interface>][@<source-ip>[#<port>]]
|
||||
.B --rev-server=<ip-address>[/<prefix-len>][,<ipaddr>][#<port>][@<interface>][@<source-ip>[#<port>]]
|
||||
This is functionally the same as
|
||||
.B --server,
|
||||
but provides some syntactic sugar to make specifying address-to-name queries easier. For example
|
||||
.B --rev-server=1.2.3.0/24,192.168.0.1
|
||||
is exactly equivalent to
|
||||
.B --server=/3.2.1.in-addr.arpa/192.168.0.1
|
||||
Allowed prefix lengths are 1-32 (IPv4) and 1-128 (IPv6). If the prefix length is omitted, dnsmasq substitutes either 32 (IPv4) or 128 (IPv6).
|
||||
.TP
|
||||
.B \-A, --address=/<domain>[/<domain>...]/[<ipaddr>]
|
||||
Specify an IP address to return for any host in the given domains.
|
||||
@@ -548,6 +550,15 @@ These IP sets must already exist. See
|
||||
.BR ipset (8)
|
||||
for more details.
|
||||
.TP
|
||||
.B --nftset=/<domain>[/<domain>...]/[(6|4)#[<family>#]<table>#<set>[,[(6|4)#[<family>#]<table>#<set>]...]
|
||||
Similar to the \fB--ipset\fP option, but accepts one or more nftables
|
||||
sets to add IP addresses into.
|
||||
These sets must already exist. See
|
||||
.BR nft (8)
|
||||
for more details. The family, table and set are passed directly to the nft. If the spec starts with 4# or 6# then
|
||||
only A or AAAA records respectively are added to the set. Since an nftset can hold only IPv4 or IPv6 addresses, this
|
||||
avoids errors being logged for addresses of the wrong type.
|
||||
.TP
|
||||
.B --connmark-allowlist-enable[=<mask>]
|
||||
Enables filtering of incoming DNS queries with associated Linux connection track marks
|
||||
according to individual allowlists configured via a series of \fB--connmark-allowlist\fP
|
||||
@@ -905,7 +916,7 @@ compiled in and the kernel must have conntrack support
|
||||
included and configured. This option cannot be combined with
|
||||
.B --query-port.
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-addr>[,<end-addr>|<mode>][,<netmask>[,<broadcast>]][,<lease time>]
|
||||
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-addr>[,<end-addr>|<mode>[,<netmask>[,<broadcast>]]][,<lease time>]
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-IPv6addr>[,<end-IPv6addr>|constructor:<interface>][,<mode>][,<prefix-len>][,<lease time>]
|
||||
|
||||
@@ -1035,7 +1046,7 @@ is also included, as described in RFC-3775 section 7.3.
|
||||
tells dnsmasq to advertise the prefix without the on-link (aka L) bit set.
|
||||
|
||||
.TP
|
||||
.B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][tag:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
|
||||
.B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][,tag:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
|
||||
Specify per host parameters for the DHCP server. This allows a machine
|
||||
with a particular hardware address to be always allocated the same
|
||||
hostname, IP address and lease time. A hostname specified like this
|
||||
@@ -1134,7 +1145,10 @@ ignore requests from unknown machines using
|
||||
If the host matches only a \fB--dhcp-host\fP directive which cannot
|
||||
be used because it specifies an address on different subnet, the tag "known-othernet" is set.
|
||||
|
||||
The tag:<tag> construct filters which dhcp-host directives are used. Tagged directives are used in preference to untagged ones.
|
||||
The tag:<tag> construct filters which dhcp-host directives are used; more than
|
||||
one can be provided, in this case the request must match all of them. Tagged
|
||||
directives are used in preference to untagged ones. Note that one of <hwaddr>,
|
||||
<client_id> or <hostname> still needs to be specified (can be a wildcard).
|
||||
|
||||
Ethernet addresses (but not client-ids) may have
|
||||
wildcard bytes, so for example
|
||||
@@ -1165,7 +1179,7 @@ has both wired and wireless interfaces.
|
||||
.TP
|
||||
.B --dhcp-hostsfile=<path>
|
||||
Read DHCP host information from the specified file. If a directory
|
||||
is given, then read all the files contained in that directory. The file contains
|
||||
is given, then read all the files contained in that directory in alphabetical order. The file contains
|
||||
information about one host per line. The format of a line is the same
|
||||
as text to the right of '=' in \fB--dhcp-host\fP. The advantage of storing DHCP host information
|
||||
in this file is that it can be changed without re-starting dnsmasq:
|
||||
@@ -1173,7 +1187,7 @@ the file will be re-read when dnsmasq receives SIGHUP.
|
||||
.TP
|
||||
.B --dhcp-optsfile=<path>
|
||||
Read DHCP option information from the specified file. If a directory
|
||||
is given, then read all the files contained in that directory. The advantage of
|
||||
is given, then read all the files contained in that directory in alphabetical order. The advantage of
|
||||
using this option is the same as for \fB--dhcp-hostsfile\fP: the
|
||||
\fB--dhcp-optsfile\fP will be re-read when dnsmasq receives SIGHUP. Note that
|
||||
it is possible to encode the information in a
|
||||
@@ -1188,7 +1202,8 @@ directory, and not an individual file. Changed or new files within
|
||||
the directory are read automatically, without the need to send SIGHUP.
|
||||
If a file is deleted or changed after it has been read by dnsmasq, then the
|
||||
host record it contained will remain until dnsmasq receives a SIGHUP, or
|
||||
is restarted; ie host records are only added dynamically.
|
||||
is restarted; ie host records are only added dynamically. The order in which the
|
||||
files in a directory are read is not defined.
|
||||
.TP
|
||||
.B --dhcp-optsdir=<path>
|
||||
This is equivalent to \fB--dhcp-optsfile\fP, with the differences noted for \fB--dhcp-hostsdir\fP.
|
||||
@@ -1433,6 +1448,12 @@ Any number of set: and tag: forms may appear, in any order.
|
||||
tag set by another
|
||||
.B --tag-if,
|
||||
the line which sets the tag must precede the one which tests it.
|
||||
|
||||
As an extension, the tag:<tag> clauses support limited wildcard matching,
|
||||
similar to the matching in the \fB--interface\fP directive. This allows, for
|
||||
example, using \fB--tag-if=set:ppp,tag:ppp*\fP to set the tag 'ppp' for all requests
|
||||
received on any matching interface (ppp0, ppp1, etc). This can be used in conjunction
|
||||
with the tag:!<tag> format meaning that no tag matching the wildcard may be set.
|
||||
.TP
|
||||
.B \-J, --dhcp-ignore=tag:<tag>[,tag:<tag>]
|
||||
When all the given tags appear in the tag set ignore the host and do
|
||||
@@ -1915,7 +1936,6 @@ additional flag "local" may be supplied which has the effect of adding
|
||||
is identical to
|
||||
.B --domain=thekelleys.org.uk,192.168.0.0/24
|
||||
.B --local=/thekelleys.org.uk/ --local=/0.168.192.in-addr.arpa/
|
||||
The network size must be 8, 16 or 24 for this to be legal.
|
||||
.TP
|
||||
.B --dhcp-fqdn
|
||||
In the default mode, dnsmasq inserts the unqualified names of
|
||||
|
||||
1310
po/pt_BR.po
1310
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
50
src/auth.c
50
src/auth.c
@@ -210,7 +210,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (local_query || in_zone(zone, intr->name, NULL))
|
||||
{
|
||||
found = 1;
|
||||
log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
|
||||
log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL, 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
T_PTR, C_IN, "d", intr->name))
|
||||
@@ -234,7 +234,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
strcat(name, ".");
|
||||
strcat(name, zone->domain);
|
||||
}
|
||||
log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));
|
||||
log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid), 0);
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
@@ -243,7 +243,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
}
|
||||
else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL)))
|
||||
{
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid), 0);
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
@@ -257,7 +257,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
if (!found && is_rev_synth(flag, &addr, name) && (local_query || in_zone(zone, name, NULL)))
|
||||
{
|
||||
log_query(F_CONFIG | F_REVERSE | flag, name, &addr, NULL);
|
||||
log_query(F_CONFIG | F_REVERSE | flag, name, &addr, NULL, 0);
|
||||
found = 1;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
@@ -269,7 +269,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (found)
|
||||
nxdomain = 0;
|
||||
else
|
||||
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL);
|
||||
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL, 0);
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -300,7 +300,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (rc == 2 && qtype == T_MX)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>", 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_MX, C_IN, "sd", rec->weight, rec->target))
|
||||
anscount++;
|
||||
@@ -315,7 +315,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (rc == 2 && qtype == T_SRV)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>", 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_SRV, C_IN, "sssd",
|
||||
rec->priority, rec->weight, rec->srvport, rec->target))
|
||||
@@ -349,7 +349,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (rc == 2 && txt->class == qtype)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, querystr(NULL, txt->class));
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, NULL, txt->class);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, txt->class, C_IN, "t", txt->len, txt->txt))
|
||||
anscount++;
|
||||
@@ -363,7 +363,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (rc == 2 && qtype == T_TXT)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>", 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_TXT, C_IN, "t", txt->len, txt->txt))
|
||||
anscount++;
|
||||
@@ -377,7 +377,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (rc == 2 && qtype == T_NAPTR)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>", 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_NAPTR, C_IN, "sszzzd",
|
||||
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
|
||||
@@ -407,7 +407,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
continue;
|
||||
|
||||
found = 1;
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL, 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
qtype == T_A ? "4" : "6", &addrlist->addr))
|
||||
@@ -417,10 +417,9 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
if (!found && is_name_synthetic(flag, name, &addr) )
|
||||
{
|
||||
found = 1;
|
||||
nxdomain = 0;
|
||||
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL, 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN, qtype == T_A ? "4" : "6", &addr))
|
||||
anscount++;
|
||||
@@ -433,8 +432,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (qtype == T_SOA)
|
||||
{
|
||||
auth = soa = 1; /* inhibits auth section */
|
||||
found = 1;
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>", 0);
|
||||
}
|
||||
else if (qtype == T_AXFR)
|
||||
{
|
||||
@@ -469,16 +467,14 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
soa = 1; /* inhibits auth section */
|
||||
ns = 1; /* ensure we include NS records! */
|
||||
axfr = 1;
|
||||
found = 1;
|
||||
axfroffset = nameoffset;
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>");
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>", 0);
|
||||
}
|
||||
else if (qtype == T_NS)
|
||||
{
|
||||
auth = 1;
|
||||
ns = 1; /* inhibits auth section */
|
||||
found = 1;
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>", 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -496,9 +492,8 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
(local_query || filter_zone(zone, flag, &(crecp->addr))))
|
||||
{
|
||||
*cut = '.'; /* restore domain part */
|
||||
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid));
|
||||
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
|
||||
*cut = 0; /* remove domain part */
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
qtype == T_A ? "4" : "6", &crecp->addr))
|
||||
@@ -518,8 +513,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
nxdomain = 0;
|
||||
if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr))))
|
||||
{
|
||||
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid));
|
||||
found = 1;
|
||||
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
qtype == T_A ? "4" : "6", &crecp->addr))
|
||||
@@ -566,7 +560,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
if (candidate)
|
||||
{
|
||||
log_query(F_CONFIG | F_CNAME, name, NULL, NULL);
|
||||
log_query(F_CONFIG | F_CNAME, name, NULL, NULL, 0);
|
||||
strcpy(name, candidate->target);
|
||||
if (!strchr(name, '.'))
|
||||
{
|
||||
@@ -584,7 +578,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
else if (cache_find_non_terminal(name, now))
|
||||
nxdomain = 0;
|
||||
|
||||
log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);
|
||||
log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -614,7 +608,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (subnet->prefixlen >= 16 )
|
||||
p += sprintf(p, "%u.", a & 0xff);
|
||||
a = a >> 8;
|
||||
p += sprintf(p, "%u.in-addr.arpa", a & 0xff);
|
||||
sprintf(p, "%u.in-addr.arpa", a & 0xff);
|
||||
|
||||
}
|
||||
else
|
||||
@@ -627,7 +621,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
int dig = ((unsigned char *)&subnet->addr.addr6)[i>>3];
|
||||
p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
|
||||
}
|
||||
p += sprintf(p, "ip6.arpa");
|
||||
sprintf(p, "ip6.arpa");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -892,7 +886,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
header->nscount = htons(0);
|
||||
addr.log.rcode = REFUSED;
|
||||
addr.log.ede = EDE_NOT_AUTH;
|
||||
log_query(F_UPSTREAM | F_RCODE, "error", &addr, NULL);
|
||||
log_query(F_UPSTREAM | F_RCODE, "error", &addr, NULL, 0);
|
||||
return resize_packet(header, ansp - (unsigned char *)header, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ void blockdata_init(void)
|
||||
|
||||
void blockdata_report(void)
|
||||
{
|
||||
my_syslog(LOG_INFO, _("pool memory in use %u, max %u, allocated %u"),
|
||||
my_syslog(LOG_INFO, _("pool memory in use %zu, max %zu, allocated %zu"),
|
||||
blockdata_count * sizeof(struct blockdata),
|
||||
blockdata_hwm * sizeof(struct blockdata),
|
||||
blockdata_alloced * sizeof(struct blockdata));
|
||||
|
||||
167
src/cache.c
167
src/cache.c
@@ -30,50 +30,100 @@ static struct crec *really_insert(char *name, union all_addr *addr, unsigned sho
|
||||
time_t now, unsigned long ttl, unsigned int flags);
|
||||
|
||||
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
|
||||
/* taken from https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml */
|
||||
static const struct {
|
||||
unsigned int type;
|
||||
const char * const name;
|
||||
} typestr[] = {
|
||||
{ 1, "A" },
|
||||
{ 2, "NS" },
|
||||
{ 5, "CNAME" },
|
||||
{ 6, "SOA" },
|
||||
{ 10, "NULL" },
|
||||
{ 11, "WKS" },
|
||||
{ 12, "PTR" },
|
||||
{ 13, "HINFO" },
|
||||
{ 15, "MX" },
|
||||
{ 16, "TXT" },
|
||||
{ 22, "NSAP" },
|
||||
{ 23, "NSAP_PTR" },
|
||||
{ 24, "SIG" },
|
||||
{ 25, "KEY" },
|
||||
{ 28, "AAAA" },
|
||||
{ 29, "LOC" },
|
||||
{ 33, "SRV" },
|
||||
{ 35, "NAPTR" },
|
||||
{ 36, "KX" },
|
||||
{ 37, "CERT" },
|
||||
{ 38, "A6" },
|
||||
{ 39, "DNAME" },
|
||||
{ 41, "OPT" },
|
||||
{ 43, "DS" },
|
||||
{ 46, "RRSIG" },
|
||||
{ 47, "NSEC" },
|
||||
{ 48, "DNSKEY" },
|
||||
{ 50, "NSEC3" },
|
||||
{ 51, "NSEC3PARAM" },
|
||||
{ 52, "TLSA" },
|
||||
{ 53, "SMIMEA" },
|
||||
{ 55, "HIP" },
|
||||
{ 249, "TKEY" },
|
||||
{ 250, "TSIG" },
|
||||
{ 251, "IXFR" },
|
||||
{ 252, "AXFR" },
|
||||
{ 253, "MAILB" },
|
||||
{ 254, "MAILA" },
|
||||
{ 255, "ANY" },
|
||||
{ 257, "CAA" }
|
||||
{ 1, "A" }, /* a host address [RFC1035] */
|
||||
{ 2, "NS" }, /* an authoritative name server [RFC1035] */
|
||||
{ 3, "MD" }, /* a mail destination (OBSOLETE - use MX) [RFC1035] */
|
||||
{ 4, "MF" }, /* a mail forwarder (OBSOLETE - use MX) [RFC1035] */
|
||||
{ 5, "CNAME" }, /* the canonical name for an alias [RFC1035] */
|
||||
{ 6, "SOA" }, /* marks the start of a zone of authority [RFC1035] */
|
||||
{ 7, "MB" }, /* a mailbox domain name (EXPERIMENTAL) [RFC1035] */
|
||||
{ 8, "MG" }, /* a mail group member (EXPERIMENTAL) [RFC1035] */
|
||||
{ 9, "MR" }, /* a mail rename domain name (EXPERIMENTAL) [RFC1035] */
|
||||
{ 10, "NULL" }, /* a null RR (EXPERIMENTAL) [RFC1035] */
|
||||
{ 11, "WKS" }, /* a well known service description [RFC1035] */
|
||||
{ 12, "PTR" }, /* a domain name pointer [RFC1035] */
|
||||
{ 13, "HINFO" }, /* host information [RFC1035] */
|
||||
{ 14, "MINFO" }, /* mailbox or mail list information [RFC1035] */
|
||||
{ 15, "MX" }, /* mail exchange [RFC1035] */
|
||||
{ 16, "TXT" }, /* text strings [RFC1035] */
|
||||
{ 17, "RP" }, /* for Responsible Person [RFC1183] */
|
||||
{ 18, "AFSDB" }, /* for AFS Data Base location [RFC1183][RFC5864] */
|
||||
{ 19, "X25" }, /* for X.25 PSDN address [RFC1183] */
|
||||
{ 20, "ISDN" }, /* for ISDN address [RFC1183] */
|
||||
{ 21, "RT" }, /* for Route Through [RFC1183] */
|
||||
{ 22, "NSAP" }, /* for NSAP address, NSAP style A record [RFC1706] */
|
||||
{ 23, "NSAP_PTR" }, /* for domain name pointer, NSAP style [RFC1348][RFC1637][RFC1706] */
|
||||
{ 24, "SIG" }, /* for security signature [RFC2535][RFC2536][RFC2537][RFC2931][RFC3008][RFC3110][RFC3755][RFC4034] */
|
||||
{ 25, "KEY" }, /* for security key [RFC2535][RFC2536][RFC2537][RFC2539][RFC3008][RFC3110][RFC3755][RFC4034] */
|
||||
{ 26, "PX" }, /* X.400 mail mapping information [RFC2163] */
|
||||
{ 27, "GPOS" }, /* Geographical Position [RFC1712] */
|
||||
{ 28, "AAAA" }, /* IP6 Address [RFC3596] */
|
||||
{ 29, "LOC" }, /* Location Information [RFC1876] */
|
||||
{ 30, "NXT" }, /* Next Domain (OBSOLETE) [RFC2535][RFC3755] */
|
||||
{ 31, "EID" }, /* Endpoint Identifier [Michael_Patton][http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt] 1995-06*/
|
||||
{ 32, "NIMLOC" }, /* Nimrod Locator [1][Michael_Patton][http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt] 1995-06*/
|
||||
{ 33, "SRV" }, /* Server Selection [1][RFC2782] */
|
||||
{ 34, "ATMA" }, /* ATM Address [ ATM Forum Technical Committee, "ATM Name System, V2.0", Doc ID: AF-DANS-0152.000, July 2000. Available from and held in escrow by IANA.] */
|
||||
{ 35, "NAPTR" }, /* Naming Authority Pointer [RFC2168][RFC2915][RFC3403] */
|
||||
{ 36, "KX" }, /* Key Exchanger [RFC2230] */
|
||||
{ 37, "CERT" }, /* CERT [RFC4398] */
|
||||
{ 38, "A6" }, /* A6 (OBSOLETE - use AAAA) [RFC2874][RFC3226][RFC6563] */
|
||||
{ 39, "DNAME" }, /* DNAME [RFC6672] */
|
||||
{ 40, "SINK" }, /* SINK [Donald_E_Eastlake][http://tools.ietf.org/html/draft-eastlake-kitchen-sink] 1997-11*/
|
||||
{ 41, "OPT" }, /* OPT [RFC3225][RFC6891] */
|
||||
{ 42, "APL" }, /* APL [RFC3123] */
|
||||
{ 43, "DS" }, /* Delegation Signer [RFC3658][RFC4034] */
|
||||
{ 44, "SSHFP" }, /* SSH Key Fingerprint [RFC4255] */
|
||||
{ 45, "IPSECKEY" }, /* IPSECKEY [RFC4025] */
|
||||
{ 46, "RRSIG" }, /* RRSIG [RFC3755][RFC4034] */
|
||||
{ 47, "NSEC" }, /* NSEC [RFC3755][RFC4034][RFC9077] */
|
||||
{ 48, "DNSKEY" }, /* DNSKEY [RFC3755][RFC4034] */
|
||||
{ 49, "DHCID" }, /* DHCID [RFC4701] */
|
||||
{ 50, "NSEC3" }, /* NSEC3 [RFC5155][RFC9077] */
|
||||
{ 51, "NSEC3PARAM" }, /* NSEC3PARAM [RFC5155] */
|
||||
{ 52, "TLSA" }, /* TLSA [RFC6698] */
|
||||
{ 53, "SMIMEA" }, /* S/MIME cert association [RFC8162] SMIMEA/smimea-completed-template 2015-12-01*/
|
||||
{ 55, "HIP" }, /* Host Identity Protocol [RFC8005] */
|
||||
{ 56, "NINFO" }, /* NINFO [Jim_Reid] NINFO/ninfo-completed-template 2008-01-21*/
|
||||
{ 57, "RKEY" }, /* RKEY [Jim_Reid] RKEY/rkey-completed-template 2008-01-21*/
|
||||
{ 58, "TALINK" }, /* Trust Anchor LINK [Wouter_Wijngaards] TALINK/talink-completed-template 2010-02-17*/
|
||||
{ 59, "CDS" }, /* Child DS [RFC7344] CDS/cds-completed-template 2011-06-06*/
|
||||
{ 60, "CDNSKEY" }, /* DNSKEY(s) the Child wants reflected in DS [RFC7344] 2014-06-16*/
|
||||
{ 61, "OPENPGPKEY" }, /* OpenPGP Key [RFC7929] OPENPGPKEY/openpgpkey-completed-template 2014-08-12*/
|
||||
{ 62, "CSYNC" }, /* Child-To-Parent Synchronization [RFC7477] 2015-01-27*/
|
||||
{ 63, "ZONEMD" }, /* Message Digest Over Zone Data [RFC8976] ZONEMD/zonemd-completed-template 2018-12-12*/
|
||||
{ 64, "SVCB" }, /* Service Binding [draft-ietf-dnsop-svcb-https-00] SVCB/svcb-completed-template 2020-06-30*/
|
||||
{ 65, "HTTPS" }, /* HTTPS Binding [draft-ietf-dnsop-svcb-https-00] HTTPS/https-completed-template 2020-06-30*/
|
||||
{ 99, "SPF" }, /* [RFC7208] */
|
||||
{ 100, "UINFO" }, /* [IANA-Reserved] */
|
||||
{ 101, "UID" }, /* [IANA-Reserved] */
|
||||
{ 102, "GID" }, /* [IANA-Reserved] */
|
||||
{ 103, "UNSPEC" }, /* [IANA-Reserved] */
|
||||
{ 104, "NID" }, /* [RFC6742] ILNP/nid-completed-template */
|
||||
{ 105, "L32" }, /* [RFC6742] ILNP/l32-completed-template */
|
||||
{ 106, "L64" }, /* [RFC6742] ILNP/l64-completed-template */
|
||||
{ 107, "LP" }, /* [RFC6742] ILNP/lp-completed-template */
|
||||
{ 108, "EUI48" }, /* an EUI-48 address [RFC7043] EUI48/eui48-completed-template 2013-03-27*/
|
||||
{ 109, "EUI64" }, /* an EUI-64 address [RFC7043] EUI64/eui64-completed-template 2013-03-27*/
|
||||
{ 249, "TKEY" }, /* Transaction Key [RFC2930] */
|
||||
{ 250, "TSIG" }, /* Transaction Signature [RFC8945] */
|
||||
{ 251, "IXFR" }, /* incremental transfer [RFC1995] */
|
||||
{ 252, "AXFR" }, /* transfer of an entire zone [RFC1035][RFC5936] */
|
||||
{ 253, "MAILB" }, /* mailbox-related RRs (MB, MG or MR) [RFC1035] */
|
||||
{ 254, "MAILA" }, /* mail agent RRs (OBSOLETE - see MX) [RFC1035] */
|
||||
{ 255, "ANY" }, /* A request for some or all records the server has available [RFC1035][RFC6895][RFC8482] */
|
||||
{ 256, "URI" }, /* URI [RFC7553] URI/uri-completed-template 2011-02-22*/
|
||||
{ 257, "CAA" }, /* Certification Authority Restriction [RFC8659] CAA/caa-completed-template 2011-04-07*/
|
||||
{ 258, "AVC" }, /* Application Visibility and Control [Wolfgang_Riedel] AVC/avc-completed-template 2016-02-26*/
|
||||
{ 259, "DOA" }, /* Digital Object Architecture [draft-durand-doa-over-dns] DOA/doa-completed-template 2017-08-30*/
|
||||
{ 260, "AMTRELAY" }, /* Automatic Multicast Tunneling Relay [RFC8777] AMTRELAY/amtrelay-completed-template 2019-02-06*/
|
||||
{ 32768, "TA" }, /* DNSSEC Trust Authorities [Sam_Weiler][http://cameo.library.cmu.edu/][ Deploying DNSSEC Without a Signed Root. Technical Report 1999-19, Information Networking Institute, Carnegie Mellon University, April 2004.] 2005-12-13*/
|
||||
{ 32769, "DLV" }, /* DNSSEC Lookaside Validation (OBSOLETE) [RFC8749][RFC4431] */
|
||||
};
|
||||
|
||||
static void cache_free(struct crec *crecp);
|
||||
@@ -433,7 +483,7 @@ static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned s
|
||||
else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
|
||||
(flags & crecp->flags & F_REVERSE) &&
|
||||
(flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
|
||||
memcmp(&crecp->addr, addr, addrlen) == 0)
|
||||
addr && memcmp(&crecp->addr, addr, addrlen) == 0)
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
cache_unlink(crecp);
|
||||
@@ -488,8 +538,6 @@ struct crec *cache_insert(char *name, union all_addr *addr, unsigned short class
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Don't log DNSSEC records here, done elsewhere */
|
||||
log_query(flags | F_UPSTREAM, name, addr, NULL);
|
||||
if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
|
||||
ttl = daemon->max_cache_ttl;
|
||||
if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
|
||||
@@ -1549,7 +1597,8 @@ static void make_non_terminals(struct crec *source)
|
||||
if (crecp)
|
||||
{
|
||||
crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_SRV | F_DNSKEY | F_DS | F_REVERSE);
|
||||
crecp->ttd = source->ttd;
|
||||
if (!(crecp->flags & F_IMMORTAL))
|
||||
crecp->ttd = source->ttd;
|
||||
crecp->name.namep = name;
|
||||
|
||||
cache_hash(crecp);
|
||||
@@ -1807,7 +1856,7 @@ char *record_source(unsigned int index)
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
char *querystr(char *desc, unsigned short type)
|
||||
static char *querystr(char *desc, unsigned short type)
|
||||
{
|
||||
unsigned int i;
|
||||
int len = 10; /* strlen("type=xxxxx") */
|
||||
@@ -1855,7 +1904,7 @@ char *querystr(char *desc, unsigned short type)
|
||||
if (types)
|
||||
sprintf(buff, "<%s>", types);
|
||||
else
|
||||
sprintf(buff, "type=%d", type);
|
||||
sprintf(buff, "<type=%d>", type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1895,19 +1944,30 @@ static char *edestr(int ede)
|
||||
}
|
||||
}
|
||||
|
||||
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg, unsigned short type)
|
||||
{
|
||||
char *source, *dest = daemon->addrbuff;
|
||||
char *source, *dest = arg;
|
||||
char *verb = "is";
|
||||
char *extra = "";
|
||||
|
||||
if (!option_bool(OPT_LOG))
|
||||
return;
|
||||
|
||||
/* build query type string if requested */
|
||||
if(type > 0)
|
||||
arg = querystr(arg, type);
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if ((flags & F_DNSSECOK) && option_bool(OPT_EXTRALOG))
|
||||
extra = " (DNSSEC signed)";
|
||||
#endif
|
||||
|
||||
name = sanitise(name);
|
||||
|
||||
if (addr)
|
||||
{
|
||||
dest = daemon->addrbuff;
|
||||
|
||||
if (flags & F_KEYTAG)
|
||||
sprintf(daemon->addrbuff, arg, addr->log.keytag, addr->log.algo, addr->log.digest);
|
||||
else if (flags & F_RCODE)
|
||||
@@ -1929,13 +1989,12 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||
sprintf(extra, " (EDE: %s)", edestr(addr->log.ede));
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (flags & (F_IPV4 | F_IPV6))
|
||||
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
||||
addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
|
||||
else
|
||||
dest = arg;
|
||||
}
|
||||
else
|
||||
dest = arg;
|
||||
|
||||
if (flags & F_REVERSE)
|
||||
{
|
||||
@@ -2001,7 +2060,7 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||
}
|
||||
else if (flags & F_IPSET)
|
||||
{
|
||||
source = "ipset add";
|
||||
source = type ? "ipset add" : "nftset add";
|
||||
dest = name;
|
||||
name = arg;
|
||||
verb = daemon->addrbuff;
|
||||
@@ -2009,7 +2068,7 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||
else
|
||||
source = "cached";
|
||||
|
||||
if (strlen(name) == 0)
|
||||
if (name && !name[0])
|
||||
name = ".";
|
||||
|
||||
if (option_bool(OPT_EXTRALOG))
|
||||
|
||||
10
src/config.h
10
src/config.h
@@ -115,6 +115,10 @@ HAVE_IPSET
|
||||
define this to include the ability to selectively add resolved ip addresses
|
||||
to given ipsets.
|
||||
|
||||
HAVE_NFTSET
|
||||
define this to include the ability to selectively add resolved ip addresses
|
||||
to given nftables sets.
|
||||
|
||||
HAVE_AUTH
|
||||
define this to include the facility to act as an authoritative DNS
|
||||
server for one or more zones.
|
||||
@@ -192,7 +196,7 @@ RESOLVFILE
|
||||
/* #define HAVE_CONNTRACK */
|
||||
/* #define HAVE_CRYPTOHASH */
|
||||
/* #define HAVE_DNSSEC */
|
||||
|
||||
/* #define HAVE_NFTSET */
|
||||
|
||||
/* Default locations for important system files. */
|
||||
|
||||
@@ -420,6 +424,10 @@ static char *compile_opts =
|
||||
"no-"
|
||||
#endif
|
||||
"ipset "
|
||||
#ifndef HAVE_NFTSET
|
||||
"no-"
|
||||
#endif
|
||||
"nftset "
|
||||
#ifndef HAVE_AUTH
|
||||
"no-"
|
||||
#endif
|
||||
|
||||
21
src/dbus.c
21
src/dbus.c
@@ -114,7 +114,7 @@ static dbus_bool_t add_watch(DBusWatch *watch, void *data)
|
||||
w->next = daemon->watches;
|
||||
daemon->watches = w;
|
||||
|
||||
w = data; /* no warning */
|
||||
(void)data; /* no warning */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -134,16 +134,20 @@ static void remove_watch(DBusWatch *watch, void *data)
|
||||
up = &(w->next);
|
||||
}
|
||||
|
||||
w = data; /* no warning */
|
||||
(void)data; /* no warning */
|
||||
}
|
||||
|
||||
static void dbus_read_servers(DBusMessage *message)
|
||||
static DBusMessage* dbus_read_servers(DBusMessage *message)
|
||||
{
|
||||
DBusMessageIter iter;
|
||||
union mysockaddr addr, source_addr;
|
||||
char *domain;
|
||||
|
||||
dbus_message_iter_init(message, &iter);
|
||||
if (!dbus_message_iter_init(message, &iter))
|
||||
{
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Failed to initialize dbus message iter");
|
||||
}
|
||||
|
||||
mark_servers(SERV_FROM_DBUS);
|
||||
|
||||
@@ -222,6 +226,7 @@ static void dbus_read_servers(DBusMessage *message)
|
||||
|
||||
/* unlink and free anything still marked. */
|
||||
cleanup_servers();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LOOP
|
||||
@@ -545,6 +550,10 @@ static DBusMessage *dbus_add_lease(DBusMessage* message)
|
||||
"Invalid IP address '%s'", ipaddr);
|
||||
|
||||
hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL, &hw_type);
|
||||
if (hw_len < 0)
|
||||
return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid HW address '%s'", hwaddr);
|
||||
|
||||
if (hw_type == 0 && hw_len != 0)
|
||||
hw_type = ARPHRD_ETHER;
|
||||
|
||||
@@ -668,7 +677,7 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
#endif
|
||||
else if (strcmp(method, "SetServers") == 0)
|
||||
{
|
||||
dbus_read_servers(message);
|
||||
reply = dbus_read_servers(message);
|
||||
new_servers = 1;
|
||||
}
|
||||
else if (strcmp(method, "SetServersEx") == 0)
|
||||
@@ -719,7 +728,7 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
if (clear_cache)
|
||||
clear_cache_and_reload(dnsmasq_time());
|
||||
|
||||
method = user_data; /* no warning */
|
||||
(void)user_data; /* no warning */
|
||||
|
||||
/* If no reply or no error, return nothing */
|
||||
if (!reply)
|
||||
|
||||
@@ -79,13 +79,46 @@ ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
|
||||
return (msg->msg_flags & MSG_TRUNC) ? -1 : new_sz;
|
||||
}
|
||||
|
||||
/* like match_netid() except that the check can have a trailing * for wildcard */
|
||||
/* started as a direct copy of match_netid() */
|
||||
int match_netid_wild(struct dhcp_netid *check, struct dhcp_netid *pool)
|
||||
{
|
||||
struct dhcp_netid *tmp1;
|
||||
|
||||
for (; check; check = check->next)
|
||||
{
|
||||
const int check_len = strlen(check->net);
|
||||
const int is_wc = (check_len > 0 && check->net[check_len - 1] == '*');
|
||||
|
||||
/* '#' for not is for backwards compat. */
|
||||
if (check->net[0] != '!' && check->net[0] != '#')
|
||||
{
|
||||
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
||||
if (is_wc ? (strncmp(check->net, tmp1->net, check_len-1) == 0) :
|
||||
(strcmp(check->net, tmp1->net) == 0))
|
||||
break;
|
||||
if (!tmp1)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
||||
if (is_wc ? (strncmp((check->net)+1, tmp1->net, check_len-2) == 0) :
|
||||
(strcmp((check->net)+1, tmp1->net) == 0))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
|
||||
{
|
||||
struct tag_if *exprs;
|
||||
struct dhcp_netid_list *list;
|
||||
|
||||
/* this now uses match_netid_wild() above so that tag_if can
|
||||
* be used to set a 'group of interfaces' tag.
|
||||
*/
|
||||
for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
|
||||
if (match_netid(exprs->tag, tags, 1))
|
||||
if (match_netid_wild(exprs->tag, tags))
|
||||
for (list = exprs->set; list; list = list->next)
|
||||
{
|
||||
list->list->next = tags;
|
||||
@@ -620,6 +653,8 @@ static const struct opttab_t {
|
||||
{ "client-arch", 93, 2 | OT_DEC },
|
||||
{ "client-interface-id", 94, 0 },
|
||||
{ "client-machine-id", 97, 0 },
|
||||
{ "posix-timezone", 100, OT_NAME }, /* RFC 4833, Sec. 2 */
|
||||
{ "tzdb-timezone", 101, OT_NAME }, /* RFC 4833, Sec. 2 */
|
||||
{ "subnet-select", 118, OT_INTERNAL },
|
||||
{ "domain-search", 119, OT_RFC1035_NAME },
|
||||
{ "sip-server", 120, 0 },
|
||||
|
||||
@@ -292,7 +292,7 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsi
|
||||
if ((maclen = find_mac(&addr, mac, 0, now)) != 0)
|
||||
break;
|
||||
|
||||
sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr));
|
||||
while(retry_send(sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr))));
|
||||
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 100000000; /* 100ms */
|
||||
|
||||
@@ -34,7 +34,6 @@ static void poll_resolv(int force, int do_reload, time_t now);
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
int bind_fallback = 0;
|
||||
time_t now;
|
||||
struct sigaction sigact;
|
||||
struct iname *if_tmp;
|
||||
@@ -59,6 +58,8 @@ int main (int argc, char **argv)
|
||||
int did_bind = 0;
|
||||
struct server *serv;
|
||||
char *netlink_warn;
|
||||
#else
|
||||
int bind_fallback = 0;
|
||||
#endif
|
||||
#if defined(HAVE_DHCP) || defined(HAVE_DHCP6)
|
||||
struct dhcp_context *context;
|
||||
@@ -345,6 +346,16 @@ int main (int argc, char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NFTSET
|
||||
if (daemon->nftsets)
|
||||
{
|
||||
nftset_init();
|
||||
# ifdef HAVE_LINUX_NETWORK
|
||||
need_cap_net_admin = 1;
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
netlink_warn = netlink_init();
|
||||
#elif defined(HAVE_BSD_NETWORK)
|
||||
@@ -377,7 +388,7 @@ int main (int argc, char **argv)
|
||||
bindtodevice(bound_device, daemon->dhcpfd);
|
||||
did_bind = 1;
|
||||
}
|
||||
if (daemon->enable_pxe && bound_device)
|
||||
if (daemon->enable_pxe && bound_device && daemon->pxefd != -1)
|
||||
{
|
||||
bindtodevice(bound_device, daemon->pxefd);
|
||||
did_bind = 1;
|
||||
@@ -920,8 +931,10 @@ int main (int argc, char **argv)
|
||||
my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
|
||||
daemon->log_file, strerror(log_err));
|
||||
|
||||
#ifndef HAVE_LINUX_NETWORK
|
||||
if (bind_fallback)
|
||||
my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
|
||||
#endif
|
||||
|
||||
if (option_bool(OPT_NOWILD))
|
||||
warn_bound_listeners();
|
||||
@@ -1575,7 +1588,7 @@ static void async_event(int pipe, time_t now)
|
||||
{
|
||||
/* block in writes until all done */
|
||||
if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
|
||||
fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
|
||||
while(retry_send(fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK)));
|
||||
do {
|
||||
helper_write();
|
||||
} while (!helper_buf_empty() || do_script_run(now));
|
||||
@@ -1984,7 +1997,7 @@ static void check_dns_listeners(time_t now)
|
||||
attribute from the listening socket.
|
||||
Reset that here. */
|
||||
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
||||
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
while(retry_send(fcntl(confd, F_SETFL, flags & ~O_NONBLOCK)));
|
||||
|
||||
buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
|
||||
|
||||
|
||||
@@ -530,23 +530,23 @@ union mysockaddr {
|
||||
|
||||
|
||||
/* The actual values here matter, since we sort on them to get records in the order
|
||||
IPv6 addr, IPv4 addr, all zero return, no-data return, send upstream. */
|
||||
#define SERV_LITERAL_ADDRESS 1 /* addr is the answer, or NoDATA is the answer, depending on the next three flags */
|
||||
#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_FOR_NODOTS 32 /* server for names with no domain part only */
|
||||
#define SERV_WARNED_RECURSIVE 64 /* avoid warning spam */
|
||||
#define SERV_FROM_DBUS 128 /* 1 if source is DBus */
|
||||
#define SERV_MARK 256 /* for mark-and-delete and log code */
|
||||
#define SERV_WILDCARD 512 /* domain has leading '*' */
|
||||
#define SERV_USE_RESOLV 1024 /* forward this domain in the normal way */
|
||||
#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_LOOP 8192 /* server causes forwarding loop */
|
||||
#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */
|
||||
#define SERV_GOT_TCP 32768 /* Got some data from the TCP connection */
|
||||
IPv6 addr, IPv4 addr, all zero return, resolvconf servers, upstream server, no-data return */
|
||||
#define SERV_LITERAL_ADDRESS 1 /* addr is the answer, or NoDATA is the answer, depending on the next four flags */
|
||||
#define SERV_USE_RESOLV 2 /* forward this domain in the normal way */
|
||||
#define SERV_ALL_ZEROS 4 /* return all zeros for A and AAAA */
|
||||
#define SERV_4ADDR 8 /* addr is IPv4 */
|
||||
#define SERV_6ADDR 16 /* addr is IPv6 */
|
||||
#define SERV_HAS_SOURCE 32 /* source address defined */
|
||||
#define SERV_FOR_NODOTS 64 /* server for names with no domain part only */
|
||||
#define SERV_WARNED_RECURSIVE 128 /* avoid warning spam */
|
||||
#define SERV_FROM_DBUS 256 /* 1 if source is DBus */
|
||||
#define SERV_MARK 512 /* for mark-and-delete and log code */
|
||||
#define SERV_WILDCARD 1024 /* domain has leading '*' */
|
||||
#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_LOOP 8192 /* server causes forwarding loop */
|
||||
#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */
|
||||
#define SERV_GOT_TCP 32768 /* Got some data from the TCP connection */
|
||||
|
||||
struct serverfd {
|
||||
int fd;
|
||||
@@ -609,6 +609,11 @@ struct serv_local {
|
||||
struct server *next;
|
||||
};
|
||||
|
||||
struct rebind_domain {
|
||||
char *domain;
|
||||
struct rebind_domain *next;
|
||||
};
|
||||
|
||||
struct ipsets {
|
||||
char **sets;
|
||||
char *domain;
|
||||
@@ -1105,10 +1110,11 @@ extern struct daemon {
|
||||
char *lease_change_command;
|
||||
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
|
||||
struct bogus_addr *bogus_addr, *ignore_addr;
|
||||
struct server *servers, *local_domains, **serverarray, *no_rebind;
|
||||
struct server *servers, *servers_tail, *local_domains, **serverarray;
|
||||
struct rebind_domain *no_rebind;
|
||||
int server_has_wildcard;
|
||||
int serverarraysz, serverarrayhwm;
|
||||
struct ipsets *ipsets;
|
||||
struct ipsets *ipsets, *nftsets;
|
||||
u32 allowlist_mask;
|
||||
struct allowlist *allowlists;
|
||||
int log_fac; /* log facility */
|
||||
@@ -1167,9 +1173,12 @@ extern struct daemon {
|
||||
char *packet; /* packet buffer */
|
||||
int packet_buff_sz; /* size of above */
|
||||
char *namebuff; /* MAXDNAME size buffer */
|
||||
#if (defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)) || defined(HAVE_DNSSEC)
|
||||
/* CONNTRACK UBUS code uses this buffer, as well as DNSSEC code. */
|
||||
char *workspacename;
|
||||
#endif
|
||||
#ifdef HAVE_DNSSEC
|
||||
char *keyname; /* MAXDNAME size buffer */
|
||||
char *workspacename; /* ditto */
|
||||
unsigned long *rr_status; /* ceiling in TTL from DNSSEC or zero for insecure */
|
||||
int rr_status_sz;
|
||||
int dnssec_no_time_check;
|
||||
@@ -1245,9 +1254,8 @@ extern struct daemon {
|
||||
/* cache.c */
|
||||
void cache_init(void);
|
||||
void next_uid(struct crec *crecp);
|
||||
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg);
|
||||
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg, unsigned short type);
|
||||
char *record_source(unsigned int index);
|
||||
char *querystr(char *desc, unsigned short type);
|
||||
int cache_find_non_terminal(char *name, time_t now);
|
||||
struct crec *cache_find_by_addr(struct crec *crecp,
|
||||
union all_addr *addr, time_t now,
|
||||
@@ -1298,8 +1306,8 @@ unsigned int extract_request(struct dns_header *header, size_t qlen,
|
||||
char *name, unsigned short *typep);
|
||||
void setup_reply(struct dns_header *header, unsigned int flags, int ede);
|
||||
int extract_addresses(struct dns_header *header, size_t qlen, char *name,
|
||||
time_t now, char **ipsets, int is_sign, int check_rebind,
|
||||
int no_cache_dnssec, int secure, int *doctored);
|
||||
time_t now, struct ipsets *ipsets, struct ipsets *nftsets, int is_sign,
|
||||
int check_rebind, int no_cache_dnssec, int secure, int *doctored);
|
||||
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
||||
void report_addresses(struct dns_header *header, size_t len, u32 mark);
|
||||
#endif
|
||||
@@ -1583,6 +1591,12 @@ void ipset_init(void);
|
||||
int add_to_ipset(const char *setname, const union all_addr *ipaddr, int flags, int remove);
|
||||
#endif
|
||||
|
||||
/* nftset.c */
|
||||
#ifdef HAVE_NFTSET
|
||||
void nftset_init(void);
|
||||
int add_to_nftset(const char *setpath, const union all_addr *ipaddr, int flags, int remove);
|
||||
#endif
|
||||
|
||||
/* pattern.c */
|
||||
#ifdef HAVE_CONNTRACK
|
||||
int is_valid_dns_name(const char *value);
|
||||
|
||||
27
src/dnssec.c
27
src/dnssec.c
@@ -724,7 +724,8 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
|
||||
/* namebuff used for workspace above, restore to leave unchanged on exit */
|
||||
p = (unsigned char*)(rrset[0]);
|
||||
extract_name(header, plen, &p, name, 1, 0);
|
||||
if (!extract_name(header, plen, &p, name, 1, 0))
|
||||
return STAT_BOGUS;
|
||||
|
||||
if (key)
|
||||
{
|
||||
@@ -954,9 +955,9 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
a.log.keytag = keytag;
|
||||
a.log.algo = algo;
|
||||
if (algo_digest_name(algo))
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu");
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu", 0);
|
||||
else
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)");
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -973,7 +974,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY");
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY", 0);
|
||||
return STAT_BOGUS | failflags;
|
||||
}
|
||||
|
||||
@@ -1012,12 +1013,14 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
if (STAT_ISEQUAL(rc, STAT_INSECURE))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("Insecure DS reply received for %s, check domain configuration and upstream DNS server DNSSEC support"), name);
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS - not secure");
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS - not secure", 0);
|
||||
return STAT_BOGUS | DNSSEC_FAIL_INDET;
|
||||
}
|
||||
|
||||
p = (unsigned char *)(header+1);
|
||||
extract_name(header, plen, &p, name, 1, 4);
|
||||
if (!extract_name(header, plen, &p, name, 1, 4))
|
||||
return STAT_BOGUS;
|
||||
|
||||
p += 4; /* qtype, qclass */
|
||||
|
||||
/* If the key needed to validate the DS is on the same domain as the DS, we'll
|
||||
@@ -1025,7 +1028,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
from the DS's zone, and not the parent zone. */
|
||||
if (STAT_ISEQUAL(rc, STAT_NEED_KEY) && hostname_isequal(name, keyname))
|
||||
{
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS", 0);
|
||||
return STAT_BOGUS;
|
||||
}
|
||||
|
||||
@@ -1081,9 +1084,9 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
a.log.algo = algo;
|
||||
a.log.digest = digest;
|
||||
if (ds_digest_name(digest) && algo_digest_name(algo))
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu");
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu", 0);
|
||||
else
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)");
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)", 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1116,7 +1119,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
|
||||
cache_end_insert();
|
||||
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no DS/cut" : "no DS");
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no DS/cut" : "no DS", 0);
|
||||
}
|
||||
|
||||
return STAT_OK;
|
||||
@@ -1893,7 +1896,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
|
||||
/* Find all the targets we're looking for answers to.
|
||||
The zeroth array element is for the query, subsequent ones
|
||||
for CNAME targets, unless the query is for a CNAME. */
|
||||
for CNAME targets, unless the query is for a CNAME or ANY. */
|
||||
|
||||
if (!expand_workspace(&targets, &target_sz, 0))
|
||||
return STAT_BOGUS;
|
||||
@@ -1912,7 +1915,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
if (qtype == T_RRSIG)
|
||||
return STAT_INSECURE;
|
||||
|
||||
if (qtype != T_CNAME)
|
||||
if (qtype != T_CNAME && qtype != T_ANY)
|
||||
for (j = ntohs(header->ancount); j != 0; j--)
|
||||
{
|
||||
if (!(p1 = skip_name(p1, header, plen, 10)))
|
||||
|
||||
@@ -207,16 +207,16 @@ int lookup_domain(char *domain, int flags, int *lowout, int *highout)
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
if (found && filter_servers(try, flags, &nlow, &nhigh))
|
||||
/* 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 */
|
||||
{
|
||||
/* We've matched a setting which says to use servers without a domain.
|
||||
Continue the search with empty query */
|
||||
if (daemon->serverarray[try]->flags & SERV_USE_RESOLV)
|
||||
if (daemon->serverarray[nlow]->flags & SERV_USE_RESOLV)
|
||||
crop_query = qlen;
|
||||
else if (filter_servers(try, flags, &nlow, &nhigh))
|
||||
/* 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 */
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -273,7 +273,7 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
|
||||
nlow--;
|
||||
|
||||
while (nhigh < daemon->serverarraysz-1 && order_servers(daemon->serverarray[nhigh], daemon->serverarray[nhigh+1]) == 0)
|
||||
nhigh++;
|
||||
nhigh++;
|
||||
|
||||
nhigh++;
|
||||
|
||||
@@ -293,10 +293,10 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
|
||||
else
|
||||
{
|
||||
/* Now the servers are on order between low and high, in the order
|
||||
IPv6 addr, IPv4 addr, return zero for both, send upstream, no-data return.
|
||||
IPv6 addr, IPv4 addr, return zero for both, resolvconf servers, send upstream, no-data return.
|
||||
|
||||
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))
|
||||
@@ -321,32 +321,40 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
|
||||
{
|
||||
nlow = i;
|
||||
|
||||
/* now look for a server */
|
||||
for (i = nlow; i < nhigh && !(daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
|
||||
|
||||
/* Short to resolv.conf servers */
|
||||
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_USE_RESOLV); i++);
|
||||
|
||||
if (i != nlow)
|
||||
{
|
||||
/* If we want a server that can do DNSSEC, and this one can't,
|
||||
return nothing, similarly if were looking only for a server
|
||||
for a particular domain. */
|
||||
if ((flags & F_DNSSECOK) && !(daemon->serverarray[nlow]->flags & SERV_DO_DNSSEC))
|
||||
nlow = nhigh;
|
||||
else if ((flags & F_DOMAINSRV) && daemon->serverarray[nlow]->domain_len == 0)
|
||||
nlow = nhigh;
|
||||
else
|
||||
nhigh = i;
|
||||
}
|
||||
nhigh = i;
|
||||
else
|
||||
{
|
||||
/* --local=/domain/, only return if we don't need a server. */
|
||||
if (flags & (F_DNSSECOK | F_DOMAINSRV | F_SERVER))
|
||||
nhigh = i;
|
||||
/* now look for a server */
|
||||
for (i = nlow; i < nhigh && !(daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
|
||||
|
||||
if (i != nlow)
|
||||
{
|
||||
/* If we want a server that can do DNSSEC, and this one can't,
|
||||
return nothing, similarly if were looking only for a server
|
||||
for a particular domain. */
|
||||
if ((flags & F_DNSSECOK) && !(daemon->serverarray[nlow]->flags & SERV_DO_DNSSEC))
|
||||
nlow = nhigh;
|
||||
else if ((flags & F_DOMAINSRV) && daemon->serverarray[nlow]->domain_len == 0)
|
||||
nlow = nhigh;
|
||||
else
|
||||
nhigh = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* --local=/domain/, only return if we don't need a server. */
|
||||
if (flags & (F_DNSSECOK | F_DOMAINSRV | F_SERVER))
|
||||
nhigh = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*lowout = nlow;
|
||||
*highout = nhigh;
|
||||
|
||||
@@ -393,7 +401,7 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
|
||||
union all_addr addr;
|
||||
|
||||
if (flags & (F_NXDOMAIN | F_NOERR))
|
||||
log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL);
|
||||
log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL, 0);
|
||||
|
||||
setup_reply(header, flags, ede);
|
||||
|
||||
@@ -411,8 +419,9 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
|
||||
addr.addr4 = srv->addr;
|
||||
|
||||
header->ancount = htons(ntohs(header->ancount) + 1);
|
||||
add_resource_record(header, limit, &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 (!add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr))
|
||||
return 0;
|
||||
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, name, (union all_addr *)&addr, NULL, 0);
|
||||
}
|
||||
|
||||
if (flags & gotname & F_IPV6)
|
||||
@@ -427,7 +436,7 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
|
||||
|
||||
header->ancount = htons(ntohs(header->ancount) + 1);
|
||||
add_resource_record(header, limit, &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);
|
||||
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, name, (union all_addr *)&addr, NULL, 0);
|
||||
}
|
||||
|
||||
if (trunc)
|
||||
@@ -520,10 +529,10 @@ static int order_qsort(const void *a, const void *b)
|
||||
/* Sort all literal NODATA and local IPV4 or IPV6 responses together,
|
||||
in a very specific order. We flip the SERV_LITERAL_ADDRESS bit
|
||||
so the order is IPv6 literal, IPv4 literal, all-zero literal,
|
||||
upstream server, NXDOMAIN literal. */
|
||||
unqualified servers, upstream server, NXDOMAIN literal. */
|
||||
if (rc == 0)
|
||||
rc = ((s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS) -
|
||||
((s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS);
|
||||
rc = ((s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS) -
|
||||
((s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS);
|
||||
|
||||
/* Finally, order by appearance in /etc/resolv.conf etc, for --strict-order */
|
||||
if (rc == 0)
|
||||
@@ -567,7 +576,10 @@ void cleanup_servers(void)
|
||||
free(serv);
|
||||
}
|
||||
else
|
||||
up = &serv->next;
|
||||
{
|
||||
up = &serv->next;
|
||||
daemon->servers_tail = serv;
|
||||
}
|
||||
}
|
||||
|
||||
for (serv = daemon->local_domains, up = &daemon->local_domains; serv; serv = tmp)
|
||||
@@ -609,7 +621,10 @@ int add_update_server(int flags,
|
||||
|
||||
if (*domain == 0)
|
||||
alloc_domain = whine_malloc(1);
|
||||
else if (!(alloc_domain = canonicalise((char *)domain, NULL)))
|
||||
else
|
||||
alloc_domain = canonicalise((char *)domain, NULL);
|
||||
|
||||
if (!alloc_domain)
|
||||
return 0;
|
||||
|
||||
/* See if there is a suitable candidate, and unmark
|
||||
@@ -630,7 +645,7 @@ int add_update_server(int flags,
|
||||
{
|
||||
size_t size;
|
||||
|
||||
if (flags & SERV_LITERAL_ADDRESS)
|
||||
if (flags & SERV_IS_LOCAL)
|
||||
{
|
||||
if (flags & SERV_6ADDR)
|
||||
size = sizeof(struct serv_addr6);
|
||||
@@ -643,56 +658,50 @@ int add_update_server(int flags,
|
||||
size = sizeof(struct server);
|
||||
|
||||
if (!(serv = whine_malloc(size)))
|
||||
return 0;
|
||||
{
|
||||
free(alloc_domain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (flags & SERV_IS_LOCAL)
|
||||
{
|
||||
serv->next = daemon->local_domains;
|
||||
daemon->local_domains = serv;
|
||||
|
||||
if (flags & SERV_4ADDR)
|
||||
((struct serv_addr4*)serv)->addr = local_addr->addr4;
|
||||
|
||||
if (flags & SERV_6ADDR)
|
||||
((struct serv_addr6*)serv)->addr = local_addr->addr6;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct server *s;
|
||||
/* Add to the end of the chain, for order */
|
||||
if (!daemon->servers)
|
||||
daemon->servers = serv;
|
||||
else
|
||||
{
|
||||
for (s = daemon->servers; s->next; s = s->next);
|
||||
s->next = serv;
|
||||
}
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
|
||||
serv->next = NULL;
|
||||
/* Add to the end of the chain, for order */
|
||||
if (daemon->servers_tail)
|
||||
daemon->servers_tail->next = serv;
|
||||
else
|
||||
daemon->servers = serv;
|
||||
daemon->servers_tail = serv;
|
||||
|
||||
#ifdef HAVE_LOOP
|
||||
serv->uid = rand32();
|
||||
#endif
|
||||
|
||||
if (interface)
|
||||
safe_strncpy(serv->interface, interface, sizeof(serv->interface));
|
||||
if (addr)
|
||||
serv->addr = *addr;
|
||||
if (source_addr)
|
||||
serv->source_addr = *source_addr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flags & SERV_IS_LOCAL))
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
|
||||
serv->flags = flags;
|
||||
serv->domain = alloc_domain;
|
||||
serv->domain_len = strlen(alloc_domain);
|
||||
|
||||
if (flags & SERV_4ADDR)
|
||||
((struct serv_addr4*)serv)->addr = local_addr->addr4;
|
||||
|
||||
if (flags & SERV_6ADDR)
|
||||
((struct serv_addr6*)serv)->addr = local_addr->addr6;
|
||||
|
||||
if (!(flags & SERV_IS_LOCAL))
|
||||
{
|
||||
#ifdef HAVE_LOOP
|
||||
serv->uid = rand32();
|
||||
#endif
|
||||
|
||||
if (interface)
|
||||
safe_strncpy(serv->interface, interface, sizeof(serv->interface));
|
||||
if (addr)
|
||||
serv->addr = *addr;
|
||||
if (source_addr)
|
||||
serv->source_addr = *source_addr;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
121
src/forward.c
121
src/forward.c
@@ -119,12 +119,12 @@ static void set_outgoing_mark(struct frec *forward, int fd)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void log_query_mysockaddr(unsigned int flags, char *name, union mysockaddr *addr, char *arg)
|
||||
static void log_query_mysockaddr(unsigned int flags, char *name, union mysockaddr *addr, char *arg, unsigned short type)
|
||||
{
|
||||
if (addr->sa.sa_family == AF_INET)
|
||||
log_query(flags | F_IPV4, name, (union all_addr *)&addr->in.sin_addr, arg);
|
||||
log_query(flags | F_IPV4, name, (union all_addr *)&addr->in.sin_addr, arg, type);
|
||||
else
|
||||
log_query(flags | F_IPV6, name, (union all_addr *)&addr->in6.sin6_addr, arg);
|
||||
log_query(flags | F_IPV6, name, (union all_addr *)&addr->in6.sin6_addr, arg, type);
|
||||
}
|
||||
|
||||
static void server_send(struct server *server, int fd,
|
||||
@@ -138,23 +138,24 @@ static void server_send(struct server *server, int fd,
|
||||
#ifdef HAVE_DNSSEC
|
||||
static void server_send_log(struct server *server, int fd,
|
||||
const void *header, size_t plen, int dumpflags,
|
||||
unsigned int logflags, char *name, char *arg)
|
||||
unsigned int logflags, char *name, char *arg,
|
||||
unsigned short type)
|
||||
{
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet(dumpflags, (void *)header, (size_t)plen, NULL, &server->addr);
|
||||
#endif
|
||||
log_query_mysockaddr(logflags, name, &server->addr, arg);
|
||||
log_query_mysockaddr(logflags, name, &server->addr, arg, type);
|
||||
server_send(server, fd, header, plen, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int domain_no_rebind(char *domain)
|
||||
{
|
||||
struct server *serv;
|
||||
int dlen = (int)strlen(domain);
|
||||
struct rebind_domain *rbd;
|
||||
size_t tlen, dlen = strlen(domain);
|
||||
|
||||
for (serv = daemon->no_rebind; serv; serv = serv->next)
|
||||
if (dlen >= serv->domain_len && strcmp(serv->domain, &domain[dlen - serv->domain_len]) == 0)
|
||||
for (rbd = daemon->no_rebind; rbd; rbd = rbd->next)
|
||||
if (dlen >= (tlen = strlen(rbd->domain)) && strcmp(rbd->domain, &domain[dlen - tlen]) == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@@ -172,7 +173,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
void *hash = hash_questions(header, plen, daemon->namebuff);
|
||||
unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
|
||||
int old_src = 0;
|
||||
int old_src = 0, old_reply = 0;
|
||||
int first, last, start = 0;
|
||||
int subnet, cacheable, forwarded = 0;
|
||||
size_t edns0_len;
|
||||
@@ -198,7 +199,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
Similarly FREC_NO_CACHE is never set in flags, so a query which is
|
||||
contigent on a particular source address EDNS0 option will never be matched. */
|
||||
if (forward)
|
||||
old_src = 1;
|
||||
{
|
||||
old_src = 1;
|
||||
old_reply = 1;
|
||||
}
|
||||
else if ((forward = lookup_frec_by_query(hash, fwd_flags,
|
||||
FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION |
|
||||
FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_NO_CACHE)))
|
||||
@@ -375,9 +379,18 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
/* In strict order mode, there must be a server later in the list
|
||||
left to send to, otherwise without the forwardall mechanism,
|
||||
code further on will cycle around the list forwever if they
|
||||
all return REFUSED. If at the last, give up. */
|
||||
all return REFUSED. If at the last, give up.
|
||||
Note that we can get here EITHER because a client retried,
|
||||
or an upstream server returned REFUSED. The above only
|
||||
applied in the later case. For client retries,
|
||||
keep tyring the last server.. */
|
||||
if (++start == last)
|
||||
goto reply;
|
||||
{
|
||||
if (old_reply)
|
||||
goto reply;
|
||||
else
|
||||
start--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -494,12 +507,12 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
if (!gotname)
|
||||
strcpy(daemon->namebuff, "query");
|
||||
log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff,
|
||||
&srv->addr, NULL);
|
||||
&srv->addr, NULL, 0);
|
||||
}
|
||||
#ifdef HAVE_DNSSEC
|
||||
else
|
||||
log_query_mysockaddr(F_NOEXTRA | F_DNSSEC, daemon->namebuff, &srv->addr,
|
||||
querystr("dnssec-retry", (forward->flags & FREC_DNSKEY_QUERY) ? T_DNSKEY : T_DS));
|
||||
"dnssec-retry", (forward->flags & FREC_DNSKEY_QUERY) ? T_DNSKEY : T_DS);
|
||||
#endif
|
||||
|
||||
srv->queries++;
|
||||
@@ -555,12 +568,33 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ipsets *domain_find_sets(struct ipsets *setlist, const char *domain) {
|
||||
/* Similar algorithm to search_servers. */
|
||||
struct ipsets *ipset_pos, *ret = NULL;
|
||||
unsigned int namelen = strlen(domain);
|
||||
unsigned int matchlen = 0;
|
||||
for (ipset_pos = setlist; ipset_pos; ipset_pos = ipset_pos->next)
|
||||
{
|
||||
unsigned int domainlen = strlen(ipset_pos->domain);
|
||||
const char *matchstart = domain + namelen - domainlen;
|
||||
if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
|
||||
(domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
|
||||
domainlen >= matchlen)
|
||||
{
|
||||
matchlen = domainlen;
|
||||
ret = ipset_pos;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t process_reply(struct dns_header *header, time_t now, struct server *server, size_t n, int check_rebind,
|
||||
int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader,
|
||||
int check_subnet, union mysockaddr *query_source, unsigned char *limit, int ede)
|
||||
{
|
||||
unsigned char *pheader, *sizep;
|
||||
char **sets = 0;
|
||||
struct ipsets *ipsets = NULL, *nftsets = NULL;
|
||||
int munged = 0, is_sign;
|
||||
unsigned int rcode = RCODE(header);
|
||||
size_t plen;
|
||||
@@ -571,24 +605,12 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
|
||||
#ifdef HAVE_IPSET
|
||||
if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
|
||||
{
|
||||
/* Similar algorithm to search_servers. */
|
||||
struct ipsets *ipset_pos;
|
||||
unsigned int namelen = strlen(daemon->namebuff);
|
||||
unsigned int matchlen = 0;
|
||||
for (ipset_pos = daemon->ipsets; ipset_pos; ipset_pos = ipset_pos->next)
|
||||
{
|
||||
unsigned int domainlen = strlen(ipset_pos->domain);
|
||||
char *matchstart = daemon->namebuff + namelen - domainlen;
|
||||
if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
|
||||
(domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
|
||||
domainlen >= matchlen)
|
||||
{
|
||||
matchlen = domainlen;
|
||||
sets = ipset_pos->sets;
|
||||
}
|
||||
}
|
||||
}
|
||||
ipsets = domain_find_sets(daemon->ipsets, daemon->namebuff);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NFTSET
|
||||
if (daemon->nftsets && extract_request(header, n, daemon->namebuff, NULL))
|
||||
nftsets = domain_find_sets(daemon->nftsets, daemon->namebuff);
|
||||
#endif
|
||||
|
||||
if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
|
||||
@@ -653,7 +675,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
union all_addr a;
|
||||
a.log.rcode = rcode;
|
||||
a.log.ede = ede;
|
||||
log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL);
|
||||
log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL, 0);
|
||||
|
||||
return resize_packet(header, n, pheader, plen);
|
||||
}
|
||||
@@ -697,7 +719,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
}
|
||||
}
|
||||
|
||||
if (extract_addresses(header, n, daemon->namebuff, now, sets, is_sign, check_rebind, no_cache, cache_secure, &doctored))
|
||||
if (extract_addresses(header, n, daemon->namebuff, now, ipsets, nftsets, is_sign, check_rebind, no_cache, cache_secure, &doctored))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
|
||||
munged = 1;
|
||||
@@ -889,7 +911,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
#endif
|
||||
server_send_log(server, fd, header, nn, DUMP_SEC_QUERY,
|
||||
F_NOEXTRA | F_DNSSEC, daemon->keyname,
|
||||
querystr("dnssec-query", STAT_ISEQUAL(status, STAT_NEED_KEY) ? T_DNSKEY : T_DS));
|
||||
"dnssec-query", STAT_ISEQUAL(status, STAT_NEED_KEY) ? T_DNSKEY : T_DS);
|
||||
server->queries++;
|
||||
}
|
||||
|
||||
@@ -1136,7 +1158,7 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he
|
||||
domain = daemon->namebuff;
|
||||
}
|
||||
|
||||
log_query(F_SECSTAT, domain, &a, result);
|
||||
log_query(F_SECSTAT, domain, &a, result, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1202,7 +1224,7 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he
|
||||
{
|
||||
daemon->log_display_id = src->log_id;
|
||||
daemon->log_source_addr = &src->source;
|
||||
log_query(F_UPSTREAM, "query", NULL, "duplicate");
|
||||
log_query(F_UPSTREAM, "query", NULL, "duplicate", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1509,10 +1531,8 @@ void receive_query(struct listener *listen, time_t now)
|
||||
#ifdef HAVE_AUTH
|
||||
struct auth_zone *zone;
|
||||
#endif
|
||||
char *types = querystr(auth_dns ? "auth" : "query", type);
|
||||
|
||||
log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
|
||||
&source_addr, types);
|
||||
&source_addr, auth_dns ? "auth" : "query", type);
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
is_single_query = 1;
|
||||
@@ -1808,7 +1828,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
daemon->log_display_id = ++daemon->log_id;
|
||||
|
||||
log_query_mysockaddr(F_NOEXTRA | F_DNSSEC, keyname, &server->addr,
|
||||
querystr("dnssec-query", STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS));
|
||||
"dnssec-query", STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS);
|
||||
|
||||
new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
|
||||
|
||||
@@ -1864,7 +1884,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
int first, last;
|
||||
unsigned int flags = 0;
|
||||
|
||||
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
||||
if (!packet || getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
||||
return packet;
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
@@ -1946,11 +1966,10 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
#ifdef HAVE_AUTH
|
||||
struct auth_zone *zone;
|
||||
#endif
|
||||
char *types = querystr(auth_dns ? "auth" : "query", qtype);
|
||||
|
||||
|
||||
log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
|
||||
&peer_addr, types);
|
||||
|
||||
&peer_addr, auth_dns ? "auth" : "query", qtype);
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
is_single_query = 1;
|
||||
#endif
|
||||
@@ -2089,7 +2108,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
/* get query name again for logging - may have been overwritten */
|
||||
if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
|
||||
strcpy(daemon->namebuff, "query");
|
||||
log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff, &serv->addr, NULL);
|
||||
log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff, &serv->addr, NULL, 0);
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (master->flags & SERV_DO_DNSSEC))
|
||||
@@ -2121,7 +2140,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
domain = daemon->namebuff;
|
||||
}
|
||||
|
||||
log_query(F_SECSTAT, domain, &a, result);
|
||||
log_query(F_SECSTAT, domain, &a, result, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2276,7 +2295,7 @@ int allocate_rfd(struct randfd_list **fdlp, struct server *serv)
|
||||
}
|
||||
}
|
||||
|
||||
if (j == daemon->numrrand)
|
||||
if (!rfd) /* should be when j == daemon->numrrand */
|
||||
{
|
||||
struct randfd_list *rfl_poll;
|
||||
|
||||
|
||||
@@ -76,9 +76,9 @@ unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name
|
||||
|
||||
#else /* HAVE_DNSSEC || HAVE_CRYPTOHASH */
|
||||
|
||||
#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest
|
||||
typedef unsigned char BYTE; // 8-bit byte
|
||||
typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
|
||||
#define SHA256_BLOCK_SIZE 32 /* SHA256 outputs a 32 byte digest */
|
||||
typedef unsigned char BYTE; /* 8-bit byte */
|
||||
typedef unsigned int WORD; /* 32-bit word, change to "long" for 16-bit machines */
|
||||
|
||||
typedef struct {
|
||||
BYTE data[64];
|
||||
@@ -238,7 +238,7 @@ static void sha256_final(SHA256_CTX *ctx, BYTE hash[])
|
||||
|
||||
i = ctx->datalen;
|
||||
|
||||
// Pad whatever data is left in the buffer.
|
||||
/* Pad whatever data is left in the buffer. */
|
||||
if (ctx->datalen < 56)
|
||||
{
|
||||
ctx->data[i++] = 0x80;
|
||||
@@ -254,7 +254,7 @@ static void sha256_final(SHA256_CTX *ctx, BYTE hash[])
|
||||
memset(ctx->data, 0, 56);
|
||||
}
|
||||
|
||||
// Append to the padding the total message's length in bits and transform.
|
||||
/* Append to the padding the total message's length in bits and transform. */
|
||||
ctx->bitlen += ctx->datalen * 8;
|
||||
ctx->data[63] = ctx->bitlen;
|
||||
ctx->data[62] = ctx->bitlen >> 8;
|
||||
@@ -266,8 +266,8 @@ static void sha256_final(SHA256_CTX *ctx, BYTE hash[])
|
||||
ctx->data[56] = ctx->bitlen >> 56;
|
||||
sha256_transform(ctx, ctx->data);
|
||||
|
||||
// Since this implementation uses little endian byte ordering and SHA uses big endian,
|
||||
// reverse all the bytes when copying the final state to the output hash.
|
||||
/* Since this implementation uses little endian byte ordering and SHA uses big endian,
|
||||
reverse all the bytes when copying the final state to the output hash. */
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
|
||||
|
||||
@@ -148,12 +148,19 @@ void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revh
|
||||
if (!(ah->flags & flag))
|
||||
continue;
|
||||
|
||||
if (stat(ah->fname, &buf) == -1 || !(S_ISDIR(buf.st_mode)))
|
||||
if (stat(ah->fname, &buf) == -1)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("bad dynamic directory %s: %s"),
|
||||
ah->fname, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(S_ISDIR(buf.st_mode)))
|
||||
{
|
||||
my_syslog(LOG_ERR, _("bad dynamic directory %s: %s"),
|
||||
ah->fname, _("not a directory"));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(ah->flags & AH_WD_DONE))
|
||||
{
|
||||
|
||||
@@ -1586,6 +1586,9 @@ void check_servers(int no_loop_check)
|
||||
if (serv->sfd)
|
||||
serv->sfd->used = 1;
|
||||
|
||||
if (count == SERVERS_LOGGED)
|
||||
my_syslog(LOG_INFO, _("more servers are defined but not logged"));
|
||||
|
||||
if (++count > SERVERS_LOGGED)
|
||||
continue;
|
||||
|
||||
@@ -1623,7 +1626,8 @@ void check_servers(int no_loop_check)
|
||||
continue;
|
||||
|
||||
if ((serv->flags & SERV_LITERAL_ADDRESS) &&
|
||||
!(serv->flags & (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)))
|
||||
!(serv->flags & (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)) &&
|
||||
strlen(serv->domain))
|
||||
{
|
||||
count--;
|
||||
if (++locals <= LOCALS_LOGGED)
|
||||
|
||||
94
src/nftset.c
Normal file
94
src/nftset.c
Normal file
@@ -0,0 +1,94 @@
|
||||
/* 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"
|
||||
|
||||
#if defined (HAVE_NFTSET) && defined (HAVE_LINUX_NETWORK)
|
||||
|
||||
#include <nftables/libnftables.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
static struct nft_ctx *ctx = NULL;
|
||||
static const char *cmd_add = "add element %s { %s }";
|
||||
static const char *cmd_del = "delete element %s { %s }";
|
||||
|
||||
void nftset_init()
|
||||
{
|
||||
ctx = nft_ctx_new(NFT_CTX_DEFAULT);
|
||||
if (ctx == NULL)
|
||||
die(_("failed to create nftset context"), NULL, EC_MISC);
|
||||
|
||||
/* disable libnftables output */
|
||||
nft_ctx_buffer_error(ctx);
|
||||
}
|
||||
|
||||
int add_to_nftset(const char *setname, const union all_addr *ipaddr, int flags, int remove)
|
||||
{
|
||||
const char *cmd = remove ? cmd_del : cmd_add;
|
||||
int ret, af = (flags & F_IPV4) ? AF_INET : AF_INET6;
|
||||
size_t new_sz;
|
||||
char *new, *err, *nl;
|
||||
static char *cmd_buf = NULL;
|
||||
static size_t cmd_buf_sz = 0;
|
||||
|
||||
inet_ntop(af, ipaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||
|
||||
if (setname[1] == ' ' && (setname[0] == '4' || setname[0] == '6'))
|
||||
{
|
||||
if (setname[0] == '4' && !(flags & F_IPV4))
|
||||
return -1;
|
||||
|
||||
if (setname[0] == '6' && !(flags & F_IPV6))
|
||||
return -1;
|
||||
|
||||
setname += 2;
|
||||
}
|
||||
|
||||
if (cmd_buf_sz == 0)
|
||||
new_sz = 150; /* initial allocation */
|
||||
else
|
||||
new_sz = snprintf(cmd_buf, cmd_buf_sz, cmd, setname, daemon->addrbuff);
|
||||
|
||||
if (new_sz > cmd_buf_sz)
|
||||
{
|
||||
if (!(new = whine_malloc(new_sz + 10)))
|
||||
return 0;
|
||||
|
||||
if (cmd_buf)
|
||||
free(cmd_buf);
|
||||
cmd_buf = new;
|
||||
cmd_buf_sz = new_sz + 10;
|
||||
snprintf(cmd_buf, cmd_buf_sz, cmd, setname, daemon->addrbuff);
|
||||
}
|
||||
|
||||
ret = nft_run_cmd_from_buffer(ctx, cmd_buf);
|
||||
err = (char *)nft_ctx_get_error_buffer(ctx);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
/* Log only first line of error return. */
|
||||
if ((nl = strchr(err, '\n')))
|
||||
*nl = 0;
|
||||
my_syslog(LOG_ERR, "nftset %s %s", setname, err);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
343
src/option.c
343
src/option.c
@@ -174,6 +174,7 @@ struct myoption {
|
||||
#define LOPT_CMARK_ALST_EN 365
|
||||
#define LOPT_CMARK_ALST 366
|
||||
#define LOPT_QUIET_TFTP 367
|
||||
#define LOPT_NFTSET 368
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -327,6 +328,7 @@ static const struct myoption opts[] =
|
||||
{ "auth-sec-servers", 1, 0, LOPT_AUTHSFS },
|
||||
{ "auth-peer", 1, 0, LOPT_AUTHPEER },
|
||||
{ "ipset", 1, 0, LOPT_IPSET },
|
||||
{ "nftset", 1, 0, LOPT_NFTSET },
|
||||
{ "connmark-allowlist-enable", 2, 0, LOPT_CMARK_ALST_EN },
|
||||
{ "connmark-allowlist", 1, 0, LOPT_CMARK_ALST },
|
||||
{ "synth-domain", 1, 0, LOPT_SYNTH },
|
||||
@@ -514,6 +516,7 @@ static struct {
|
||||
{ LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL },
|
||||
{ LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL },
|
||||
{ LOPT_IPSET, ARG_DUP, "/<domain>[/<domain>...]/<ipset>...", gettext_noop("Specify ipsets to which matching domains should be added"), NULL },
|
||||
{ LOPT_NFTSET, ARG_DUP, "/<domain>[/<domain>...]/<nftset>...", gettext_noop("Specify nftables sets to which matching domains should be added"), NULL },
|
||||
{ LOPT_CMARK_ALST_EN, ARG_ONE, "[=<mask>]", gettext_noop("Enable filtering of DNS queries with connection-track marks."), NULL },
|
||||
{ LOPT_CMARK_ALST, ARG_DUP, "<connmark>[/<mask>][,<pattern>[/<pattern>...]]", gettext_noop("Set allowed DNS patterns for a connection-track mark."), NULL },
|
||||
{ LOPT_SYNTH, ARG_DUP, "<domain>,<range>,[<prefix>]", gettext_noop("Specify a domain and address range for synthesised names"), NULL },
|
||||
@@ -798,7 +801,7 @@ static void do_usage(void)
|
||||
|
||||
if (usage[i].arg)
|
||||
{
|
||||
strcpy(buff, usage[i].arg);
|
||||
safe_strncpy(buff, usage[i].arg, sizeof(buff));
|
||||
for (j = 0; tab[j].handle; j++)
|
||||
if (tab[j].handle == *(usage[i].arg))
|
||||
sprintf(buff, "%d", tab[j].val);
|
||||
@@ -935,52 +938,124 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int domain_rev4(char *domain, struct in_addr addr, int msize)
|
||||
static char *domain_rev4(int from_file, char *server, struct in_addr *addr4, int size)
|
||||
{
|
||||
in_addr_t a = ntohl(addr.s_addr);
|
||||
|
||||
*domain = 0;
|
||||
int i, j;
|
||||
char *string;
|
||||
int msize;
|
||||
u16 flags = 0;
|
||||
char domain[29]; /* strlen("xxx.yyy.zzz.ttt.in-addr.arpa")+1 */
|
||||
union mysockaddr serv_addr, source_addr;
|
||||
char interface[IF_NAMESIZE+1];
|
||||
int count = 1, rem, addrbytes, addrbits;
|
||||
|
||||
switch (msize)
|
||||
if (!server)
|
||||
flags = SERV_LITERAL_ADDRESS;
|
||||
else if ((string = parse_server(server, &serv_addr, &source_addr, interface, &flags)))
|
||||
return string;
|
||||
|
||||
if (from_file)
|
||||
flags |= SERV_FROM_FILE;
|
||||
|
||||
rem = size & 0x7;
|
||||
addrbytes = (32 - size) >> 3;
|
||||
addrbits = (32 - size) & 7;
|
||||
|
||||
if (size > 32 || size < 1)
|
||||
return _("bad IPv4 prefix length");
|
||||
|
||||
/* Zero out last address bits according to CIDR mask */
|
||||
((u8 *)addr4)[3-addrbytes] &= ~((1 << addrbits)-1);
|
||||
|
||||
size = size & ~0x7;
|
||||
|
||||
if (rem != 0)
|
||||
count = 1 << (8 - rem);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
case 32:
|
||||
domain += sprintf(domain, "%u.", a & 0xff);
|
||||
/* fall through */
|
||||
case 24:
|
||||
domain += sprintf(domain, "%d.", (a >> 8) & 0xff);
|
||||
/* fall through */
|
||||
case 16:
|
||||
domain += sprintf(domain, "%d.", (a >> 16) & 0xff);
|
||||
/* fall through */
|
||||
case 8:
|
||||
domain += sprintf(domain, "%d.", (a >> 24) & 0xff);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
*domain = 0;
|
||||
string = domain;
|
||||
msize = size/8;
|
||||
|
||||
for (j = (rem == 0) ? msize-1 : msize; j >= 0; j--)
|
||||
{
|
||||
int dig = ((unsigned char *)addr4)[j];
|
||||
|
||||
if (j == msize)
|
||||
dig += i;
|
||||
|
||||
string += sprintf(string, "%d.", dig);
|
||||
}
|
||||
|
||||
sprintf(string, "in-addr.arpa");
|
||||
|
||||
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
|
||||
return _("error");
|
||||
}
|
||||
|
||||
domain += sprintf(domain, "in-addr.arpa");
|
||||
|
||||
return 1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int domain_rev6(char *domain, struct in6_addr *addr, int msize)
|
||||
static char *domain_rev6(int from_file, char *server, struct in6_addr *addr6, int size)
|
||||
{
|
||||
int i;
|
||||
int i, j;
|
||||
char *string;
|
||||
int msize;
|
||||
u16 flags = 0;
|
||||
char domain[73]; /* strlen("32*<n.>ip6.arpa")+1 */
|
||||
union mysockaddr serv_addr, source_addr;
|
||||
char interface[IF_NAMESIZE+1];
|
||||
int count = 1, rem, addrbytes, addrbits;
|
||||
|
||||
if (msize > 128 || msize%4)
|
||||
return 0;
|
||||
if (!server)
|
||||
flags = SERV_LITERAL_ADDRESS;
|
||||
else if ((string = parse_server(server, &serv_addr, &source_addr, interface, &flags)))
|
||||
return string;
|
||||
|
||||
if (from_file)
|
||||
flags |= SERV_FROM_FILE;
|
||||
|
||||
*domain = 0;
|
||||
rem = size & 0x3;
|
||||
addrbytes = (128 - size) >> 3;
|
||||
addrbits = (128 - size) & 7;
|
||||
|
||||
if (size > 128 || size < 1)
|
||||
return _("bad IPv6 prefix length");
|
||||
|
||||
/* Zero out last address bits according to CIDR mask */
|
||||
addr6->s6_addr[15-addrbytes] &= ~((1 << addrbits) - 1);
|
||||
|
||||
size = size & ~0x3;
|
||||
|
||||
if (rem != 0)
|
||||
count = 1 << (4 - rem);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
*domain = 0;
|
||||
string = domain;
|
||||
msize = size/4;
|
||||
|
||||
for (j = (rem == 0) ? msize-1 : msize; j >= 0; j--)
|
||||
{
|
||||
int dig = ((unsigned char *)addr6)[j>>1];
|
||||
|
||||
dig = j & 1 ? dig & 15 : dig >> 4;
|
||||
|
||||
if (j == msize)
|
||||
dig += i;
|
||||
|
||||
string += sprintf(string, "%.1x.", dig);
|
||||
}
|
||||
|
||||
sprintf(string, "ip6.arpa");
|
||||
|
||||
for (i = msize-1; i >= 0; i -= 4)
|
||||
{
|
||||
int dig = ((unsigned char *)addr)[i>>3];
|
||||
domain += sprintf(domain, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
|
||||
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
|
||||
return _("error");
|
||||
}
|
||||
domain += sprintf(domain, "ip6.arpa");
|
||||
|
||||
return 1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
@@ -1829,6 +1904,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->next = li;
|
||||
*up = new;
|
||||
}
|
||||
else
|
||||
free(path);
|
||||
|
||||
}
|
||||
|
||||
@@ -1995,7 +2072,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
if (!(name = canonicalise_opt(arg)) ||
|
||||
(comma && !(target = canonicalise_opt(comma))))
|
||||
ret_err(_("bad MX name"));
|
||||
{
|
||||
free(name);
|
||||
free(target);
|
||||
ret_err(_("bad MX name"));
|
||||
}
|
||||
|
||||
new = opt_malloc(sizeof(struct mx_srv_record));
|
||||
new->next = daemon->mxnames;
|
||||
@@ -2302,17 +2383,13 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
|
||||
ret_err_free(_("bad prefix"), new);
|
||||
}
|
||||
else if (strcmp(arg, "local") != 0 ||
|
||||
(msize != 8 && msize != 16 && msize != 24))
|
||||
else if (strcmp(arg, "local") != 0)
|
||||
ret_err_free(gen_err, new);
|
||||
else
|
||||
{
|
||||
char domain[29]; /* strlen("xxx.yyy.zzz.ttt.in-addr.arpa")+1 */
|
||||
/* local=/xxx.yyy.zzz.in-addr.arpa/ */
|
||||
/* domain_rev4 can't fail here, msize checked above. */
|
||||
domain_rev4(domain, new->start, msize);
|
||||
add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, domain, NULL);
|
||||
|
||||
domain_rev4(0, NULL, &new->start, msize);
|
||||
|
||||
/* local=/<domain>/ */
|
||||
/* d_raw can't failed to canonicalise here, checked above. */
|
||||
add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, d_raw, NULL);
|
||||
@@ -2347,16 +2424,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN)
|
||||
ret_err_free(_("bad prefix"), new);
|
||||
}
|
||||
else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
|
||||
else if (strcmp(arg, "local") != 0)
|
||||
ret_err_free(gen_err, new);
|
||||
else
|
||||
{
|
||||
char domain[73]; /* strlen("32*<n.>ip6.arpa")+1 */
|
||||
/* generate the equivalent of
|
||||
local=/xxx.yyy.zzz.ip6.arpa/ */
|
||||
domain_rev6(domain, &new->start6, msize);
|
||||
add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, domain, NULL);
|
||||
|
||||
domain_rev6(0, NULL, &new->start6, msize);
|
||||
|
||||
/* local=/<domain>/ */
|
||||
/* d_raw can't failed to canonicalise here, checked above. */
|
||||
add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, d_raw, NULL);
|
||||
@@ -2635,7 +2710,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
case LOPT_NO_REBIND: /* --rebind-domain-ok */
|
||||
{
|
||||
struct server *new;
|
||||
struct rebind_domain *new;
|
||||
|
||||
unhide_metas(arg);
|
||||
|
||||
@@ -2644,9 +2719,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
do {
|
||||
comma = split_chr(arg, '/');
|
||||
new = opt_malloc(sizeof(struct serv_local));
|
||||
new->domain = opt_string_alloc(arg);
|
||||
new->domain_len = strlen(arg);
|
||||
new = opt_malloc(sizeof(struct rebind_domain));
|
||||
new->domain = canonicalise_opt(arg);
|
||||
new->next = daemon->no_rebind;
|
||||
daemon->no_rebind = new;
|
||||
arg = comma;
|
||||
@@ -2684,7 +2758,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
if (!arg || !*arg)
|
||||
flags = SERV_LITERAL_ADDRESS;
|
||||
else if (option == 'A')
|
||||
else if (option != 'S')
|
||||
{
|
||||
/* # as literal address means return zero address for 4 and 6 */
|
||||
if (strcmp(arg, "#") == 0)
|
||||
@@ -2700,11 +2774,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
if ((err = parse_server(arg, &serv_addr, &source_addr, interface, &flags)))
|
||||
ret_err(err);
|
||||
|
||||
/* server=//1.2.3.4 is special. */
|
||||
if (strlen(domain) == 0 && lastdomain)
|
||||
flags |= SERV_FOR_NODOTS;
|
||||
|
||||
}
|
||||
|
||||
if (servers_only && option == 'S')
|
||||
@@ -2712,6 +2781,19 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* server=//1.2.3.4 is special. */
|
||||
if (lastdomain)
|
||||
{
|
||||
if (strlen(domain) == 0)
|
||||
flags |= SERV_FOR_NODOTS;
|
||||
else
|
||||
flags &= ~SERV_FOR_NODOTS;
|
||||
|
||||
/* address=/#/ matches the same as without domain */
|
||||
if (option != 'S' && domain[0] == '#' && domain[1] == 0)
|
||||
domain[0] = 0;
|
||||
}
|
||||
|
||||
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, &addr))
|
||||
ret_err(gen_err);
|
||||
|
||||
@@ -2728,57 +2810,62 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
char *string;
|
||||
int size;
|
||||
u16 flags = 0;
|
||||
char domain[73]; /* strlen("32*<n.>ip6.arpa")+1 */
|
||||
struct in_addr addr4;
|
||||
struct in6_addr addr6;
|
||||
union mysockaddr serv_addr, source_addr;
|
||||
char interface[IF_NAMESIZE+1];
|
||||
|
||||
|
||||
unhide_metas(arg);
|
||||
if (!arg)
|
||||
ret_err(gen_err);
|
||||
|
||||
comma=split(arg);
|
||||
|
||||
if (!(string = split_chr(arg, '/')) || !atoi_check(string, &size))
|
||||
ret_err(gen_err);
|
||||
|
||||
if (!(string = split_chr(arg, '/')) || !atoi_check(string, &size))
|
||||
size = -1;
|
||||
|
||||
if (inet_pton(AF_INET, arg, &addr4))
|
||||
{
|
||||
if (!domain_rev4(domain, addr4, size))
|
||||
ret_err(_("bad IPv4 prefix"));
|
||||
if (size == -1)
|
||||
size = 32;
|
||||
|
||||
if ((string = domain_rev4(servers_only, comma, &addr4, size)))
|
||||
ret_err(string);
|
||||
}
|
||||
else if (inet_pton(AF_INET6, arg, &addr6))
|
||||
{
|
||||
if (!domain_rev6(domain, &addr6, size))
|
||||
ret_err(_("bad IPv6 prefix"));
|
||||
if (size == -1)
|
||||
size = 128;
|
||||
|
||||
if ((string = domain_rev6(servers_only, comma, &addr6, size)))
|
||||
ret_err(string);
|
||||
}
|
||||
else
|
||||
ret_err(gen_err);
|
||||
|
||||
if (!comma)
|
||||
flags |= SERV_LITERAL_ADDRESS;
|
||||
else if ((string = parse_server(comma, &serv_addr, &source_addr, interface, &flags)))
|
||||
ret_err(string);
|
||||
|
||||
if (servers_only)
|
||||
flags |= SERV_FROM_FILE;
|
||||
|
||||
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
|
||||
ret_err(gen_err);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LOPT_IPSET: /* --ipset */
|
||||
case LOPT_NFTSET: /* --nftset */
|
||||
#ifndef HAVE_IPSET
|
||||
ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives"));
|
||||
break;
|
||||
#else
|
||||
if (option == LOPT_IPSET)
|
||||
{
|
||||
ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives"));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifndef HAVE_NFTSET
|
||||
if (option == LOPT_NFTSET)
|
||||
{
|
||||
ret_err(_("recompile with HAVE_NFTSET defined to enable nftset directives"));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
struct ipsets ipsets_head;
|
||||
struct ipsets *ipsets = &ipsets_head;
|
||||
struct ipsets **daemon_sets =
|
||||
(option == LOPT_IPSET) ? &daemon->ipsets : &daemon->nftsets;
|
||||
int size;
|
||||
char *end;
|
||||
char **sets, **sets_pos;
|
||||
@@ -2823,19 +2910,24 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
sets = sets_pos = opt_malloc(sizeof(char *) * size);
|
||||
|
||||
do {
|
||||
char *p;
|
||||
end = split(arg);
|
||||
*sets_pos++ = opt_string_alloc(arg);
|
||||
*sets_pos = opt_string_alloc(arg);
|
||||
/* Use '#' to delimit table and set */
|
||||
if (option == LOPT_NFTSET)
|
||||
while ((p = strchr(*sets_pos, '#')))
|
||||
*p = ' ';
|
||||
sets_pos++;
|
||||
arg = end;
|
||||
} while (end);
|
||||
*sets_pos = 0;
|
||||
for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next)
|
||||
ipsets->next->sets = sets;
|
||||
ipsets->next = daemon->ipsets;
|
||||
daemon->ipsets = ipsets_head.next;
|
||||
ipsets->next = *daemon_sets;
|
||||
*daemon_sets = ipsets_head.next;
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case LOPT_CMARK_ALST_EN: /* --connmark-allowlist-enable */
|
||||
#ifndef HAVE_CONNTRACK
|
||||
@@ -3615,6 +3707,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
inet_ntop(AF_INET, &in, daemon->addrbuff, ADDRSTRLEN);
|
||||
sprintf(errstr, _("duplicate dhcp-host IP address %s"),
|
||||
daemon->addrbuff);
|
||||
dhcp_config_free(new);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -3778,16 +3871,16 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
case LOPT_NAME_MATCH: /* --dhcp-name-match */
|
||||
{
|
||||
struct dhcp_match_name *new = opt_malloc(sizeof(struct dhcp_match_name));
|
||||
struct dhcp_netid *id = opt_malloc(sizeof(struct dhcp_netid));
|
||||
struct dhcp_match_name *new;
|
||||
ssize_t len;
|
||||
|
||||
if (!(comma = split(arg)) || (len = strlen(comma)) == 0)
|
||||
ret_err(gen_err);
|
||||
|
||||
new = opt_malloc(sizeof(struct dhcp_match_name));
|
||||
new->wildcard = 0;
|
||||
new->netid = id;
|
||||
id->net = opt_string_alloc(set_prefix(arg));
|
||||
new->netid = opt_malloc(sizeof(struct dhcp_netid));
|
||||
new->netid->net = opt_string_alloc(set_prefix(arg));
|
||||
|
||||
if (comma[len-1] == '*')
|
||||
{
|
||||
@@ -3991,6 +4084,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
}
|
||||
|
||||
dhcp_netid_free(new->netid);
|
||||
free(new);
|
||||
ret_err(gen_err);
|
||||
}
|
||||
|
||||
@@ -4366,7 +4461,7 @@ err:
|
||||
case LOPT_CNAME: /* --cname */
|
||||
{
|
||||
struct cname *new;
|
||||
char *alias, *target, *last, *pen;
|
||||
char *alias, *target=NULL, *last, *pen;
|
||||
int ttl = -1;
|
||||
|
||||
for (last = pen = NULL, comma = arg; comma; comma = split(comma))
|
||||
@@ -4381,13 +4476,13 @@ err:
|
||||
if (pen != arg && atoi_check(last, &ttl))
|
||||
last = pen;
|
||||
|
||||
target = canonicalise_opt(last);
|
||||
|
||||
while (arg != last)
|
||||
{
|
||||
int arglen = strlen(arg);
|
||||
alias = canonicalise_opt(arg);
|
||||
|
||||
if (!target)
|
||||
target = canonicalise_opt(last);
|
||||
if (!alias || !target)
|
||||
{
|
||||
free(target);
|
||||
@@ -4690,7 +4785,7 @@ err:
|
||||
struct name_list *nl;
|
||||
if (!canon)
|
||||
{
|
||||
struct name_list *tmp = new->names, *next;
|
||||
struct name_list *tmp, *next;
|
||||
for (tmp = new->names; tmp; tmp = next)
|
||||
{
|
||||
next = tmp->next;
|
||||
@@ -5027,15 +5122,33 @@ static int one_file(char *file, int hard_opt)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int file_filter(const struct dirent *ent)
|
||||
{
|
||||
size_t lenfile = strlen(ent->d_name);
|
||||
|
||||
/* ignore emacs backups and dotfiles */
|
||||
|
||||
if (lenfile == 0 ||
|
||||
ent->d_name[lenfile - 1] == '~' ||
|
||||
(ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
|
||||
ent->d_name[0] == '.')
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
/* expand any name which is a directory */
|
||||
struct hostsfile *expand_filelist(struct hostsfile *list)
|
||||
{
|
||||
unsigned int i;
|
||||
struct hostsfile *ah;
|
||||
int entcnt, n;
|
||||
struct hostsfile *ah, *last, *next, **up;
|
||||
struct dirent **namelist;
|
||||
|
||||
/* find largest used index */
|
||||
for (i = SRC_AH, ah = list; ah; ah = ah->next)
|
||||
{
|
||||
last = ah;
|
||||
|
||||
if (i <= ah->index)
|
||||
i = ah->index + 1;
|
||||
|
||||
@@ -5051,46 +5164,48 @@ struct hostsfile *expand_filelist(struct hostsfile *list)
|
||||
struct stat buf;
|
||||
if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode))
|
||||
{
|
||||
DIR *dir_stream;
|
||||
struct dirent *ent;
|
||||
|
||||
/* don't read this as a file */
|
||||
ah->flags |= AH_INACTIVE;
|
||||
|
||||
if (!(dir_stream = opendir(ah->fname)))
|
||||
entcnt = scandir(ah->fname, &namelist, file_filter, alphasort);
|
||||
if (entcnt < 0)
|
||||
my_syslog(LOG_ERR, _("cannot access directory %s: %s"),
|
||||
ah->fname, strerror(errno));
|
||||
else
|
||||
{
|
||||
while ((ent = readdir(dir_stream)))
|
||||
for (n = 0; n < entcnt; n++)
|
||||
{
|
||||
ent = namelist[n];
|
||||
size_t lendir = strlen(ah->fname);
|
||||
size_t lenfile = strlen(ent->d_name);
|
||||
struct hostsfile *ah1;
|
||||
char *path;
|
||||
|
||||
/* ignore emacs backups and dotfiles */
|
||||
if (lenfile == 0 ||
|
||||
ent->d_name[lenfile - 1] == '~' ||
|
||||
(ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
|
||||
ent->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
/* see if we have an existing record.
|
||||
dir is ah->fname
|
||||
file is ent->d_name
|
||||
path to match is ah1->fname */
|
||||
|
||||
for (ah1 = list; ah1; ah1 = ah1->next)
|
||||
for (up = &list, ah1 = list; ah1; ah1 = next)
|
||||
{
|
||||
next = ah1->next;
|
||||
|
||||
if (lendir < strlen(ah1->fname) &&
|
||||
strstr(ah1->fname, ah->fname) == ah1->fname &&
|
||||
ah1->fname[lendir] == '/' &&
|
||||
strcmp(ah1->fname + lendir + 1, ent->d_name) == 0)
|
||||
{
|
||||
ah1->flags &= ~AH_INACTIVE;
|
||||
/* If found, remove from list to re-insert at the end.
|
||||
Unless it's already at the end. */
|
||||
if (last != ah1)
|
||||
*up = next;
|
||||
break;
|
||||
}
|
||||
|
||||
up = &ah1->next;
|
||||
}
|
||||
|
||||
/* make new record */
|
||||
@@ -5111,17 +5226,21 @@ struct hostsfile *expand_filelist(struct hostsfile *list)
|
||||
ah1->fname = path;
|
||||
ah1->index = i++;
|
||||
ah1->flags = AH_DIR;
|
||||
ah1->next = list;
|
||||
list = ah1;
|
||||
}
|
||||
|
||||
/* Edge case, may be the last in the list anyway */
|
||||
if (last != ah1)
|
||||
last->next = ah1;
|
||||
ah1->next = NULL;
|
||||
last = ah1;
|
||||
|
||||
/* inactivate record if not regular file */
|
||||
if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode))
|
||||
ah1->flags |= AH_INACTIVE;
|
||||
|
||||
}
|
||||
closedir(dir_stream);
|
||||
}
|
||||
free(namelist);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,13 +20,13 @@
|
||||
|
||||
#define LOG(...) \
|
||||
do { \
|
||||
my_syslog(LOG_WARNING, __VA_ARGS__); \
|
||||
my_syslog(LOG_DEBUG, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT(condition) \
|
||||
do { \
|
||||
if (!(condition)) \
|
||||
LOG("[pattern.c:%d] Assertion failure: %s", __LINE__, #condition); \
|
||||
my_syslog(LOG_ERR, _("[pattern.c:%d] Assertion failure: %s"), __LINE__, #condition); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
@@ -66,8 +66,8 @@ static int is_string_matching_glob_pattern(
|
||||
pattern_character -= 'a' - 'A';
|
||||
if (pattern_character == '*')
|
||||
{
|
||||
// zero-or-more-character wildcard
|
||||
// Try to match at value_index, otherwise restart at value_index + 1 next.
|
||||
/* zero-or-more-character wildcard */
|
||||
/* Try to match at value_index, otherwise restart at value_index + 1 next. */
|
||||
next_pattern_index = pattern_index;
|
||||
pattern_index++;
|
||||
if (value_index < num_value_bytes)
|
||||
@@ -78,7 +78,7 @@ static int is_string_matching_glob_pattern(
|
||||
}
|
||||
else
|
||||
{
|
||||
// ordinary character
|
||||
/* ordinary character */
|
||||
if (value_index < num_value_bytes)
|
||||
{
|
||||
char value_character = value[value_index];
|
||||
@@ -139,7 +139,7 @@ int is_valid_dns_name(const char *value)
|
||||
(*c < 'A' || *c > 'Z') &&
|
||||
(*c < 'a' || *c > 'z'))
|
||||
{
|
||||
LOG("Invalid DNS name: Invalid character %c.", *c);
|
||||
LOG(_("Invalid DNS name: Invalid character %c."), *c);
|
||||
return 0;
|
||||
}
|
||||
if (*c)
|
||||
@@ -148,12 +148,12 @@ int is_valid_dns_name(const char *value)
|
||||
{
|
||||
if (!*c || *c == '.')
|
||||
{
|
||||
LOG("Invalid DNS name: Empty label.");
|
||||
LOG(_("Invalid DNS name: Empty label."));
|
||||
return 0;
|
||||
}
|
||||
if (*c == '-')
|
||||
{
|
||||
LOG("Invalid DNS name: Label starts with hyphen.");
|
||||
LOG(_("Invalid DNS name: Label starts with hyphen."));
|
||||
return 0;
|
||||
}
|
||||
label = c;
|
||||
@@ -167,13 +167,13 @@ int is_valid_dns_name(const char *value)
|
||||
{
|
||||
if (c[-1] == '-')
|
||||
{
|
||||
LOG("Invalid DNS name: Label ends with hyphen.");
|
||||
LOG(_("Invalid DNS name: Label ends with hyphen."));
|
||||
return 0;
|
||||
}
|
||||
size_t num_label_bytes = (size_t) (c - label);
|
||||
if (num_label_bytes > 63)
|
||||
{
|
||||
LOG("Invalid DNS name: Label is too long (%zu).", num_label_bytes);
|
||||
LOG(_("Invalid DNS name: Label is too long (%zu)."), num_label_bytes);
|
||||
return 0;
|
||||
}
|
||||
num_labels++;
|
||||
@@ -181,12 +181,12 @@ int is_valid_dns_name(const char *value)
|
||||
{
|
||||
if (num_labels < 2)
|
||||
{
|
||||
LOG("Invalid DNS name: Not enough labels (%zu).", num_labels);
|
||||
LOG(_("Invalid DNS name: Not enough labels (%zu)."), num_labels);
|
||||
return 0;
|
||||
}
|
||||
if (is_label_numeric)
|
||||
{
|
||||
LOG("Invalid DNS name: Final label is fully numeric.");
|
||||
LOG(_("Invalid DNS name: Final label is fully numeric."));
|
||||
return 0;
|
||||
}
|
||||
if (num_label_bytes == 5 &&
|
||||
@@ -196,12 +196,12 @@ int is_valid_dns_name(const char *value)
|
||||
(label[3] == 'a' || label[3] == 'A') &&
|
||||
(label[4] == 'l' || label[4] == 'L'))
|
||||
{
|
||||
LOG("Invalid DNS name: \"local\" pseudo-TLD.");
|
||||
LOG(_("Invalid DNS name: \"local\" pseudo-TLD."));
|
||||
return 0;
|
||||
}
|
||||
if (num_bytes < 1 || num_bytes > 253)
|
||||
{
|
||||
LOG("DNS name has invalid length (%zu).", num_bytes);
|
||||
LOG(_("DNS name has invalid length (%zu)."), num_bytes);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@@ -249,13 +249,13 @@ int is_valid_dns_name_pattern(const char *value)
|
||||
for (const char *c = value;; c++)
|
||||
{
|
||||
if (*c &&
|
||||
*c != '*' && // Wildcard.
|
||||
*c != '*' && /* Wildcard. */
|
||||
*c != '-' && *c != '.' &&
|
||||
(*c < '0' || *c > '9') &&
|
||||
(*c < 'A' || *c > 'Z') &&
|
||||
(*c < 'a' || *c > 'z'))
|
||||
{
|
||||
LOG("Invalid DNS name pattern: Invalid character %c.", *c);
|
||||
LOG(_("Invalid DNS name pattern: Invalid character %c."), *c);
|
||||
return 0;
|
||||
}
|
||||
if (*c && *c != '*')
|
||||
@@ -264,12 +264,12 @@ int is_valid_dns_name_pattern(const char *value)
|
||||
{
|
||||
if (!*c || *c == '.')
|
||||
{
|
||||
LOG("Invalid DNS name pattern: Empty label.");
|
||||
LOG(_("Invalid DNS name pattern: Empty label."));
|
||||
return 0;
|
||||
}
|
||||
if (*c == '-')
|
||||
{
|
||||
LOG("Invalid DNS name pattern: Label starts with hyphen.");
|
||||
LOG(_("Invalid DNS name pattern: Label starts with hyphen."));
|
||||
return 0;
|
||||
}
|
||||
label = c;
|
||||
@@ -282,7 +282,7 @@ int is_valid_dns_name_pattern(const char *value)
|
||||
{
|
||||
if (num_wildcards >= 2)
|
||||
{
|
||||
LOG("Invalid DNS name pattern: Wildcard character used more than twice per label.");
|
||||
LOG(_("Invalid DNS name pattern: Wildcard character used more than twice per label."));
|
||||
return 0;
|
||||
}
|
||||
num_wildcards++;
|
||||
@@ -292,13 +292,13 @@ int is_valid_dns_name_pattern(const char *value)
|
||||
{
|
||||
if (c[-1] == '-')
|
||||
{
|
||||
LOG("Invalid DNS name pattern: Label ends with hyphen.");
|
||||
LOG(_("Invalid DNS name pattern: Label ends with hyphen."));
|
||||
return 0;
|
||||
}
|
||||
size_t num_label_bytes = (size_t) (c - label) - num_wildcards;
|
||||
if (num_label_bytes > 63)
|
||||
{
|
||||
LOG("Invalid DNS name pattern: Label is too long (%zu).", num_label_bytes);
|
||||
LOG(_("Invalid DNS name pattern: Label is too long (%zu)."), num_label_bytes);
|
||||
return 0;
|
||||
}
|
||||
num_labels++;
|
||||
@@ -306,17 +306,17 @@ int is_valid_dns_name_pattern(const char *value)
|
||||
{
|
||||
if (num_labels < 2)
|
||||
{
|
||||
LOG("Invalid DNS name pattern: Not enough labels (%zu).", num_labels);
|
||||
LOG(_("Invalid DNS name pattern: Not enough labels (%zu)."), num_labels);
|
||||
return 0;
|
||||
}
|
||||
if (num_wildcards != 0 || previous_label_has_wildcard)
|
||||
{
|
||||
LOG("Invalid DNS name pattern: Wildcard within final two labels.");
|
||||
LOG(_("Invalid DNS name pattern: Wildcard within final two labels."));
|
||||
return 0;
|
||||
}
|
||||
if (is_label_numeric)
|
||||
{
|
||||
LOG("Invalid DNS name pattern: Final label is fully numeric.");
|
||||
LOG(_("Invalid DNS name pattern: Final label is fully numeric."));
|
||||
return 0;
|
||||
}
|
||||
if (num_label_bytes == 5 &&
|
||||
@@ -326,12 +326,12 @@ int is_valid_dns_name_pattern(const char *value)
|
||||
(label[3] == 'a' || label[3] == 'A') &&
|
||||
(label[4] == 'l' || label[4] == 'L'))
|
||||
{
|
||||
LOG("Invalid DNS name pattern: \"local\" pseudo-TLD.");
|
||||
LOG(_("Invalid DNS name pattern: \"local\" pseudo-TLD."));
|
||||
return 0;
|
||||
}
|
||||
if (num_bytes < 1 || num_bytes > 253)
|
||||
{
|
||||
LOG("DNS name pattern has invalid length after removing wildcards (%zu).", num_bytes);
|
||||
LOG(_("DNS name pattern has invalid length after removing wildcards (%zu)."), num_bytes);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
@@ -746,6 +746,8 @@ static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void
|
||||
add 7 to round up */
|
||||
int len = (maclen + 9) >> 3;
|
||||
unsigned char *p = expand(len << 3);
|
||||
if (!p)
|
||||
return 1;
|
||||
memset(p, 0, len << 3);
|
||||
*p++ = ICMP6_OPT_SOURCE_MAC;
|
||||
*p++ = len;
|
||||
|
||||
768
src/rfc1035.c
768
src/rfc1035.c
File diff suppressed because it is too large
Load Diff
@@ -600,7 +600,7 @@ void check_tftp_listeners(time_t now)
|
||||
/* Wrong source address. See rfc1350 para 4. */
|
||||
prettyprint_addr(&peer, daemon->addrbuff);
|
||||
len = tftp_err(ERR_TID, daemon->packet, _("ignoring packet from %s (TID mismatch)"), daemon->addrbuff);
|
||||
sendto(transfer->sockfd, daemon->packet, len, 0, &peer.sa, sa_len(&peer));
|
||||
while(retry_send(sendto(transfer->sockfd, daemon->packet, len, 0, &peer.sa, sa_len(&peer))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
74
src/ubus.c
74
src/ubus.c
@@ -84,7 +84,7 @@ static void ubus_destroy(struct ubus_context *ubus)
|
||||
ubus_free(ubus);
|
||||
daemon->ubus = NULL;
|
||||
|
||||
// Forces re-initialization when we're reusing the same definitions later on.
|
||||
/* Forces re-initialization when we're reusing the same definitions later on. */
|
||||
ubus_object.id = 0;
|
||||
ubus_object_type.id = 0;
|
||||
}
|
||||
@@ -171,6 +171,16 @@ void check_ubus_listeners()
|
||||
}
|
||||
}
|
||||
|
||||
#define CHECK(stmt) \
|
||||
do { \
|
||||
int e = (stmt); \
|
||||
if (e) \
|
||||
{ \
|
||||
my_syslog(LOG_ERR, _("UBus command failed: %d (%s)"), e, #stmt); \
|
||||
return (UBUS_STATUS_UNKNOWN_ERROR); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
@@ -181,12 +191,13 @@ static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj
|
||||
(void)method;
|
||||
(void)msg;
|
||||
|
||||
blob_buf_init(&b, BLOBMSG_TYPE_TABLE);
|
||||
CHECK(blob_buf_init(&b, BLOBMSG_TYPE_TABLE));
|
||||
|
||||
for (i=0; i < __METRIC_MAX; i++)
|
||||
blobmsg_add_u32(&b, get_metric_name(i), daemon->metrics[i]);
|
||||
CHECK(blobmsg_add_u32(&b, get_metric_name(i), daemon->metrics[i]));
|
||||
|
||||
return ubus_send_reply(ctx, req, b.head);
|
||||
CHECK(ubus_send_reply(ctx, req, b.head));
|
||||
return UBUS_STATUS_OK;
|
||||
}
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
@@ -305,66 +316,71 @@ fail:
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef CHECK
|
||||
|
||||
#define CHECK(stmt) \
|
||||
do { \
|
||||
int e = (stmt); \
|
||||
if (e) \
|
||||
{ \
|
||||
my_syslog(LOG_ERR, _("UBus command failed: %d (%s)"), e, #stmt); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface)
|
||||
{
|
||||
struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
|
||||
int ret;
|
||||
|
||||
if (!ubus || !ubus_object.has_subscribers)
|
||||
return;
|
||||
|
||||
blob_buf_init(&b, BLOBMSG_TYPE_TABLE);
|
||||
CHECK(blob_buf_init(&b, BLOBMSG_TYPE_TABLE));
|
||||
if (mac)
|
||||
blobmsg_add_string(&b, "mac", mac);
|
||||
CHECK(blobmsg_add_string(&b, "mac", mac));
|
||||
if (ip)
|
||||
blobmsg_add_string(&b, "ip", ip);
|
||||
CHECK(blobmsg_add_string(&b, "ip", ip));
|
||||
if (name)
|
||||
blobmsg_add_string(&b, "name", name);
|
||||
CHECK(blobmsg_add_string(&b, "name", name));
|
||||
if (interface)
|
||||
blobmsg_add_string(&b, "interface", interface);
|
||||
CHECK(blobmsg_add_string(&b, "interface", interface));
|
||||
|
||||
ret = ubus_notify(ubus, &ubus_object, type, b.head, -1);
|
||||
if (ret)
|
||||
my_syslog(LOG_ERR, _("Failed to send UBus event: %s"), ubus_strerror(ret));
|
||||
CHECK(ubus_notify(ubus, &ubus_object, type, b.head, -1));
|
||||
}
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
void ubus_event_bcast_connmark_allowlist_refused(u32 mark, const char *name)
|
||||
{
|
||||
struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
|
||||
int ret;
|
||||
|
||||
if (!ubus || !ubus_object.has_subscribers)
|
||||
return;
|
||||
|
||||
blob_buf_init(&b, 0);
|
||||
blobmsg_add_u32(&b, "mark", mark);
|
||||
blobmsg_add_string(&b, "name", name);
|
||||
CHECK(blob_buf_init(&b, 0));
|
||||
CHECK(blobmsg_add_u32(&b, "mark", mark));
|
||||
CHECK(blobmsg_add_string(&b, "name", name));
|
||||
|
||||
ret = ubus_notify(ubus, &ubus_object, "connmark-allowlist.refused", b.head, -1);
|
||||
if (ret)
|
||||
my_syslog(LOG_ERR, _("Failed to send UBus event: %s"), ubus_strerror(ret));
|
||||
CHECK(ubus_notify(ubus, &ubus_object, "connmark-allowlist.refused", b.head, -1));
|
||||
}
|
||||
|
||||
void ubus_event_bcast_connmark_allowlist_resolved(u32 mark, const char *name, const char *value, u32 ttl)
|
||||
{
|
||||
struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
|
||||
int ret;
|
||||
|
||||
if (!ubus || !ubus_object.has_subscribers)
|
||||
return;
|
||||
|
||||
blob_buf_init(&b, 0);
|
||||
blobmsg_add_u32(&b, "mark", mark);
|
||||
blobmsg_add_string(&b, "name", name);
|
||||
blobmsg_add_string(&b, "value", value);
|
||||
blobmsg_add_u32(&b, "ttl", ttl);
|
||||
CHECK(blob_buf_init(&b, 0));
|
||||
CHECK(blobmsg_add_u32(&b, "mark", mark));
|
||||
CHECK(blobmsg_add_string(&b, "name", name));
|
||||
CHECK(blobmsg_add_string(&b, "value", value));
|
||||
CHECK(blobmsg_add_u32(&b, "ttl", ttl));
|
||||
|
||||
ret = ubus_notify(ubus, &ubus_object, "connmark-allowlist.resolved", b.head, /* timeout: */ 1000);
|
||||
if (ret)
|
||||
my_syslog(LOG_ERR, _("Failed to send UBus event: %s"), ubus_strerror(ret));
|
||||
/* Set timeout to allow UBus subscriber to configure firewall rules before returning. */
|
||||
CHECK(ubus_notify(ubus, &ubus_object, "connmark-allowlist.resolved", b.head, /* timeout: */ 1000));
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef CHECK
|
||||
|
||||
#endif /* HAVE_UBUS */
|
||||
|
||||
73
src/util.c
73
src/util.c
@@ -115,7 +115,8 @@ u64 rand64(void)
|
||||
return (u64)out[outleft+1] + (((u64)out[outleft]) << 32);
|
||||
}
|
||||
|
||||
/* returns 2 if names is OK but contains one or more underscores */
|
||||
/* returns 1 if name is OK and ascii printable
|
||||
* returns 2 if name should be processed by IDN */
|
||||
static int check_name(char *in)
|
||||
{
|
||||
/* remove trailing .
|
||||
@@ -123,7 +124,9 @@ static int check_name(char *in)
|
||||
size_t dotgap = 0, l = strlen(in);
|
||||
char c;
|
||||
int nowhite = 0;
|
||||
int idn_encode = 0;
|
||||
int hasuscore = 0;
|
||||
int hasucase = 0;
|
||||
|
||||
if (l == 0 || l > MAXDNAME) return 0;
|
||||
|
||||
@@ -136,28 +139,49 @@ static int check_name(char *in)
|
||||
for (; (c = *in); in++)
|
||||
{
|
||||
if (c == '.')
|
||||
dotgap = 0;
|
||||
dotgap = 0;
|
||||
else if (++dotgap > MAXLABEL)
|
||||
return 0;
|
||||
return 0;
|
||||
else if (isascii((unsigned char)c) && iscntrl((unsigned char)c))
|
||||
/* iscntrl only gives expected results for ascii */
|
||||
return 0;
|
||||
#if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
|
||||
/* iscntrl only gives expected results for ascii */
|
||||
return 0;
|
||||
else if (!isascii((unsigned char)c))
|
||||
return 0;
|
||||
#if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
|
||||
return 0;
|
||||
#else
|
||||
idn_encode = 1;
|
||||
#endif
|
||||
else if (c != ' ')
|
||||
{
|
||||
nowhite = 1;
|
||||
if (c == '_')
|
||||
hasuscore = 1;
|
||||
}
|
||||
{
|
||||
nowhite = 1;
|
||||
#if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
|
||||
if (c == '_')
|
||||
hasuscore = 1;
|
||||
#else
|
||||
(void)hasuscore;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
hasucase = 1;
|
||||
#else
|
||||
(void)hasucase;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (!nowhite)
|
||||
return 0;
|
||||
|
||||
return hasuscore ? 2 : 1;
|
||||
#if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
|
||||
/* Older libidn2 strips underscores, so don't do IDN processing
|
||||
if the name has an underscore unless it also has non-ascii characters. */
|
||||
idn_encode = idn_encode || (hasucase && !hasuscore);
|
||||
#else
|
||||
idn_encode = idn_encode || hasucase;
|
||||
#endif
|
||||
|
||||
return (idn_encode) ? 2 : 1;
|
||||
}
|
||||
|
||||
/* Hostnames have a more limited valid charset than domain names
|
||||
@@ -204,12 +228,8 @@ char *canonicalise(char *in, int *nomem)
|
||||
if (!(rc = check_name(in)))
|
||||
return NULL;
|
||||
|
||||
#if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
|
||||
/* older libidn2 strips underscores, so don't do IDN processing
|
||||
if the name has an underscore (check_name() returned 2) */
|
||||
if (rc != 2)
|
||||
#endif
|
||||
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
|
||||
if (rc == 2)
|
||||
{
|
||||
# ifdef HAVE_LIBIDN2
|
||||
rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL);
|
||||
@@ -234,12 +254,14 @@ char *canonicalise(char *in, int *nomem)
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
(void)rc;
|
||||
#endif
|
||||
|
||||
if ((ret = whine_malloc(strlen(in)+1)))
|
||||
strcpy(ret, in);
|
||||
else if (nomem)
|
||||
*nomem = 1;
|
||||
*nomem = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -408,13 +430,12 @@ int hostname_issubdomain(char *a, char *b)
|
||||
time_t dnsmasq_time(void)
|
||||
{
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
struct tms dummy;
|
||||
static long tps = 0;
|
||||
struct timespec ts;
|
||||
|
||||
if (tps == 0)
|
||||
tps = sysconf(_SC_CLK_TCK);
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
|
||||
die(_("cannot read monotonic clock: %s"), NULL, EC_MISC);
|
||||
|
||||
return (time_t)(times(&dummy)/tps);
|
||||
return ts.tv_sec;
|
||||
#else
|
||||
return time(NULL);
|
||||
#endif
|
||||
@@ -528,7 +549,7 @@ void prettyprint_time(char *buf, unsigned int t)
|
||||
if ((x = (t/60)%60))
|
||||
p += sprintf(&buf[p], "%um", x);
|
||||
if ((x = t%60))
|
||||
p += sprintf(&buf[p], "%us", x);
|
||||
sprintf(&buf[p], "%us", x);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,7 +595,7 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||
int j, bytes = (1 + (r - in))/2;
|
||||
for (j = 0; j < bytes; j++)
|
||||
{
|
||||
char sav = sav;
|
||||
char sav;
|
||||
if (j < bytes - 1)
|
||||
{
|
||||
sav = in[(j+1)*2];
|
||||
|
||||
Reference in New Issue
Block a user