summaryrefslogtreecommitdiffstats
path: root/contrib/ipfilter/ip_state.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ipfilter/ip_state.c')
-rw-r--r--contrib/ipfilter/ip_state.c112
1 files changed, 95 insertions, 17 deletions
diff --git a/contrib/ipfilter/ip_state.c b/contrib/ipfilter/ip_state.c
index c14c23f..1503bb9 100644
--- a/contrib/ipfilter/ip_state.c
+++ b/contrib/ipfilter/ip_state.c
@@ -7,7 +7,7 @@
*/
#if !defined(lint)
static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-1995 Darren Reed";
-static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.3.2.9 1999/10/21 14:31:09 darrenr Exp $";
+static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.3.2.16 1999/12/28 05:24:58 darrenr Exp $";
#endif
#include <sys/errno.h>
@@ -200,10 +200,6 @@ int which;
} else
isp = &is->is_next;
}
- if (fr_state_doflush) {
- (void) fr_state_flush(1);
- fr_state_doflush = 0;
- }
RWLOCK_EXIT(&ipf_state);
SPL_X(s);
return removed;
@@ -231,6 +227,14 @@ int mode;
} else
error = EINVAL;
break;
+#ifdef IPFILTER_LOG
+ case SIOCIPFFB :
+ if (!(mode & FWRITE))
+ error = EPERM;
+ else
+ *(int *)data = ipflog_clear(IPL_LOGSTATE);
+ break;
+#endif
case SIOCGIPST :
IWCOPY((caddr_t)fr_statetstats(), data, sizeof(ips_stat_t));
break;
@@ -346,9 +350,11 @@ u_int flags;
{
register tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp;
+ is->is_dport = tcp->th_dport;
+ is->is_sport = tcp->th_sport;
if ((flags & (FI_W_DPORT|FI_W_SPORT)) == 0) {
- hv += (is->is_dport = tcp->th_dport);
- hv += (is->is_sport = tcp->th_sport);
+ hv += tcp->th_dport;
+ hv += tcp->th_sport;
}
ATOMIC_INC(ips_stats.iss_udp);
is->is_age = fr_udptimeout;
@@ -656,12 +662,14 @@ fr_info_t *fin;
register u_short sport, dport;
register u_char pr;
struct icmp *ic;
+ u_short savelen;
fr_info_t ofin;
- u_int hv, dest;
tcphdr_t *tcp;
+ icmphdr_t *icmp;
frentry_t *fr;
ip_t *oip;
int type;
+ u_int hv;
/*
* Does it at least have the return (basic) IP header ?
@@ -683,6 +691,70 @@ fr_info_t *fin;
oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN);
if (ip->ip_len < ICMPERR_MAXPKTLEN + ((oip->ip_hl - 5) << 2))
return NULL;
+
+ if (oip->ip_p == IPPROTO_ICMP) {
+
+ icmp = (icmphdr_t *)((char *)oip + (oip->ip_hl << 2));
+
+ /*
+ * a ICMP error can only be generated as a result of an
+ * ICMP query, not as the response on an ICMP error
+ *
+ * XXX theoretically ICMP_ECHOREP and the other reply's are
+ * ICMP query's as well, but adding them here seems strange XXX
+ */
+ if ((icmp->icmp_type != ICMP_ECHO) &&
+ (icmp->icmp_type != ICMP_TSTAMP) &&
+ (icmp->icmp_type != ICMP_IREQ) &&
+ (icmp->icmp_type != ICMP_MASKREQ))
+ return NULL;
+
+ /*
+ * perform a lookup of the ICMP packet in the state table
+ */
+
+ hv = (pr = oip->ip_p);
+ hv += (src.s_addr = oip->ip_src.s_addr);
+ hv += (dst.s_addr = oip->ip_dst.s_addr);
+ if (icmp->icmp_type == ICMP_ECHO) {
+ hv += icmp->icmp_id;
+ hv += icmp->icmp_seq;
+ }
+ hv %= fr_statesize;
+
+ oip->ip_len = ntohs(oip->ip_len);
+ fr_makefrip(oip->ip_hl << 2, oip, &ofin);
+ oip->ip_len = htons(oip->ip_len);
+ ofin.fin_ifp = fin->fin_ifp;
+ ofin.fin_out = !fin->fin_out;
+ ofin.fin_mp = NULL; /* if dereferenced, panic XXX */
+
+ READ_ENTER(&ipf_state);
+ for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next)
+ if ((is->is_p == pr) &&
+ fr_matchsrcdst(is, src, dst, &ofin, NULL)) {
+ /*
+ * in the state table ICMP query's are stored
+ * with the type of the corresponding ICMP
+ * response. Correct here
+ */
+ if (((is->is_type == ICMP_ECHOREPLY) &&
+ (icmp->icmp_id == is->is_icmp.ics_id) &&
+ (icmp->icmp_seq == is->is_icmp.ics_seq) &&
+ (icmp->icmp_type == ICMP_ECHO)) ||
+ (is->is_type - 1 == ic->icmp_type)) {
+ ips_stats.iss_hits++;
+ is->is_pkts++;
+ is->is_bytes += ip->ip_len;
+ fr = is->is_rule;
+ RWLOCK_EXIT(&ipf_state);
+ return fr;
+ }
+ }
+ RWLOCK_EXIT(&ipf_state);
+ return NULL;
+ };
+
if ((oip->ip_p != IPPROTO_TCP) && (oip->ip_p != IPPROTO_UDP))
return NULL;
@@ -706,9 +778,10 @@ fr_info_t *fin;
* watch out here, as ip is in host order and oip in network
* order. Any change we make must be undone afterwards.
*/
- oip->ip_len = ntohs(oip->ip_len);
+ savelen = oip->ip_len;
+ oip->ip_len = ip->ip_len - (ip->ip_hl << 2) - ICMPERR_ICMPHLEN;
fr_makefrip(oip->ip_hl << 2, oip, &ofin);
- oip->ip_len = htons(oip->ip_len);
+ oip->ip_len = savelen;
ofin.fin_ifp = fin->fin_ifp;
ofin.fin_out = !fin->fin_out;
ofin.fin_mp = NULL; /* if dereferenced, panic XXX */
@@ -729,7 +802,6 @@ fr_info_t *fin;
* we must swap src and dst here because the icmp
* comes the other way around
*/
- dest = (is->is_dst.s_addr != src.s_addr);
is->is_pkts++;
is->is_bytes += ip->ip_len;
/*
@@ -777,17 +849,20 @@ fr_info_t *fin;
switch (ip->ip_p)
{
case IPPROTO_ICMP :
- hv += ic->icmp_id;
- hv += ic->icmp_seq;
+ if ((ic->icmp_type == ICMP_ECHO) ||
+ (ic->icmp_type == ICMP_ECHOREPLY)) {
+ hv += ic->icmp_id;
+ hv += ic->icmp_seq;
+ }
hv %= fr_statesize;
READ_ENTER(&ipf_state);
for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next)
if ((is->is_p == pr) &&
- (ic->icmp_id == is->is_icmp.ics_id) &&
- (ic->icmp_seq == is->is_icmp.ics_seq) &&
fr_matchsrcdst(is, src, dst, fin, NULL)) {
if ((is->is_type == ICMP_ECHOREPLY) &&
- (ic->icmp_type == ICMP_ECHO))
+ (ic->icmp_type == ICMP_ECHO) &&
+ (ic->icmp_id == is->is_icmp.ics_id) &&
+ (ic->icmp_seq == is->is_icmp.ics_seq))
;
else if (is->is_type != ic->icmp_type)
continue;
@@ -818,7 +893,6 @@ retry_tcp:
if ((is->is_p == pr) &&
fr_matchsrcdst(is, src, dst, fin, tcp)) {
if (fr_tcpstate(is, fin, ip, tcp)) {
- break;
#ifndef _KERNEL
if (tcp->th_flags & TCP_CLOSE) {
*isp = is->is_next;
@@ -964,6 +1038,10 @@ void fr_timeoutstate()
ips_num--;
} else
isp = &is->is_next;
+ if (fr_state_doflush) {
+ (void) fr_state_flush(1);
+ fr_state_doflush = 0;
+ }
RWLOCK_EXIT(&ipf_state);
SPL_X(s);
}
OpenPOWER on IntegriCloud