diff options
author | kstailey <kstailey@cvs.openbsd.org> | 1997-02-11 22:24:21 +0000 |
---|---|---|
committer | kstailey <kstailey@cvs.openbsd.org> | 1997-02-11 22:24:21 +0000 |
commit | 80aea2f1d26c615419d2d028087115c47f9fd46f (patch) | |
tree | f63dc8d784c2927447f3929c843a58673ed5ffc0 /sys/netinet/ip_state.c | |
parent | 5e04debc4b0038a40277cd3f8198955ee51896d3 (diff) |
IPF 1.3.7
Diffstat (limited to 'sys/netinet/ip_state.c')
-rw-r--r-- | sys/netinet/ip_state.c | 316 |
1 files changed, 226 insertions, 90 deletions
diff --git a/sys/netinet/ip_state.c b/sys/netinet/ip_state.c index c6c04d57c77..71af2c23176 100644 --- a/sys/netinet/ip_state.c +++ b/sys/netinet/ip_state.c @@ -1,3 +1,4 @@ +/* $OpenBSD: ip_state.c,v 1.7 1997/02/11 22:23:28 kstailey Exp $ */ /* * (C)opyright 1995 by Darren Reed. * @@ -6,9 +7,9 @@ * to the original author and the contributors. */ #if 0 -#ifndef lint +#if !defined(lint) && defined(LIBC_SCCS) static char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-1995 Darren Reed"; -static char rcsid[] = "$OpenBSD: ip_state.c,v 1.6 1997/01/18 08:29:21 downsj Exp $"; +static char rcsid[] = "Id: ip_state.c,v 2.0.1.2 1997/01/09 15:22:45 darrenr Exp "; #endif #endif @@ -16,24 +17,18 @@ static char rcsid[] = "$OpenBSD: ip_state.c,v 1.6 1997/01/18 08:29:21 downsj Exp # include <stdlib.h> # include <string.h> #endif -#ifndef linux #include <sys/errno.h> #include <sys/types.h> -#if defined(_KERNEL) || defined(KERNEL) -#include <sys/systm.h> -#endif #include <sys/param.h> #include <sys/file.h> #include <sys/ioctl.h> #include <sys/uio.h> #include <sys/protosw.h> #include <sys/socket.h> +#ifdef _KERNEL +# include <sys/systm.h> +#endif #if !defined(__SVR4) && !defined(__svr4__) -# if defined(__OpenBSD__) -# include <sys/dirent.h> -# else -# include <sys/dir.h> -# endif # include <sys/mbuf.h> #else # include <sys/byteorder.h> @@ -52,11 +47,10 @@ static char rcsid[] = "$OpenBSD: ip_state.c,v 1.6 1997/01/18 08:29:21 downsj Exp #include <netinet/ip.h> #include <netinet/ip_var.h> #include <netinet/tcp.h> +#include <netinet/tcp_fsm.h> #include <netinet/udp.h> #include <netinet/tcpip.h> #include <netinet/ip_icmp.h> -#include <sys/syslog.h> -#endif #include "ip_fil_compat.h" #include "ip_fil.h" #include "ip_state.h" @@ -64,6 +58,15 @@ static char rcsid[] = "$OpenBSD: ip_state.c,v 1.6 1997/01/18 08:29:21 downsj Exp #define MIN(a,b) (((a)<(b))?(a):(b)) #endif +void set_tcp_age __P((int *, u_char *, ip_t *, fr_info_t *, int)); +#ifndef _KERNEL +int fr_tcpstate __P((register ipstate_t *, fr_info_t *, ip_t *, tcphdr_t *, + u_short, ipstate_t **)); +#else +int fr_tcpstate __P((register ipstate_t *, fr_info_t *, ip_t *, tcphdr_t *, + u_short)); +#endif + #define TCP_CLOSE (TH_FIN|TH_RST) ipstate_t *ips_table[IPSTATE_SIZE]; @@ -77,6 +80,17 @@ extern kmutex_t ipf_state; #endif +#define FIVE_DAYS (2 * 5 * 86400) /* 5 days: half closed session */ + +u_long fr_tcpidletimeout = FIVE_DAYS, + fr_tcpclosewait = 60, + fr_tcplastack = 20, + fr_tcptimeout = 120, + fr_tcpclosed = 1, + fr_udptimeout = 120, + fr_icmptimeout = 120; + + ips_stat_t * fr_statetstats() { @@ -104,10 +118,15 @@ fr_addstate(ip, fin, pass) register ipstate_t *is = &ips; register u_int hv; + if ((ip->ip_off & 0x1fff) || (fin->fin_fi.fi_fl & FI_SHORT)) + return -1; if (ips_num == IPSTATE_MAX) { ips_stats.iss_max++; return -1; } + ips.is_age = 1; + ips.is_state[0] = 0; + ips.is_state[1] = 0; /* * Copy and calculate... */ @@ -137,7 +156,7 @@ fr_addstate(ip, fin, pass) return -1; } ips_stats.iss_icmp++; - is->is_age = 120; + is->is_age = fr_icmptimeout; break; } case IPPROTO_TCP : @@ -152,7 +171,8 @@ fr_addstate(ip, fin, pass) hv += (is->is_sport = tcp->th_sport); is->is_seq = ntohl(tcp->th_seq); is->is_ack = ntohl(tcp->th_ack); - is->is_win = ntohs(tcp->th_win); + is->is_swin = ntohs(tcp->th_win); + is->is_dwin = is->is_swin; /* start them the same */ ips_stats.iss_tcp++; /* * If we're creating state for a starting connectoin, start the @@ -160,9 +180,9 @@ fr_addstate(ip, fin, pass) * connect. */ if ((tcp->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) - is->is_age = 120; - else - is->is_age = 0; + is->is_ack = 0; /* Trumpet WinSock 'ism */ + set_tcp_age(&is->is_age, is->is_state, ip, fin, + tcp->th_sport == is->is_sport); break; } case IPPROTO_UDP : @@ -172,7 +192,7 @@ fr_addstate(ip, fin, pass) hv += (is->is_dport = tcp->th_dport); hv += (is->is_sport = tcp->th_sport); ips_stats.iss_udp++; - is->is_age = 120; + is->is_age = fr_udptimeout; break; } default : @@ -198,6 +218,91 @@ fr_addstate(ip, fin, pass) /* + * check to see if a packet with TCP headers fits within the TCP window. + * change timeout depending on whether new packet is a SYN-ACK returning for a + * SYN or a RST or FIN which indicate time to close up shop. + */ +int +fr_tcpstate(is, fin, ip, tcp, sport +#ifndef _KERNEL + ,isp) + ipstate_t **isp; +#else + ) +#endif + register ipstate_t *is; + fr_info_t *fin; + ip_t *ip; + tcphdr_t *tcp; + u_short sport; +{ + register int seqskew, ackskew; + register u_short swin, dwin; + register tcp_seq seq, ack; + int source; + + /* + * Find difference between last checked packet and this packet. + */ + seq = ntohl(tcp->th_seq); + ack = ntohl(tcp->th_ack); + if (sport == is->is_sport) { + seqskew = seq - is->is_seq; + ackskew = ack - is->is_ack; + } else { + seqskew = ack - is->is_seq; + if (!is->is_ack) + /* + * Must be a SYN-ACK in reply to a SYN. + */ + is->is_ack = seq; + ackskew = seq - is->is_ack; + } + + /* + * Make skew values absolute + */ + if (seqskew < 0) + seqskew = -seqskew; + if (ackskew < 0) + ackskew = -ackskew; + + /* + * If the difference in sequence and ack numbers is within the + * window size of the connection, store these values and match + * the packet. + */ + if ((source = (sport == is->is_sport))) { + swin = is->is_swin; + dwin = is->is_dwin; + } else { + dwin = is->is_swin; + swin = is->is_dwin; + } + + if ((seqskew <= swin) && (ackskew <= dwin)) { + if (source) { + is->is_seq = seq; + is->is_ack = ack; + is->is_swin = ntohs(tcp->th_win); + } else { + is->is_seq = ack; + is->is_ack = seq; + is->is_dwin = ntohs(tcp->th_win); + } + ips_stats.iss_hits++; + /* + * Nearing end of connection, start timeout. + */ + set_tcp_age(&is->is_age, is->is_state, ip, fin, + tcp->th_sport == is->is_sport); + return 1; + } + return 0; +} + + +/* * Check if a packet has a registered state. */ int @@ -212,7 +317,7 @@ fr_checkstate(ip, fin) tcphdr_t *tcp; u_int hv, hlen; - if ((ip->ip_off & 0x1fff) && !(fin->fin_fi.fi_fl & FI_SHORT)) + if ((ip->ip_off & 0x1fff) || (fin->fin_fi.fi_fl & FI_SHORT)) return 0; hlen = fin->fin_hlen; @@ -244,7 +349,7 @@ fr_checkstate(ip, fin) if (is->is_icmp.ics_type && is->is_icmp.ics_type != ic->icmp_type) continue; - is->is_age = 120; + is->is_age = fr_icmptimeout; ips_stats.iss_hits++; MUTEX_EXIT(&ipf_state); return is->is_pass; @@ -254,92 +359,34 @@ fr_checkstate(ip, fin) case IPPROTO_TCP : { register u_short dport = tcp->th_dport, sport = tcp->th_sport; - register u_short win = ntohs(tcp->th_win); - tcp_seq seq, ack; hv += dport; hv += sport; hv %= IPSTATE_SIZE; MUTEX_ENTER(&ipf_state); for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next) { - register int dl, seqskew, ackskew; - if ((is->is_p == pr) && PAIRS(sport, dport, is->is_sport, is->is_dport) && - IPPAIR(src, dst, is->is_src, is->is_dst)) { - dl = ip->ip_len - hlen - sizeof(tcphdr_t); - /* - * Find difference between last checked packet - * and this packet. - */ - seq = ntohl(tcp->th_seq); - ack = ntohl(tcp->th_ack); - if (sport == is->is_sport) { - seqskew = seq - is->is_seq; - ackskew = ack - is->is_ack; - } else { - seqskew = ack - is->is_seq; - if (!is->is_ack) { - /* - * Must be a SYN-ACK in reply - * to a SYN. Set age timeout - * to 0 to stop deletion. - */ - is->is_ack = seq; - is->is_age = 0; - } - ackskew = seq - is->is_ack; - } - - /* - * Make skew values absolute - */ - if (seqskew < 0) - seqskew = -seqskew; - if (ackskew < 0) - ackskew = -ackskew; - /* - * If the difference in sequence and ack - * numbers is within the window size of the - * connection, store these values and match - * the packet. - */ - if ((seqskew <= win) && (ackskew <= win)) { - is->is_win = win; - if (sport == is->is_sport) { - is->is_seq = seq; - is->is_ack = ack; - } else { - is->is_seq = ack; - is->is_ack = seq; - } - ips_stats.iss_hits++; - /* - * Nearing end of connection, start - * timeout. - */ + IPPAIR(src, dst, is->is_src, is->is_dst)) + if (fr_tcpstate(is, fin, ip, tcp, sport +#ifndef _KERNEL + , NULL +#endif + )) { #ifdef _KERNEL - if (!is->is_age) { - if (tcp->th_flags & TH_FIN) - is->is_age = 120; - if (tcp->th_flags & TH_RST) - is->is_age = 1; - } MUTEX_EXIT(&ipf_state); return is->is_pass; #else - if (tcp->th_flags & TCP_CLOSE) { - int pass = is->is_pass; + int pass = is->is_pass; + if (tcp->th_flags & TCP_CLOSE) { *isp = is->is_next; isp = &ips_table[hv]; KFREE(is); - return pass; } - return is->is_pass; + return pass; #endif } - } } MUTEX_EXIT(&ipf_state); break; @@ -360,7 +407,7 @@ fr_checkstate(ip, fin) PAIRS(sport, dport, is->is_sport, is->is_dport) && IPPAIR(src, dst, is->is_src, is->is_dst)) { ips_stats.iss_hits++; - is->is_age = 120; + is->is_age = fr_udptimeout; MUTEX_EXIT(&ipf_state); return is->is_pass; } @@ -395,7 +442,7 @@ fr_stateunload() /* - * Slowly expire held state for thingslike UDP and ICMP. Timeouts are set + * Slowly expire held state for things like UDP and ICMP. Timeouts are set * in expectation of this being called twice per second. */ void @@ -419,3 +466,92 @@ fr_timeoutstate() isp = &is->is_next; MUTEX_EXIT(&ipf_state); } + + +/* + * Original idea freom Pradeep Krishnan for use primarily with NAT code. + * (pkrishna@netcom.com) + */ +void +set_tcp_age(age, state, ip, fin, dir) + int *age; + u_char *state; + ip_t *ip; + fr_info_t *fin; + int dir; +{ + tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; + u_char flags = tcp->th_flags; + int dlen, ostate; + + ostate = state[1 - dir]; + + dlen = ip->ip_len - fin->fin_hlen - (tcp->th_off << 2); + + if (flags & TH_RST) { + if (!(tcp->th_flags & TH_PUSH) && !dlen) { + *age = fr_tcpclosed; + state[dir] = TCPS_CLOSED; + } else { + *age = fr_tcpclosewait; + state[dir] = TCPS_CLOSE_WAIT; + } + return; + } + + *age = fr_tcptimeout; /* 1 min */ + + switch(state[dir]) + { + case TCPS_FIN_WAIT_2: + case TCPS_CLOSED: + if ((flags & TH_OPENING) == TH_OPENING) + state[dir] = TCPS_SYN_RECEIVED; + else if (flags & TH_SYN) + state[dir] = TCPS_SYN_SENT; + break; + case TCPS_SYN_RECEIVED: + if ((flags & (TH_FIN|TH_ACK)) == TH_ACK) { + state[dir] = TCPS_ESTABLISHED; + *age = fr_tcpidletimeout; + } + break; + case TCPS_SYN_SENT: + if ((flags & (TH_FIN|TH_ACK)) == TH_ACK) { + state[dir] = TCPS_ESTABLISHED; + *age = fr_tcpidletimeout; + } + break; + case TCPS_ESTABLISHED: + if (flags & TH_FIN) { + state[dir] = TCPS_CLOSE_WAIT; + if (!(flags & TH_PUSH) && !dlen && + ostate > TCPS_ESTABLISHED) + *age = fr_tcplastack; + else + *age = fr_tcpclosewait; + } else + *age = fr_tcpidletimeout; + break; + case TCPS_CLOSE_WAIT: + if ((flags & TH_FIN) && !(flags & TH_PUSH) && !dlen && + ostate > TCPS_ESTABLISHED) { + *age = fr_tcplastack; + state[dir] = TCPS_LAST_ACK; + } else + *age = fr_tcpclosewait; + break; + case TCPS_LAST_ACK: + if (flags & TH_ACK) { + state[dir] = TCPS_FIN_WAIT_2; + if (!(flags & TH_PUSH) && !dlen && + ostate > TCPS_ESTABLISHED) + *age = fr_tcplastack; + else { + *age = fr_tcpclosewait; + state[dir] = TCPS_CLOSE_WAIT; + } + } + break; + } +} |