Deleted Added
sdiff udiff text old ( 89336 ) new ( 92685 )
full compact
1/*
2 * Copyright (C) 1995-2002 by Darren Reed.
3 *
4 * See the IPFILTER.LICENCE file for details on licencing.
5 */
6
7#ifdef __sgi
8# include <sys/ptimers.h>
9#endif
10#include <sys/errno.h>
11#include <sys/types.h>
12#include <sys/param.h>
13#include <sys/file.h>
14#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
15 defined(_KERNEL)
16# include "opt_ipfilter_log.h"
17#endif

--- 16 unchanged lines hidden (view full) ---

34# include <sys/fcntl.h>
35# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM)
36# include "opt_ipfilter.h"
37# endif
38#else
39# include <sys/ioctl.h>
40#endif
41#include <sys/time.h>
42#ifndef linux
43# include <sys/protosw.h>
44#endif
45#include <sys/socket.h>
46#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux)
47# include <sys/systm.h>
48#endif
49#if !defined(__SVR4) && !defined(__svr4__)

--- 25 unchanged lines hidden (view full) ---

75#endif
76#include <netinet/udp.h>
77#include <netinet/ip_icmp.h>
78#include "netinet/ip_compat.h"
79#include <netinet/tcpip.h>
80#include "netinet/ip_fil.h"
81#include "netinet/ip_nat.h"
82#include "netinet/ip_frag.h"
83#include "netinet/ip_state.h"
84#ifdef USE_INET6
85#include <netinet/icmp6.h>
86#endif
87#if (__FreeBSD_version >= 300000)
88# include <sys/malloc.h>
89# if (defined(_KERNEL) || defined(KERNEL)) && !defined(IPFILTER_LKM)
90# include <sys/libkern.h>
91# include <sys/systm.h>
92# endif
93#endif
94
95#if !defined(lint)
96static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed";
97/* static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.38 2001/07/23 13:49:46 darrenr Exp $"; */
98static const char rcsid[] = "@(#)$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_state.c 92685 2002-03-19 11:44:16Z darrenr $";
99#endif
100
101#ifndef MIN
102# define MIN(a,b) (((a)<(b))?(a):(b))
103#endif
104
105#define TCP_CLOSE (TH_FIN|TH_RST)
106
107static ipstate_t **ips_table = NULL;
108static int ips_num = 0;
109static int ips_wild = 0;
110static ips_stat_t ips_stats;
111#if (SOLARIS || defined(__sgi)) && defined(_KERNEL)
112extern KRWLOCK_T ipf_state, ipf_mutex;
113extern kmutex_t ipf_rw;
114#endif
115

--- 26 unchanged lines hidden (view full) ---

