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