mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-04 13:48:30 +00:00
Compare commits
32
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8389b943d3 | ||
|
|
f2266d9678 | ||
|
|
56bd806978 | ||
|
|
ac7eeea44d | ||
|
|
b741059549 | ||
|
|
cbd984287f | ||
|
|
32e15c3f45 | ||
|
|
f0dc324e35 | ||
|
|
f83c6cf51a | ||
|
|
c068b3ae2f | ||
|
|
adf9dec1e6 | ||
|
|
767d9cbd96 | ||
|
|
e7ccd95c04 | ||
|
|
719f79a8fd | ||
|
|
96f6444958 | ||
|
|
df25f204ba | ||
|
|
8acdc3ede7 | ||
|
|
857b445522 | ||
|
|
5bcca1219a | ||
|
|
4558c26fcd | ||
|
|
a92c6d77dc | ||
|
|
0c95a5ff53 | ||
|
|
cb6d06bb54 | ||
|
|
3ef955c85a | ||
|
|
5e95c16c32 | ||
|
|
4205e2ebcf | ||
|
|
9d806c51c2 | ||
|
|
a38bb31727 | ||
|
|
8a1ef367e2 | ||
|
|
1291865c92 | ||
|
|
a9ebbee7b6 | ||
|
|
06df5ad7d0 |
No files matched your search
@@ -76,6 +76,12 @@ version 2.86
|
||||
Disallowed queries are not forwarded; they are rejected
|
||||
with a REFUSED error code.
|
||||
|
||||
Allow smaller then 64 prefix lengths in synth-domain, with caveats.
|
||||
--synth-domain=1234:4567::/56,example.com is now valid.
|
||||
|
||||
Make domains generated by --synth-domain appear in replies
|
||||
when in authoritative mode.
|
||||
|
||||
|
||||
version 2.85
|
||||
Fix problem with DNS retries in 2.83/2.84.
|
||||
|
||||
+25
-10
@@ -327,8 +327,8 @@ are re-written. So
|
||||
maps 192.168.0.10->192.168.0.40 to 10.0.0.10->10.0.0.40
|
||||
.TP
|
||||
.B \-B, --bogus-nxdomain=<ipaddr>[/prefix]
|
||||
Transform replies which contain the IP specified address or subnet into "No such
|
||||
domain" replies. This is intended to counteract a devious move made by
|
||||
Transform replies which contain the specified address or subnet into "No such
|
||||
domain" replies. IPv4 and IPv6 are supported. This is intended to counteract a devious move made by
|
||||
Verisign in September 2003 when they started returning the address of
|
||||
an advertising web page in response to queries for unregistered names,
|
||||
instead of the correct NXDOMAIN response. This option tells dnsmasq to
|
||||
@@ -336,7 +336,7 @@ fake the correct response when it sees this behaviour. As at Sept 2003
|
||||
the IP address being returned by Verisign is 64.94.110.11
|
||||
.TP
|
||||
.B --ignore-address=<ipaddr>[/prefix]
|
||||
Ignore replies to A-record queries which include the specified address or subnet.
|
||||
Ignore replies to A or AAAA queries which include the specified address or subnet.
|
||||
No error is generated, dnsmasq simply continues to listen for another reply.
|
||||
This is useful to defeat blocking strategies which rely on quickly supplying a
|
||||
forged answer to a DNS request for certain domain, before the correct answer can arrive.
|
||||
@@ -460,13 +460,22 @@ repeated domain or ipaddr parts as required.
|
||||
More specific domains take precedence over less specific domains, so:
|
||||
.B --server=/google.com/1.2.3.4
|
||||
.B --server=/www.google.com/2.3.4.5
|
||||
will send queries for *.google.com to 1.2.3.4, except *www.google.com,
|
||||
which will go to 2.3.4.5
|
||||
will send queries for google.com and gmail.google.com to 1.2.3.4, but www.google.com
|
||||
will go to 2.3.4.5
|
||||
|
||||
Matching of domains is normally done on complete labels, so /google.com/ matches google.com and www.google.com
|
||||
but NOT supergoogle.com. This can be overridden with a * at the start of a pattern only: /*google.com/
|
||||
will match google.com and www.google.com AND supergoogle.com. The non-wildcard form has priority, so
|
||||
if /google.com/ and /*google.com/ are both specified then google.com and www.google.com will match /google.com/
|
||||
and /*google.com/ will only match supergoogle.com.
|
||||
|
||||
For historical reasons, the pattern /.google.com/ is equivalent to /google.com/ if you wish to match any subdomain
|
||||
of google.com but NOT google.com itself, use /*.google.com/
|
||||
|
||||
The special server address '#' means, "use the standard servers", so
|
||||
.B --server=/google.com/1.2.3.4
|
||||
.B --server=/www.google.com/#
|
||||
will send queries for *.google.com to 1.2.3.4, except *www.google.com which will
|
||||
will send queries for google.com and its subdomains to 1.2.3.4, except www.google.com (and its subdomains) which will
|
||||
be forwarded as usual.
|
||||
|
||||
Also permitted is a -S
|
||||
@@ -696,7 +705,8 @@ configured a zero is added in front of the label. ::1 becomes 0--1.
|
||||
V4 mapped IPv6 addresses, which have a representation like ::ffff:1.2.3.4 are handled specially, and become like 0--ffff-1-2-3-4
|
||||
|
||||
The address range can be of the form
|
||||
<ip address>,<ip address> or <ip address>/<netmask> in both forms of the option.
|
||||
<start address>,<end address> or <ip address>/<prefix-length> in both forms of the option. For IPv6 the start and end addresses
|
||||
must fall in the same /64 network, or prefix-length must be greater than or equal to 64 except that shorter prefix lengths than 64 are allowed only if non-sequential names are in use.
|
||||
.TP
|
||||
.B --dumpfile=<path/to/file>
|
||||
Specify the location of a pcap-format file which dnsmasq uses to dump copies of network packets for debugging purposes. If the file exists when dnsmasq starts, it is not deleted; new packets are added to the end.
|
||||
@@ -1603,10 +1613,11 @@ tried. This flag disables this check. Use with caution.
|
||||
Extra logging for DHCP: log all the options sent to DHCP clients and
|
||||
the tags used to determine them.
|
||||
.TP
|
||||
.B --quiet-dhcp, --quiet-dhcp6, --quiet-ra
|
||||
.B --quiet-dhcp, --quiet-dhcp6, --quiet-ra, --quiet-tftp
|
||||
Suppress logging of the routine operation of these protocols. Errors and
|
||||
problems will still be logged. \fB--quiet-dhcp\fP and quiet-dhcp6 are
|
||||
over-ridden by \fB--log-dhcp\fP.
|
||||
problems will still be logged. \fB--quiet-tftp\fP does not consider file not
|
||||
found to be an error. \fB--quiet-dhcp\fP and quiet-dhcp6 are over-ridden by
|
||||
\fB--log-dhcp\fP.
|
||||
.TP
|
||||
.B \-l, --dhcp-leasefile=<path>
|
||||
Use the specified file to store DHCP lease information.
|
||||
@@ -2408,6 +2419,10 @@ following data is used to populate the authoritative zone.
|
||||
.B --mx-host, --srv-host, --dns-rr, --txt-record, --naptr-record, --caa-record,
|
||||
as long as the record names are in the authoritative domain.
|
||||
.PP
|
||||
.B --synth-domain
|
||||
as long as the domain is in the authoritative zone and, for
|
||||
reverse (PTR) queries, the address is in the relevant subnet.
|
||||
.PP
|
||||
.B --cname
|
||||
as long as the record name is in the authoritative domain. If the
|
||||
target of the CNAME is unqualified, then it is qualified with the
|
||||
|
||||
+38
-1
@@ -105,7 +105,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
int nameoffset, axfroffset = 0;
|
||||
int q, anscount = 0, authcount = 0;
|
||||
struct crec *crecp;
|
||||
int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0;
|
||||
int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0, out_of_zone = 0;
|
||||
struct auth_zone *zone = NULL;
|
||||
struct addrlist *subnet = NULL;
|
||||
char *cut;
|
||||
@@ -146,6 +146,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (qclass != C_IN)
|
||||
{
|
||||
auth = 0;
|
||||
out_of_zone = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -159,6 +160,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
if (!zone)
|
||||
{
|
||||
out_of_zone = 1;
|
||||
auth = 0;
|
||||
continue;
|
||||
}
|
||||
@@ -253,6 +255,17 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
} while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
|
||||
|
||||
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);
|
||||
found = 1;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
T_PTR, C_IN, "d", name))
|
||||
anscount++;
|
||||
}
|
||||
|
||||
if (found)
|
||||
nxdomain = 0;
|
||||
else
|
||||
@@ -273,6 +286,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
if (!zone)
|
||||
{
|
||||
out_of_zone = 1;
|
||||
auth = 0;
|
||||
continue;
|
||||
}
|
||||
@@ -400,6 +414,17 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && is_name_synthetic(flag, name, &addr) )
|
||||
{
|
||||
found = 1;
|
||||
nxdomain = 0;
|
||||
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN, qtype == T_A ? "4" : "6", &addr))
|
||||
anscount++;
|
||||
}
|
||||
|
||||
if (!cut)
|
||||
{
|
||||
@@ -855,10 +880,22 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
SET_RCODE(header, NXDOMAIN);
|
||||
else
|
||||
SET_RCODE(header, NOERROR); /* no error */
|
||||
|
||||
header->ancount = htons(anscount);
|
||||
header->nscount = htons(authcount);
|
||||
header->arcount = htons(0);
|
||||
|
||||
if (!local_query && out_of_zone)
|
||||
{
|
||||
SET_RCODE(header, REFUSED);
|
||||
header->ancount = htons(0);
|
||||
header->nscount = htons(0);
|
||||
addr.log.rcode = REFUSED;
|
||||
addr.log.ede = EDE_NOT_AUTH;
|
||||
log_query(F_UPSTREAM | F_RCODE, "error", &addr, NULL);
|
||||
return resize_packet(header, ansp - (unsigned char *)header, NULL, 0);
|
||||
}
|
||||
|
||||
/* Advertise our packet size limit in our reply */
|
||||
if (have_pseudoheader)
|
||||
return add_pseudoheader(header, ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
|
||||
+15
-14
@@ -1602,18 +1602,18 @@ int cache_make_stat(struct txt_record *t)
|
||||
case TXT_STAT_SERVERS:
|
||||
/* sum counts from different records for same server */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
serv->flags &= ~SERV_COUNTED;
|
||||
serv->flags &= ~SERV_MARK;
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (!(serv->flags & SERV_COUNTED))
|
||||
if (!(serv->flags & SERV_MARK))
|
||||
{
|
||||
char *new, *lenp;
|
||||
int port, newlen, bytes_avail, bytes_needed;
|
||||
unsigned int queries = 0, failed_queries = 0;
|
||||
for (serv1 = serv; serv1; serv1 = serv1->next)
|
||||
if (!(serv1->flags & SERV_COUNTED) && sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
if (!(serv1->flags & SERV_MARK) && sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
{
|
||||
serv1->flags |= SERV_COUNTED;
|
||||
serv1->flags |= SERV_MARK;
|
||||
queries += serv1->queries;
|
||||
failed_queries += serv1->failed_queries;
|
||||
}
|
||||
@@ -1641,6 +1641,7 @@ int cache_make_stat(struct txt_record *t)
|
||||
}
|
||||
t->txt = (unsigned char *)buff;
|
||||
t->len = p - buff;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1683,24 +1684,24 @@ void dump_cache(time_t now)
|
||||
|
||||
/* sum counts from different records for same server */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
serv->flags &= ~SERV_COUNTED;
|
||||
serv->flags &= ~SERV_MARK;
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (!(serv->flags & SERV_COUNTED))
|
||||
if (!(serv->flags & SERV_MARK))
|
||||
{
|
||||
int port;
|
||||
unsigned int queries = 0, failed_queries = 0;
|
||||
for (serv1 = serv; serv1; serv1 = serv1->next)
|
||||
if (!(serv1->flags & SERV_COUNTED) && sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
if (!(serv1->flags & SERV_MARK) && sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
{
|
||||
serv1->flags |= SERV_COUNTED;
|
||||
serv1->flags |= SERV_MARK;
|
||||
queries += serv1->queries;
|
||||
failed_queries += serv1->failed_queries;
|
||||
}
|
||||
port = prettyprint_addr(&serv->addr, daemon->addrbuff);
|
||||
my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), daemon->addrbuff, port, queries, failed_queries);
|
||||
}
|
||||
|
||||
|
||||
if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
|
||||
{
|
||||
struct crec *cache ;
|
||||
@@ -1922,10 +1923,10 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||
else
|
||||
sprintf(daemon->addrbuff, "%u", rcode);
|
||||
|
||||
if (addr->log.ede != -1)
|
||||
if (addr->log.ede != EDE_UNSET)
|
||||
{
|
||||
extra = daemon->addrbuff;
|
||||
sprintf(extra, " (EDE:%s)", edestr(addr->log.ede));
|
||||
sprintf(extra, " (EDE: %s)", edestr(addr->log.ede));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1973,10 +1974,10 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||
source = "reply";
|
||||
else if (flags & F_SECSTAT)
|
||||
{
|
||||
if (addr && addr->log.ede != -1)
|
||||
if (addr && addr->log.ede != EDE_UNSET && option_bool(OPT_EXTRALOG))
|
||||
{
|
||||
extra = daemon->addrbuff;
|
||||
sprintf(extra, " (EDE:%s)", edestr(addr->log.ede));
|
||||
sprintf(extra, " (EDE: %s)", edestr(addr->log.ede));
|
||||
}
|
||||
source = "validation";
|
||||
dest = arg;
|
||||
@@ -2022,5 +2023,5 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||
}
|
||||
}
|
||||
else
|
||||
my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
|
||||
my_syslog(LOG_INFO, "%s %s %s %s%s", source, name, verb, dest, extra);
|
||||
}
|
||||
+3
-5
@@ -222,7 +222,6 @@ static void dbus_read_servers(DBusMessage *message)
|
||||
|
||||
/* unlink and free anything still marked. */
|
||||
cleanup_servers();
|
||||
check_servers(0);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LOOP
|
||||
@@ -277,7 +276,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
{
|
||||
const char *str = NULL;
|
||||
union mysockaddr addr, source_addr;
|
||||
int flags = 0;
|
||||
u16 flags = 0;
|
||||
char interface[IF_NAMESIZE];
|
||||
char *str_addr, *str_domain = NULL;
|
||||
|
||||
@@ -413,8 +412,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
}
|
||||
|
||||
cleanup_servers();
|
||||
check_servers(0);
|
||||
|
||||
|
||||
if (dup)
|
||||
free(dup);
|
||||
|
||||
@@ -713,7 +711,7 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
if (new_servers)
|
||||
{
|
||||
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
|
||||
check_servers();
|
||||
check_servers(0);
|
||||
if (option_bool(OPT_RELOAD))
|
||||
clear_cache = 1;
|
||||
}
|
||||
|
||||
+2
-1
@@ -85,7 +85,8 @@
|
||||
#define EDNS0_OPTION_NOMCPEID 65074 /* Nominum temporary assignment */
|
||||
#define EDNS0_OPTION_UMBRELLA 20292 /* Cisco Umbrella temporary assignment */
|
||||
|
||||
/* RFC-8914 extended errors */
|
||||
/* RFC-8914 extended errors, negative values are our definitions */
|
||||
#define EDE_UNSET -1 /* No extended DNS error available */
|
||||
#define EDE_OTHER 0 /* Other */
|
||||
#define EDE_USUPDNSKEY 1 /* Unsupported DNSKEY algo */
|
||||
#define EDE_USUPDS 2 /* Unsupported DS Digest */
|
||||
|
||||
+35
-21
@@ -437,8 +437,6 @@ int main (int argc, char **argv)
|
||||
#ifdef HAVE_DBUS
|
||||
{
|
||||
char *err;
|
||||
daemon->dbus = NULL;
|
||||
daemon->watches = NULL;
|
||||
if ((err = dbus_init()))
|
||||
die(_("DBus error: %s"), err, EC_MISC);
|
||||
}
|
||||
@@ -450,7 +448,6 @@ int main (int argc, char **argv)
|
||||
#ifdef HAVE_UBUS
|
||||
{
|
||||
char *err;
|
||||
daemon->ubus = NULL;
|
||||
if ((err = ubus_init()))
|
||||
die(_("UBus error: %s"), err, EC_MISC);
|
||||
}
|
||||
@@ -1065,14 +1062,15 @@ int main (int argc, char **argv)
|
||||
set_dns_listeners();
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
set_dbus_listeners();
|
||||
if (option_bool(OPT_DBUS))
|
||||
set_dbus_listeners();
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_UBUS
|
||||
if (option_bool(OPT_UBUS))
|
||||
set_ubus_listeners();
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->relay4)
|
||||
{
|
||||
@@ -1192,28 +1190,44 @@ int main (int argc, char **argv)
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
/* if we didn't create a DBus connection, retry now. */
|
||||
if (option_bool(OPT_DBUS) && !daemon->dbus)
|
||||
if (option_bool(OPT_DBUS))
|
||||
{
|
||||
char *err;
|
||||
if ((err = dbus_init()))
|
||||
my_syslog(LOG_WARNING, _("DBus error: %s"), err);
|
||||
if (daemon->dbus)
|
||||
my_syslog(LOG_INFO, _("connected to system DBus"));
|
||||
if (!daemon->dbus)
|
||||
{
|
||||
char *err = dbus_init();
|
||||
|
||||
if (daemon->dbus)
|
||||
my_syslog(LOG_INFO, _("connected to system DBus"));
|
||||
else if (err)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("DBus error: %s"), err);
|
||||
reset_option_bool(OPT_DBUS); /* fatal error, stop trying. */
|
||||
}
|
||||
}
|
||||
|
||||
check_dbus_listeners();
|
||||
}
|
||||
check_dbus_listeners();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UBUS
|
||||
/* if we didn't create a UBus connection, retry now. */
|
||||
if (option_bool(OPT_UBUS) && !daemon->ubus)
|
||||
{
|
||||
char *err;
|
||||
if ((err = ubus_init()))
|
||||
my_syslog(LOG_WARNING, _("UBus error: %s"), err);
|
||||
if (daemon->ubus)
|
||||
my_syslog(LOG_INFO, _("connected to system UBus"));
|
||||
if (option_bool(OPT_UBUS))
|
||||
{
|
||||
if (!daemon->ubus)
|
||||
{
|
||||
char *err = ubus_init();
|
||||
|
||||
if (daemon->ubus)
|
||||
my_syslog(LOG_INFO, _("connected to system UBus"));
|
||||
else if (err)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("UBus error: %s"), err);
|
||||
reset_option_bool(OPT_UBUS); /* fatal error, stop trying. */
|
||||
}
|
||||
}
|
||||
|
||||
check_ubus_listeners();
|
||||
}
|
||||
check_ubus_listeners();
|
||||
#endif
|
||||
|
||||
check_dns_listeners(now);
|
||||
|
||||
+11
-6
@@ -107,6 +107,7 @@ typedef unsigned long long u64;
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
@@ -273,7 +274,8 @@ struct event_desc {
|
||||
#define OPT_UMBRELLA 63
|
||||
#define OPT_UMBRELLA_DEVID 64
|
||||
#define OPT_CMARK_ALST_EN 65
|
||||
#define OPT_LAST 66
|
||||
#define OPT_QUIET_TFTP 66
|
||||
#define OPT_LAST 67
|
||||
|
||||
#define OPTION_BITS (sizeof(unsigned int)*8)
|
||||
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
|
||||
@@ -329,7 +331,8 @@ union all_addr {
|
||||
|
||||
|
||||
struct bogus_addr {
|
||||
struct in_addr addr, mask;
|
||||
int is6, prefix;
|
||||
union all_addr addr;
|
||||
struct bogus_addr *next;
|
||||
};
|
||||
|
||||
@@ -536,8 +539,8 @@ union mysockaddr {
|
||||
#define SERV_FOR_NODOTS 32 /* server for names with no domain part only */
|
||||
#define SERV_WARNED_RECURSIVE 64 /* avoid warning spam */
|
||||
#define SERV_FROM_DBUS 128 /* 1 if source is DBus */
|
||||
#define SERV_MARK 256 /* for mark-and-delete */
|
||||
#define SERV_COUNTED 512 /* workspace for log code */
|
||||
#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 */
|
||||
@@ -958,10 +961,10 @@ struct dhcp_bridge {
|
||||
};
|
||||
|
||||
struct cond_domain {
|
||||
char *domain, *prefix;
|
||||
char *domain, *prefix; /* prefix is text-prefix on domain name */
|
||||
struct in_addr start, end;
|
||||
struct in6_addr start6, end6;
|
||||
int is6, indexed;
|
||||
int is6, indexed, prefixlen;
|
||||
struct cond_domain *next;
|
||||
};
|
||||
|
||||
@@ -1103,6 +1106,7 @@ extern struct daemon {
|
||||
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;
|
||||
int server_has_wildcard;
|
||||
int serverarraysz, serverarrayhwm;
|
||||
struct ipsets *ipsets;
|
||||
u32 allowlist_mask;
|
||||
@@ -1367,6 +1371,7 @@ int hostname_issubdomain(char *a, char *b);
|
||||
time_t dnsmasq_time(void);
|
||||
int netmask_length(struct in_addr mask);
|
||||
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
|
||||
int is_same_net_prefix(struct in_addr a, struct in_addr b, int prefix);
|
||||
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen);
|
||||
u64 addr6part(struct in6_addr *addr);
|
||||
void setaddr6part(struct in6_addr *addr, u64 host);
|
||||
|
||||
+3
-2
@@ -744,7 +744,8 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
}
|
||||
}
|
||||
|
||||
return STAT_BOGUS | failflags;
|
||||
/* If we reach this point, no verifying key was found */
|
||||
return STAT_BOGUS | failflags | DNSSEC_FAIL_NOKEY;
|
||||
}
|
||||
|
||||
|
||||
@@ -2193,6 +2194,6 @@ int errflags_to_ede(int status)
|
||||
else if (status & DNSSEC_FAIL_NOSIG)
|
||||
return EDE_NO_RRSIG;
|
||||
else
|
||||
return -1;
|
||||
return EDE_UNSET;
|
||||
}
|
||||
#endif /* HAVE_DNSSEC */
|
||||
+114
-45
@@ -32,11 +32,19 @@ void build_server_array(void)
|
||||
#ifdef HAVE_LOOP
|
||||
if (!(serv->flags & SERV_LOOP))
|
||||
#endif
|
||||
count++;
|
||||
{
|
||||
count++;
|
||||
if (serv->flags & SERV_WILDCARD)
|
||||
daemon->server_has_wildcard = 1;
|
||||
}
|
||||
|
||||
for (serv = daemon->local_domains; serv; serv = serv->next)
|
||||
count++;
|
||||
|
||||
{
|
||||
count++;
|
||||
if (serv->flags & SERV_WILDCARD)
|
||||
daemon->server_has_wildcard = 1;
|
||||
}
|
||||
|
||||
daemon->serverarraysz = count;
|
||||
|
||||
if (count > daemon->serverarrayhwm)
|
||||
@@ -57,7 +65,7 @@ void build_server_array(void)
|
||||
|
||||
count = 0;
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next, count++)
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
#ifdef HAVE_LOOP
|
||||
if (!(serv->flags & SERV_LOOP))
|
||||
#endif
|
||||
@@ -65,6 +73,7 @@ void build_server_array(void)
|
||||
daemon->serverarray[count] = serv;
|
||||
serv->serial = count;
|
||||
serv->last_server = -1;
|
||||
count++;
|
||||
}
|
||||
|
||||
for (serv = daemon->local_domains; serv; serv = serv->next, count++)
|
||||
@@ -92,13 +101,13 @@ void build_server_array(void)
|
||||
reply of IPv4 or IPV6.
|
||||
return 0 if nothing found, 1 otherwise.
|
||||
*/
|
||||
int lookup_domain(char *qdomain, int flags, int *lowout, int *highout)
|
||||
int lookup_domain(char *domain, int flags, int *lowout, int *highout)
|
||||
{
|
||||
int rc, crop_query, nodots;
|
||||
ssize_t qlen;
|
||||
int try, high, low = 0;
|
||||
int nlow = 0, nhigh = 0;
|
||||
char *cp;
|
||||
char *cp, *qdomain = domain;
|
||||
|
||||
/* may be no configured servers. */
|
||||
if (daemon->serverarraysz == 0)
|
||||
@@ -178,16 +187,36 @@ int lookup_domain(char *qdomain, int flags, int *lowout, int *highout)
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
/* 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)
|
||||
crop_query = qlen;
|
||||
else
|
||||
int found = 1;
|
||||
|
||||
if (daemon->server_has_wildcard)
|
||||
{
|
||||
/* We have a match, but it may only be (say) an IPv6 address, and
|
||||
if the query wasn't for an AAAA record, it's no good, and we need
|
||||
to continue generalising */
|
||||
if (filter_servers(try, flags, &nlow, &nhigh))
|
||||
/* if we have example.com and *example.com we need to check against *example.com,
|
||||
but the binary search may have found either. Use the fact that example.com is sorted before *example.com
|
||||
We favour example.com in the case that both match (ie www.example.com) */
|
||||
while (try != 0 && order(qdomain, qlen, daemon->serverarray[try-1]) == 0)
|
||||
try--;
|
||||
|
||||
if (!(qdomain == domain || *qdomain == 0 || *(qdomain-1) == '.'))
|
||||
{
|
||||
while (try < daemon->serverarraysz-1 && order(qdomain, qlen, daemon->serverarray[try+1]) == 0)
|
||||
try++;
|
||||
|
||||
if (!(daemon->serverarray[try]->flags & SERV_WILDCARD))
|
||||
found = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
/* 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)
|
||||
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 */
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -197,11 +226,13 @@ int lookup_domain(char *qdomain, int flags, int *lowout, int *highout)
|
||||
crop_query = 1;
|
||||
|
||||
/* strip chars off the query based on the largest possible remaining match,
|
||||
then continue to the start of the next label. */
|
||||
then continue to the start of the next label unless we have a wildcard
|
||||
domain somewhere, in which case we have to go one at a time. */
|
||||
qlen -= crop_query;
|
||||
qdomain += crop_query;
|
||||
while (qlen > 0 && (*(qdomain-1) != '.'))
|
||||
qlen--, qdomain++;
|
||||
if (!daemon->server_has_wildcard)
|
||||
while (qlen > 0 && (*(qdomain-1) != '.'))
|
||||
qlen--, qdomain++;
|
||||
}
|
||||
|
||||
/* domain has no dots, and we have at least one server configured to handle such,
|
||||
@@ -212,11 +243,6 @@ int lookup_domain(char *qdomain, int flags, int *lowout, int *highout)
|
||||
(nlow == nhigh || daemon->serverarray[nlow]->domain_len == 0))
|
||||
filter_servers(daemon->serverarraysz-1, flags, &nlow, &nhigh);
|
||||
|
||||
/* F_DOMAINSRV returns only domain-specific servers, so if we got to a
|
||||
general server, return empty set. */
|
||||
if (nlow != nhigh && (flags & F_DOMAINSRV) && daemon->serverarray[nlow]->domain_len == 0)
|
||||
nlow = nhigh;
|
||||
|
||||
if (lowout)
|
||||
*lowout = nlow;
|
||||
|
||||
@@ -251,19 +277,26 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
|
||||
|
||||
nhigh++;
|
||||
|
||||
/* Now the servers are on order between low and high, in the order
|
||||
return zero for both, IPv6 addr, IPv4 addr, no-data return, send upstream.
|
||||
|
||||
See which of those match our query in that priority order and narrow (low, high) */
|
||||
|
||||
#define SERV_LOCAL_ADDRESS (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)
|
||||
|
||||
for (i = nlow; (flags & F_CONFIG) && i < nhigh && (daemon->serverarray[i]->flags & SERV_LOCAL_ADDRESS); i++);
|
||||
|
||||
if (i != nlow)
|
||||
nhigh = i;
|
||||
if (flags & F_CONFIG)
|
||||
{
|
||||
/* We're just lookin for any matches that return an RR. */
|
||||
for (i = nlow; i < nhigh; i++)
|
||||
if (daemon->serverarray[i]->flags & SERV_LOCAL_ADDRESS)
|
||||
break;
|
||||
|
||||
/* failed, return failure. */
|
||||
if (i == nhigh)
|
||||
nhigh = nlow;
|
||||
}
|
||||
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.
|
||||
|
||||
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))
|
||||
@@ -288,18 +321,26 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
|
||||
{
|
||||
nlow = i;
|
||||
|
||||
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
|
||||
|
||||
/* --local=/domain/, only return if we don't need a server. */
|
||||
if (i != nlow && !(flags & (F_DNSSECOK | F_DOMAINSRV | F_SERVER)))
|
||||
nhigh = i;
|
||||
else
|
||||
/* now look for a server */
|
||||
for (i = nlow; i < nhigh && !(daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
|
||||
|
||||
if (i != nlow)
|
||||
{
|
||||
nlow = i;
|
||||
/* If we want a server that can do DNSSEC, and this one can't,
|
||||
return nothing. */
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -449,13 +490,22 @@ static int order(char *qdomain, size_t qlen, struct server *serv)
|
||||
|
||||
static int order_servers(struct server *s1, struct server *s2)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* need full comparison of dotless servers in
|
||||
order_qsort() and filter_servers() */
|
||||
|
||||
if (s1->flags & SERV_FOR_NODOTS)
|
||||
return (s2->flags & SERV_FOR_NODOTS) ? 0 : 1;
|
||||
|
||||
return order(s1->domain, s1->domain_len, s2);
|
||||
if ((rc = order(s1->domain, s1->domain_len, s2)) != 0)
|
||||
return rc;
|
||||
|
||||
/* For identical domains, sort wildcard ones first */
|
||||
if (s1->flags & SERV_WILDCARD)
|
||||
return (s2->flags & SERV_WILDCARD) ? 0 : 1;
|
||||
|
||||
return (s2->flags & SERV_WILDCARD) ? -1 : 0;
|
||||
}
|
||||
|
||||
static int order_qsort(const void *a, const void *b)
|
||||
@@ -468,10 +518,12 @@ static int order_qsort(const void *a, const void *b)
|
||||
rc = order_servers(s1, s2);
|
||||
|
||||
/* Sort all literal NODATA and local IPV4 or IPV6 responses together,
|
||||
in a very specific order. */
|
||||
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. */
|
||||
if (rc == 0)
|
||||
rc = (s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS)) -
|
||||
(s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS));
|
||||
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);
|
||||
|
||||
/* Finally, order by appearance in /etc/resolv.conf etc, for --strict-order */
|
||||
if (rc == 0)
|
||||
@@ -489,10 +541,14 @@ void mark_servers(int flag)
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (serv->flags & flag)
|
||||
serv->flags |= SERV_MARK;
|
||||
else
|
||||
serv->flags &= ~SERV_MARK;
|
||||
|
||||
for (serv = daemon->local_domains; serv; serv = serv->next)
|
||||
if (serv->flags & flag)
|
||||
serv->flags |= SERV_MARK;
|
||||
else
|
||||
serv->flags &= ~SERV_MARK;
|
||||
}
|
||||
|
||||
void cleanup_servers(void)
|
||||
@@ -538,7 +594,20 @@ int add_update_server(int flags,
|
||||
struct server *serv = NULL;
|
||||
char *alloc_domain;
|
||||
|
||||
if (!domain || strlen(domain) == 0)
|
||||
if (!domain)
|
||||
domain = "";
|
||||
|
||||
/* .domain == domain, for historical reasons. */
|
||||
if (*domain == '.')
|
||||
while (*domain == '.') domain++;
|
||||
else if (*domain == '*')
|
||||
{
|
||||
domain++;
|
||||
if (*domain != 0)
|
||||
flags |= SERV_WILDCARD;
|
||||
}
|
||||
|
||||
if (*domain == 0)
|
||||
alloc_domain = whine_malloc(1);
|
||||
else if (!(alloc_domain = canonicalise((char *)domain, NULL)))
|
||||
return 0;
|
||||
|
||||
+36
-32
@@ -18,8 +18,9 @@
|
||||
|
||||
|
||||
static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c);
|
||||
static int match_domain(struct in_addr addr, struct cond_domain *c);
|
||||
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c);
|
||||
|
||||
static int match_domain6(struct in6_addr *addr, struct cond_domain *c);
|
||||
|
||||
int is_name_synthetic(int flags, char *name, union all_addr *addr)
|
||||
{
|
||||
@@ -135,28 +136,9 @@ int is_name_synthetic(int flags, char *name, union all_addr *addr)
|
||||
}
|
||||
|
||||
if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr))
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
{
|
||||
if (!c->is6 &&
|
||||
ntohl(addr->addr4.s_addr) >= ntohl(c->start.s_addr) &&
|
||||
ntohl(addr->addr4.s_addr) <= ntohl(c->end.s_addr))
|
||||
found = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
u64 addrpart = addr6part(&addr->addr6);
|
||||
|
||||
if (c->is6 &&
|
||||
is_same_net6(&addr->addr6, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
found = (prot == AF_INET) ? match_domain(addr->addr4, c) : match_domain6(&addr->addr6, c);
|
||||
}
|
||||
|
||||
|
||||
/* restore name */
|
||||
for (p = tail; *p; p++)
|
||||
if (*p == '.' || *p == ':')
|
||||
@@ -246,14 +228,22 @@ int is_rev_synth(int flag, union all_addr *addr, char *name)
|
||||
}
|
||||
|
||||
|
||||
static int match_domain(struct in_addr addr, struct cond_domain *c)
|
||||
{
|
||||
if (!c->is6 &&
|
||||
ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
|
||||
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c)
|
||||
{
|
||||
for (; c; c = c->next)
|
||||
if (!c->is6 &&
|
||||
ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
|
||||
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
|
||||
if (match_domain(addr, c))
|
||||
return c;
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -267,16 +257,30 @@ char *get_domain(struct in_addr addr)
|
||||
return daemon->domain_suffix;
|
||||
}
|
||||
|
||||
|
||||
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c)
|
||||
static int match_domain6(struct in6_addr *addr, struct cond_domain *c)
|
||||
{
|
||||
u64 addrpart = addr6part(addr);
|
||||
|
||||
if (c->is6)
|
||||
{
|
||||
if (c->prefixlen >= 64)
|
||||
{
|
||||
if (is_same_net6(addr, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
return 1;
|
||||
}
|
||||
else if (is_same_net6(addr, &c->start6, c->prefixlen))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c)
|
||||
{
|
||||
for (; c; c = c->next)
|
||||
if (c->is6 &&
|
||||
is_same_net6(addr, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
if (match_domain6(addr, c))
|
||||
return c;
|
||||
|
||||
return NULL;
|
||||
|
||||
+27
-14
@@ -177,7 +177,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
int subnet, cacheable, forwarded = 0;
|
||||
size_t edns0_len;
|
||||
unsigned char *pheader;
|
||||
int ede = -1;
|
||||
int ede = EDE_UNSET;
|
||||
(void)do_bit;
|
||||
|
||||
if (header->hb4 & HB4_CD)
|
||||
@@ -537,7 +537,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
{
|
||||
u16 swap = htons((u16)ede);
|
||||
|
||||
if (ede != -1)
|
||||
if (ede != EDE_UNSET)
|
||||
plen = add_pseudoheader(header, plen, (unsigned char *)limit, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||
else
|
||||
plen = add_pseudoheader(header, plen, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
@@ -734,12 +734,6 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pheader && ede != -1)
|
||||
{
|
||||
u16 swap = htons((u16)ede);
|
||||
n = add_pseudoheader(header, n, limit, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 1);
|
||||
}
|
||||
|
||||
/* do this after extract_addresses. Ensure NODATA reply and remove
|
||||
nameserver info. */
|
||||
if (munged)
|
||||
@@ -753,7 +747,15 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
/* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
|
||||
sections of the packet. Find the new length here and put back pseudoheader
|
||||
if it was removed. */
|
||||
return resize_packet(header, n, pheader, plen);
|
||||
n = resize_packet(header, n, pheader, plen);
|
||||
|
||||
if (pheader && ede != EDE_UNSET)
|
||||
{
|
||||
u16 swap = htons((u16)ede);
|
||||
n = add_pseudoheader(header, n, limit, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 1);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
@@ -1092,7 +1094,7 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he
|
||||
{
|
||||
int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
||||
size_t nn;
|
||||
int ede = -1;
|
||||
int ede = EDE_UNSET;
|
||||
|
||||
(void)status;
|
||||
|
||||
@@ -1240,6 +1242,8 @@ static int is_query_allowed_for_mark(u32 mark, const char *name)
|
||||
static size_t answer_disallowed(struct dns_header *header, size_t qlen, u32 mark, const char *name)
|
||||
{
|
||||
unsigned char *p;
|
||||
(void)name;
|
||||
(void)mark;
|
||||
|
||||
#ifdef HAVE_UBUS
|
||||
if (name)
|
||||
@@ -1580,6 +1584,9 @@ void receive_query(struct listener *listen, time_t now)
|
||||
|
||||
if (m >= 1)
|
||||
{
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet(DUMP_REPLY, daemon->packet, m, NULL, &source_addr);
|
||||
#endif
|
||||
send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
|
||||
(char *)header, m, &source_addr, &dst_addr, if_index);
|
||||
daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
|
||||
@@ -1593,6 +1600,9 @@ void receive_query(struct listener *listen, time_t now)
|
||||
local_auth, do_bit, have_pseudoheader);
|
||||
if (m >= 1)
|
||||
{
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet(DUMP_REPLY, daemon->packet, m, NULL, &source_addr);
|
||||
#endif
|
||||
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
||||
if (local_auth)
|
||||
if (option_bool(OPT_CMARK_ALST_EN) && have_mark && ((u32)mark & daemon->allowlist_mask))
|
||||
@@ -1607,15 +1617,18 @@ void receive_query(struct listener *listen, time_t now)
|
||||
else
|
||||
{
|
||||
int ad_reqd = do_bit;
|
||||
/* RFC 6840 5.7 */
|
||||
/* RFC 6840 5.7 */
|
||||
if (header->hb4 & HB4_AD)
|
||||
ad_reqd = 1;
|
||||
|
||||
|
||||
m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
|
||||
dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
|
||||
|
||||
if (m >= 1)
|
||||
{
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet(DUMP_REPLY, daemon->packet, m, NULL, &source_addr);
|
||||
#endif
|
||||
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
||||
if (option_bool(OPT_CMARK_ALST_EN) && have_mark && ((u32)mark & daemon->allowlist_mask))
|
||||
report_addresses(header, m, mark);
|
||||
@@ -1905,7 +1918,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
while (1)
|
||||
{
|
||||
int ede = -1;
|
||||
int ede = EDE_UNSET;
|
||||
|
||||
if (query_count == TCP_MAX_QUERIES ||
|
||||
!packet ||
|
||||
@@ -2136,7 +2149,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
{
|
||||
u16 swap = htons((u16)ede);
|
||||
|
||||
if (ede != -1)
|
||||
if (ede != EDE_UNSET)
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||
else
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
|
||||
@@ -235,7 +235,6 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
|
||||
/* stringify MAC into dhcp_buff */
|
||||
p = daemon->dhcp_buff;
|
||||
|
||||
@@ -1021,6 +1021,7 @@ void lease_set_hostname(struct dhcp_lease *lease, const char *name, int auth, ch
|
||||
}
|
||||
|
||||
kill_name(lease_tmp);
|
||||
lease_tmp->flags |= LEASE_CHANGED; /* run script on change */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-3
@@ -1506,6 +1506,9 @@ void check_servers(int no_loop_check)
|
||||
if (!no_loop_check)
|
||||
loop_send_probes();
|
||||
#endif
|
||||
|
||||
/* clear all marks. */
|
||||
mark_servers(0);
|
||||
|
||||
/* interface may be new since startup */
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
@@ -1588,7 +1591,7 @@ void check_servers(int no_loop_check)
|
||||
|
||||
if (strlen(serv->domain) != 0 || (serv->flags & SERV_FOR_NODOTS))
|
||||
{
|
||||
char *s1, *s2, *s3 = "";
|
||||
char *s1, *s2, *s3 = "", *s4 = "";
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC))
|
||||
@@ -1599,9 +1602,9 @@ void check_servers(int no_loop_check)
|
||||
else if (strlen(serv->domain) == 0)
|
||||
s1 = _("default"), s2 = "";
|
||||
else
|
||||
s1 = _("domain"), s2 = serv->domain;
|
||||
s1 = _("domain"), s2 = serv->domain, s4 = (serv->flags & SERV_WILDCARD) ? "*" : "";
|
||||
|
||||
my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s %s"), daemon->namebuff, port, s1, s2, s3);
|
||||
my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s%s %s"), daemon->namebuff, port, s1, s4, s2, s3);
|
||||
}
|
||||
#ifdef HAVE_LOOP
|
||||
else if (serv->flags & SERV_LOOP)
|
||||
|
||||
+73
-40
@@ -173,6 +173,7 @@ struct myoption {
|
||||
#define LOPT_UMBRELLA 364
|
||||
#define LOPT_CMARK_ALST_EN 365
|
||||
#define LOPT_CMARK_ALST 366
|
||||
#define LOPT_QUIET_TFTP 367
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -351,6 +352,7 @@ static const struct myoption opts[] =
|
||||
{ "dynamic-host", 1, 0, LOPT_DYNHOST },
|
||||
{ "log-debug", 0, 0, LOPT_LOG_DEBUG },
|
||||
{ "umbrella", 2, 0, LOPT_UMBRELLA },
|
||||
{ "quiet-tftp", 0, 0, LOPT_QUIET_TFTP },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -536,6 +538,7 @@ static struct {
|
||||
{ LOPT_DUMPMASK, ARG_ONE, "<hex>", gettext_noop("Mask which packets to dump"), NULL },
|
||||
{ LOPT_SCRIPT_TIME, OPT_LEASE_RENEW, NULL, gettext_noop("Call dhcp-script when lease expiry changes."), NULL },
|
||||
{ LOPT_UMBRELLA, ARG_ONE, "[=<optspec>]", gettext_noop("Send Cisco Umbrella identifiers including remote IP."), NULL },
|
||||
{ LOPT_QUIET_TFTP, OPT_QUIET_TFTP, NULL, gettext_noop("Do not log routine TFTP."), NULL },
|
||||
{ 0, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -651,7 +654,7 @@ static char *canonicalise_opt(char *s)
|
||||
return 0;
|
||||
|
||||
if (strlen(s) == 0)
|
||||
return "";
|
||||
return opt_string_alloc("");
|
||||
|
||||
unhide_metas(s);
|
||||
if (!(ret = canonicalise(s, &nomem)) && nomem)
|
||||
@@ -965,7 +968,7 @@ static int domain_rev6(char *domain, struct in6_addr *addr, int msize)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (msize%4)
|
||||
if (msize > 128 || msize%4)
|
||||
return 0;
|
||||
|
||||
*domain = 0;
|
||||
@@ -1185,11 +1188,15 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
{
|
||||
new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7);
|
||||
new->flags |= DHOPT_VENDOR;
|
||||
if ((new->flags & DHOPT_ENCAPSULATE) || flags == DHOPT_MATCH)
|
||||
goto_err(_("inappropriate vendor:"));
|
||||
}
|
||||
else if (strstr(arg, "encap:") == arg)
|
||||
{
|
||||
new->u.encap = atoi(arg+6);
|
||||
new->flags |= DHOPT_ENCAPSULATE;
|
||||
if ((new->flags & DHOPT_VENDOR) || flags == DHOPT_MATCH)
|
||||
goto_err(_("inappropriate encap:"));
|
||||
}
|
||||
else if (strstr(arg, "vi-encap:") == arg)
|
||||
{
|
||||
@@ -2224,7 +2231,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
arg = comma;
|
||||
comma = split(arg);
|
||||
daemon->hostmaster = opt_string_alloc(arg);
|
||||
for (cp = daemon->hostmaster; *cp; cp++)
|
||||
for (cp = daemon->hostmaster; cp && *cp; cp++)
|
||||
if (*cp == '@')
|
||||
*cp = '.';
|
||||
|
||||
@@ -2254,10 +2261,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
char *d, *d_raw = arg;
|
||||
comma = split(arg);
|
||||
if (!(d = canonicalise_opt(arg)))
|
||||
if (!(d = canonicalise_opt(d_raw)))
|
||||
ret_err(gen_err);
|
||||
else
|
||||
{
|
||||
free(d); /* allocate this again below. */
|
||||
if (comma)
|
||||
{
|
||||
struct cond_domain *new = opt_malloc(sizeof(struct cond_domain));
|
||||
@@ -2265,6 +2273,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
new->prefix = NULL;
|
||||
new->indexed = 0;
|
||||
new->prefixlen = 0;
|
||||
|
||||
unhide_metas(comma);
|
||||
if ((netpart = split_chr(comma, '/')))
|
||||
@@ -2276,7 +2285,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
ret_err_free(gen_err, new);
|
||||
else if (inet_pton(AF_INET, comma, &new->start))
|
||||
{
|
||||
int mask = (1 << (32 - msize)) - 1;
|
||||
int mask;
|
||||
|
||||
if (msize > 32)
|
||||
ret_err_free(_("bad prefix length"), new);
|
||||
|
||||
mask = (1 << (32 - msize)) - 1;
|
||||
new->is6 = 0;
|
||||
new->start.s_addr = ntohl(htonl(new->start.s_addr) & ~mask);
|
||||
new->end.s_addr = new->start.s_addr | htonl(mask);
|
||||
@@ -2307,21 +2321,25 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
else if (inet_pton(AF_INET6, comma, &new->start6))
|
||||
{
|
||||
u64 mask = (1LLU << (128 - msize)) - 1LLU;
|
||||
u64 addrpart = addr6part(&new->start6);
|
||||
u64 mask, addrpart = addr6part(&new->start6);
|
||||
|
||||
if (msize > 128)
|
||||
ret_err_free(_("bad prefix length"), new);
|
||||
|
||||
mask = (1LLU << (128 - msize)) - 1LLU;
|
||||
|
||||
new->is6 = 1;
|
||||
new->prefixlen = msize;
|
||||
|
||||
/* prefix==64 overflows the mask calculation above */
|
||||
if (msize == 64)
|
||||
if (msize <= 64)
|
||||
mask = (u64)-1LL;
|
||||
|
||||
new->end6 = new->start6;
|
||||
setaddr6part(&new->start6, addrpart & ~mask);
|
||||
setaddr6part(&new->end6, addrpart | mask);
|
||||
|
||||
if (msize < 64)
|
||||
ret_err_free(gen_err, new);
|
||||
else if (arg)
|
||||
if (arg)
|
||||
{
|
||||
if (option != 's')
|
||||
{
|
||||
@@ -2381,7 +2399,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
}
|
||||
|
||||
new->domain = d;
|
||||
new->domain = canonicalise_opt(d_raw);
|
||||
if (option == 's')
|
||||
{
|
||||
new->next = daemon->cond_domain;
|
||||
@@ -2390,19 +2408,21 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
else
|
||||
{
|
||||
char *star;
|
||||
new->next = daemon->synth_domains;
|
||||
daemon->synth_domains = new;
|
||||
if (new->prefix &&
|
||||
(star = strrchr(new->prefix, '*'))
|
||||
&& *(star+1) == 0)
|
||||
{
|
||||
*star = 0;
|
||||
new->indexed = 1;
|
||||
if (new->is6 && new->prefixlen < 64)
|
||||
ret_err_free(_("prefix length too small"), new);
|
||||
}
|
||||
new->next = daemon->synth_domains;
|
||||
daemon->synth_domains = new;
|
||||
}
|
||||
}
|
||||
else if (option == 's')
|
||||
daemon->domain_suffix = d;
|
||||
daemon->domain_suffix = canonicalise_opt(d_raw);
|
||||
else
|
||||
ret_err(gen_err);
|
||||
}
|
||||
@@ -2527,30 +2547,47 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
case 'B': /* --bogus-nxdomain */
|
||||
case LOPT_IGNORE_ADDR: /* --ignore-address */
|
||||
{
|
||||
struct in_addr addr;
|
||||
int prefix = 32;
|
||||
union all_addr addr;
|
||||
int prefix, is6 = 0;
|
||||
struct bogus_addr *baddr;
|
||||
|
||||
unhide_metas(arg);
|
||||
|
||||
if (!arg ||
|
||||
((comma = split_chr(arg, '/')) && !atoi_check(comma, &prefix)) ||
|
||||
(inet_pton(AF_INET, arg, &addr) != 1))
|
||||
ret_err(gen_err); /* error */
|
||||
((comma = split_chr(arg, '/')) && !atoi_check(comma, &prefix)))
|
||||
ret_err(gen_err);
|
||||
|
||||
if (inet_pton(AF_INET6, arg, &addr.addr6) == 1)
|
||||
is6 = 1;
|
||||
else if (inet_pton(AF_INET, arg, &addr.addr4) != 1)
|
||||
ret_err(gen_err);
|
||||
|
||||
if (!comma)
|
||||
{
|
||||
if (is6)
|
||||
prefix = 128;
|
||||
else
|
||||
prefix = 32;
|
||||
}
|
||||
|
||||
if (prefix > 128 || (!is6 && prefix > 32))
|
||||
ret_err(gen_err);
|
||||
|
||||
baddr = opt_malloc(sizeof(struct bogus_addr));
|
||||
if (option == 'B')
|
||||
{
|
||||
baddr->next = daemon->bogus_addr;
|
||||
daemon->bogus_addr = baddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
|
||||
if (option == 'B')
|
||||
{
|
||||
baddr->next = daemon->bogus_addr;
|
||||
daemon->bogus_addr = baddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
baddr->next = daemon->ignore_addr;
|
||||
daemon->ignore_addr = baddr;
|
||||
}
|
||||
baddr->mask.s_addr = htonl(~((1 << (32 - prefix)) - 1));
|
||||
baddr->addr.s_addr = addr.s_addr & baddr->mask.s_addr;
|
||||
baddr->next = daemon->ignore_addr;
|
||||
daemon->ignore_addr = baddr;
|
||||
}
|
||||
|
||||
baddr->prefix = prefix;
|
||||
baddr->is6 = is6;
|
||||
baddr->addr = addr;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2636,11 +2673,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
char *last;
|
||||
|
||||
arg++;
|
||||
/* elide leading dots - they are implied in the search algorithm */
|
||||
while (*arg == '.') arg++;
|
||||
|
||||
domain = lastdomain = arg;
|
||||
domain = lastdomain = ++arg;
|
||||
|
||||
while ((last = split_chr(arg, '/')))
|
||||
{
|
||||
@@ -4150,13 +4183,13 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
comma = split(arg);
|
||||
new->interface = opt_string_alloc(split(comma));
|
||||
new->iface_index = 0;
|
||||
if (inet_pton(AF_INET, arg, &new->local) && inet_pton(AF_INET, comma, &new->server))
|
||||
if (comma && inet_pton(AF_INET, arg, &new->local) && inet_pton(AF_INET, comma, &new->server))
|
||||
{
|
||||
new->next = daemon->relay4;
|
||||
daemon->relay4 = new;
|
||||
}
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (inet_pton(AF_INET6, arg, &new->local) && inet_pton(AF_INET6, comma, &new->server))
|
||||
else if (comma && inet_pton(AF_INET6, arg, &new->local) && inet_pton(AF_INET6, comma, &new->server))
|
||||
{
|
||||
new->next = daemon->relay6;
|
||||
daemon->relay6 = new;
|
||||
|
||||
+46
-39
@@ -364,7 +364,7 @@ int private_net(struct in_addr addr, int ban_localhost)
|
||||
|
||||
return
|
||||
(((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
|
||||
((ip_addr & 0xFF000000) == 0x00000000) /* RFC 5735 section 3. "here" network */ ||
|
||||
(((ip_addr & 0xFF000000) == 0x00000000) && ban_localhost) /* RFC 5735 section 3. "here" network */ ||
|
||||
((ip_addr & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
|
||||
((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
|
||||
((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
|
||||
@@ -375,12 +375,21 @@ int private_net(struct in_addr addr, int ban_localhost)
|
||||
((ip_addr & 0xFFFFFFFF) == 0xFFFFFFFF) /* 255.255.255.255/32 (broadcast)*/ ;
|
||||
}
|
||||
|
||||
static int private_net6(struct in6_addr *a)
|
||||
static int private_net6(struct in6_addr *a, int ban_localhost)
|
||||
{
|
||||
return
|
||||
IN6_IS_ADDR_UNSPECIFIED(a) || /* RFC 6303 4.3 */
|
||||
IN6_IS_ADDR_LOOPBACK(a) || /* RFC 6303 4.3 */
|
||||
/* Block IPv4-mapped IPv6 addresses in private IPv4 address space */
|
||||
if (IN6_IS_ADDR_V4MAPPED(a))
|
||||
{
|
||||
struct in_addr v4;
|
||||
v4.s_addr = ((const uint32_t *) (a))[3];
|
||||
return private_net(v4, ban_localhost);
|
||||
}
|
||||
|
||||
return
|
||||
(IN6_IS_ADDR_UNSPECIFIED(a) && ban_localhost) || /* RFC 6303 4.3 */
|
||||
(IN6_IS_ADDR_LOOPBACK(a) && ban_localhost) || /* RFC 6303 4.3 */
|
||||
IN6_IS_ADDR_LINKLOCAL(a) || /* RFC 6303 4.5 */
|
||||
IN6_IS_ADDR_SITELOCAL(a) ||
|
||||
((unsigned char *)a)[0] == 0xfd || /* RFC 6303 4.4 */
|
||||
((u32 *)a)[0] == htonl(0x20010db8); /* RFC 6303 4.6 */
|
||||
}
|
||||
@@ -795,28 +804,9 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
private_net(addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
|
||||
return 1;
|
||||
|
||||
/* Block IPv4-mapped IPv6 addresses in private IPv4 address space */
|
||||
if (flags & F_IPV6)
|
||||
{
|
||||
if (IN6_IS_ADDR_V4MAPPED(&addr.addr6))
|
||||
{
|
||||
struct in_addr v4;
|
||||
v4.s_addr = ((const uint32_t *) (&addr.addr6))[3];
|
||||
if (private_net(v4, !option_bool(OPT_LOCAL_REBIND)))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check for link-local (LL) and site-local (ULA) IPv6 addresses */
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&addr.addr6) ||
|
||||
IN6_IS_ADDR_SITELOCAL(&addr.addr6))
|
||||
return 1;
|
||||
|
||||
/* Check for the IPv6 loopback address (::1) when
|
||||
option rebind-localhost-ok is NOT set */
|
||||
if (!option_bool(OPT_LOCAL_REBIND) &&
|
||||
IN6_IS_ADDR_LOOPBACK(&addr.addr6))
|
||||
return 1;
|
||||
}
|
||||
if ((flags & F_IPV6) &&
|
||||
private_net6(&addr.addr6, !option_bool(OPT_LOCAL_REBIND)))
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPSET
|
||||
@@ -982,10 +972,12 @@ unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
|
||||
|
||||
*name = 0; /* return empty name if no query found. */
|
||||
|
||||
if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY ||
|
||||
ntohs(header->ancount) != 0 || ntohs(header->nscount) != 0)
|
||||
if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
|
||||
return 0; /* must be exactly one query. */
|
||||
|
||||
if (!(header->hb3 & HB3_QR) && (ntohs(header->ancount) != 0 || ntohs(header->nscount) != 0))
|
||||
return 0; /* non-standard query. */
|
||||
|
||||
if (!extract_name(header, qlen, &p, name, 1, 4))
|
||||
return 0; /* bad packet */
|
||||
|
||||
@@ -1087,7 +1079,6 @@ static int check_bad_address(struct dns_header *header, size_t qlen, struct bogu
|
||||
int i, qtype, qclass, rdlen;
|
||||
unsigned long ttl;
|
||||
struct bogus_addr *baddrp;
|
||||
struct in_addr addr;
|
||||
|
||||
/* skip over questions */
|
||||
if (!(p = skip_questions(header, qlen)))
|
||||
@@ -1109,17 +1100,33 @@ static int check_bad_address(struct dns_header *header, size_t qlen, struct bogu
|
||||
if (ttlp)
|
||||
*ttlp = ttl;
|
||||
|
||||
if (qclass == C_IN && qtype == T_A)
|
||||
if (qclass == C_IN)
|
||||
{
|
||||
if (!CHECK_LEN(header, p, qlen, INADDRSZ))
|
||||
return 0;
|
||||
|
||||
for (baddrp = baddr; baddrp; baddrp = baddrp->next)
|
||||
if (qtype == T_A)
|
||||
{
|
||||
memcpy(&addr, p, INADDRSZ);
|
||||
struct in_addr addr;
|
||||
|
||||
if ((addr.s_addr & baddrp->mask.s_addr) == baddrp->addr.s_addr)
|
||||
return 1;
|
||||
if (!CHECK_LEN(header, p, qlen, INADDRSZ))
|
||||
return 0;
|
||||
|
||||
memcpy(&addr, p, INADDRSZ);
|
||||
|
||||
for (baddrp = baddr; baddrp; baddrp = baddrp->next)
|
||||
if (!baddrp->is6 && is_same_net_prefix(addr, baddrp->addr.addr4, baddrp->prefix))
|
||||
return 1;
|
||||
}
|
||||
else if (qtype == T_AAAA)
|
||||
{
|
||||
struct in6_addr addr;
|
||||
|
||||
if (!CHECK_LEN(header, p, qlen, IN6ADDRSZ))
|
||||
return 0;
|
||||
|
||||
memcpy(&addr, p, IN6ADDRSZ);
|
||||
|
||||
for (baddrp = baddr; baddrp; baddrp = baddrp->next)
|
||||
if (baddrp->is6 && is_same_net6(&addr, &baddrp->addr.addr6, baddrp->prefix))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1618,7 +1625,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
}
|
||||
}
|
||||
else if (option_bool(OPT_BOGUSPRIV) &&
|
||||
((is_arpa == F_IPV6 && private_net6(&addr.addr6)) || (is_arpa == F_IPV4 && private_net(addr.addr4, 1))) &&
|
||||
((is_arpa == F_IPV6 && private_net6(&addr.addr6, 1)) || (is_arpa == F_IPV4 && private_net(addr.addr4, 1))) &&
|
||||
!lookup_domain(name, F_DOMAINSRV, NULL, NULL))
|
||||
{
|
||||
/* if no configured server, not in cache, enabled and private IPV4 address, return NXDOMAIN */
|
||||
|
||||
+2
-1
@@ -761,7 +761,8 @@ static ssize_t tftp_err(int err, char *packet, char *message, char *file)
|
||||
len = snprintf(mess->message, MAXMESSAGE, message, file, errstr);
|
||||
ret += (len < MAXMESSAGE) ? len + 1 : MAXMESSAGE; /* include terminating zero */
|
||||
|
||||
my_syslog(MS_TFTP | LOG_ERR, "%s", mess->message);
|
||||
if (err != ERR_FNF || !option_bool(OPT_QUIET_TFTP))
|
||||
my_syslog(MS_TFTP | LOG_ERR, "%s", mess->message);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
+11
-1
@@ -436,7 +436,17 @@ int netmask_length(struct in_addr mask)
|
||||
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
|
||||
{
|
||||
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
|
||||
}
|
||||
}
|
||||
|
||||
int is_same_net_prefix(struct in_addr a, struct in_addr b, int prefix)
|
||||
{
|
||||
struct in_addr mask;
|
||||
|
||||
mask.s_addr = htonl(~((1 << (32 - prefix)) - 1));
|
||||
|
||||
return is_same_net(a, b, mask);
|
||||
}
|
||||
|
||||
|
||||
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user