From 22b5770b99b774abc6d6f4c89e51ba8c1b453eaa Mon Sep 17 00:00:00 2001 From: Andre Oppermann Date: Fri, 23 Apr 2004 14:28:38 +0000 Subject: [PATCH] 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 --- sbin/ipfw/ipfw.8 | 18 +++++++++++++++++- sbin/ipfw/ipfw2.c | 12 +++++++++++- sys/netinet/ip_fw.h | 1 + sys/netinet/ip_fw2.c | 38 +++++++++++++++++++++++++++++++------- 4 files changed, 60 insertions(+), 9 deletions(-) diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index 910c7af85349..d7d0f0adfac9 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -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 diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index 9063b530a58d..b0c28f6b02f4 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -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; diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index 8e3047de183f..7258b6c99931 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -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 */ diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c index 7097b20f7abe..e440f01840f4 100644 --- a/sys/netinet/ip_fw2.c +++ b/sys/netinet/ip_fw2.c @@ -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;