Subject: bin/8640: Relay loop in faithd(8)
To: None <gnats-bugs@gnats.netbsd.org>
From: Feico Dillema <dillema@acm.org>
List: netbsd-bugs
Date: 10/17/1999 15:50:54
>Number: 8640
>Category: bin
>Synopsis: faithd enters relay loop for IPv4 connections
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: bin-bug-people (Utility Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sun Oct 17 15:03:00 1999
>Last-Modified:
>Originator: Feico Dillema
>Organization:
University of Tromso
>Release: Sun Oct 17 1999
>Environment:
System: NetBSD server6 1.4K NetBSD 1.4K (PASTA.v6) #2: Tue Sep 28 01:46:29 CEST 1999 root@server6:/usr/src/sys/arch/i386/compile/PASTA.v6 i386
>Description:
When faithd(8) is used to relay connections *and* to
accept connections for local service it will enter
a relay loop if the target address is an IPv4 address.
>How-To-Repeat:
Example:
say, machine has local IPv4 address A.B.C.D,
and a faithd is started on it for e.g. telnet as:
faithd telnet /usr/libexec/telnetd telnetd
Now a `telnet A.B.C.D` to this machine makes faithd enter a relay loop
due to fact that it sees an incoming connection for the IPV4MAPPED
address: ::ffff:A.B.C.D. Instead of starting a local telnetd to serve
the request, it translates ::ffff:A.B.C.D into IPv4 address A.B.C.D
and relays the connection this address. This relayed connection to
A.B.C.D is comes into faithd again as ::ffff:A.B.C.D, which repeats
the relay process untill the kernel runs out of proc-table entries.
>Fix:
The following little patch adds support for IPv4 Mapped Addresses
to src/usr.sbin/faith/faithd.c and avoids the relay loop:
--- faithd.c.orig Sun Oct 17 23:41:04 1999
+++ faithd.c Sun Oct 17 23:42:06 1999
@@ -508,14 +508,14 @@
struct sockaddr_in *sin4;
for (p = myaddrs; p; p = p->next) {
+ struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)dst;
+ struct sockaddr_in *dst4 = (struct sockaddr_in *)dst;
sin6 = (struct sockaddr_in6 *)p->addr;
sin4 = (struct sockaddr_in *)p->addr;
/* ugly! */
if (p->addr->sa_len == dst->sa_len
&& p->addr->sa_family == dst->sa_family) {
- struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)dst;
- struct sockaddr_in *dst4 = (struct sockaddr_in *)dst;
switch (dst->sa_family) {
case AF_INET6:
@@ -526,6 +526,18 @@
case AF_INET:
if (sin4->sin_addr.s_addr == dst4->sin_addr.s_addr)
return 0;
+ break;
+ }
+ }
+ else { /* probably even uglier ? */
+
+ switch (dst->sa_family) {
+ case AF_INET6:
+ if (IN6_IS_ADDR_V4MAPPED(&(dst6->sin6_addr)))
+ if (sin4->sin_addr.s_addr == dst6->sin6_addr.s6_addr32[3])
+ return 0;
+ break;
+ default:
break;
}
}
>Audit-Trail:
>Unformatted: