diff mbox

[3/3] libxtables: avoid returning duplicate address for host resolution

Message ID 20170308162658.5697-4-jengelh@inai.de
State Not Applicable
Delegated to: Pablo Neira
Headers show

Commit Message

Jan Engelhardt March 8, 2017, 4:26 p.m. UTC
A long-standing problem has been that `iptables -s any_host_here`
could yield multiple rules with the same address if the DNS was
indeed so populated.

Signed-off-by: Jan Engelhardt <jengelh@inai.de>
---
 libxtables/xtables.c | 44 ++++++++++++++++++++++++++++++++------------
 1 file changed, 32 insertions(+), 12 deletions(-)

Comments

Pablo Neira Ayuso March 8, 2017, 4:45 p.m. UTC | #1
On Wed, Mar 08, 2017 at 05:26:58PM +0100, Jan Engelhardt wrote:
> A long-standing problem has been that `iptables -s any_host_here`
> could yield multiple rules with the same address if the DNS was
> indeed so populated.

When did anyone report this problem out of the localhost case?
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jan Engelhardt March 8, 2017, 4:56 p.m. UTC | #2
On Wednesday 2017-03-08 17:45, Pablo Neira Ayuso wrote:

>On Wed, Mar 08, 2017 at 05:26:58PM +0100, Jan Engelhardt wrote:
>> A long-standing problem has been that `iptables -s any_host_here`
>> could yield multiple rules with the same address if the DNS was
>> indeed so populated.
>
>When did anyone report this problem out of the localhost case?

It's been a long time. I think the issue was actually that one can 
specify multiple host names, and if those hostnames happen to resolve to 
the same address in the end, iptables would emit two rules of which one 
is essentially redundant.

  iptables -A INPUT -s www2.company.com,www3.company.com
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Pablo Neira Ayuso March 10, 2017, 6:22 p.m. UTC | #3
On Wed, Mar 08, 2017 at 05:56:43PM +0100, Jan Engelhardt wrote:
> On Wednesday 2017-03-08 17:45, Pablo Neira Ayuso wrote:
> 
> >On Wed, Mar 08, 2017 at 05:26:58PM +0100, Jan Engelhardt wrote:
> >> A long-standing problem has been that `iptables -s any_host_here`
> >> could yield multiple rules with the same address if the DNS was
> >> indeed so populated.
> >
> >When did anyone report this problem out of the localhost case?
> 
> It's been a long time. I think the issue was actually that one can 
> specify multiple host names, and if those hostnames happen to resolve to 
> the same address in the end, iptables would emit two rules of which one 
> is essentially redundant.
> 
>   iptables -A INPUT -s www2.company.com,www3.company.com

Got me thinking, are you sure we want to fix this?

I think this rule expansion based on DNS is probably one of the most
creepy features that we have in iptables... Probably if we leave it
broken this will just scare people away from using this :).

But your call.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index 891d81a..d994306 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -1364,7 +1364,7 @@  static struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
 	struct addrinfo hints;
 	struct addrinfo *res, *p;
 	int err;
-	unsigned int i;
+	size_t i, j;
 
 	memset(&hints, 0, sizeof(hints));
 	hints.ai_family   = AF_INET;
@@ -1374,14 +1374,23 @@  static struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
 	err = getaddrinfo(name, NULL, &hints, &res);
 	if (err != 0)
 		return NULL;
-	for (p = res; p != NULL; p = p->ai_next)
-		++*naddr;
 	addr = xtables_calloc(*naddr, sizeof(struct in_addr));
-	for (i = 0, p = res; p != NULL; p = p->ai_next)
-		memcpy(&addr[i++],
-		       &((const struct sockaddr_in *)p->ai_addr)->sin_addr,
-		       sizeof(struct in_addr));
+	for (i = 0, p = res; p != NULL; p = p->ai_next) {
+		const struct sockaddr_in *newaddr = (const void *)p->ai_addr;
+		bool seen = false;
+
+		for (j = 0; j < i; ++j) {
+			if (memcmp(newaddr, &addr[j], sizeof(*newaddr)) == 0) {
+				seen = true;
+				break;
+			}
+		}
+		if (seen)
+			continue;
+		memcpy(&addr[i++], &newaddr->sin_addr, sizeof(newaddr->sin_addr));
+	}
 	freeaddrinfo(res);
+	*naddr = i;
 	return addr;
 }
 
@@ -1650,7 +1659,7 @@  host_to_ip6addr(const char *name, unsigned int *naddr)
 	struct addrinfo hints;
 	struct addrinfo *res, *p;
 	int err;
-	unsigned int i;
+	size_t i, j;
 
 	memset(&hints, 0, sizeof(hints));
 	hints.ai_family   = AF_INET6;
@@ -1665,11 +1674,22 @@  host_to_ip6addr(const char *name, unsigned int *naddr)
 		++*naddr;
 	/* Copy each element of the address chain */
 	addr = xtables_calloc(*naddr, sizeof(struct in6_addr));
-	for (i = 0, p = res; p != NULL; p = p->ai_next)
-		memcpy(&addr[i++],
-		       &((const struct sockaddr_in6 *)p->ai_addr)->sin6_addr,
-		       sizeof(struct in6_addr));
+	for (i = 0, p = res; p != NULL; p = p->ai_next) {
+		const struct sockaddr_in6 *newaddr = (const void *)p->ai_addr;
+		bool seen = false;
+
+		for (j = 0; j < i; ++j) {
+			if (memcmp(newaddr, &addr[j], sizeof(*newaddr)) == 0) {
+				seen = true;
+				break;
+			}
+		}
+		if (seen)
+			continue;
+		memcpy(&addr[i++], &newaddr->sin6_addr, sizeof(newaddr->sin6_addr));
+	}
 	freeaddrinfo(res);
+	*naddr = i;
 	return addr;
 }