142 fr_udptimeout = 240,
143 fr_udpacktimeout = 24,
144 fr_icmptimeout = 120,
145 fr_icmpacktimeout = 12;
146int fr_statemax = IPSTATE_MAX,
147 fr_statesize = IPSTATE_SIZE;
148int fr_state_doflush = 0,
149 fr_state_lock = 0;
150ipstate_t *ips_list = NULL;
151
152static int icmpreplytype4[ICMP_MAXTYPE + 1];
153#ifdef USE_INET6
154static int icmpreplytype6[ICMP6_MAXTYPE + 1];
155#endif
156
157int fr_stateinit()
158{
159 int i;
160
161 KMALLOCS(ips_table, ipstate_t **, fr_statesize * sizeof(ipstate_t *));
162 if (ips_table != NULL)
163 bzero((char *)ips_table, fr_statesize * sizeof(ipstate_t *));
164 else
165 return -1;
166
167 /* fill icmp reply type table */
168 for (i = 0; i <= ICMP_MAXTYPE; i++)
169 icmpreplytype4[i] = -1;
170 icmpreplytype4[ICMP_ECHO] = ICMP_ECHOREPLY;
171 icmpreplytype4[ICMP_TSTAMP] = ICMP_TSTAMPREPLY;
172 icmpreplytype4[ICMP_IREQ] = ICMP_IREQREPLY;
173 icmpreplytype4[ICMP_MASKREQ] = ICMP_MASKREPLY;
174#ifdef USE_INET6
175 /* fill icmp reply type table */
176 for (i = 0; i <= ICMP6_MAXTYPE; i++)
177 icmpreplytype6[i] = -1;
178 icmpreplytype6[ICMP6_ECHO_REQUEST] = ICMP6_ECHO_REPLY;
179 icmpreplytype6[ICMP6_MEMBERSHIP_QUERY] = ICMP6_MEMBERSHIP_REPORT;
180 icmpreplytype6[ICMP6_NI_QUERY] = ICMP6_NI_REPLY;
181 icmpreplytype6[ND_ROUTER_SOLICIT] = ND_ROUTER_ADVERT;
182 icmpreplytype6[ND_NEIGHBOR_SOLICIT] = ND_NEIGHBOR_ADVERT;
183#endif
184
185 return 0;
186}
187
188
189static ips_stat_t *fr_statetstats()
190{
191 ips_stats.iss_active = ips_num;
192 ips_stats.iss_table = ips_table;
193 ips_stats.iss_list = ips_list;
194 return &ips_stats;
195}
196
197
198/*
199 * flush state tables. two actions currently defined:
200 * which == 0 : flush all state table entries
201 * which == 1 : flush TCP connections which have started to close but are
202 * stuck for some reason.
203 * which == 2 : flush TCP connections which have been idle for a long time,
204 * starting at > 4 days idle and working back in successive half-
205 * days to at most 12 hours old.
206 */
207static int fr_state_flush(which)
208int which;
209{
210 ipstate_t *is, **isp;
211#if defined(_KERNEL) && !SOLARIS
212 int s;
213#endif
214 int delete, removed = 0, try;
215
216 SPL_NET(s);
217 for (isp = &ips_list; (is = *isp); ) {
218 delete = 0;
219
220 switch (which)
221 {
222 case 0 :
223 delete = 1;
224 break;
225 case 1 :
226 case 2 :
227 if (is->is_p != IPPROTO_TCP)
228 break;
229 if ((is->is_state[0] != TCPS_ESTABLISHED) ||
230 (is->is_state[1] != TCPS_ESTABLISHED))
231 delete = 1;
232 break;
233 }
234

--- 5 unchanged lines hidden (view full) ---

240#ifdef IPFILTER_LOG
241 ipstate_log(is, ISL_FLUSH);
242#endif
243 fr_delstate(is);
244 removed++;
245 } else
246 isp = &is->is_next;
247 }
248
249 /*
250 * Asked to remove inactive entries, try again if first attempt
251 * failed. In this case, 86400 is half a day because the counter is
252 * activated every half second.
253 */
254 if ((which == 2) && (removed == 0)) {
255 try = 86400; /* half a day */
256 for (; (try < FIVE_DAYS) && (removed == 0); try += 86400) {
257 for (isp = &ips_list; (is = *isp); ) {
258 delete = 0;
259 if ((is->is_p == IPPROTO_TCP) &&
260 ((is->is_state[0] == TCPS_ESTABLISHED) ||
261 (is->is_state[1] == TCPS_ESTABLISHED)) &&
262 (is->is_age < try)) {
263 ips_stats.iss_fin++;
264 delete = 1;
265 } else if ((is->is_p != IPPROTO_TCP) &&
266 (is->is_pkts > 1)) {
267 ips_stats.iss_expire++;
268 delete = 1;
269 }
270 if (delete) {
271#ifdef IPFILTER_LOG
272 ipstate_log(is, ISL_FLUSH);
273#endif
274 fr_delstate(is);
275 removed++;
276 } else
277 isp = &is->is_next;
278 }
279 }
280 }
281
282 SPL_X(s);
283 return removed;
284}
285
286
287static int fr_state_remove(data)
288caddr_t data;
289{

--- 96 unchanged lines hidden (view full) ---

386 default :
387 error = EINVAL;
388 break;
389 }
390 return error;
391}
392
393
394/*
395 * Copy out state information from the kernel to a user space process.
396 */
397int fr_stgetent(data)
398caddr_t data;
399{
400 register ipstate_t *is, *isn;
401 ipstate_save_t ips;
402 int error;
403
404 error = IRCOPYPTR(data, (caddr_t)&ips, sizeof(ips));
405 if (error)
406 return error;
407
408 isn = ips.ips_next;
409 if (!isn) {
410 isn = ips_list;
411 if (isn == NULL) {
412 if (ips.ips_next == NULL)
413 return ENOENT;
414 return 0;

--- 10 unchanged lines hidden (view full) ---

425 if (!is)
426 return ESRCH;
427 }
428 ips.ips_next = isn->is_next;
429 bcopy((char *)isn, (char *)&ips.ips_is, sizeof(ips.ips_is));
430 if (isn->is_rule)
431 bcopy((char *)isn->is_rule, (char *)&ips.ips_fr,
432 sizeof(ips.ips_fr));
433 error = IWCOPYPTR((caddr_t)&ips, data, sizeof(ips));
434 if (error)
435 error = EFAULT;
436 return error;
437}
438
439
440int fr_stputent(data)
441caddr_t data;
442{
443 register ipstate_t *is, *isn;
444 ipstate_save_t ips;
445 int error, out, i;
446 frentry_t *fr;
447 char *name;
448
449 error = IRCOPYPTR(data, (caddr_t)&ips, sizeof(ips));
450 if (error)
451 return error;
452
453 KMALLOC(isn, ipstate_t *);
454 if (isn == NULL)
455 return ENOMEM;
456
457 bcopy((char *)&ips.ips_is, (char *)isn, sizeof(*isn));
458 fr = isn->is_rule;
459 if (fr != NULL) {
460 if (isn->is_flags & FI_NEWFR) {
461 KMALLOC(fr, frentry_t *);
462 if (fr == NULL) {
463 KFREE(isn);
464 return ENOMEM;
465 }
466 bcopy((char *)&ips.ips_fr, (char *)fr, sizeof(*fr));
467 out = fr->fr_flags & FR_OUTQUE ? 1 : 0;
468 isn->is_rule = fr;
469 ips.ips_is.is_rule = fr;
470
471 /*
472 * Look up all the interface names in the rule.
473 */
474 for (i = 0; i < 4; i++) {
475 name = fr->fr_ifnames[i];
476 if ((name[1] == '\0') &&
477 ((name[0] == '-') || (name[0] == '*'))) {
478 fr->fr_ifas[i] = NULL;
479 } else if (*name != '\0') {
480 fr->fr_ifas[i] = GETUNIT(name,
481 fr->fr_v);
482 if (fr->fr_ifas[i] == NULL)
483 fr->fr_ifas[i] = (void *)-1;
484 else {
485 strncpy(isn->is_ifname[i],
486 IFNAME(fr->fr_ifas[i]),
487 IFNAMSIZ);
488 }
489 }
490 isn->is_ifp[out] = fr->fr_ifas[i];
491 }
492
493 /*
494 * send a copy back to userland of what we ended up
495 * to allow for verification.
496 */
497 error = IWCOPYPTR((caddr_t)&ips, data, sizeof(ips));
498 if (error) {
499 KFREE(isn);
500 KFREE(fr);
501 return EFAULT;
502 }
503 } else {
504 for (is = ips_list; is; is = is->is_next)
505 if (is->is_rule == fr)

--- 4 unchanged lines hidden (view full) ---

510 }
511 }
512 }
513 fr_stinsert(isn);
514 return 0;
515}
516
517
518/*
519 * Insert a state table entry manually.
520 */
521void fr_stinsert(is)
522register ipstate_t *is;
523{
524 register u_int hv = is->is_hv;
525 char *name;
526 int i;
527
528 MUTEX_INIT(&is->is_lock, "ipf state entry", NULL);
529
530 /*
531 * Look up all the interface names in the state entry.
532 */
533 for (i = 0; i < 4; i++) {
534 name = is->is_ifname[i];
535 if ((name[1] == '\0') &&
536 ((name[0] == '-') || (name[0] == '*'))) {
537 is->is_ifp[0] = NULL;
538 } else if (*name != '\0') {
539 is->is_ifp[i] = GETUNIT(name, is->is_v);
540 if (is->is_ifp[i] == NULL)
541 is->is_ifp[i] = (void *)-1;
542 }
543 }
544
545
546 /*
547 * add into list table.
548 */
549 if (ips_list)
550 ips_list->is_pnext = &is->is_next;
551 is->is_pnext = &ips_list;
552 is->is_next = ips_list;
553 ips_list = is;

--- 6 unchanged lines hidden (view full) ---

560 ips_table[hv] = is;
561 ips_num++;
562}
563
564
565/*
566 * Create a new ipstate structure and hang it off the hash table.
567 */
568ipstate_t *fr_addstate(ip, fin, stsave, flags)
569ip_t *ip;
570fr_info_t *fin;
571ipstate_t **stsave;
572u_int flags;
573{
574 register tcphdr_t *tcp = NULL;
575 register ipstate_t *is;
576 register u_int hv;
577 struct icmp *ic;
578 ipstate_t ips;
579 u_int pass;
580 void *ifp;
581 int out;
582
583 if (fr_state_lock || (fin->fin_off != 0) || (fin->fin_fl & FI_SHORT))
584 return NULL;
585 if (ips_num == fr_statemax) {
586 ips_stats.iss_max++;
587 fr_state_doflush = 1;
588 return NULL;
589 }
590 out = fin->fin_out;
591 is = &ips;
592 bzero((char *)is, sizeof(*is));
593 ips.is_age = 1;
594 /*
595 * Copy and calculate...
596 */
597 hv = (is->is_p = fin->fin_fi.fi_p);
598 is->is_src = fin->fin_fi.fi_src;
599 hv += is->is_saddr;
600 is->is_dst = fin->fin_fi.fi_dst;
601 hv += is->is_daddr;
602#ifdef USE_INET6
603 if (fin->fin_v == 6) {
604 if ((is->is_p == IPPROTO_ICMPV6) &&
605 IN6_IS_ADDR_MULTICAST(&is->is_dst.in6)) {
606 /*
607 * So you can do keep state with neighbour discovery.
608 */
609 flags |= FI_W_DADDR;
610 hv -= is->is_daddr;
611 } else {
612 hv += is->is_dst.i6[1];
613 hv += is->is_dst.i6[2];
614 hv += is->is_dst.i6[3];
615 }
616 hv += is->is_src.i6[1];
617 hv += is->is_src.i6[2];
618 hv += is->is_src.i6[3];
619 }
620#endif
621
622 switch (is->is_p)
623 {
624#ifdef USE_INET6
625 case IPPROTO_ICMPV6 :
626 ic = (struct icmp *)fin->fin_dp;
627 if ((ic->icmp_type & ICMP6_INFOMSG_MASK) == 0)
628 return NULL;
629
630 switch (ic->icmp_type)
631 {
632 case ICMP6_ECHO_REQUEST :
633 is->is_icmp.ics_type = ic->icmp_type;
634 hv += (is->is_icmp.ics_id = ic->icmp_id);
635 hv += (is->is_icmp.ics_seq = ic->icmp_seq);
636 break;
637 case ICMP6_MEMBERSHIP_QUERY :
638 case ND_ROUTER_SOLICIT :
639 case ND_NEIGHBOR_SOLICIT :
640 case ICMP6_NI_QUERY :
641 is->is_icmp.ics_type = ic->icmp_type;
642 break;
643 default :
644 return NULL;
645 }
646 ATOMIC_INCL(ips_stats.iss_icmp);
647 is->is_age = fr_icmptimeout;
648 break;
649#endif
650 case IPPROTO_ICMP :
651 ic = (struct icmp *)fin->fin_dp;
652
653 switch (ic->icmp_type)
654 {
655 case ICMP_ECHO :
656 case ICMP_TSTAMP :
657 case ICMP_IREQ :
658 case ICMP_MASKREQ :
659 is->is_icmp.ics_type = ic->icmp_type;
660 hv += (is->is_icmp.ics_id = ic->icmp_id);
661 hv += (is->is_icmp.ics_seq = ic->icmp_seq);
662 break;
663 default :
664 return NULL;
665 }
666 ATOMIC_INCL(ips_stats.iss_icmp);
667 is->is_age = fr_icmptimeout;
668 break;
669 case IPPROTO_TCP :
670 tcp = (tcphdr_t *)fin->fin_dp;
671
672 if (tcp->th_flags & TH_RST)
673 return NULL;
674 /*
675 * The endian of the ports doesn't matter, but the ack and
676 * sequence numbers do as we do mathematics on them later.
677 */
678 is->is_sport = htons(fin->fin_data[0]);
679 is->is_dport = htons(fin->fin_data[1]);
680 if ((flags & (FI_W_DPORT|FI_W_SPORT)) == 0) {
681 hv += is->is_sport;
682 hv += is->is_dport;
683 }
684 is->is_send = ntohl(tcp->th_seq) + fin->fin_dlen -
685 (tcp->th_off << 2) +
686 ((tcp->th_flags & TH_SYN) ? 1 : 0) +
687 ((tcp->th_flags & TH_FIN) ? 1 : 0);
688 is->is_maxsend = is->is_send;
689 is->is_dend = 0;
690 is->is_maxdwin = 1;
691 is->is_maxswin = ntohs(tcp->th_win);
692 if (is->is_maxswin == 0)
693 is->is_maxswin = 1;
694 /*
695 * If we're creating state for a starting connection, start the
696 * timer on it as we'll never see an error if it fails to
697 * connect.
698 */
699 ATOMIC_INCL(ips_stats.iss_tcp);
700 break;
701
702 case IPPROTO_UDP :
703 tcp = (tcphdr_t *)fin->fin_dp;
704
705 is->is_sport = htons(fin->fin_data[0]);
706 is->is_dport = htons(fin->fin_data[1]);
707 if ((flags & (FI_W_DPORT|FI_W_SPORT)) == 0) {
708 hv += is->is_sport;
709 hv += is->is_dport;
710 }
711 ATOMIC_INCL(ips_stats.iss_udp);
712 is->is_age = fr_udptimeout;
713 break;
714 default :
715 is->is_age = fr_udptimeout;
716 break;
717 }
718
719 KMALLOC(is, ipstate_t *);
720 if (is == NULL) {
721 ATOMIC_INCL(ips_stats.iss_nomem);
722 return NULL;
723 }
724 bcopy((char *)&ips, (char *)is, sizeof(*is));
725 hv %= fr_statesize;
726 is->is_hv = hv;
727 is->is_rule = fin->fin_fr;
728 if (is->is_rule != NULL) {
729 ATOMIC_INC32(is->is_rule->fr_ref);
730 pass = is->is_rule->fr_flags;
731 is->is_frage[0] = is->is_rule->fr_age[0];
732 is->is_frage[1] = is->is_rule->fr_age[1];
733 if (is->is_frage[0] != 0)
734 is->is_age = is->is_frage[0];
735
736 is->is_ifp[(out << 1) + 1] = is->is_rule->fr_ifas[1];
737 is->is_ifp[(1 - out) << 1] = is->is_rule->fr_ifas[2];
738 is->is_ifp[((1 - out) << 1) + 1] = is->is_rule->fr_ifas[3];
739
740 if (((ifp = is->is_rule->fr_ifas[1]) != NULL) &&
741 (ifp != (void *)-1))
742 strncpy(is->is_ifname[(out << 1) + 1],
743 IFNAME(ifp), IFNAMSIZ);
744 if (((ifp = is->is_rule->fr_ifas[2]) != NULL) &&
745 (ifp != (void *)-1))
746 strncpy(is->is_ifname[(1 - out) << 1],
747 IFNAME(ifp), IFNAMSIZ);
748 if (((ifp = is->is_rule->fr_ifas[3]) != NULL) &&
749 (ifp != (void *)-1))
750 strncpy(is->is_ifname[((1 - out) << 1) + 1],
751 IFNAME(ifp), IFNAMSIZ);
752 } else
753 pass = fr_flags;
754
755 is->is_ifp[out << 1] = fin->fin_ifp;
756 strncpy(is->is_ifname[out << 1], IFNAME(fin->fin_ifp), IFNAMSIZ);
757
758 WRITE_ENTER(&ipf_state);
759
760 is->is_pass = pass;
761 if ((flags & FI_IGNOREPKT) == 0) {
762 is->is_pkts = 1;
763 is->is_bytes = fin->fin_dlen + fin->fin_hlen;
764 }
765 /*
766 * We want to check everything that is a property of this packet,
767 * but we don't (automatically) care about it's fragment status as
768 * this may change.
769 */
770 is->is_v = fin->fin_v;
771 is->is_rulen = fin->fin_rule;
772 is->is_opt = fin->fin_fi.fi_optmsk;
773 is->is_optmsk = 0xffffffff;
774 is->is_sec = fin->fin_fi.fi_secmsk;
775 is->is_secmsk = 0xffff;
776 is->is_auth = fin->fin_fi.fi_auth;
777 is->is_authmsk = 0xffff;
778 is->is_flags = fin->fin_fl & FI_CMP;
779 is->is_flags |= FI_CMP << 4;
780 is->is_flags |= flags & (FI_WILDP|FI_WILDA);
781 if (flags & (FI_WILDP|FI_WILDA))
782 ips_wild++;
783
784 if (pass & FR_LOGFIRST)
785 is->is_pass &= ~(FR_LOGFIRST|FR_LOG);
786 fr_stinsert(is);
787 is->is_me = stsave;
788 if (is->is_p == IPPROTO_TCP) {
789 fr_tcp_age(&is->is_age, is->is_state, fin,
790 0); /* 0 = packet from the source */
791 }
792#ifdef IPFILTER_LOG
793 ipstate_log(is, ISL_NEW);
794#endif
795 RWLOCK_EXIT(&ipf_state);
796 fin->fin_rev = IP6NEQ(is->is_dst, fin->fin_fi.fi_dst);
797 if ((fin->fin_fi.fi_fl & FI_FRAG) && (pass & FR_KEEPFRAG))
798 ipfr_newfrag(ip, fin, pass ^ FR_KEEPSTATE);

--- 103 unchanged lines hidden (view full) ---

902 fr_tcp_age(&is->is_age, is->is_state, fin, !source);
903 ret = 1;
904 }
905 MUTEX_EXIT(&is->is_lock);
906 return ret;
907}
908
909
910/*
911 * Match a state table entry against an IP packet.
912 */
913static int fr_matchsrcdst(is, src, dst, fin, tcp)
914ipstate_t *is;
915union i6addr src, dst;
916fr_info_t *fin;
917tcphdr_t *tcp;
918{
919 int ret = 0, rev, out, flags, idx;
920 u_short sp, dp;
921 void *ifp;
922
923 rev = IP6NEQ(is->is_dst, dst);
924 ifp = fin->fin_ifp;
925 out = fin->fin_out;
926 flags = is->is_flags & (FI_WILDA|FI_WILDP);
927 sp = 0;
928 dp = 0;
929
930 if (tcp != NULL) {
931 flags = is->is_flags;
932 sp = tcp->th_sport;
933 dp = tcp->th_dport;
934 if (!rev) {
935 if (!(flags & FI_W_SPORT) && (sp != is->is_sport))
936 rev = 1;
937 else if (!(flags & FI_W_DPORT) && (dp != is->is_dport))
938 rev = 1;
939 }
940 }
941
942 idx = (out << 1) + rev;
943
944 if ((is->is_ifp[idx] == NULL &&
945 (*is->is_ifname[idx] == '\0' || *is->is_ifname[idx] == '*')) ||
946 is->is_ifp[idx] == ifp)
947 ret = 1;
948
949 if (ret == 0)
950 return 0;
951 ret = 0;
952
953 if (rev == 0) {
954 if ((IP6EQ(is->is_dst, dst) || (flags & FI_W_DADDR)) &&
955 (IP6EQ(is->is_src, src) || (flags & FI_W_SADDR)) &&
956 (!tcp || ((sp == is->is_sport || flags & FI_W_SPORT) &&
957 (dp == is->is_dport || flags & FI_W_DPORT)))) {
958 ret = 1;
959 }
960 } else {
961 if ((IP6EQ(is->is_dst, src) || (flags & FI_W_DADDR)) &&
962 (IP6EQ(is->is_src, dst) || (flags & FI_W_SADDR)) &&
963 (!tcp || ((sp == is->is_dport || flags & FI_W_DPORT) &&
964 (dp == is->is_sport || flags & FI_W_SPORT)))) {
965 ret = 1;
966 }
967 }
968 if (ret == 0)
969 return 0;

--- 6 unchanged lines hidden (view full) ---

976 flags = is->is_flags & (FI_CMP|(FI_CMP<<4));
977
978 if (((fin->fin_fl & (flags >> 4)) != (flags & FI_CMP)) ||
979 (fin->fin_fi.fi_optmsk != is->is_opt) ||
980 (fin->fin_fi.fi_secmsk != is->is_sec) ||
981 (fin->fin_fi.fi_auth != is->is_auth))
982 return 0;
983
984 flags = is->is_flags & (FI_WILDA|FI_WILDP);
985 if ((flags & (FI_W_SADDR|FI_W_DADDR))) {
986 if ((flags & FI_W_SADDR) != 0) {
987 if (rev == 0) {
988 is->is_src = fin->fin_fi.fi_src;
989 } else {
990 is->is_src = fin->fin_fi.fi_dst;
991 }
992 } else if ((flags & FI_W_DPORT) != 0) {
993 if (rev == 0) {
994 is->is_dst = fin->fin_fi.fi_dst;
995 } else {
996 is->is_dst = fin->fin_fi.fi_src;
997 }
998 }
999 is->is_flags &= ~(FI_W_SADDR|FI_W_DADDR);
1000 if ((is->is_flags & (FI_WILDA|FI_WILDP)) == 0)
1001 ips_wild--;
1002 }
1003
1004 if ((flags & (FI_W_SPORT|FI_W_DPORT))) {
1005 if ((flags & FI_W_SPORT) != 0) {
1006 if (rev == 0) {
1007 is->is_sport = sp;
1008 is->is_send = htonl(tcp->th_seq);
1009 } else {
1010 is->is_sport = dp;
1011 is->is_send = htonl(tcp->th_ack);

--- 10 unchanged lines hidden (view full) ---

1022 is->is_maxdend = is->is_dend + 1;
1023 }
1024 is->is_flags &= ~(FI_W_SPORT|FI_W_DPORT);
1025 ips_wild--;
1026 }
1027
1028 ret = -1;
1029
1030 if (is->is_ifp[idx] == NULL &&
1031 (*is->is_ifname[idx] == '\0' || *is->is_ifname[idx] == '*'))
1032 ret = idx;
1033
1034 if (ret >= 0) {
1035 is->is_ifp[ret] = ifp;
1036 strncpy(is->is_ifname[ret], IFNAME(ifp),
1037 sizeof(is->is_ifname[ret]));
1038 }
1039 fin->fin_rev = rev;
1040 return 1;
1041}
1042
1043static int fr_matchicmpqueryreply(v, is, icmp)
1044int v;
1045ipstate_t *is;
1046icmphdr_t *icmp;
1047{
1048 if (v == 4) {
1049 /*
1050 * If we matched its type on the way in, then when going out
1051 * it will still be the same type.
1052 */
1053 if (((icmp->icmp_type == is->is_type) ||
1054 (icmpreplytype4[is->is_type] == icmp->icmp_type))) {
1055 if (icmp->icmp_type != ICMP_ECHOREPLY)
1056 return 1;
1057 if ((icmp->icmp_id == is->is_icmp.ics_id) &&
1058 (icmp->icmp_seq == is->is_icmp.ics_seq))
1059 return 1;
1060 }
1061 }
1062#ifdef USE_INET6
1063 else if (is->is_v == 6) {
1064 if (((icmp->icmp_type == is->is_type) ||
1065 (icmpreplytype6[is->is_type] == icmp->icmp_type))) {
1066 if (icmp->icmp_type != ICMP6_ECHO_REPLY)
1067 return 1;
1068 if ((icmp->icmp_id == is->is_icmp.ics_id) &&
1069 (icmp->icmp_seq == is->is_icmp.ics_seq))
1070 return 1;
1071 }
1072 }
1073#endif
1074 return 0;
1075}
1076
1077static frentry_t *fr_checkicmpmatchingstate(ip, fin)
1078ip_t *ip;
1079fr_info_t *fin;

--- 15 unchanged lines hidden (view full) ---

1095 /*
1096 * Does it at least have the return (basic) IP header ?
1097 * Only a basic IP header (no options) should be with
1098 * an ICMP error header.
1099 */
1100 if (((ip->ip_v != 4) || (ip->ip_hl != 5)) ||
1101 (fin->fin_plen < ICMPERR_MINPKTLEN))
1102 return NULL;
1103
1104 ic = (struct icmp *)fin->fin_dp;
1105 type = ic->icmp_type;
1106 /*
1107 * If it's not an error type, then return
1108 */
1109 if ((type != ICMP_UNREACH) && (type != ICMP_SOURCEQUENCH) &&
1110 (type != ICMP_REDIRECT) && (type != ICMP_TIMXCEED) &&
1111 (type != ICMP_PARAMPROB))

--- 37 unchanged lines hidden (view full) ---

1149
1150 /*
1151 * in the IPv4 case we must zero the i6addr union otherwise
1152 * the IP6EQ and IP6NEQ macros produce the wrong results because
1153 * of the 'junk' in the unused part of the union
1154 */
1155 bzero((char *)&src, sizeof(src));
1156 bzero((char *)&dst, sizeof(dst));
1157 fr = NULL;
1158
1159 switch (oip->ip_p)
1160 {
1161 case IPPROTO_ICMP :
1162 icmp = (icmphdr_t *)((char *)oip + (oip->ip_hl << 2));
1163
1164 /*
1165 * a ICMP error can only be generated as a result of an
1166 * ICMP query, not as the response on an ICMP error
1167 *
1168 * XXX theoretically ICMP_ECHOREP and the other reply's are
1169 * ICMP query's as well, but adding them here seems strange XXX

--- 29 unchanged lines hidden (view full) ---

1199 for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext)
1200 if ((is->is_p == pr) && (is->is_v == 4) &&
1201 fr_matchsrcdst(is, src, dst, &ofin, NULL) &&
1202 fr_matchicmpqueryreply(is->is_v, is, icmp)) {
1203 ips_stats.iss_hits++;
1204 is->is_pkts++;
1205 is->is_bytes += ip->ip_len;
1206 fr = is->is_rule;
1207 break;
1208 }
1209 RWLOCK_EXIT(&ipf_state);
1210 return fr;
1211
1212 case IPPROTO_TCP :
1213 case IPPROTO_UDP :
1214 break;
1215 default :
1216 return NULL;
1217 }
1218
1219 tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2));
1220 dport = tcp->th_dport;
1221 sport = tcp->th_sport;
1222
1223 hv = (pr = oip->ip_p);
1224 src.in4 = oip->ip_src;
1225 hv += src.in4.s_addr;
1226 dst.in4 = oip->ip_dst;

--- 34 unchanged lines hidden (view full) ---

1261 ips_stats.iss_hits++;
1262 is->is_pkts++;
1263 is->is_bytes += fin->fin_plen;
1264 /*
1265 * we deliberately do not touch the timeouts
1266 * for the accompanying state table entry.
1267 * It remains to be seen if that is correct. XXX
1268 */
1269 break;
1270 }
1271 }
1272 RWLOCK_EXIT(&ipf_state);
1273 return fr;
1274}
1275
1276
1277/*
1278 * Move a state hash table entry from its old location at is->is_hv to
1279 * its new location, indexed by hv % fr_statesize.
1280 */
1281static void fr_ipsmove(isp, is, hv)
1282ipstate_t **isp, *is;
1283u_int hv;
1284{
1285 u_int hvm;
1286
1287 hvm = is->is_hv;
1288 /*

--- 30 unchanged lines hidden (view full) ---

1319{
1320 union i6addr dst, src;
1321 register ipstate_t *is, **isp;
1322 register u_char pr;
1323 u_int hv, hvm, hlen, tryagain, pass, v;
1324 struct icmp *ic;
1325 frentry_t *fr;
1326 tcphdr_t *tcp;
1327 int rev;
1328
1329 if (fr_state_lock || (fin->fin_off != 0) || (fin->fin_fl & FI_SHORT))
1330 return NULL;
1331
1332 is = NULL;
1333 hlen = fin->fin_hlen;
1334 tcp = (tcphdr_t *)((char *)ip + hlen);
1335 ic = (struct icmp *)tcp;
1336 hv = (pr = fin->fin_fi.fi_p);
1337 src = fin->fin_fi.fi_src;
1338 dst = fin->fin_fi.fi_dst;
1339 hv += src.in4.s_addr;
1340 hv += dst.in4.s_addr;
1341
1342 /*
1343 * Search the hash table for matching packet header info.
1344 * At the bottom of this switch statement, the following is expected:
1345 * is == NULL, no lock on ipf_state is held.
1346 * is != NULL, a lock on ipf_state is held.
1347 */
1348 v = fin->fin_fi.fi_v;
1349#ifdef USE_INET6
1350 if (v == 6) {
1351 hv += fin->fin_fi.fi_src.i6[1];
1352 hv += fin->fin_fi.fi_src.i6[2];
1353 hv += fin->fin_fi.fi_src.i6[3];
1354
1355 if ((fin->fin_p == IPPROTO_ICMPV6) &&
1356 IN6_IS_ADDR_MULTICAST(&fin->fin_fi.fi_dst.in6)) {
1357 hv -= dst.in4.s_addr;
1358 } else {
1359 hv += fin->fin_fi.fi_dst.i6[1];
1360 hv += fin->fin_fi.fi_dst.i6[2];
1361 hv += fin->fin_fi.fi_dst.i6[3];
1362 }
1363 }
1364#endif
1365
1366 switch (fin->fin_p)
1367 {
1368#ifdef USE_INET6
1369 case IPPROTO_ICMPV6 :
1370 tcp = NULL;
1371 tryagain = 0;
1372 if (v == 6) {
1373 if ((ic->icmp_type == ICMP6_ECHO_REQUEST) ||
1374 (ic->icmp_type == ICMP6_ECHO_REPLY)) {
1375 hv += ic->icmp_id;
1376 hv += ic->icmp_seq;
1377 }
1378 }
1379 READ_ENTER(&ipf_state);
1380icmp6again:
1381 hvm = hv % fr_statesize;
1382 for (isp = &ips_table[hvm]; (is = *isp); isp = &is->is_hnext)
1383 if ((is->is_p == pr) && (is->is_v == v) &&
1384 fr_matchsrcdst(is, src, dst, fin, NULL) &&
1385 fr_matchicmpqueryreply(v, is, ic)) {
1386 rev = fin->fin_rev;
1387 if (is->is_frage[rev] != 0)
1388 is->is_age = is->is_frage[rev];
1389 else if (fin->fin_rev)
1390 is->is_age = fr_icmpacktimeout;
1391 else
1392 is->is_age = fr_icmptimeout;
1393 break;
1394 }
1395
1396 if (is != NULL) {
1397 if (tryagain && !(is->is_flags & FI_W_DADDR)) {
1398 hv += fin->fin_fi.fi_src.i6[0];
1399 hv += fin->fin_fi.fi_src.i6[1];
1400 hv += fin->fin_fi.fi_src.i6[2];
1401 hv += fin->fin_fi.fi_src.i6[3];
1402 fr_ipsmove(isp, is, hv);
1403 MUTEX_DOWNGRADE(&ipf_state);
1404 }
1405 break;
1406 }
1407 RWLOCK_EXIT(&ipf_state);
1408
1409 /*
1410 * No matching icmp state entry. Perhaps this is a
1411 * response to another state entry.
1412 */
1413 if ((ips_wild != 0) && (v == 6) && (tryagain == 0) &&
1414 !IN6_IS_ADDR_MULTICAST(&fin->fin_fi.fi_src.in6)) {
1415 hv -= fin->fin_fi.fi_src.i6[0];
1416 hv -= fin->fin_fi.fi_src.i6[1];
1417 hv -= fin->fin_fi.fi_src.i6[2];
1418 hv -= fin->fin_fi.fi_src.i6[3];
1419 tryagain = 1;
1420 WRITE_ENTER(&ipf_state);
1421 goto icmp6again;
1422 }
1423
1424 fr = fr_checkicmp6matchingstate((ip6_t *)ip, fin);
1425 if (fr)
1426 return fr;
1427 break;
1428#endif
1429 case IPPROTO_ICMP :
1430 tcp = NULL;
1431 if (v == 4) {
1432 hv += ic->icmp_id;
1433 hv += ic->icmp_seq;
1434 }
1435 hvm = hv % fr_statesize;
1436 READ_ENTER(&ipf_state);
1437 for (isp = &ips_table[hvm]; (is = *isp); isp = &is->is_hnext)
1438 if ((is->is_p == pr) && (is->is_v == v) &&
1439 fr_matchsrcdst(is, src, dst, fin, NULL) &&
1440 fr_matchicmpqueryreply(v, is, ic)) {
1441 rev = fin->fin_rev;
1442 if (is->is_frage[rev] != 0)
1443 is->is_age = is->is_frage[rev];
1444 else if (fin->fin_rev)
1445 is->is_age = fr_icmpacktimeout;
1446 else
1447 is->is_age = fr_icmptimeout;
1448 break;
1449 }
1450
1451 if (is != NULL)
1452 break;
1453 RWLOCK_EXIT(&ipf_state);
1454 /*
1455 * No matching icmp state entry. Perhaps this is a
1456 * response to another state entry.
1457 */
1458 fr = fr_checkicmpmatchingstate(ip, fin);
1459 if (fr)
1460 return fr;
1461 break;
1462 case IPPROTO_TCP :
1463 /*
1464 * Just plain ignore RST flag set with either FIN or SYN.
1465 */
1466 if ((tcp->th_flags & TH_RST) &&
1467 ((tcp->th_flags & (TH_FIN|TH_SYN|TH_RST)) != TH_RST))
1468 break;
1469 case IPPROTO_UDP :
1470 {
1471 register u_short dport, sport;
1472
1473 dport = tcp->th_dport;
1474 sport = tcp->th_sport;
1475 tryagain = 0;
1476 hv += dport;
1477 hv += sport;
1478 READ_ENTER(&ipf_state);
1479retry_tcpudp:
1480 hvm = hv % fr_statesize;
1481 for (isp = &ips_table[hvm]; (is = *isp); isp = &is->is_hnext)
1482 if ((is->is_p == pr) && (is->is_v == v) &&
1483 fr_matchsrcdst(is, src, dst, fin, tcp)) {
1484 rev = fin->fin_rev;
1485 if ((pr == IPPROTO_TCP)) {
1486 if (!fr_tcpstate(is, fin, ip, tcp)) {
1487 continue;
1488 }
1489 } else if ((pr == IPPROTO_UDP)) {
1490 if (is->is_frage[rev] != 0)
1491 is->is_age = is->is_frage[rev];
1492 else if (fin->fin_rev)
1493 is->is_age = fr_udpacktimeout;
1494 else
1495 is->is_age = fr_udptimeout;
1496 }
1497 break;
1498 }
1499 if (is != NULL) {
1500 if (tryagain &&

--- 11 unchanged lines hidden (view full) ---

1512 hv -= sport;
1513 tryagain = 1;
1514 WRITE_ENTER(&ipf_state);
1515 goto retry_tcpudp;
1516 }
1517 break;
1518 }
1519 default :
1520 tcp = NULL;
1521 hv %= fr_statesize;
1522 READ_ENTER(&ipf_state);
1523 for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) {
1524 if ((is->is_p == pr) && (is->is_v == v) &&
1525 fr_matchsrcdst(is, src, dst, fin, NULL)) {
1526 rev = fin->fin_rev;
1527 if (is->is_frage[rev] != 0)
1528 is->is_age = is->is_frage[rev];
1529 else
1530 is->is_age = fr_udptimeout;
1531 break;
1532 }
1533 }
1534 if (is == NULL) {
1535 RWLOCK_EXIT(&ipf_state);
1536 }
1537 break;
1538 }
1539
1540 if (is == NULL) {
1541 ATOMIC_INCL(ips_stats.iss_miss);
1542 return NULL;
1543 }
1544
1545 MUTEX_ENTER(&is->is_lock);
1546 is->is_bytes += fin->fin_plen;
1547 ips_stats.iss_hits++;
1548 is->is_pkts++;
1549 MUTEX_EXIT(&is->is_lock);
1550 fr = is->is_rule;
1551 fin->fin_rule = is->is_rulen;
1552 if (fr != NULL) {
1553 fin->fin_group = fr->fr_group;
1554 fin->fin_icode = fr->fr_icode;
1555 }
1556 fin->fin_fr = fr;
1557 pass = is->is_pass;
1558 RWLOCK_EXIT(&ipf_state);
1559 if ((fin->fin_fl & FI_FRAG) && (pass & FR_KEEPFRAG))
1560 ipfr_newfrag(ip, fin, pass ^ FR_KEEPSTATE);
1561#ifndef _KERNEL
1562 if ((tcp != NULL) && (tcp->th_flags & TCP_CLOSE))
1563 fr_delstate(is);
1564#endif
1565 return fr;
1566}
1567
1568
1569/*
1570 * Sync. state entries. If interfaces come or go or just change position,
1571 * this is needed.
1572 */
1573void ip_statesync(ifp)
1574void *ifp;
1575{
1576 register ipstate_t *is;
1577 int i;
1578
1579 WRITE_ENTER(&ipf_state);
1580 for (is = ips_list; is; is = is->is_next) {
1581 for (i = 0; i < 4; i++) {
1582 if (is->is_ifp[i] == ifp) {
1583 is->is_ifpin = GETUNIT(is->is_ifname[i],
1584 is->is_v);
1585 if (!is->is_ifp[i])
1586 is->is_ifp[i] = (void *)-1;
1587 }
1588 }
1589 }
1590 RWLOCK_EXIT(&ipf_state);
1591}
1592
1593
1594/*
1595 * Must always be called with fr_ipfstate held as a write lock.
1596 */

