npf_alg.c revision 1.8 1 1.8 christos /* $NetBSD: npf_alg.c,v 1.8 2013/03/20 00:29:47 christos Exp $ */
2 1.1 rmind
3 1.1 rmind /*-
4 1.1 rmind * Copyright (c) 2010 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.1 rmind * NPF interface for application level gateways (ALGs).
34 1.1 rmind */
35 1.1 rmind
36 1.1 rmind #include <sys/cdefs.h>
37 1.8 christos __KERNEL_RCSID(0, "$NetBSD: npf_alg.c,v 1.8 2013/03/20 00:29:47 christos 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.1 rmind /* NAT ALG structure for registration. */
51 1.1 rmind struct npf_alg {
52 1.6 rmind LIST_ENTRY(npf_alg) na_entry;
53 1.8 christos const char * na_name;
54 1.6 rmind npf_alg_t * na_bptr;
55 1.6 rmind npf_alg_func_t na_match_func;
56 1.6 rmind npf_alg_func_t na_tr_func;
57 1.6 rmind npf_alg_sfunc_t na_se_func;
58 1.1 rmind };
59 1.1 rmind
60 1.6 rmind static LIST_HEAD(, npf_alg) nat_alg_list __cacheline_aligned;
61 1.6 rmind static kmutex_t nat_alg_lock __cacheline_aligned;
62 1.6 rmind static pserialize_t nat_alg_psz __cacheline_aligned;
63 1.1 rmind
64 1.1 rmind void
65 1.1 rmind npf_alg_sysinit(void)
66 1.1 rmind {
67 1.1 rmind
68 1.4 rmind mutex_init(&nat_alg_lock, MUTEX_DEFAULT, IPL_NONE);
69 1.4 rmind nat_alg_psz = pserialize_create();
70 1.1 rmind LIST_INIT(&nat_alg_list);
71 1.1 rmind }
72 1.1 rmind
73 1.1 rmind void
74 1.1 rmind npf_alg_sysfini(void)
75 1.1 rmind {
76 1.1 rmind
77 1.1 rmind KASSERT(LIST_EMPTY(&nat_alg_list));
78 1.4 rmind pserialize_destroy(nat_alg_psz);
79 1.4 rmind mutex_destroy(&nat_alg_lock);
80 1.1 rmind }
81 1.1 rmind
82 1.8 christos static const char npf_alg_prefix[] = "npf_alg_";
83 1.8 christos #define NPF_EXT_PREFLEN (sizeof(npf_alg_prefix) - 1)
84 1.8 christos
85 1.8 christos static npf_alg_t *
86 1.8 christos npf_alg_lookup(const char *name, bool autoload)
87 1.8 christos {
88 1.8 christos npf_alg_t *alg;
89 1.8 christos char modname[64 + NPF_EXT_PREFLEN];
90 1.8 christos int error;
91 1.8 christos
92 1.8 christos KASSERT(mutex_owned(&nat_alg_lock));
93 1.8 christos
94 1.8 christos again:
95 1.8 christos LIST_FOREACH(alg, &nat_alg_list, na_entry)
96 1.8 christos if (strcmp(alg->na_name, name) == 0)
97 1.8 christos break;
98 1.8 christos
99 1.8 christos if (alg != NULL || !autoload)
100 1.8 christos return alg;
101 1.8 christos
102 1.8 christos mutex_exit(&nat_alg_lock);
103 1.8 christos autoload = false;
104 1.8 christos snprintf(modname, sizeof(modname), "%s%s", npf_alg_prefix, name);
105 1.8 christos error = module_autoload(modname, MODULE_CLASS_MISC);
106 1.8 christos mutex_enter(&nat_alg_lock);
107 1.8 christos
108 1.8 christos if (error)
109 1.8 christos return NULL;
110 1.8 christos goto again;
111 1.8 christos }
112 1.8 christos
113 1.8 christos npf_alg_t *
114 1.8 christos npf_alg_construct(const char *name)
115 1.8 christos {
116 1.8 christos npf_alg_t *alg;
117 1.8 christos
118 1.8 christos mutex_enter(&nat_alg_lock);
119 1.8 christos alg = npf_alg_lookup(name, true);
120 1.8 christos mutex_exit(&nat_alg_lock);
121 1.8 christos return alg;
122 1.8 christos }
123 1.8 christos
124 1.1 rmind /*
125 1.1 rmind * npf_alg_register: register application-level gateway.
126 1.1 rmind */
127 1.1 rmind npf_alg_t *
128 1.8 christos npf_alg_register(const char *name, npf_alg_func_t mfunc, npf_alg_func_t tfunc,
129 1.6 rmind npf_alg_sfunc_t sfunc)
130 1.1 rmind {
131 1.1 rmind npf_alg_t *alg;
132 1.1 rmind
133 1.3 rmind alg = kmem_zalloc(sizeof(npf_alg_t), KM_SLEEP);
134 1.8 christos alg->na_name = name;
135 1.2 rmind alg->na_bptr = alg;
136 1.6 rmind alg->na_match_func = mfunc;
137 1.6 rmind alg->na_tr_func = tfunc;
138 1.6 rmind alg->na_se_func = sfunc;
139 1.4 rmind
140 1.4 rmind mutex_enter(&nat_alg_lock);
141 1.8 christos if (npf_alg_lookup(name, false) != NULL) {
142 1.8 christos mutex_exit(&nat_alg_lock);
143 1.8 christos kmem_free(alg, sizeof(npf_alg_t));
144 1.8 christos return NULL;
145 1.8 christos }
146 1.1 rmind LIST_INSERT_HEAD(&nat_alg_list, alg, na_entry);
147 1.4 rmind mutex_exit(&nat_alg_lock);
148 1.4 rmind
149 1.1 rmind return alg;
150 1.1 rmind }
151 1.1 rmind
152 1.1 rmind /*
153 1.1 rmind * npf_alg_unregister: unregister application-level gateway.
154 1.1 rmind */
155 1.1 rmind int
156 1.1 rmind npf_alg_unregister(npf_alg_t *alg)
157 1.1 rmind {
158 1.4 rmind mutex_enter(&nat_alg_lock);
159 1.4 rmind LIST_REMOVE(alg, na_entry);
160 1.4 rmind pserialize_perform(nat_alg_psz);
161 1.4 rmind mutex_exit(&nat_alg_lock);
162 1.4 rmind
163 1.7 rmind npf_config_enter();
164 1.7 rmind npf_ruleset_freealg(npf_config_natset(), alg);
165 1.7 rmind npf_config_exit();
166 1.5 rmind
167 1.1 rmind kmem_free(alg, sizeof(npf_alg_t));
168 1.1 rmind return 0;
169 1.1 rmind }
170 1.1 rmind
171 1.2 rmind /*
172 1.2 rmind * npf_alg_match: call ALG matching inspectors, determine if any ALG matches.
173 1.2 rmind */
174 1.2 rmind bool
175 1.6 rmind npf_alg_match(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, int di)
176 1.1 rmind {
177 1.1 rmind npf_alg_t *alg;
178 1.4 rmind bool match = false;
179 1.4 rmind int s;
180 1.1 rmind
181 1.4 rmind s = pserialize_read_enter();
182 1.1 rmind LIST_FOREACH(alg, &nat_alg_list, na_entry) {
183 1.6 rmind npf_alg_func_t func = alg->na_match_func;
184 1.4 rmind
185 1.6 rmind if (func && func(npc, nbuf, nt, di)) {
186 1.4 rmind match = true;
187 1.4 rmind break;
188 1.1 rmind }
189 1.1 rmind }
190 1.4 rmind pserialize_read_exit(s);
191 1.4 rmind return match;
192 1.1 rmind }
193 1.1 rmind
194 1.1 rmind /*
195 1.2 rmind * npf_alg_exec: execute ALG hooks for translation.
196 1.1 rmind */
197 1.1 rmind void
198 1.6 rmind npf_alg_exec(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, int di)
199 1.1 rmind {
200 1.1 rmind npf_alg_t *alg;
201 1.4 rmind int s;
202 1.1 rmind
203 1.4 rmind s = pserialize_read_enter();
204 1.1 rmind LIST_FOREACH(alg, &nat_alg_list, na_entry) {
205 1.6 rmind npf_alg_func_t func;
206 1.6 rmind
207 1.6 rmind if ((func = alg->na_tr_func) != NULL) {
208 1.6 rmind (func)(npc, nbuf, nt, di);
209 1.1 rmind }
210 1.1 rmind }
211 1.4 rmind pserialize_read_exit(s);
212 1.1 rmind }
213 1.1 rmind
214 1.6 rmind npf_session_t *
215 1.6 rmind npf_alg_session(npf_cache_t *npc, nbuf_t *nbuf, int di)
216 1.1 rmind {
217 1.6 rmind npf_session_t *se = NULL;
218 1.1 rmind npf_alg_t *alg;
219 1.4 rmind int s;
220 1.1 rmind
221 1.4 rmind s = pserialize_read_enter();
222 1.1 rmind LIST_FOREACH(alg, &nat_alg_list, na_entry) {
223 1.6 rmind npf_alg_sfunc_t func = alg->na_se_func;
224 1.4 rmind
225 1.6 rmind if (func && (se = func(npc, nbuf, di)) != NULL) {
226 1.4 rmind break;
227 1.1 rmind }
228 1.1 rmind }
229 1.4 rmind pserialize_read_exit(s);
230 1.6 rmind return se;
231 1.1 rmind }
232