Home | History | Annotate | Line # | Download | only in npf
npf_alg.c revision 1.9
      1  1.9     rmind /*	$NetBSD: npf_alg.c,v 1.9 2013/06/02 02:20:04 rmind Exp $	*/
      2  1.1     rmind 
      3  1.1     rmind /*-
      4  1.9     rmind  * Copyright (c) 2010-2013 The NetBSD Foundation, Inc.
      5  1.1     rmind  * All rights reserved.
      6  1.1     rmind  *
      7  1.1     rmind  * This material is based upon work partially supported by The
      8  1.1     rmind  * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
      9  1.1     rmind  *
     10  1.1     rmind  * Redistribution and use in source and binary forms, with or without
     11  1.1     rmind  * modification, are permitted provided that the following conditions
     12  1.1     rmind  * are met:
     13  1.1     rmind  * 1. Redistributions of source code must retain the above copyright
     14  1.1     rmind  *    notice, this list of conditions and the following disclaimer.
     15  1.1     rmind  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1     rmind  *    notice, this list of conditions and the following disclaimer in the
     17  1.1     rmind  *    documentation and/or other materials provided with the distribution.
     18  1.1     rmind  *
     19  1.1     rmind  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  1.1     rmind  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  1.1     rmind  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  1.1     rmind  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  1.1     rmind  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  1.1     rmind  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  1.1     rmind  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  1.1     rmind  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  1.1     rmind  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  1.1     rmind  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  1.1     rmind  * POSSIBILITY OF SUCH DAMAGE.
     30  1.1     rmind  */
     31  1.1     rmind 
     32  1.1     rmind /*
     33  1.9     rmind  * NPF interface for the Application Level Gateways (ALGs).
     34  1.1     rmind  */
     35  1.1     rmind 
     36  1.1     rmind #include <sys/cdefs.h>
     37  1.9     rmind __KERNEL_RCSID(0, "$NetBSD: npf_alg.c,v 1.9 2013/06/02 02:20:04 rmind Exp $");
     38  1.1     rmind 
     39  1.1     rmind #include <sys/param.h>
     40  1.4     rmind #include <sys/types.h>
     41  1.4     rmind 
     42  1.1     rmind #include <sys/kmem.h>
     43  1.4     rmind #include <sys/pserialize.h>
     44  1.4     rmind #include <sys/mutex.h>
     45  1.1     rmind #include <net/pfil.h>
     46  1.8  christos #include <sys/module.h>
     47  1.1     rmind 
     48  1.1     rmind #include "npf_impl.h"
     49  1.1     rmind 
     50  1.9     rmind /*
     51  1.9     rmind  * NAT ALG description structure.  For more compact use of cache,
     52  1.9     rmind  * the functions are separated in their own arrays.  The number of
     53  1.9     rmind  * ALGs is expected to be very small.
     54  1.9     rmind  */
     55  1.9     rmind 
     56  1.1     rmind struct npf_alg {
     57  1.9     rmind 	const char *	na_name;
     58  1.9     rmind 	u_int		na_slot;
     59  1.1     rmind };
     60  1.1     rmind 
     61  1.9     rmind #define	NPF_MAX_ALGS	8
     62  1.9     rmind 
     63  1.9     rmind /* List of ALGs and the count. */
     64  1.9     rmind static pserialize_t	alg_psz			__cacheline_aligned;
     65  1.9     rmind static npf_alg_t	alg_list[NPF_MAX_ALGS]	__read_mostly;
     66  1.9     rmind static u_int		alg_count		__read_mostly;
     67  1.9     rmind 
     68  1.9     rmind /* Session, matching and translation functions. */
     69  1.9     rmind static npf_alg_sfunc_t	alg_sfunc[NPF_MAX_ALGS]	__read_mostly;
     70  1.9     rmind static npf_alg_func_t	alg_mfunc[NPF_MAX_ALGS]	__read_mostly;
     71  1.9     rmind static npf_alg_func_t	alg_tfunc[NPF_MAX_ALGS]	__read_mostly;
     72  1.9     rmind 
     73  1.9     rmind static const char	alg_prefix[] = "npf_alg_";
     74  1.9     rmind #define	NPF_EXT_PREFLEN	(sizeof(alg_prefix) - 1)
     75  1.1     rmind 
     76  1.1     rmind void
     77  1.1     rmind npf_alg_sysinit(void)
     78  1.1     rmind {
     79  1.9     rmind 	alg_psz = pserialize_create();
     80  1.9     rmind 	memset(&alg_list, 0, sizeof(alg_list));
     81  1.9     rmind 	alg_count = 0;
     82  1.9     rmind 
     83  1.9     rmind 	memset(&alg_mfunc, 0, sizeof(alg_mfunc));
     84  1.9     rmind 	memset(&alg_tfunc, 0, sizeof(alg_tfunc));
     85  1.9     rmind 	memset(&alg_sfunc, 0, sizeof(alg_sfunc));
     86  1.1     rmind }
     87  1.1     rmind 
     88  1.1     rmind void
     89  1.1     rmind npf_alg_sysfini(void)
     90  1.1     rmind {
     91  1.9     rmind 	pserialize_destroy(alg_psz);
     92  1.1     rmind }
     93  1.1     rmind 
     94  1.8  christos static npf_alg_t *
     95  1.9     rmind npf_alg_lookup(const char *name)
     96  1.8  christos {
     97  1.9     rmind 	KASSERT(npf_config_locked_p());
     98  1.8  christos 
     99  1.9     rmind 	for (u_int i = 0; i < alg_count; i++) {
    100  1.9     rmind 		npf_alg_t *alg = &alg_list[i];
    101  1.9     rmind 		const char *aname = alg->na_name;
    102  1.8  christos 
    103  1.9     rmind 		if (aname && strcmp(aname, name) == 0)
    104  1.9     rmind 			return alg;
    105  1.9     rmind 	}
    106  1.9     rmind 	return NULL;
    107  1.8  christos }
    108  1.8  christos 
    109  1.8  christos npf_alg_t *
    110  1.8  christos npf_alg_construct(const char *name)
    111  1.8  christos {
    112  1.8  christos 	npf_alg_t *alg;
    113  1.8  christos 
    114  1.9     rmind 	npf_config_enter();
    115  1.9     rmind 	if ((alg = npf_alg_lookup(name)) == NULL) {
    116  1.9     rmind 		char modname[NPF_EXT_PREFLEN + 64];
    117  1.9     rmind 		snprintf(modname, sizeof(modname), "%s%s", alg_prefix, name);
    118  1.9     rmind 		npf_config_exit();
    119  1.9     rmind 
    120  1.9     rmind 		if (module_autoload(modname, MODULE_CLASS_MISC) != 0) {
    121  1.9     rmind 			return NULL;
    122  1.9     rmind 		}
    123  1.9     rmind 		npf_config_enter();
    124  1.9     rmind 		alg = npf_alg_lookup(name);
    125  1.9     rmind 	}
    126  1.9     rmind 	npf_config_exit();
    127  1.8  christos 	return alg;
    128  1.8  christos }
    129  1.8  christos 
    130  1.1     rmind /*
    131  1.1     rmind  * npf_alg_register: register application-level gateway.
    132  1.1     rmind  */
    133  1.1     rmind npf_alg_t *
    134  1.8  christos npf_alg_register(const char *name, npf_alg_func_t mfunc, npf_alg_func_t tfunc,
    135  1.6     rmind     npf_alg_sfunc_t sfunc)
    136  1.1     rmind {
    137  1.1     rmind 	npf_alg_t *alg;
    138  1.9     rmind 	u_int i;
    139  1.1     rmind 
    140  1.9     rmind 	npf_config_enter();
    141  1.9     rmind 	if (npf_alg_lookup(name) != NULL) {
    142  1.9     rmind 		npf_config_exit();
    143  1.9     rmind 		return NULL;
    144  1.9     rmind 	}
    145  1.9     rmind 
    146  1.9     rmind 	/* Find a spare slot. */
    147  1.9     rmind 	for (i = 0; i < NPF_MAX_ALGS; i++) {
    148  1.9     rmind 		alg = &alg_list[i];
    149  1.9     rmind 		if (alg->na_name == NULL) {
    150  1.9     rmind 			break;
    151  1.9     rmind 		}
    152  1.9     rmind 	}
    153  1.9     rmind 	if (i == NPF_MAX_ALGS) {
    154  1.9     rmind 		npf_config_exit();
    155  1.8  christos 		return NULL;
    156  1.8  christos 	}
    157  1.4     rmind 
    158  1.9     rmind 	/* Register the ALG. */
    159  1.9     rmind 	alg->na_name = name;
    160  1.9     rmind 	alg->na_slot = i;
    161  1.9     rmind 
    162  1.9     rmind 	/* Assign the functions. */
    163  1.9     rmind 	alg_mfunc[i] = mfunc;
    164  1.9     rmind 	alg_tfunc[i] = tfunc;
    165  1.9     rmind 	alg_sfunc[i] = sfunc;
    166  1.9     rmind 
    167  1.9     rmind 	alg_count = MAX(alg_count, i + 1);
    168  1.9     rmind 	npf_config_exit();
    169  1.1     rmind 	return alg;
    170  1.1     rmind }
    171  1.1     rmind 
    172  1.1     rmind /*
    173  1.1     rmind  * npf_alg_unregister: unregister application-level gateway.
    174  1.1     rmind  */
    175  1.1     rmind int
    176  1.1     rmind npf_alg_unregister(npf_alg_t *alg)
    177  1.1     rmind {
    178  1.9     rmind 	u_int i = alg->na_slot;
    179  1.4     rmind 
    180  1.9     rmind 	/* Deactivate the functions first. */
    181  1.7     rmind 	npf_config_enter();
    182  1.9     rmind 	alg_mfunc[i] = NULL;
    183  1.9     rmind 	alg_tfunc[i] = NULL;
    184  1.9     rmind 	alg_sfunc[i] = NULL;
    185  1.9     rmind 	pserialize_perform(alg_psz);
    186  1.9     rmind 
    187  1.9     rmind 	/* Finally, unregister the ALG. */
    188  1.7     rmind 	npf_ruleset_freealg(npf_config_natset(), alg);
    189  1.9     rmind 	alg->na_name = NULL;
    190  1.7     rmind 	npf_config_exit();
    191  1.5     rmind 
    192  1.1     rmind 	return 0;
    193  1.1     rmind }
    194  1.1     rmind 
    195  1.2     rmind /*
    196  1.2     rmind  * npf_alg_match: call ALG matching inspectors, determine if any ALG matches.
    197  1.2     rmind  */
    198  1.2     rmind bool
    199  1.6     rmind npf_alg_match(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, int di)
    200  1.1     rmind {
    201  1.4     rmind 	bool match = false;
    202  1.4     rmind 	int s;
    203  1.1     rmind 
    204  1.4     rmind 	s = pserialize_read_enter();
    205  1.9     rmind 	for (u_int i = 0; i < alg_count; i++) {
    206  1.9     rmind 		npf_alg_func_t func = alg_mfunc[i];
    207  1.4     rmind 
    208  1.6     rmind 		if (func && func(npc, nbuf, nt, di)) {
    209  1.4     rmind 			match = true;
    210  1.4     rmind 			break;
    211  1.1     rmind 		}
    212  1.1     rmind 	}
    213  1.4     rmind 	pserialize_read_exit(s);
    214  1.4     rmind 	return match;
    215  1.1     rmind }
    216  1.1     rmind 
    217  1.1     rmind /*
    218  1.2     rmind  * npf_alg_exec: execute ALG hooks for translation.
    219  1.1     rmind  */
    220  1.1     rmind void
    221  1.6     rmind npf_alg_exec(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, int di)
    222  1.1     rmind {
    223  1.4     rmind 	int s;
    224  1.1     rmind 
    225  1.4     rmind 	s = pserialize_read_enter();
    226  1.9     rmind 	for (u_int i = 0; i < alg_count; i++) {
    227  1.6     rmind 		npf_alg_func_t func;
    228  1.6     rmind 
    229  1.9     rmind 		if ((func = alg_tfunc[i]) != NULL) {
    230  1.9     rmind 			func(npc, nbuf, nt, di);
    231  1.1     rmind 		}
    232  1.1     rmind 	}
    233  1.4     rmind 	pserialize_read_exit(s);
    234  1.1     rmind }
    235  1.1     rmind 
    236  1.6     rmind npf_session_t *
    237  1.6     rmind npf_alg_session(npf_cache_t *npc, nbuf_t *nbuf, int di)
    238  1.1     rmind {
    239  1.6     rmind 	npf_session_t *se = NULL;
    240  1.4     rmind 	int s;
    241  1.1     rmind 
    242  1.4     rmind 	s = pserialize_read_enter();
    243  1.9     rmind 	for (u_int i = 0; i < alg_count; i++) {
    244  1.9     rmind 		npf_alg_sfunc_t func = alg_sfunc[i];
    245  1.4     rmind 
    246  1.6     rmind 		if (func && (se = func(npc, nbuf, di)) != NULL) {
    247  1.4     rmind 			break;
    248  1.1     rmind 		}
    249  1.1     rmind 	}
    250  1.4     rmind 	pserialize_read_exit(s);
    251  1.6     rmind 	return se;
    252  1.1     rmind }
    253