197b932f1Srmind /*-
238bb64a8Srmind * Copyright (c) 2010-2012 The NetBSD Foundation, Inc.
397b932f1Srmind * All rights reserved.
497b932f1Srmind *
597b932f1Srmind * This material is based upon work partially supported by The
697b932f1Srmind * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
797b932f1Srmind *
897b932f1Srmind * Redistribution and use in source and binary forms, with or without
997b932f1Srmind * modification, are permitted provided that the following conditions
1097b932f1Srmind * are met:
1197b932f1Srmind * 1. Redistributions of source code must retain the above copyright
1297b932f1Srmind * notice, this list of conditions and the following disclaimer.
1397b932f1Srmind * 2. Redistributions in binary form must reproduce the above copyright
1497b932f1Srmind * notice, this list of conditions and the following disclaimer in the
1597b932f1Srmind * documentation and/or other materials provided with the distribution.
1697b932f1Srmind *
1797b932f1Srmind * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1897b932f1Srmind * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1997b932f1Srmind * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2097b932f1Srmind * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2197b932f1Srmind * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2297b932f1Srmind * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2397b932f1Srmind * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2497b932f1Srmind * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2597b932f1Srmind * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2697b932f1Srmind * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2797b932f1Srmind * POSSIBILITY OF SUCH DAMAGE.
2897b932f1Srmind */
2997b932f1Srmind
3097b932f1Srmind /*
31c6d74635Srmind * NPF state engine to track connection.
3297b932f1Srmind */
3397b932f1Srmind
340473fe8bSchristos #ifdef _KERNEL
3597b932f1Srmind #include <sys/cdefs.h>
36*d6939920Srmind __KERNEL_RCSID(0, "$NetBSD: npf_state.c,v 1.23 2020/05/30 14:16:56 rmind Exp $");
3797b932f1Srmind
3897b932f1Srmind #include <sys/param.h>
3997b932f1Srmind #include <sys/systm.h>
4097b932f1Srmind #include <sys/mutex.h>
410473fe8bSchristos #endif
4297b932f1Srmind
4397b932f1Srmind #include "npf_impl.h"
4497b932f1Srmind
45255cf3c4Srmind /*
46c6d74635Srmind * Generic connection states and timeout table.
47255cf3c4Srmind *
48f49c13e6Srmind * Note: used for connection-less protocols.
49255cf3c4Srmind */
50255cf3c4Srmind
51c6d74635Srmind #define NPF_ANY_CONN_CLOSED 0
52c6d74635Srmind #define NPF_ANY_CONN_NEW 1
53c6d74635Srmind #define NPF_ANY_CONN_ESTABLISHED 2
54c6d74635Srmind #define NPF_ANY_CONN_NSTATES 3
55255cf3c4Srmind
567e3fb338Srmind /*
577e3fb338Srmind * Parameters.
587e3fb338Srmind */
597e3fb338Srmind typedef struct {
607e3fb338Srmind int timeouts[NPF_ANY_CONN_NSTATES];
61*d6939920Srmind int gre_timeout;
627e3fb338Srmind } npf_state_params_t;
637e3fb338Srmind
647e3fb338Srmind /*
657e3fb338Srmind * Generic FSM.
667e3fb338Srmind */
67c6d74635Srmind static const uint8_t npf_generic_fsm[NPF_ANY_CONN_NSTATES][2] = {
68c6d74635Srmind [NPF_ANY_CONN_CLOSED] = {
69c6d74635Srmind [NPF_FLOW_FORW] = NPF_ANY_CONN_NEW,
70255cf3c4Srmind },
71c6d74635Srmind [NPF_ANY_CONN_NEW] = {
72c6d74635Srmind [NPF_FLOW_FORW] = NPF_ANY_CONN_NEW,
73c6d74635Srmind [NPF_FLOW_BACK] = NPF_ANY_CONN_ESTABLISHED,
74255cf3c4Srmind },
75c6d74635Srmind [NPF_ANY_CONN_ESTABLISHED] = {
76c6d74635Srmind [NPF_FLOW_FORW] = NPF_ANY_CONN_ESTABLISHED,
77c6d74635Srmind [NPF_FLOW_BACK] = NPF_ANY_CONN_ESTABLISHED,
78255cf3c4Srmind },
7997b932f1Srmind };
8097b932f1Srmind
8138bb64a8Srmind /*
8261ec0f9cSrmind * State sampler for debugging.
8361ec0f9cSrmind */
84c0ea6c8dSchristos #if defined(_NPF_TESTING)
8561ec0f9cSrmind static void (*npf_state_sample)(npf_state_t *, bool) = NULL;
8661ec0f9cSrmind #define NPF_STATE_SAMPLE(n, r) if (npf_state_sample) (*npf_state_sample)(n, r);
8761ec0f9cSrmind #else
8861ec0f9cSrmind #define NPF_STATE_SAMPLE(n, r)
8961ec0f9cSrmind #endif
9061ec0f9cSrmind
917e3fb338Srmind void
npf_state_sysinit(npf_t * npf)927e3fb338Srmind npf_state_sysinit(npf_t *npf)
937e3fb338Srmind {
947e3fb338Srmind npf_state_params_t *params = npf_param_allocgroup(npf,
957e3fb338Srmind NPF_PARAMS_GENERIC_STATE, sizeof(npf_state_params_t));
967e3fb338Srmind npf_param_t param_map[] = {
977e3fb338Srmind /*
987e3fb338Srmind * Generic timeout (in seconds).
997e3fb338Srmind */
1007e3fb338Srmind {
1017e3fb338Srmind "state.generic.timeout.closed",
1027e3fb338Srmind ¶ms->timeouts[NPF_ANY_CONN_CLOSED],
1037e3fb338Srmind .default_val = 0,
1047e3fb338Srmind .min = 0, .max = INT_MAX
1057e3fb338Srmind },
1067e3fb338Srmind {
1077e3fb338Srmind "state.generic.timeout.new",
1087e3fb338Srmind ¶ms->timeouts[NPF_ANY_CONN_NEW],
1097e3fb338Srmind .default_val = 30,
1107e3fb338Srmind .min = 0, .max = INT_MAX
1117e3fb338Srmind },
1127e3fb338Srmind {
1137e3fb338Srmind "state.generic.timeout.established",
1147e3fb338Srmind ¶ms->timeouts[NPF_ANY_CONN_ESTABLISHED],
1157e3fb338Srmind .default_val = 60,
1167e3fb338Srmind .min = 0, .max = INT_MAX
1177e3fb338Srmind },
118*d6939920Srmind {
119*d6939920Srmind "state.generic.timeout.gre",
120*d6939920Srmind ¶ms->gre_timeout,
121*d6939920Srmind .default_val = 24 * 60 * 60,
122*d6939920Srmind .min = 0, .max = INT_MAX
123*d6939920Srmind },
1247e3fb338Srmind };
1257e3fb338Srmind npf_param_register(npf, param_map, __arraycount(param_map));
1267e3fb338Srmind npf_state_tcp_sysinit(npf);
1277e3fb338Srmind }
1287e3fb338Srmind
1297e3fb338Srmind void
npf_state_sysfini(npf_t * npf)1307e3fb338Srmind npf_state_sysfini(npf_t *npf)
1317e3fb338Srmind {
1327e3fb338Srmind const size_t len = sizeof(npf_state_params_t);
1337e3fb338Srmind npf_param_freegroup(npf, NPF_PARAMS_GENERIC_STATE, len);
1347e3fb338Srmind npf_state_tcp_sysfini(npf);
1357e3fb338Srmind }
1367e3fb338Srmind
13761ec0f9cSrmind /*
13838bb64a8Srmind * npf_state_init: initialise the state structure.
13938bb64a8Srmind *
14038bb64a8Srmind * Should normally be called on a first packet, which also determines the
14138bb64a8Srmind * direction in a case of connection-orientated protocol. Returns true on
14238bb64a8Srmind * success and false otherwise (e.g. if protocol is not supported).
14338bb64a8Srmind */
14497b932f1Srmind bool
npf_state_init(npf_cache_t * npc,npf_state_t * nst)145d5cb4211Srmind npf_state_init(npf_cache_t *npc, npf_state_t *nst)
14697b932f1Srmind {
14737527ec6Srmind const int proto = npc->npc_proto;
148255cf3c4Srmind bool ret;
14997b932f1Srmind
150e8a3af9dSzoltan KASSERT(npf_iscached(npc, NPC_IP46));
151e8a3af9dSzoltan KASSERT(npf_iscached(npc, NPC_LAYER4));
152b7b64eb5Srmind
153255cf3c4Srmind memset(nst, 0, sizeof(npf_state_t));
154b7b64eb5Srmind
155255cf3c4Srmind switch (proto) {
156255cf3c4Srmind case IPPROTO_TCP:
157255cf3c4Srmind /* Pass to TCP state tracking engine. */
158d5cb4211Srmind ret = npf_state_tcp(npc, nst, NPF_FLOW_FORW);
159255cf3c4Srmind break;
160255cf3c4Srmind case IPPROTO_UDP:
161255cf3c4Srmind case IPPROTO_ICMP:
162*d6939920Srmind case IPPROTO_GRE:
163255cf3c4Srmind /* Generic. */
164255cf3c4Srmind nst->nst_state = npf_generic_fsm[nst->nst_state][NPF_FLOW_FORW];
165255cf3c4Srmind ret = true;
166255cf3c4Srmind break;
167255cf3c4Srmind default:
168255cf3c4Srmind ret = false;
16997b932f1Srmind }
1708b3f8af5Srmind NPF_STATE_SAMPLE(nst, ret);
171255cf3c4Srmind return ret;
17297b932f1Srmind }
17397b932f1Srmind
17497b932f1Srmind void
npf_state_destroy(npf_state_t * nst)17597b932f1Srmind npf_state_destroy(npf_state_t *nst)
17697b932f1Srmind {
177255cf3c4Srmind nst->nst_state = 0;
17897b932f1Srmind }
17997b932f1Srmind
18038bb64a8Srmind /*
18138bb64a8Srmind * npf_state_inspect: inspect the packet according to the protocol state.
18238bb64a8Srmind *
18338bb64a8Srmind * Return true if packet is considered to match the state (e.g. for TCP,
18438bb64a8Srmind * the packet belongs to the tracked connection) and false otherwise.
18538bb64a8Srmind */
18697b932f1Srmind bool
npf_state_inspect(npf_cache_t * npc,npf_state_t * nst,const npf_flow_t flow)187*d6939920Srmind npf_state_inspect(npf_cache_t *npc, npf_state_t *nst, const npf_flow_t flow)
18897b932f1Srmind {
18937527ec6Srmind const int proto = npc->npc_proto;
19097b932f1Srmind bool ret;
19197b932f1Srmind
19297b932f1Srmind switch (proto) {
19397b932f1Srmind case IPPROTO_TCP:
194255cf3c4Srmind /* Pass to TCP state tracking engine. */
195*d6939920Srmind ret = npf_state_tcp(npc, nst, flow);
196255cf3c4Srmind break;
197255cf3c4Srmind case IPPROTO_UDP:
198255cf3c4Srmind case IPPROTO_ICMP:
199*d6939920Srmind case IPPROTO_GRE:
200255cf3c4Srmind /* Generic. */
201*d6939920Srmind nst->nst_state = npf_generic_fsm[nst->nst_state][flow];
202255cf3c4Srmind ret = true;
20397b932f1Srmind break;
20497b932f1Srmind default:
205255cf3c4Srmind ret = false;
20697b932f1Srmind }
2078b3f8af5Srmind NPF_STATE_SAMPLE(nst, ret);
208255cf3c4Srmind
20997b932f1Srmind return ret;
21097b932f1Srmind }
21197b932f1Srmind
21293471725Srmind /*
2137e3fb338Srmind * npf_state_etime: return the expiration time depending on the state.
21493471725Srmind */
21597b932f1Srmind int
npf_state_etime(npf_t * npf,const npf_state_t * nst,const int proto)2167e3fb338Srmind npf_state_etime(npf_t *npf, const npf_state_t *nst, const int proto)
21797b932f1Srmind {
2187e3fb338Srmind const npf_state_params_t *params;
2197e3fb338Srmind const unsigned state = nst->nst_state;
220255cf3c4Srmind int timeout = 0;
22197b932f1Srmind
222255cf3c4Srmind switch (proto) {
223255cf3c4Srmind case IPPROTO_TCP:
224255cf3c4Srmind /* Pass to TCP state tracking engine. */
2257e3fb338Srmind timeout = npf_state_tcp_timeout(npf, nst);
226255cf3c4Srmind break;
227255cf3c4Srmind case IPPROTO_UDP:
228255cf3c4Srmind case IPPROTO_ICMP:
229255cf3c4Srmind /* Generic. */
2307e3fb338Srmind params = npf->params[NPF_PARAMS_GENERIC_STATE];
2317e3fb338Srmind timeout = params->timeouts[state];
232255cf3c4Srmind break;
233*d6939920Srmind case IPPROTO_GRE:
234*d6939920Srmind params = npf->params[NPF_PARAMS_GENERIC_STATE];
235*d6939920Srmind timeout = params->gre_timeout;
236*d6939920Srmind break;
237255cf3c4Srmind default:
238255cf3c4Srmind KASSERT(false);
23997b932f1Srmind }
240255cf3c4Srmind return timeout;
24197b932f1Srmind }
24297b932f1Srmind
24397b932f1Srmind void
npf_state_dump(const npf_state_t * nst)244f75d4435Srmind npf_state_dump(const npf_state_t *nst)
24597b932f1Srmind {
24634931850Syamt #if defined(DDB) || defined(_NPF_TESTING)
247f75d4435Srmind const npf_tcpstate_t *fst = &nst->nst_tcpst[0];
248f75d4435Srmind const npf_tcpstate_t *tst = &nst->nst_tcpst[1];
24997b932f1Srmind
25097b932f1Srmind printf("\tstate (%p) %d:\n\t\t"
251255cf3c4Srmind "F { end %u maxend %u mwin %u wscale %u }\n\t\t"
252255cf3c4Srmind "T { end %u maxend %u mwin %u wscale %u }\n",
25397b932f1Srmind nst, nst->nst_state,
254255cf3c4Srmind fst->nst_end, fst->nst_maxend, fst->nst_maxwin, fst->nst_wscale,
255255cf3c4Srmind tst->nst_end, tst->nst_maxend, tst->nst_maxwin, tst->nst_wscale
25697b932f1Srmind );
25797b932f1Srmind #endif
25834931850Syamt }
25961ec0f9cSrmind
260c0ea6c8dSchristos #if defined(_NPF_TESTING)
26161ec0f9cSrmind void
npf_state_setsampler(void (* func)(npf_state_t *,bool))26261ec0f9cSrmind npf_state_setsampler(void (*func)(npf_state_t *, bool))
26361ec0f9cSrmind {
26461ec0f9cSrmind npf_state_sample = func;
26561ec0f9cSrmind }
26661ec0f9cSrmind #endif
267