summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2013-10-16 13:09:53 +0100
committerSimon Kelley <simon@thekelleys.org.uk>2013-10-16 14:33:23 +0100
commitdc27e148a154079929510c3fda978045b64440dc (patch)
tree080a0409504479c55963df0efc7adaea306caa9d
parent45cca585922f4c351cb17cb69d3c0d32cd3e03c9 (diff)
downloaddnsmasq-2.67rc4.tar.gz
Warning when using --bind-interfaces and routeable addresses.v2.67rc4
-rw-r--r--src/dnsmasq.c3
-rw-r--r--src/dnsmasq.h4
-rw-r--r--src/network.c59
-rw-r--r--src/rfc1035.c2
4 files changed, 65 insertions, 3 deletions
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index 83d77d8..a2b37dc 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -632,6 +632,8 @@ int main (int argc, char **argv)
if (bind_fallback)
my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
+
+ warn_bound_listeners();
if (!option_bool(OPT_NOWILD))
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
@@ -856,6 +858,7 @@ int main (int argc, char **argv)
enumerate_interfaces(0);
/* NB, is_dad_listeners() == 1 --> we're binding interfaces */
create_bound_listeners(0);
+ warn_bound_listeners();
}
#ifdef HAVE_LINUX_NETWORK
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index adf0828..17a351f 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -454,7 +454,7 @@ struct ipsets {
struct irec {
union mysockaddr addr;
struct in_addr netmask; /* only valid for IPv4 */
- int tftp_ok, dhcp_ok, mtu, done, dad, dns_auth, index, multicast_done;
+ int tftp_ok, dhcp_ok, mtu, done, warned, dad, dns_auth, index, multicast_done;
char *name;
struct irec *next;
};
@@ -988,6 +988,7 @@ unsigned char *skip_questions(struct dns_header *header, size_t plen);
int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
char *name, int isExtract, int extrabytes);
int in_arpa_name_2_addr(char *namein, struct all_addr *addrp);
+int private_net(struct in_addr addr, int ban_localhost);
/* auth.c */
#ifdef HAVE_AUTH
@@ -1068,6 +1069,7 @@ void check_servers(void);
int enumerate_interfaces(int reset);
void create_wildcard_listeners(void);
void create_bound_listeners(int die);
+void warn_bound_listeners(void);
int is_dad_listeners(void);
int iface_check(int family, struct all_addr *addr, char *name, int *auth_dns);
int loopback_exception(int fd, int family, struct all_addr *addr, char *name);
diff --git a/src/network.c b/src/network.c
index fc0346e..de5d9f2 100644
--- a/src/network.c
+++ b/src/network.c
@@ -16,6 +16,10 @@
#include "dnsmasq.h"
+#ifndef IN6_IS_ADDR_ULA
+#define IN6_IS_ADDR_ULA(a) ((((__const uint32_t *) (a))[0] & htonl (0xfe00000)) == htonl (0xfc000000))
+#endif
+
#ifdef HAVE_LINUX_NETWORK
int indextoname(int fd, int index, char *name)
@@ -383,7 +387,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
iface->dns_auth = auth_dns;
iface->mtu = mtu;
iface->dad = dad;
- iface->done = iface->multicast_done = 0;
+ iface->done = iface->multicast_done = iface->warned = 0;
iface->index = if_index;
if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
{
@@ -824,6 +828,59 @@ void create_bound_listeners(int dienow)
}
}
+/* In --bind-interfaces, the only access control is the addresses we're listening on.
+ There's nothing to avoid a query to the address of an internal interface arriving via
+ an external interface where we don't want to accept queries, except that in the usual
+ case the addresses of internal interfaces are RFC1918. When bind-interfaces in use,
+ and we listen on an address that looks like it's probably globally routeable, shout.
+
+ The fix is to use --bind-dynamic, which actually checks the arrival interface too.
+ Tough if your platform doesn't support this.
+*/
+
+void warn_bound_listeners(void)
+{
+ struct irec *iface;
+ int advice = 0;
+
+ for (iface = daemon->interfaces; iface; iface = iface->next)
+ if (option_bool(OPT_NOWILD) && !iface->dns_auth)
+ {
+ int warn = 0;
+ if (iface->addr.sa.sa_family == AF_INET)
+ {
+ if (!private_net(iface->addr.in.sin_addr, 1))
+ {
+ inet_ntop(AF_INET, &iface->addr.in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
+ warn = 1;
+ }
+ }
+#ifdef HAVE_IPV6
+ else
+ {
+ if (!IN6_IS_ADDR_LINKLOCAL(&iface->addr.in6.sin6_addr) &&
+ !IN6_IS_ADDR_SITELOCAL(&iface->addr.in6.sin6_addr) &&
+ !IN6_IS_ADDR_ULA(&iface->addr.in6.sin6_addr) &&
+ !IN6_IS_ADDR_LOOPBACK(&iface->addr.in6.sin6_addr))
+ {
+ inet_ntop(AF_INET6, &iface->addr.in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN);
+ warn = 1;
+ }
+ }
+#endif
+ if (warn)
+ {
+ iface->warned = advice = 1;
+ my_syslog(LOG_WARNING,
+ _("LOUD WARNING: listening on %s may accept requests via interfaces other than %s. "),
+ daemon->addrbuff, iface->name);
+ }
+ }
+
+ if (advice)
+ my_syslog(LOG_WARNING, _("LOUD WARNING: use --bind-dynamic rather than --bind-interfaces to avoid DNS amplification attacks via these interface(s)."));
+}
+
int is_dad_listeners(void)
{
struct irec *iface;
diff --git a/src/rfc1035.c b/src/rfc1035.c
index 655216e..573ec31 100644
--- a/src/rfc1035.c
+++ b/src/rfc1035.c
@@ -724,7 +724,7 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
}
/* is addr in the non-globally-routed IP space? */
-static int private_net(struct in_addr addr, int ban_localhost)
+int private_net(struct in_addr addr, int ban_localhost)
{
in_addr_t ip_addr = ntohl(addr.s_addr);