Add the option versrcreach to verify that a valid route to the

source address of a packet exists in the routing table.  The
default route is ignored because it would match everything and
render the check pointless.

This option is very useful for routers with a complete view of
the Internet (BGP) in the routing table to reject packets with
spoofed or unrouteable source addresses.

Example:

 ipfw add 1000 deny ip from any to any not versrcreach

also known in Cisco-speak as:

  ip verify unicast source reachable-via any

Reviewed by:	luigi
This commit is contained in:
Andre Oppermann 2004-04-23 14:28:38 +00:00
parent b62dccc7e5
commit 22b5770b99
4 changed files with 60 additions and 9 deletions

View File

@ -1230,7 +1230,23 @@ the Cisco IOS command:
.Pp
.Dl ip verify unicast reverse-path
.Pp
This option can be used to make anti-spoofing rules.
This option can be used to make anti-spoofing rules to reject all
packets with source addresses not from this interface.
.It Cm versrcreach
For incoming packets,
a routing table lookup is done on the packet's source address.
If a route to the source address exists, but not the default route,
the packet matches.
Otherwise the packet does not match.
All outgoing packets match.
.Pp
The name and functionality of the option is intentionally similar to
the Cisco IOS command:
.Pp
.Dl ip verify unicast source reachable-via any
.Pp
This option can be used to make anti-spoofing rules to reject all
packets whose source address is unreachable.
.El
.Sh SETS OF RULES
Each rule belongs to one of 32 different

View File

@ -226,6 +226,7 @@ enum tokens {
TOK_MAC,
TOK_MACTYPE,
TOK_VERREVPATH,
TOK_VERSRCREACH,
TOK_IPSEC,
TOK_COMMENT,
@ -338,6 +339,7 @@ struct _s_x rule_options[] = {
{ "mac", TOK_MAC },
{ "mac-type", TOK_MACTYPE },
{ "verrevpath", TOK_VERREVPATH },
{ "versrcreach", TOK_VERSRCREACH },
{ "ipsec", TOK_IPSEC },
{ "//", TOK_COMMENT },
@ -1268,6 +1270,10 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
printf(" verrevpath");
break;
case O_VERSRCREACH:
printf(" versrcreach");
break;
case O_IPSEC:
printf(" ipsec");
break;
@ -1874,7 +1880,7 @@ help(void)
" ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n"
" mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n"
" setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n"
" verrevpath\n"
" verrevpath | versrcreach\n"
);
exit(0);
}
@ -3400,6 +3406,10 @@ add(int ac, char *av[])
fill_cmd(cmd, O_VERREVPATH, 0, 0);
break;
case TOK_VERSRCREACH:
fill_cmd(cmd, O_VERSRCREACH, 0, 0);
break;
case TOK_IPSEC:
fill_cmd(cmd, O_IPSEC, 0, 0);
break;

View File

@ -95,6 +95,7 @@ enum ipfw_opcodes { /* arguments (4 byte each) */
O_TCPOPTS, /* arg1 = 2*u8 bitmap */
O_VERREVPATH, /* none */
O_VERSRCREACH, /* none */
O_PROBE_STATE, /* none */
O_KEEP_STATE, /* none */

View File

@ -439,21 +439,27 @@ iface_match(struct ifnet *ifp, ipfw_insn_if *cmd)
}
/*
* The verify_path function checks if a route to the src exists and
* if it is reachable via ifp (when provided).
*
* The 'verrevpath' option checks that the interface that an IP packet
* arrives on is the same interface that traffic destined for the
* packet's source address would be routed out of. This is a measure
* to block forged packets. This is also commonly known as "anti-spoofing"
* or Unicast Reverse Path Forwarding (Unicast RFP) in Cisco-ese. The
* name of the knob is purposely reminisent of the Cisco IOS command,
* packet's source address would be routed out of. The 'versrcreach'
* option just checks that the source address is reachable via any route
* (except default) in the routing table. These two are a measure to block
* forged packets. This is also commonly known as "anti-spoofing" or Unicast
* Reverse Path Forwarding (Unicast RFP) in Cisco-ese. The name of the knobs
* is purposely reminiscent of the Cisco IOS command,
*
* ip verify unicast reverse-path
* ip verify unicast source reachable-via any
*
* which implements the same functionality. But note that syntax is
* misleading. The check may be performed on all IP packets whether unicast,
* multicast, or broadcast.
*/
static int
verify_rev_path(struct in_addr src, struct ifnet *ifp)
verify_path(struct in_addr src, struct ifnet *ifp)
{
struct route ro;
struct sockaddr_in *dst;
@ -468,10 +474,21 @@ verify_rev_path(struct in_addr src, struct ifnet *ifp)
if (ro.ro_rt == NULL)
return 0;
if ((ifp == NULL) || (ro.ro_rt->rt_ifp->if_index != ifp->if_index)) {
/* if ifp is provided, check for equality with rtentry */
if (ifp != NULL && ro.ro_rt->rt_ifp != ifp) {
RTFREE(ro.ro_rt);
return 0;
}
/* if no ifp provided, check if rtentry is not default route */
if (ifp == NULL &&
satosin(rt_key(ro.ro_rt))->sin_addr.s_addr == INADDR_ANY) {
RTFREE(ro.ro_rt);
return 0;
}
/* found valid route */
RTFREE(ro.ro_rt);
return 1;
}
@ -1911,7 +1928,13 @@ ipfw_chk(struct ip_fw_args *args)
/* Outgoing packets automatically pass/match */
match = ((oif != NULL) ||
(m->m_pkthdr.rcvif == NULL) ||
verify_rev_path(src_ip, m->m_pkthdr.rcvif));
verify_path(src_ip, m->m_pkthdr.rcvif));
break;
case O_VERSRCREACH:
/* Outgoing packets automatically pass/match */
match = ((oif != NULL) ||
verify_path(src_ip, NULL));
break;
case O_IPSEC:
@ -2546,6 +2569,7 @@ check_ipfw_struct(struct ip_fw *rule, int size)
case O_TCPOPTS:
case O_ESTAB:
case O_VERREVPATH:
case O_VERSRCREACH:
case O_IPSEC:
if (cmdlen != F_INSN_SIZE(ipfw_insn))
goto bad_size;