1 /*
2 * Copyright (C) 1995-2003 by Darren Reed.
3 *
4 * See the IPFILTER.LICENCE file for details on licencing.
5 *
6 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
7 *
8 * Copyright (c) 2014, Joyent, Inc. All rights reserved.
9 */
10
11 #if defined(KERNEL) || defined(_KERNEL)
12 # undef KERNEL
13 # undef _KERNEL
14 # define KERNEL 1
15 # define _KERNEL 1
16 #endif
17 #include <sys/errno.h>
18 #include <sys/types.h>
19 #include <sys/param.h>
20 #include <sys/file.h>
21 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
22 defined(_KERNEL)
23 # include "opt_ipfilter_log.h"
24 #endif
25 #if defined(_KERNEL) && defined(__FreeBSD_version) && \
26 (__FreeBSD_version >= 400000) && !defined(KLD_MODULE)
27 #include "opt_inet6.h"
28 #endif
91 #include "netinet/ip_frag.h"
92 #include "netinet/ip_state.h"
93 #include "netinet/ip_proxy.h"
94 #include "netinet/ipf_stack.h"
95 #ifdef IPFILTER_SYNC
96 #include "netinet/ip_sync.h"
97 #endif
98 #ifdef IPFILTER_SCAN
99 #include "netinet/ip_scan.h"
100 #endif
101 #ifdef USE_INET6
102 #include <netinet/icmp6.h>
103 #endif
104 #if (__FreeBSD_version >= 300000)
105 # include <sys/malloc.h>
106 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
107 # include <sys/libkern.h>
108 # include <sys/systm.h>
109 # endif
110 #endif
111 /* END OF INCLUDES */
112
113
114 #if !defined(lint)
115 static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed";
116 static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.186.2.36 2005/08/11 19:58:03 darrenr Exp $";
117 #endif
118
119 #ifdef USE_INET6
120 static ipstate_t *fr_checkicmp6matchingstate __P((fr_info_t *));
121 #endif
122 static ipstate_t *fr_matchsrcdst __P((fr_info_t *, ipstate_t *, i6addr_t *,
123 i6addr_t *, tcphdr_t *, u_32_t));
124 static ipstate_t *fr_checkicmpmatchingstate __P((fr_info_t *));
125 static int fr_state_flush __P((int, int, ipf_stack_t *));
126 static ips_stat_t *fr_statetstats __P((ipf_stack_t *));
127 static int fr_state_remove __P((caddr_t, ipf_stack_t *));
128 static void fr_ipsmove __P((ipstate_t *, u_int, ipf_stack_t *));
129 static int fr_tcpstate __P((fr_info_t *, tcphdr_t *, ipstate_t *));
130 static int fr_tcpoptions __P((fr_info_t *, tcphdr_t *, tcpdata_t *));
1428 }
1429 bcopy((char *)&ips, (char *)is, sizeof(*is));
1430 /*
1431 * Do not do the modulous here, it is done in fr_stinsert().
1432 */
1433 if (fr != NULL) {
1434 (void) strncpy(is->is_group, fr->fr_group, FR_GROUPLEN);
1435 if (fr->fr_age[0] != 0) {
1436 is->is_tqehead[0] =
1437 fr_addtimeoutqueue(&ifs->ifs_ips_utqe,
1438 fr->fr_age[0], ifs);
1439 is->is_sti.tqe_flags |= TQE_RULEBASED;
1440 }
1441 if (fr->fr_age[1] != 0) {
1442 is->is_tqehead[1] =
1443 fr_addtimeoutqueue(&ifs->ifs_ips_utqe,
1444 fr->fr_age[1], ifs);
1445 is->is_sti.tqe_flags |= TQE_RULEBASED;
1446 }
1447 is->is_tag = fr->fr_logtag;
1448
1449 is->is_ifp[(out << 1) + 1] = fr->fr_ifas[1];
1450 is->is_ifp[(1 - out) << 1] = fr->fr_ifas[2];
1451 is->is_ifp[((1 - out) << 1) + 1] = fr->fr_ifas[3];
1452
1453 if (((ifp = fr->fr_ifas[1]) != NULL) &&
1454 (ifp != (void *)-1)) {
1455 COPYIFNAME(ifp, is->is_ifname[(out << 1) + 1], fr->fr_v);
1456 }
1457 if (((ifp = fr->fr_ifas[2]) != NULL) &&
1458 (ifp != (void *)-1)) {
1459 COPYIFNAME(ifp, is->is_ifname[(1 - out) << 1], fr->fr_v);
1460 }
1461 if (((ifp = fr->fr_ifas[3]) != NULL) &&
1462 (ifp != (void *)-1)) {
1463 COPYIFNAME(ifp, is->is_ifname[((1 - out) << 1) + 1], fr->fr_v);
1464 }
1465 }
1466
1467 is->is_ifp[out << 1] = fin->fin_ifp;
1507 * timer on it as we'll never see an error if it fails to
1508 * connect.
1509 */
1510 (void) fr_tcp_age(&is->is_sti, fin, ifs->ifs_ips_tqtqb,
1511 is->is_flags);
1512 MUTEX_EXIT(&is->is_lock);
1513 #ifdef IPFILTER_SCAN
1514 if ((is->is_flags & SI_CLONE) == 0)
1515 (void) ipsc_attachis(is);
1516 #endif
1517 } else {
1518 MUTEX_EXIT(&is->is_lock);
1519 }
1520 #ifdef IPFILTER_SYNC
1521 if ((is->is_flags & IS_STATESYNC) && ((is->is_flags & SI_CLONE) == 0))
1522 is->is_sync = ipfsync_new(SMC_STATE, fin, is);
1523 #endif
1524 if (ifs->ifs_ipstate_logging)
1525 ipstate_log(is, ISL_NEW, ifs);
1526
1527 RWLOCK_EXIT(&ifs->ifs_ipf_state);
1528 fin->fin_rev = IP6_NEQ(&is->is_dst, &fin->fin_daddr);
1529 fin->fin_flx |= FI_STATE;
1530 if (fin->fin_flx & FI_FRAG)
1531 (void) fr_newfrag(fin, pass ^ FR_KEEPSTATE);
1532
1533 return is;
1534 }
1535
1536
1537 /* ------------------------------------------------------------------------ */
1538 /* Function: fr_tcpoptions */
1539 /* Returns: int - 1 == packet matches state entry, 0 == it does not */
1540 /* Parameters: fin(I) - pointer to packet information */
1541 /* tcp(I) - pointer to TCP packet header */
1542 /* td(I) - pointer to TCP data held as part of the state */
1543 /* */
1544 /* Look after the TCP header for any options and deal with those that are */
1545 /* present. Record details about those that we recogise. */
1546 /* ------------------------------------------------------------------------ */
2297 is->is_sport = sp;
2298 is->is_send = ntohl(tcp->th_seq);
2299 } else {
2300 is->is_sport = dp;
2301 is->is_send = ntohl(tcp->th_ack);
2302 }
2303 is->is_maxsend = is->is_send + 1;
2304 } else if ((flags & SI_W_DPORT) != 0) {
2305 if (rev == 0) {
2306 is->is_dport = dp;
2307 is->is_dend = ntohl(tcp->th_ack);
2308 } else {
2309 is->is_dport = sp;
2310 is->is_dend = ntohl(tcp->th_seq);
2311 }
2312 is->is_maxdend = is->is_dend + 1;
2313 }
2314 is->is_flags &= ~(SI_W_SPORT|SI_W_DPORT);
2315 if ((flags & SI_CLONED) && ifs->ifs_ipstate_logging)
2316 ipstate_log(is, ISL_CLONE, ifs);
2317 }
2318
2319 ret = -1;
2320
2321 if (is->is_flx[out][rev] == 0) {
2322 is->is_flx[out][rev] = flx;
2323 /*
2324 * If we are dealing with the first packet coming in reverse
2325 * direction (sent by peer), then we have to set options into
2326 * state.
2327 */
2328 if (rev == 1 && is->is_optmsk[1] == 0x0) {
2329 is->is_optmsk[1] = 0xffffffff;
2330 is->is_opt[1] = fin->fin_optmsk;
2331 DTRACE_PROBE(set_rev_opts);
2332 }
2333 if (is->is_v == 6) {
2334 is->is_opt[rev] &= ~0x8;
2335 is->is_optmsk[rev] &= ~0x8;
2336 }
3380 ipfsync_del(is->is_sync);
3381 #endif
3382 #ifdef IPFILTER_SCAN
3383 (void) ipsc_detachis(is);
3384 #endif
3385
3386 /*
3387 * Now remove it from master list of state table entries.
3388 */
3389 if (is->is_pnext != NULL) {
3390 *is->is_pnext = is->is_next;
3391 if (is->is_next != NULL) {
3392 is->is_next->is_pnext = is->is_pnext;
3393 is->is_next = NULL;
3394 }
3395 is->is_pnext = NULL;
3396 }
3397
3398 if (ifs->ifs_ipstate_logging != 0 && why != 0)
3399 ipstate_log(is, why, ifs);
3400
3401 if (is->is_rule != NULL) {
3402 is->is_rule->fr_statecnt--;
3403 (void)fr_derefrule(&is->is_rule, ifs);
3404 }
3405
3406 MUTEX_DESTROY(&is->is_lock);
3407 KFREE(is);
3408 ifs->ifs_ips_num--;
3409
3410 return (0);
3411 }
3412
3413
3414 /* ------------------------------------------------------------------------ */
3415 /* Function: fr_timeoutstate */
3416 /* Returns: Nil */
3417 /* Parameters: ifs - ipf stack instance */
3418 /* */
3419 /* Slowly expire held state for thingslike UDP and ICMP. The algorithm */
3420 /* used here is to keep the queue sorted with the oldest things at the top */
3914 if (rval == 2) {
3915 DTRACE_PROBE1(state_keeping_timer, int, nstate);
3916 rval = 1;
3917 }
3918 else if (rval == 1) {
3919 tqe->tqe_state[dir] = nstate;
3920 /*
3921 * The nstate can either advance to a new state, or remain
3922 * unchanged, resetting the timer by moving to the bottom of
3923 * the queue.
3924 */
3925 DTRACE_PROBE1(state_done, int, nstate);
3926
3927 if ((tqe->tqe_flags & TQE_RULEBASED) == 0)
3928 fr_movequeue(tqe, tqe->tqe_ifq, tqtab + nstate, ifs);
3929 }
3930
3931 return rval;
3932 }
3933
3934
3935 /* ------------------------------------------------------------------------ */
3936 /* Function: ipstate_log */
3937 /* Returns: Nil */
3938 /* Parameters: is(I) - pointer to state structure */
3939 /* type(I) - type of log entry to create */
3940 /* */
3941 /* Creates a state table log entry using the state structure and type info. */
3942 /* passed in. Log packet/byte counts, source/destination address and other */
3943 /* protocol specific information. */
3944 /* ------------------------------------------------------------------------ */
3945 void ipstate_log(is, type, ifs)
3946 struct ipstate *is;
3947 u_int type;
3948 ipf_stack_t *ifs;
3949 {
3950 #ifdef IPFILTER_LOG
3951 struct ipslog ipsl;
3952 size_t sizes[1];
3953 void *items[1];
3954 int types[1];
|
1 /*
2 * Copyright (C) 1995-2003 by Darren Reed.
3 *
4 * See the IPFILTER.LICENCE file for details on licencing.
5 *
6 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
7 *
8 * Copyright 2019 Joyent, Inc.
9 */
10
11 #if defined(KERNEL) || defined(_KERNEL)
12 # undef KERNEL
13 # undef _KERNEL
14 # define KERNEL 1
15 # define _KERNEL 1
16 #endif
17 #include <sys/errno.h>
18 #include <sys/types.h>
19 #include <sys/param.h>
20 #include <sys/file.h>
21 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
22 defined(_KERNEL)
23 # include "opt_ipfilter_log.h"
24 #endif
25 #if defined(_KERNEL) && defined(__FreeBSD_version) && \
26 (__FreeBSD_version >= 400000) && !defined(KLD_MODULE)
27 #include "opt_inet6.h"
28 #endif
91 #include "netinet/ip_frag.h"
92 #include "netinet/ip_state.h"
93 #include "netinet/ip_proxy.h"
94 #include "netinet/ipf_stack.h"
95 #ifdef IPFILTER_SYNC
96 #include "netinet/ip_sync.h"
97 #endif
98 #ifdef IPFILTER_SCAN
99 #include "netinet/ip_scan.h"
100 #endif
101 #ifdef USE_INET6
102 #include <netinet/icmp6.h>
103 #endif
104 #if (__FreeBSD_version >= 300000)
105 # include <sys/malloc.h>
106 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
107 # include <sys/libkern.h>
108 # include <sys/systm.h>
109 # endif
110 #endif
111 #include <sys/uuid.h>
112 /* END OF INCLUDES */
113
114
115 #if !defined(lint)
116 static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed";
117 static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.186.2.36 2005/08/11 19:58:03 darrenr Exp $";
118 #endif
119
120 #ifdef USE_INET6
121 static ipstate_t *fr_checkicmp6matchingstate __P((fr_info_t *));
122 #endif
123 static ipstate_t *fr_matchsrcdst __P((fr_info_t *, ipstate_t *, i6addr_t *,
124 i6addr_t *, tcphdr_t *, u_32_t));
125 static ipstate_t *fr_checkicmpmatchingstate __P((fr_info_t *));
126 static int fr_state_flush __P((int, int, ipf_stack_t *));
127 static ips_stat_t *fr_statetstats __P((ipf_stack_t *));
128 static int fr_state_remove __P((caddr_t, ipf_stack_t *));
129 static void fr_ipsmove __P((ipstate_t *, u_int, ipf_stack_t *));
130 static int fr_tcpstate __P((fr_info_t *, tcphdr_t *, ipstate_t *));
131 static int fr_tcpoptions __P((fr_info_t *, tcphdr_t *, tcpdata_t *));
1429 }
1430 bcopy((char *)&ips, (char *)is, sizeof(*is));
1431 /*
1432 * Do not do the modulous here, it is done in fr_stinsert().
1433 */
1434 if (fr != NULL) {
1435 (void) strncpy(is->is_group, fr->fr_group, FR_GROUPLEN);
1436 if (fr->fr_age[0] != 0) {
1437 is->is_tqehead[0] =
1438 fr_addtimeoutqueue(&ifs->ifs_ips_utqe,
1439 fr->fr_age[0], ifs);
1440 is->is_sti.tqe_flags |= TQE_RULEBASED;
1441 }
1442 if (fr->fr_age[1] != 0) {
1443 is->is_tqehead[1] =
1444 fr_addtimeoutqueue(&ifs->ifs_ips_utqe,
1445 fr->fr_age[1], ifs);
1446 is->is_sti.tqe_flags |= TQE_RULEBASED;
1447 }
1448 is->is_tag = fr->fr_logtag;
1449 memcpy(is->is_uuid, fr->fr_uuid, sizeof (uuid_t));
1450
1451 is->is_ifp[(out << 1) + 1] = fr->fr_ifas[1];
1452 is->is_ifp[(1 - out) << 1] = fr->fr_ifas[2];
1453 is->is_ifp[((1 - out) << 1) + 1] = fr->fr_ifas[3];
1454
1455 if (((ifp = fr->fr_ifas[1]) != NULL) &&
1456 (ifp != (void *)-1)) {
1457 COPYIFNAME(ifp, is->is_ifname[(out << 1) + 1], fr->fr_v);
1458 }
1459 if (((ifp = fr->fr_ifas[2]) != NULL) &&
1460 (ifp != (void *)-1)) {
1461 COPYIFNAME(ifp, is->is_ifname[(1 - out) << 1], fr->fr_v);
1462 }
1463 if (((ifp = fr->fr_ifas[3]) != NULL) &&
1464 (ifp != (void *)-1)) {
1465 COPYIFNAME(ifp, is->is_ifname[((1 - out) << 1) + 1], fr->fr_v);
1466 }
1467 }
1468
1469 is->is_ifp[out << 1] = fin->fin_ifp;
1509 * timer on it as we'll never see an error if it fails to
1510 * connect.
1511 */
1512 (void) fr_tcp_age(&is->is_sti, fin, ifs->ifs_ips_tqtqb,
1513 is->is_flags);
1514 MUTEX_EXIT(&is->is_lock);
1515 #ifdef IPFILTER_SCAN
1516 if ((is->is_flags & SI_CLONE) == 0)
1517 (void) ipsc_attachis(is);
1518 #endif
1519 } else {
1520 MUTEX_EXIT(&is->is_lock);
1521 }
1522 #ifdef IPFILTER_SYNC
1523 if ((is->is_flags & IS_STATESYNC) && ((is->is_flags & SI_CLONE) == 0))
1524 is->is_sync = ipfsync_new(SMC_STATE, fin, is);
1525 #endif
1526 if (ifs->ifs_ipstate_logging)
1527 ipstate_log(is, ISL_NEW, ifs);
1528
1529 if (IFS_CFWLOG(ifs, is->is_rule))
1530 ipf_log_cfwlog(is, ISL_NEW, ifs);
1531
1532 RWLOCK_EXIT(&ifs->ifs_ipf_state);
1533 fin->fin_rev = IP6_NEQ(&is->is_dst, &fin->fin_daddr);
1534 fin->fin_flx |= FI_STATE;
1535 if (fin->fin_flx & FI_FRAG)
1536 (void) fr_newfrag(fin, pass ^ FR_KEEPSTATE);
1537
1538 return is;
1539 }
1540
1541
1542 /* ------------------------------------------------------------------------ */
1543 /* Function: fr_tcpoptions */
1544 /* Returns: int - 1 == packet matches state entry, 0 == it does not */
1545 /* Parameters: fin(I) - pointer to packet information */
1546 /* tcp(I) - pointer to TCP packet header */
1547 /* td(I) - pointer to TCP data held as part of the state */
1548 /* */
1549 /* Look after the TCP header for any options and deal with those that are */
1550 /* present. Record details about those that we recogise. */
1551 /* ------------------------------------------------------------------------ */
2302 is->is_sport = sp;
2303 is->is_send = ntohl(tcp->th_seq);
2304 } else {
2305 is->is_sport = dp;
2306 is->is_send = ntohl(tcp->th_ack);
2307 }
2308 is->is_maxsend = is->is_send + 1;
2309 } else if ((flags & SI_W_DPORT) != 0) {
2310 if (rev == 0) {
2311 is->is_dport = dp;
2312 is->is_dend = ntohl(tcp->th_ack);
2313 } else {
2314 is->is_dport = sp;
2315 is->is_dend = ntohl(tcp->th_seq);
2316 }
2317 is->is_maxdend = is->is_dend + 1;
2318 }
2319 is->is_flags &= ~(SI_W_SPORT|SI_W_DPORT);
2320 if ((flags & SI_CLONED) && ifs->ifs_ipstate_logging)
2321 ipstate_log(is, ISL_CLONE, ifs);
2322 if ((flags & SI_CLONED) && IFS_CFWLOG(ifs, is->is_rule))
2323 ipf_log_cfwlog(is, ISL_CLONE, ifs);
2324 }
2325
2326 ret = -1;
2327
2328 if (is->is_flx[out][rev] == 0) {
2329 is->is_flx[out][rev] = flx;
2330 /*
2331 * If we are dealing with the first packet coming in reverse
2332 * direction (sent by peer), then we have to set options into
2333 * state.
2334 */
2335 if (rev == 1 && is->is_optmsk[1] == 0x0) {
2336 is->is_optmsk[1] = 0xffffffff;
2337 is->is_opt[1] = fin->fin_optmsk;
2338 DTRACE_PROBE(set_rev_opts);
2339 }
2340 if (is->is_v == 6) {
2341 is->is_opt[rev] &= ~0x8;
2342 is->is_optmsk[rev] &= ~0x8;
2343 }
3387 ipfsync_del(is->is_sync);
3388 #endif
3389 #ifdef IPFILTER_SCAN
3390 (void) ipsc_detachis(is);
3391 #endif
3392
3393 /*
3394 * Now remove it from master list of state table entries.
3395 */
3396 if (is->is_pnext != NULL) {
3397 *is->is_pnext = is->is_next;
3398 if (is->is_next != NULL) {
3399 is->is_next->is_pnext = is->is_pnext;
3400 is->is_next = NULL;
3401 }
3402 is->is_pnext = NULL;
3403 }
3404
3405 if (ifs->ifs_ipstate_logging != 0 && why != 0)
3406 ipstate_log(is, why, ifs);
3407 #if 0
3408 /*
3409 * For now, ipf_log_cfwlog() copes with all "why" values. Strictly
3410 * speaking, though, they all map to one event (CFWEV_END), which for
3411 * now is not supported, hence the #if 0.
3412 */
3413 if (why != 0 && IFS_CFWLOG(ifs, is->is_rule))
3414 ipf_log_cfwlog(is, why, ifs);
3415 #endif
3416 if (is->is_rule != NULL) {
3417 is->is_rule->fr_statecnt--;
3418 (void)fr_derefrule(&is->is_rule, ifs);
3419 }
3420
3421 MUTEX_DESTROY(&is->is_lock);
3422 KFREE(is);
3423 ifs->ifs_ips_num--;
3424
3425 return (0);
3426 }
3427
3428
3429 /* ------------------------------------------------------------------------ */
3430 /* Function: fr_timeoutstate */
3431 /* Returns: Nil */
3432 /* Parameters: ifs - ipf stack instance */
3433 /* */
3434 /* Slowly expire held state for thingslike UDP and ICMP. The algorithm */
3435 /* used here is to keep the queue sorted with the oldest things at the top */
3929 if (rval == 2) {
3930 DTRACE_PROBE1(state_keeping_timer, int, nstate);
3931 rval = 1;
3932 }
3933 else if (rval == 1) {
3934 tqe->tqe_state[dir] = nstate;
3935 /*
3936 * The nstate can either advance to a new state, or remain
3937 * unchanged, resetting the timer by moving to the bottom of
3938 * the queue.
3939 */
3940 DTRACE_PROBE1(state_done, int, nstate);
3941
3942 if ((tqe->tqe_flags & TQE_RULEBASED) == 0)
3943 fr_movequeue(tqe, tqe->tqe_ifq, tqtab + nstate, ifs);
3944 }
3945
3946 return rval;
3947 }
3948
3949 /* ------------------------------------------------------------------------ */
3950 /* Function: ipstate_log */
3951 /* Returns: Nil */
3952 /* Parameters: is(I) - pointer to state structure */
3953 /* type(I) - type of log entry to create */
3954 /* */
3955 /* Creates a state table log entry using the state structure and type info. */
3956 /* passed in. Log packet/byte counts, source/destination address and other */
3957 /* protocol specific information. */
3958 /* ------------------------------------------------------------------------ */
3959 void ipstate_log(is, type, ifs)
3960 struct ipstate *is;
3961 u_int type;
3962 ipf_stack_t *ifs;
3963 {
3964 #ifdef IPFILTER_LOG
3965 struct ipslog ipsl;
3966 size_t sizes[1];
3967 void *items[1];
3968 int types[1];
|