Add a 'verrevpath' option that verifies the interface that a packet

comes in on is the same interface that we would route out of to get to
the packet's source address. Essentially automates an anti-spoofing
check using the information in the routing table.

Experimental. The usage and rule format for the feature may still be
subject to change.
This commit is contained in:
Crist J. Clark 2003-03-15 01:13:00 +00:00
parent 1fe8a56688
commit 010dabb047
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=112250
4 changed files with 90 additions and 0 deletions

View File

@ -1115,6 +1115,22 @@ Match all TCP or UDP packets sent by or received for a
A
.Ar user
may be matched by name or identification number.
.It Cm verrevpath
For incoming packets,
a routing table lookup is done on the packet's source address.
If the interface on which the packet entered the system matches the
outgoing interface for the route,
the packet matches.
If the interfaces do not match up,
the packet does not match.
All outgoing packets or packets with no incoming interface match.
.Pp
The name and functionality of the option is intentionally similar to
the Cisco IOS command:
.Pp
.Dl ip verify unicast reverse-path
.Pp
This option can be used to make anti-spoofing rules.
.El
.Sh SETS OF RULES
Each rule belongs to one of 32 different
@ -1818,6 +1834,18 @@ The
.Nm ipfw1
syntax would require a separate rule for each IP in the above
example.
.Pp
The
.Cm verrevpath
option could be used to do automated anti-spoofing by adding the
following to the top of a ruleset:
.Pp
.Dl "ipfw add deny ip from any to any not verrevpath in"
.Pp
This rule drops all incoming packets that appear to be coming to the
sytem on the wrong interface. For example, a packet with a source
address belonging to a host on a protected internal network would be
dropped if it tried to enter the system from an external interface.
.Ss DYNAMIC RULES
In order to protect a site from flood attacks involving fake
TCP packets, it is safer to use dynamic rules:

View File

@ -224,6 +224,7 @@ enum tokens {
TOK_ICMPTYPES,
TOK_MAC,
TOK_MACTYPE,
TOK_VERREVPATH,
TOK_PLR,
TOK_NOERROR,
@ -333,6 +334,7 @@ struct _s_x rule_options[] = {
{ "MAC", TOK_MAC },
{ "mac", TOK_MAC },
{ "mac-type", TOK_MACTYPE },
{ "verrevpath", TOK_VERREVPATH },
{ "not", TOK_NOT }, /* pseudo option */
{ "!", /* escape ? */ TOK_NOT }, /* pseudo option */
@ -1162,6 +1164,10 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
}
break;
case O_VERREVPATH:
printf(" verrevpath");
break;
case O_KEEP_STATE:
printf(" keep-state");
break;
@ -3160,6 +3166,10 @@ add(int ac, char *av[])
ac--; av++;
break;
case TOK_VERREVPATH:
fill_cmd(cmd, O_VERREVPATH, 0, 0);
break;
default:
errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s);
}

View File

@ -89,6 +89,8 @@ enum ipfw_opcodes { /* arguments (4 byte each) */
O_ICMPTYPE, /* u32 = icmp bitmap */
O_TCPOPTS, /* arg1 = 2*u8 bitmap */
O_VERREVPATH, /* none */
O_PROBE_STATE, /* none */
O_KEEP_STATE, /* none */
O_LIMIT, /* ipfw_insn_limit */

View File

@ -402,6 +402,48 @@ iface_match(struct ifnet *ifp, ipfw_insn_if *cmd)
return(0); /* no match, fail ... */
}
/*
* 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,
*
* ip verify unicast reverse-path
*
* 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)
{
static struct route ro;
struct sockaddr_in *dst;
dst = (struct sockaddr_in *)&(ro.ro_dst);
/* Check if we've cached the route from the previous call. */
if (src.s_addr != dst->sin_addr.s_addr) {
ro.ro_rt = NULL;
bzero(dst, sizeof(*dst));
dst->sin_family = AF_INET;
dst->sin_len = sizeof(*dst);
dst->sin_addr = src;
rtalloc_ign(&ro, RTF_CLONING|RTF_PRCLONING);
}
if ((ro.ro_rt == NULL) || (ifp == NULL) ||
(ro.ro_rt->rt_ifp->if_index != ifp->if_index))
return 0;
return 1;
}
static u_int64_t norule_counter; /* counter for ipfw_log(NULL...) */
#define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0
@ -1755,6 +1797,13 @@ ipfw_chk(struct ip_fw_args *args)
match = (random()<((ipfw_insn_u32 *)cmd)->d[0]);
break;
case O_VERREVPATH:
/* Outgoing packets automatically pass/match */
match = ((oif != NULL) ||
(m->m_pkthdr.rcvif == NULL) ||
verify_rev_path(src_ip, m->m_pkthdr.rcvif));
break;
/*
* The second set of opcodes represents 'actions',
* i.e. the terminal part of a rule once the packet
@ -2322,6 +2371,7 @@ check_ipfw_struct(struct ip_fw *rule, int size)
case O_TCPFLAGS:
case O_TCPOPTS:
case O_ESTAB:
case O_VERREVPATH:
if (cmdlen != F_INSN_SIZE(ipfw_insn))
goto bad_size;
break;