1 1.1 rmind /*- 2 1.8 rmind * Copyright (c) 2010-2012 The NetBSD Foundation, Inc. 3 1.1 rmind * All rights reserved. 4 1.1 rmind * 5 1.1 rmind * This material is based upon work partially supported by The 6 1.1 rmind * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. 7 1.1 rmind * 8 1.1 rmind * Redistribution and use in source and binary forms, with or without 9 1.1 rmind * modification, are permitted provided that the following conditions 10 1.1 rmind * are met: 11 1.1 rmind * 1. Redistributions of source code must retain the above copyright 12 1.1 rmind * notice, this list of conditions and the following disclaimer. 13 1.1 rmind * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 rmind * notice, this list of conditions and the following disclaimer in the 15 1.1 rmind * documentation and/or other materials provided with the distribution. 16 1.1 rmind * 17 1.1 rmind * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 1.1 rmind * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 1.1 rmind * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 1.1 rmind * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 1.1 rmind * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 1.1 rmind * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 1.1 rmind * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 1.1 rmind * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 1.1 rmind * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 1.1 rmind * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 1.1 rmind * POSSIBILITY OF SUCH DAMAGE. 28 1.1 rmind */ 29 1.1 rmind 30 1.1 rmind /* 31 1.16 rmind * NPF state engine to track connection. 32 1.1 rmind */ 33 1.1 rmind 34 1.18 christos #ifdef _KERNEL 35 1.1 rmind #include <sys/cdefs.h> 36 1.23 rmind __KERNEL_RCSID(0, "$NetBSD: npf_state.c,v 1.23 2020/05/30 14:16:56 rmind Exp $"); 37 1.1 rmind 38 1.1 rmind #include <sys/param.h> 39 1.1 rmind #include <sys/systm.h> 40 1.1 rmind #include <sys/mutex.h> 41 1.18 christos #endif 42 1.1 rmind 43 1.1 rmind #include "npf_impl.h" 44 1.1 rmind 45 1.6 rmind /* 46 1.16 rmind * Generic connection states and timeout table. 47 1.6 rmind * 48 1.13 rmind * Note: used for connection-less protocols. 49 1.6 rmind */ 50 1.6 rmind 51 1.16 rmind #define NPF_ANY_CONN_CLOSED 0 52 1.16 rmind #define NPF_ANY_CONN_NEW 1 53 1.16 rmind #define NPF_ANY_CONN_ESTABLISHED 2 54 1.16 rmind #define NPF_ANY_CONN_NSTATES 3 55 1.16 rmind 56 1.22 rmind /* 57 1.22 rmind * Parameters. 58 1.22 rmind */ 59 1.22 rmind typedef struct { 60 1.22 rmind int timeouts[NPF_ANY_CONN_NSTATES]; 61 1.23 rmind int gre_timeout; 62 1.22 rmind } npf_state_params_t; 63 1.22 rmind 64 1.22 rmind /* 65 1.22 rmind * Generic FSM. 66 1.22 rmind */ 67 1.16 rmind static const uint8_t npf_generic_fsm[NPF_ANY_CONN_NSTATES][2] = { 68 1.16 rmind [NPF_ANY_CONN_CLOSED] = { 69 1.16 rmind [NPF_FLOW_FORW] = NPF_ANY_CONN_NEW, 70 1.6 rmind }, 71 1.16 rmind [NPF_ANY_CONN_NEW] = { 72 1.16 rmind [NPF_FLOW_FORW] = NPF_ANY_CONN_NEW, 73 1.16 rmind [NPF_FLOW_BACK] = NPF_ANY_CONN_ESTABLISHED, 74 1.6 rmind }, 75 1.16 rmind [NPF_ANY_CONN_ESTABLISHED] = { 76 1.16 rmind [NPF_FLOW_FORW] = NPF_ANY_CONN_ESTABLISHED, 77 1.16 rmind [NPF_FLOW_BACK] = NPF_ANY_CONN_ESTABLISHED, 78 1.6 rmind }, 79 1.3 rmind }; 80 1.1 rmind 81 1.8 rmind /* 82 1.12 rmind * State sampler for debugging. 83 1.12 rmind */ 84 1.21 christos #if defined(_NPF_TESTING) 85 1.12 rmind static void (*npf_state_sample)(npf_state_t *, bool) = NULL; 86 1.12 rmind #define NPF_STATE_SAMPLE(n, r) if (npf_state_sample) (*npf_state_sample)(n, r); 87 1.12 rmind #else 88 1.12 rmind #define NPF_STATE_SAMPLE(n, r) 89 1.12 rmind #endif 90 1.12 rmind 91 1.22 rmind void 92 1.22 rmind npf_state_sysinit(npf_t *npf) 93 1.22 rmind { 94 1.22 rmind npf_state_params_t *params = npf_param_allocgroup(npf, 95 1.22 rmind NPF_PARAMS_GENERIC_STATE, sizeof(npf_state_params_t)); 96 1.22 rmind npf_param_t param_map[] = { 97 1.22 rmind /* 98 1.22 rmind * Generic timeout (in seconds). 99 1.22 rmind */ 100 1.22 rmind { 101 1.22 rmind "state.generic.timeout.closed", 102 1.22 rmind ¶ms->timeouts[NPF_ANY_CONN_CLOSED], 103 1.22 rmind .default_val = 0, 104 1.22 rmind .min = 0, .max = INT_MAX 105 1.22 rmind }, 106 1.22 rmind { 107 1.22 rmind "state.generic.timeout.new", 108 1.22 rmind ¶ms->timeouts[NPF_ANY_CONN_NEW], 109 1.22 rmind .default_val = 30, 110 1.22 rmind .min = 0, .max = INT_MAX 111 1.22 rmind }, 112 1.22 rmind { 113 1.22 rmind "state.generic.timeout.established", 114 1.22 rmind ¶ms->timeouts[NPF_ANY_CONN_ESTABLISHED], 115 1.22 rmind .default_val = 60, 116 1.22 rmind .min = 0, .max = INT_MAX 117 1.22 rmind }, 118 1.23 rmind { 119 1.23 rmind "state.generic.timeout.gre", 120 1.23 rmind ¶ms->gre_timeout, 121 1.23 rmind .default_val = 24 * 60 * 60, 122 1.23 rmind .min = 0, .max = INT_MAX 123 1.23 rmind }, 124 1.22 rmind }; 125 1.22 rmind npf_param_register(npf, param_map, __arraycount(param_map)); 126 1.22 rmind npf_state_tcp_sysinit(npf); 127 1.22 rmind } 128 1.22 rmind 129 1.22 rmind void 130 1.22 rmind npf_state_sysfini(npf_t *npf) 131 1.22 rmind { 132 1.22 rmind const size_t len = sizeof(npf_state_params_t); 133 1.22 rmind npf_param_freegroup(npf, NPF_PARAMS_GENERIC_STATE, len); 134 1.22 rmind npf_state_tcp_sysfini(npf); 135 1.22 rmind } 136 1.22 rmind 137 1.12 rmind /* 138 1.8 rmind * npf_state_init: initialise the state structure. 139 1.8 rmind * 140 1.8 rmind * Should normally be called on a first packet, which also determines the 141 1.8 rmind * direction in a case of connection-orientated protocol. Returns true on 142 1.8 rmind * success and false otherwise (e.g. if protocol is not supported). 143 1.8 rmind */ 144 1.1 rmind bool 145 1.17 rmind npf_state_init(npf_cache_t *npc, npf_state_t *nst) 146 1.1 rmind { 147 1.14 rmind const int proto = npc->npc_proto; 148 1.6 rmind bool ret; 149 1.1 rmind 150 1.5 zoltan KASSERT(npf_iscached(npc, NPC_IP46)); 151 1.5 zoltan KASSERT(npf_iscached(npc, NPC_LAYER4)); 152 1.2 rmind 153 1.6 rmind memset(nst, 0, sizeof(npf_state_t)); 154 1.2 rmind 155 1.6 rmind switch (proto) { 156 1.6 rmind case IPPROTO_TCP: 157 1.6 rmind /* Pass to TCP state tracking engine. */ 158 1.17 rmind ret = npf_state_tcp(npc, nst, NPF_FLOW_FORW); 159 1.6 rmind break; 160 1.6 rmind case IPPROTO_UDP: 161 1.6 rmind case IPPROTO_ICMP: 162 1.23 rmind case IPPROTO_GRE: 163 1.6 rmind /* Generic. */ 164 1.6 rmind nst->nst_state = npf_generic_fsm[nst->nst_state][NPF_FLOW_FORW]; 165 1.6 rmind ret = true; 166 1.6 rmind break; 167 1.6 rmind default: 168 1.6 rmind ret = false; 169 1.1 rmind } 170 1.11 rmind NPF_STATE_SAMPLE(nst, ret); 171 1.6 rmind return ret; 172 1.1 rmind } 173 1.1 rmind 174 1.1 rmind void 175 1.1 rmind npf_state_destroy(npf_state_t *nst) 176 1.1 rmind { 177 1.6 rmind nst->nst_state = 0; 178 1.1 rmind } 179 1.1 rmind 180 1.8 rmind /* 181 1.8 rmind * npf_state_inspect: inspect the packet according to the protocol state. 182 1.8 rmind * 183 1.8 rmind * Return true if packet is considered to match the state (e.g. for TCP, 184 1.8 rmind * the packet belongs to the tracked connection) and false otherwise. 185 1.8 rmind */ 186 1.1 rmind bool 187 1.23 rmind npf_state_inspect(npf_cache_t *npc, npf_state_t *nst, const npf_flow_t flow) 188 1.1 rmind { 189 1.14 rmind const int proto = npc->npc_proto; 190 1.1 rmind bool ret; 191 1.1 rmind 192 1.1 rmind switch (proto) { 193 1.1 rmind case IPPROTO_TCP: 194 1.6 rmind /* Pass to TCP state tracking engine. */ 195 1.23 rmind ret = npf_state_tcp(npc, nst, flow); 196 1.6 rmind break; 197 1.6 rmind case IPPROTO_UDP: 198 1.6 rmind case IPPROTO_ICMP: 199 1.23 rmind case IPPROTO_GRE: 200 1.6 rmind /* Generic. */ 201 1.23 rmind nst->nst_state = npf_generic_fsm[nst->nst_state][flow]; 202 1.6 rmind ret = true; 203 1.1 rmind break; 204 1.1 rmind default: 205 1.6 rmind ret = false; 206 1.1 rmind } 207 1.11 rmind NPF_STATE_SAMPLE(nst, ret); 208 1.6 rmind 209 1.1 rmind return ret; 210 1.1 rmind } 211 1.1 rmind 212 1.3 rmind /* 213 1.22 rmind * npf_state_etime: return the expiration time depending on the state. 214 1.3 rmind */ 215 1.1 rmind int 216 1.22 rmind npf_state_etime(npf_t *npf, const npf_state_t *nst, const int proto) 217 1.1 rmind { 218 1.22 rmind const npf_state_params_t *params; 219 1.22 rmind const unsigned state = nst->nst_state; 220 1.6 rmind int timeout = 0; 221 1.1 rmind 222 1.6 rmind switch (proto) { 223 1.6 rmind case IPPROTO_TCP: 224 1.6 rmind /* Pass to TCP state tracking engine. */ 225 1.22 rmind timeout = npf_state_tcp_timeout(npf, nst); 226 1.6 rmind break; 227 1.6 rmind case IPPROTO_UDP: 228 1.6 rmind case IPPROTO_ICMP: 229 1.6 rmind /* Generic. */ 230 1.22 rmind params = npf->params[NPF_PARAMS_GENERIC_STATE]; 231 1.22 rmind timeout = params->timeouts[state]; 232 1.6 rmind break; 233 1.23 rmind case IPPROTO_GRE: 234 1.23 rmind params = npf->params[NPF_PARAMS_GENERIC_STATE]; 235 1.23 rmind timeout = params->gre_timeout; 236 1.23 rmind break; 237 1.6 rmind default: 238 1.6 rmind KASSERT(false); 239 1.1 rmind } 240 1.6 rmind return timeout; 241 1.1 rmind } 242 1.1 rmind 243 1.1 rmind void 244 1.9 rmind npf_state_dump(const npf_state_t *nst) 245 1.1 rmind { 246 1.4 yamt #if defined(DDB) || defined(_NPF_TESTING) 247 1.9 rmind const npf_tcpstate_t *fst = &nst->nst_tcpst[0]; 248 1.9 rmind const npf_tcpstate_t *tst = &nst->nst_tcpst[1]; 249 1.1 rmind 250 1.1 rmind printf("\tstate (%p) %d:\n\t\t" 251 1.6 rmind "F { end %u maxend %u mwin %u wscale %u }\n\t\t" 252 1.6 rmind "T { end %u maxend %u mwin %u wscale %u }\n", 253 1.1 rmind nst, nst->nst_state, 254 1.6 rmind fst->nst_end, fst->nst_maxend, fst->nst_maxwin, fst->nst_wscale, 255 1.6 rmind tst->nst_end, tst->nst_maxend, tst->nst_maxwin, tst->nst_wscale 256 1.1 rmind ); 257 1.4 yamt #endif 258 1.1 rmind } 259 1.12 rmind 260 1.21 christos #if defined(_NPF_TESTING) 261 1.12 rmind void 262 1.12 rmind npf_state_setsampler(void (*func)(npf_state_t *, bool)) 263 1.12 rmind { 264 1.12 rmind npf_state_sample = func; 265 1.12 rmind } 266 1.12 rmind #endif 267