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 | |
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@
-rw-r--r-- | usr.sbin/relayd/parse.y | 30 | ||||
-rw-r--r-- | usr.sbin/relayd/relay.c | 20 | ||||
-rw-r--r-- | usr.sbin/relayd/relayd.c | 53 | ||||
-rw-r--r-- | usr.sbin/relayd/relayd.conf.5 | 36 | ||||
-rw-r--r-- | usr.sbin/relayd/relayd.h | 5 |
5 files changed, 131 insertions, 13 deletions
diff --git a/usr.sbin/relayd/parse.y b/usr.sbin/relayd/parse.y index b8812cac4c8..1fa08a74550 100644 --- a/usr.sbin/relayd/parse.y +++ b/usr.sbin/relayd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.121 2008/07/19 11:38:54 reyk Exp $ */ +/* $OpenBSD: parse.y,v 1.122 2008/07/22 23:17:37 reyk Exp $ */ /* * Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org> @@ -130,7 +130,7 @@ typedef struct { %token ON PATH PORT PREFORK PROTO QUERYSTR REAL REDIRECT RELAY REMOVE TRAP %token REQUEST RESPONSE RETRY RETURN ROUNDROBIN SACK SCRIPT SEND SESSION %token SOCKET SSL STICKYADDR STYLE TABLE TAG TCP TIMEOUT TO UPDATES URL -%token VIRTUAL WITH ERROR ROUTE TRANSPARENT PARENT +%token VIRTUAL WITH ERROR ROUTE TRANSPARENT PARENT INET INET6 %token <v.string> STRING %token <v.number> NUMBER %type <v.string> interface hostname table @@ -1136,7 +1136,7 @@ relayoptsl : LISTEN ON STRING port optssl { } tableport = h->port; } - | forwardmode TO forwardspec interface { + | forwardmode TO forwardspec interface dstaf { rlay->rl_conf.fwdmode = $1; switch ($1) { case FWD_NORMAL: @@ -1234,6 +1234,28 @@ dstmode : /* empty */ { $$ = RELAY_DSTMODE_DEFAULT; } | HASH { $$ = RELAY_DSTMODE_HASH; } ; +dstaf : /* empty */ { + rlay->rl_conf.dstaf.ss_family = AF_UNSPEC; + } + | INET { + rlay->rl_conf.dstaf.ss_family = AF_INET; + } + | INET6 STRING { + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *)&rlay->rl_conf.dstaf; + if (inet_pton(AF_INET6, $2, &sin6->sin6_addr) == -1) { + yyerror("invalid ipv6 address %s", $2); + free($2); + YYERROR; + } + free($2); + + sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(*sin6); + } + ; + interface : /*empty*/ { $$ = NULL; } | INTERFACE STRING { $$ = $2; } ; @@ -1373,6 +1395,8 @@ lookup(char *s) { "host", HOST }, { "icmp", ICMP }, { "include", INCLUDE }, + { "inet", INET }, + { "inet6", INET6 }, { "interface", INTERFACE }, { "interval", INTERVAL }, { "ip", IP }, diff --git a/usr.sbin/relayd/relay.c b/usr.sbin/relayd/relay.c index 21cbc69750e..f1dc6b066c4 100644 --- a/usr.sbin/relayd/relay.c +++ b/usr.sbin/relayd/relay.c @@ -1,4 +1,4 @@ -/* $OpenBSD: relay.c,v 1.94 2008/07/16 15:02:19 reyk Exp $ */ +/* $OpenBSD: relay.c,v 1.95 2008/07/22 23:17:37 reyk Exp $ */ /* * Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org> @@ -2186,7 +2186,7 @@ int relay_connect(struct session *con) { struct relay *rlay = (struct relay *)con->se_relay; - int bnds = -1; + int bnds = -1, ret; if (gettimeofday(&con->se_tv_start, NULL)) return (-1); @@ -2208,6 +2208,22 @@ relay_connect(struct session *con) bnds = con->se_bnds; } + /* Do the IPv4-to-IPv6 or IPv6-to-IPv4 translation if requested */ + if (rlay->rl_conf.dstaf.ss_family != AF_UNSPEC) { + if (con->se_out.ss.ss_family == AF_INET && + rlay->rl_conf.dstaf.ss_family == AF_INET6) + ret = map4to6(&con->se_out.ss, &rlay->rl_conf.dstaf); + else if (con->se_out.ss.ss_family == AF_INET6 && + rlay->rl_conf.dstaf.ss_family == AF_INET) + ret = map6to4(&con->se_out.ss); + else + ret = 0; + if (ret != 0) { + log_debug("relay_connect: mapped to invalid address"); + return (-1); + } + } + retry: if ((con->se_out.s = relay_socket_connect(&con->se_out.ss, con->se_out.port, rlay->rl_proto, bnds)) == -1) { 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); +} diff --git a/usr.sbin/relayd/relayd.conf.5 b/usr.sbin/relayd/relayd.conf.5 index 8314273a2b1..19956ae7564 100644 --- a/usr.sbin/relayd/relayd.conf.5 +++ b/usr.sbin/relayd/relayd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: relayd.conf.5,v 1.90 2008/07/19 16:35:50 jmc Exp $ +.\" $OpenBSD: relayd.conf.5,v 1.91 2008/07/22 23:17:37 reyk Exp $ .\" .\" Copyright (c) 2006, 2007 Reyk Floeter <reyk@openbsd.org> .\" Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: July 19 2008 $ +.Dd $Mdocdate: July 22 2008 $ .Dt RELAYD.CONF 5 .Os .Sh NAME @@ -489,7 +489,7 @@ Start the relay but immediately close any accepted connections. .Ic forward to .Ar address .Op Ic port Ar port -.Op Ic retry Ar number +.Ar options ... .Xc Specify the address and port of the target host to connect to. If the @@ -497,16 +497,40 @@ If the option is not specified, the port from the .Ic listen on directive will be used. -.Pp Use the .Ic transparent keyword to enable fully-transparent mode; the source address of the client will be retained in this case. .Pp -The optional host retry option will be used as a tolerance for failed +The following options may be specified for forward directives: +.Pp +.Bl -tag -width Ds +.It Ic retry Ar number +The optional host +.Ic retry +option will be used as a tolerance for failed host connections; the connection will be retried for .Ar number more times. +.It Ic inet +If the requested destination is an IPv6 address, +.Xr relayd 8 +will forward the connection to an IPv4 address which is determined by +the last 4 octets of the original IPv6 destination. +For example, if the original IPv6 destination address is +2001:db8:7395:ffff::a01:101, the session is relayed to the IPv4 +address 10.1.1.1 (a01:101). +.It Ic inet6 Ar address-prefix +If the requested destination is an IPv4 address, +.Xr relayd 8 +will forward the connection to an IPv6 address which is determined by +setting the last 4 octets of the specified IPv6 +.Ar address-prefix +to the 4 octets of the original IPv4 destination. +For example, if the original IPv4 destination address is 10.1.1.1 and +the specified address prefix is 2001:db8:7395:ffff::, the session is +relayed to the IPv6 address 2001:db8:7395:ffff::a01:101. +.El .It Xo .Ic forward to .Aq Ar table @@ -520,7 +544,7 @@ section above for information about table options. .It Xo .Ic forward to .Ic nat lookup -.Op Ic retry Ar number +.Ar options ... .Xc When redirecting connections with an .Ar rdr diff --git a/usr.sbin/relayd/relayd.h b/usr.sbin/relayd/relayd.h index c6ebf8eb955..30143f13b9f 100644 --- a/usr.sbin/relayd/relayd.h +++ b/usr.sbin/relayd/relayd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: relayd.h,v 1.108 2008/07/19 11:38:54 reyk Exp $ */ +/* $OpenBSD: relayd.h,v 1.109 2008/07/22 23:17:37 reyk Exp $ */ /* * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -590,6 +590,7 @@ struct relay_config { objid_t dsttable; struct sockaddr_storage ss; struct sockaddr_storage dstss; + struct sockaddr_storage dstaf; struct timeval timeout; enum forwardmode fwdmode; }; @@ -863,6 +864,8 @@ struct protonode *protonode_header(enum direction, struct protocol *, struct protonode *); int protonode_add(enum direction, struct protocol *, struct protonode *); +int map6to4(struct sockaddr_storage *); +int map4to6(struct sockaddr_storage *, struct sockaddr_storage *); /* carp.c */ int carp_demote_init(char *, int); |