1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
2 | |
---|
3 | /*- |
---|
4 | * Copyright (c) 2015-2016 Yandex LLC |
---|
5 | * Copyright (c) 2015-2016 Andrey V. Elsukov <ae@FreeBSD.org> |
---|
6 | * Copyright (c) 2015 Alexander V. Chernikov <melifaro@FreeBSD.org> |
---|
7 | * All rights reserved. |
---|
8 | * |
---|
9 | * Redistribution and use in source and binary forms, with or without |
---|
10 | * modification, are permitted provided that the following conditions |
---|
11 | * are met: |
---|
12 | * |
---|
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 AUTHOR ``AS IS'' AND ANY EXPRESS OR |
---|
20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
---|
21 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
---|
22 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
---|
23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
---|
24 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
---|
25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
---|
26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
---|
27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
---|
28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
29 | */ |
---|
30 | |
---|
31 | #include <sys/cdefs.h> |
---|
32 | __FBSDID("$FreeBSD$"); |
---|
33 | |
---|
34 | #include <sys/param.h> |
---|
35 | #include <sys/systm.h> |
---|
36 | #include <sys/counter.h> |
---|
37 | #include <sys/errno.h> |
---|
38 | #include <sys/kernel.h> |
---|
39 | #include <sys/lock.h> |
---|
40 | #include <sys/malloc.h> |
---|
41 | #include <sys/mbuf.h> |
---|
42 | #include <sys/module.h> |
---|
43 | #include <sys/rmlock.h> |
---|
44 | #include <sys/rwlock.h> |
---|
45 | #include <sys/socket.h> |
---|
46 | #include <sys/sockopt.h> |
---|
47 | #include <sys/queue.h> |
---|
48 | #include <sys/syslog.h> |
---|
49 | #include <sys/sysctl.h> |
---|
50 | |
---|
51 | #include <net/if.h> |
---|
52 | #include <net/if_var.h> |
---|
53 | #include <net/pfil.h> |
---|
54 | #include <net/route.h> |
---|
55 | #include <net/vnet.h> |
---|
56 | |
---|
57 | #include <netinet/in.h> |
---|
58 | #include <netinet/ip_var.h> |
---|
59 | #include <netinet/ip_fw.h> |
---|
60 | #include <netinet6/in6_var.h> |
---|
61 | #include <netinet6/ip6_var.h> |
---|
62 | |
---|
63 | #include <netpfil/ipfw/ip_fw_private.h> |
---|
64 | #include <netpfil/ipfw/nat64/ip_fw_nat64.h> |
---|
65 | #include <netpfil/ipfw/nat64/nat64stl.h> |
---|
66 | #include <netinet6/ip_fw_nat64.h> |
---|
67 | |
---|
68 | VNET_DEFINE(uint16_t, nat64stl_eid) = 0; |
---|
69 | |
---|
70 | static struct nat64stl_cfg *nat64stl_alloc_config(const char *name, uint8_t set); |
---|
71 | static void nat64stl_free_config(struct nat64stl_cfg *cfg); |
---|
72 | static struct nat64stl_cfg *nat64stl_find(struct namedobj_instance *ni, |
---|
73 | const char *name, uint8_t set); |
---|
74 | |
---|
75 | static struct nat64stl_cfg * |
---|
76 | nat64stl_alloc_config(const char *name, uint8_t set) |
---|
77 | { |
---|
78 | struct nat64stl_cfg *cfg; |
---|
79 | |
---|
80 | cfg = malloc(sizeof(struct nat64stl_cfg), M_IPFW, M_WAITOK | M_ZERO); |
---|
81 | COUNTER_ARRAY_ALLOC(cfg->stats.stats, NAT64STATS, M_WAITOK); |
---|
82 | cfg->no.name = cfg->name; |
---|
83 | cfg->no.etlv = IPFW_TLV_NAT64STL_NAME; |
---|
84 | cfg->no.set = set; |
---|
85 | strlcpy(cfg->name, name, sizeof(cfg->name)); |
---|
86 | return (cfg); |
---|
87 | } |
---|
88 | |
---|
89 | static void |
---|
90 | nat64stl_free_config(struct nat64stl_cfg *cfg) |
---|
91 | { |
---|
92 | |
---|
93 | COUNTER_ARRAY_FREE(cfg->stats.stats, NAT64STATS); |
---|
94 | free(cfg, M_IPFW); |
---|
95 | } |
---|
96 | |
---|
97 | static void |
---|
98 | nat64stl_export_config(struct ip_fw_chain *ch, struct nat64stl_cfg *cfg, |
---|
99 | ipfw_nat64stl_cfg *uc) |
---|
100 | { |
---|
101 | struct named_object *no; |
---|
102 | |
---|
103 | uc->prefix6 = cfg->prefix6; |
---|
104 | uc->plen6 = cfg->plen6; |
---|
105 | uc->flags = cfg->flags & NAT64STL_FLAGSMASK; |
---|
106 | uc->set = cfg->no.set; |
---|
107 | strlcpy(uc->name, cfg->no.name, sizeof(uc->name)); |
---|
108 | |
---|
109 | no = ipfw_objhash_lookup_table_kidx(ch, cfg->map64); |
---|
110 | ipfw_export_obj_ntlv(no, &uc->ntlv6); |
---|
111 | no = ipfw_objhash_lookup_table_kidx(ch, cfg->map46); |
---|
112 | ipfw_export_obj_ntlv(no, &uc->ntlv4); |
---|
113 | } |
---|
114 | |
---|
115 | struct nat64stl_dump_arg { |
---|
116 | struct ip_fw_chain *ch; |
---|
117 | struct sockopt_data *sd; |
---|
118 | }; |
---|
119 | |
---|
120 | static int |
---|
121 | export_config_cb(struct namedobj_instance *ni, struct named_object *no, |
---|
122 | void *arg) |
---|
123 | { |
---|
124 | struct nat64stl_dump_arg *da = (struct nat64stl_dump_arg *)arg; |
---|
125 | ipfw_nat64stl_cfg *uc; |
---|
126 | |
---|
127 | uc = (ipfw_nat64stl_cfg *)ipfw_get_sopt_space(da->sd, sizeof(*uc)); |
---|
128 | nat64stl_export_config(da->ch, (struct nat64stl_cfg *)no, uc); |
---|
129 | return (0); |
---|
130 | } |
---|
131 | |
---|
132 | static struct nat64stl_cfg * |
---|
133 | nat64stl_find(struct namedobj_instance *ni, const char *name, uint8_t set) |
---|
134 | { |
---|
135 | struct nat64stl_cfg *cfg; |
---|
136 | |
---|
137 | cfg = (struct nat64stl_cfg *)ipfw_objhash_lookup_name_type(ni, set, |
---|
138 | IPFW_TLV_NAT64STL_NAME, name); |
---|
139 | |
---|
140 | return (cfg); |
---|
141 | } |
---|
142 | |
---|
143 | |
---|
144 | static int |
---|
145 | nat64stl_create_internal(struct ip_fw_chain *ch, struct nat64stl_cfg *cfg, |
---|
146 | ipfw_nat64stl_cfg *i) |
---|
147 | { |
---|
148 | |
---|
149 | IPFW_UH_WLOCK_ASSERT(ch); |
---|
150 | |
---|
151 | if (ipfw_objhash_alloc_idx(CHAIN_TO_SRV(ch), &cfg->no.kidx) != 0) |
---|
152 | return (ENOSPC); |
---|
153 | cfg->flags |= NAT64STL_KIDX; |
---|
154 | |
---|
155 | if (ipfw_ref_table(ch, &i->ntlv4, &cfg->map46) != 0) |
---|
156 | return (EINVAL); |
---|
157 | cfg->flags |= NAT64STL_46T; |
---|
158 | |
---|
159 | if (ipfw_ref_table(ch, &i->ntlv6, &cfg->map64) != 0) |
---|
160 | return (EINVAL); |
---|
161 | cfg->flags |= NAT64STL_64T; |
---|
162 | |
---|
163 | ipfw_objhash_add(CHAIN_TO_SRV(ch), &cfg->no); |
---|
164 | |
---|
165 | return (0); |
---|
166 | } |
---|
167 | |
---|
168 | /* |
---|
169 | * Creates new nat64 instance. |
---|
170 | * Data layout (v0)(current): |
---|
171 | * Request: [ ipfw_obj_lheader ipfw_nat64stl_cfg ] |
---|
172 | * |
---|
173 | * Returns 0 on success |
---|
174 | */ |
---|
175 | static int |
---|
176 | nat64stl_create(struct ip_fw_chain *ch, ip_fw3_opheader *op3, |
---|
177 | struct sockopt_data *sd) |
---|
178 | { |
---|
179 | ipfw_obj_lheader *olh; |
---|
180 | ipfw_nat64stl_cfg *uc; |
---|
181 | struct namedobj_instance *ni; |
---|
182 | struct nat64stl_cfg *cfg; |
---|
183 | int error; |
---|
184 | |
---|
185 | if (sd->valsize != sizeof(*olh) + sizeof(*uc)) |
---|
186 | return (EINVAL); |
---|
187 | |
---|
188 | olh = (ipfw_obj_lheader *)sd->kbuf; |
---|
189 | uc = (ipfw_nat64stl_cfg *)(olh + 1); |
---|
190 | |
---|
191 | if (ipfw_check_object_name_generic(uc->name) != 0) |
---|
192 | return (EINVAL); |
---|
193 | if (!IN6_IS_ADDR_WKPFX(&uc->prefix6)) |
---|
194 | return (EINVAL); |
---|
195 | if (uc->plen6 != 96 || uc->set >= IPFW_MAX_SETS) |
---|
196 | return (EINVAL); |
---|
197 | |
---|
198 | /* XXX: check types of tables */ |
---|
199 | |
---|
200 | ni = CHAIN_TO_SRV(ch); |
---|
201 | error = 0; |
---|
202 | |
---|
203 | IPFW_UH_RLOCK(ch); |
---|
204 | if (nat64stl_find(ni, uc->name, uc->set) != NULL) { |
---|
205 | IPFW_UH_RUNLOCK(ch); |
---|
206 | return (EEXIST); |
---|
207 | } |
---|
208 | IPFW_UH_RUNLOCK(ch); |
---|
209 | |
---|
210 | cfg = nat64stl_alloc_config(uc->name, uc->set); |
---|
211 | cfg->prefix6 = uc->prefix6; |
---|
212 | cfg->plen6 = uc->plen6; |
---|
213 | cfg->flags = uc->flags & NAT64STL_FLAGSMASK; |
---|
214 | |
---|
215 | IPFW_UH_WLOCK(ch); |
---|
216 | |
---|
217 | if (nat64stl_find(ni, uc->name, uc->set) != NULL) { |
---|
218 | IPFW_UH_WUNLOCK(ch); |
---|
219 | nat64stl_free_config(cfg); |
---|
220 | return (EEXIST); |
---|
221 | } |
---|
222 | error = nat64stl_create_internal(ch, cfg, uc); |
---|
223 | if (error == 0) { |
---|
224 | /* Okay, let's link data */ |
---|
225 | IPFW_WLOCK(ch); |
---|
226 | SRV_OBJECT(ch, cfg->no.kidx) = cfg; |
---|
227 | IPFW_WUNLOCK(ch); |
---|
228 | |
---|
229 | IPFW_UH_WUNLOCK(ch); |
---|
230 | return (0); |
---|
231 | } |
---|
232 | |
---|
233 | if (cfg->flags & NAT64STL_KIDX) |
---|
234 | ipfw_objhash_free_idx(ni, cfg->no.kidx); |
---|
235 | if (cfg->flags & NAT64STL_46T) |
---|
236 | ipfw_unref_table(ch, cfg->map46); |
---|
237 | if (cfg->flags & NAT64STL_64T) |
---|
238 | ipfw_unref_table(ch, cfg->map64); |
---|
239 | |
---|
240 | IPFW_UH_WUNLOCK(ch); |
---|
241 | nat64stl_free_config(cfg); |
---|
242 | return (error); |
---|
243 | } |
---|
244 | |
---|
245 | /* |
---|
246 | * Change existing nat64stl instance configuration. |
---|
247 | * Data layout (v0)(current): |
---|
248 | * Request: [ ipfw_obj_header ipfw_nat64stl_cfg ] |
---|
249 | * Reply: [ ipfw_obj_header ipfw_nat64stl_cfg ] |
---|
250 | * |
---|
251 | * Returns 0 on success |
---|
252 | */ |
---|
253 | static int |
---|
254 | nat64stl_config(struct ip_fw_chain *ch, ip_fw3_opheader *op, |
---|
255 | struct sockopt_data *sd) |
---|
256 | { |
---|
257 | ipfw_obj_header *oh; |
---|
258 | ipfw_nat64stl_cfg *uc; |
---|
259 | struct nat64stl_cfg *cfg; |
---|
260 | struct namedobj_instance *ni; |
---|
261 | |
---|
262 | if (sd->valsize != sizeof(*oh) + sizeof(*uc)) |
---|
263 | return (EINVAL); |
---|
264 | |
---|
265 | oh = (ipfw_obj_header *)ipfw_get_sopt_space(sd, |
---|
266 | sizeof(*oh) + sizeof(*uc)); |
---|
267 | uc = (ipfw_nat64stl_cfg *)(oh + 1); |
---|
268 | |
---|
269 | if (ipfw_check_object_name_generic(oh->ntlv.name) != 0 || |
---|
270 | oh->ntlv.set >= IPFW_MAX_SETS) |
---|
271 | return (EINVAL); |
---|
272 | |
---|
273 | ni = CHAIN_TO_SRV(ch); |
---|
274 | if (sd->sopt->sopt_dir == SOPT_GET) { |
---|
275 | IPFW_UH_RLOCK(ch); |
---|
276 | cfg = nat64stl_find(ni, oh->ntlv.name, oh->ntlv.set); |
---|
277 | if (cfg == NULL) { |
---|
278 | IPFW_UH_RUNLOCK(ch); |
---|
279 | return (EEXIST); |
---|
280 | } |
---|
281 | nat64stl_export_config(ch, cfg, uc); |
---|
282 | IPFW_UH_RUNLOCK(ch); |
---|
283 | return (0); |
---|
284 | } |
---|
285 | |
---|
286 | IPFW_UH_WLOCK(ch); |
---|
287 | cfg = nat64stl_find(ni, oh->ntlv.name, oh->ntlv.set); |
---|
288 | if (cfg == NULL) { |
---|
289 | IPFW_UH_WUNLOCK(ch); |
---|
290 | return (EEXIST); |
---|
291 | } |
---|
292 | |
---|
293 | /* |
---|
294 | * For now allow to change only following values: |
---|
295 | * flags. |
---|
296 | */ |
---|
297 | |
---|
298 | cfg->flags = uc->flags & NAT64STL_FLAGSMASK; |
---|
299 | IPFW_UH_WUNLOCK(ch); |
---|
300 | return (0); |
---|
301 | } |
---|
302 | |
---|
303 | static void |
---|
304 | nat64stl_detach_config(struct ip_fw_chain *ch, struct nat64stl_cfg *cfg) |
---|
305 | { |
---|
306 | |
---|
307 | IPFW_UH_WLOCK_ASSERT(ch); |
---|
308 | |
---|
309 | ipfw_objhash_del(CHAIN_TO_SRV(ch), &cfg->no); |
---|
310 | ipfw_objhash_free_idx(CHAIN_TO_SRV(ch), cfg->no.kidx); |
---|
311 | ipfw_unref_table(ch, cfg->map46); |
---|
312 | ipfw_unref_table(ch, cfg->map64); |
---|
313 | } |
---|
314 | |
---|
315 | /* |
---|
316 | * Destroys nat64 instance. |
---|
317 | * Data layout (v0)(current): |
---|
318 | * Request: [ ipfw_obj_header ] |
---|
319 | * |
---|
320 | * Returns 0 on success |
---|
321 | */ |
---|
322 | static int |
---|
323 | nat64stl_destroy(struct ip_fw_chain *ch, ip_fw3_opheader *op3, |
---|
324 | struct sockopt_data *sd) |
---|
325 | { |
---|
326 | ipfw_obj_header *oh; |
---|
327 | struct nat64stl_cfg *cfg; |
---|
328 | |
---|
329 | if (sd->valsize != sizeof(*oh)) |
---|
330 | return (EINVAL); |
---|
331 | |
---|
332 | oh = (ipfw_obj_header *)sd->kbuf; |
---|
333 | if (ipfw_check_object_name_generic(oh->ntlv.name) != 0) |
---|
334 | return (EINVAL); |
---|
335 | |
---|
336 | IPFW_UH_WLOCK(ch); |
---|
337 | cfg = nat64stl_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set); |
---|
338 | if (cfg == NULL) { |
---|
339 | IPFW_UH_WUNLOCK(ch); |
---|
340 | return (ESRCH); |
---|
341 | } |
---|
342 | if (cfg->no.refcnt > 0) { |
---|
343 | IPFW_UH_WUNLOCK(ch); |
---|
344 | return (EBUSY); |
---|
345 | } |
---|
346 | |
---|
347 | IPFW_WLOCK(ch); |
---|
348 | SRV_OBJECT(ch, cfg->no.kidx) = NULL; |
---|
349 | IPFW_WUNLOCK(ch); |
---|
350 | |
---|
351 | nat64stl_detach_config(ch, cfg); |
---|
352 | IPFW_UH_WUNLOCK(ch); |
---|
353 | |
---|
354 | nat64stl_free_config(cfg); |
---|
355 | return (0); |
---|
356 | } |
---|
357 | |
---|
358 | /* |
---|
359 | * Lists all nat64stl instances currently available in kernel. |
---|
360 | * Data layout (v0)(current): |
---|
361 | * Request: [ ipfw_obj_lheader ] |
---|
362 | * Reply: [ ipfw_obj_lheader ipfw_nat64stl_cfg x N ] |
---|
363 | * |
---|
364 | * Returns 0 on success |
---|
365 | */ |
---|
366 | static int |
---|
367 | nat64stl_list(struct ip_fw_chain *ch, ip_fw3_opheader *op3, |
---|
368 | struct sockopt_data *sd) |
---|
369 | { |
---|
370 | ipfw_obj_lheader *olh; |
---|
371 | struct nat64stl_dump_arg da; |
---|
372 | |
---|
373 | /* Check minimum header size */ |
---|
374 | if (sd->valsize < sizeof(ipfw_obj_lheader)) |
---|
375 | return (EINVAL); |
---|
376 | |
---|
377 | olh = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*olh)); |
---|
378 | |
---|
379 | IPFW_UH_RLOCK(ch); |
---|
380 | olh->count = ipfw_objhash_count_type(CHAIN_TO_SRV(ch), |
---|
381 | IPFW_TLV_NAT64STL_NAME); |
---|
382 | olh->objsize = sizeof(ipfw_nat64stl_cfg); |
---|
383 | olh->size = sizeof(*olh) + olh->count * olh->objsize; |
---|
384 | |
---|
385 | if (sd->valsize < olh->size) { |
---|
386 | IPFW_UH_RUNLOCK(ch); |
---|
387 | return (ENOMEM); |
---|
388 | } |
---|
389 | memset(&da, 0, sizeof(da)); |
---|
390 | da.ch = ch; |
---|
391 | da.sd = sd; |
---|
392 | ipfw_objhash_foreach_type(CHAIN_TO_SRV(ch), export_config_cb, |
---|
393 | &da, IPFW_TLV_NAT64STL_NAME); |
---|
394 | IPFW_UH_RUNLOCK(ch); |
---|
395 | |
---|
396 | return (0); |
---|
397 | } |
---|
398 | |
---|
399 | #define __COPY_STAT_FIELD(_cfg, _stats, _field) \ |
---|
400 | (_stats)->_field = NAT64STAT_FETCH(&(_cfg)->stats, _field) |
---|
401 | static void |
---|
402 | export_stats(struct ip_fw_chain *ch, struct nat64stl_cfg *cfg, |
---|
403 | struct ipfw_nat64stl_stats *stats) |
---|
404 | { |
---|
405 | |
---|
406 | __COPY_STAT_FIELD(cfg, stats, opcnt64); |
---|
407 | __COPY_STAT_FIELD(cfg, stats, opcnt46); |
---|
408 | __COPY_STAT_FIELD(cfg, stats, ofrags); |
---|
409 | __COPY_STAT_FIELD(cfg, stats, ifrags); |
---|
410 | __COPY_STAT_FIELD(cfg, stats, oerrors); |
---|
411 | __COPY_STAT_FIELD(cfg, stats, noroute4); |
---|
412 | __COPY_STAT_FIELD(cfg, stats, noroute6); |
---|
413 | __COPY_STAT_FIELD(cfg, stats, noproto); |
---|
414 | __COPY_STAT_FIELD(cfg, stats, nomem); |
---|
415 | __COPY_STAT_FIELD(cfg, stats, dropped); |
---|
416 | } |
---|
417 | |
---|
418 | /* |
---|
419 | * Get nat64stl statistics. |
---|
420 | * Data layout (v0)(current): |
---|
421 | * Request: [ ipfw_obj_header ] |
---|
422 | * Reply: [ ipfw_obj_header ipfw_obj_ctlv [ uint64_t x N ]] |
---|
423 | * |
---|
424 | * Returns 0 on success |
---|
425 | */ |
---|
426 | static int |
---|
427 | nat64stl_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op, |
---|
428 | struct sockopt_data *sd) |
---|
429 | { |
---|
430 | struct ipfw_nat64stl_stats stats; |
---|
431 | struct nat64stl_cfg *cfg; |
---|
432 | ipfw_obj_header *oh; |
---|
433 | ipfw_obj_ctlv *ctlv; |
---|
434 | size_t sz; |
---|
435 | |
---|
436 | sz = sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ctlv) + sizeof(stats); |
---|
437 | if (sd->valsize % sizeof(uint64_t)) |
---|
438 | return (EINVAL); |
---|
439 | if (sd->valsize < sz) |
---|
440 | return (ENOMEM); |
---|
441 | oh = (ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); |
---|
442 | if (oh == NULL) |
---|
443 | return (EINVAL); |
---|
444 | memset(&stats, 0, sizeof(stats)); |
---|
445 | |
---|
446 | IPFW_UH_RLOCK(ch); |
---|
447 | cfg = nat64stl_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set); |
---|
448 | if (cfg == NULL) { |
---|
449 | IPFW_UH_RUNLOCK(ch); |
---|
450 | return (ESRCH); |
---|
451 | } |
---|
452 | export_stats(ch, cfg, &stats); |
---|
453 | IPFW_UH_RUNLOCK(ch); |
---|
454 | |
---|
455 | ctlv = (ipfw_obj_ctlv *)(oh + 1); |
---|
456 | memset(ctlv, 0, sizeof(*ctlv)); |
---|
457 | ctlv->head.type = IPFW_TLV_COUNTERS; |
---|
458 | ctlv->head.length = sz - sizeof(ipfw_obj_header); |
---|
459 | ctlv->count = sizeof(stats) / sizeof(uint64_t); |
---|
460 | ctlv->objsize = sizeof(uint64_t); |
---|
461 | ctlv->version = IPFW_NAT64_VERSION; |
---|
462 | memcpy(ctlv + 1, &stats, sizeof(stats)); |
---|
463 | return (0); |
---|
464 | } |
---|
465 | |
---|
466 | /* |
---|
467 | * Reset nat64stl statistics. |
---|
468 | * Data layout (v0)(current): |
---|
469 | * Request: [ ipfw_obj_header ] |
---|
470 | * |
---|
471 | * Returns 0 on success |
---|
472 | */ |
---|
473 | static int |
---|
474 | nat64stl_reset_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op, |
---|
475 | struct sockopt_data *sd) |
---|
476 | { |
---|
477 | struct nat64stl_cfg *cfg; |
---|
478 | ipfw_obj_header *oh; |
---|
479 | |
---|
480 | if (sd->valsize != sizeof(*oh)) |
---|
481 | return (EINVAL); |
---|
482 | oh = (ipfw_obj_header *)sd->kbuf; |
---|
483 | if (ipfw_check_object_name_generic(oh->ntlv.name) != 0 || |
---|
484 | oh->ntlv.set >= IPFW_MAX_SETS) |
---|
485 | return (EINVAL); |
---|
486 | |
---|
487 | IPFW_UH_WLOCK(ch); |
---|
488 | cfg = nat64stl_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set); |
---|
489 | if (cfg == NULL) { |
---|
490 | IPFW_UH_WUNLOCK(ch); |
---|
491 | return (ESRCH); |
---|
492 | } |
---|
493 | COUNTER_ARRAY_ZERO(cfg->stats.stats, NAT64STATS); |
---|
494 | IPFW_UH_WUNLOCK(ch); |
---|
495 | return (0); |
---|
496 | } |
---|
497 | |
---|
498 | static struct ipfw_sopt_handler scodes[] = { |
---|
499 | |
---|
500 | { IP_FW_NAT64STL_CREATE, 0, HDIR_SET, nat64stl_create }, |
---|
501 | { IP_FW_NAT64STL_DESTROY,0, HDIR_SET, nat64stl_destroy }, |
---|
502 | { IP_FW_NAT64STL_CONFIG, 0, HDIR_BOTH, nat64stl_config }, |
---|
503 | { IP_FW_NAT64STL_LIST, 0, HDIR_GET, nat64stl_list }, |
---|
504 | { IP_FW_NAT64STL_STATS, 0, HDIR_GET, nat64stl_stats }, |
---|
505 | { IP_FW_NAT64STL_RESET_STATS,0, HDIR_SET, nat64stl_reset_stats }, |
---|
506 | }; |
---|
507 | |
---|
508 | static int |
---|
509 | nat64stl_classify(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) |
---|
510 | { |
---|
511 | ipfw_insn *icmd; |
---|
512 | |
---|
513 | icmd = cmd - 1; |
---|
514 | if (icmd->opcode != O_EXTERNAL_ACTION || |
---|
515 | icmd->arg1 != V_nat64stl_eid) |
---|
516 | return (1); |
---|
517 | |
---|
518 | *puidx = cmd->arg1; |
---|
519 | *ptype = 0; |
---|
520 | return (0); |
---|
521 | } |
---|
522 | |
---|
523 | static void |
---|
524 | nat64stl_update_arg1(ipfw_insn *cmd, uint16_t idx) |
---|
525 | { |
---|
526 | |
---|
527 | cmd->arg1 = idx; |
---|
528 | } |
---|
529 | |
---|
530 | static int |
---|
531 | nat64stl_findbyname(struct ip_fw_chain *ch, struct tid_info *ti, |
---|
532 | struct named_object **pno) |
---|
533 | { |
---|
534 | int err; |
---|
535 | |
---|
536 | err = ipfw_objhash_find_type(CHAIN_TO_SRV(ch), ti, |
---|
537 | IPFW_TLV_NAT64STL_NAME, pno); |
---|
538 | return (err); |
---|
539 | } |
---|
540 | |
---|
541 | static struct named_object * |
---|
542 | nat64stl_findbykidx(struct ip_fw_chain *ch, uint16_t idx) |
---|
543 | { |
---|
544 | struct namedobj_instance *ni; |
---|
545 | struct named_object *no; |
---|
546 | |
---|
547 | IPFW_UH_WLOCK_ASSERT(ch); |
---|
548 | ni = CHAIN_TO_SRV(ch); |
---|
549 | no = ipfw_objhash_lookup_kidx(ni, idx); |
---|
550 | KASSERT(no != NULL, ("NAT with index %d not found", idx)); |
---|
551 | |
---|
552 | return (no); |
---|
553 | } |
---|
554 | |
---|
555 | static int |
---|
556 | nat64stl_manage_sets(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set, |
---|
557 | enum ipfw_sets_cmd cmd) |
---|
558 | { |
---|
559 | |
---|
560 | return (ipfw_obj_manage_sets(CHAIN_TO_SRV(ch), IPFW_TLV_NAT64STL_NAME, |
---|
561 | set, new_set, cmd)); |
---|
562 | } |
---|
563 | |
---|
564 | static struct opcode_obj_rewrite opcodes[] = { |
---|
565 | { |
---|
566 | .opcode = O_EXTERNAL_INSTANCE, |
---|
567 | .etlv = IPFW_TLV_EACTION /* just show it isn't table */, |
---|
568 | .classifier = nat64stl_classify, |
---|
569 | .update = nat64stl_update_arg1, |
---|
570 | .find_byname = nat64stl_findbyname, |
---|
571 | .find_bykidx = nat64stl_findbykidx, |
---|
572 | .manage_sets = nat64stl_manage_sets, |
---|
573 | }, |
---|
574 | }; |
---|
575 | |
---|
576 | static int |
---|
577 | destroy_config_cb(struct namedobj_instance *ni, struct named_object *no, |
---|
578 | void *arg) |
---|
579 | { |
---|
580 | struct nat64stl_cfg *cfg; |
---|
581 | struct ip_fw_chain *ch; |
---|
582 | |
---|
583 | ch = (struct ip_fw_chain *)arg; |
---|
584 | cfg = (struct nat64stl_cfg *)SRV_OBJECT(ch, no->kidx); |
---|
585 | SRV_OBJECT(ch, no->kidx) = NULL; |
---|
586 | nat64stl_detach_config(ch, cfg); |
---|
587 | nat64stl_free_config(cfg); |
---|
588 | return (0); |
---|
589 | } |
---|
590 | |
---|
591 | int |
---|
592 | nat64stl_init(struct ip_fw_chain *ch, int first) |
---|
593 | { |
---|
594 | |
---|
595 | V_nat64stl_eid = ipfw_add_eaction(ch, ipfw_nat64stl, "nat64stl"); |
---|
596 | if (V_nat64stl_eid == 0) |
---|
597 | return (ENXIO); |
---|
598 | IPFW_ADD_SOPT_HANDLER(first, scodes); |
---|
599 | IPFW_ADD_OBJ_REWRITER(first, opcodes); |
---|
600 | return (0); |
---|
601 | } |
---|
602 | |
---|
603 | void |
---|
604 | nat64stl_uninit(struct ip_fw_chain *ch, int last) |
---|
605 | { |
---|
606 | |
---|
607 | IPFW_DEL_OBJ_REWRITER(last, opcodes); |
---|
608 | IPFW_DEL_SOPT_HANDLER(last, scodes); |
---|
609 | ipfw_del_eaction(ch, V_nat64stl_eid); |
---|
610 | /* |
---|
611 | * Since we already have deregistered external action, |
---|
612 | * our named objects become unaccessible via rules, because |
---|
613 | * all rules were truncated by ipfw_del_eaction(). |
---|
614 | * So, we can unlink and destroy our named objects without holding |
---|
615 | * IPFW_WLOCK(). |
---|
616 | */ |
---|
617 | IPFW_UH_WLOCK(ch); |
---|
618 | ipfw_objhash_foreach_type(CHAIN_TO_SRV(ch), destroy_config_cb, ch, |
---|
619 | IPFW_TLV_NAT64STL_NAME); |
---|
620 | V_nat64stl_eid = 0; |
---|
621 | IPFW_UH_WUNLOCK(ch); |
---|
622 | } |
---|
623 | |
---|