npf_alg.c revision 1.10
1/* $NetBSD: npf_alg.c,v 1.10 2013/12/06 01:33:37 rmind Exp $ */ 2 3/*- 4 * Copyright (c) 2010-2013 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 interface for the Application Level Gateways (ALGs). 34 */ 35 36#include <sys/cdefs.h> 37__KERNEL_RCSID(0, "$NetBSD: npf_alg.c,v 1.10 2013/12/06 01:33:37 rmind Exp $"); 38 39#include <sys/param.h> 40#include <sys/types.h> 41 42#include <sys/kmem.h> 43#include <sys/pserialize.h> 44#include <sys/mutex.h> 45#include <net/pfil.h> 46#include <sys/module.h> 47 48#include "npf_impl.h" 49 50/* 51 * NAT ALG description structure. For more compact use of cache, 52 * the functions are separated in their own arrays. The number of 53 * ALGs is expected to be very small. 54 */ 55 56struct npf_alg { 57 const char * na_name; 58 u_int na_slot; 59}; 60 61/* List of ALGs and the count. */ 62static pserialize_t alg_psz __cacheline_aligned; 63static npf_alg_t alg_list[NPF_MAX_ALGS] __read_mostly; 64static u_int alg_count __read_mostly; 65 66/* Session, matching and translation functions. */ 67static npf_alg_sfunc_t alg_sfunc[NPF_MAX_ALGS] __read_mostly; 68static npf_alg_func_t alg_mfunc[NPF_MAX_ALGS] __read_mostly; 69static npf_alg_func_t alg_tfunc[NPF_MAX_ALGS] __read_mostly; 70 71static const char alg_prefix[] = "npf_alg_"; 72#define NPF_EXT_PREFLEN (sizeof(alg_prefix) - 1) 73 74void 75npf_alg_sysinit(void) 76{ 77 alg_psz = pserialize_create(); 78 memset(&alg_list, 0, sizeof(alg_list)); 79 alg_count = 0; 80 81 memset(&alg_mfunc, 0, sizeof(alg_mfunc)); 82 memset(&alg_tfunc, 0, sizeof(alg_tfunc)); 83 memset(&alg_sfunc, 0, sizeof(alg_sfunc)); 84} 85 86void 87npf_alg_sysfini(void) 88{ 89 pserialize_destroy(alg_psz); 90} 91 92static npf_alg_t * 93npf_alg_lookup(const char *name) 94{ 95 KASSERT(npf_config_locked_p()); 96 97 for (u_int i = 0; i < alg_count; i++) { 98 npf_alg_t *alg = &alg_list[i]; 99 const char *aname = alg->na_name; 100 101 if (aname && strcmp(aname, name) == 0) 102 return alg; 103 } 104 return NULL; 105} 106 107npf_alg_t * 108npf_alg_construct(const char *name) 109{ 110 npf_alg_t *alg; 111 112 npf_config_enter(); 113 if ((alg = npf_alg_lookup(name)) == NULL) { 114 char modname[NPF_EXT_PREFLEN + 64]; 115 snprintf(modname, sizeof(modname), "%s%s", alg_prefix, name); 116 npf_config_exit(); 117 118 if (module_autoload(modname, MODULE_CLASS_MISC) != 0) { 119 return NULL; 120 } 121 npf_config_enter(); 122 alg = npf_alg_lookup(name); 123 } 124 npf_config_exit(); 125 return alg; 126} 127 128/* 129 * npf_alg_register: register application-level gateway. 130 */ 131npf_alg_t * 132npf_alg_register(const char *name, npf_alg_func_t mfunc, npf_alg_func_t tfunc, 133 npf_alg_sfunc_t sfunc) 134{ 135 npf_alg_t *alg; 136 u_int i; 137 138 npf_config_enter(); 139 if (npf_alg_lookup(name) != NULL) { 140 npf_config_exit(); 141 return NULL; 142 } 143 144 /* Find a spare slot. */ 145 for (i = 0; i < NPF_MAX_ALGS; i++) { 146 alg = &alg_list[i]; 147 if (alg->na_name == NULL) { 148 break; 149 } 150 } 151 if (i == NPF_MAX_ALGS) { 152 npf_config_exit(); 153 return NULL; 154 } 155 156 /* Register the ALG. */ 157 alg->na_name = name; 158 alg->na_slot = i; 159 160 /* Assign the functions. */ 161 alg_mfunc[i] = mfunc; 162 alg_tfunc[i] = tfunc; 163 alg_sfunc[i] = sfunc; 164 165 alg_count = MAX(alg_count, i + 1); 166 npf_config_exit(); 167 return alg; 168} 169 170/* 171 * npf_alg_unregister: unregister application-level gateway. 172 */ 173int 174npf_alg_unregister(npf_alg_t *alg) 175{ 176 u_int i = alg->na_slot; 177 178 /* Deactivate the functions first. */ 179 npf_config_enter(); 180 alg_mfunc[i] = NULL; 181 alg_tfunc[i] = NULL; 182 alg_sfunc[i] = NULL; 183 pserialize_perform(alg_psz); 184 185 /* Finally, unregister the ALG. */ 186 npf_ruleset_freealg(npf_config_natset(), alg); 187 alg->na_name = NULL; 188 npf_config_exit(); 189 190 return 0; 191} 192 193/* 194 * npf_alg_match: call ALG matching inspectors, determine if any ALG matches. 195 */ 196bool 197npf_alg_match(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, int di) 198{ 199 bool match = false; 200 int s; 201 202 s = pserialize_read_enter(); 203 for (u_int i = 0; i < alg_count; i++) { 204 npf_alg_func_t func = alg_mfunc[i]; 205 206 if (func && func(npc, nbuf, nt, di)) { 207 match = true; 208 break; 209 } 210 } 211 pserialize_read_exit(s); 212 return match; 213} 214 215/* 216 * npf_alg_exec: execute ALG hooks for translation. 217 */ 218void 219npf_alg_exec(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, bool forw) 220{ 221 int s; 222 223 s = pserialize_read_enter(); 224 for (u_int i = 0; i < alg_count; i++) { 225 npf_alg_func_t func; 226 227 if ((func = alg_tfunc[i]) != NULL) { 228 func(npc, nbuf, nt, (int)forw); 229 } 230 } 231 pserialize_read_exit(s); 232} 233 234npf_session_t * 235npf_alg_session(npf_cache_t *npc, nbuf_t *nbuf, int di) 236{ 237 npf_session_t *se = NULL; 238 int s; 239 240 s = pserialize_read_enter(); 241 for (u_int i = 0; i < alg_count; i++) { 242 npf_alg_sfunc_t func = alg_sfunc[i]; 243 244 if (func && (se = func(npc, nbuf, di)) != NULL) { 245 break; 246 } 247 } 248 pserialize_read_exit(s); 249 return se; 250} 251