Add --servers-file. Allows dynamic update of upstream servers
full access to configuration.
-
+ Add --local-service. Accept DNS queries only from hosts
+ whose address is on a local subnet, ie a subnet for which
+ an interface exists on the server. This option
+ only has effect is there are no --interface --except-interface,
+ --listen-address or --auth-server options. It is intended
+ to be set as a default on installation, to allow
+ unconfigured installations to be useful but also safe from
+ being used for DNS amplification attacks.
+
+
version 2.68
Use random addresses for DHCPv6 temporary address
allocations, instead of algorithmically determined stable
the address dnsmasq is listening on. When an interface is specified,
it may be qualified with "/4" or "/6" to specify only the IPv4 or IPv6
addresses associated with the interface.
+.TP
+.B --local-service
+Accept DNS queries only from hosts whose address is on a local subnet,
+ie a subnet for which an interface exists on the server. This option
+only has effect is there are no --interface --except-interface,
+--listen-address or --auth-server options. It is intended to be set as
+a default on installation, to allow unconfigured installations to be
+useful but also safe from being used for DNS amplification attacks.
.TP
.B \-2, --no-dhcp-interface=<interface name>
Do not provide DHCP or TFTP on the specified interface, but do provide DNS service.
#define OPT_DNSSEC_PERMISS 46
#define OPT_DNSSEC_DEBUG 47
#define OPT_DNSSEC_NO_SIGN 48
-#define OPT_LAST 49
+#define OPT_LOCAL_SERVICE 49
+#define OPT_LAST 50
/* extra flags for my_syslog, we use a couple of facilities since they are known
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
pid_t tcp_pids[MAX_PROCS];
struct randfd randomsocks[RANDOM_SOCKS];
int v6pktinfo;
+ struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */
/* DHCP state */
int dhcpfd, helperfd, pxefd;
source_addr.in6.sin6_flowinfo = 0;
#endif
+ /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
+ if (option_bool(OPT_LOCAL_SERVICE))
+ {
+ struct addrlist *addr;
+#ifdef HAVE_IPV6
+ if (listen->family == AF_INET6)
+ {
+ for (addr = daemon->interface_addrs; addr; addr = addr->next)
+ if ((addr->flags & ADDRLIST_IPV6) &&
+ is_same_net6(&addr->addr.addr.addr6, &source_addr.in6.sin6_addr, addr->prefixlen))
+ break;
+ }
+ else
+#endif
+ {
+ struct in_addr netmask;
+ for (addr = daemon->interface_addrs; addr; addr = addr->next)
+ {
+ netmask.s_addr = 0xffffffff << (32 - addr->prefixlen);
+ if (!(addr->flags & ADDRLIST_IPV6) &&
+ is_same_net(addr->addr.addr.addr4, source_addr.in.sin_addr, netmask))
+ break;
+ }
+ }
+ if (!addr)
+ {
+ my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
+ return;
+ }
+ }
+
if (check_dst)
{
struct ifreq ifr;
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
return packet;
+
+ /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
+ if (option_bool(OPT_LOCAL_SERVICE))
+ {
+ struct addrlist *addr;
+#ifdef HAVE_IPV6
+ if (peer_addr.sa.sa_family == AF_INET6)
+ {
+ for (addr = daemon->interface_addrs; addr; addr = addr->next)
+ if ((addr->flags & ADDRLIST_IPV6) &&
+ is_same_net6(&addr->addr.addr.addr6, &peer_addr.in6.sin6_addr, addr->prefixlen))
+ break;
+ }
+ else
+#endif
+ {
+ struct in_addr netmask;
+ for (addr = daemon->interface_addrs; addr; addr = addr->next)
+ {
+ netmask.s_addr = 0xffffffff << (32 - addr->prefixlen);
+ if (!(addr->flags & ADDRLIST_IPV6) &&
+ is_same_net(addr->addr.addr.addr4, peer_addr.in.sin_addr, netmask))
+ break;
+ }
+ }
+ if (!addr)
+ {
+ my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
+ return packet;
+ }
+ }
while (1)
{
if (!label)
label = ifr.ifr_name;
+
+ /* maintain a list of all addresses on all interfaces for --local-service option */
+ if (option_bool(OPT_LOCAL_SERVICE))
+ {
+ struct addrlist *al;
+ if (param->spare)
+ {
+ al = param->spare;
+ param->spare = al->next;
+ }
+ else
+ al = whine_malloc(sizeof(struct addrlist));
+
+ if (al)
+ {
+ al->next = daemon->interface_addrs;
+ daemon->interface_addrs = al;
+ al->prefixlen = prefixlen;
+
+ if (addr->sa.sa_family == AF_INET)
+ {
+ al->addr.addr.addr4 = addr->in.sin_addr;
+ al->flags = 0;
+ }
+#ifdef HAVE_IPV6
+ else
+ {
+ al->addr.addr.addr6 = addr->in6.sin6_addr;
+ al->flags = ADDRLIST_IPV6;
+ }
+#endif
+ }
+ }
#ifdef HAVE_IPV6
if (addr->sa.sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr))
intname->addr = NULL;
}
+ /* Remove list of addresses of local interfaces */
+ for (addr = daemon->interface_addrs; addr; addr = tmp)
+ {
+ tmp = addr->next;
+ addr->next = spare;
+ spare = addr;
+ }
+ daemon->interface_addrs = NULL;
+
#ifdef HAVE_AUTH
/* remove addresses stored against auth_zone subnets, but not
ones configured as address literals */
#define LOPT_REV_SERV 332
#define LOPT_SERVERS_FILE 333
#define LOPT_DNSSEC_CHECK 334
+#define LOPT_LOCAL_SERVICE 335
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
{ "domain-suffix", 1, 0, 's' },
{ "interface", 1, 0, 'i' },
{ "listen-address", 1, 0, 'a' },
+ { "local-service", 0, 0, LOPT_LOCAL_SERVICE },
{ "bogus-priv", 0, 0, 'b' },
{ "bogus-nxdomain", 1, 0, 'B' },
{ "selfmx", 0, 0, 'e' },
{ LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
{ LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
{ LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },
+ { LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks"), NULL },
{ 0, 0, NULL, NULL, NULL }
};
else if (option_bool(OPT_DHCP_FQDN))
die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
+ /* If there's access-control config, then ignore --local-service, it's intended
+ as a system default to keep otherwise unconfigured installations safe. */
+ if (daemon->if_names || daemon->if_except || daemon->if_addrs || daemon->authserver)
+ reset_option_bool(OPT_LOCAL_SERVICE);
+
if (testmode)
{
fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));