1 /* $NetBSD: npf_state.c,v 1.17 2014/07/20 00:37:41 rmind 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 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: npf_state.c,v 1.17 2014/07/20 00:37:41 rmind Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 42 #include <sys/mutex.h> 43 44 #include "npf_impl.h" 45 46 /* 47 * Generic connection states and timeout table. 48 * 49 * Note: used for connection-less protocols. 50 */ 51 52 #define NPF_ANY_CONN_CLOSED 0 53 #define NPF_ANY_CONN_NEW 1 54 #define NPF_ANY_CONN_ESTABLISHED 2 55 #define NPF_ANY_CONN_NSTATES 3 56 57 static const uint8_t npf_generic_fsm[NPF_ANY_CONN_NSTATES][2] = { 58 [NPF_ANY_CONN_CLOSED] = { 59 [NPF_FLOW_FORW] = NPF_ANY_CONN_NEW, 60 }, 61 [NPF_ANY_CONN_NEW] = { 62 [NPF_FLOW_FORW] = NPF_ANY_CONN_NEW, 63 [NPF_FLOW_BACK] = NPF_ANY_CONN_ESTABLISHED, 64 }, 65 [NPF_ANY_CONN_ESTABLISHED] = { 66 [NPF_FLOW_FORW] = NPF_ANY_CONN_ESTABLISHED, 67 [NPF_FLOW_BACK] = NPF_ANY_CONN_ESTABLISHED, 68 }, 69 }; 70 71 static u_int npf_generic_timeout[] __read_mostly = { 72 [NPF_ANY_CONN_CLOSED] = 0, 73 [NPF_ANY_CONN_NEW] = 30, 74 [NPF_ANY_CONN_ESTABLISHED] = 60, 75 }; 76 77 /* 78 * State sampler for debugging. 79 */ 80 #if defined(_NPF_TESTING) 81 static void (*npf_state_sample)(npf_state_t *, bool) = NULL; 82 #define NPF_STATE_SAMPLE(n, r) if (npf_state_sample) (*npf_state_sample)(n, r); 83 #else 84 #define NPF_STATE_SAMPLE(n, r) 85 #endif 86 87 /* 88 * npf_state_init: initialise the state structure. 89 * 90 * Should normally be called on a first packet, which also determines the 91 * direction in a case of connection-orientated protocol. Returns true on 92 * success and false otherwise (e.g. if protocol is not supported). 93 */ 94 bool 95 npf_state_init(npf_cache_t *npc, npf_state_t *nst) 96 { 97 const int proto = npc->npc_proto; 98 bool ret; 99 100 KASSERT(npf_iscached(npc, NPC_IP46)); 101 KASSERT(npf_iscached(npc, NPC_LAYER4)); 102 103 memset(nst, 0, sizeof(npf_state_t)); 104 105 switch (proto) { 106 case IPPROTO_TCP: 107 /* Pass to TCP state tracking engine. */ 108 ret = npf_state_tcp(npc, nst, NPF_FLOW_FORW); 109 break; 110 case IPPROTO_UDP: 111 case IPPROTO_ICMP: 112 /* Generic. */ 113 nst->nst_state = npf_generic_fsm[nst->nst_state][NPF_FLOW_FORW]; 114 ret = true; 115 break; 116 default: 117 ret = false; 118 } 119 NPF_STATE_SAMPLE(nst, ret); 120 return ret; 121 } 122 123 void 124 npf_state_destroy(npf_state_t *nst) 125 { 126 nst->nst_state = 0; 127 } 128 129 /* 130 * npf_state_inspect: inspect the packet according to the protocol state. 131 * 132 * Return true if packet is considered to match the state (e.g. for TCP, 133 * the packet belongs to the tracked connection) and false otherwise. 134 */ 135 bool 136 npf_state_inspect(npf_cache_t *npc, npf_state_t *nst, const bool forw) 137 { 138 const int proto = npc->npc_proto; 139 const int di = forw ? NPF_FLOW_FORW : NPF_FLOW_BACK; 140 bool ret; 141 142 switch (proto) { 143 case IPPROTO_TCP: 144 /* Pass to TCP state tracking engine. */ 145 ret = npf_state_tcp(npc, nst, di); 146 break; 147 case IPPROTO_UDP: 148 case IPPROTO_ICMP: 149 /* Generic. */ 150 nst->nst_state = npf_generic_fsm[nst->nst_state][di]; 151 ret = true; 152 break; 153 default: 154 ret = false; 155 } 156 NPF_STATE_SAMPLE(nst, ret); 157 158 return ret; 159 } 160 161 /* 162 * npf_state_etime: return connection expiration time according to the state. 163 */ 164 int 165 npf_state_etime(const npf_state_t *nst, const int proto) 166 { 167 const u_int state = nst->nst_state; 168 int timeout = 0; 169 170 switch (proto) { 171 case IPPROTO_TCP: 172 /* Pass to TCP state tracking engine. */ 173 timeout = npf_state_tcp_timeout(nst); 174 break; 175 case IPPROTO_UDP: 176 case IPPROTO_ICMP: 177 /* Generic. */ 178 timeout = npf_generic_timeout[state]; 179 break; 180 default: 181 KASSERT(false); 182 } 183 return timeout; 184 } 185 186 void 187 npf_state_dump(const npf_state_t *nst) 188 { 189 #if defined(DDB) || defined(_NPF_TESTING) 190 const npf_tcpstate_t *fst = &nst->nst_tcpst[0]; 191 const npf_tcpstate_t *tst = &nst->nst_tcpst[1]; 192 193 printf("\tstate (%p) %d:\n\t\t" 194 "F { end %u maxend %u mwin %u wscale %u }\n\t\t" 195 "T { end %u maxend %u mwin %u wscale %u }\n", 196 nst, nst->nst_state, 197 fst->nst_end, fst->nst_maxend, fst->nst_maxwin, fst->nst_wscale, 198 tst->nst_end, tst->nst_maxend, tst->nst_maxwin, tst->nst_wscale 199 ); 200 #endif 201 } 202 203 #if defined(_NPF_TESTING) 204 void 205 npf_state_setsampler(void (*func)(npf_state_t *, bool)) 206 { 207 npf_state_sample = func; 208 } 209 #endif 210