--- 7 unchanged lines hidden (view full) ---

1604 if (is->is_next)
1605 is->is_next->is_pnext = is->is_pnext;
1606 *is->is_pnext = is->is_next;
1607 if (is->is_hnext)
1608 is->is_hnext->is_phnext = is->is_phnext;
1609 *is->is_phnext = is->is_hnext;
1610 if (ips_table[is->is_hv] == NULL)
1611 ips_stats.iss_inuse--;
1612 if (is->is_me)
1613 *is->is_me = NULL;
1614
1615 fr = is->is_rule;
1616 if (fr != NULL) {
1617 fr->fr_ref--;
1618 if (fr->fr_ref == 0) {
1619 KFREE(fr);
1620 }
1621 }

--- 45 unchanged lines hidden (view full) ---

1667 ips_stats.iss_expire++;
1668#ifdef IPFILTER_LOG
1669 ipstate_log(is, ISL_EXPIRE);
1670#endif
1671 fr_delstate(is);
1672 } else
1673 isp = &is->is_next;
1674 if (fr_state_doflush) {
1675 (void) fr_state_flush(2);
1676 fr_state_doflush = 0;
1677 }
1678 RWLOCK_EXIT(&ipf_state);
1679 SPL_X(s);
1680}
1681
1682
1683/*

--- 67 unchanged lines hidden (view full) ---

1751 * The next piece of code makes it possible to get
1752 * already established connections into the state table
1753 * after a restart or reload of the filter rules; this
1754 * does not work when a strict 'flags S keep state' is
1755 * used for tcp connections of course
1756 */
1757 if ((flags & (TH_FIN|TH_SYN|TH_RST|TH_ACK)) == TH_ACK) {
1758 /* we saw an A, guess 'dir' is in ESTABLISHED mode */
1759 if (state[1 - dir] == TCPS_CLOSED ||
1760 state[1 - dir] == TCPS_ESTABLISHED) {
1761 state[dir] = TCPS_ESTABLISHED;
1762 *age = fr_tcpidletimeout;
1763 }
1764 }
1765 /*
1766 * TODO: besides regular ACK packets we can have other
1767 * packets as well; it is yet to be determined how we
1768 * should initialize the states in those cases
1769 */
1770 break;
1771

