mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-20 02:38:32 +00:00
--local-service. Default protection from DNS amplification attacks.
This commit is contained in:
@@ -67,6 +67,15 @@ version 2.69
|
|||||||
Add --servers-file. Allows dynamic update of upstream servers
|
Add --servers-file. Allows dynamic update of upstream servers
|
||||||
full access to configuration.
|
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
|
version 2.68
|
||||||
Use random addresses for DHCPv6 temporary address
|
Use random addresses for DHCPv6 temporary address
|
||||||
|
|||||||
@@ -209,6 +209,14 @@ 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
|
it may be qualified with "/4" or "/6" to specify only the IPv4 or IPv6
|
||||||
addresses associated with the interface.
|
addresses associated with the interface.
|
||||||
.TP
|
.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>
|
.B \-2, --no-dhcp-interface=<interface name>
|
||||||
Do not provide DHCP or TFTP on the specified interface, but do provide DNS service.
|
Do not provide DHCP or TFTP on the specified interface, but do provide DNS service.
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
@@ -233,7 +233,8 @@ struct event_desc {
|
|||||||
#define OPT_DNSSEC_PERMISS 46
|
#define OPT_DNSSEC_PERMISS 46
|
||||||
#define OPT_DNSSEC_DEBUG 47
|
#define OPT_DNSSEC_DEBUG 47
|
||||||
#define OPT_DNSSEC_NO_SIGN 48
|
#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
|
/* 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. */
|
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
|
||||||
@@ -966,6 +967,7 @@ extern struct daemon {
|
|||||||
pid_t tcp_pids[MAX_PROCS];
|
pid_t tcp_pids[MAX_PROCS];
|
||||||
struct randfd randomsocks[RANDOM_SOCKS];
|
struct randfd randomsocks[RANDOM_SOCKS];
|
||||||
int v6pktinfo;
|
int v6pktinfo;
|
||||||
|
struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */
|
||||||
|
|
||||||
/* DHCP state */
|
/* DHCP state */
|
||||||
int dhcpfd, helperfd, pxefd;
|
int dhcpfd, helperfd, pxefd;
|
||||||
|
|||||||
@@ -1081,6 +1081,37 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
source_addr.in6.sin6_flowinfo = 0;
|
source_addr.in6.sin6_flowinfo = 0;
|
||||||
#endif
|
#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)
|
if (check_dst)
|
||||||
{
|
{
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
@@ -1545,6 +1576,37 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
||||||
return packet;
|
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)
|
while (1)
|
||||||
{
|
{
|
||||||
if (!packet ||
|
if (!packet ||
|
||||||
|
|||||||
@@ -269,6 +269,39 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
|
|||||||
if (!label)
|
if (!label)
|
||||||
label = ifr.ifr_name;
|
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
|
#ifdef HAVE_IPV6
|
||||||
if (addr->sa.sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr))
|
if (addr->sa.sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr))
|
||||||
@@ -565,6 +598,15 @@ int enumerate_interfaces(int reset)
|
|||||||
intname->addr = NULL;
|
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
|
#ifdef HAVE_AUTH
|
||||||
/* remove addresses stored against auth_zone subnets, but not
|
/* remove addresses stored against auth_zone subnets, but not
|
||||||
ones configured as address literals */
|
ones configured as address literals */
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ struct myoption {
|
|||||||
#define LOPT_REV_SERV 332
|
#define LOPT_REV_SERV 332
|
||||||
#define LOPT_SERVERS_FILE 333
|
#define LOPT_SERVERS_FILE 333
|
||||||
#define LOPT_DNSSEC_CHECK 334
|
#define LOPT_DNSSEC_CHECK 334
|
||||||
|
#define LOPT_LOCAL_SERVICE 335
|
||||||
|
|
||||||
#ifdef HAVE_GETOPT_LONG
|
#ifdef HAVE_GETOPT_LONG
|
||||||
static const struct option opts[] =
|
static const struct option opts[] =
|
||||||
@@ -175,6 +176,7 @@ static const struct myoption opts[] =
|
|||||||
{ "domain-suffix", 1, 0, 's' },
|
{ "domain-suffix", 1, 0, 's' },
|
||||||
{ "interface", 1, 0, 'i' },
|
{ "interface", 1, 0, 'i' },
|
||||||
{ "listen-address", 1, 0, 'a' },
|
{ "listen-address", 1, 0, 'a' },
|
||||||
|
{ "local-service", 0, 0, LOPT_LOCAL_SERVICE },
|
||||||
{ "bogus-priv", 0, 0, 'b' },
|
{ "bogus-priv", 0, 0, 'b' },
|
||||||
{ "bogus-nxdomain", 1, 0, 'B' },
|
{ "bogus-nxdomain", 1, 0, 'B' },
|
||||||
{ "selfmx", 0, 0, 'e' },
|
{ "selfmx", 0, 0, 'e' },
|
||||||
@@ -448,6 +450,7 @@ static struct {
|
|||||||
{ LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
|
{ 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_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_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 }
|
{ 0, 0, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -4457,6 +4460,11 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
|||||||
else if (option_bool(OPT_DHCP_FQDN))
|
else if (option_bool(OPT_DHCP_FQDN))
|
||||||
die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
|
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)
|
if (testmode)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));
|
fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));
|
||||||
|
|||||||
Reference in New Issue
Block a user