From 010dabb04786dea184084bca10236b853a349ee2 Mon Sep 17 00:00:00 2001 From: "Crist J. Clark" Date: Sat, 15 Mar 2003 01:13:00 +0000 Subject: [PATCH] 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. --- sbin/ipfw/ipfw.8 | 28 +++++++++++++++++++++++++ sbin/ipfw/ipfw2.c | 10 +++++++++ sys/netinet/ip_fw.h | 2 ++ sys/netinet/ip_fw2.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+) diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index 4dfd91293118..2968109457bc 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -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: diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index 6d2857fce2f1..edec049e988e 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -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); } diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index b3fffb8df9eb..f2b932e39fd5 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -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 */ diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c index eabcd67028ac..fbf3293b7ea3 100644 --- a/sys/netinet/ip_fw2.c +++ b/sys/netinet/ip_fw2.c @@ -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;