diff options
Diffstat (limited to 'sys/netinet/ip_fw.c')
-rw-r--r-- | sys/netinet/ip_fw.c | 80 |
1 files changed, 39 insertions, 41 deletions
diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c index 3f3d325..0b86c74 100644 --- a/sys/netinet/ip_fw.c +++ b/sys/netinet/ip_fw.c @@ -78,6 +78,13 @@ static int fw_verbose_limit = IPFIREWALL_VERBOSE_LIMIT; static int fw_verbose_limit = 0; #endif +/* + * Right now, two fields in the IP header are changed to host format + * by the IP layer before calling the firewall. Ideally, we would like + * to have them in network format so that the packet can be + * used as it comes from the device driver (and is thus readonly). + */ + static u_int64_t counter; /* counter for ipfw_report(NULL...) */ struct ipfw_flow_id last_pkt ; @@ -102,7 +109,6 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose, CTLFLAG_RW, SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw_verbose_limit, 0, "Set upper limit of matches of ipfw rules logged"); -#if STATEFUL /* * Extension for stateful ipfw. * @@ -173,7 +179,6 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_rst_lifetime, CTLFLAG_RW, &dyn_rst_lifetime, 0, "Lifetime of dyn. rules for rst"); SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_short_lifetime, CTLFLAG_RW, &dyn_short_lifetime, 0, "Lifetime of dyn. rules for other situations"); -#endif /* STATEFUL */ #endif @@ -198,7 +203,7 @@ static __inline int int range_flag, int mask)); static int tcpflg_match __P((struct tcphdr *tcp, struct ip_fw *f)); static int icmptype_match __P((struct icmp * icmp, struct ip_fw * f)); -static void ipfw_report __P((struct ip_fw *f, struct ip *ip, +static void ipfw_report __P((struct ip_fw *f, struct ip *ip, int offset, struct ifnet *rif, struct ifnet *oif)); static void flush_rule_ptrs(void); @@ -486,7 +491,7 @@ iface_match(struct ifnet *ifp, union ip_fw_if *ifu, int byname) } static void -ipfw_report(struct ip_fw *f, struct ip *ip, +ipfw_report(struct ip_fw *f, struct ip *ip, int offset, struct ifnet *rif, struct ifnet *oif) { struct tcphdr *const tcp = (struct tcphdr *) ((u_int32_t *) ip+ ip->ip_hl); @@ -571,33 +576,33 @@ ipfw_report(struct ip_fw *f, struct ip *ip, case IPPROTO_TCP: len = snprintf(SNPARGS(proto, 0), "TCP %s", inet_ntoa(ip->ip_src)); - if ((ip->ip_off & IP_OFFMASK) == 0) + if (offset == 0) len += snprintf(SNPARGS(proto, len), ":%d ", ntohs(tcp->th_sport)); else len += snprintf(SNPARGS(proto, len), " "); len += snprintf(SNPARGS(proto, len), "%s", inet_ntoa(ip->ip_dst)); - if ((ip->ip_off & IP_OFFMASK) == 0) + if (offset == 0) snprintf(SNPARGS(proto, len), ":%d", ntohs(tcp->th_dport)); break; case IPPROTO_UDP: len = snprintf(SNPARGS(proto, 0), "UDP %s", inet_ntoa(ip->ip_src)); - if ((ip->ip_off & IP_OFFMASK) == 0) + if (offset == 0) len += snprintf(SNPARGS(proto, len), ":%d ", ntohs(udp->uh_sport)); else len += snprintf(SNPARGS(proto, len), " "); len += snprintf(SNPARGS(proto, len), "%s", inet_ntoa(ip->ip_dst)); - if ((ip->ip_off & IP_OFFMASK) == 0) + if (offset == 0) snprintf(SNPARGS(proto, len), ":%d", ntohs(udp->uh_dport)); break; case IPPROTO_ICMP: - if ((ip->ip_off & IP_OFFMASK) == 0) + if (offset == 0) len = snprintf(SNPARGS(proto, 0), "ICMP:%u.%u ", icmp->icmp_type, icmp->icmp_code); else @@ -613,9 +618,9 @@ ipfw_report(struct ip_fw *f, struct ip *ip, break; } - if ((ip->ip_off & IP_OFFMASK)) + if (offset != 0) snprintf(SNPARGS(fragment, 0), " Fragment = %d", - ip->ip_off & IP_OFFMASK); + offset); else fragment[0] = '\0'; if (oif) @@ -635,7 +640,6 @@ ipfw_report(struct ip_fw *f, struct ip *ip, f ? f->fw_number : -1); } -#if STATEFUL static __inline int hash_packet(struct ipfw_flow_id *id) { @@ -883,7 +887,6 @@ install_state(struct ip_fw_chain *chain) } q = lookup_dyn_rule(&last_pkt, NULL) ; /* XXX this just sets the lifetime ... */ } -#endif /* STATEFUL */ /* * given an ip_fw_chain *, lookup_next_rule will return a pointer @@ -950,17 +953,18 @@ ip_fw_chk(struct ip **pip, int hlen, struct in_addr src_ip, dst_ip; /* XXX */ u_int8_t proto= 0, flags = 0 ; /* XXX */ u_int16_t skipto, bridgeCookie; + u_int16_t ip_len; -#if STATEFUL int dyn_checked = 0 ; /* set after dyn.rules have been checked. */ int direction = MATCH_FORWARD ; /* dirty trick... */ struct ipfw_dyn_rule *q = NULL ; -#endif /* Special hack for bridging (as usual) */ if (cookie == NULL) { bridgeCookie = 0; cookie = &bridgeCookie; +#define BRIDGED (cookie == &bridgeCookie) + hlen = ip->ip_hl << 2; } /* Grab and reset cookie */ @@ -982,7 +986,13 @@ ip_fw_chk(struct ip **pip, int hlen, proto = ip->ip_p; src_ip = ip->ip_src; dst_ip = ip->ip_dst; - offset = (ip->ip_off & IP_OFFMASK); + if (0 && BRIDGED) { + offset = (NTOHS(ip->ip_off) & IP_OFFMASK); + ip_len = NTOHS(ip->ip_len); + } else { + offset = (ip->ip_off & IP_OFFMASK); + ip_len = ip->ip_len; + } if (offset == 0) { struct tcphdr *tcp; struct udphdr *udp; @@ -1059,7 +1069,6 @@ again: if (f->fw_number == IPFW_DEFAULT_RULE) goto got_match ; -#if STATEFUL /* * dynamic rules are checked at the first keep-state or * check-state occurrence. @@ -1076,17 +1085,16 @@ again: chain = q->chain ; f = chain->rule ; q->pcnt++ ; - q->bcnt += ip->ip_len; + q->bcnt += ip_len; goto got_match ; /* random not allowed here */ } /* if this was a check-only rule, continue with next */ if (f->fw_flg & IP_FW_F_CHECK_S) continue ; } -#endif /* stateful ipfw */ /* Check if rule only valid for bridged packets */ - if ((f->fw_flg & IP_FW_BRIDGED) != 0 && cookie != &bridgeCookie) + if ((f->fw_flg & IP_FW_BRIDGED) != 0 && ! (BRIDGED) ) continue; if (oif) { @@ -1137,7 +1145,7 @@ again: /* Check IP header values */ if (f->fw_ipflg & IP_FW_IF_IPOPT && !ipopts_match(ip, f)) continue; - if (f->fw_ipflg & IP_FW_IF_IPLEN && f->fw_iplen != ip->ip_len) + if (f->fw_ipflg & IP_FW_IF_IPLEN && f->fw_iplen != ip_len) continue; if (f->fw_ipflg & IP_FW_IF_IPID && f->fw_ipid != ntohs(ip->ip_id)) continue; @@ -1304,7 +1312,7 @@ check_ports: bogusfrag: if (fw_verbose) - ipfw_report(NULL, ip, rif, oif); + ipfw_report(NULL, ip, offset, rif, oif); goto dropit; } @@ -1314,23 +1322,21 @@ rnd_then_got_match: random() < ((struct ip_fw_ext *)f)->dont_match_prob ) continue ; got_match: -#if STATEFUL /* stateful ipfw */ /* * If not a dynamic match (q == NULL) and keep-state, install * a new dynamic entry. */ if (q == NULL && f->fw_flg & IP_FW_F_KEEP_S) install_state(chain); -#endif *flow_id = chain ; /* XXX set flow id */ /* Update statistics */ f->fw_pcnt += 1; - f->fw_bcnt += ip->ip_len; + f->fw_bcnt += ip_len; f->timestamp = time_second; /* Log to console if desired */ if ((f->fw_flg & IP_FW_F_PRN) && fw_verbose) - ipfw_report(f, ip, rif, oif); + ipfw_report(f, ip, offset, rif, oif); /* Take appropriate action */ switch (f->fw_flg & IP_FW_F_COMMAND) { @@ -1401,6 +1407,7 @@ got_match: switch (rule->fw_reject_code) { case IP_FW_REJECT_RST: { + /* XXX warning, this code writes into the mbuf */ struct tcphdr *const tcp = (struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl); struct tcpiphdr ti, *const tip = (struct tcpiphdr *) ip; @@ -1412,7 +1419,7 @@ got_match: bcopy(&ti, ip, sizeof(ti)); NTOHL(tip->ti_seq); NTOHL(tip->ti_ack); - tip->ti_len = ip->ip_len - hlen - (tip->ti_off << 2); + tip->ti_len = ip_len - hlen - (tip->ti_off << 2); if (tcp->th_flags & TH_ACK) { tcp_respond(NULL, (void *)ip, tcp, *m, (tcp_seq)0, ntohl(tcp->th_ack), TH_RST); @@ -1443,6 +1450,7 @@ dropit: *m = NULL; } return(0); +#undef BRIDGED } /* @@ -1549,9 +1557,7 @@ del_entry(struct ip_fw_head *chainptr, u_short number) while (fcp && fcp->rule->fw_number == number) { struct ip_fw_chain *next; -#if STATEFUL - remove_dyn_rule(fcp, 1 /* force_delete */); -#endif + remove_dyn_rule(fcp, 1 /* delete */); next = LIST_NEXT(fcp, chain); LIST_REMOVE(fcp, chain); #ifdef DUMMYNET @@ -1835,7 +1841,6 @@ ip_fw_ctl(struct sockopt *sopt) for (fcp = LIST_FIRST(&ip_fw_chain), size = 0; fcp; fcp = LIST_NEXT(fcp, chain)) size += sizeof *fcp->rule; -#if STATEFUL if (ipfw_dyn_v) { int i ; struct ipfw_dyn_rule *p ; @@ -1844,7 +1849,6 @@ ip_fw_ctl(struct sockopt *sopt) for ( p = ipfw_dyn_v[i] ; p != NULL ; p = p->next ) size += sizeof(*p) ; } -#endif buf = malloc(size, M_TEMP, M_WAITOK); if (buf == 0) { error = ENOBUFS; @@ -1860,7 +1864,6 @@ ip_fw_ctl(struct sockopt *sopt) ((struct ip_fw_ext *)fcp->rule)->dyn_type; bp++; } -#if STATEFUL if (ipfw_dyn_v) { int i ; struct ipfw_dyn_rule *p, *dst, *last = NULL ; @@ -1880,17 +1883,14 @@ ip_fw_ctl(struct sockopt *sopt) if (last != NULL) last->next = NULL ; } -#endif error = sooptcopyout(sopt, buf, size); FREE(buf, M_TEMP); break; case IP_FW_FLUSH: -#if STATEFUL - s = splnet(); - remove_dyn_rule(NULL, 1 /* force delete */); - splx(s); -#endif + s = splnet(); + remove_dyn_rule(NULL, 1 /* force delete */); + splx(s); for (fcp = ip_fw_chain.lh_first; fcp != 0 && fcp->rule->fw_number != IPFW_DEFAULT_RULE; fcp = ip_fw_chain.lh_first) { @@ -2039,9 +2039,7 @@ ipfw_modevent(module_t mod, int type, void *unused) s = splnet(); ip_fw_chk_ptr = old_chk_ptr; ip_fw_ctl_ptr = old_ctl_ptr; -#if STATEFUL remove_dyn_rule(NULL, 1 /* force delete */); -#endif 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); |