Compare commits
26 Commits
v2.87test1
...
v2.87test2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
14
CHANGELOG
14
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
|
||||
@@ -92,6 +103,9 @@ version 2.86
|
||||
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.
|
||||
|
||||
7
Makefile
7
Makefile
@@ -70,6 +70,7 @@ 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`
|
||||
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 ' ')
|
||||
@@ -82,7 +83,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
|
||||
@@ -91,7 +92,7 @@ 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_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 :
|
||||
@@ -116,7 +117,7 @@ all-i18n : $(BUILDDIR)
|
||||
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_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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -505,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.
|
||||
@@ -549,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
|
||||
@@ -1036,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
|
||||
@@ -1135,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
|
||||
@@ -1923,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
|
||||
|
||||
10
src/auth.c
10
src/auth.c
@@ -417,7 +417,6 @@ 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, 0);
|
||||
@@ -433,7 +432,6 @@ 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>", 0);
|
||||
}
|
||||
else if (qtype == T_AXFR)
|
||||
@@ -469,7 +467,6 @@ 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>", 0);
|
||||
}
|
||||
@@ -477,7 +474,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
{
|
||||
auth = 1;
|
||||
ns = 1; /* inhibits auth section */
|
||||
found = 1;
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>", 0);
|
||||
}
|
||||
}
|
||||
@@ -498,7 +494,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
*cut = '.'; /* restore domain part */
|
||||
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))
|
||||
@@ -519,7 +514,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr))))
|
||||
{
|
||||
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
|
||||
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))
|
||||
@@ -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");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -483,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);
|
||||
@@ -1597,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);
|
||||
@@ -2059,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;
|
||||
@@ -2067,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)
|
||||
|
||||
@@ -88,7 +88,7 @@ int match_netid_wild(struct dhcp_netid *check, struct dhcp_netid *pool)
|
||||
for (; check; check = check->next)
|
||||
{
|
||||
const int check_len = strlen(check->net);
|
||||
const int is_wc = (check->net[check_len - 1] == '*');
|
||||
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] != '#')
|
||||
|
||||
@@ -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 */
|
||||
@@ -1297,8 +1303,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
|
||||
@@ -1582,6 +1588,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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -1017,7 +1018,9 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -411,7 +419,8 @@ 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);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -151,11 +151,11 @@ static void server_send_log(struct server *server, int fd,
|
||||
|
||||
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;
|
||||
@@ -556,12 +556,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;
|
||||
@@ -572,24 +593,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)))
|
||||
@@ -698,7 +707,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;
|
||||
@@ -1863,7 +1872,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
|
||||
@@ -2274,7 +2283,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;
|
||||
|
||||
|
||||
@@ -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
|
||||
294
src/option.c
294
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,132 @@ 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)
|
||||
{
|
||||
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);
|
||||
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");
|
||||
|
||||
for (i = 0; i < addrbytes; i++)
|
||||
if (((u8 *)addr4)[3-i] != 0)
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
||||
if (i != addrbytes || (((u8 *)addr4)[3-addrbytes] & ((1 << addrbits) - 1)) != 0)
|
||||
return _("address part not zero");
|
||||
|
||||
size = size & ~0x7;
|
||||
|
||||
if (rem != 0)
|
||||
count = 1 << (8 - rem);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
*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");
|
||||
|
||||
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);
|
||||
for (i = 0; i < addrbytes; i++)
|
||||
if (addr6->s6_addr[15-i] != 0)
|
||||
break;
|
||||
|
||||
if (i != addrbytes || (addr6->s6_addr[15-addrbytes] & ((1 << addrbits) - 1)) != 0)
|
||||
return _("address part not zero");
|
||||
|
||||
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");
|
||||
|
||||
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 +1912,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 +2080,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 +2391,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 +2432,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 +2718,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 +2727,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 +2766,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)
|
||||
@@ -2708,11 +2790,18 @@ 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 (strlen(domain) == 0 && lastdomain)
|
||||
flags |= SERV_FOR_NODOTS;
|
||||
else
|
||||
flags &= ~SERV_FOR_NODOTS;
|
||||
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);
|
||||
|
||||
@@ -2729,57 +2818,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;
|
||||
@@ -2824,19 +2918,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
|
||||
@@ -3616,6 +3715,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;
|
||||
}
|
||||
}
|
||||
@@ -3779,16 +3879,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] == '*')
|
||||
{
|
||||
@@ -3992,6 +4092,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);
|
||||
}
|
||||
|
||||
@@ -4367,7 +4469,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))
|
||||
@@ -4382,13 +4484,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);
|
||||
@@ -4691,7 +4793,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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -540,8 +540,8 @@ static int print_txt(struct dns_header *header, const size_t qlen, char *name,
|
||||
expired and cleaned out that way.
|
||||
Return 1 if we reject an address because it look like part of dns-rebinding attack. */
|
||||
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)
|
||||
struct ipsets *ipsets, struct ipsets *nftsets, int is_sign, int check_rebind,
|
||||
int no_cache_dnssec, int secure, int *doctored)
|
||||
{
|
||||
unsigned char *p, *p1, *endrr, *namep;
|
||||
int j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
|
||||
@@ -551,6 +551,11 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
char **ipsets_cur;
|
||||
#else
|
||||
(void)ipsets; /* unused */
|
||||
#endif
|
||||
#ifdef HAVE_NFTSET
|
||||
char **nftsets_cur;
|
||||
#else
|
||||
(void)nftsets; /* unused */
|
||||
#endif
|
||||
int found = 0, cname_count = CNAME_CHAIN;
|
||||
struct crec *cpp = NULL;
|
||||
@@ -843,14 +848,15 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
|
||||
#ifdef HAVE_IPSET
|
||||
if (ipsets && (flags & (F_IPV4 | F_IPV6)))
|
||||
{
|
||||
ipsets_cur = ipsets;
|
||||
while (*ipsets_cur)
|
||||
{
|
||||
log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, name, &addr, *ipsets_cur, 0);
|
||||
add_to_ipset(*ipsets_cur++, &addr, flags, 0);
|
||||
}
|
||||
}
|
||||
for (ipsets_cur = ipsets->sets; *ipsets_cur; ipsets_cur++)
|
||||
if (add_to_ipset(*ipsets_cur, &addr, flags, 0) == 0)
|
||||
log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, ipsets->domain, &addr, *ipsets_cur, 1);
|
||||
#endif
|
||||
#ifdef HAVE_NFTSET
|
||||
if (nftsets && (flags & (F_IPV4 | F_IPV6)))
|
||||
for (nftsets_cur = nftsets->sets; *nftsets_cur; nftsets_cur++)
|
||||
if (add_to_nftset(*nftsets_cur, &addr, flags, 0) == 0)
|
||||
log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, nftsets->domain, &addr, *nftsets_cur, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -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))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -550,7 +550,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -596,7 +596,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