summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2014-06-07 12:37:33 -0700
committerH. Peter Anvin <hpa@zytor.com>2014-06-07 12:37:33 -0700
commitc89a63a441cdd176c52740bf386b78548f46d492 (patch)
tree5ff8afc32788c1f7d6d21963024bbaddf915ff54
parent128e6a3905fe12c546ff1eb7cb7d71334407872d (diff)
downloadtftp-hpa-c89a63a441cdd176c52740bf386b78548f46d492.tar.gz
tftp: convert IPv6-mapped IPv4 addresses to IPv4
If we receive IPv4 addresses mapped to IPv6, convert them back to IPv4 so that mapping scripts which use \i behave sanely. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--tftpd/recvfrom.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/tftpd/recvfrom.c b/tftpd/recvfrom.c
index d050b80..b613823 100644
--- a/tftpd/recvfrom.c
+++ b/tftpd/recvfrom.c
@@ -113,6 +113,25 @@ err:
return rv;
}
+#ifdef HAVE_IPV6
+static void normalize_ip6_compat(union sock_addr *myaddr)
+{
+ static const uint8_t ip6_compat_prefix[12] =
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
+ struct sockaddr_in in;
+
+ if (!memcmp(&myaddr->s6.sin6_addr, ip6_compat_prefix,
+ sizeof ip6_compat_prefix)) {
+ bzero(&in, sizeof in);
+ in.sin_family = AF_INET;
+ in.sin_port = myaddr->s6.sin6_port;
+ memcpy(&in.sin_addr, (const char *)&myaddr->s6.sin6_addr +
+ sizeof ip6_compat_prefix, sizeof in.sin_addr);
+ memcpy(&myaddr->si, &in, sizeof in);
+ }
+}
+#endif
+
int
myrecvfrom(int s, void *buf, int len, unsigned int flags,
struct sockaddr *from, socklen_t * fromlen,
@@ -233,6 +252,7 @@ myrecvfrom(int s, void *buf, int len, unsigned int flags,
sizeof(struct in6_addr));
}
#endif
+ normalize_ip6_compat(myaddr);
}
#endif
}