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
|
socket bound to port
|
||||||
.Ar port .
|
.Ar port .
|
||||||
The search terminates.
|
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
|
Change the next-hop on matching packets to
|
||||||
.Ar ipaddr ,
|
.Ar ipaddr ,
|
||||||
which can be an IP address or a host name.
|
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.
|
The search terminates if this rule matches.
|
||||||
.Pp
|
.Pp
|
||||||
If
|
If
|
||||||
@ -1584,11 +1588,14 @@ This can significantly reduce number of rules in some configurations.
|
|||||||
The
|
The
|
||||||
.Cm tablearg
|
.Cm tablearg
|
||||||
argument can be used with the following actions:
|
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:
|
action parameters:
|
||||||
.Cm tag, untag,
|
.Cm tag, untag,
|
||||||
rule options:
|
rule options:
|
||||||
.Cm limit, tagged.
|
.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
|
See the
|
||||||
.Sx EXAMPLES
|
.Sx EXAMPLES
|
||||||
Section for example usage of tables and the tablearg keyword.
|
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 "ipfw table 1 add 192.168.0.2 1"
|
||||||
.Dl "..."
|
.Dl "..."
|
||||||
.Dl "ipfw pipe tablearg ip from table(1) to any"
|
.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
|
.Ss SETS OF RULES
|
||||||
To add a set of rules atomically, e.g.\& set 18:
|
To add a set of rules atomically, e.g.\& set 18:
|
||||||
.Pp
|
.Pp
|
||||||
|
@ -1545,7 +1545,11 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
|
|||||||
{
|
{
|
||||||
ipfw_insn_sa *s = (ipfw_insn_sa *)cmd;
|
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)
|
if (s->sa.sin_port)
|
||||||
printf(",%d", s->sa.sin_port);
|
printf(",%d", s->sa.sin_port);
|
||||||
}
|
}
|
||||||
@ -4030,11 +4034,14 @@ add(int ac, char *av[])
|
|||||||
"illegal forwarding port ``%s''", s);
|
"illegal forwarding port ``%s''", s);
|
||||||
p->sa.sin_port = (u_short)i;
|
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++;
|
ac--; av++;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case TOK_COMMENT:
|
case TOK_COMMENT:
|
||||||
/* pretend it is a 'count' rule followed by the comment */
|
/* pretend it is a 'count' rule followed by the comment */
|
||||||
action->opcode = O_COUNT;
|
action->opcode = O_COUNT;
|
||||||
@ -4943,9 +4950,21 @@ table_handler(int ac, char *av[])
|
|||||||
if (lookup_host(*av, (struct in_addr *)&ent.addr) != 0)
|
if (lookup_host(*av, (struct in_addr *)&ent.addr) != 0)
|
||||||
errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
|
errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
|
||||||
ac--; av++;
|
ac--; av++;
|
||||||
if (do_add && ac)
|
if (do_add && ac) {
|
||||||
ent.value = strtoul(*av, NULL, 0);
|
unsigned int tval;
|
||||||
else
|
/* 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;
|
ent.value = 0;
|
||||||
if (do_cmd(do_add ? IP_FW_TABLE_ADD : IP_FW_TABLE_DEL,
|
if (do_cmd(do_add ? IP_FW_TABLE_ADD : IP_FW_TABLE_DEL,
|
||||||
&ent, sizeof(ent)) < 0) {
|
&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)
|
if (do_cmd(IP_FW_TABLE_LIST, tbl, (uintptr_t)&l) < 0)
|
||||||
err(EX_OSERR, "getsockopt(IP_FW_TABLE_LIST)");
|
err(EX_OSERR, "getsockopt(IP_FW_TABLE_LIST)");
|
||||||
for (a = 0; a < tbl->cnt; a++) {
|
for (a = 0; a < tbl->cnt; a++) {
|
||||||
printf("%s/%u %u\n",
|
/* Heuristic to print it the right way */
|
||||||
inet_ntoa(*(struct in_addr *)&tbl->ent[a].addr),
|
/* valuse < 64k are printed as numbers */
|
||||||
tbl->ent[a].masklen, tbl->ent[a].value);
|
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
|
} else
|
||||||
errx(EX_USAGE, "invalid table command %s", *av);
|
errx(EX_USAGE, "invalid table command %s", *av);
|
||||||
|
@ -521,6 +521,8 @@ struct ip_fw_args {
|
|||||||
struct inpcb *inp;
|
struct inpcb *inp;
|
||||||
|
|
||||||
struct _ip6dn_args dummypar; /* dummynet->ip6_output */
|
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
|
static void
|
||||||
ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
|
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;
|
struct ether_header *eh = args->eh;
|
||||||
char *action;
|
char *action;
|
||||||
@ -831,9 +831,15 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
|
|||||||
case O_FORWARD_IP: {
|
case O_FORWARD_IP: {
|
||||||
ipfw_insn_sa *sa = (ipfw_insn_sa *)cmd;
|
ipfw_insn_sa *sa = (ipfw_insn_sa *)cmd;
|
||||||
int len;
|
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",
|
len = snprintf(SNPARGS(action2, 0), "Forward to %s",
|
||||||
inet_ntoa(sa->sa.sin_addr));
|
inet_ntoa(dummyaddr));
|
||||||
|
|
||||||
if (sa->sa.sin_port)
|
if (sa->sa.sin_port)
|
||||||
snprintf(SNPARGS(action2, len), ":%d",
|
snprintf(SNPARGS(action2, len), ":%d",
|
||||||
sa->sa.sin_port);
|
sa->sa.sin_port);
|
||||||
@ -2785,7 +2791,7 @@ do { \
|
|||||||
|
|
||||||
case O_LOG:
|
case O_LOG:
|
||||||
if (fw_verbose)
|
if (fw_verbose)
|
||||||
ipfw_log(f, hlen, args, m, oif, offset);
|
ipfw_log(f, hlen, args, m, oif, offset, tablearg);
|
||||||
match = 1;
|
match = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -3141,13 +3147,23 @@ do { \
|
|||||||
retval = IP_FW_DENY;
|
retval = IP_FW_DENY;
|
||||||
goto done;
|
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 */
|
if (args->eh) /* not valid on layer2 pkts */
|
||||||
break;
|
break;
|
||||||
if (!q || dyn_dir == MATCH_FORWARD)
|
if (!q || dyn_dir == MATCH_FORWARD) {
|
||||||
args->next_hop =
|
if (sa->sin_addr.s_addr == INADDR_ANY) {
|
||||||
&((ipfw_insn_sa *)cmd)->sa;
|
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;
|
retval = IP_FW_PASS;
|
||||||
|
}
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
case O_NETGRAPH:
|
case O_NETGRAPH:
|
||||||
|
Loading…
Reference in New Issue
Block a user