Allow ipfw to forward to a destination that is specified by a table.
for example: fwd tablearg ip from any to table(1) where table 1 has entries of the form: 1.1.1.0/24 10.2.3.4 208.23.2.0/24 router2 This allows trivial implementation of a secondary routing table implemented in the firewall layer. I expect more work (under discussion with Glebius) to follow this to clean up some of the messy parts of ipfw related to tables. Reviewed by: Glebius MFC after: 1 month
This commit is contained in:
parent
5657c870dc
commit
c487be961a
@ -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
|
||||
|
@ -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 @@ add(int ac, char *av[])
|
||||
"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);
|
||||
|
@ -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 */
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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 @@ do { \
|
||||
|
||||
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 @@ do { \
|
||||
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:
|
||||
|
Loading…
Reference in New Issue
Block a user