mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-06 15:51:41 +00:00
Compare commits
20
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
+15
-6
@@ -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
|
maps 192.168.0.10->192.168.0.40 to 10.0.0.10->10.0.0.40
|
||||||
.TP
|
.TP
|
||||||
.B \-B, --bogus-nxdomain=<ipaddr>[/prefix]
|
.B \-B, --bogus-nxdomain=<ipaddr>[/prefix]
|
||||||
Transform replies which contain the IP specified address or subnet into "No such
|
Transform replies which contain the specified address or subnet into "No such
|
||||||
domain" replies. This is intended to counteract a devious move made by
|
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
|
Verisign in September 2003 when they started returning the address of
|
||||||
an advertising web page in response to queries for unregistered names,
|
an advertising web page in response to queries for unregistered names,
|
||||||
instead of the correct NXDOMAIN response. This option tells dnsmasq to
|
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
|
the IP address being returned by Verisign is 64.94.110.11
|
||||||
.TP
|
.TP
|
||||||
.B --ignore-address=<ipaddr>[/prefix]
|
.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.
|
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
|
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.
|
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:
|
More specific domains take precedence over less specific domains, so:
|
||||||
.B --server=/google.com/1.2.3.4
|
.B --server=/google.com/1.2.3.4
|
||||||
.B --server=/www.google.com/2.3.4.5
|
.B --server=/www.google.com/2.3.4.5
|
||||||
will send queries for *.google.com to 1.2.3.4, except *www.google.com,
|
will send queries for google.com and gmail.google.com to 1.2.3.4, but www.google.com
|
||||||
which will go to 2.3.4.5
|
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
|
The special server address '#' means, "use the standard servers", so
|
||||||
.B --server=/google.com/1.2.3.4
|
.B --server=/google.com/1.2.3.4
|
||||||
.B --server=/www.google.com/#
|
.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.
|
be forwarded as usual.
|
||||||
|
|
||||||
Also permitted is a -S
|
Also permitted is a -S
|
||||||
|
|||||||
+14
-13
@@ -1602,18 +1602,18 @@ int cache_make_stat(struct txt_record *t)
|
|||||||
case TXT_STAT_SERVERS:
|
case TXT_STAT_SERVERS:
|
||||||
/* sum counts from different records for same server */
|
/* sum counts from different records for same server */
|
||||||
for (serv = daemon->servers; serv; serv = serv->next)
|
for (serv = daemon->servers; serv; serv = serv->next)
|
||||||
serv->flags &= ~SERV_COUNTED;
|
serv->flags &= ~SERV_MARK;
|
||||||
|
|
||||||
for (serv = daemon->servers; serv; serv = serv->next)
|
for (serv = daemon->servers; serv; serv = serv->next)
|
||||||
if (!(serv->flags & SERV_COUNTED))
|
if (!(serv->flags & SERV_MARK))
|
||||||
{
|
{
|
||||||
char *new, *lenp;
|
char *new, *lenp;
|
||||||
int port, newlen, bytes_avail, bytes_needed;
|
int port, newlen, bytes_avail, bytes_needed;
|
||||||
unsigned int queries = 0, failed_queries = 0;
|
unsigned int queries = 0, failed_queries = 0;
|
||||||
for (serv1 = serv; serv1; serv1 = serv1->next)
|
for (serv1 = serv; serv1; serv1 = serv1->next)
|
||||||
if (!(serv1->flags & 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;
|
queries += serv1->queries;
|
||||||
failed_queries += serv1->failed_queries;
|
failed_queries += serv1->failed_queries;
|
||||||
}
|
}
|
||||||
@@ -1641,6 +1641,7 @@ int cache_make_stat(struct txt_record *t)
|
|||||||
}
|
}
|
||||||
t->txt = (unsigned char *)buff;
|
t->txt = (unsigned char *)buff;
|
||||||
t->len = p - buff;
|
t->len = p - buff;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1683,24 +1684,24 @@ void dump_cache(time_t now)
|
|||||||
|
|
||||||
/* sum counts from different records for same server */
|
/* sum counts from different records for same server */
|
||||||
for (serv = daemon->servers; serv; serv = serv->next)
|
for (serv = daemon->servers; serv; serv = serv->next)
|
||||||
serv->flags &= ~SERV_COUNTED;
|
serv->flags &= ~SERV_MARK;
|
||||||
|
|
||||||
for (serv = daemon->servers; serv; serv = serv->next)
|
for (serv = daemon->servers; serv; serv = serv->next)
|
||||||
if (!(serv->flags & SERV_COUNTED))
|
if (!(serv->flags & SERV_MARK))
|
||||||
{
|
{
|
||||||
int port;
|
int port;
|
||||||
unsigned int queries = 0, failed_queries = 0;
|
unsigned int queries = 0, failed_queries = 0;
|
||||||
for (serv1 = serv; serv1; serv1 = serv1->next)
|
for (serv1 = serv; serv1; serv1 = serv1->next)
|
||||||
if (!(serv1->flags & 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;
|
queries += serv1->queries;
|
||||||
failed_queries += serv1->failed_queries;
|
failed_queries += serv1->failed_queries;
|
||||||
}
|
}
|
||||||
port = prettyprint_addr(&serv->addr, daemon->addrbuff);
|
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);
|
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))
|
if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
|
||||||
{
|
{
|
||||||
struct crec *cache ;
|
struct crec *cache ;
|
||||||
@@ -1922,10 +1923,10 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
|||||||
else
|
else
|
||||||
sprintf(daemon->addrbuff, "%u", rcode);
|
sprintf(daemon->addrbuff, "%u", rcode);
|
||||||
|
|
||||||
if (addr->log.ede != -1)
|
if (addr->log.ede != EDE_UNSET)
|
||||||
{
|
{
|
||||||
extra = daemon->addrbuff;
|
extra = daemon->addrbuff;
|
||||||
sprintf(extra, " (EDE:%s)", edestr(addr->log.ede));
|
sprintf(extra, " (EDE: %s)", edestr(addr->log.ede));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1973,10 +1974,10 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
|||||||
source = "reply";
|
source = "reply";
|
||||||
else if (flags & F_SECSTAT)
|
else if (flags & F_SECSTAT)
|
||||||
{
|
{
|
||||||
if (addr && addr->log.ede != -1)
|
if (addr && addr->log.ede != EDE_UNSET)
|
||||||
{
|
{
|
||||||
extra = daemon->addrbuff;
|
extra = daemon->addrbuff;
|
||||||
sprintf(extra, " (EDE:%s)", edestr(addr->log.ede));
|
sprintf(extra, " (EDE: %s)", edestr(addr->log.ede));
|
||||||
}
|
}
|
||||||
source = "validation";
|
source = "validation";
|
||||||
dest = arg;
|
dest = arg;
|
||||||
|
|||||||
+3
-5
@@ -222,7 +222,6 @@ static void dbus_read_servers(DBusMessage *message)
|
|||||||
|
|
||||||
/* unlink and free anything still marked. */
|
/* unlink and free anything still marked. */
|
||||||
cleanup_servers();
|
cleanup_servers();
|
||||||
check_servers(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LOOP
|
#ifdef HAVE_LOOP
|
||||||
@@ -277,7 +276,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
|||||||
{
|
{
|
||||||
const char *str = NULL;
|
const char *str = NULL;
|
||||||
union mysockaddr addr, source_addr;
|
union mysockaddr addr, source_addr;
|
||||||
int flags = 0;
|
u16 flags = 0;
|
||||||
char interface[IF_NAMESIZE];
|
char interface[IF_NAMESIZE];
|
||||||
char *str_addr, *str_domain = NULL;
|
char *str_addr, *str_domain = NULL;
|
||||||
|
|
||||||
@@ -413,8 +412,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cleanup_servers();
|
cleanup_servers();
|
||||||
check_servers(0);
|
|
||||||
|
|
||||||
if (dup)
|
if (dup)
|
||||||
free(dup);
|
free(dup);
|
||||||
|
|
||||||
@@ -713,7 +711,7 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
|||||||
if (new_servers)
|
if (new_servers)
|
||||||
{
|
{
|
||||||
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
|
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
|
||||||
check_servers();
|
check_servers(0);
|
||||||
if (option_bool(OPT_RELOAD))
|
if (option_bool(OPT_RELOAD))
|
||||||
clear_cache = 1;
|
clear_cache = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -85,7 +85,8 @@
|
|||||||
#define EDNS0_OPTION_NOMCPEID 65074 /* Nominum temporary assignment */
|
#define EDNS0_OPTION_NOMCPEID 65074 /* Nominum temporary assignment */
|
||||||
#define EDNS0_OPTION_UMBRELLA 20292 /* Cisco Umbrella temporary assignment */
|
#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_OTHER 0 /* Other */
|
||||||
#define EDE_USUPDNSKEY 1 /* Unsupported DNSKEY algo */
|
#define EDE_USUPDNSKEY 1 /* Unsupported DNSKEY algo */
|
||||||
#define EDE_USUPDS 2 /* Unsupported DS Digest */
|
#define EDE_USUPDS 2 /* Unsupported DS Digest */
|
||||||
|
|||||||
+35
-21
@@ -437,8 +437,6 @@ int main (int argc, char **argv)
|
|||||||
#ifdef HAVE_DBUS
|
#ifdef HAVE_DBUS
|
||||||
{
|
{
|
||||||
char *err;
|
char *err;
|
||||||
daemon->dbus = NULL;
|
|
||||||
daemon->watches = NULL;
|
|
||||||
if ((err = dbus_init()))
|
if ((err = dbus_init()))
|
||||||
die(_("DBus error: %s"), err, EC_MISC);
|
die(_("DBus error: %s"), err, EC_MISC);
|
||||||
}
|
}
|
||||||
@@ -450,7 +448,6 @@ int main (int argc, char **argv)
|
|||||||
#ifdef HAVE_UBUS
|
#ifdef HAVE_UBUS
|
||||||
{
|
{
|
||||||
char *err;
|
char *err;
|
||||||
daemon->ubus = NULL;
|
|
||||||
if ((err = ubus_init()))
|
if ((err = ubus_init()))
|
||||||
die(_("UBus error: %s"), err, EC_MISC);
|
die(_("UBus error: %s"), err, EC_MISC);
|
||||||
}
|
}
|
||||||
@@ -1065,14 +1062,15 @@ int main (int argc, char **argv)
|
|||||||
set_dns_listeners();
|
set_dns_listeners();
|
||||||
|
|
||||||
#ifdef HAVE_DBUS
|
#ifdef HAVE_DBUS
|
||||||
set_dbus_listeners();
|
if (option_bool(OPT_DBUS))
|
||||||
|
set_dbus_listeners();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_UBUS
|
#ifdef HAVE_UBUS
|
||||||
if (option_bool(OPT_UBUS))
|
if (option_bool(OPT_UBUS))
|
||||||
set_ubus_listeners();
|
set_ubus_listeners();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
if (daemon->dhcp || daemon->relay4)
|
if (daemon->dhcp || daemon->relay4)
|
||||||
{
|
{
|
||||||
@@ -1192,28 +1190,44 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
#ifdef HAVE_DBUS
|
#ifdef HAVE_DBUS
|
||||||
/* if we didn't create a DBus connection, retry now. */
|
/* 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 (!daemon->dbus)
|
||||||
if ((err = dbus_init()))
|
{
|
||||||
my_syslog(LOG_WARNING, _("DBus error: %s"), err);
|
char *err = dbus_init();
|
||||||
if (daemon->dbus)
|
|
||||||
my_syslog(LOG_INFO, _("connected to system DBus"));
|
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
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_UBUS
|
#ifdef HAVE_UBUS
|
||||||
/* if we didn't create a UBus connection, retry now. */
|
/* if we didn't create a UBus connection, retry now. */
|
||||||
if (option_bool(OPT_UBUS) && !daemon->ubus)
|
if (option_bool(OPT_UBUS))
|
||||||
{
|
{
|
||||||
char *err;
|
if (!daemon->ubus)
|
||||||
if ((err = ubus_init()))
|
{
|
||||||
my_syslog(LOG_WARNING, _("UBus error: %s"), err);
|
char *err = ubus_init();
|
||||||
if (daemon->ubus)
|
|
||||||
my_syslog(LOG_INFO, _("connected to system UBus"));
|
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
|
#endif
|
||||||
|
|
||||||
check_dns_listeners(now);
|
check_dns_listeners(now);
|
||||||
|
|||||||
+6
-3
@@ -329,7 +329,8 @@ union all_addr {
|
|||||||
|
|
||||||
|
|
||||||
struct bogus_addr {
|
struct bogus_addr {
|
||||||
struct in_addr addr, mask;
|
int is6, prefix;
|
||||||
|
union all_addr addr;
|
||||||
struct bogus_addr *next;
|
struct bogus_addr *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -536,8 +537,8 @@ union mysockaddr {
|
|||||||
#define SERV_FOR_NODOTS 32 /* server for names with no domain part only */
|
#define SERV_FOR_NODOTS 32 /* server for names with no domain part only */
|
||||||
#define SERV_WARNED_RECURSIVE 64 /* avoid warning spam */
|
#define SERV_WARNED_RECURSIVE 64 /* avoid warning spam */
|
||||||
#define SERV_FROM_DBUS 128 /* 1 if source is DBus */
|
#define SERV_FROM_DBUS 128 /* 1 if source is DBus */
|
||||||
#define SERV_MARK 256 /* for mark-and-delete */
|
#define SERV_MARK 256 /* for mark-and-delete and log code */
|
||||||
#define SERV_COUNTED 512 /* workspace for log code */
|
#define SERV_WILDCARD 512 /* domain has leading '*' */
|
||||||
#define SERV_USE_RESOLV 1024 /* forward this domain in the normal way */
|
#define SERV_USE_RESOLV 1024 /* forward this domain in the normal way */
|
||||||
#define SERV_FROM_RESOLV 2048 /* 1 for servers from resolv, 0 for command line. */
|
#define SERV_FROM_RESOLV 2048 /* 1 for servers from resolv, 0 for command line. */
|
||||||
#define SERV_FROM_FILE 4096 /* read from --servers-file */
|
#define SERV_FROM_FILE 4096 /* read from --servers-file */
|
||||||
@@ -1103,6 +1104,7 @@ extern struct daemon {
|
|||||||
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
|
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
|
||||||
struct bogus_addr *bogus_addr, *ignore_addr;
|
struct bogus_addr *bogus_addr, *ignore_addr;
|
||||||
struct server *servers, *local_domains, **serverarray, *no_rebind;
|
struct server *servers, *local_domains, **serverarray, *no_rebind;
|
||||||
|
int server_has_wildcard;
|
||||||
int serverarraysz, serverarrayhwm;
|
int serverarraysz, serverarrayhwm;
|
||||||
struct ipsets *ipsets;
|
struct ipsets *ipsets;
|
||||||
u32 allowlist_mask;
|
u32 allowlist_mask;
|
||||||
@@ -1367,6 +1369,7 @@ int hostname_issubdomain(char *a, char *b);
|
|||||||
time_t dnsmasq_time(void);
|
time_t dnsmasq_time(void);
|
||||||
int netmask_length(struct in_addr mask);
|
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(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);
|
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen);
|
||||||
u64 addr6part(struct in6_addr *addr);
|
u64 addr6part(struct in6_addr *addr);
|
||||||
void setaddr6part(struct in6_addr *addr, u64 host);
|
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)
|
else if (status & DNSSEC_FAIL_NOSIG)
|
||||||
return EDE_NO_RRSIG;
|
return EDE_NO_RRSIG;
|
||||||
else
|
else
|
||||||
return -1;
|
return EDE_UNSET;
|
||||||
}
|
}
|
||||||
#endif /* HAVE_DNSSEC */
|
#endif /* HAVE_DNSSEC */
|
||||||
+114
-45
@@ -32,11 +32,19 @@ void build_server_array(void)
|
|||||||
#ifdef HAVE_LOOP
|
#ifdef HAVE_LOOP
|
||||||
if (!(serv->flags & SERV_LOOP))
|
if (!(serv->flags & SERV_LOOP))
|
||||||
#endif
|
#endif
|
||||||
count++;
|
{
|
||||||
|
count++;
|
||||||
|
if (serv->flags & SERV_WILDCARD)
|
||||||
|
daemon->server_has_wildcard = 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (serv = daemon->local_domains; serv; serv = serv->next)
|
for (serv = daemon->local_domains; serv; serv = serv->next)
|
||||||
count++;
|
{
|
||||||
|
count++;
|
||||||
|
if (serv->flags & SERV_WILDCARD)
|
||||||
|
daemon->server_has_wildcard = 1;
|
||||||
|
}
|
||||||
|
|
||||||
daemon->serverarraysz = count;
|
daemon->serverarraysz = count;
|
||||||
|
|
||||||
if (count > daemon->serverarrayhwm)
|
if (count > daemon->serverarrayhwm)
|
||||||
@@ -57,7 +65,7 @@ void build_server_array(void)
|
|||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
|
|
||||||
for (serv = daemon->servers; serv; serv = serv->next, count++)
|
for (serv = daemon->servers; serv; serv = serv->next)
|
||||||
#ifdef HAVE_LOOP
|
#ifdef HAVE_LOOP
|
||||||
if (!(serv->flags & SERV_LOOP))
|
if (!(serv->flags & SERV_LOOP))
|
||||||
#endif
|
#endif
|
||||||
@@ -65,6 +73,7 @@ void build_server_array(void)
|
|||||||
daemon->serverarray[count] = serv;
|
daemon->serverarray[count] = serv;
|
||||||
serv->serial = count;
|
serv->serial = count;
|
||||||
serv->last_server = -1;
|
serv->last_server = -1;
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (serv = daemon->local_domains; serv; serv = serv->next, 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.
|
reply of IPv4 or IPV6.
|
||||||
return 0 if nothing found, 1 otherwise.
|
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;
|
int rc, crop_query, nodots;
|
||||||
ssize_t qlen;
|
ssize_t qlen;
|
||||||
int try, high, low = 0;
|
int try, high, low = 0;
|
||||||
int nlow = 0, nhigh = 0;
|
int nlow = 0, nhigh = 0;
|
||||||
char *cp;
|
char *cp, *qdomain = domain;
|
||||||
|
|
||||||
/* may be no configured servers. */
|
/* may be no configured servers. */
|
||||||
if (daemon->serverarraysz == 0)
|
if (daemon->serverarraysz == 0)
|
||||||
@@ -178,16 +187,36 @@ int lookup_domain(char *qdomain, int flags, int *lowout, int *highout)
|
|||||||
|
|
||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
{
|
{
|
||||||
/* We've matched a setting which says to use servers without a domain.
|
int found = 1;
|
||||||
Continue the search with empty query */
|
|
||||||
if (daemon->serverarray[try]->flags & SERV_USE_RESOLV)
|
if (daemon->server_has_wildcard)
|
||||||
crop_query = qlen;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
/* We have a match, but it may only be (say) an IPv6 address, and
|
/* if we have example.com and *example.com we need to check against *example.com,
|
||||||
if the query wasn't for an AAAA record, it's no good, and we need
|
but the binary search may have found either. Use the fact that example.com is sorted before *example.com
|
||||||
to continue generalising */
|
We favour example.com in the case that both match (ie www.example.com) */
|
||||||
if (filter_servers(try, flags, &nlow, &nhigh))
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,11 +226,13 @@ int lookup_domain(char *qdomain, int flags, int *lowout, int *highout)
|
|||||||
crop_query = 1;
|
crop_query = 1;
|
||||||
|
|
||||||
/* strip chars off the query based on the largest possible remaining match,
|
/* 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;
|
qlen -= crop_query;
|
||||||
qdomain += crop_query;
|
qdomain += crop_query;
|
||||||
while (qlen > 0 && (*(qdomain-1) != '.'))
|
if (!daemon->server_has_wildcard)
|
||||||
qlen--, qdomain++;
|
while (qlen > 0 && (*(qdomain-1) != '.'))
|
||||||
|
qlen--, qdomain++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* domain has no dots, and we have at least one server configured to handle such,
|
/* 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))
|
(nlow == nhigh || daemon->serverarray[nlow]->domain_len == 0))
|
||||||
filter_servers(daemon->serverarraysz-1, flags, &nlow, &nhigh);
|
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)
|
if (lowout)
|
||||||
*lowout = nlow;
|
*lowout = nlow;
|
||||||
|
|
||||||
@@ -251,19 +277,26 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
|
|||||||
|
|
||||||
nhigh++;
|
nhigh++;
|
||||||
|
|
||||||
/* Now the servers are on order between low and high, in the order
|
|
||||||
return zero for both, IPv6 addr, IPv4 addr, no-data return, send upstream.
|
|
||||||
|
|
||||||
See which of those match our query in that priority order and narrow (low, high) */
|
|
||||||
|
|
||||||
#define SERV_LOCAL_ADDRESS (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)
|
#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 (flags & F_CONFIG)
|
||||||
|
{
|
||||||
if (i != nlow)
|
/* We're just lookin for any matches that return an RR. */
|
||||||
nhigh = i;
|
for (i = nlow; i < nhigh; i++)
|
||||||
|
if (daemon->serverarray[i]->flags & SERV_LOCAL_ADDRESS)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* failed, return failure. */
|
||||||
|
if (i == nhigh)
|
||||||
|
nhigh = nlow;
|
||||||
|
}
|
||||||
else
|
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++);
|
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_6ADDR); i++);
|
||||||
|
|
||||||
if (i != nlow && (flags & F_IPV6))
|
if (i != nlow && (flags & F_IPV6))
|
||||||
@@ -288,18 +321,26 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
|
|||||||
{
|
{
|
||||||
nlow = i;
|
nlow = i;
|
||||||
|
|
||||||
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
|
/* now look for a server */
|
||||||
|
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)))
|
if (i != nlow)
|
||||||
nhigh = i;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
nlow = i;
|
|
||||||
/* If we want a server that can do DNSSEC, and this one can't,
|
/* 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))
|
if ((flags & F_DNSSECOK) && !(daemon->serverarray[nlow]->flags & SERV_DO_DNSSEC))
|
||||||
nlow = nhigh;
|
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)
|
static int order_servers(struct server *s1, struct server *s2)
|
||||||
{
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
/* need full comparison of dotless servers in
|
/* need full comparison of dotless servers in
|
||||||
order_qsort() and filter_servers() */
|
order_qsort() and filter_servers() */
|
||||||
|
|
||||||
if (s1->flags & SERV_FOR_NODOTS)
|
if (s1->flags & SERV_FOR_NODOTS)
|
||||||
return (s2->flags & SERV_FOR_NODOTS) ? 0 : 1;
|
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)
|
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);
|
rc = order_servers(s1, s2);
|
||||||
|
|
||||||
/* Sort all literal NODATA and local IPV4 or IPV6 responses together,
|
/* 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)
|
if (rc == 0)
|
||||||
rc = (s2->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));
|
((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 */
|
/* Finally, order by appearance in /etc/resolv.conf etc, for --strict-order */
|
||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
@@ -489,10 +541,14 @@ void mark_servers(int flag)
|
|||||||
for (serv = daemon->servers; serv; serv = serv->next)
|
for (serv = daemon->servers; serv; serv = serv->next)
|
||||||
if (serv->flags & flag)
|
if (serv->flags & flag)
|
||||||
serv->flags |= SERV_MARK;
|
serv->flags |= SERV_MARK;
|
||||||
|
else
|
||||||
|
serv->flags &= ~SERV_MARK;
|
||||||
|
|
||||||
for (serv = daemon->local_domains; serv; serv = serv->next)
|
for (serv = daemon->local_domains; serv; serv = serv->next)
|
||||||
if (serv->flags & flag)
|
if (serv->flags & flag)
|
||||||
serv->flags |= SERV_MARK;
|
serv->flags |= SERV_MARK;
|
||||||
|
else
|
||||||
|
serv->flags &= ~SERV_MARK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_servers(void)
|
void cleanup_servers(void)
|
||||||
@@ -538,7 +594,20 @@ int add_update_server(int flags,
|
|||||||
struct server *serv = NULL;
|
struct server *serv = NULL;
|
||||||
char *alloc_domain;
|
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);
|
alloc_domain = whine_malloc(1);
|
||||||
else if (!(alloc_domain = canonicalise((char *)domain, NULL)))
|
else if (!(alloc_domain = canonicalise((char *)domain, NULL)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+27
-14
@@ -177,7 +177,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
int subnet, cacheable, forwarded = 0;
|
int subnet, cacheable, forwarded = 0;
|
||||||
size_t edns0_len;
|
size_t edns0_len;
|
||||||
unsigned char *pheader;
|
unsigned char *pheader;
|
||||||
int ede = -1;
|
int ede = EDE_UNSET;
|
||||||
(void)do_bit;
|
(void)do_bit;
|
||||||
|
|
||||||
if (header->hb4 & HB4_CD)
|
if (header->hb4 & HB4_CD)
|
||||||
@@ -537,7 +537,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
{
|
{
|
||||||
u16 swap = htons((u16)ede);
|
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);
|
plen = add_pseudoheader(header, plen, (unsigned char *)limit, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||||
else
|
else
|
||||||
plen = add_pseudoheader(header, plen, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
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
|
#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
|
/* do this after extract_addresses. Ensure NODATA reply and remove
|
||||||
nameserver info. */
|
nameserver info. */
|
||||||
if (munged)
|
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
|
/* 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
|
sections of the packet. Find the new length here and put back pseudoheader
|
||||||
if it was removed. */
|
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
|
#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;
|
int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
||||||
size_t nn;
|
size_t nn;
|
||||||
int ede = -1;
|
int ede = EDE_UNSET;
|
||||||
|
|
||||||
(void)status;
|
(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)
|
static size_t answer_disallowed(struct dns_header *header, size_t qlen, u32 mark, const char *name)
|
||||||
{
|
{
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
|
(void)name;
|
||||||
|
(void)mark;
|
||||||
|
|
||||||
#ifdef HAVE_UBUS
|
#ifdef HAVE_UBUS
|
||||||
if (name)
|
if (name)
|
||||||
@@ -1580,6 +1584,9 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
|
|
||||||
if (m >= 1)
|
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),
|
send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
|
||||||
(char *)header, m, &source_addr, &dst_addr, if_index);
|
(char *)header, m, &source_addr, &dst_addr, if_index);
|
||||||
daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
|
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);
|
local_auth, do_bit, have_pseudoheader);
|
||||||
if (m >= 1)
|
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 defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
||||||
if (local_auth)
|
if (local_auth)
|
||||||
if (option_bool(OPT_CMARK_ALST_EN) && have_mark && ((u32)mark & daemon->allowlist_mask))
|
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
|
else
|
||||||
{
|
{
|
||||||
int ad_reqd = do_bit;
|
int ad_reqd = do_bit;
|
||||||
/* RFC 6840 5.7 */
|
/* RFC 6840 5.7 */
|
||||||
if (header->hb4 & HB4_AD)
|
if (header->hb4 & HB4_AD)
|
||||||
ad_reqd = 1;
|
ad_reqd = 1;
|
||||||
|
|
||||||
m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
|
m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
|
||||||
dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
|
dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
|
||||||
|
|
||||||
if (m >= 1)
|
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 defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
||||||
if (option_bool(OPT_CMARK_ALST_EN) && have_mark && ((u32)mark & daemon->allowlist_mask))
|
if (option_bool(OPT_CMARK_ALST_EN) && have_mark && ((u32)mark & daemon->allowlist_mask))
|
||||||
report_addresses(header, m, mark);
|
report_addresses(header, m, mark);
|
||||||
@@ -1905,7 +1918,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
int ede = -1;
|
int ede = EDE_UNSET;
|
||||||
|
|
||||||
if (query_count == TCP_MAX_QUERIES ||
|
if (query_count == TCP_MAX_QUERIES ||
|
||||||
!packet ||
|
!packet ||
|
||||||
@@ -2136,7 +2149,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
{
|
{
|
||||||
u16 swap = htons((u16)ede);
|
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);
|
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||||
else
|
else
|
||||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
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
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
||||||
/* stringify MAC into dhcp_buff */
|
/* stringify MAC into dhcp_buff */
|
||||||
p = daemon->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);
|
kill_name(lease_tmp);
|
||||||
|
lease_tmp->flags |= LEASE_CHANGED; /* run script on change */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-3
@@ -1506,6 +1506,9 @@ void check_servers(int no_loop_check)
|
|||||||
if (!no_loop_check)
|
if (!no_loop_check)
|
||||||
loop_send_probes();
|
loop_send_probes();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* clear all marks. */
|
||||||
|
mark_servers(0);
|
||||||
|
|
||||||
/* interface may be new since startup */
|
/* interface may be new since startup */
|
||||||
if (!option_bool(OPT_NOWILD))
|
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))
|
if (strlen(serv->domain) != 0 || (serv->flags & SERV_FOR_NODOTS))
|
||||||
{
|
{
|
||||||
char *s1, *s2, *s3 = "";
|
char *s1, *s2, *s3 = "", *s4 = "";
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC))
|
if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC))
|
||||||
@@ -1599,9 +1602,9 @@ void check_servers(int no_loop_check)
|
|||||||
else if (strlen(serv->domain) == 0)
|
else if (strlen(serv->domain) == 0)
|
||||||
s1 = _("default"), s2 = "";
|
s1 = _("default"), s2 = "";
|
||||||
else
|
else
|
||||||
s1 = _("domain"), s2 = serv->domain;
|
s1 = _("domain"), s2 = serv->domain, 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
|
#ifdef HAVE_LOOP
|
||||||
else if (serv->flags & SERV_LOOP)
|
else if (serv->flags & SERV_LOOP)
|
||||||
|
|||||||
+36
-23
@@ -2527,30 +2527,47 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|||||||
case 'B': /* --bogus-nxdomain */
|
case 'B': /* --bogus-nxdomain */
|
||||||
case LOPT_IGNORE_ADDR: /* --ignore-address */
|
case LOPT_IGNORE_ADDR: /* --ignore-address */
|
||||||
{
|
{
|
||||||
struct in_addr addr;
|
union all_addr addr;
|
||||||
int prefix = 32;
|
int prefix, is6 = 0;
|
||||||
|
struct bogus_addr *baddr;
|
||||||
|
|
||||||
unhide_metas(arg);
|
unhide_metas(arg);
|
||||||
|
|
||||||
if (!arg ||
|
if (!arg ||
|
||||||
((comma = split_chr(arg, '/')) && !atoi_check(comma, &prefix)) ||
|
((comma = split_chr(arg, '/')) && !atoi_check(comma, &prefix)))
|
||||||
(inet_pton(AF_INET, arg, &addr) != 1))
|
ret_err(gen_err);
|
||||||
ret_err(gen_err); /* error */
|
|
||||||
|
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
|
else
|
||||||
{
|
{
|
||||||
struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
|
baddr->next = daemon->ignore_addr;
|
||||||
if (option == 'B')
|
daemon->ignore_addr = baddr;
|
||||||
{
|
|
||||||
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->prefix = prefix;
|
||||||
|
baddr->is6 = is6;
|
||||||
|
baddr->addr = addr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2636,11 +2653,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|||||||
{
|
{
|
||||||
char *last;
|
char *last;
|
||||||
|
|
||||||
arg++;
|
domain = lastdomain = ++arg;
|
||||||
/* elide leading dots - they are implied in the search algorithm */
|
|
||||||
while (*arg == '.') arg++;
|
|
||||||
|
|
||||||
domain = lastdomain = arg;
|
|
||||||
|
|
||||||
while ((last = split_chr(arg, '/')))
|
while ((last = split_chr(arg, '/')))
|
||||||
{
|
{
|
||||||
|
|||||||
+46
-39
@@ -364,7 +364,7 @@ int private_net(struct in_addr addr, int ban_localhost)
|
|||||||
|
|
||||||
return
|
return
|
||||||
(((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
|
(((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 & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
|
||||||
((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
|
((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
|
||||||
((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (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)*/ ;
|
((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
|
/* Block IPv4-mapped IPv6 addresses in private IPv4 address space */
|
||||||
IN6_IS_ADDR_UNSPECIFIED(a) || /* RFC 6303 4.3 */
|
if (IN6_IS_ADDR_V4MAPPED(a))
|
||||||
IN6_IS_ADDR_LOOPBACK(a) || /* RFC 6303 4.3 */
|
{
|
||||||
|
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_LINKLOCAL(a) || /* RFC 6303 4.5 */
|
||||||
|
IN6_IS_ADDR_SITELOCAL(a) ||
|
||||||
((unsigned char *)a)[0] == 0xfd || /* RFC 6303 4.4 */
|
((unsigned char *)a)[0] == 0xfd || /* RFC 6303 4.4 */
|
||||||
((u32 *)a)[0] == htonl(0x20010db8); /* RFC 6303 4.6 */
|
((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)))
|
private_net(addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* Block IPv4-mapped IPv6 addresses in private IPv4 address space */
|
if ((flags & F_IPV6) &&
|
||||||
if (flags & F_IPV6)
|
private_net6(&addr.addr6, !option_bool(OPT_LOCAL_REBIND)))
|
||||||
{
|
return 1;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_IPSET
|
#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. */
|
*name = 0; /* return empty name if no query found. */
|
||||||
|
|
||||||
if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY ||
|
if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
|
||||||
ntohs(header->ancount) != 0 || ntohs(header->nscount) != 0)
|
|
||||||
return 0; /* must be exactly one 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))
|
if (!extract_name(header, qlen, &p, name, 1, 4))
|
||||||
return 0; /* bad packet */
|
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;
|
int i, qtype, qclass, rdlen;
|
||||||
unsigned long ttl;
|
unsigned long ttl;
|
||||||
struct bogus_addr *baddrp;
|
struct bogus_addr *baddrp;
|
||||||
struct in_addr addr;
|
|
||||||
|
|
||||||
/* skip over questions */
|
/* skip over questions */
|
||||||
if (!(p = skip_questions(header, qlen)))
|
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)
|
if (ttlp)
|
||||||
*ttlp = ttl;
|
*ttlp = ttl;
|
||||||
|
|
||||||
if (qclass == C_IN && qtype == T_A)
|
if (qclass == C_IN)
|
||||||
{
|
{
|
||||||
if (!CHECK_LEN(header, p, qlen, INADDRSZ))
|
if (qtype == T_A)
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (baddrp = baddr; baddrp; baddrp = baddrp->next)
|
|
||||||
{
|
{
|
||||||
memcpy(&addr, p, INADDRSZ);
|
struct in_addr addr;
|
||||||
|
|
||||||
if ((addr.s_addr & baddrp->mask.s_addr) == baddrp->addr.s_addr)
|
if (!CHECK_LEN(header, p, qlen, INADDRSZ))
|
||||||
return 1;
|
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) &&
|
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))
|
!lookup_domain(name, F_DOMAINSRV, NULL, NULL))
|
||||||
{
|
{
|
||||||
/* if no configured server, not in cache, enabled and private IPV4 address, return NXDOMAIN */
|
/* if no configured server, not in cache, enabled and private IPV4 address, return NXDOMAIN */
|
||||||
|
|||||||
+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)
|
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);
|
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)
|
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in new issue
Block a user