npf_alg.c revision 1.9
1/* $NetBSD: npf_alg.c,v 1.9 2013/06/02 02:20:04 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.9 2013/06/02 02:20:04 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#define NPF_MAX_ALGS 8 62 63/* List of ALGs and the count. */ 64static pserialize_t alg_psz __cacheline_aligned; 65static npf_alg_t alg_list[NPF_MAX_ALGS] __read_mostly; 66static u_int alg_count __read_mostly; 67 68/* Session, matching and translation functions. */ 69static npf_alg_sfunc_t alg_sfunc[NPF_MAX_ALGS] __read_mostly; 70static npf_alg_func_t alg_mfunc[NPF_MAX_ALGS] __read_mostly; 71static npf_alg_func_t alg_tfunc[NPF_MAX_ALGS] __read_mostly; 72 73static const char alg_prefix[] = "npf_alg_"; 74#define NPF_EXT_PREFLEN (sizeof(alg_prefix) - 1) 75 76void 77npf_alg_sysinit(void) 78{ 79 alg_psz = pserialize_create(); 80 memset(&alg_list, 0, sizeof(alg_list)); 81 alg_count = 0; 82 83 memset(&alg_mfunc, 0, sizeof(alg_mfunc)); 84 memset(&alg_tfunc, 0, sizeof(alg_tfunc)); 85 memset(&alg_sfunc, 0, sizeof(alg_sfunc)); 86} 87 88void 89npf_alg_sysfini(void) 90{ 91 pserialize_destroy(alg_psz); 92} 93 94static npf_alg_t * 95npf_alg_lookup(const char *name) 96{ 97 KASSERT(npf_config_locked_p()); 98 99 for (u_int i = 0; i < alg_count; i++) { 100 npf_alg_t *alg = &alg_list[i]; 101 const char *aname = alg->na_name; 102 103 if (aname && strcmp(aname, name) == 0) 104 return alg; 105 } 106 return NULL; 107} 108 109npf_alg_t * 110npf_alg_construct(const char *name) 111{ 112 npf_alg_t *alg; 113 114 npf_config_enter(); 115 if ((alg = npf_alg_lookup(name)) == NULL) { 116 char modname[NPF_EXT_PREFLEN + 64]; 117 snprintf(modname, sizeof(modname), "%s%s", alg_prefix, name); 118 npf_config_exit(); 119 120 if (module_autoload(modname, MODULE_CLASS_MISC) != 0) { 121 return NULL; 122 } 123 npf_config_enter(); 124 alg = npf_alg_lookup(name); 125 } 126 npf_config_exit(); 127 return alg; 128} 129 130/* 131 * npf_alg_register: register application-level gateway. 132 */ 133npf_alg_t * 134npf_alg_register(const char *name, npf_alg_func_t mfunc, npf_alg_func_t tfunc, 135 npf_alg_sfunc_t sfunc) 136{ 137 npf_alg_t *alg; 138 u_int i; 139 140 npf_config_enter(); 141 if (npf_alg_lookup(name) != NULL) { 142 npf_config_exit(); 143 return NULL; 144 } 145 146 /* Find a spare slot. */ 147 for (i = 0; i < NPF_MAX_ALGS; i++) { 148 alg = &alg_list[i]; 149 if (alg->na_name == NULL) { 150 break; 151 } 152 } 153 if (i == NPF_MAX_ALGS) { 154 npf_config_exit(); 155 return NULL; 156 } 157 158 /* Register the ALG. */ 159 alg->na_name = name; 160 alg->na_slot = i; 161 162 /* Assign the functions. */ 163 alg_mfunc[i] = mfunc; 164 alg_tfunc[i] = tfunc; 165 alg_sfunc[i] = sfunc; 166 167 alg_count = MAX(alg_count, i + 1); 168 npf_config_exit(); 169 return alg; 170} 171 172/* 173 * npf_alg_unregister: unregister application-level gateway. 174 */ 175int 176npf_alg_unregister(npf_alg_t *alg) 177{ 178 u_int i = alg->na_slot; 179 180 /* Deactivate the functions first. */ 181 npf_config_enter(); 182 alg_mfunc[i] = NULL; 183 alg_tfunc[i] = NULL; 184 alg_sfunc[i] = NULL; 185 pserialize_perform(alg_psz); 186 187 /* Finally, unregister the ALG. */ 188 npf_ruleset_freealg(npf_config_natset(), alg); 189 alg->na_name = NULL; 190 npf_config_exit(); 191 192 return 0; 193} 194 195/* 196 * npf_alg_match: call ALG matching inspectors, determine if any ALG matches. 197 */ 198bool 199npf_alg_match(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, int di) 200{ 201 bool match = false; 202 int s; 203 204 s = pserialize_read_enter(); 205 for (u_int i = 0; i < alg_count; i++) { 206 npf_alg_func_t func = alg_mfunc[i]; 207 208 if (func && func(npc, nbuf, nt, di)) { 209 match = true; 210 break; 211 } 212 } 213 pserialize_read_exit(s); 214 return match; 215} 216 217/* 218 * npf_alg_exec: execute ALG hooks for translation. 219 */ 220void 221npf_alg_exec(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, int di) 222{ 223 int s; 224 225 s = pserialize_read_enter(); 226 for (u_int i = 0; i < alg_count; i++) { 227 npf_alg_func_t func; 228 229 if ((func = alg_tfunc[i]) != NULL) { 230 func(npc, nbuf, nt, di); 231 } 232 } 233 pserialize_read_exit(s); 234} 235 236npf_session_t * 237npf_alg_session(npf_cache_t *npc, nbuf_t *nbuf, int di) 238{ 239 npf_session_t *se = NULL; 240 int s; 241 242 s = pserialize_read_enter(); 243 for (u_int i = 0; i < alg_count; i++) { 244 npf_alg_sfunc_t func = alg_sfunc[i]; 245 246 if (func && (se = func(npc, nbuf, di)) != NULL) { 247 break; 248 } 249 } 250 pserialize_read_exit(s); 251 return se; 252} 253