mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
Handle wrong interface for locally-routed packets.
This commit is contained in:
@@ -1354,20 +1354,29 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
else
|
||||
{
|
||||
int if_index;
|
||||
|
||||
char intr_name[IF_NAMESIZE];
|
||||
|
||||
/* In full wildcard mode, need to refresh interface list.
|
||||
This happens automagically in CLEVERBIND */
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces();
|
||||
|
||||
/* if we can find the arrival interface, check it's one that's allowed */
|
||||
if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0)
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces();
|
||||
|
||||
/* if we can find the arrival interface, check it's one that's allowed */
|
||||
if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
|
||||
indextoname(listener->tcpfd, if_index, intr_name))
|
||||
{
|
||||
struct all_addr addr;
|
||||
addr.addr.addr4 = tcp_addr.in.sin_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
if (tcp_addr.sa.sa_family == AF_INET6)
|
||||
addr.addr.addr6 = tcp_addr.in6.sin6_addr;
|
||||
#endif
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->index == if_index)
|
||||
break;
|
||||
|
||||
if (!iface)
|
||||
if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
|
||||
client_ok = 0;
|
||||
}
|
||||
|
||||
@@ -1375,10 +1384,10 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
iface = listener->iface; /* May be NULL */
|
||||
else
|
||||
{
|
||||
/* Check for allowed interfaces when binding the wildcard address:
|
||||
we do this by looking for an interface with the same address as
|
||||
the local address of the TCP connection, then looking to see if that's
|
||||
an allowed interface. As a side effect, we get the netmask of the
|
||||
/* Check for allowed interfaces when binding the wildcard address:
|
||||
we do this by looking for an interface with the same address as
|
||||
the local address of the TCP connection, then looking to see if that's
|
||||
an allowed interface. As a side effect, we get the netmask of the
|
||||
interface too, for localisation. */
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
|
||||
@@ -1002,6 +1002,7 @@ void create_wildcard_listeners(void);
|
||||
void create_bound_listeners(int die);
|
||||
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);
|
||||
int fix_fd(int fd);
|
||||
int tcp_interface(int fd, int af);
|
||||
struct in_addr get_ifaddr(char *intr);
|
||||
|
||||
@@ -763,10 +763,17 @@ void receive_query(struct listener *listen, time_t now)
|
||||
|
||||
/* enforce available interface configuration */
|
||||
|
||||
if (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
|
||||
!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns))
|
||||
if (!indextoname(listen->fd, if_index, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
if (!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns))
|
||||
{
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces();
|
||||
if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name))
|
||||
return;
|
||||
}
|
||||
|
||||
if (listen->family == AF_INET && option_bool(OPT_LOCALISE))
|
||||
{
|
||||
struct irec *iface;
|
||||
@@ -780,7 +787,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
break;
|
||||
|
||||
/* interface may be new */
|
||||
if (!iface)
|
||||
if (!iface && !option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces();
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
|
||||
@@ -170,7 +170,40 @@ int iface_check(int family, struct all_addr *addr, char *name, int *auth)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Fix for problem that the kernel sometimes reports the loopback inerface as the
|
||||
arrival interface when a packet originates locally, even when sent to address of
|
||||
an interface other than the loopback. Accept packet if it arrived via a loopback
|
||||
interface, even when we're not accepting packets that way, as long as the destination
|
||||
address is one we're believing. Interface list must be up-to-date before calling. */
|
||||
int loopback_exception(int fd, int family, struct all_addr *addr, char *name)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
struct irec *iface;
|
||||
|
||||
strncpy(ifr.ifr_name, name, IF_NAMESIZE);
|
||||
if (ioctl(fd, SIOCGIFFLAGS, &ifr) != -1 &&
|
||||
ifr.ifr_flags & IFF_LOOPBACK)
|
||||
{
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->addr.sa.sa_family == family)
|
||||
{
|
||||
if (family == AF_INET)
|
||||
{
|
||||
if (iface->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
|
||||
return 1;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (IN6_ARE_ADDR_EQUAL(&iface->addr.in6.sin6_addr, &addr->addr.addr6))
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iface_allowed(struct irec **irecp, int if_index,
|
||||
union mysockaddr *addr, struct in_addr netmask, int dad)
|
||||
{
|
||||
|
||||
17
src/tftp.c
17
src/tftp.c
@@ -61,6 +61,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
char *name = NULL;
|
||||
char *prefix = daemon->tftp_prefix;
|
||||
struct tftp_prefix *pref;
|
||||
struct all_addr addra;
|
||||
|
||||
union {
|
||||
struct cmsghdr align; /* this ensures alignment */
|
||||
@@ -189,18 +190,22 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
return;
|
||||
|
||||
name = namebuff;
|
||||
|
||||
addra.addr.addr4 = addr.in.sin_addr;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (listen->family == AF_INET6)
|
||||
addra.addr.addr6 = addr.in6.sin6_addr;
|
||||
#endif
|
||||
|
||||
if (!iface_check(listen->family, &addra, name, NULL))
|
||||
{
|
||||
if (!iface_check(AF_INET6, (struct all_addr *)&addr.in6.sin6_addr, name, NULL))
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces();
|
||||
if (!loopback_exception(listen->tftpfd, listen->family, &addra, name))
|
||||
return;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (!iface_check(AF_INET, (struct all_addr *)&addr.in.sin_addr, name, NULL))
|
||||
return;
|
||||
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
/* allowed interfaces are the same as for DHCP */
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
|
||||
Reference in New Issue
Block a user