npf.c revision 1.20 1 /* $NetBSD: npf.c,v 1.20 2013/09/19 01:04:46 rmind Exp $ */
2
3 /*-
4 * Copyright (c) 2010-2013 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.20 2013/09/19 01:04:46 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_RELOAD, &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 nl_config_t *
183 npf_config_retrieve(int fd, bool *active, bool *loaded)
184 {
185 prop_dictionary_t npf_dict;
186 nl_config_t *ncf;
187 int error;
188
189 error = prop_dictionary_recv_ioctl(fd, IOC_NPF_GETCONF, &npf_dict);
190 if (error) {
191 return NULL;
192 }
193 ncf = calloc(1, sizeof(*ncf));
194 if (ncf == NULL) {
195 prop_object_release(npf_dict);
196 return NULL;
197 }
198 ncf->ncf_dict = npf_dict;
199 ncf->ncf_alg_list = prop_dictionary_get(npf_dict, "algs");
200 ncf->ncf_rules_list = prop_dictionary_get(npf_dict, "rules");
201 ncf->ncf_rproc_list = prop_dictionary_get(npf_dict, "rprocs");
202 ncf->ncf_table_list = prop_dictionary_get(npf_dict, "tables");
203 ncf->ncf_nat_list = prop_dictionary_get(npf_dict, "translation");
204
205 prop_dictionary_get_bool(npf_dict, "active", active);
206 *loaded = (ncf->ncf_rules_list != NULL);
207 return ncf;
208 }
209
210 int
211 npf_config_flush(int fd)
212 {
213 nl_config_t *ncf;
214 int error;
215
216 ncf = npf_config_create();
217 if (ncf == NULL) {
218 return ENOMEM;
219 }
220 ncf->ncf_flush = true;
221 error = npf_config_submit(ncf, fd);
222 npf_config_destroy(ncf);
223 return error;
224 }
225
226 void
227 _npf_config_error(nl_config_t *ncf, nl_error_t *ne)
228 {
229 memset(ne, 0, sizeof(*ne));
230 prop_dictionary_get_int32(ncf->ncf_err, "id", &ne->ne_id);
231 prop_dictionary_get_cstring(ncf->ncf_err,
232 "source-file", &ne->ne_source_file);
233 prop_dictionary_get_uint32(ncf->ncf_err,
234 "source-line", &ne->ne_source_line);
235 prop_dictionary_get_int32(ncf->ncf_err,
236 "code-error", &ne->ne_ncode_error);
237 prop_dictionary_get_int32(ncf->ncf_err,
238 "code-errat", &ne->ne_ncode_errat);
239 }
240
241 void
242 npf_config_destroy(nl_config_t *ncf)
243 {
244 if (!ncf->ncf_dict) {
245 prop_object_release(ncf->ncf_alg_list);
246 prop_object_release(ncf->ncf_rules_list);
247 prop_object_release(ncf->ncf_rproc_list);
248 prop_object_release(ncf->ncf_table_list);
249 prop_object_release(ncf->ncf_nat_list);
250 }
251 if (ncf->ncf_err) {
252 prop_object_release(ncf->ncf_err);
253 }
254 if (ncf->ncf_debug) {
255 prop_object_release(ncf->ncf_debug);
256 }
257 free(ncf);
258 }
259
260 void
261 _npf_config_setsubmit(nl_config_t *ncf, const char *plist_file)
262 {
263 ncf->ncf_plist = plist_file;
264 }
265
266 static bool
267 _npf_prop_array_lookup(prop_array_t array, const char *key, const char *name)
268 {
269 prop_dictionary_t dict;
270 prop_object_iterator_t it;
271
272 it = prop_array_iterator(array);
273 while ((dict = prop_object_iterator_next(it)) != NULL) {
274 const char *lname;
275 prop_dictionary_get_cstring_nocopy(dict, key, &lname);
276 if (strcmp(name, lname) == 0)
277 break;
278 }
279 prop_object_iterator_release(it);
280 return dict ? true : false;
281 }
282
283 /*
284 * DYNAMIC RULESET INTERFACE.
285 */
286
287 int
288 npf_ruleset_add(int fd, const char *rname, nl_rule_t *rl, uint64_t *id)
289 {
290 prop_dictionary_t rldict = rl->nrl_dict;
291 prop_dictionary_t ret;
292 int error;
293
294 prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
295 prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_ADD);
296 error = prop_dictionary_sendrecv_ioctl(rldict, fd, IOC_NPF_RULE, &ret);
297 if (!error) {
298 prop_dictionary_get_uint64(ret, "id", id);
299 }
300 return error;
301 }
302
303 int
304 npf_ruleset_remove(int fd, const char *rname, uint64_t id)
305 {
306 prop_dictionary_t rldict;
307
308 rldict = prop_dictionary_create();
309 if (rldict == NULL) {
310 return ENOMEM;
311 }
312 prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
313 prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_REMOVE);
314 prop_dictionary_set_uint64(rldict, "id", id);
315 return prop_dictionary_send_ioctl(rldict, fd, IOC_NPF_RULE);
316 }
317
318 int
319 npf_ruleset_remkey(int fd, const char *rname, const void *key, size_t len)
320 {
321 prop_dictionary_t rldict;
322 prop_data_t keyobj;
323
324 rldict = prop_dictionary_create();
325 if (rldict == NULL) {
326 return ENOMEM;
327 }
328 prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
329 prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_REMKEY);
330
331 keyobj = prop_data_create_data(key, len);
332 if (keyobj == NULL) {
333 prop_object_release(rldict);
334 return ENOMEM;
335 }
336 prop_dictionary_set(rldict, "key", keyobj);
337 prop_object_release(keyobj);
338
339 return prop_dictionary_send_ioctl(rldict, fd, IOC_NPF_RULE);
340 }
341
342 int
343 npf_ruleset_flush(int fd, const char *rname)
344 {
345 prop_dictionary_t rldict;
346
347 rldict = prop_dictionary_create();
348 if (rldict == NULL) {
349 return ENOMEM;
350 }
351 prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
352 prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_FLUSH);
353 return prop_dictionary_send_ioctl(rldict, fd, IOC_NPF_RULE);
354 }
355
356 /*
357 * _npf_ruleset_transform: transform the ruleset representing nested
358 * rules with lists into an array.
359 */
360
361 static void
362 _npf_ruleset_transform1(prop_array_t rlset, prop_array_t rules)
363 {
364 prop_object_iterator_t it;
365 prop_dictionary_t rldict;
366 prop_array_t subrlset;
367
368 it = prop_array_iterator(rules);
369 while ((rldict = prop_object_iterator_next(it)) != NULL) {
370 unsigned idx;
371
372 /* Add rules to the array (reference is retained). */
373 prop_array_add(rlset, rldict);
374
375 subrlset = prop_dictionary_get(rldict, "subrules");
376 if (subrlset) {
377 /* Process subrules recursively. */
378 _npf_ruleset_transform1(rlset, subrlset);
379 /* Add the skip-to position. */
380 idx = prop_array_count(rlset);
381 prop_dictionary_set_uint32(rldict, "skip-to", idx);
382 prop_dictionary_remove(rldict, "subrules");
383 }
384 }
385 prop_object_iterator_release(it);
386 }
387
388 static prop_array_t
389 _npf_ruleset_transform(prop_array_t rlset)
390 {
391 prop_array_t nrlset;
392
393 nrlset = prop_array_create();
394 _npf_ruleset_transform1(nrlset, rlset);
395 return nrlset;
396 }
397
398 /*
399 * NPF EXTENSION INTERFACE.
400 */
401
402 nl_ext_t *
403 npf_ext_construct(const char *name)
404 {
405 nl_ext_t *ext;
406
407 ext = malloc(sizeof(*ext));
408 if (ext == NULL) {
409 return NULL;
410 }
411 ext->nxt_name = strdup(name);
412 if (ext->nxt_name == NULL) {
413 free(ext);
414 return NULL;
415 }
416 ext->nxt_dict = prop_dictionary_create();
417
418 return ext;
419 }
420
421 void
422 npf_ext_param_u32(nl_ext_t *ext, const char *key, uint32_t val)
423 {
424 prop_dictionary_t extdict = ext->nxt_dict;
425 prop_dictionary_set_uint32(extdict, key, val);
426 }
427
428 void
429 npf_ext_param_bool(nl_ext_t *ext, const char *key, bool val)
430 {
431 prop_dictionary_t extdict = ext->nxt_dict;
432 prop_dictionary_set_bool(extdict, key, val);
433 }
434
435 /*
436 * RULE INTERFACE.
437 */
438
439 nl_rule_t *
440 npf_rule_create(const char *name, uint32_t attr, u_int if_idx)
441 {
442 prop_dictionary_t rldict;
443 nl_rule_t *rl;
444
445 rl = malloc(sizeof(*rl));
446 if (rl == NULL) {
447 return NULL;
448 }
449 rldict = prop_dictionary_create();
450 if (rldict == NULL) {
451 free(rl);
452 return NULL;
453 }
454 if (name) {
455 prop_dictionary_set_cstring(rldict, "name", name);
456 }
457 prop_dictionary_set_uint32(rldict, "attributes", attr);
458
459 if (if_idx) {
460 prop_dictionary_set_uint32(rldict, "interface", if_idx);
461 }
462 rl->nrl_dict = rldict;
463 return rl;
464 }
465
466 int
467 npf_rule_setcode(nl_rule_t *rl, int type, const void *code, size_t len)
468 {
469 prop_dictionary_t rldict = rl->nrl_dict;
470 prop_data_t cdata;
471
472 switch (type) {
473 case NPF_CODE_NC:
474 case NPF_CODE_BPF:
475 break;
476 default:
477 return ENOTSUP;
478 }
479 prop_dictionary_set_uint32(rldict, "code-type", type);
480 if ((cdata = prop_data_create_data(code, len)) == NULL) {
481 return ENOMEM;
482 }
483 prop_dictionary_set(rldict, "code", cdata);
484 prop_object_release(cdata);
485 return 0;
486 }
487
488 int
489 npf_rule_setkey(nl_rule_t *rl, const void *key, size_t len)
490 {
491 prop_dictionary_t rldict = rl->nrl_dict;
492 prop_data_t kdata;
493
494 if ((kdata = prop_data_create_data(key, len)) == NULL) {
495 return ENOMEM;
496 }
497 prop_dictionary_set(rldict, "key", kdata);
498 prop_object_release(kdata);
499 return 0;
500 }
501
502 int
503 npf_rule_setinfo(nl_rule_t *rl, const void *info, size_t len)
504 {
505 prop_dictionary_t rldict = rl->nrl_dict;
506 prop_data_t idata;
507
508 if ((idata = prop_data_create_data(info, len)) == NULL) {
509 return ENOMEM;
510 }
511 prop_dictionary_set(rldict, "info", idata);
512 prop_object_release(idata);
513 return 0;
514 }
515
516 int
517 npf_rule_setprio(nl_rule_t *rl, pri_t pri)
518 {
519 prop_dictionary_t rldict = rl->nrl_dict;
520
521 prop_dictionary_set_int32(rldict, "priority", pri);
522 return 0;
523 }
524
525 int
526 npf_rule_setproc(nl_rule_t *rl, const char *name)
527 {
528 prop_dictionary_t rldict = rl->nrl_dict;
529
530 prop_dictionary_set_cstring(rldict, "rproc", name);
531 return 0;
532 }
533
534 void *
535 npf_rule_export(nl_rule_t *rl, size_t *length)
536 {
537 prop_dictionary_t rldict = rl->nrl_dict;
538 void *xml;
539
540 if ((xml = prop_dictionary_externalize(rldict)) == NULL) {
541 return NULL;
542 }
543 *length = strlen(xml);
544 return xml;
545 }
546
547 bool
548 npf_rule_exists_p(nl_config_t *ncf, const char *name)
549 {
550 return _npf_prop_array_lookup(ncf->ncf_rules_list, "name", name);
551 }
552
553 int
554 npf_rule_insert(nl_config_t *ncf, nl_rule_t *parent, nl_rule_t *rl)
555 {
556 prop_dictionary_t rldict = rl->nrl_dict;
557 prop_array_t rlset;
558
559 if (parent) {
560 prop_dictionary_t pdict = parent->nrl_dict;
561 rlset = prop_dictionary_get(pdict, "subrules");
562 if (rlset == NULL) {
563 rlset = prop_array_create();
564 prop_dictionary_set(pdict, "subrules", rlset);
565 prop_object_release(rlset);
566 }
567 } else {
568 rlset = ncf->ncf_rules_list;
569 }
570 prop_array_add(rlset, rldict);
571 return 0;
572 }
573
574 static nl_rule_t *
575 _npf_rule_iterate1(nl_config_t *ncf, prop_array_t rlist, unsigned *level)
576 {
577 prop_dictionary_t rldict;
578 uint32_t skipto = 0;
579
580 if (!ncf->ncf_rule_iter) {
581 /* Initialise the iterator. */
582 ncf->ncf_rule_iter = prop_array_iterator(rlist);
583 ncf->ncf_nlevel = 0;
584 ncf->ncf_reduce[0] = 0;
585 ncf->ncf_counter = 0;
586 }
587
588 rldict = prop_object_iterator_next(ncf->ncf_rule_iter);
589 if ((ncf->ncf_cur_rule.nrl_dict = rldict) == NULL) {
590 prop_object_iterator_release(ncf->ncf_rule_iter);
591 ncf->ncf_rule_iter = NULL;
592 return NULL;
593 }
594 *level = ncf->ncf_nlevel;
595
596 prop_dictionary_get_uint32(rldict, "skip-to", &skipto);
597 if (skipto) {
598 ncf->ncf_nlevel++;
599 ncf->ncf_reduce[ncf->ncf_nlevel] = skipto;
600 }
601 if (ncf->ncf_reduce[ncf->ncf_nlevel] == ++ncf->ncf_counter) {
602 assert(ncf->ncf_nlevel > 0);
603 ncf->ncf_nlevel--;
604 }
605 return &ncf->ncf_cur_rule;
606 }
607
608 nl_rule_t *
609 npf_rule_iterate(nl_config_t *ncf, unsigned *level)
610 {
611 return _npf_rule_iterate1(ncf, ncf->ncf_rules_list, level);
612 }
613
614 const char *
615 npf_rule_getname(nl_rule_t *rl)
616 {
617 prop_dictionary_t rldict = rl->nrl_dict;
618 const char *rname = NULL;
619
620 prop_dictionary_get_cstring_nocopy(rldict, "name", &rname);
621 return rname;
622 }
623
624 uint32_t
625 npf_rule_getattr(nl_rule_t *rl)
626 {
627 prop_dictionary_t rldict = rl->nrl_dict;
628 uint32_t attr = 0;
629
630 prop_dictionary_get_uint32(rldict, "attributes", &attr);
631 return attr;
632 }
633
634 unsigned
635 npf_rule_getinterface(nl_rule_t *rl)
636 {
637 prop_dictionary_t rldict = rl->nrl_dict;
638 unsigned if_idx = 0;
639
640 prop_dictionary_get_uint32(rldict, "interface", &if_idx);
641 return if_idx;
642 }
643
644 const void *
645 npf_rule_getinfo(nl_rule_t *rl, size_t *len)
646 {
647 prop_dictionary_t rldict = rl->nrl_dict;
648 prop_object_t obj = prop_dictionary_get(rldict, "info");
649
650 *len = prop_data_size(obj);
651 return prop_data_data_nocopy(obj);
652 }
653
654 const char *
655 npf_rule_getproc(nl_rule_t *rl)
656 {
657 prop_dictionary_t rldict = rl->nrl_dict;
658 const char *rpname = NULL;
659
660 prop_dictionary_get_cstring_nocopy(rldict, "rproc", &rpname);
661 return rpname;
662 }
663
664 #if 1
665 static int
666 _npf_rule_foreach1(prop_array_t rules, nl_rule_callback_t func)
667 {
668 prop_dictionary_t rldict;
669 prop_object_iterator_t it;
670 unsigned reduce[16], n;
671 unsigned nlevel;
672
673 if (!rules || prop_object_type(rules) != PROP_TYPE_ARRAY) {
674 return ENOENT;
675 }
676 it = prop_array_iterator(rules);
677 if (it == NULL) {
678 return ENOMEM;
679 }
680
681 nlevel = 0;
682 reduce[nlevel] = 0;
683 n = 0;
684
685 while ((rldict = prop_object_iterator_next(it)) != NULL) {
686 nl_rule_t nrl = { .nrl_dict = rldict };
687 uint32_t skipto = 0;
688
689 prop_dictionary_get_uint32(rldict, "skip-to", &skipto);
690 (*func)(&nrl, nlevel);
691 if (skipto) {
692 nlevel++;
693 reduce[nlevel] = skipto;
694 }
695 if (reduce[nlevel] == ++n) {
696 assert(nlevel > 0);
697 nlevel--;
698 }
699 }
700 prop_object_iterator_release(it);
701 return 0;
702 }
703
704 int
705 _npf_rule_foreach(nl_config_t *ncf, nl_rule_callback_t func)
706 {
707 return _npf_rule_foreach1(ncf->ncf_rules_list, func);
708 }
709 #endif
710
711 int
712 _npf_ruleset_list(int fd, const char *rname, nl_config_t *ncf)
713 {
714 prop_dictionary_t rldict, ret;
715 int error;
716
717 rldict = prop_dictionary_create();
718 if (rldict == NULL) {
719 return ENOMEM;
720 }
721 prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
722 prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_LIST);
723 error = prop_dictionary_sendrecv_ioctl(rldict, fd, IOC_NPF_RULE, &ret);
724 if (!error) {
725 prop_array_t rules;
726
727 rules = prop_dictionary_get(ret, "rules");
728 if (rules == NULL) {
729 return EINVAL;
730 }
731 prop_object_release(ncf->ncf_rules_list);
732 ncf->ncf_rules_list = rules;
733 }
734 return error;
735 }
736
737 #if 1
738 pri_t
739 _npf_rule_getinfo(nl_rule_t *nrl, const char **rname, uint32_t *attr,
740 u_int *if_idx)
741 {
742 prop_dictionary_t rldict = nrl->nrl_dict;
743 pri_t prio;
744
745 prop_dictionary_get_cstring_nocopy(rldict, "name", rname);
746 prop_dictionary_get_uint32(rldict, "attributes", attr);
747 prop_dictionary_get_int32(rldict, "priority", &prio);
748 prop_dictionary_get_uint32(rldict, "interface", if_idx);
749 return prio;
750 }
751
752 const void *
753 _npf_rule_ncode(nl_rule_t *nrl, size_t *size)
754 {
755 prop_dictionary_t rldict = nrl->nrl_dict;
756 prop_object_t obj = prop_dictionary_get(rldict, "code");
757 *size = prop_data_size(obj);
758 return prop_data_data_nocopy(obj);
759 }
760 #endif
761
762 void
763 npf_rule_destroy(nl_rule_t *rl)
764 {
765
766 prop_object_release(rl->nrl_dict);
767 free(rl);
768 }
769
770 /*
771 * RULE PROCEDURE INTERFACE.
772 */
773
774 nl_rproc_t *
775 npf_rproc_create(const char *name)
776 {
777 prop_dictionary_t rpdict;
778 prop_array_t extcalls;
779 nl_rproc_t *nrp;
780
781 nrp = malloc(sizeof(nl_rproc_t));
782 if (nrp == NULL) {
783 return NULL;
784 }
785 rpdict = prop_dictionary_create();
786 if (rpdict == NULL) {
787 free(nrp);
788 return NULL;
789 }
790 prop_dictionary_set_cstring(rpdict, "name", name);
791
792 extcalls = prop_array_create();
793 if (extcalls == NULL) {
794 prop_object_release(rpdict);
795 free(nrp);
796 return NULL;
797 }
798 prop_dictionary_set(rpdict, "extcalls", extcalls);
799 prop_object_release(extcalls);
800
801 nrp->nrp_dict = rpdict;
802 return nrp;
803 }
804
805 int
806 npf_rproc_extcall(nl_rproc_t *rp, nl_ext_t *ext)
807 {
808 prop_dictionary_t rpdict = rp->nrp_dict;
809 prop_dictionary_t extdict = ext->nxt_dict;
810 prop_array_t extcalls;
811
812 extcalls = prop_dictionary_get(rpdict, "extcalls");
813 if (_npf_prop_array_lookup(extcalls, "name", ext->nxt_name)) {
814 return EEXIST;
815 }
816 prop_dictionary_set_cstring(extdict, "name", ext->nxt_name);
817 prop_array_add(extcalls, extdict);
818 return 0;
819 }
820
821 bool
822 npf_rproc_exists_p(nl_config_t *ncf, const char *name)
823 {
824 return _npf_prop_array_lookup(ncf->ncf_rproc_list, "name", name);
825 }
826
827 int
828 npf_rproc_insert(nl_config_t *ncf, nl_rproc_t *rp)
829 {
830 prop_dictionary_t rpdict = rp->nrp_dict;
831 const char *name;
832
833 if (!prop_dictionary_get_cstring_nocopy(rpdict, "name", &name)) {
834 return EINVAL;
835 }
836 if (npf_rproc_exists_p(ncf, name)) {
837 return EEXIST;
838 }
839 prop_array_add(ncf->ncf_rproc_list, rpdict);
840 return 0;
841 }
842
843 nl_rproc_t *
844 npf_rproc_iterate(nl_config_t *ncf)
845 {
846 prop_dictionary_t rpdict;
847
848 if (!ncf->ncf_rproc_iter) {
849 /* Initialise the iterator. */
850 ncf->ncf_rproc_iter = prop_array_iterator(ncf->ncf_rproc_list);
851 }
852 rpdict = prop_object_iterator_next(ncf->ncf_rproc_iter);
853 if ((ncf->ncf_cur_rproc.nrp_dict = rpdict) == NULL) {
854 prop_object_iterator_release(ncf->ncf_rproc_iter);
855 ncf->ncf_rproc_iter = NULL;
856 return NULL;
857 }
858 return &ncf->ncf_cur_rproc;
859 }
860
861 const char *
862 npf_rproc_getname(nl_rproc_t *rp)
863 {
864 prop_dictionary_t rpdict = rp->nrp_dict;
865 const char *rpname = NULL;
866
867 prop_dictionary_get_cstring_nocopy(rpdict, "name", &rpname);
868 return rpname;
869 }
870
871 /*
872 * TRANSLATION INTERFACE.
873 */
874
875 nl_nat_t *
876 npf_nat_create(int type, u_int flags, u_int if_idx,
877 npf_addr_t *addr, int af, in_port_t port)
878 {
879 nl_rule_t *rl;
880 prop_dictionary_t rldict;
881 prop_data_t addrdat;
882 uint32_t attr;
883 size_t sz;
884
885 if (af == AF_INET) {
886 sz = sizeof(struct in_addr);
887 } else if (af == AF_INET6) {
888 sz = sizeof(struct in6_addr);
889 } else {
890 return NULL;
891 }
892
893 attr = NPF_RULE_PASS | NPF_RULE_FINAL |
894 (type == NPF_NATOUT ? NPF_RULE_OUT : NPF_RULE_IN);
895
896 /* Create a rule for NAT policy. Next, will add translation data. */
897 rl = npf_rule_create(NULL, attr, if_idx);
898 if (rl == NULL) {
899 return NULL;
900 }
901 rldict = rl->nrl_dict;
902
903 /* Translation type and flags. */
904 prop_dictionary_set_int32(rldict, "type", type);
905 prop_dictionary_set_uint32(rldict, "flags", flags);
906
907 /* Translation IP. */
908 addrdat = prop_data_create_data(addr, sz);
909 if (addrdat == NULL) {
910 npf_rule_destroy(rl);
911 return NULL;
912 }
913 prop_dictionary_set(rldict, "translation-ip", addrdat);
914 prop_object_release(addrdat);
915
916 /* Translation port (for redirect case). */
917 prop_dictionary_set_uint16(rldict, "translation-port", port);
918
919 return (nl_nat_t *)rl;
920 }
921
922 int
923 npf_nat_insert(nl_config_t *ncf, nl_nat_t *nt, pri_t pri __unused)
924 {
925 prop_dictionary_t rldict = nt->nrl_dict;
926
927 prop_dictionary_set_int32(rldict, "priority", NPF_PRI_LAST);
928 prop_array_add(ncf->ncf_nat_list, rldict);
929 return 0;
930 }
931
932 nl_nat_t *
933 npf_nat_iterate(nl_config_t *ncf)
934 {
935 u_int level;
936 return _npf_rule_iterate1(ncf, ncf->ncf_nat_list, &level);
937 }
938
939 int
940 npf_nat_gettype(nl_nat_t *nt)
941 {
942 prop_dictionary_t rldict = nt->nrl_dict;
943 int type = 0;
944
945 prop_dictionary_get_int32(rldict, "type", &type);
946 return type;
947 }
948
949 void
950 npf_nat_getmap(nl_nat_t *nt, npf_addr_t *addr, size_t *alen, in_port_t *port)
951 {
952 prop_dictionary_t rldict = nt->nrl_dict;
953 prop_object_t obj = prop_dictionary_get(rldict, "translation-ip");
954
955 *alen = prop_data_size(obj);
956 memcpy(addr, prop_data_data_nocopy(obj), *alen);
957
958 *port = 0;
959 prop_dictionary_get_uint16(rldict, "translation-port", port);
960 }
961
962 #if 1
963 int
964 _npf_nat_foreach(nl_config_t *ncf, nl_rule_callback_t func)
965 {
966 return _npf_rule_foreach1(ncf->ncf_nat_list, func);
967 }
968
969 void
970 _npf_nat_getinfo(nl_nat_t *nt, int *type, u_int *flags, npf_addr_t *addr,
971 size_t *alen, in_port_t *port)
972 {
973 prop_dictionary_t rldict = nt->nrl_dict;
974
975 prop_dictionary_get_int32(rldict, "type", type);
976 prop_dictionary_get_uint32(rldict, "flags", flags);
977
978 prop_object_t obj = prop_dictionary_get(rldict, "translation-ip");
979 *alen = prop_data_size(obj);
980 memcpy(addr, prop_data_data_nocopy(obj), *alen);
981
982 prop_dictionary_get_uint16(rldict, "translation-port", port);
983 }
984 #endif
985
986 /*
987 * TABLE INTERFACE.
988 */
989
990 nl_table_t *
991 npf_table_create(u_int id, int type)
992 {
993 prop_dictionary_t tldict;
994 prop_array_t tblents;
995 nl_table_t *tl;
996
997 tl = malloc(sizeof(*tl));
998 if (tl == NULL) {
999 return NULL;
1000 }
1001 tldict = prop_dictionary_create();
1002 if (tldict == NULL) {
1003 free(tl);
1004 return NULL;
1005 }
1006 prop_dictionary_set_uint32(tldict, "id", id);
1007 prop_dictionary_set_int32(tldict, "type", type);
1008
1009 tblents = prop_array_create();
1010 if (tblents == NULL) {
1011 prop_object_release(tldict);
1012 free(tl);
1013 return NULL;
1014 }
1015 prop_dictionary_set(tldict, "entries", tblents);
1016 prop_object_release(tblents);
1017
1018 tl->ntl_dict = tldict;
1019 return tl;
1020 }
1021
1022 int
1023 npf_table_add_entry(nl_table_t *tl, int af, const npf_addr_t *addr,
1024 const npf_netmask_t mask)
1025 {
1026 prop_dictionary_t tldict = tl->ntl_dict, entdict;
1027 prop_array_t tblents;
1028 prop_data_t addrdata;
1029 unsigned alen;
1030
1031 /* Create the table entry. */
1032 entdict = prop_dictionary_create();
1033 if (entdict == NULL) {
1034 return ENOMEM;
1035 }
1036
1037 switch (af) {
1038 case AF_INET:
1039 alen = sizeof(struct in_addr);
1040 break;
1041 case AF_INET6:
1042 alen = sizeof(struct in6_addr);
1043 break;
1044 default:
1045 return EINVAL;
1046 }
1047
1048 addrdata = prop_data_create_data(addr, alen);
1049 prop_dictionary_set(entdict, "addr", addrdata);
1050 prop_dictionary_set_uint8(entdict, "mask", mask);
1051 prop_object_release(addrdata);
1052
1053 tblents = prop_dictionary_get(tldict, "entries");
1054 prop_array_add(tblents, entdict);
1055 prop_object_release(entdict);
1056 return 0;
1057 }
1058
1059 bool
1060 npf_table_exists_p(nl_config_t *ncf, u_int tid)
1061 {
1062 prop_dictionary_t tldict;
1063 prop_object_iterator_t it;
1064 u_int i;
1065
1066 it = prop_array_iterator(ncf->ncf_table_list);
1067 while ((tldict = prop_object_iterator_next(it)) != NULL) {
1068 if (prop_dictionary_get_uint32(tldict, "id", &i) && tid == i)
1069 break;
1070 }
1071 prop_object_iterator_release(it);
1072 return tldict ? true : false;
1073 }
1074
1075 int
1076 npf_table_insert(nl_config_t *ncf, nl_table_t *tl)
1077 {
1078 prop_dictionary_t tldict = tl->ntl_dict;
1079 u_int tid;
1080
1081 if (!prop_dictionary_get_uint32(tldict, "id", &tid)) {
1082 return EINVAL;
1083 }
1084 if (npf_table_exists_p(ncf, tid)) {
1085 return EEXIST;
1086 }
1087 prop_array_add(ncf->ncf_table_list, tldict);
1088 return 0;
1089 }
1090
1091 nl_table_t *
1092 npf_table_iterate(nl_config_t *ncf)
1093 {
1094 prop_dictionary_t tldict;
1095
1096 if (!ncf->ncf_table_iter) {
1097 /* Initialise the iterator. */
1098 ncf->ncf_table_iter = prop_array_iterator(ncf->ncf_table_list);
1099 }
1100 tldict = prop_object_iterator_next(ncf->ncf_table_iter);
1101 if ((ncf->ncf_cur_table.ntl_dict = tldict) == NULL) {
1102 prop_object_iterator_release(ncf->ncf_table_iter);
1103 ncf->ncf_table_iter = NULL;
1104 return NULL;
1105 }
1106 return &ncf->ncf_cur_table;
1107 }
1108
1109 unsigned
1110 npf_table_getid(nl_table_t *tl)
1111 {
1112 prop_dictionary_t tldict = tl->ntl_dict;
1113 u_int id = 0;
1114
1115 prop_dictionary_get_uint32(tldict, "id", &id);
1116 return id;
1117 }
1118
1119 int
1120 npf_table_gettype(nl_table_t *tl)
1121 {
1122 prop_dictionary_t tldict = tl->ntl_dict;
1123 int type = 0;
1124
1125 prop_dictionary_get_int32(tldict, "type", &type);
1126 return type;
1127 }
1128
1129 void
1130 npf_table_destroy(nl_table_t *tl)
1131 {
1132 prop_object_release(tl->ntl_dict);
1133 free(tl);
1134 }
1135
1136 #if 1
1137 void
1138 _npf_table_foreach(nl_config_t *ncf, nl_table_callback_t func)
1139 {
1140 prop_dictionary_t tldict;
1141 prop_object_iterator_t it;
1142
1143 it = prop_array_iterator(ncf->ncf_table_list);
1144 while ((tldict = prop_object_iterator_next(it)) != NULL) {
1145 u_int id;
1146 int type;
1147
1148 prop_dictionary_get_uint32(tldict, "id", &id);
1149 prop_dictionary_get_int32(tldict, "type", &type);
1150 (*func)(id, type);
1151 }
1152 prop_object_iterator_release(it);
1153 }
1154 #endif
1155
1156 /*
1157 * ALG INTERFACE.
1158 */
1159
1160 int
1161 _npf_alg_load(nl_config_t *ncf, const char *name)
1162 {
1163 prop_dictionary_t al_dict;
1164
1165 if (_npf_prop_array_lookup(ncf->ncf_alg_list, "name", name))
1166 return EEXIST;
1167
1168 al_dict = prop_dictionary_create();
1169 prop_dictionary_set_cstring(al_dict, "name", name);
1170 prop_array_add(ncf->ncf_alg_list, al_dict);
1171 prop_object_release(al_dict);
1172 return 0;
1173 }
1174
1175 int
1176 _npf_alg_unload(nl_config_t *ncf, const char *name)
1177 {
1178 if (!_npf_prop_array_lookup(ncf->ncf_alg_list, "name", name))
1179 return ENOENT;
1180
1181 // Not yet: prop_array_add(ncf->ncf_alg_list, al_dict);
1182 return ENOTSUP;
1183 }
1184
1185 /*
1186 * MISC.
1187 */
1188
1189 int
1190 npf_sessions_recv(int fd, const char *fpath)
1191 {
1192 prop_dictionary_t sdict;
1193 int error;
1194
1195 error = prop_dictionary_recv_ioctl(fd, IOC_NPF_SESSIONS_SAVE, &sdict);
1196 if (error) {
1197 return error;
1198 }
1199 if (!prop_dictionary_externalize_to_file(sdict, fpath)) {
1200 error = errno;
1201 }
1202 prop_object_release(sdict);
1203 return error;
1204 }
1205
1206 int
1207 npf_sessions_send(int fd, const char *fpath)
1208 {
1209 prop_dictionary_t sdict;
1210 int error;
1211
1212 if (fpath) {
1213 sdict = prop_dictionary_internalize_from_file(fpath);
1214 if (sdict == NULL) {
1215 return errno;
1216 }
1217 } else {
1218 /* Empty: will flush the sessions. */
1219 prop_array_t selist = prop_array_create();
1220 sdict = prop_dictionary_create();
1221 prop_dictionary_set(sdict, "session-list", selist);
1222 prop_object_release(selist);
1223 }
1224 error = prop_dictionary_send_ioctl(sdict, fd, IOC_NPF_SESSIONS_LOAD);
1225 prop_object_release(sdict);
1226 return error;
1227 }
1228
1229 static prop_dictionary_t
1230 _npf_debug_initonce(nl_config_t *ncf)
1231 {
1232 if (!ncf->ncf_debug) {
1233 prop_array_t iflist = prop_array_create();
1234 ncf->ncf_debug = prop_dictionary_create();
1235 prop_dictionary_set(ncf->ncf_debug, "interfaces", iflist);
1236 prop_object_release(iflist);
1237 }
1238 return ncf->ncf_debug;
1239 }
1240
1241 void
1242 _npf_debug_addif(nl_config_t *ncf, struct ifaddrs *ifa, u_int if_idx)
1243 {
1244 prop_dictionary_t ifdict, dbg = _npf_debug_initonce(ncf);
1245 prop_array_t iflist = prop_dictionary_get(dbg, "interfaces");
1246
1247 if (_npf_prop_array_lookup(iflist, "name", ifa->ifa_name)) {
1248 return;
1249 }
1250
1251 ifdict = prop_dictionary_create();
1252 prop_dictionary_set_cstring(ifdict, "name", ifa->ifa_name);
1253 prop_dictionary_set_uint32(ifdict, "flags", ifa->ifa_flags);
1254 if (!if_idx) {
1255 if_idx = if_nametoindex(ifa->ifa_name);
1256 }
1257 prop_dictionary_set_uint32(ifdict, "idx", if_idx);
1258
1259 const struct sockaddr *sa = ifa->ifa_addr;
1260 npf_addr_t addr;
1261 size_t alen = 0;
1262
1263 switch (sa ? sa->sa_family : -1) {
1264 case AF_INET: {
1265 const struct sockaddr_in *sin = (const void *)sa;
1266 alen = sizeof(sin->sin_addr);
1267 memcpy(&addr, &sin->sin_addr, alen);
1268 break;
1269 }
1270 case AF_INET6: {
1271 const struct sockaddr_in6 *sin6 = (const void *)sa;
1272 alen = sizeof(sin6->sin6_addr);
1273 memcpy(&addr, &sin6->sin6_addr, alen);
1274 break;
1275 }
1276 default:
1277 break;
1278 }
1279
1280 if (alen) {
1281 prop_data_t addrdata = prop_data_create_data(&addr, alen);
1282 prop_dictionary_set(ifdict, "addr", addrdata);
1283 prop_object_release(addrdata);
1284 }
1285 prop_array_add(iflist, ifdict);
1286 prop_object_release(ifdict);
1287 }
1288