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,6 +1354,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
int if_index;
|
int if_index;
|
||||||
|
char intr_name[IF_NAMESIZE];
|
||||||
|
|
||||||
/* In full wildcard mode, need to refresh interface list.
|
/* In full wildcard mode, need to refresh interface list.
|
||||||
This happens automagically in CLEVERBIND */
|
This happens automagically in CLEVERBIND */
|
||||||
@@ -1361,13 +1362,21 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
|||||||
enumerate_interfaces();
|
enumerate_interfaces();
|
||||||
|
|
||||||
/* if we can find the arrival interface, check it's one that's allowed */
|
/* 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 ((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)
|
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||||
if (iface->index == if_index)
|
if (iface->index == if_index)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!iface)
|
if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
|
||||||
client_ok = 0;
|
client_ok = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1002,6 +1002,7 @@ void create_wildcard_listeners(void);
|
|||||||
void create_bound_listeners(int die);
|
void create_bound_listeners(int die);
|
||||||
int is_dad_listeners(void);
|
int is_dad_listeners(void);
|
||||||
int iface_check(int family, struct all_addr *addr, char *name, int *auth_dns);
|
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 fix_fd(int fd);
|
||||||
int tcp_interface(int fd, int af);
|
int tcp_interface(int fd, int af);
|
||||||
struct in_addr get_ifaddr(char *intr);
|
struct in_addr get_ifaddr(char *intr);
|
||||||
|
|||||||
@@ -763,10 +763,17 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
|
|
||||||
/* enforce available interface configuration */
|
/* enforce available interface configuration */
|
||||||
|
|
||||||
if (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
|
if (!indextoname(listen->fd, if_index, ifr.ifr_name))
|
||||||
!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns))
|
|
||||||
return;
|
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))
|
if (listen->family == AF_INET && option_bool(OPT_LOCALISE))
|
||||||
{
|
{
|
||||||
struct irec *iface;
|
struct irec *iface;
|
||||||
@@ -780,7 +787,7 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* interface may be new */
|
/* interface may be new */
|
||||||
if (!iface)
|
if (!iface && !option_bool(OPT_CLEVERBIND))
|
||||||
enumerate_interfaces();
|
enumerate_interfaces();
|
||||||
|
|
||||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||||
|
|||||||
@@ -171,6 +171,39 @@ int iface_check(int family, struct all_addr *addr, char *name, int *auth)
|
|||||||
return ret;
|
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,
|
static int iface_allowed(struct irec **irecp, int if_index,
|
||||||
union mysockaddr *addr, struct in_addr netmask, int dad)
|
union mysockaddr *addr, struct in_addr netmask, int dad)
|
||||||
{
|
{
|
||||||
|
|||||||
15
src/tftp.c
15
src/tftp.c
@@ -61,6 +61,7 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
char *name = NULL;
|
char *name = NULL;
|
||||||
char *prefix = daemon->tftp_prefix;
|
char *prefix = daemon->tftp_prefix;
|
||||||
struct tftp_prefix *pref;
|
struct tftp_prefix *pref;
|
||||||
|
struct all_addr addra;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct cmsghdr align; /* this ensures alignment */
|
struct cmsghdr align; /* this ensures alignment */
|
||||||
@@ -190,16 +191,20 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
|
|
||||||
name = namebuff;
|
name = namebuff;
|
||||||
|
|
||||||
|
addra.addr.addr4 = addr.in.sin_addr;
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if (listen->family == AF_INET6)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
#endif
|
|
||||||
if (!iface_check(AF_INET, (struct all_addr *)&addr.in.sin_addr, name, NULL))
|
|
||||||
return;
|
|
||||||
|
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
/* allowed interfaces are the same as for DHCP */
|
/* allowed interfaces are the same as for DHCP */
|
||||||
|
|||||||
Reference in New Issue
Block a user