npf.c revision 1.30 1 /* $NetBSD: npf.c,v 1.30 2014/07/23 01:25:34 rmind Exp $ */
2
3 /*-
4 * Copyright (c) 2010-2014 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This material is based upon work partially supported by The
8 * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.30 2014/07/23 01:25:34 rmind Exp $");
34
35 #include <sys/types.h>
36 #include <netinet/in_systm.h>
37 #include <netinet/in.h>
38 #include <net/if.h>
39 #include <prop/proplib.h>
40
41 #include <stdlib.h>
42 #include <string.h>
43 #include <assert.h>
44 #include <errno.h>
45 #include <err.h>
46
47 #define _NPF_PRIVATE
48 #include "npf.h"
49
50 struct nl_rule {
51 prop_dictionary_t nrl_dict;
52 };
53
54 struct nl_rproc {
55 prop_dictionary_t nrp_dict;
56 };
57
58 struct nl_table {
59 prop_dictionary_t ntl_dict;
60 };
61
62 struct nl_alg {
63 prop_dictionary_t nal_dict;
64 };
65
66 struct nl_ext {
67 const char * nxt_name;
68 prop_dictionary_t nxt_dict;
69 };
70
71 struct nl_config {
72 /* Rules, translations, tables, procedures. */
73 prop_dictionary_t ncf_dict;
74 prop_array_t ncf_alg_list;
75 prop_array_t ncf_rules_list;
76 prop_array_t ncf_rproc_list;
77 prop_array_t ncf_table_list;
78 prop_array_t ncf_nat_list;
79
80 /* Iterators. */
81 prop_object_iterator_t ncf_rule_iter;
82 unsigned ncf_reduce[16];
83 unsigned ncf_nlevel;
84 unsigned ncf_counter;
85 nl_rule_t ncf_cur_rule;
86
87 prop_object_iterator_t ncf_table_iter;
88 nl_table_t ncf_cur_table;
89
90 prop_object_iterator_t ncf_rproc_iter;
91 nl_rproc_t ncf_cur_rproc;
92
93 /* Error report and debug information. */
94 prop_dictionary_t ncf_err;
95 prop_dictionary_t ncf_debug;
96
97 /* Custom file to externalise property-list. */
98 const char * ncf_plist;
99 bool ncf_flush;
100 };
101
102 static prop_array_t _npf_ruleset_transform(prop_array_t);
103
104 /*
105 * CONFIGURATION INTERFACE.
106 */
107
108 nl_config_t *
109 npf_config_create(void)
110 {
111 nl_config_t *ncf;
112
113 ncf = calloc(1, sizeof(*ncf));
114 if (ncf == NULL) {
115 return NULL;
116 }
117 ncf->ncf_alg_list = prop_array_create();
118 ncf->ncf_rules_list = prop_array_create();
119 ncf->ncf_rproc_list = prop_array_create();
120 ncf->ncf_table_list = prop_array_create();
121 ncf->ncf_nat_list = prop_array_create();
122
123 ncf->ncf_plist = NULL;
124 ncf->ncf_flush = false;
125
126 return ncf;
127 }
128
129 int
130 npf_config_submit(nl_config_t *ncf, int fd)
131 {
132 const char *plist = ncf->ncf_plist;
133 prop_dictionary_t npf_dict;
134 prop_array_t rlset;
135 int error = 0;
136
137 npf_dict = prop_dictionary_create();
138 if (npf_dict == NULL) {
139 return ENOMEM;
140 }
141 prop_dictionary_set_uint32(npf_dict, "version", NPF_VERSION);
142
143 rlset = _npf_ruleset_transform(ncf->ncf_rules_list);
144 if (rlset == NULL) {
145 prop_object_release(npf_dict);
146 return ENOMEM;
147 }
148 prop_object_release(ncf->ncf_rules_list);
149 ncf->ncf_rules_list = rlset;
150
151 prop_dictionary_set(npf_dict, "rules", ncf->ncf_rules_list);
152 prop_dictionary_set(npf_dict, "algs", ncf->ncf_alg_list);
153 prop_dictionary_set(npf_dict, "rprocs", ncf->ncf_rproc_list);
154 prop_dictionary_set(npf_dict, "tables", ncf->ncf_table_list);
155 prop_dictionary_set(npf_dict, "translation", ncf->ncf_nat_list);
156 prop_dictionary_set_bool(npf_dict, "flush", ncf->ncf_flush);
157 if (ncf->ncf_debug) {
158 prop_dictionary_set(npf_dict, "debug", ncf->ncf_debug);
159 }
160
161 if (plist) {
162 if (!prop_dictionary_externalize_to_file(npf_dict, plist)) {
163 error = errno;
164 }
165 prop_object_release(npf_dict);
166 return error;
167 }
168 if (fd) {
169 error = prop_dictionary_sendrecv_ioctl(npf_dict, fd,
170 IOC_NPF_LOAD, &ncf->ncf_err);
171 if (error) {
172 prop_object_release(npf_dict);
173 assert(ncf->ncf_err == NULL);
174 return error;
175 }
176 prop_dictionary_get_int32(ncf->ncf_err, "errno", &error);
177 }
178 prop_object_release(npf_dict);
179 return error;
180 }
181
182 static nl_config_t *
183 _npf_config_consdict(prop_dictionary_t npf_dict)
184 {
185 nl_config_t *ncf;
186
187 ncf = calloc(1, sizeof(*ncf));
188 if (ncf == NULL) {
189 return NULL;
190 }
191 ncf->ncf_dict = npf_dict;
192 ncf->ncf_alg_list = prop_dictionary_get(npf_dict, "algs");
193 ncf->ncf_rules_list = prop_dictionary_get(npf_dict, "rules");
194 ncf->ncf_rproc_list = prop_dictionary_get(npf_dict, "rprocs");
195 ncf->ncf_table_list = prop_dictionary_get(npf_dict, "tables");
196 ncf->ncf_nat_list = prop_dictionary_get(npf_dict, "translation");
197 return ncf;
198 }
199
200 nl_config_t *
201 npf_config_retrieve(int fd, bool *active, bool *loaded)
202 {
203 prop_dictionary_t npf_dict;
204 nl_config_t *ncf;
205 int error;
206
207 error = prop_dictionary_recv_ioctl(fd, IOC_NPF_SAVE, &npf_dict);
208 if (error) {
209 return NULL;
210 }
211 ncf = _npf_config_consdict(npf_dict);
212 if (ncf == NULL) {
213 prop_object_release(npf_dict);
214 return NULL;
215 }
216 prop_dictionary_get_bool(npf_dict, "active", active);
217 *loaded = (ncf->ncf_rules_list != NULL);
218 return ncf;
219 }
220
221 int
222 npf_config_export(const nl_config_t *ncf, const char *path)
223 {
224 prop_dictionary_t npf_dict = ncf->ncf_dict;
225 int error = 0;
226
227 if (!prop_dictionary_externalize_to_file(npf_dict, path)) {
228 error = errno;
229 }
230 return 0;
231 }
232
233 nl_config_t *
234 npf_config_import(const char *path)
235 {
236 prop_dictionary_t npf_dict;
237 nl_config_t *ncf;
238
239 npf_dict = prop_dictionary_internalize_from_file(path);
240 if (npf_dict) {
241 return NULL;
242 }
243 ncf = _npf_config_consdict(npf_dict);
244 if (ncf == NULL) {
245 prop_object_release(npf_dict);
246 return NULL;
247 }
248 return ncf;
249 }
250
251 int
252 npf_config_flush(int fd)
253 {
254 nl_config_t *ncf;
255 int error;
256
257 ncf = npf_config_create();
258 if (ncf == NULL) {
259 return ENOMEM;
260 }
261 ncf->ncf_flush = true;
262 error = npf_config_submit(ncf, fd);
263 npf_config_destroy(ncf);
264 return error;
265 }
266
267 void
268 _npf_config_error(nl_config_t *ncf, nl_error_t *ne)
269 {
270 memset(ne, 0, sizeof(*ne));
271 prop_dictionary_get_int32(ncf->ncf_err, "id", &ne->ne_id);
272 prop_dictionary_get_cstring(ncf->ncf_err,
273 "source-file", &ne->ne_source_file);
274 prop_dictionary_get_uint32(ncf->ncf_err,
275 "source-line", &ne->ne_source_line);
276 prop_dictionary_get_int32(ncf->ncf_err,
277 "code-error", &ne->ne_ncode_error);
278 prop_dictionary_get_int32(ncf->ncf_err,
279 "code-errat", &ne->ne_ncode_errat);
280 }
281
282 void
283 npf_config_destroy(nl_config_t *ncf)
284 {
285 if (!ncf->ncf_dict) {
286 prop_object_release(ncf->ncf_alg_list);
287 prop_object_release(ncf->ncf_rules_list);
288 prop_object_release(ncf->ncf_rproc_list);
289 prop_object_release(ncf->ncf_table_list);
290 prop_object_release(ncf->ncf_nat_list);
291 }
292 if (ncf->ncf_err) {
293 prop_object_release(ncf->ncf_err);
294 }
295 if (ncf->ncf_debug) {
296 prop_object_release(ncf->ncf_debug);
297 }
298 free(ncf);
299 }
300
301 void
302 _npf_config_setsubmit(nl_config_t *ncf, const char *plist_file)
303 {
304 ncf->ncf_plist = plist_file;
305 }
306
307 static bool
308 _npf_prop_array_lookup(prop_array_t array, const char *key, const char *name)
309 {
310 prop_dictionary_t dict;
311 prop_object_iterator_t it;
312
313 it = prop_array_iterator(array);
314 while ((dict = prop_object_iterator_next(it)) != NULL) {
315 const char *lname;
316 prop_dictionary_get_cstring_nocopy(dict, key, &lname);
317 if (strcmp(name, lname) == 0)
318 break;
319 }
320 prop_object_iterator_release(it);
321 return dict ? true : false;
322 }
323
324 /*
325 * DYNAMIC RULESET INTERFACE.
326 */
327
328 int
329 npf_ruleset_add(int fd, const char *rname, nl_rule_t *rl, uint64_t *id)
330 {
331 prop_dictionary_t rldict = rl->nrl_dict;
332 prop_dictionary_t ret;
333 int error;
334
335 prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
336 prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_ADD);
337 error = prop_dictionary_sendrecv_ioctl(rldict, fd, IOC_NPF_RULE, &ret);
338 if (!error) {
339 prop_dictionary_get_uint64(ret, "id", id);
340 }
341 return error;
342 }
343
344 int
345 npf_ruleset_remove(int fd, const char *rname, uint64_t id)
346 {
347 prop_dictionary_t rldict;
348
349 rldict = prop_dictionary_create();
350 if (rldict == NULL) {
351 return ENOMEM;
352 }
353 prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
354 prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_REMOVE);
355 prop_dictionary_set_uint64(rldict, "id", id);
356 return prop_dictionary_send_ioctl(rldict, fd, IOC_NPF_RULE);
357 }
358
359 int
360 npf_ruleset_remkey(int fd, const char *rname, const void *key, size_t len)
361 {
362 prop_dictionary_t rldict;
363 prop_data_t keyobj;
364
365 rldict = prop_dictionary_create();
366 if (rldict == NULL) {
367 return ENOMEM;
368 }
369 prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
370 prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_REMKEY);
371
372 keyobj = prop_data_create_data(key, len);
373 if (keyobj == NULL) {
374 prop_object_release(rldict);
375 return ENOMEM;
376 }
377 prop_dictionary_set(rldict, "key", keyobj);
378 prop_object_release(keyobj);
379
380 return prop_dictionary_send_ioctl(rldict, fd, IOC_NPF_RULE);
381 }
382
383 int
384 npf_ruleset_flush(int fd, const char *rname)
385 {
386 prop_dictionary_t rldict;
387
388 rldict = prop_dictionary_create();
389 if (rldict == NULL) {
390 return ENOMEM;
391 }
392 prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
393 prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_FLUSH);
394 return prop_dictionary_send_ioctl(rldict, fd, IOC_NPF_RULE);
395 }
396
397 /*
398 * _npf_ruleset_transform: transform the ruleset representing nested
399 * rules with lists into an array.
400 */
401
402 static void
403 _npf_ruleset_transform1(prop_array_t rlset, prop_array_t rules)
404 {
405 prop_object_iterator_t it;
406 prop_dictionary_t rldict;
407 prop_array_t subrlset;
408
409 it = prop_array_iterator(rules);
410 while ((rldict = prop_object_iterator_next(it)) != NULL) {
411 unsigned idx;
412
413 /* Add rules to the array (reference is retained). */
414 prop_array_add(rlset, rldict);
415
416 subrlset = prop_dictionary_get(rldict, "subrules");
417 if (subrlset) {
418 /* Process subrules recursively. */
419 _npf_ruleset_transform1(rlset, subrlset);
420 /* Add the skip-to position. */
421 idx = prop_array_count(rlset);
422 prop_dictionary_set_uint32(rldict, "skip-to", idx);
423 prop_dictionary_remove(rldict, "subrules");
424 }
425 }
426 prop_object_iterator_release(it);
427 }
428
429 static prop_array_t
430 _npf_ruleset_transform(prop_array_t rlset)
431 {
432 prop_array_t nrlset;
433
434 nrlset = prop_array_create();
435 _npf_ruleset_transform1(nrlset, rlset);
436 return nrlset;
437 }
438
439 /*
440 * NPF EXTENSION INTERFACE.
441 */
442
443 nl_ext_t *
444 npf_ext_construct(const char *name)
445 {
446 nl_ext_t *ext;
447
448 ext = malloc(sizeof(*ext));
449 if (ext == NULL) {
450 return NULL;
451 }
452 ext->nxt_name = strdup(name);
453 if (ext->nxt_name == NULL) {
454 free(ext);
455 return NULL;
456 }
457 ext->nxt_dict = prop_dictionary_create();
458
459 return ext;
460 }
461
462 void
463 npf_ext_param_u32(nl_ext_t *ext, const char *key, uint32_t val)
464 {
465 prop_dictionary_t extdict = ext->nxt_dict;
466 prop_dictionary_set_uint32(extdict, key, val);
467 }
468
469 void
470 npf_ext_param_bool(nl_ext_t *ext, const char *key, bool val)
471 {
472 prop_dictionary_t extdict = ext->nxt_dict;
473 prop_dictionary_set_bool(extdict, key, val);
474 }
475
476 void
477 npf_ext_param_string(nl_ext_t *ext, const char *key, const char *val)
478 {
479 prop_dictionary_t extdict = ext->nxt_dict;
480 prop_dictionary_set_cstring(extdict, key, val);
481 }
482
483 /*
484 * RULE INTERFACE.
485 */
486
487 nl_rule_t *
488 npf_rule_create(const char *name, uint32_t attr, const char *ifname)
489 {
490 prop_dictionary_t rldict;
491 nl_rule_t *rl;
492
493 rl = malloc(sizeof(*rl));
494 if (rl == NULL) {
495 return NULL;
496 }
497 rldict = prop_dictionary_create();
498 if (rldict == NULL) {
499 free(rl);
500 return NULL;
501 }
502 if (name) {
503 prop_dictionary_set_cstring(rldict, "name", name);
504 }
505 prop_dictionary_set_uint32(rldict, "attributes", attr);
506
507 if (ifname) {
508 prop_dictionary_set_cstring(rldict, "interface", ifname);
509 }
510 rl->nrl_dict = rldict;
511 return rl;
512 }
513
514 int
515 npf_rule_setcode(nl_rule_t *rl, int type, const void *code, size_t len)
516 {
517 prop_dictionary_t rldict = rl->nrl_dict;
518 prop_data_t cdata;
519
520 switch (type) {
521 case NPF_CODE_NC:
522 case NPF_CODE_BPF:
523 break;
524 default:
525 return ENOTSUP;
526 }
527 prop_dictionary_set_uint32(rldict, "code-type", type);
528 if ((cdata = prop_data_create_data(code, len)) == NULL) {
529 return ENOMEM;
530 }
531 prop_dictionary_set(rldict, "code", cdata);
532 prop_object_release(cdata);
533 return 0;
534 }
535
536 int
537 npf_rule_setkey(nl_rule_t *rl, const void *key, size_t len)
538 {
539 prop_dictionary_t rldict = rl->nrl_dict;
540 prop_data_t kdata;
541
542 if ((kdata = prop_data_create_data(key, len)) == NULL) {
543 return ENOMEM;
544 }
545 prop_dictionary_set(rldict, "key", kdata);
546 prop_object_release(kdata);
547 return 0;
548 }
549
550 int
551 npf_rule_setinfo(nl_rule_t *rl, const void *info, size_t len)
552 {
553 prop_dictionary_t rldict = rl->nrl_dict;
554 prop_data_t idata;
555
556 if ((idata = prop_data_create_data(info, len)) == NULL) {
557 return ENOMEM;
558 }
559 prop_dictionary_set(rldict, "info", idata);
560 prop_object_release(idata);
561 return 0;
562 }
563
564 int
565 npf_rule_setprio(nl_rule_t *rl, pri_t pri)
566 {
567 prop_dictionary_t rldict = rl->nrl_dict;
568
569 prop_dictionary_set_int32(rldict, "priority", pri);
570 return 0;
571 }
572
573 int
574 npf_rule_setproc(nl_rule_t *rl, const char *name)
575 {
576 prop_dictionary_t rldict = rl->nrl_dict;
577
578 prop_dictionary_set_cstring(rldict, "rproc", name);
579 return 0;
580 }
581
582 void *
583 npf_rule_export(nl_rule_t *rl, size_t *length)
584 {
585 prop_dictionary_t rldict = rl->nrl_dict;
586 void *xml;
587
588 if ((xml = prop_dictionary_externalize(rldict)) == NULL) {
589 return NULL;
590 }
591 *length = strlen(xml);
592 return xml;
593 }
594
595 bool
596 npf_rule_exists_p(nl_config_t *ncf, const char *name)
597 {
598 return _npf_prop_array_lookup(ncf->ncf_rules_list, "name", name);
599 }
600
601 int
602 npf_rule_insert(nl_config_t *ncf, nl_rule_t *parent, nl_rule_t *rl)
603 {
604 prop_dictionary_t rldict = rl->nrl_dict;
605 prop_array_t rlset;
606
607 if (parent) {
608 prop_dictionary_t pdict = parent->nrl_dict;
609 rlset = prop_dictionary_get(pdict, "subrules");
610 if (rlset == NULL) {
611 rlset = prop_array_create();
612 prop_dictionary_set(pdict, "subrules", rlset);
613 prop_object_release(rlset);
614 }
615 } else {
616 rlset = ncf->ncf_rules_list;
617 }
618 prop_array_add(rlset, rldict);
619 return 0;
620 }
621
622 static nl_rule_t *
623 _npf_rule_iterate1(nl_config_t *ncf, prop_array_t rlist, unsigned *level)
624 {
625 prop_dictionary_t rldict;
626 uint32_t skipto = 0;
627
628 if (!ncf->ncf_rule_iter) {
629 /* Initialise the iterator. */
630 ncf->ncf_rule_iter = prop_array_iterator(rlist);
631 ncf->ncf_nlevel = 0;
632 ncf->ncf_reduce[0] = 0;
633 ncf->ncf_counter = 0;
634 }
635
636 rldict = prop_object_iterator_next(ncf->ncf_rule_iter);
637 if ((ncf->ncf_cur_rule.nrl_dict = rldict) == NULL) {
638 prop_object_iterator_release(ncf->ncf_rule_iter);
639 ncf->ncf_rule_iter = NULL;
640 return NULL;
641 }
642 *level = ncf->ncf_nlevel;
643
644 prop_dictionary_get_uint32(rldict, "skip-to", &skipto);
645 if (skipto) {
646 ncf->ncf_nlevel++;
647 ncf->ncf_reduce[ncf->ncf_nlevel] = skipto;
648 }
649 if (ncf->ncf_reduce[ncf->ncf_nlevel] == ++ncf->ncf_counter) {
650 assert(ncf->ncf_nlevel > 0);
651 ncf->ncf_nlevel--;
652 }
653 return &ncf->ncf_cur_rule;
654 }
655
656 nl_rule_t *
657 npf_rule_iterate(nl_config_t *ncf, unsigned *level)
658 {
659 return _npf_rule_iterate1(ncf, ncf->ncf_rules_list, level);
660 }
661
662 const char *
663 npf_rule_getname(nl_rule_t *rl)
664 {
665 prop_dictionary_t rldict = rl->nrl_dict;
666 const char *rname = NULL;
667
668 prop_dictionary_get_cstring_nocopy(rldict, "name", &rname);
669 return rname;
670 }
671
672 uint32_t
673 npf_rule_getattr(nl_rule_t *rl)
674 {
675 prop_dictionary_t rldict = rl->nrl_dict;
676 uint32_t attr = 0;
677
678 prop_dictionary_get_uint32(rldict, "attributes", &attr);
679 return attr;
680 }
681
682 const char *
683 npf_rule_getinterface(nl_rule_t *rl)
684 {
685 prop_dictionary_t rldict = rl->nrl_dict;
686 const char *ifname = NULL;
687
688 prop_dictionary_get_cstring_nocopy(rldict, "interface", &ifname);
689 return ifname;
690 }
691
692 const void *
693 npf_rule_getinfo(nl_rule_t *rl, size_t *len)
694 {
695 prop_dictionary_t rldict = rl->nrl_dict;
696 prop_object_t obj = prop_dictionary_get(rldict, "info");
697
698 *len = prop_data_size(obj);
699 return prop_data_data_nocopy(obj);
700 }
701
702 const char *
703 npf_rule_getproc(nl_rule_t *rl)
704 {
705 prop_dictionary_t rldict = rl->nrl_dict;
706 const char *rpname = NULL;
707
708 prop_dictionary_get_cstring_nocopy(rldict, "rproc", &rpname);
709 return rpname;
710 }
711
712 int
713 _npf_ruleset_list(int fd, const char *rname, nl_config_t *ncf)
714 {
715 prop_dictionary_t rldict, ret;
716 int error;
717
718 rldict = prop_dictionary_create();
719 if (rldict == NULL) {
720 return ENOMEM;
721 }
722 prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
723 prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_LIST);
724 error = prop_dictionary_sendrecv_ioctl(rldict, fd, IOC_NPF_RULE, &ret);
725 if (!error) {
726 prop_array_t rules;
727
728 rules = prop_dictionary_get(ret, "rules");
729 if (rules == NULL) {
730 return EINVAL;
731 }
732 prop_object_release(ncf->ncf_rules_list);
733 ncf->ncf_rules_list = rules;
734 }
735 return error;
736 }
737
738 void
739 npf_rule_destroy(nl_rule_t *rl)
740 {
741
742 prop_object_release(rl->nrl_dict);
743 free(rl);
744 }
745
746 /*
747 * RULE PROCEDURE INTERFACE.
748 */
749
750 nl_rproc_t *
751 npf_rproc_create(const char *name)
752 {
753 prop_dictionary_t rpdict;
754 prop_array_t extcalls;
755 nl_rproc_t *nrp;
756
757 nrp = malloc(sizeof(nl_rproc_t));
758 if (nrp == NULL) {
759 return NULL;
760 }
761 rpdict = prop_dictionary_create();
762 if (rpdict == NULL) {
763 free(nrp);
764 return NULL;
765 }
766 prop_dictionary_set_cstring(rpdict, "name", name);
767
768 extcalls = prop_array_create();
769 if (extcalls == NULL) {
770 prop_object_release(rpdict);
771 free(nrp);
772 return NULL;
773 }
774 prop_dictionary_set(rpdict, "extcalls", extcalls);
775 prop_object_release(extcalls);
776
777 nrp->nrp_dict = rpdict;
778 return nrp;
779 }
780
781 int
782 npf_rproc_extcall(nl_rproc_t *rp, nl_ext_t *ext)
783 {
784 prop_dictionary_t rpdict = rp->nrp_dict;
785 prop_dictionary_t extdict = ext->nxt_dict;
786 prop_array_t extcalls;
787
788 extcalls = prop_dictionary_get(rpdict, "extcalls");
789 if (_npf_prop_array_lookup(extcalls, "name", ext->nxt_name)) {
790 return EEXIST;
791 }
792 prop_dictionary_set_cstring(extdict, "name", ext->nxt_name);
793 prop_array_add(extcalls, extdict);
794 return 0;
795 }
796
797 bool
798 npf_rproc_exists_p(nl_config_t *ncf, const char *name)
799 {
800 return _npf_prop_array_lookup(ncf->ncf_rproc_list, "name", name);
801 }
802
803 int
804 npf_rproc_insert(nl_config_t *ncf, nl_rproc_t *rp)
805 {
806 prop_dictionary_t rpdict = rp->nrp_dict;
807 const char *name;
808
809 if (!prop_dictionary_get_cstring_nocopy(rpdict, "name", &name)) {
810 return EINVAL;
811 }
812 if (npf_rproc_exists_p(ncf, name)) {
813 return EEXIST;
814 }
815 prop_array_add(ncf->ncf_rproc_list, rpdict);
816 return 0;
817 }
818
819 nl_rproc_t *
820 npf_rproc_iterate(nl_config_t *ncf)
821 {
822 prop_dictionary_t rpdict;
823
824 if (!ncf->ncf_rproc_iter) {
825 /* Initialise the iterator. */
826 ncf->ncf_rproc_iter = prop_array_iterator(ncf->ncf_rproc_list);
827 }
828 rpdict = prop_object_iterator_next(ncf->ncf_rproc_iter);
829 if ((ncf->ncf_cur_rproc.nrp_dict = rpdict) == NULL) {
830 prop_object_iterator_release(ncf->ncf_rproc_iter);
831 ncf->ncf_rproc_iter = NULL;
832 return NULL;
833 }
834 return &ncf->ncf_cur_rproc;
835 }
836
837 const char *
838 npf_rproc_getname(nl_rproc_t *rp)
839 {
840 prop_dictionary_t rpdict = rp->nrp_dict;
841 const char *rpname = NULL;
842
843 prop_dictionary_get_cstring_nocopy(rpdict, "name", &rpname);
844 return rpname;
845 }
846
847 /*
848 * TRANSLATION INTERFACE.
849 */
850
851 nl_nat_t *
852 npf_nat_create(int type, u_int flags, const char *ifname,
853 int af, npf_addr_t *addr, npf_netmask_t mask, in_port_t port)
854 {
855 nl_rule_t *rl;
856 prop_dictionary_t rldict;
857 prop_data_t addrdat;
858 uint32_t attr;
859 size_t sz;
860
861 if (af == AF_INET) {
862 sz = sizeof(struct in_addr);
863 } else if (af == AF_INET6) {
864 sz = sizeof(struct in6_addr);
865 } else {
866 return NULL;
867 }
868
869 attr = NPF_RULE_PASS | NPF_RULE_FINAL |
870 (type == NPF_NATOUT ? NPF_RULE_OUT : NPF_RULE_IN);
871
872 /* Create a rule for NAT policy. Next, will add translation data. */
873 rl = npf_rule_create(NULL, attr, ifname);
874 if (rl == NULL) {
875 return NULL;
876 }
877 rldict = rl->nrl_dict;
878
879 /* Translation type and flags. */
880 prop_dictionary_set_int32(rldict, "type", type);
881 prop_dictionary_set_uint32(rldict, "flags", flags);
882
883 /* Translation IP and mask. */
884 addrdat = prop_data_create_data(addr, sz);
885 if (addrdat == NULL) {
886 npf_rule_destroy(rl);
887 return NULL;
888 }
889 prop_dictionary_set(rldict, "translation-ip", addrdat);
890 prop_dictionary_set_uint32(rldict, "translation-mask", mask);
891 prop_object_release(addrdat);
892
893 /* Translation port (for redirect case). */
894 prop_dictionary_set_uint16(rldict, "translation-port", port);
895
896 return (nl_nat_t *)rl;
897 }
898
899 int
900 npf_nat_insert(nl_config_t *ncf, nl_nat_t *nt, pri_t pri __unused)
901 {
902 prop_dictionary_t rldict = nt->nrl_dict;
903
904 prop_dictionary_set_int32(rldict, "priority", NPF_PRI_LAST);
905 prop_array_add(ncf->ncf_nat_list, rldict);
906 return 0;
907 }
908
909 nl_nat_t *
910 npf_nat_iterate(nl_config_t *ncf)
911 {
912 u_int level;
913 return _npf_rule_iterate1(ncf, ncf->ncf_nat_list, &level);
914 }
915
916 int
917 npf_nat_setalgo(nl_nat_t *nt, u_int algo)
918 {
919 prop_dictionary_t rldict = nt->nrl_dict;
920 prop_dictionary_set_uint32(rldict, "translation-algo", algo);
921 return 0;
922 }
923
924 int
925 npf_nat_setnpt66(nl_nat_t *nt, uint16_t adj)
926 {
927 prop_dictionary_t rldict = nt->nrl_dict;
928 int error;
929
930 if ((error = npf_nat_setalgo(nt, NPF_ALGO_NPT66)) != 0) {
931 return error;
932 }
933 prop_dictionary_set_uint16(rldict, "npt66-adjustment", adj);
934 return 0;
935 }
936
937 int
938 npf_nat_gettype(nl_nat_t *nt)
939 {
940 prop_dictionary_t rldict = nt->nrl_dict;
941 int type = 0;
942
943 prop_dictionary_get_int32(rldict, "type", &type);
944 return type;
945 }
946
947 u_int
948 npf_nat_getflags(nl_nat_t *nt)
949 {
950 prop_dictionary_t rldict = nt->nrl_dict;
951 unsigned flags = 0;
952
953 prop_dictionary_get_uint32(rldict, "flags", &flags);
954 return flags;
955 }
956
957 void
958 npf_nat_getmap(nl_nat_t *nt, npf_addr_t *addr, size_t *alen, in_port_t *port)
959 {
960 prop_dictionary_t rldict = nt->nrl_dict;
961 prop_object_t obj = prop_dictionary_get(rldict, "translation-ip");
962
963 *alen = prop_data_size(obj);
964 memcpy(addr, prop_data_data_nocopy(obj), *alen);
965
966 *port = 0;
967 prop_dictionary_get_uint16(rldict, "translation-port", port);
968 }
969
970 /*
971 * TABLE INTERFACE.
972 */
973
974 nl_table_t *
975 npf_table_create(const char *name, u_int id, int type)
976 {
977 prop_dictionary_t tldict;
978 prop_array_t tblents;
979 nl_table_t *tl;
980
981 tl = malloc(sizeof(*tl));
982 if (tl == NULL) {
983 return NULL;
984 }
985 tldict = prop_dictionary_create();
986 if (tldict == NULL) {
987 free(tl);
988 return NULL;
989 }
990 prop_dictionary_set_cstring(tldict, "name", name);
991 prop_dictionary_set_uint32(tldict, "id", id);
992 prop_dictionary_set_int32(tldict, "type", type);
993
994 tblents = prop_array_create();
995 if (tblents == NULL) {
996 prop_object_release(tldict);
997 free(tl);
998 return NULL;
999 }
1000 prop_dictionary_set(tldict, "entries", tblents);
1001 prop_object_release(tblents);
1002
1003 tl->ntl_dict = tldict;
1004 return tl;
1005 }
1006
1007 int
1008 npf_table_add_entry(nl_table_t *tl, int af, const npf_addr_t *addr,
1009 const npf_netmask_t mask)
1010 {
1011 prop_dictionary_t tldict = tl->ntl_dict, entdict;
1012 prop_array_t tblents;
1013 prop_data_t addrdata;
1014 unsigned alen;
1015
1016 /* Create the table entry. */
1017 entdict = prop_dictionary_create();
1018 if (entdict == NULL) {
1019 return ENOMEM;
1020 }
1021
1022 switch (af) {
1023 case AF_INET:
1024 alen = sizeof(struct in_addr);
1025 break;
1026 case AF_INET6:
1027 alen = sizeof(struct in6_addr);
1028 break;
1029 default:
1030 return EINVAL;
1031 }
1032
1033 addrdata = prop_data_create_data(addr, alen);
1034 prop_dictionary_set(entdict, "addr", addrdata);
1035 prop_dictionary_set_uint8(entdict, "mask", mask);
1036 prop_object_release(addrdata);
1037
1038 tblents = prop_dictionary_get(tldict, "entries");
1039 prop_array_add(tblents, entdict);
1040 prop_object_release(entdict);
1041 return 0;
1042 }
1043
1044 int
1045 npf_table_setdata(nl_table_t *tl, const void *blob, size_t len)
1046 {
1047 prop_dictionary_t tldict = tl->ntl_dict;
1048 prop_data_t bobj;
1049
1050 if ((bobj = prop_data_create_data(blob, len)) == NULL) {
1051 return ENOMEM;
1052 }
1053 prop_dictionary_set(tldict, "data", bobj);
1054 prop_object_release(bobj);
1055 return 0;
1056 }
1057
1058 static bool
1059 _npf_table_exists_p(nl_config_t *ncf, const char *name)
1060 {
1061 prop_dictionary_t tldict;
1062 prop_object_iterator_t it;
1063
1064 it = prop_array_iterator(ncf->ncf_table_list);
1065 while ((tldict = prop_object_iterator_next(it)) != NULL) {
1066 const char *tname = NULL;
1067
1068 if (prop_dictionary_get_cstring_nocopy(tldict, "name", &tname)
1069 && strcmp(tname, name) == 0)
1070 break;
1071 }
1072 prop_object_iterator_release(it);
1073 return tldict ? true : false;
1074 }
1075
1076 int
1077 npf_table_insert(nl_config_t *ncf, nl_table_t *tl)
1078 {
1079 prop_dictionary_t tldict = tl->ntl_dict;
1080 const char *name = NULL;
1081
1082 if (!prop_dictionary_get_cstring_nocopy(tldict, "name", &name)) {
1083 return EINVAL;
1084 }
1085 if (_npf_table_exists_p(ncf, name)) {
1086 return EEXIST;
1087 }
1088 prop_array_add(ncf->ncf_table_list, tldict);
1089 return 0;
1090 }
1091
1092 nl_table_t *
1093 npf_table_iterate(nl_config_t *ncf)
1094 {
1095 prop_dictionary_t tldict;
1096
1097 if (!ncf->ncf_table_iter) {
1098 /* Initialise the iterator. */
1099 ncf->ncf_table_iter = prop_array_iterator(ncf->ncf_table_list);
1100 }
1101 tldict = prop_object_iterator_next(ncf->ncf_table_iter);
1102 if ((ncf->ncf_cur_table.ntl_dict = tldict) == NULL) {
1103 prop_object_iterator_release(ncf->ncf_table_iter);
1104 ncf->ncf_table_iter = NULL;
1105 return NULL;
1106 }
1107 return &ncf->ncf_cur_table;
1108 }
1109
1110 unsigned
1111 npf_table_getid(nl_table_t *tl)
1112 {
1113 prop_dictionary_t tldict = tl->ntl_dict;
1114 unsigned id = (unsigned)-1;
1115
1116 prop_dictionary_get_uint32(tldict, "id", &id);
1117 return id;
1118 }
1119
1120 const char *
1121 npf_table_getname(nl_table_t *tl)
1122 {
1123 prop_dictionary_t tldict = tl->ntl_dict;
1124 const char *tname = NULL;
1125
1126 prop_dictionary_get_cstring_nocopy(tldict, "name", &tname);
1127 return tname;
1128 }
1129
1130 int
1131 npf_table_gettype(nl_table_t *tl)
1132 {
1133 prop_dictionary_t tldict = tl->ntl_dict;
1134 int type = 0;
1135
1136 prop_dictionary_get_int32(tldict, "type", &type);
1137 return type;
1138 }
1139
1140 void
1141 npf_table_destroy(nl_table_t *tl)
1142 {
1143 prop_object_release(tl->ntl_dict);
1144 free(tl);
1145 }
1146
1147 /*
1148 * ALG INTERFACE.
1149 */
1150
1151 int
1152 _npf_alg_load(nl_config_t *ncf, const char *name)
1153 {
1154 prop_dictionary_t al_dict;
1155
1156 if (_npf_prop_array_lookup(ncf->ncf_alg_list, "name", name))
1157 return EEXIST;
1158
1159 al_dict = prop_dictionary_create();
1160 prop_dictionary_set_cstring(al_dict, "name", name);
1161 prop_array_add(ncf->ncf_alg_list, al_dict);
1162 prop_object_release(al_dict);
1163 return 0;
1164 }
1165
1166 int
1167 _npf_alg_unload(nl_config_t *ncf, const char *name)
1168 {
1169 if (!_npf_prop_array_lookup(ncf->ncf_alg_list, "name", name))
1170 return ENOENT;
1171
1172 // Not yet: prop_array_add(ncf->ncf_alg_list, al_dict);
1173 return ENOTSUP;
1174 }
1175
1176 /*
1177 * MISC.
1178 */
1179
1180 static prop_dictionary_t
1181 _npf_debug_initonce(nl_config_t *ncf)
1182 {
1183 if (!ncf->ncf_debug) {
1184 prop_array_t iflist = prop_array_create();
1185 ncf->ncf_debug = prop_dictionary_create();
1186 prop_dictionary_set(ncf->ncf_debug, "interfaces", iflist);
1187 prop_object_release(iflist);
1188 }
1189 return ncf->ncf_debug;
1190 }
1191
1192 void
1193 _npf_debug_addif(nl_config_t *ncf, const char *ifname)
1194 {
1195 prop_dictionary_t ifdict, dbg = _npf_debug_initonce(ncf);
1196 prop_array_t iflist = prop_dictionary_get(dbg, "interfaces");
1197 u_int if_idx = if_nametoindex(ifname);
1198
1199 if (_npf_prop_array_lookup(iflist, "name", ifname)) {
1200 return;
1201 }
1202 ifdict = prop_dictionary_create();
1203 prop_dictionary_set_cstring(ifdict, "name", ifname);
1204 prop_dictionary_set_uint32(ifdict, "index", if_idx);
1205 prop_array_add(iflist, ifdict);
1206 prop_object_release(ifdict);
1207 }
1208