summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
Diffstat (limited to 'sbin')
-rw-r--r--sbin/ipfw/ipfw.84
-rw-r--r--sbin/ipfw/ipfw2.c108
2 files changed, 90 insertions, 22 deletions
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8
index 6fc12c8..9d00287 100644
--- a/sbin/ipfw/ipfw.8
+++ b/sbin/ipfw/ipfw.8
@@ -1,7 +1,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 29, 2011
+.Dd August 20, 2011
.Dt IPFW 8
.Os
.Sh NAME
@@ -726,7 +726,7 @@ The search terminates.
Change the next-hop on matching packets to
.Ar ipaddr ,
which can be an IP address or a host name.
-The next hop can also be supplied by the last table
+For IPv4, the next hop can also be supplied by the last table
looked up for the packet by using the
.Cm tablearg
keyword instead of an explicit address.
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index e389e99..615c4d1 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -1111,6 +1111,18 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
}
break;
+ case O_FORWARD_IP6:
+ {
+ char buf[4 + INET6_ADDRSTRLEN + 1];
+ ipfw_insn_sa6 *s = (ipfw_insn_sa6 *)cmd;
+
+ printf("fwd %s", inet_ntop(AF_INET6, &s->sa.sin6_addr,
+ buf, sizeof(buf)));
+ if (s->sa.sin6_port)
+ printf(",%d", s->sa.sin6_port);
+ }
+ break;
+
case O_LOG: /* O_LOG is printed last */
logptr = (ipfw_insn_log *)cmd;
break;
@@ -2809,40 +2821,96 @@ chkarg:
break;
case TOK_FORWARD: {
- ipfw_insn_sa *p = (ipfw_insn_sa *)action;
+ /*
+ * Locate the address-port separator (':' or ',').
+ * Could be one of the following:
+ * hostname:port
+ * IPv4 a.b.c.d,port
+ * IPv4 a.b.c.d:port
+ * IPv6 w:x:y::z,port
+ * The ':' can only be used with hostname and IPv4 address.
+ * XXX-BZ Should we also support [w:x:y::z]:port?
+ */
+ struct sockaddr_storage result;
+ struct addrinfo *res;
char *s, *end;
+ int family;
+ u_short port_number;
NEED1("missing forward address[:port]");
- action->opcode = O_FORWARD_IP;
- action->len = F_INSN_SIZE(ipfw_insn_sa);
-
- /*
- * In the kernel we assume AF_INET and use only
- * sin_port and sin_addr. Remember to set sin_len as
- * the routing code seems to use it too.
- */
- p->sa.sin_family = AF_INET;
- p->sa.sin_len = sizeof(struct sockaddr_in);
- p->sa.sin_port = 0;
/*
* locate the address-port separator (':' or ',')
*/
- s = strchr(*av, ':');
- if (s == NULL)
- s = strchr(*av, ',');
+ s = strchr(*av, ',');
+ if (s == NULL) {
+ /* Distinguish between IPv4:port and IPv6 cases. */
+ s = strchr(*av, ':');
+ if (s && strchr(s+1, ':'))
+ s = NULL; /* no port */
+ }
+
+ port_number = 0;
if (s != NULL) {
+ /* Terminate host portion and set s to start of port. */
*(s++) = '\0';
i = strtoport(s, &end, 0 /* base */, 0 /* proto */);
if (s == end)
errx(EX_DATAERR,
"illegal forwarding port ``%s''", s);
- p->sa.sin_port = (u_short)i;
+ port_number = (u_short)i;
+ }
+
+ if (_substrcmp(*av, "tablearg") == 0) {
+ family = PF_INET;
+ ((struct sockaddr_in*)&result)->sin_addr.s_addr =
+ INADDR_ANY;
+ } else {
+ /*
+ * Resolve the host name or address to a family and a
+ * network representation of the addres.
+ */
+ if (getaddrinfo(*av, NULL, NULL, &res))
+ errx(EX_DATAERR, NULL);
+ /* Just use the first host in the answer. */
+ family = res->ai_family;
+ memcpy(&result, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+ }
+
+ if (family == PF_INET) {
+ ipfw_insn_sa *p = (ipfw_insn_sa *)action;
+
+ action->opcode = O_FORWARD_IP;
+ action->len = F_INSN_SIZE(ipfw_insn_sa);
+
+ /*
+ * In the kernel we assume AF_INET and use only
+ * sin_port and sin_addr. Remember to set sin_len as
+ * the routing code seems to use it too.
+ */
+ p->sa.sin_len = sizeof(struct sockaddr_in);
+ p->sa.sin_family = AF_INET;
+ p->sa.sin_port = port_number;
+ p->sa.sin_addr.s_addr =
+ ((struct sockaddr_in *)&result)->sin_addr.s_addr;
+ } else if (family == PF_INET6) {
+ ipfw_insn_sa6 *p = (ipfw_insn_sa6 *)action;
+
+ action->opcode = O_FORWARD_IP6;
+ action->len = F_INSN_SIZE(ipfw_insn_sa6);
+
+ p->sa.sin6_len = sizeof(struct sockaddr_in6);
+ p->sa.sin6_family = AF_INET6;
+ p->sa.sin6_port = port_number;
+ p->sa.sin6_flowinfo = 0;
+ p->sa.sin6_scope_id = 0;
+ /* No table support for v6 yet. */
+ bcopy(&((struct sockaddr_in6*)&result)->sin6_addr,
+ &p->sa.sin6_addr, sizeof(p->sa.sin6_addr));
+ } else {
+ errx(EX_DATAERR, "Invalid address family in forward action");
}
- if (_substrcmp(*av, "tablearg") == 0)
- p->sa.sin_addr.s_addr = INADDR_ANY;
- else
- lookup_host(*av, &(p->sa.sin_addr));
av++;
break;
}
OpenPOWER on IntegriCloud