diff options
author | luigi <luigi@FreeBSD.org> | 1998-12-14 18:09:13 +0000 |
---|---|---|
committer | luigi <luigi@FreeBSD.org> | 1998-12-14 18:09:13 +0000 |
commit | 4b628fa86de9e1f3e478283a0118b2209ccc5885 (patch) | |
tree | 1e45fc838f0be7bd575a8f9d8373624ff7318a2a /sys/netinet/ip_fw.c | |
parent | 78f32fa7e071a1e01b906f438ffe7454438b1730 (diff) | |
download | FreeBSD-src-4b628fa86de9e1f3e478283a0118b2209ccc5885.zip FreeBSD-src-4b628fa86de9e1f3e478283a0118b2209ccc5885.tar.gz |
Last bits (i think) of dummynet for -current.
Diffstat (limited to 'sys/netinet/ip_fw.c')
-rw-r--r-- | sys/netinet/ip_fw.c | 270 |
1 files changed, 198 insertions, 72 deletions
diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c index 8e818dc..d9069dc 100644 --- a/sys/netinet/ip_fw.c +++ b/sys/netinet/ip_fw.c @@ -12,15 +12,16 @@ * * This software is provided ``AS IS'' without any warranties of any kind. * - * $Id: ip_fw.c,v 1.98 1998/11/15 15:33:52 bde Exp $ + * $Id: ip_fw.c,v 1.96 1998/08/23 03:07:14 wollman Exp $ */ /* * Implement IP packet firewall */ -#if !defined(KLD_MODULE) && !defined(IPFIREWALL_MODULE) +#ifndef IPFIREWALL_MODULE #include "opt_ipfw.h" +#include "opt_ipdn.h" #include "opt_ipdivert.h" #include "opt_inet.h" #ifndef INET @@ -43,18 +44,25 @@ #include <netinet/ip_var.h> #include <netinet/ip_icmp.h> #include <netinet/ip_fw.h> +#ifdef DUMMYNET +#include <net/route.h> +#include <netinet/ip_dummynet.h> +#endif #include <netinet/tcp.h> #include <netinet/tcp_timer.h> #include <netinet/tcp_var.h> #include <netinet/tcpip.h> #include <netinet/udp.h> +#include <netinet/if_ether.h> /* XXX ethertype_ip */ + static int fw_debug = 1; #ifdef IPFIREWALL_VERBOSE static int fw_verbose = 1; #else static int fw_verbose = 0; #endif +static int fw_one_pass = 0; /* XXX */ #ifdef IPFIREWALL_VERBOSE_LIMIT static int fw_verbose_limit = IPFIREWALL_VERBOSE_LIMIT; #else @@ -63,13 +71,14 @@ static int fw_verbose_limit = 0; #define IPFW_DEFAULT_RULE ((u_int)(u_short)~0) -static LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain; +LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain; -static MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); +MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); #ifdef SYSCTL_NODE SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall"); SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, debug, CTLFLAG_RW, &fw_debug, 0, ""); +SYSCTL_INT(_net_inet_ip_fw, OID_AUTO,one_pass,CTLFLAG_RW, &fw_one_pass, 0, ""); SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw_verbose, 0, ""); SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw_verbose_limit, 0, ""); #endif @@ -100,8 +109,16 @@ static int icmptype_match __P((struct icmp * icmp, struct ip_fw * f)); static void ipfw_report __P((struct ip_fw *f, struct ip *ip, struct ifnet *rif, struct ifnet *oif)); +static void flush_rule_ptrs(void); + +#ifdef IPFIREWALL_MODULE +static ip_fw_chk_t *old_chk_ptr; +static ip_fw_ctl_t *old_ctl_ptr; +#endif + static int ip_fw_chk __P((struct ip **pip, int hlen, struct ifnet *oif, u_int16_t *cookie, struct mbuf **m, + struct ip_fw_chain **flow_id, struct sockaddr_in **next_hop)); static int ip_fw_ctl __P((struct sockopt *sopt)); @@ -279,6 +296,7 @@ static void ipfw_report(struct ip_fw *f, struct ip *ip, struct ifnet *rif, struct ifnet *oif) { + if (ip) { static u_int64_t counter; struct tcphdr *const tcp = (struct tcphdr *) ((u_int32_t *) ip+ ip->ip_hl); struct udphdr *const udp = (struct udphdr *) ((u_int32_t *) ip+ ip->ip_hl); @@ -319,6 +337,11 @@ ipfw_report(struct ip_fw *f, struct ip *ip, case IP_FW_F_SKIPTO: printf("SkipTo %d", f->fw_skipto_rule); break; +#ifdef DUMMYNET + case IP_FW_F_PIPE: + printf("Pipe %d", f->fw_skipto_rule); + break; +#endif #ifdef IPFIREWALL_FORWARD case IP_FW_F_FWD: printf("Forward to "); @@ -383,15 +406,45 @@ ipfw_report(struct ip_fw *f, struct ip *ip, printf("ipfw: limit reached on rule #%d\n", f ? f->fw_number : -1); } +} + +/* + * given an ip_fw_chain *, lookup_next_rule will return a pointer + * of the same type to the next one. This can be either the jump + * target (for skipto instructions) or the next one in the chain (in + * all other cases including a missing jump target). + * Backward jumps are not allowed, so start looking from the next + * rule... + */ +static struct ip_fw_chain * lookup_next_rule(struct ip_fw_chain *me); + +static struct ip_fw_chain * +lookup_next_rule(struct ip_fw_chain *me) +{ + struct ip_fw_chain *chain ; + int rule = me->rule->fw_skipto_rule ; /* guess... */ + + if ( (me->rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_SKIPTO ) + for (chain = me->chain.le_next; chain ; chain = chain->chain.le_next ) + if (chain->rule->fw_number >= rule) + return chain ; + return me->chain.le_next ; /* failure or not a skipto */ +} /* * Parameters: * - * ip Pointer to packet header (struct ip *) + * pip Pointer to packet header (struct ip **) + * XXX future extension: pip = NULL means a complete ethernet packet + * including ethernet header in the mbuf. Other fields + * are ignored/invalid. + * * hlen Packet header length * oif Outgoing interface, or NULL if packet is incoming * *cookie Skip up to the first rule past this rule number; * *m The packet; we set to NULL when/if we nuke it. + * *flow_id pointer to the last matching rule (in/out) + * *next_hop socket we are forwarding to (in/out). * * Return value: * @@ -404,17 +457,58 @@ ipfw_report(struct ip_fw *f, struct ip *ip, static int ip_fw_chk(struct ip **pip, int hlen, struct ifnet *oif, u_int16_t *cookie, struct mbuf **m, + struct ip_fw_chain **flow_id, struct sockaddr_in **next_hop) { struct ip_fw_chain *chain; struct ip_fw *rule = NULL; - struct ip *ip = *pip; + struct ip *ip = NULL ; struct ifnet *const rif = (*m)->m_pkthdr.rcvif; - u_short offset = (ip->ip_off & IP_OFFMASK); + u_short offset ; u_short src_port, dst_port; u_int16_t skipto = *cookie; - *cookie = 0; + if (pip) { /* normal ip packet */ + ip = *pip; + offset = (ip->ip_off & IP_OFFMASK); + } else { /* bridged or non-ip packet */ + struct ether_header *eh = mtod(*m, struct ether_header *); + switch (ntohs(eh->ether_type)) { + case ETHERTYPE_IP : + if ((*m)->m_len<sizeof(struct ether_header) + sizeof(struct ip)) + goto non_ip ; + ip = (struct ip *)(eh + 1 ); + if (ip->ip_v != IPVERSION) + goto non_ip ; + hlen = ip->ip_hl << 2; + if (hlen < sizeof(struct ip)) /* minimum header length */ + goto non_ip ; + if ((*m)->m_len < 14 + hlen + 14) { + printf("-- m_len %d, need more...\n", (*m)->m_len); + goto non_ip ; + } + offset = (ip->ip_off & IP_OFFMASK); + break ; + default : +non_ip: ip = NULL ; + break ; + } + } + + if (*flow_id) { + if (fw_one_pass) + return 0 ; /* accept if passed first test */ + /* + * pkt has already been tagged. Look for the next rule + * to restart processing + */ + chain = LIST_NEXT( *flow_id, chain); + + if ( (chain = (*flow_id)->rule->next_rule_ptr) == NULL ) + chain = (*flow_id)->rule->next_rule_ptr = + lookup_next_rule(*flow_id) ; + if (! chain) goto dropit; + } else { /* * Go down the chain, looking for enlightment * If we've been asked to start at a given rule immediatly, do so. @@ -428,8 +522,12 @@ ip_fw_chk(struct ip **pip, int hlen, } if (! chain) goto dropit; } + } + *cookie = 0; for (; chain; chain = LIST_NEXT(chain, chain)) { - register struct ip_fw *const f = chain->rule; + register struct ip_fw * f ; +again: + f = chain->rule; if (oif) { /* Check direction outbound */ @@ -440,6 +538,40 @@ ip_fw_chk(struct ip **pip, int hlen, if (!(f->fw_flg & IP_FW_F_IN)) continue; } + if (ip == NULL ) { + /* + * do relevant checks for non-ip packets: + * after this, only goto got_match or continue + */ + struct ether_header *eh = mtod(*m, struct ether_header *); + + /* + * make default rule always match or we have a panic + */ + if (f->fw_number == IPFW_DEFAULT_RULE) + goto got_match ; + /* + * temporary hack: + * udp from 0.0.0.0 means this rule applies. + * 1 src port is match ether type + * 2 src ports (interval) is match ether type + * 3 src ports is match ether address + */ + if ( f->fw_src.s_addr != 0 || f->fw_prot != IPPROTO_UDP) + continue; + switch (IP_FW_GETNSRCP(f)) { + case 1: /* match one type */ + if ( /* ( (f->fw_flg & IP_FW_F_INVSRC) != 0) ^ */ + ( f->fw_uar.fw_pts[0] == ntohs(eh->ether_type) ) ) { + printf("match!\n"); + goto got_match ; + } + break ; + default: + break ; + } + continue ; + } /* Fragments */ if ((f->fw_flg & IP_FW_F_FRAG) && !(ip->ip_off & IP_OFFMASK)) @@ -489,12 +621,12 @@ ip_fw_chk(struct ip **pip, int hlen, continue; #define PULLUP_TO(len) do { \ - if ((*m)->m_len < (len) \ - && (*m = m_pullup(*m, (len))) == 0) { \ + if ((*m)->m_len < (len) ) { \ + if ( (*m = m_pullup(*m, (len))) == 0) \ goto bogusfrag; \ - } \ *pip = ip = mtod(*m, struct ip *); \ offset = (ip->ip_off & IP_OFFMASK); \ + } \ } while (0) /* Protocol specific checks */ @@ -578,9 +710,19 @@ bogusfrag: } got_match: + *flow_id = chain ; /* XXX set flow id */ /* Update statistics */ f->fw_pcnt += 1; + /* + * note -- bridged-ip packets still have some fields + * in network order, including ip_len + */ + if (ip) { + if (pip) f->fw_bcnt += ip->ip_len; + else + f->fw_bcnt += ntohs(ip->ip_len); + } f->timestamp = time_second; /* Log to console if desired */ @@ -593,9 +735,11 @@ got_match: return(0); case IP_FW_F_COUNT: continue; +#ifdef IPDIVERT case IP_FW_F_DIVERT: *cookie = f->fw_number; return(f->fw_divert_port); +#endif case IP_FW_F_TEE: /* * XXX someday tee packet here, but beware that you @@ -606,17 +750,17 @@ got_match: * to write custom routine. */ continue; - case IP_FW_F_SKIPTO: -#ifdef DIAGNOSTIC - while (LIST_NEXT(chain, chain) - && LIST_NEXT(chain, chain)->rule->fw_number - < f->fw_skipto_rule) -#else - while (LIST_NEXT(chain, chain)->rule->fw_number - < f->fw_skipto_rule) + case IP_FW_F_SKIPTO: /* XXX check */ + if ( f->next_rule_ptr ) + chain = f->next_rule_ptr ; + else + chain = lookup_next_rule(chain) ; + if (! chain) goto dropit; + goto again ; +#ifdef DUMMYNET + case IP_FW_F_PIPE: + return(f->fw_pipe_nr | 0x10000 ); #endif - chain = LIST_NEXT(chain, chain); - continue; #ifdef IPFIREWALL_FORWARD case IP_FW_F_FWD: /* Change the next-hop address for this packet. @@ -656,6 +800,7 @@ got_match: * - The packet is not a multicast or broadcast packet */ if ((rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT + && ip && (ip->ip_p != IPPROTO_ICMP || is_icmp_query(ip)) && !((*m)->m_flags & (M_BCAST|M_MCAST)) && !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { @@ -698,7 +843,7 @@ dropit: /* * Finally, drop the packet. */ - *cookie = 0; + /* *cookie = 0; */ /* XXX is this necessary ? */ if (*m) { m_freem(*m); *m = NULL; @@ -706,6 +851,22 @@ dropit: return(0); } +/* + * when a rule is added/deleted, zero the direct pointers within + * all firewall rules. These will be reconstructed on the fly + * as packets are matched. + * Must be called at splnet(). + */ +static void +flush_rule_ptrs() +{ + struct ip_fw_chain *fcp ; + + for (fcp = ip_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next) { + fcp->rule->next_rule_ptr = NULL ; + } +} + static int add_entry(struct ip_fw_head *chainptr, struct ip_fw *frwl) { @@ -727,6 +888,8 @@ add_entry(struct ip_fw_head *chainptr, struct ip_fw *frwl) ftmp->fw_in_if.fu_via_if.name[FW_IFNLEN - 1] = '\0'; ftmp->fw_pcnt = 0L; ftmp->fw_bcnt = 0L; + ftmp->next_rule_ptr = NULL ; + ftmp->pipe_ptr = NULL ; fwc->rule = ftmp; s = splnet(); @@ -763,6 +926,7 @@ add_entry(struct ip_fw_head *chainptr, struct ip_fw *frwl) fcpl = fcp; } } + flush_rule_ptrs(); splx(s); return (0); @@ -786,6 +950,10 @@ del_entry(struct ip_fw_head *chainptr, u_short number) next = LIST_NEXT(fcp, chain); LIST_REMOVE(fcp, chain); +#ifdef DUMMYNET + dn_rule_delete(fcp) ; +#endif + flush_rule_ptrs(); free(fcp->rule, M_IPFW); free(fcp, M_IPFW); fcp = next; @@ -941,6 +1109,7 @@ check_ipfw_struct(struct ip_fw *frwl) } break; case IP_FW_F_DIVERT: /* Diverting to port zero is invalid */ + case IP_FW_F_PIPE: /* piping through 0 is invalid */ case IP_FW_F_TEE: if (frwl->fw_divert_port == 0) { dprintf(("%s can't divert to port 0\n", err_prefix)); @@ -1049,12 +1218,15 @@ ip_fw_ctl(struct sockopt *sopt) break; default: - panic("ip_fw_ctl"); + printf("ip_fw_ctl invalid option %d\n", sopt->sopt_name); + error = EINVAL ; } return (error); } +struct ip_fw_chain *ip_fw_default_rule ; + void ip_fw_init(void) { @@ -1077,6 +1249,7 @@ ip_fw_init(void) add_entry(&ip_fw_chain, &default_rule)) panic("ip_fw_init"); + ip_fw_default_rule = ip_fw_chain.lh_first ; printf("IP packet filtering initialized, " #ifdef IPDIVERT "divert enabled, "); @@ -1102,10 +1275,7 @@ ip_fw_init(void) #endif } -static ip_fw_chk_t *old_chk_ptr; -static ip_fw_ctl_t *old_ctl_ptr; - -#if defined(IPFIREWALL_MODULE) && !defined(KLD_MODULE) +#ifdef IPFIREWALL_MODULE #include <sys/exec.h> #include <sys/sysent.h> @@ -1152,48 +1322,4 @@ ipfw_mod(struct lkm_table *lkmtp, int cmd, int ver) MOD_DISPATCH(ipfw, lkmtp, cmd, ver, ipfw_load, ipfw_unload, lkm_nullcmd); } -#else -static int -ipfw_modevent(module_t mod, int type, void *unused) -{ - int s; - - switch (type) { - case MOD_LOAD: - s = splnet(); - - old_chk_ptr = ip_fw_chk_ptr; - old_ctl_ptr = ip_fw_ctl_ptr; - - ip_fw_init(); - splx(s); - return 0; - case MOD_UNLOAD: - s = splnet(); - - ip_fw_chk_ptr = old_chk_ptr; - ip_fw_ctl_ptr = old_ctl_ptr; - - while (LIST_FIRST(&ip_fw_chain) != NULL) { - struct ip_fw_chain *fcp = LIST_FIRST(&ip_fw_chain); - LIST_REMOVE(LIST_FIRST(&ip_fw_chain), chain); - free(fcp->rule, M_IPFW); - free(fcp, M_IPFW); - } - - splx(s); - printf("IP firewall unloaded\n"); - return 0; - default: - break; - } - return 0; -} - -static moduledata_t ipfwmod = { - "ipfw", - ipfw_modevent, - 0 -}; -DECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PSEUDO, SI_ORDER_ANY); #endif |