summaryrefslogtreecommitdiff
path: root/usr.sbin/relayd/relayd.c
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2008-07-22 23:17:38 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2008-07-22 23:17:38 +0000
commitfbe219bd235dfb3465ac762683f46f5cc5c67dd4 (patch)
tree403f73864d2b321cd5c1ad59c8ec3000f01a2146 /usr.sbin/relayd/relayd.c
parent59e24e00344933c83781a4833897f7769c0250af (diff)
Add dynamic IPv6-to-IPv4 and IPv4-to-IPv6 translation inspired by
faithd(8) by doing a similar mapping of IPv4/6 addresses with relayd(8) and pf(4) redirections without the need of the faith(4) interface. The trick works in both directions, it can accept IPv6 connections and relay them to IPv4 hosts by extracting the last 4 octets from the IPv6 destination (like faithd(8)), and it can accept IPv4 connections and relay them to IPv6 hosts by prepending the 4 octets of the original IPv4 destination to a configured IPv6 prefix. An access list is not needed because the classification is done in pf.conf(5). It helps to get more faith in relayd. manpage bits ok jmc@ yes, sounds good todd@
Diffstat (limited to 'usr.sbin/relayd/relayd.c')
-rw-r--r--usr.sbin/relayd/relayd.c53
1 files changed, 52 insertions, 1 deletions
diff --git a/usr.sbin/relayd/relayd.c b/usr.sbin/relayd/relayd.c
index fad7f12692d..accff773de0 100644
--- a/usr.sbin/relayd/relayd.c
+++ b/usr.sbin/relayd/relayd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: relayd.c,v 1.78 2008/07/09 14:06:44 reyk Exp $ */
+/* $OpenBSD: relayd.c,v 1.79 2008/07/22 23:17:37 reyk Exp $ */
/*
* Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org>
@@ -1199,3 +1199,54 @@ bindany(struct ctl_bindany *bnd)
close(s);
return (-1);
}
+
+int
+map6to4(struct sockaddr_storage *in6)
+{
+ struct sockaddr_storage out4;
+ struct sockaddr_in *sin4 = (struct sockaddr_in *)&out4;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)in6;
+
+ bzero(sin4, sizeof(*sin4));
+ sin4->sin_len = sizeof(*sin4);
+ sin4->sin_family = AF_INET;
+ sin4->sin_port = sin6->sin6_port;
+
+ bcopy(&sin6->sin6_addr.s6_addr[12], &sin4->sin_addr.s_addr,
+ sizeof(sin4->sin_addr));
+
+ if (sin4->sin_addr.s_addr == INADDR_ANY ||
+ sin4->sin_addr.s_addr == INADDR_BROADCAST ||
+ IN_MULTICAST(ntohl(sin4->sin_addr.s_addr)))
+ return (-1);
+
+ bcopy(&out4, in6, sizeof(*in6));
+
+ return (0);
+}
+
+int
+map4to6(struct sockaddr_storage *in4, struct sockaddr_storage *map)
+{
+ struct sockaddr_storage out6;
+ struct sockaddr_in *sin4 = (struct sockaddr_in *)in4;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&out6;
+ struct sockaddr_in6 *map6 = (struct sockaddr_in6 *)map;
+
+ if (sin4->sin_addr.s_addr == INADDR_ANY ||
+ sin4->sin_addr.s_addr == INADDR_BROADCAST ||
+ IN_MULTICAST(ntohl(sin4->sin_addr.s_addr)))
+ return (-1);
+
+ bcopy(map6, sin6, sizeof(*sin6));
+ sin6->sin6_len = sizeof(*sin6);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = sin4->sin_port;
+
+ bcopy(&sin4->sin_addr.s_addr, &sin6->sin6_addr.s6_addr[12],
+ sizeof(sin4->sin_addr));
+
+ bcopy(&out6, in4, sizeof(*in4));
+
+ return (0);
+}