summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sbin/ipfw/ipfw.818
-rw-r--r--sbin/ipfw/ipfw2.c53
-rw-r--r--sys/netinet/ip_fw.h2
-rw-r--r--sys/netinet/ip_fw2.c30
4 files changed, 85 insertions, 18 deletions
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8
index 3c7aac4..6321589 100644
--- a/sbin/ipfw/ipfw.8
+++ b/sbin/ipfw/ipfw.8
@@ -684,10 +684,14 @@ Divert packets that match this rule to the
socket bound to port
.Ar port .
The search terminates.
-.It Cm fwd | forward Ar ipaddr Ns Op , Ns Ar port
+.It Cm fwd | forward Ar ipaddr | tablearg Ns Op , Ns Ar port
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
+looked up for the packet by using the
+.Em tablearg
+keyword instead of an explicit address.
The search terminates if this rule matches.
.Pp
If
@@ -1584,11 +1588,14 @@ This can significantly reduce number of rules in some configurations.
The
.Cm tablearg
argument can be used with the following actions:
-.Cm pipe , queue, divert, tee, netgraph, ngtee,
+.Cm pipe , queue, divert, tee, netgraph, ngtee, fwd
action parameters:
.Cm tag, untag,
rule options:
.Cm limit, tagged.
+.Pp
+When used with 'fwd' it is possible to supply table entries with values
+that are in the form of IP addresses or hostnames.
See the
.Sx EXAMPLES
Section for example usage of tables and the tablearg keyword.
@@ -2380,6 +2387,13 @@ Then we classify traffic using a single rule:
.Dl "ipfw table 1 add 192.168.0.2 1"
.Dl "..."
.Dl "ipfw pipe tablearg ip from table(1) to any"
+.Pp
+Using the fwd action, the table entries may include hostnames and IP addresses.
+.Pp
+.Dl "ipfw table 1 add 192.168.2.0/24 10.23.2.1"
+.Dl "ipfw table 1 add 192.168.0.0/27 router1.dmz"
+.Dl "..."
+.Dl "ipfw add 100 fwd tablearg ip from any to table(1)"
.Ss SETS OF RULES
To add a set of rules atomically, e.g.\& set 18:
.Pp
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index f5d8ed6..a486fbe 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -1545,7 +1545,11 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
{
ipfw_insn_sa *s = (ipfw_insn_sa *)cmd;
- printf("fwd %s", inet_ntoa(s->sa.sin_addr));
+ if (s->sa.sin_addr.s_addr == INADDR_ANY) {
+ printf("fwd tablearg");
+ } else {
+ printf("fwd %s", inet_ntoa(s->sa.sin_addr));
+ }
if (s->sa.sin_port)
printf(",%d", s->sa.sin_port);
}
@@ -4030,11 +4034,14 @@ chkarg:
"illegal forwarding port ``%s''", s);
p->sa.sin_port = (u_short)i;
}
- lookup_host(*av, &(p->sa.sin_addr));
+ if (_substrcmp(*av, "tablearg") == 0) {
+ p->sa.sin_addr.s_addr = INADDR_ANY; /* htonl not needed */
+ } else {
+ lookup_host(*av, &(p->sa.sin_addr));
}
ac--; av++;
break;
-
+ }
case TOK_COMMENT:
/* pretend it is a 'count' rule followed by the comment */
action->opcode = O_COUNT;
@@ -4943,9 +4950,21 @@ table_handler(int ac, char *av[])
if (lookup_host(*av, (struct in_addr *)&ent.addr) != 0)
errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
ac--; av++;
- if (do_add && ac)
- ent.value = strtoul(*av, NULL, 0);
- else
+ if (do_add && ac) {
+ unsigned int tval;
+ /* isdigit is a bit of a hack here.. */
+ if (strchr(*av, (int)'.') == NULL && isdigit(**av)) {
+ ent.value = strtoul(*av, NULL, 0);
+ } else {
+ if (lookup_host(*av, (struct in_addr *)&tval) == 0) {
+ /* The value must be stored in host order *
+ * so that the values < 65k can be distinguished */
+ ent.value = ntohl(tval);
+ } else {
+ errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
+ }
+ }
+ } else
ent.value = 0;
if (do_cmd(do_add ? IP_FW_TABLE_ADD : IP_FW_TABLE_DEL,
&ent, sizeof(ent)) < 0) {
@@ -4978,9 +4997,25 @@ table_handler(int ac, char *av[])
if (do_cmd(IP_FW_TABLE_LIST, tbl, (uintptr_t)&l) < 0)
err(EX_OSERR, "getsockopt(IP_FW_TABLE_LIST)");
for (a = 0; a < tbl->cnt; a++) {
- printf("%s/%u %u\n",
- inet_ntoa(*(struct in_addr *)&tbl->ent[a].addr),
- tbl->ent[a].masklen, tbl->ent[a].value);
+ /* Heuristic to print it the right way */
+ /* valuse < 64k are printed as numbers */
+ unsigned int tval;
+ tval = tbl->ent[a].value;
+ if (tval > 0xffff) {
+ char tbuf[128];
+ strncpy(tbuf,
+ inet_ntoa(*(struct in_addr *)
+ &tbl->ent[a].addr), 127);
+ /* inet_ntoa expects host order */
+ tval = htonl(tval);
+ printf("%s/%u %s\n",
+ tbuf, tbl->ent[a].masklen,
+ inet_ntoa(*(struct in_addr *)&tval));
+ } else {
+ printf("%s/%u %u\n",
+ inet_ntoa(*(struct in_addr *)&tbl->ent[a].addr),
+ tbl->ent[a].masklen, tbl->ent[a].value);
+ }
}
} else
errx(EX_USAGE, "invalid table command %s", *av);
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
index 14ca1d5..086ce8e 100644
--- a/sys/netinet/ip_fw.h
+++ b/sys/netinet/ip_fw.h
@@ -521,6 +521,8 @@ struct ip_fw_args {
struct inpcb *inp;
struct _ip6dn_args dummypar; /* dummynet->ip6_output */
+ struct sockaddr_in hopstore; /* store here if cannot use a pointer */
+
};
/*
diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c
index e9b24df..47fc7f6 100644
--- a/sys/netinet/ip_fw2.c
+++ b/sys/netinet/ip_fw2.c
@@ -738,7 +738,7 @@ static u_int64_t norule_counter; /* counter for ipfw_log(NULL...) */
*/
static void
ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
- struct mbuf *m, struct ifnet *oif, u_short offset)
+ struct mbuf *m, struct ifnet *oif, u_short offset, uint32_t tablearg)
{
struct ether_header *eh = args->eh;
char *action;
@@ -831,9 +831,15 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
case O_FORWARD_IP: {
ipfw_insn_sa *sa = (ipfw_insn_sa *)cmd;
int len;
+ struct in_addr dummyaddr;
+ if (sa->sa.sin_addr.s_addr == INADDR_ANY)
+ dummyaddr.s_addr = htonl(tablearg);
+ else
+ dummyaddr.s_addr = sa->sa.sin_addr.s_addr;
len = snprintf(SNPARGS(action2, 0), "Forward to %s",
- inet_ntoa(sa->sa.sin_addr));
+ inet_ntoa(dummyaddr));
+
if (sa->sa.sin_port)
snprintf(SNPARGS(action2, len), ":%d",
sa->sa.sin_port);
@@ -2785,7 +2791,7 @@ check_body:
case O_LOG:
if (fw_verbose)
- ipfw_log(f, hlen, args, m, oif, offset);
+ ipfw_log(f, hlen, args, m, oif, offset, tablearg);
match = 1;
break;
@@ -3141,13 +3147,23 @@ check_body:
retval = IP_FW_DENY;
goto done;
- case O_FORWARD_IP:
+ case O_FORWARD_IP: {
+ struct sockaddr_in *sa;
+ sa = &(((ipfw_insn_sa *)cmd)->sa);
if (args->eh) /* not valid on layer2 pkts */
break;
- if (!q || dyn_dir == MATCH_FORWARD)
- args->next_hop =
- &((ipfw_insn_sa *)cmd)->sa;
+ if (!q || dyn_dir == MATCH_FORWARD) {
+ if (sa->sin_addr.s_addr == INADDR_ANY) {
+ bcopy(sa, &args->hopstore,
+ sizeof(*sa));
+ args->hopstore.sin_addr.s_addr = htonl(tablearg);
+ args->next_hop = &args->hopstore;
+ } else {
+ args->next_hop = sa;
+ }
+ }
retval = IP_FW_PASS;
+ }
goto done;
case O_NETGRAPH:
OpenPOWER on IntegriCloud