Home | History | Annotate | Line # | Download | only in npf
npf_alg.c revision 1.15
      1 /*	$NetBSD: npf_alg.c,v 1.15 2014/08/11 23:48:01 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.15 2014/08/11 23:48:01 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 
     56 struct npf_alg {
     57 	const char *	na_name;
     58 	u_int		na_slot;
     59 };
     60 
     61 /* List of ALGs and the count. */
     62 static pserialize_t	alg_psz			__cacheline_aligned;
     63 static npf_alg_t	alg_list[NPF_MAX_ALGS]	__read_mostly;
     64 static u_int		alg_count		__read_mostly;
     65 
     66 /* Matching, inspection and translation functions. */
     67 static npfa_funcs_t	alg_funcs[NPF_MAX_ALGS]	__read_mostly;
     68 
     69 static const char	alg_prefix[] = "npf_alg_";
     70 #define	NPF_EXT_PREFLEN	(sizeof(alg_prefix) - 1)
     71 
     72 void
     73 npf_alg_sysinit(void)
     74 {
     75 	alg_psz = pserialize_create();
     76 	memset(alg_list, 0, sizeof(alg_list));
     77 	memset(alg_funcs, 0, sizeof(alg_funcs));
     78 	alg_count = 0;
     79 }
     80 
     81 void
     82 npf_alg_sysfini(void)
     83 {
     84 	pserialize_destroy(alg_psz);
     85 }
     86 
     87 static npf_alg_t *
     88 npf_alg_lookup(const char *name)
     89 {
     90 	KASSERT(npf_config_locked_p());
     91 
     92 	for (u_int i = 0; i < alg_count; i++) {
     93 		npf_alg_t *alg = &alg_list[i];
     94 		const char *aname = alg->na_name;
     95 
     96 		if (aname && strcmp(aname, name) == 0)
     97 			return alg;
     98 	}
     99 	return NULL;
    100 }
    101 
    102 npf_alg_t *
    103 npf_alg_construct(const char *name)
    104 {
    105 	npf_alg_t *alg;
    106 
    107 	npf_config_enter();
    108 	if ((alg = npf_alg_lookup(name)) == NULL) {
    109 		char modname[NPF_EXT_PREFLEN + 64];
    110 		snprintf(modname, sizeof(modname), "%s%s", alg_prefix, name);
    111 		npf_config_exit();
    112 
    113 		if (module_autoload(modname, MODULE_CLASS_MISC) != 0) {
    114 			return NULL;
    115 		}
    116 		npf_config_enter();
    117 		alg = npf_alg_lookup(name);
    118 	}
    119 	npf_config_exit();
    120 	return alg;
    121 }
    122 
    123 /*
    124  * npf_alg_register: register application-level gateway.
    125  */
    126 npf_alg_t *
    127 npf_alg_register(const char *name, const npfa_funcs_t *funcs)
    128 {
    129 	npf_alg_t *alg;
    130 	u_int i;
    131 
    132 	npf_config_enter();
    133 	if (npf_alg_lookup(name) != NULL) {
    134 		npf_config_exit();
    135 		return NULL;
    136 	}
    137 
    138 	/* Find a spare slot. */
    139 	for (i = 0; i < NPF_MAX_ALGS; i++) {
    140 		alg = &alg_list[i];
    141 		if (alg->na_name == NULL) {
    142 			break;
    143 		}
    144 	}
    145 	if (i == NPF_MAX_ALGS) {
    146 		npf_config_exit();
    147 		return NULL;
    148 	}
    149 
    150 	/* Register the ALG. */
    151 	alg->na_name = name;
    152 	alg->na_slot = i;
    153 
    154 	/* Assign the functions. */
    155 	alg_funcs[i].match = funcs->match;
    156 	alg_funcs[i].translate = funcs->translate;
    157 	alg_funcs[i].inspect = funcs->inspect;
    158 
    159 	alg_count = MAX(alg_count, i + 1);
    160 	npf_config_exit();
    161 
    162 	return alg;
    163 }
    164 
    165 /*
    166  * npf_alg_unregister: unregister application-level gateway.
    167  */
    168 int
    169 npf_alg_unregister(npf_alg_t *alg)
    170 {
    171 	u_int i = alg->na_slot;
    172 
    173 	/* Deactivate the functions first. */
    174 	npf_config_enter();
    175 	alg_funcs[i].match = NULL;
    176 	alg_funcs[i].translate = NULL;
    177 	alg_funcs[i].inspect = NULL;
    178 	pserialize_perform(alg_psz);
    179 
    180 	/* Finally, unregister the ALG. */
    181 	npf_ruleset_freealg(npf_config_natset(), alg);
    182 	alg->na_name = NULL;
    183 	npf_config_exit();
    184 
    185 	return 0;
    186 }
    187 
    188 /*
    189  * npf_alg_match: call ALG matching inspectors, determine if any ALG matches.
    190  */
    191 bool
    192 npf_alg_match(npf_cache_t *npc, npf_nat_t *nt, int di)
    193 {
    194 	bool match = false;
    195 	int s;
    196 
    197 	s = pserialize_read_enter();
    198 	for (u_int i = 0; i < alg_count; i++) {
    199 		const npfa_funcs_t *f = &alg_funcs[i];
    200 
    201 		if (f->match && f->match(npc, nt, di)) {
    202 			match = true;
    203 			break;
    204 		}
    205 	}
    206 	pserialize_read_exit(s);
    207 	return match;
    208 }
    209 
    210 /*
    211  * npf_alg_exec: execute ALG hooks for translation.
    212  */
    213 void
    214 npf_alg_exec(npf_cache_t *npc, npf_nat_t *nt, bool forw)
    215 {
    216 	int s;
    217 
    218 	s = pserialize_read_enter();
    219 	for (u_int i = 0; i < alg_count; i++) {
    220 		const npfa_funcs_t *f = &alg_funcs[i];
    221 
    222 		if (f->translate) {
    223 			f->translate(npc, nt, forw);
    224 		}
    225 	}
    226 	pserialize_read_exit(s);
    227 }
    228 
    229 npf_conn_t *
    230 npf_alg_conn(npf_cache_t *npc, int di)
    231 {
    232 	npf_conn_t *con = NULL;
    233 	int s;
    234 
    235 	s = pserialize_read_enter();
    236 	for (u_int i = 0; i < alg_count; i++) {
    237 		const npfa_funcs_t *f = &alg_funcs[i];
    238 
    239 		if (!f->inspect)
    240 			continue;
    241 		if ((con = f->inspect(npc, di)) != NULL)
    242 			break;
    243 	}
    244 	pserialize_read_exit(s);
    245 	return con;
    246 }
    247 
    248 prop_array_t
    249 npf_alg_export(void)
    250 {
    251 	prop_array_t alglist = prop_array_create();
    252 
    253 	KASSERT(npf_config_locked_p());
    254 
    255 	for (u_int i = 0; i < alg_count; i++) {
    256 		const npf_alg_t *alg = &alg_list[i];
    257 
    258 		if (alg->na_name == NULL) {
    259 			continue;
    260 		}
    261 		prop_dictionary_t algdict = prop_dictionary_create();
    262 		prop_dictionary_set_cstring(algdict, "name", alg->na_name);
    263 		prop_array_add(alglist, algdict);
    264 		prop_object_release(algdict);
    265 	}
    266 	return alglist;
    267 }
    268