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