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