]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet/ip_state.c
xnu-124.13.tar.gz
[apple/xnu.git] / bsd / netinet / ip_state.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Copyright (C) 1995-1997 by Darren Reed.
24 *
25 * Redistribution and use in source and binary forms are permitted
26 * provided that this notice is preserved and due credit is given
27 * to the original author and the contributors.
28 */
29#if !defined(lint)
30/* static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-1995 Darren Reed"; */
31#endif
32
33#include "opt_ipfilter.h"
34#if defined(KERNEL) && !defined(_KERNEL)
35#define _KERNEL
36#endif
37#define __FreeBSD_version 300000 /* it's a hack, but close enough */
38
39#if !defined(_KERNEL) && !defined(KERNEL) && !defined(__KERNEL__)
40# include <stdlib.h>
41# include <string.h>
42#else
43# ifdef linux
44# include <linux/kernel.h>
45# include <linux/module.h>
46# endif
47#endif
48#include <sys/errno.h>
49#include <sys/types.h>
50#include <sys/param.h>
51#include <sys/file.h>
52#if defined(KERNEL) && (__FreeBSD_version >= 220000)
53# include <sys/filio.h>
54# include <sys/fcntl.h>
55# include <sys/malloc.h>
56#else
57# include <sys/ioctl.h>
58#endif
59#include <sys/time.h>
60#include <sys/uio.h>
61#ifndef linux
62#include <sys/protosw.h>
63#endif
64#include <sys/socket.h>
65#if defined(_KERNEL) && !defined(linux)
66# include <sys/systm.h>
67#endif
68#if !defined(__SVR4) && !defined(__svr4__)
69# ifndef linux
70# include <sys/mbuf.h>
71# endif
72#else
73# include <sys/filio.h>
74# include <sys/byteorder.h>
75# include <sys/dditypes.h>
76# include <sys/stream.h>
77# include <sys/kmem.h>
78#endif
79
80#include <net/if.h>
81#if sun
82#include <net/af.h>
83#endif
84#include <net/route.h>
85#include <netinet/in.h>
86#include <netinet/in_systm.h>
87#include <netinet/ip.h>
88#include <netinet/tcp.h>
89#ifndef linux
90# include <netinet/ip_var.h>
91# include <netinet/tcp_fsm.h>
92#endif
93#include <netinet/udp.h>
94#include <netinet/ip_icmp.h>
95#include "netinet/ip_compat.h"
96#include <netinet/tcpip.h>
97#include "netinet/ip_fil.h"
98#include "netinet/ip_nat.h"
99#include "netinet/ip_frag.h"
100#include "netinet/ip_proxy.h"
101#include "netinet/ip_state.h"
102#ifndef MIN
103#define MIN(a,b) (((a)<(b))?(a):(b))
104#endif
105
106#define TCP_CLOSE (TH_FIN|TH_RST)
107
108static ipstate_t *ips_table[IPSTATE_SIZE];
109static int ips_num = 0;
110static ips_stat_t ips_stats;
111#if (SOLARIS || defined(__sgi)) && defined(_KERNEL)
112extern kmutex_t ipf_state;
113#endif
114
115static int fr_matchsrcdst __P((ipstate_t *, struct in_addr, struct in_addr,
116 fr_info_t *, void *, u_short, u_short));
117static int fr_state_flush __P((int));
118static ips_stat_t *fr_statetstats __P((void));
119
120
121#define FIVE_DAYS (2 * 5 * 86400) /* 5 days: half closed session */
122
123u_long fr_tcpidletimeout = FIVE_DAYS,
124 fr_tcpclosewait = 60,
125 fr_tcplastack = 20,
126 fr_tcptimeout = 120,
127 fr_tcpclosed = 1,
128 fr_udptimeout = 120,
129 fr_icmptimeout = 120;
130
131
132static ips_stat_t *fr_statetstats()
133{
134 ips_stats.iss_active = ips_num;
135 ips_stats.iss_table = ips_table;
136 return &ips_stats;
137}
138
139
140/*
141 * flush state tables. two actions currently defined:
142 * which == 0 : flush all state table entries
143 * which == 1 : flush TCP connections which have started to close but are
144 * stuck for some reason.
145 */
146static int fr_state_flush(which)
147int which;
148{
149 register int i;
150 register ipstate_t *is, **isp;
151#if defined(_KERNEL) && !SOLARIS
152 int s;
153#endif
154 int delete, removed = 0;
155
156 SPL_NET(s);
157 MUTEX_ENTER(&ipf_state);
158 for (i = 0; i < IPSTATE_SIZE; i++)
159 for (isp = &ips_table[i]; (is = *isp); ) {
160 delete = 0;
161
162 switch (which)
163 {
164 case 0 :
165 delete = 1;
166 break;
167 case 1 :
168 if ((is->is_p == IPPROTO_TCP) &&
169 (((is->is_state[0] <= TCPS_ESTABLISHED) &&
170 (is->is_state[1] > TCPS_ESTABLISHED)) ||
171 ((is->is_state[1] <= TCPS_ESTABLISHED) &&
172 (is->is_state[0] > TCPS_ESTABLISHED))))
173 delete = 1;
174 break;
175 }
176
177 if (delete) {
178 *isp = is->is_next;
179 if (is->is_p == IPPROTO_TCP)
180 ips_stats.iss_fin++;
181 else
182 ips_stats.iss_expire++;
183#if IPFILTER_LOG
184 ipstate_log(is, ISL_FLUSH);
185#endif
186 KFREE(is);
187 ips_num--;
188 removed++;
189 } else
190 isp = &is->is_next;
191 }
192 MUTEX_EXIT(&ipf_state);
193 SPL_X(s);
194 return removed;
195}
196
197
198int fr_state_ioctl(data, cmd, mode)
199caddr_t data;
200#if defined(__NetBSD__) || defined(__OpenBSD__)
201u_long cmd;
202#else
203int cmd;
204#endif
205int mode;
206{
207 int arg, ret, error = 0;
208
209 switch (cmd)
210 {
211 case SIOCIPFFL :
212 IRCOPY(data, (caddr_t)&arg, sizeof(arg));
213 if (arg == 0 || arg == 1) {
214 ret = fr_state_flush(arg);
215 IWCOPY((caddr_t)&ret, data, sizeof(ret));
216 } else
217 error = EINVAL;
218 break;
219 case SIOCGIPST :
220 IWCOPY((caddr_t)fr_statetstats(), data, sizeof(ips_stat_t));
221 break;
222 case FIONREAD :
223#if IPFILTER_LOG
224 IWCOPY((caddr_t)&iplused[IPL_LOGSTATE], (caddr_t)data,
225 sizeof(iplused[IPL_LOGSTATE]));
226#endif
227 break;
228 default :
229 return EINVAL;
230 }
231 return error;
232}
233
234
235/*
236 * Create a new ipstate structure and hang it off the hash table.
237 */
238int fr_addstate(ip, fin, pass)
239ip_t *ip;
240fr_info_t *fin;
241u_int pass;
242{
243 ipstate_t ips;
244 register ipstate_t *is = &ips;
245 register u_int hv;
246
247 if ((ip->ip_off & 0x1fff) || (fin->fin_fi.fi_fl & FI_SHORT))
248 return -1;
249 if (ips_num == IPSTATE_MAX) {
250 ips_stats.iss_max++;
251 return -1;
252 }
253 ips.is_age = 1;
254 ips.is_state[0] = 0;
255 ips.is_state[1] = 0;
256 /*
257 * Copy and calculate...
258 */
259 hv = (is->is_p = ip->ip_p);
260 hv += (is->is_src.s_addr = ip->ip_src.s_addr);
261 hv += (is->is_dst.s_addr = ip->ip_dst.s_addr);
262
263 switch (ip->ip_p)
264 {
265 case IPPROTO_ICMP :
266 {
267 struct icmp *ic = (struct icmp *)fin->fin_dp;
268
269 switch (ic->icmp_type)
270 {
271 case ICMP_ECHO :
272 is->is_icmp.ics_type = ICMP_ECHOREPLY; /* XXX */
273 hv += (is->is_icmp.ics_id = ic->icmp_id);
274 hv += (is->is_icmp.ics_seq = ic->icmp_seq);
275 break;
276 case ICMP_TSTAMP :
277 case ICMP_IREQ :
278 case ICMP_MASKREQ :
279 is->is_icmp.ics_type = ic->icmp_type + 1;
280 break;
281 default :
282 return -1;
283 }
284 ips_stats.iss_icmp++;
285 is->is_age = fr_icmptimeout;
286 break;
287 }
288 case IPPROTO_TCP :
289 {
290 register tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp;
291
292 /*
293 * The endian of the ports doesn't matter, but the ack and
294 * sequence numbers do as we do mathematics on them later.
295 */
296 hv += (is->is_dport = tcp->th_dport);
297 hv += (is->is_sport = tcp->th_sport);
298 is->is_seq = ntohl(tcp->th_seq);
299 is->is_ack = ntohl(tcp->th_ack);
300 is->is_swin = ntohs(tcp->th_win);
301 is->is_dwin = is->is_swin; /* start them the same */
302 ips_stats.iss_tcp++;
303 /*
304 * If we're creating state for a starting connection, start the
305 * timer on it as we'll never see an error if it fails to
306 * connect.
307 */
308 if ((tcp->th_flags & (TH_SYN|TH_ACK)) == TH_SYN)
309 is->is_ack = 0; /* Trumpet WinSock 'ism */
310 fr_tcp_age(&is->is_age, is->is_state, ip, fin,
311 tcp->th_sport == is->is_sport);
312 break;
313 }
314 case IPPROTO_UDP :
315 {
316 register tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp;
317
318 hv += (is->is_dport = tcp->th_dport);
319 hv += (is->is_sport = tcp->th_sport);
320 ips_stats.iss_udp++;
321 is->is_age = fr_udptimeout;
322 break;
323 }
324 default :
325 return -1;
326 }
327
328 KMALLOC(is, ipstate_t *, sizeof(*is));
329 if (is == NULL) {
330 ips_stats.iss_nomem++;
331 return -1;
332 }
333 bcopy((char *)&ips, (char *)is, sizeof(*is));
334 hv %= IPSTATE_SIZE;
335 MUTEX_ENTER(&ipf_state);
336
337 is->is_pass = pass;
338 is->is_pkts = 1;
339 is->is_bytes = ip->ip_len;
340 /*
341 * Copy these from the rule itself.
342 */
343 is->is_opt = fin->fin_fr->fr_ip.fi_optmsk;
344 is->is_optmsk = fin->fin_fr->fr_mip.fi_optmsk;
345 is->is_sec = fin->fin_fr->fr_ip.fi_secmsk;
346 is->is_secmsk = fin->fin_fr->fr_mip.fi_secmsk;
347 is->is_auth = fin->fin_fr->fr_ip.fi_auth;
348 is->is_authmsk = fin->fin_fr->fr_mip.fi_auth;
349 is->is_flags = fin->fin_fr->fr_ip.fi_fl;
350 is->is_flags |= fin->fin_fr->fr_mip.fi_fl << 4;
351 /*
352 * add into table.
353 */
354 is->is_next = ips_table[hv];
355 ips_table[hv] = is;
356 if (fin->fin_out) {
357 is->is_ifpin = NULL;
358 is->is_ifpout = fin->fin_ifp;
359 } else {
360 is->is_ifpin = fin->fin_ifp;
361 is->is_ifpout = NULL;
362 }
363 if (pass & FR_LOGFIRST)
364 is->is_pass &= ~(FR_LOGFIRST|FR_LOG);
365 ips_num++;
366#if IPFILTER_LOG
367 ipstate_log(is, ISL_NEW);
368#endif
369 MUTEX_EXIT(&ipf_state);
370 if (fin->fin_fi.fi_fl & FI_FRAG)
371 ipfr_newfrag(ip, fin, pass ^ FR_KEEPSTATE);
372 return 0;
373}
374
375
376/*
377 * check to see if a packet with TCP headers fits within the TCP window.
378 * change timeout depending on whether new packet is a SYN-ACK returning for a
379 * SYN or a RST or FIN which indicate time to close up shop.
380 */
381int fr_tcpstate(is, fin, ip, tcp)
382register ipstate_t *is;
383fr_info_t *fin;
384ip_t *ip;
385tcphdr_t *tcp;
386{
387 register int seqskew, ackskew;
388 register u_short swin, dwin;
389 register tcp_seq seq, ack;
390 int source;
391
392 /*
393 * Find difference between last checked packet and this packet.
394 */
395 seq = ntohl(tcp->th_seq);
396 ack = ntohl(tcp->th_ack);
397 source = (ip->ip_src.s_addr == is->is_src.s_addr);
398
399 if (!(tcp->th_flags & TH_ACK)) /* Pretend an ack was sent */
400 ack = source ? is->is_ack : is->is_seq;
401
402 if (source) {
403 if (!is->is_seq)
404 /*
405 * Must be an outgoing SYN-ACK in reply to a SYN.
406 */
407 is->is_seq = seq;
408 seqskew = seq - is->is_seq;
409 ackskew = ack - is->is_ack;
410 } else {
411 if (!is->is_ack)
412 /*
413 * Must be a SYN-ACK in reply to a SYN.
414 */
415 is->is_ack = seq;
416 ackskew = seq - is->is_ack;
417 seqskew = ack - is->is_seq;
418 }
419
420 /*
421 * Make skew values absolute
422 */
423 if (seqskew < 0)
424 seqskew = -seqskew;
425 if (ackskew < 0)
426 ackskew = -ackskew;
427
428 /*
429 * If the difference in sequence and ack numbers is within the
430 * window size of the connection, store these values and match
431 * the packet.
432 */
433 if (source) {
434 swin = is->is_swin;
435 dwin = is->is_dwin;
436 } else {
437 dwin = is->is_swin;
438 swin = is->is_dwin;
439 }
440
441 if ((seqskew <= dwin) && (ackskew <= swin)) {
442 if (source) {
443 is->is_seq = seq;
444 is->is_ack = ack;
445 is->is_swin = ntohs(tcp->th_win);
446 } else {
447 is->is_seq = ack;
448 is->is_ack = seq;
449 is->is_dwin = ntohs(tcp->th_win);
450 }
451 ips_stats.iss_hits++;
452 is->is_pkts++;
453 is->is_bytes += ip->ip_len;
454 /*
455 * Nearing end of connection, start timeout.
456 */
457 fr_tcp_age(&is->is_age, is->is_state, ip, fin, source);
458 return 1;
459 }
460 return 0;
461}
462
463
464static int fr_matchsrcdst(is, src, dst, fin, tcp, sp, dp)
465ipstate_t *is;
466struct in_addr src, dst;
467fr_info_t *fin;
468void *tcp;
469u_short sp, dp;
470{
471 int ret = 0, rev, out;
472 void *ifp;
473
474 rev = (is->is_dst.s_addr != dst.s_addr);
475 ifp = fin->fin_ifp;
476 out = fin->fin_out;
477
478 if (!rev) {
479 if (out) {
480 if (!is->is_ifpout)
481 is->is_ifpout = ifp;
482 } else {
483 if (!is->is_ifpin)
484 is->is_ifpin = ifp;
485 }
486 } else {
487 if (out) {
488 if (!is->is_ifpin)
489 is->is_ifpin = ifp;
490 } else {
491 if (!is->is_ifpout)
492 is->is_ifpout = ifp;
493 }
494 }
495
496 if (!rev) {
497 if (((out && is->is_ifpout == ifp) ||
498 (!out && is->is_ifpin == ifp)) &&
499 (is->is_dst.s_addr == dst.s_addr) &&
500 (is->is_src.s_addr == src.s_addr) &&
501 (!tcp || (sp == is->is_sport) &&
502 (dp == is->is_dport))) {
503 ret = 1;
504 }
505 } else {
506 if (((out && is->is_ifpin == ifp) ||
507 (!out && is->is_ifpout == ifp)) &&
508 (is->is_dst.s_addr == src.s_addr) &&
509 (is->is_src.s_addr == dst.s_addr) &&
510 (!tcp || (sp == is->is_dport) &&
511 (dp == is->is_sport))) {
512 ret = 1;
513 }
514 }
515
516 /*
517 * Whether or not this should be here, is questionable, but the aim
518 * is to get this out of the main line.
519 */
520 if (ret) {
521 if (((fin->fin_fi.fi_optmsk & is->is_optmsk) != is->is_opt) ||
522 ((fin->fin_fi.fi_secmsk & is->is_secmsk) != is->is_sec) ||
523 ((fin->fin_fi.fi_auth & is->is_authmsk) != is->is_auth) ||
524 ((fin->fin_fi.fi_fl & (is->is_flags >> 4)) !=
525 (is->is_flags & 0xf)))
526 ret = 0;
527 }
528 return ret;
529}
530
531
532/*
533 * Check if a packet has a registered state.
534 */
535int fr_checkstate(ip, fin)
536ip_t *ip;
537fr_info_t *fin;
538{
539 register struct in_addr dst, src;
540 register ipstate_t *is, **isp;
541 register u_char pr;
542 struct icmp *ic;
543 tcphdr_t *tcp;
544 u_int hv, hlen, pass;
545
546 if ((ip->ip_off & 0x1fff) || (fin->fin_fi.fi_fl & FI_SHORT))
547 return 0;
548
549 hlen = fin->fin_hlen;
550 tcp = (tcphdr_t *)((char *)ip + hlen);
551 ic = (struct icmp *)tcp;
552 hv = (pr = ip->ip_p);
553 hv += (src.s_addr = ip->ip_src.s_addr);
554 hv += (dst.s_addr = ip->ip_dst.s_addr);
555
556 /*
557 * Search the hash table for matching packet header info.
558 */
559 switch (ip->ip_p)
560 {
561 case IPPROTO_ICMP :
562 hv += ic->icmp_id;
563 hv += ic->icmp_seq;
564 hv %= IPSTATE_SIZE;
565 MUTEX_ENTER(&ipf_state);
566 for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next)
567 if ((is->is_p == pr) &&
568 (ic->icmp_id == is->is_icmp.ics_id) &&
569 (ic->icmp_seq == is->is_icmp.ics_seq) &&
570 fr_matchsrcdst(is, src, dst, fin, NULL, 0, 0)) {
571 if (is->is_icmp.ics_type != ic->icmp_type)
572 continue;
573 is->is_age = fr_icmptimeout;
574 is->is_pkts++;
575 is->is_bytes += ip->ip_len;
576 ips_stats.iss_hits++;
577 pass = is->is_pass;
578 MUTEX_EXIT(&ipf_state);
579 return pass;
580 }
581 MUTEX_EXIT(&ipf_state);
582 break;
583 case IPPROTO_TCP :
584 {
585 register u_short dport = tcp->th_dport, sport = tcp->th_sport;
586
587 hv += dport;
588 hv += sport;
589 hv %= IPSTATE_SIZE;
590 MUTEX_ENTER(&ipf_state);
591 for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next)
592 if ((is->is_p == pr) &&
593 fr_matchsrcdst(is, src, dst, fin, tcp,
594 sport, dport)) {
595 if (fr_tcpstate(is, fin, ip, tcp)) {
596 pass = is->is_pass;
597#ifdef _KERNEL
598 MUTEX_EXIT(&ipf_state);
599#else
600
601 if (tcp->th_flags & TCP_CLOSE) {
602 *isp = is->is_next;
603 isp = &ips_table[hv];
604 KFREE(is);
605 }
606#endif
607 return pass;
608 }
609 }
610 MUTEX_EXIT(&ipf_state);
611 break;
612 }
613 case IPPROTO_UDP :
614 {
615 register u_short dport = tcp->th_dport, sport = tcp->th_sport;
616
617 hv += dport;
618 hv += sport;
619 hv %= IPSTATE_SIZE;
620 /*
621 * Nothing else to match on but ports. and IP#'s
622 */
623 MUTEX_ENTER(&ipf_state);
624 for (is = ips_table[hv]; is; is = is->is_next)
625 if ((is->is_p == pr) &&
626 fr_matchsrcdst(is, src, dst, fin,
627 tcp, sport, dport)) {
628 ips_stats.iss_hits++;
629 is->is_pkts++;
630 is->is_bytes += ip->ip_len;
631 is->is_age = fr_udptimeout;
632 pass = is->is_pass;
633 MUTEX_EXIT(&ipf_state);
634 return pass;
635 }
636 MUTEX_EXIT(&ipf_state);
637 break;
638 }
639 default :
640 break;
641 }
642 ips_stats.iss_miss++;
643 return 0;
644}
645
646
647/*
648 * Free memory in use by all state info. kept.
649 */
650void fr_stateunload()
651{
652 register int i;
653 register ipstate_t *is, **isp;
654
655 MUTEX_ENTER(&ipf_state);
656 for (i = 0; i < IPSTATE_SIZE; i++)
657 for (isp = &ips_table[i]; (is = *isp); ) {
658 *isp = is->is_next;
659 KFREE(is);
660 }
661 MUTEX_EXIT(&ipf_state);
662}
663
664
665/*
666 * Slowly expire held state for thingslike UDP and ICMP. Timeouts are set
667 * in expectation of this being called twice per second.
668 */
669void fr_timeoutstate()
670{
671 register int i;
672 register ipstate_t *is, **isp;
673#if defined(_KERNEL) && !SOLARIS
674 int s;
675#endif
676
677 SPL_NET(s);
678 MUTEX_ENTER(&ipf_state);
679 for (i = 0; i < IPSTATE_SIZE; i++)
680 for (isp = &ips_table[i]; (is = *isp); )
681 if (is->is_age && !--is->is_age) {
682 *isp = is->is_next;
683 if (is->is_p == IPPROTO_TCP)
684 ips_stats.iss_fin++;
685 else
686 ips_stats.iss_expire++;
687#if IPFILTER_LOG
688 ipstate_log(is, ISL_EXPIRE);
689#endif
690 KFREE(is);
691 ips_num--;
692 } else
693 isp = &is->is_next;
694 MUTEX_EXIT(&ipf_state);
695 SPL_X(s);
696}
697
698
699/*
700 * Original idea freom Pradeep Krishnan for use primarily with NAT code.
701 * (pkrishna@netcom.com)
702 */
703void fr_tcp_age(age, state, ip, fin, dir)
704u_long *age;
705u_char *state;
706ip_t *ip;
707fr_info_t *fin;
708int dir;
709{
710 tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp;
711 u_char flags = tcp->th_flags;
712 int dlen, ostate;
713
714 ostate = state[1 - dir];
715
716 dlen = ip->ip_len - fin->fin_hlen - (tcp->th_off << 2);
717
718 if (flags & TH_RST) {
719 if (!(tcp->th_flags & TH_PUSH) && !dlen) {
720 *age = fr_tcpclosed;
721 state[dir] = TCPS_CLOSED;
722 } else {
723 *age = fr_tcpclosewait;
724 state[dir] = TCPS_CLOSE_WAIT;
725 }
726 return;
727 }
728
729 *age = fr_tcptimeout; /* 1 min */
730
731 switch(state[dir])
732 {
733 case TCPS_FIN_WAIT_2:
734 case TCPS_CLOSED:
735 if ((flags & TH_OPENING) == TH_OPENING)
736 state[dir] = TCPS_SYN_RECEIVED;
737 else if (flags & TH_SYN)
738 state[dir] = TCPS_SYN_SENT;
739 break;
740 case TCPS_SYN_RECEIVED:
741 if ((flags & (TH_FIN|TH_ACK)) == TH_ACK) {
742 state[dir] = TCPS_ESTABLISHED;
743 current_active_connections++;
744 *age = fr_tcpidletimeout;
745 }
746 break;
747 case TCPS_SYN_SENT:
748 if ((flags & (TH_FIN|TH_ACK)) == TH_ACK) {
749 state[dir] = TCPS_ESTABLISHED;
750 current_active_connections++;
751 *age = fr_tcpidletimeout;
752 }
753 break;
754 case TCPS_ESTABLISHED:
755 if (flags & TH_FIN) {
756 state[dir] = TCPS_CLOSE_WAIT;
757 if (!(flags & TH_PUSH) && !dlen &&
758 ostate > TCPS_ESTABLISHED)
759 *age = fr_tcplastack;
760 else
761 *age = fr_tcpclosewait;
762 } else
763 *age = fr_tcpidletimeout;
764 break;
765 case TCPS_CLOSE_WAIT:
766 if ((flags & TH_FIN) && !(flags & TH_PUSH) && !dlen &&
767 ostate > TCPS_ESTABLISHED) {
768 *age = fr_tcplastack;
769 state[dir] = TCPS_LAST_ACK;
770 } else
771 *age = fr_tcpclosewait;
772 break;
773 case TCPS_LAST_ACK:
774 if (flags & TH_ACK) {
775 state[dir] = TCPS_FIN_WAIT_2;
776 if (!(flags & TH_PUSH) && !dlen &&
777 ostate > TCPS_ESTABLISHED)
778 *age = fr_tcplastack;
779 else {
780 *age = fr_tcpclosewait;
781 state[dir] = TCPS_CLOSE_WAIT;
782 }
783 }
784 break;
785 }
786}
787
788
789#if IPFILTER_LOG
790void ipstate_log(is, type)
791struct ipstate *is;
792u_short type;
793{
794 struct ipslog ipsl;
795 void *items[1];
796 size_t sizes[1];
797 int types[1];
798
799 ipsl.isl_pkts = is->is_pkts;
800 ipsl.isl_bytes = is->is_bytes;
801 ipsl.isl_src = is->is_src;
802 ipsl.isl_dst = is->is_dst;
803 ipsl.isl_p = is->is_p;
804 ipsl.isl_flags = is->is_flags;
805 ipsl.isl_type = type;
806 if (ipsl.isl_p == IPPROTO_TCP || ipsl.isl_p == IPPROTO_UDP) {
807 ipsl.isl_sport = is->is_sport;
808 ipsl.isl_dport = is->is_dport;
809 } else if (ipsl.isl_p == IPPROTO_ICMP)
810 ipsl.isl_itype = is->is_icmp.ics_type;
811 else {
812 ipsl.isl_ps.isl_filler[0] = 0;
813 ipsl.isl_ps.isl_filler[1] = 0;
814 }
815 items[0] = &ipsl;
816 sizes[0] = sizeof(ipsl);
817 types[0] = 0;
818
819 (void) ipllog(IPL_LOGSTATE, 0, items, sizes, types, 1);
820}
821#endif