1 /* $NetBSD: npf_state.c,v 1.15 2013/11/04 22:17:21 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 sessions. 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: npf_state.c,v 1.15 2013/11/04 22:17:21 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 session states and timeout table. 48 * 49 * Note: used for connection-less protocols. 50 */ 51 52 #define NPF_ANY_SESSION_CLOSED 0 53 #define NPF_ANY_SESSION_NEW 1 54 #define NPF_ANY_SESSION_ESTABLISHED 2 55 #define NPF_ANY_SESSION_NSTATES 3 56 57 static const uint8_t npf_generic_fsm[NPF_ANY_SESSION_NSTATES][2] = { 58 [NPF_ANY_SESSION_CLOSED] = { 59 [NPF_FLOW_FORW] = NPF_ANY_SESSION_NEW, 60 }, 61 [NPF_ANY_SESSION_NEW] = { 62 [NPF_FLOW_FORW] = NPF_ANY_SESSION_NEW, 63 [NPF_FLOW_BACK] = NPF_ANY_SESSION_ESTABLISHED, 64 }, 65 [NPF_ANY_SESSION_ESTABLISHED] = { 66 [NPF_FLOW_FORW] = NPF_ANY_SESSION_ESTABLISHED, 67 [NPF_FLOW_BACK] = NPF_ANY_SESSION_ESTABLISHED, 68 }, 69 }; 70 71 static u_int npf_generic_timeout[] __read_mostly = { 72 [NPF_ANY_SESSION_CLOSED] = 0, 73 [NPF_ANY_SESSION_NEW] = 30, 74 [NPF_ANY_SESSION_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, nbuf_t *nbuf, 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 mutex_init(&nst->nst_lock, MUTEX_DEFAULT, IPL_SOFTNET); 105 106 switch (proto) { 107 case IPPROTO_TCP: 108 /* Pass to TCP state tracking engine. */ 109 ret = npf_state_tcp(npc, nbuf, 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 mutex_destroy(&nst->nst_lock); 129 } 130 131 /* 132 * npf_state_inspect: inspect the packet according to the protocol state. 133 * 134 * Return true if packet is considered to match the state (e.g. for TCP, 135 * the packet belongs to the tracked connection) and false otherwise. 136 */ 137 bool 138 npf_state_inspect(npf_cache_t *npc, nbuf_t *nbuf, 139 npf_state_t *nst, const bool forw) 140 { 141 const int proto = npc->npc_proto; 142 const int di = forw ? NPF_FLOW_FORW : NPF_FLOW_BACK; 143 bool ret; 144 145 mutex_enter(&nst->nst_lock); 146 switch (proto) { 147 case IPPROTO_TCP: 148 /* Pass to TCP state tracking engine. */ 149 ret = npf_state_tcp(npc, nbuf, nst, di); 150 break; 151 case IPPROTO_UDP: 152 case IPPROTO_ICMP: 153 /* Generic. */ 154 nst->nst_state = npf_generic_fsm[nst->nst_state][di]; 155 ret = true; 156 break; 157 default: 158 ret = false; 159 } 160 NPF_STATE_SAMPLE(nst, ret); 161 mutex_exit(&nst->nst_lock); 162 163 return ret; 164 } 165 166 /* 167 * npf_state_etime: return session expiration time according to the state. 168 */ 169 int 170 npf_state_etime(const npf_state_t *nst, const int proto) 171 { 172 const u_int state = nst->nst_state; 173 int timeout = 0; 174 175 switch (proto) { 176 case IPPROTO_TCP: 177 /* Pass to TCP state tracking engine. */ 178 timeout = npf_state_tcp_timeout(nst); 179 break; 180 case IPPROTO_UDP: 181 case IPPROTO_ICMP: 182 /* Generic. */ 183 timeout = npf_generic_timeout[state]; 184 break; 185 default: 186 KASSERT(false); 187 } 188 return timeout; 189 } 190 191 void 192 npf_state_dump(const npf_state_t *nst) 193 { 194 #if defined(DDB) || defined(_NPF_TESTING) 195 const npf_tcpstate_t *fst = &nst->nst_tcpst[0]; 196 const npf_tcpstate_t *tst = &nst->nst_tcpst[1]; 197 198 printf("\tstate (%p) %d:\n\t\t" 199 "F { end %u maxend %u mwin %u wscale %u }\n\t\t" 200 "T { end %u maxend %u mwin %u wscale %u }\n", 201 nst, nst->nst_state, 202 fst->nst_end, fst->nst_maxend, fst->nst_maxwin, fst->nst_wscale, 203 tst->nst_end, tst->nst_maxend, tst->nst_maxwin, tst->nst_wscale 204 ); 205 #endif 206 } 207 208 #if defined(_NPF_TESTING) 209 void 210 npf_state_setsampler(void (*func)(npf_state_t *, bool)) 211 { 212 npf_state_sample = func; 213 } 214 #endif 215