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