--- 172 unchanged lines hidden (view full) ---

1944 ipsl.isl_flags = is->is_flags;
1945 if (ipsl.isl_p == IPPROTO_TCP || ipsl.isl_p == IPPROTO_UDP) {
1946 ipsl.isl_sport = is->is_sport;
1947 ipsl.isl_dport = is->is_dport;
1948 if (ipsl.isl_p == IPPROTO_TCP) {
1949 ipsl.isl_state[0] = is->is_state[0];
1950 ipsl.isl_state[1] = is->is_state[1];
1951 }
1952 } else if (ipsl.isl_p == IPPROTO_ICMP) {
1953 ipsl.isl_itype = is->is_icmp.ics_type;
1954 } else if (ipsl.isl_p == IPPROTO_ICMPV6) {
1955 ipsl.isl_itype = is->is_icmp.ics_type;
1956 } else {
1957 ipsl.isl_ps.isl_filler[0] = 0;
1958 ipsl.isl_ps.isl_filler[1] = 0;
1959 }
1960 items[0] = &ipsl;
1961 sizes[0] = sizeof(ipsl);
1962 types[0] = 0;
1963
1964 (void) ipllog(IPL_LOGSTATE, NULL, items, sizes, types, 1);

--- 136 unchanged lines hidden (view full) ---

2101 * other way around. Note that the minimal amount
2102 * of info present does not allow for checking against
2103 * tcp internals such as seq and ack numbers.
2104 */
2105 if ((is->is_p == pr) && (is->is_v == 6) &&
2106 fr_matchsrcdst(is, src, dst, &ofin, tcp)) {
2107 fr = is->is_rule;
2108 ips_stats.iss_hits++;
2109 is->is_pkts++;
2110 is->is_bytes += fin->fin_plen;
2111 /*
2112 * we deliberately do not touch the timeouts
2113 * for the accompanying state table entry.
2114 * It remains to be seen if that is correct. XXX
2115 */
2116 RWLOCK_EXIT(&ipf_state);
2117 return fr;
2118 }
2119 }
2120 RWLOCK_EXIT(&ipf_state);
2121 return NULL;
2122}
2123#endif