diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2008-07-22 23:17:38 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2008-07-22 23:17:38 +0000 |
commit | fbe219bd235dfb3465ac762683f46f5cc5c67dd4 (patch) | |
tree | 403f73864d2b321cd5c1ad59c8ec3000f01a2146 /usr.sbin/relayd/relayd.c | |
parent | 59e24e00344933c83781a4833897f7769c0250af (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.c | 53 |
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); +} |