Home | History | Annotate | Line # | Download | only in npf
npf_alg.c revision 1.15.4.1
      1  1.15.4.1  pgoyette /*	$NetBSD: npf_alg.c,v 1.15.4.1 2017/01/07 08:56:50 pgoyette 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.15.4.1  pgoyette #ifdef _KERNEL
     37       1.1     rmind #include <sys/cdefs.h>
     38  1.15.4.1  pgoyette __KERNEL_RCSID(0, "$NetBSD: npf_alg.c,v 1.15.4.1 2017/01/07 08:56:50 pgoyette Exp $");
     39       1.1     rmind 
     40       1.1     rmind #include <sys/param.h>
     41       1.4     rmind #include <sys/types.h>
     42       1.4     rmind 
     43       1.1     rmind #include <sys/kmem.h>
     44       1.4     rmind #include <sys/pserialize.h>
     45       1.4     rmind #include <sys/mutex.h>
     46       1.1     rmind #include <net/pfil.h>
     47       1.8  christos #include <sys/module.h>
     48  1.15.4.1  pgoyette #endif
     49       1.1     rmind 
     50       1.1     rmind #include "npf_impl.h"
     51       1.1     rmind 
     52       1.9     rmind /*
     53       1.9     rmind  * NAT ALG description structure.  For more compact use of cache,
     54       1.9     rmind  * the functions are separated in their own arrays.  The number of
     55       1.9     rmind  * ALGs is expected to be very small.
     56       1.9     rmind  */
     57       1.9     rmind 
     58       1.1     rmind struct npf_alg {
     59       1.9     rmind 	const char *	na_name;
     60       1.9     rmind 	u_int		na_slot;
     61       1.1     rmind };
     62       1.1     rmind 
     63  1.15.4.1  pgoyette struct npf_algset {
     64  1.15.4.1  pgoyette 	/* List of ALGs and the count. */
     65  1.15.4.1  pgoyette 	npf_alg_t	alg_list[NPF_MAX_ALGS];
     66  1.15.4.1  pgoyette 	u_int		alg_count;
     67       1.9     rmind 
     68  1.15.4.1  pgoyette 	/* Matching, inspection and translation functions. */
     69  1.15.4.1  pgoyette 	npfa_funcs_t	alg_funcs[NPF_MAX_ALGS];
     70  1.15.4.1  pgoyette };
     71       1.9     rmind 
     72       1.9     rmind static const char	alg_prefix[] = "npf_alg_";
     73       1.9     rmind #define	NPF_EXT_PREFLEN	(sizeof(alg_prefix) - 1)
     74       1.1     rmind 
     75       1.1     rmind void
     76  1.15.4.1  pgoyette npf_alg_init(npf_t *npf)
     77       1.1     rmind {
     78  1.15.4.1  pgoyette 	npf_algset_t *aset;
     79  1.15.4.1  pgoyette 
     80  1.15.4.1  pgoyette 	aset = kmem_zalloc(sizeof(npf_algset_t), KM_SLEEP);
     81  1.15.4.1  pgoyette 	npf->algset = aset;
     82       1.1     rmind }
     83       1.1     rmind 
     84       1.1     rmind void
     85  1.15.4.1  pgoyette npf_alg_fini(npf_t *npf)
     86       1.1     rmind {
     87  1.15.4.1  pgoyette 	npf_algset_t *aset = npf->algset;
     88  1.15.4.1  pgoyette 
     89  1.15.4.1  pgoyette 	kmem_free(aset, sizeof(npf_algset_t));
     90       1.1     rmind }
     91       1.1     rmind 
     92       1.8  christos static npf_alg_t *
     93  1.15.4.1  pgoyette npf_alg_lookup(npf_t *npf, const char *name)
     94       1.8  christos {
     95  1.15.4.1  pgoyette 	npf_algset_t *aset = npf->algset;
     96  1.15.4.1  pgoyette 
     97  1.15.4.1  pgoyette 	KASSERT(npf_config_locked_p(npf));
     98       1.8  christos 
     99  1.15.4.1  pgoyette 	for (u_int i = 0; i < aset->alg_count; i++) {
    100  1.15.4.1  pgoyette 		npf_alg_t *alg = &aset->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.15.4.1  pgoyette npf_alg_construct(npf_t *npf, const char *name)
    111       1.8  christos {
    112       1.8  christos 	npf_alg_t *alg;
    113       1.8  christos 
    114  1.15.4.1  pgoyette 	npf_config_enter(npf);
    115  1.15.4.1  pgoyette 	if ((alg = npf_alg_lookup(npf, 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.15.4.1  pgoyette 		npf_config_exit(npf);
    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.15.4.1  pgoyette 		npf_config_enter(npf);
    124  1.15.4.1  pgoyette 		alg = npf_alg_lookup(npf, name);
    125       1.9     rmind 	}
    126  1.15.4.1  pgoyette 	npf_config_exit(npf);
    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.15.4.1  pgoyette npf_alg_register(npf_t *npf, const char *name, const npfa_funcs_t *funcs)
    135       1.1     rmind {
    136  1.15.4.1  pgoyette 	npf_algset_t *aset = npf->algset;
    137  1.15.4.1  pgoyette 	npfa_funcs_t *afuncs;
    138       1.1     rmind 	npf_alg_t *alg;
    139       1.9     rmind 	u_int i;
    140       1.1     rmind 
    141  1.15.4.1  pgoyette 	npf_config_enter(npf);
    142  1.15.4.1  pgoyette 	if (npf_alg_lookup(npf, name) != NULL) {
    143  1.15.4.1  pgoyette 		npf_config_exit(npf);
    144       1.9     rmind 		return NULL;
    145       1.9     rmind 	}
    146       1.9     rmind 
    147       1.9     rmind 	/* Find a spare slot. */
    148       1.9     rmind 	for (i = 0; i < NPF_MAX_ALGS; i++) {
    149  1.15.4.1  pgoyette 		alg = &aset->alg_list[i];
    150       1.9     rmind 		if (alg->na_name == NULL) {
    151       1.9     rmind 			break;
    152       1.9     rmind 		}
    153       1.9     rmind 	}
    154       1.9     rmind 	if (i == NPF_MAX_ALGS) {
    155  1.15.4.1  pgoyette 		npf_config_exit(npf);
    156       1.8  christos 		return NULL;
    157       1.8  christos 	}
    158       1.4     rmind 
    159       1.9     rmind 	/* Register the ALG. */
    160       1.9     rmind 	alg->na_name = name;
    161       1.9     rmind 	alg->na_slot = i;
    162       1.9     rmind 
    163       1.9     rmind 	/* Assign the functions. */
    164  1.15.4.1  pgoyette 	afuncs = &aset->alg_funcs[i];
    165  1.15.4.1  pgoyette 	afuncs->match = funcs->match;
    166  1.15.4.1  pgoyette 	afuncs->translate = funcs->translate;
    167  1.15.4.1  pgoyette 	afuncs->inspect = funcs->inspect;
    168       1.9     rmind 
    169  1.15.4.1  pgoyette 	aset->alg_count = MAX(aset->alg_count, i + 1);
    170  1.15.4.1  pgoyette 	npf_config_exit(npf);
    171      1.11     rmind 
    172       1.1     rmind 	return alg;
    173       1.1     rmind }
    174       1.1     rmind 
    175       1.1     rmind /*
    176       1.1     rmind  * npf_alg_unregister: unregister application-level gateway.
    177       1.1     rmind  */
    178       1.1     rmind int
    179  1.15.4.1  pgoyette npf_alg_unregister(npf_t *npf, npf_alg_t *alg)
    180       1.1     rmind {
    181  1.15.4.1  pgoyette 	npf_algset_t *aset = npf->algset;
    182       1.9     rmind 	u_int i = alg->na_slot;
    183  1.15.4.1  pgoyette 	npfa_funcs_t *afuncs;
    184       1.4     rmind 
    185       1.9     rmind 	/* Deactivate the functions first. */
    186  1.15.4.1  pgoyette 	npf_config_enter(npf);
    187  1.15.4.1  pgoyette 	afuncs = &aset->alg_funcs[i];
    188  1.15.4.1  pgoyette 	afuncs->match = NULL;
    189  1.15.4.1  pgoyette 	afuncs->translate = NULL;
    190  1.15.4.1  pgoyette 	afuncs->inspect = NULL;
    191  1.15.4.1  pgoyette 	pserialize_perform(npf->qsbr);
    192       1.9     rmind 
    193       1.9     rmind 	/* Finally, unregister the ALG. */
    194  1.15.4.1  pgoyette 	npf_ruleset_freealg(npf_config_natset(npf), alg);
    195       1.9     rmind 	alg->na_name = NULL;
    196  1.15.4.1  pgoyette 	npf_config_exit(npf);
    197       1.5     rmind 
    198       1.1     rmind 	return 0;
    199       1.1     rmind }
    200       1.1     rmind 
    201       1.2     rmind /*
    202       1.2     rmind  * npf_alg_match: call ALG matching inspectors, determine if any ALG matches.
    203       1.2     rmind  */
    204       1.2     rmind bool
    205      1.14     rmind npf_alg_match(npf_cache_t *npc, npf_nat_t *nt, int di)
    206       1.1     rmind {
    207  1.15.4.1  pgoyette 	npf_algset_t *aset = npc->npc_ctx->algset;
    208       1.4     rmind 	bool match = false;
    209       1.4     rmind 	int s;
    210       1.1     rmind 
    211       1.4     rmind 	s = pserialize_read_enter();
    212  1.15.4.1  pgoyette 	for (u_int i = 0; i < aset->alg_count; i++) {
    213  1.15.4.1  pgoyette 		const npfa_funcs_t *f = &aset->alg_funcs[i];
    214       1.4     rmind 
    215      1.14     rmind 		if (f->match && f->match(npc, nt, di)) {
    216       1.4     rmind 			match = true;
    217       1.4     rmind 			break;
    218       1.1     rmind 		}
    219       1.1     rmind 	}
    220       1.4     rmind 	pserialize_read_exit(s);
    221       1.4     rmind 	return match;
    222       1.1     rmind }
    223       1.1     rmind 
    224       1.1     rmind /*
    225       1.2     rmind  * npf_alg_exec: execute ALG hooks for translation.
    226       1.1     rmind  */
    227       1.1     rmind void
    228      1.14     rmind npf_alg_exec(npf_cache_t *npc, npf_nat_t *nt, bool forw)
    229       1.1     rmind {
    230  1.15.4.1  pgoyette 	npf_algset_t *aset = npc->npc_ctx->algset;
    231       1.4     rmind 	int s;
    232       1.1     rmind 
    233       1.4     rmind 	s = pserialize_read_enter();
    234  1.15.4.1  pgoyette 	for (u_int i = 0; i < aset->alg_count; i++) {
    235  1.15.4.1  pgoyette 		const npfa_funcs_t *f = &aset->alg_funcs[i];
    236       1.6     rmind 
    237      1.11     rmind 		if (f->translate) {
    238      1.14     rmind 			f->translate(npc, nt, forw);
    239       1.1     rmind 		}
    240       1.1     rmind 	}
    241       1.4     rmind 	pserialize_read_exit(s);
    242       1.1     rmind }
    243       1.1     rmind 
    244      1.13     rmind npf_conn_t *
    245      1.14     rmind npf_alg_conn(npf_cache_t *npc, int di)
    246       1.1     rmind {
    247  1.15.4.1  pgoyette 	npf_algset_t *aset = npc->npc_ctx->algset;
    248      1.13     rmind 	npf_conn_t *con = NULL;
    249       1.4     rmind 	int s;
    250       1.1     rmind 
    251       1.4     rmind 	s = pserialize_read_enter();
    252  1.15.4.1  pgoyette 	for (u_int i = 0; i < aset->alg_count; i++) {
    253  1.15.4.1  pgoyette 		const npfa_funcs_t *f = &aset->alg_funcs[i];
    254       1.4     rmind 
    255      1.12     rmind 		if (!f->inspect)
    256      1.11     rmind 			continue;
    257      1.14     rmind 		if ((con = f->inspect(npc, di)) != NULL)
    258       1.4     rmind 			break;
    259       1.1     rmind 	}
    260       1.4     rmind 	pserialize_read_exit(s);
    261      1.13     rmind 	return con;
    262       1.1     rmind }
    263      1.15     rmind 
    264      1.15     rmind prop_array_t
    265  1.15.4.1  pgoyette npf_alg_export(npf_t *npf)
    266      1.15     rmind {
    267      1.15     rmind 	prop_array_t alglist = prop_array_create();
    268  1.15.4.1  pgoyette 	npf_algset_t *aset = npf->algset;
    269      1.15     rmind 
    270  1.15.4.1  pgoyette 	KASSERT(npf_config_locked_p(npf));
    271      1.15     rmind 
    272  1.15.4.1  pgoyette 	for (u_int i = 0; i < aset->alg_count; i++) {
    273  1.15.4.1  pgoyette 		const npf_alg_t *alg = &aset->alg_list[i];
    274      1.15     rmind 
    275      1.15     rmind 		if (alg->na_name == NULL) {
    276      1.15     rmind 			continue;
    277      1.15     rmind 		}
    278      1.15     rmind 		prop_dictionary_t algdict = prop_dictionary_create();
    279      1.15     rmind 		prop_dictionary_set_cstring(algdict, "name", alg->na_name);
    280      1.15     rmind 		prop_array_add(alglist, algdict);
    281      1.15     rmind 		prop_object_release(algdict);
    282      1.15     rmind 	}
    283      1.15     rmind 	return alglist;
    284      1.15     rmind }
    285