Home | History | Annotate | Line # | Download | only in libnpf
npf.c revision 1.43
      1 /*	$NetBSD: npf.c,v 1.43 2017/01/03 00:59:31 christos Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2010-2015 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.43 2017/01/03 00:59:31 christos 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, procedures, tables, connections. */
     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 	prop_array_t		ncf_conn_list;
     80 
     81 	/* Iterators. */
     82 	prop_object_iterator_t	ncf_rule_iter;
     83 	unsigned		ncf_reduce[16];
     84 	unsigned		ncf_nlevel;
     85 	unsigned		ncf_counter;
     86 	nl_rule_t		ncf_cur_rule;
     87 
     88 	prop_object_iterator_t	ncf_table_iter;
     89 	nl_table_t		ncf_cur_table;
     90 
     91 	prop_object_iterator_t	ncf_rproc_iter;
     92 	nl_rproc_t		ncf_cur_rproc;
     93 
     94 	/* Error report and debug information. */
     95 	prop_dictionary_t	ncf_err;
     96 	prop_dictionary_t	ncf_debug;
     97 
     98 	bool			ncf_flush;
     99 };
    100 
    101 static prop_array_t	_npf_ruleset_transform(prop_array_t);
    102 
    103 static bool
    104 _npf_add_addr(prop_dictionary_t dict, const char *name, int af,
    105     const npf_addr_t *addr)
    106 {
    107 	size_t sz;
    108 
    109 	if (af == AF_INET) {
    110 		sz = sizeof(struct in_addr);
    111 	} else if (af == AF_INET6) {
    112 		sz = sizeof(struct in6_addr);
    113 	} else {
    114 		return false;
    115 	}
    116 	prop_data_t addrdat = prop_data_create_data(addr, sz);
    117 	if (addrdat == NULL) {
    118 		return false;
    119 	}
    120 	prop_dictionary_set(dict, name, addrdat);
    121 	prop_object_release(addrdat);
    122 	return true;
    123 }
    124 
    125 static unsigned
    126 _npf_get_addr(prop_dictionary_t dict, const char *name, npf_addr_t *addr)
    127 {
    128 	prop_object_t obj = prop_dictionary_get(dict, name);
    129 	const void *d = prop_data_data_nocopy(obj);
    130 
    131 	if (d == NULL)
    132 		return false;
    133 
    134 	size_t sz = prop_data_size(obj);
    135 	switch (sz) {
    136 	case sizeof(struct in_addr):
    137 	case sizeof(struct in6_addr):
    138 		memcpy(addr, d, sz);
    139 		return (unsigned)sz;
    140 	default:
    141 		return 0;
    142 	}
    143 }
    144 
    145 /*
    146  * CONFIGURATION INTERFACE.
    147  */
    148 
    149 nl_config_t *
    150 npf_config_create(void)
    151 {
    152 	nl_config_t *ncf;
    153 
    154 	ncf = calloc(1, sizeof(*ncf));
    155 	if (ncf == NULL) {
    156 		return NULL;
    157 	}
    158 	ncf->ncf_alg_list = prop_array_create();
    159 	ncf->ncf_rules_list = prop_array_create();
    160 	ncf->ncf_rproc_list = prop_array_create();
    161 	ncf->ncf_table_list = prop_array_create();
    162 	ncf->ncf_nat_list = prop_array_create();
    163 	ncf->ncf_flush = false;
    164 	return ncf;
    165 }
    166 
    167 static prop_dictionary_t
    168 _npf_build_config(nl_config_t *ncf)
    169 {
    170 	prop_dictionary_t npf_dict;
    171 	prop_array_t rlset;
    172 
    173 	npf_dict = prop_dictionary_create();
    174 	if (npf_dict == NULL) {
    175 		return NULL;
    176 	}
    177 	prop_dictionary_set_uint32(npf_dict, "version", NPF_VERSION);
    178 
    179 	rlset = _npf_ruleset_transform(ncf->ncf_rules_list);
    180 	if (rlset == NULL) {
    181 		prop_object_release(npf_dict);
    182 		return NULL;
    183 	}
    184 	prop_object_release(ncf->ncf_rules_list);
    185 	ncf->ncf_rules_list = rlset;
    186 
    187 	prop_dictionary_set(npf_dict, "rules", ncf->ncf_rules_list);
    188 	prop_dictionary_set(npf_dict, "algs", ncf->ncf_alg_list);
    189 	prop_dictionary_set(npf_dict, "rprocs", ncf->ncf_rproc_list);
    190 	prop_dictionary_set(npf_dict, "tables", ncf->ncf_table_list);
    191 	prop_dictionary_set(npf_dict, "nat", ncf->ncf_nat_list);
    192 	if (ncf->ncf_conn_list) {
    193 		prop_dictionary_set(npf_dict, "conn-list",
    194 		    ncf->ncf_conn_list);
    195 	}
    196 	prop_dictionary_set_bool(npf_dict, "flush", ncf->ncf_flush);
    197 	if (ncf->ncf_debug) {
    198 		prop_dictionary_set(npf_dict, "debug", ncf->ncf_debug);
    199 	}
    200 	return npf_dict;
    201 }
    202 
    203 int
    204 npf_config_submit(nl_config_t *ncf, int fd, npf_error_t *errinfo)
    205 {
    206 #if !defined(_NPF_STANDALONE)
    207 	prop_dictionary_t npf_dict;
    208 	int error = 0;
    209 
    210 	npf_dict = _npf_build_config(ncf);
    211 	if (!npf_dict) {
    212 		return ENOMEM;
    213 	}
    214 	error = prop_dictionary_sendrecv_ioctl(npf_dict, fd,
    215 	    IOC_NPF_LOAD, &ncf->ncf_err);
    216 	if (error) {
    217 		prop_object_release(npf_dict);
    218 		assert(ncf->ncf_err == NULL);
    219 		return error;
    220 	}
    221 	prop_dictionary_get_int32(ncf->ncf_err, "errno", &error);
    222 	if (error) {
    223 		memset(errinfo, 0, sizeof(*errinfo));
    224 
    225 		prop_dictionary_get_int64(ncf->ncf_err, "id",
    226 		    &errinfo->id);
    227 		prop_dictionary_get_cstring(ncf->ncf_err,
    228 		    "source-file", &errinfo->source_file);
    229 		prop_dictionary_get_uint32(ncf->ncf_err,
    230 		    "source-line", &errinfo->source_line);
    231 	}
    232 	prop_object_release(npf_dict);
    233 	return error;
    234 #else
    235 	(void)ncf; (void)fd;
    236 	return ENOTSUP;
    237 #endif
    238 }
    239 
    240 static nl_config_t *
    241 _npf_config_consdict(prop_dictionary_t npf_dict)
    242 {
    243 	nl_config_t *ncf;
    244 
    245 	ncf = calloc(1, sizeof(*ncf));
    246 	if (ncf == NULL) {
    247 		return NULL;
    248 	}
    249 	ncf->ncf_dict = npf_dict;
    250 	ncf->ncf_alg_list = prop_dictionary_get(npf_dict, "algs");
    251 	ncf->ncf_rules_list = prop_dictionary_get(npf_dict, "rules");
    252 	ncf->ncf_rproc_list = prop_dictionary_get(npf_dict, "rprocs");
    253 	ncf->ncf_table_list = prop_dictionary_get(npf_dict, "tables");
    254 	ncf->ncf_nat_list = prop_dictionary_get(npf_dict, "nat");
    255 	ncf->ncf_conn_list = prop_dictionary_get(npf_dict, "conn-list");
    256 	return ncf;
    257 }
    258 
    259 nl_config_t *
    260 npf_config_retrieve(int fd)
    261 {
    262 	prop_dictionary_t npf_dict;
    263 	nl_config_t *ncf;
    264 	int error;
    265 
    266 #ifdef _NPF_STANDALONE
    267 	error = ENOTSUP;
    268 #else
    269 	error = prop_dictionary_recv_ioctl(fd, IOC_NPF_SAVE, &npf_dict);
    270 #endif
    271 	if (error) {
    272 		return NULL;
    273 	}
    274 	ncf = _npf_config_consdict(npf_dict);
    275 	if (ncf == NULL) {
    276 		prop_object_release(npf_dict);
    277 		return NULL;
    278 	}
    279 	return ncf;
    280 }
    281 
    282 void *
    283 npf_config_export(nl_config_t *ncf, size_t *length)
    284 {
    285 	prop_dictionary_t npf_dict = ncf->ncf_dict;
    286 	void *blob;
    287 
    288 	if (!npf_dict && (npf_dict = _npf_build_config(ncf)) == NULL) {
    289 		errno = ENOMEM;
    290 		return NULL;
    291 	}
    292 	if ((blob = prop_dictionary_externalize(npf_dict)) == NULL) {
    293 		prop_object_release(npf_dict);
    294 		return NULL;
    295 	}
    296 	prop_object_release(npf_dict);
    297 	*length = strlen(blob);
    298 	return blob;
    299 }
    300 
    301 nl_config_t *
    302 npf_config_import(const void *blob, size_t len __unused)
    303 {
    304 	prop_dictionary_t npf_dict;
    305 	nl_config_t *ncf;
    306 
    307 	npf_dict = prop_dictionary_internalize(blob);
    308 	if (!npf_dict) {
    309 		return NULL;
    310 	}
    311 	ncf = _npf_config_consdict(npf_dict);
    312 	if (!ncf) {
    313 		prop_object_release(npf_dict);
    314 		return NULL;
    315 	}
    316 	return ncf;
    317 }
    318 
    319 int
    320 npf_config_flush(int fd)
    321 {
    322 	nl_config_t *ncf;
    323 	npf_error_t errinfo;
    324 	int error;
    325 
    326 	ncf = npf_config_create();
    327 	if (ncf == NULL) {
    328 		return ENOMEM;
    329 	}
    330 	ncf->ncf_flush = true;
    331 	error = npf_config_submit(ncf, fd, &errinfo);
    332 	npf_config_destroy(ncf);
    333 	return error;
    334 }
    335 
    336 bool
    337 npf_config_active_p(nl_config_t *ncf)
    338 {
    339 	bool active = false;
    340 	prop_dictionary_get_bool(ncf->ncf_dict, "active", &active);
    341 	return active;
    342 }
    343 
    344 bool
    345 npf_config_loaded_p(nl_config_t *ncf)
    346 {
    347 	return ncf->ncf_rules_list != NULL;
    348 }
    349 
    350 void *
    351 npf_config_build(nl_config_t *ncf)
    352 {
    353 	if (!ncf->ncf_dict && !(ncf->ncf_dict = _npf_build_config(ncf))) {
    354 		errno = ENOMEM;
    355 		return NULL;
    356 	}
    357 	return (void *)ncf->ncf_dict;
    358 }
    359 
    360 void
    361 npf_config_destroy(nl_config_t *ncf)
    362 {
    363 	if (!ncf->ncf_dict) {
    364 		prop_object_release(ncf->ncf_alg_list);
    365 		prop_object_release(ncf->ncf_rules_list);
    366 		prop_object_release(ncf->ncf_rproc_list);
    367 		prop_object_release(ncf->ncf_table_list);
    368 		prop_object_release(ncf->ncf_nat_list);
    369 	}
    370 	if (ncf->ncf_err) {
    371 		prop_object_release(ncf->ncf_err);
    372 	}
    373 	if (ncf->ncf_debug) {
    374 		prop_object_release(ncf->ncf_debug);
    375 	}
    376 	free(ncf);
    377 }
    378 
    379 static bool
    380 _npf_prop_array_lookup(prop_array_t array, const char *key, const char *name)
    381 {
    382 	prop_dictionary_t dict;
    383 	prop_object_iterator_t it;
    384 
    385 	it = prop_array_iterator(array);
    386 	while ((dict = prop_object_iterator_next(it)) != NULL) {
    387 		const char *lname;
    388 		prop_dictionary_get_cstring_nocopy(dict, key, &lname);
    389 		if (strcmp(name, lname) == 0)
    390 			break;
    391 	}
    392 	prop_object_iterator_release(it);
    393 	return dict ? true : false;
    394 }
    395 
    396 /*
    397  * DYNAMIC RULESET INTERFACE.
    398  */
    399 
    400 int
    401 npf_ruleset_add(int fd, const char *rname, nl_rule_t *rl, uint64_t *id)
    402 {
    403 	prop_dictionary_t rldict = rl->nrl_dict;
    404 	prop_dictionary_t ret;
    405 	int error;
    406 
    407 	prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
    408 	prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_ADD);
    409 #ifdef _NPF_STANDALONE
    410 	error = ENOTSUP;
    411 #else
    412 	error = prop_dictionary_sendrecv_ioctl(rldict, fd, IOC_NPF_RULE, &ret);
    413 #endif
    414 	if (!error) {
    415 		prop_dictionary_get_uint64(ret, "id", id);
    416 	}
    417 	return error;
    418 }
    419 
    420 int
    421 npf_ruleset_remove(int fd, const char *rname, uint64_t id)
    422 {
    423 	prop_dictionary_t rldict;
    424 
    425 	rldict = prop_dictionary_create();
    426 	if (rldict == NULL) {
    427 		return ENOMEM;
    428 	}
    429 	prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
    430 	prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_REMOVE);
    431 	prop_dictionary_set_uint64(rldict, "id", id);
    432 #ifdef _NPF_STANDALONE
    433 	return ENOTSUP;
    434 #else
    435 	return prop_dictionary_send_ioctl(rldict, fd, IOC_NPF_RULE);
    436 #endif
    437 }
    438 
    439 int
    440 npf_ruleset_remkey(int fd, const char *rname, const void *key, size_t len)
    441 {
    442 	prop_dictionary_t rldict;
    443 	prop_data_t keyobj;
    444 
    445 	rldict = prop_dictionary_create();
    446 	if (rldict == NULL) {
    447 		return ENOMEM;
    448 	}
    449 	prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
    450 	prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_REMKEY);
    451 
    452 	keyobj = prop_data_create_data(key, len);
    453 	if (keyobj == NULL) {
    454 		prop_object_release(rldict);
    455 		return ENOMEM;
    456 	}
    457 	prop_dictionary_set(rldict, "key", keyobj);
    458 	prop_object_release(keyobj);
    459 
    460 #ifdef _NPF_STANDALONE
    461 	return ENOTSUP;
    462 #else
    463 	return prop_dictionary_send_ioctl(rldict, fd, IOC_NPF_RULE);
    464 #endif
    465 }
    466 
    467 int
    468 npf_ruleset_flush(int fd, const char *rname)
    469 {
    470 	prop_dictionary_t rldict;
    471 
    472 	rldict = prop_dictionary_create();
    473 	if (rldict == NULL) {
    474 		return ENOMEM;
    475 	}
    476 	prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
    477 	prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_FLUSH);
    478 #ifdef _NPF_STANDALONE
    479 	return ENOTSUP;
    480 #else
    481 	return prop_dictionary_send_ioctl(rldict, fd, IOC_NPF_RULE);
    482 #endif
    483 }
    484 
    485 /*
    486  * _npf_ruleset_transform: transform the ruleset representing nested
    487  * rules with lists into an array.
    488  */
    489 
    490 static void
    491 _npf_ruleset_transform1(prop_array_t rlset, prop_array_t rules)
    492 {
    493 	prop_object_iterator_t it;
    494 	prop_dictionary_t rldict;
    495 	prop_array_t subrlset;
    496 
    497 	it = prop_array_iterator(rules);
    498 	while ((rldict = prop_object_iterator_next(it)) != NULL) {
    499 		unsigned idx;
    500 
    501 		/* Add rules to the array (reference is retained). */
    502 		prop_array_add(rlset, rldict);
    503 
    504 		subrlset = prop_dictionary_get(rldict, "subrules");
    505 		if (subrlset) {
    506 			/* Process subrules recursively. */
    507 			_npf_ruleset_transform1(rlset, subrlset);
    508 			/* Add the skip-to position. */
    509 			idx = prop_array_count(rlset);
    510 			prop_dictionary_set_uint32(rldict, "skip-to", idx);
    511 			prop_dictionary_remove(rldict, "subrules");
    512 		}
    513 	}
    514 	prop_object_iterator_release(it);
    515 }
    516 
    517 static prop_array_t
    518 _npf_ruleset_transform(prop_array_t rlset)
    519 {
    520 	prop_array_t nrlset;
    521 
    522 	nrlset = prop_array_create();
    523 	_npf_ruleset_transform1(nrlset, rlset);
    524 	return nrlset;
    525 }
    526 
    527 /*
    528  * NPF EXTENSION INTERFACE.
    529  */
    530 
    531 nl_ext_t *
    532 npf_ext_construct(const char *name)
    533 {
    534 	nl_ext_t *ext;
    535 
    536 	ext = malloc(sizeof(*ext));
    537 	if (ext == NULL) {
    538 		return NULL;
    539 	}
    540 	ext->nxt_name = strdup(name);
    541 	if (ext->nxt_name == NULL) {
    542 		free(ext);
    543 		return NULL;
    544 	}
    545 	ext->nxt_dict = prop_dictionary_create();
    546 
    547 	return ext;
    548 }
    549 
    550 void
    551 npf_ext_param_u32(nl_ext_t *ext, const char *key, uint32_t val)
    552 {
    553 	prop_dictionary_t extdict = ext->nxt_dict;
    554 	prop_dictionary_set_uint32(extdict, key, val);
    555 }
    556 
    557 void
    558 npf_ext_param_bool(nl_ext_t *ext, const char *key, bool val)
    559 {
    560 	prop_dictionary_t extdict = ext->nxt_dict;
    561 	prop_dictionary_set_bool(extdict, key, val);
    562 }
    563 
    564 void
    565 npf_ext_param_string(nl_ext_t *ext, const char *key, const char *val)
    566 {
    567 	prop_dictionary_t extdict = ext->nxt_dict;
    568 	prop_dictionary_set_cstring(extdict, key, val);
    569 }
    570 
    571 /*
    572  * RULE INTERFACE.
    573  */
    574 
    575 nl_rule_t *
    576 npf_rule_create(const char *name, uint32_t attr, const char *ifname)
    577 {
    578 	prop_dictionary_t rldict;
    579 	nl_rule_t *rl;
    580 
    581 	rl = malloc(sizeof(*rl));
    582 	if (rl == NULL) {
    583 		return NULL;
    584 	}
    585 	rldict = prop_dictionary_create();
    586 	if (rldict == NULL) {
    587 		free(rl);
    588 		return NULL;
    589 	}
    590 	if (name) {
    591 		prop_dictionary_set_cstring(rldict, "name", name);
    592 	}
    593 	prop_dictionary_set_uint32(rldict, "attr", attr);
    594 
    595 	if (ifname) {
    596 		prop_dictionary_set_cstring(rldict, "ifname", ifname);
    597 	}
    598 	rl->nrl_dict = rldict;
    599 	return rl;
    600 }
    601 
    602 int
    603 npf_rule_setcode(nl_rule_t *rl, int type, const void *code, size_t len)
    604 {
    605 	prop_dictionary_t rldict = rl->nrl_dict;
    606 	prop_data_t cdata;
    607 
    608 	switch (type) {
    609 	case NPF_CODE_NC:
    610 	case NPF_CODE_BPF:
    611 		break;
    612 	default:
    613 		return ENOTSUP;
    614 	}
    615 	prop_dictionary_set_uint32(rldict, "code-type", (uint32_t)type);
    616 	if ((cdata = prop_data_create_data(code, len)) == NULL) {
    617 		return ENOMEM;
    618 	}
    619 	prop_dictionary_set(rldict, "code", cdata);
    620 	prop_object_release(cdata);
    621 	return 0;
    622 }
    623 
    624 int
    625 npf_rule_setkey(nl_rule_t *rl, const void *key, size_t len)
    626 {
    627 	prop_dictionary_t rldict = rl->nrl_dict;
    628 	prop_data_t kdata;
    629 
    630 	if ((kdata = prop_data_create_data(key, len)) == NULL) {
    631 		return ENOMEM;
    632 	}
    633 	prop_dictionary_set(rldict, "key", kdata);
    634 	prop_object_release(kdata);
    635 	return 0;
    636 }
    637 
    638 int
    639 npf_rule_setinfo(nl_rule_t *rl, const void *info, size_t len)
    640 {
    641 	prop_dictionary_t rldict = rl->nrl_dict;
    642 	prop_data_t idata;
    643 
    644 	if ((idata = prop_data_create_data(info, len)) == NULL) {
    645 		return ENOMEM;
    646 	}
    647 	prop_dictionary_set(rldict, "info", idata);
    648 	prop_object_release(idata);
    649 	return 0;
    650 }
    651 
    652 int
    653 npf_rule_setprio(nl_rule_t *rl, int pri)
    654 {
    655 	prop_dictionary_t rldict = rl->nrl_dict;
    656 
    657 	prop_dictionary_set_int32(rldict, "prio", pri);
    658 	return 0;
    659 }
    660 
    661 int
    662 npf_rule_setproc(nl_rule_t *rl, const char *name)
    663 {
    664 	prop_dictionary_t rldict = rl->nrl_dict;
    665 
    666 	prop_dictionary_set_cstring(rldict, "rproc", name);
    667 	return 0;
    668 }
    669 
    670 void *
    671 npf_rule_export(nl_rule_t *rl, size_t *length)
    672 {
    673 	prop_dictionary_t rldict = rl->nrl_dict;
    674 	void *xml;
    675 
    676 	if ((xml = prop_dictionary_externalize(rldict)) == NULL) {
    677 		return NULL;
    678 	}
    679 	*length = strlen(xml);
    680 	return xml;
    681 }
    682 
    683 bool
    684 npf_rule_exists_p(nl_config_t *ncf, const char *name)
    685 {
    686 	return _npf_prop_array_lookup(ncf->ncf_rules_list, "name", name);
    687 }
    688 
    689 int
    690 npf_rule_insert(nl_config_t *ncf, nl_rule_t *parent, nl_rule_t *rl)
    691 {
    692 	prop_dictionary_t rldict = rl->nrl_dict;
    693 	prop_array_t rlset;
    694 
    695 	if (parent) {
    696 		prop_dictionary_t pdict = parent->nrl_dict;
    697 		rlset = prop_dictionary_get(pdict, "subrules");
    698 		if (rlset == NULL) {
    699 			rlset = prop_array_create();
    700 			prop_dictionary_set(pdict, "subrules", rlset);
    701 			prop_object_release(rlset);
    702 		}
    703 	} else {
    704 		rlset = ncf->ncf_rules_list;
    705 	}
    706 	prop_array_add(rlset, rldict);
    707 	prop_object_release(rldict);
    708 	return 0;
    709 }
    710 
    711 static nl_rule_t *
    712 _npf_rule_iterate1(nl_config_t *ncf, prop_array_t rlist, unsigned *level)
    713 {
    714 	prop_dictionary_t rldict;
    715 	uint32_t skipto = 0;
    716 
    717 	if (!ncf->ncf_rule_iter) {
    718 		/* Initialise the iterator. */
    719 		ncf->ncf_rule_iter = prop_array_iterator(rlist);
    720 		ncf->ncf_nlevel = 0;
    721 		ncf->ncf_reduce[0] = 0;
    722 		ncf->ncf_counter = 0;
    723 	}
    724 
    725 	rldict = prop_object_iterator_next(ncf->ncf_rule_iter);
    726 	if ((ncf->ncf_cur_rule.nrl_dict = rldict) == NULL) {
    727 		prop_object_iterator_release(ncf->ncf_rule_iter);
    728 		ncf->ncf_rule_iter = NULL;
    729 		return NULL;
    730 	}
    731 	*level = ncf->ncf_nlevel;
    732 
    733 	prop_dictionary_get_uint32(rldict, "skip-to", &skipto);
    734 	if (skipto) {
    735 		ncf->ncf_nlevel++;
    736 		ncf->ncf_reduce[ncf->ncf_nlevel] = skipto;
    737 	}
    738 	if (ncf->ncf_reduce[ncf->ncf_nlevel] == ++ncf->ncf_counter) {
    739 		assert(ncf->ncf_nlevel > 0);
    740 		ncf->ncf_nlevel--;
    741 	}
    742 	return &ncf->ncf_cur_rule;
    743 }
    744 
    745 nl_rule_t *
    746 npf_rule_iterate(nl_config_t *ncf, unsigned *level)
    747 {
    748 	return _npf_rule_iterate1(ncf, ncf->ncf_rules_list, level);
    749 }
    750 
    751 const char *
    752 npf_rule_getname(nl_rule_t *rl)
    753 {
    754 	prop_dictionary_t rldict = rl->nrl_dict;
    755 	const char *rname = NULL;
    756 
    757 	prop_dictionary_get_cstring_nocopy(rldict, "name", &rname);
    758 	return rname;
    759 }
    760 
    761 uint32_t
    762 npf_rule_getattr(nl_rule_t *rl)
    763 {
    764 	prop_dictionary_t rldict = rl->nrl_dict;
    765 	uint32_t attr = 0;
    766 
    767 	prop_dictionary_get_uint32(rldict, "attr", &attr);
    768 	return attr;
    769 }
    770 
    771 const char *
    772 npf_rule_getinterface(nl_rule_t *rl)
    773 {
    774 	prop_dictionary_t rldict = rl->nrl_dict;
    775 	const char *ifname = NULL;
    776 
    777 	prop_dictionary_get_cstring_nocopy(rldict, "ifname", &ifname);
    778 	return ifname;
    779 }
    780 
    781 const void *
    782 npf_rule_getinfo(nl_rule_t *rl, size_t *len)
    783 {
    784 	prop_dictionary_t rldict = rl->nrl_dict;
    785 	prop_object_t obj = prop_dictionary_get(rldict, "info");
    786 
    787 	*len = prop_data_size(obj);
    788 	return prop_data_data_nocopy(obj);
    789 }
    790 
    791 const char *
    792 npf_rule_getproc(nl_rule_t *rl)
    793 {
    794 	prop_dictionary_t rldict = rl->nrl_dict;
    795 	const char *rpname = NULL;
    796 
    797 	prop_dictionary_get_cstring_nocopy(rldict, "rproc", &rpname);
    798 	return rpname;
    799 }
    800 
    801 uint64_t
    802 npf_rule_getid(nl_rule_t *rl)
    803 {
    804 	prop_dictionary_t rldict = rl->nrl_dict;
    805 	uint64_t id = 0;
    806 
    807 	(void)prop_dictionary_get_uint64(rldict, "id", &id);
    808 	return id;
    809 }
    810 
    811 const void *
    812 npf_rule_getcode(nl_rule_t *rl, int *type, size_t *len)
    813 {
    814 	prop_dictionary_t rldict = rl->nrl_dict;
    815 	prop_object_t obj = prop_dictionary_get(rldict, "code");
    816 
    817 	prop_dictionary_get_uint32(rldict, "code-type", (uint32_t *)type);
    818 	*len = prop_data_size(obj);
    819 	return prop_data_data_nocopy(obj);
    820 }
    821 
    822 int
    823 _npf_ruleset_list(int fd, const char *rname, nl_config_t *ncf)
    824 {
    825 	prop_dictionary_t rldict, ret;
    826 	int error;
    827 
    828 	rldict = prop_dictionary_create();
    829 	if (rldict == NULL) {
    830 		return ENOMEM;
    831 	}
    832 	prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
    833 	prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_LIST);
    834 #ifdef _NPF_STANDALONE
    835 	error = ENOTSUP;
    836 #else
    837 	error = prop_dictionary_sendrecv_ioctl(rldict, fd, IOC_NPF_RULE, &ret);
    838 #endif
    839 	if (!error) {
    840 		prop_array_t rules;
    841 
    842 		rules = prop_dictionary_get(ret, "rules");
    843 		if (rules == NULL) {
    844 			return EINVAL;
    845 		}
    846 		prop_object_release(ncf->ncf_rules_list);
    847 		ncf->ncf_rules_list = rules;
    848 	}
    849 	return error;
    850 }
    851 
    852 void
    853 npf_rule_destroy(nl_rule_t *rl)
    854 {
    855 
    856 	prop_object_release(rl->nrl_dict);
    857 	free(rl);
    858 }
    859 
    860 /*
    861  * RULE PROCEDURE INTERFACE.
    862  */
    863 
    864 nl_rproc_t *
    865 npf_rproc_create(const char *name)
    866 {
    867 	prop_dictionary_t rpdict;
    868 	prop_array_t extcalls;
    869 	nl_rproc_t *nrp;
    870 
    871 	nrp = malloc(sizeof(nl_rproc_t));
    872 	if (nrp == NULL) {
    873 		return NULL;
    874 	}
    875 	rpdict = prop_dictionary_create();
    876 	if (rpdict == NULL) {
    877 		free(nrp);
    878 		return NULL;
    879 	}
    880 	prop_dictionary_set_cstring(rpdict, "name", name);
    881 
    882 	extcalls = prop_array_create();
    883 	if (extcalls == NULL) {
    884 		prop_object_release(rpdict);
    885 		free(nrp);
    886 		return NULL;
    887 	}
    888 	prop_dictionary_set(rpdict, "extcalls", extcalls);
    889 	prop_object_release(extcalls);
    890 
    891 	nrp->nrp_dict = rpdict;
    892 	return nrp;
    893 }
    894 
    895 int
    896 npf_rproc_extcall(nl_rproc_t *rp, nl_ext_t *ext)
    897 {
    898 	prop_dictionary_t rpdict = rp->nrp_dict;
    899 	prop_dictionary_t extdict = ext->nxt_dict;
    900 	prop_array_t extcalls;
    901 
    902 	extcalls = prop_dictionary_get(rpdict, "extcalls");
    903 	if (_npf_prop_array_lookup(extcalls, "name", ext->nxt_name)) {
    904 		return EEXIST;
    905 	}
    906 	prop_dictionary_set_cstring(extdict, "name", ext->nxt_name);
    907 	prop_array_add(extcalls, extdict);
    908 	prop_object_release(extdict);
    909 	return 0;
    910 }
    911 
    912 bool
    913 npf_rproc_exists_p(nl_config_t *ncf, const char *name)
    914 {
    915 	return _npf_prop_array_lookup(ncf->ncf_rproc_list, "name", name);
    916 }
    917 
    918 int
    919 npf_rproc_insert(nl_config_t *ncf, nl_rproc_t *rp)
    920 {
    921 	prop_dictionary_t rpdict = rp->nrp_dict;
    922 	const char *name;
    923 
    924 	if (!prop_dictionary_get_cstring_nocopy(rpdict, "name", &name)) {
    925 		return EINVAL;
    926 	}
    927 	if (npf_rproc_exists_p(ncf, name)) {
    928 		return EEXIST;
    929 	}
    930 	prop_array_add(ncf->ncf_rproc_list, rpdict);
    931 	prop_object_release(rpdict);
    932 	return 0;
    933 }
    934 
    935 nl_rproc_t *
    936 npf_rproc_iterate(nl_config_t *ncf)
    937 {
    938 	prop_dictionary_t rpdict;
    939 
    940 	if (!ncf->ncf_rproc_iter) {
    941 		/* Initialise the iterator. */
    942 		ncf->ncf_rproc_iter = prop_array_iterator(ncf->ncf_rproc_list);
    943 	}
    944 	rpdict = prop_object_iterator_next(ncf->ncf_rproc_iter);
    945 	if ((ncf->ncf_cur_rproc.nrp_dict = rpdict) == NULL) {
    946 		prop_object_iterator_release(ncf->ncf_rproc_iter);
    947 		ncf->ncf_rproc_iter = NULL;
    948 		return NULL;
    949 	}
    950 	return &ncf->ncf_cur_rproc;
    951 }
    952 
    953 const char *
    954 npf_rproc_getname(nl_rproc_t *rp)
    955 {
    956 	prop_dictionary_t rpdict = rp->nrp_dict;
    957 	const char *rpname = NULL;
    958 
    959 	prop_dictionary_get_cstring_nocopy(rpdict, "name", &rpname);
    960 	return rpname;
    961 }
    962 
    963 /*
    964  * NAT INTERFACE.
    965  */
    966 
    967 nl_nat_t *
    968 npf_nat_create(int type, u_int flags, const char *ifname,
    969     int af, npf_addr_t *addr, npf_netmask_t mask, in_port_t port)
    970 {
    971 	nl_rule_t *rl;
    972 	prop_dictionary_t rldict;
    973 	uint32_t attr;
    974 
    975 	attr = NPF_RULE_PASS | NPF_RULE_FINAL |
    976 	    (type == NPF_NATOUT ? NPF_RULE_OUT : NPF_RULE_IN);
    977 
    978 	/* Create a rule for NAT policy.  Next, will add NAT data. */
    979 	rl = npf_rule_create(NULL, attr, ifname);
    980 	if (rl == NULL) {
    981 		return NULL;
    982 	}
    983 	rldict = rl->nrl_dict;
    984 
    985 	/* Translation type and flags. */
    986 	prop_dictionary_set_int32(rldict, "type", type);
    987 	prop_dictionary_set_uint32(rldict, "flags", flags);
    988 
    989 	/* Translation IP and mask. */
    990 	if (!_npf_add_addr(rldict, "nat-ip", af, addr)) {
    991 		npf_rule_destroy(rl);
    992 		return NULL;
    993 	}
    994 	prop_dictionary_set_uint32(rldict, "nat-mask", (uint32_t)mask);
    995 
    996 	/* Translation port (for redirect case). */
    997 	prop_dictionary_set_uint16(rldict, "nat-port", port);
    998 
    999 	return (nl_nat_t *)rl;
   1000 }
   1001 
   1002 int
   1003 npf_nat_insert(nl_config_t *ncf, nl_nat_t *nt, int pri __unused)
   1004 {
   1005 	prop_dictionary_t rldict = nt->nrl_dict;
   1006 
   1007 	prop_dictionary_set_int32(rldict, "prio", NPF_PRI_LAST);
   1008 	prop_array_add(ncf->ncf_nat_list, rldict);
   1009 	prop_object_release(rldict);
   1010 	return 0;
   1011 }
   1012 
   1013 nl_nat_t *
   1014 npf_nat_iterate(nl_config_t *ncf)
   1015 {
   1016 	u_int level;
   1017 	return _npf_rule_iterate1(ncf, ncf->ncf_nat_list, &level);
   1018 }
   1019 
   1020 int
   1021 npf_nat_setalgo(nl_nat_t *nt, u_int algo)
   1022 {
   1023 	prop_dictionary_t rldict = nt->nrl_dict;
   1024 	prop_dictionary_set_uint32(rldict, "nat-algo", algo);
   1025 	return 0;
   1026 }
   1027 
   1028 int
   1029 npf_nat_setnpt66(nl_nat_t *nt, uint16_t adj)
   1030 {
   1031 	prop_dictionary_t rldict = nt->nrl_dict;
   1032 	int error;
   1033 
   1034 	if ((error = npf_nat_setalgo(nt, NPF_ALGO_NPT66)) != 0) {
   1035 		return error;
   1036 	}
   1037 	prop_dictionary_set_uint16(rldict, "npt66-adj", adj);
   1038 	return 0;
   1039 }
   1040 
   1041 int
   1042 npf_nat_gettype(nl_nat_t *nt)
   1043 {
   1044 	prop_dictionary_t rldict = nt->nrl_dict;
   1045 	int type = 0;
   1046 
   1047 	prop_dictionary_get_int32(rldict, "type", &type);
   1048 	return type;
   1049 }
   1050 
   1051 u_int
   1052 npf_nat_getflags(nl_nat_t *nt)
   1053 {
   1054 	prop_dictionary_t rldict = nt->nrl_dict;
   1055 	unsigned flags = 0;
   1056 
   1057 	prop_dictionary_get_uint32(rldict, "flags", &flags);
   1058 	return flags;
   1059 }
   1060 
   1061 void
   1062 npf_nat_getmap(nl_nat_t *nt, npf_addr_t *addr, size_t *alen, in_port_t *port)
   1063 {
   1064 	prop_dictionary_t rldict = nt->nrl_dict;
   1065 	prop_object_t obj = prop_dictionary_get(rldict, "nat-ip");
   1066 
   1067 	*alen = prop_data_size(obj);
   1068 	memcpy(addr, prop_data_data_nocopy(obj), *alen);
   1069 
   1070 	*port = 0;
   1071 	prop_dictionary_get_uint16(rldict, "nat-port", port);
   1072 }
   1073 
   1074 /*
   1075  * TABLE INTERFACE.
   1076  */
   1077 
   1078 nl_table_t *
   1079 npf_table_create(const char *name, u_int id, int type)
   1080 {
   1081 	prop_dictionary_t tldict;
   1082 	prop_array_t tblents;
   1083 	nl_table_t *tl;
   1084 
   1085 	tl = malloc(sizeof(*tl));
   1086 	if (tl == NULL) {
   1087 		return NULL;
   1088 	}
   1089 	tldict = prop_dictionary_create();
   1090 	if (tldict == NULL) {
   1091 		free(tl);
   1092 		return NULL;
   1093 	}
   1094 	prop_dictionary_set_cstring(tldict, "name", name);
   1095 	prop_dictionary_set_uint64(tldict, "id", (uint64_t)id);
   1096 	prop_dictionary_set_int32(tldict, "type", type);
   1097 
   1098 	tblents = prop_array_create();
   1099 	if (tblents == NULL) {
   1100 		prop_object_release(tldict);
   1101 		free(tl);
   1102 		return NULL;
   1103 	}
   1104 	prop_dictionary_set(tldict, "entries", tblents);
   1105 	prop_object_release(tblents);
   1106 
   1107 	tl->ntl_dict = tldict;
   1108 	return tl;
   1109 }
   1110 
   1111 int
   1112 npf_table_add_entry(nl_table_t *tl, int af, const npf_addr_t *addr,
   1113     const npf_netmask_t mask)
   1114 {
   1115 	prop_dictionary_t tldict = tl->ntl_dict, entdict;
   1116 	prop_array_t tblents;
   1117 
   1118 	/* Create the table entry. */
   1119 	entdict = prop_dictionary_create();
   1120 	if (entdict == NULL) {
   1121 		return ENOMEM;
   1122 	}
   1123 
   1124 	if (!_npf_add_addr(entdict, "addr", af, addr)) {
   1125 		return EINVAL;
   1126 	}
   1127 	prop_dictionary_set_uint8(entdict, "mask", mask);
   1128 
   1129 	tblents = prop_dictionary_get(tldict, "entries");
   1130 	prop_array_add(tblents, entdict);
   1131 	prop_object_release(entdict);
   1132 	return 0;
   1133 }
   1134 
   1135 int
   1136 npf_table_setdata(nl_table_t *tl, const void *blob, size_t len)
   1137 {
   1138 	prop_dictionary_t tldict = tl->ntl_dict;
   1139 	prop_data_t bobj;
   1140 
   1141 	if ((bobj = prop_data_create_data(blob, len)) == NULL) {
   1142 		return ENOMEM;
   1143 	}
   1144 	prop_dictionary_set(tldict, "data", bobj);
   1145 	prop_object_release(bobj);
   1146 	return 0;
   1147 }
   1148 
   1149 static bool
   1150 _npf_table_exists_p(nl_config_t *ncf, const char *name)
   1151 {
   1152 	prop_dictionary_t tldict;
   1153 	prop_object_iterator_t it;
   1154 
   1155 	it = prop_array_iterator(ncf->ncf_table_list);
   1156 	while ((tldict = prop_object_iterator_next(it)) != NULL) {
   1157 		const char *tname = NULL;
   1158 
   1159 		if (prop_dictionary_get_cstring_nocopy(tldict, "name", &tname)
   1160 		    && strcmp(tname, name) == 0)
   1161 			break;
   1162 	}
   1163 	prop_object_iterator_release(it);
   1164 	return tldict ? true : false;
   1165 }
   1166 
   1167 int
   1168 npf_table_insert(nl_config_t *ncf, nl_table_t *tl)
   1169 {
   1170 	prop_dictionary_t tldict = tl->ntl_dict;
   1171 	const char *name = NULL;
   1172 
   1173 	if (!prop_dictionary_get_cstring_nocopy(tldict, "name", &name)) {
   1174 		return EINVAL;
   1175 	}
   1176 	if (_npf_table_exists_p(ncf, name)) {
   1177 		return EEXIST;
   1178 	}
   1179 	prop_array_add(ncf->ncf_table_list, tldict);
   1180 	prop_object_release(tldict);
   1181 	return 0;
   1182 }
   1183 
   1184 nl_table_t *
   1185 npf_table_iterate(nl_config_t *ncf)
   1186 {
   1187 	prop_dictionary_t tldict;
   1188 
   1189 	if (!ncf->ncf_table_iter) {
   1190 		/* Initialise the iterator. */
   1191 		ncf->ncf_table_iter = prop_array_iterator(ncf->ncf_table_list);
   1192 	}
   1193 	tldict = prop_object_iterator_next(ncf->ncf_table_iter);
   1194 	if ((ncf->ncf_cur_table.ntl_dict = tldict) == NULL) {
   1195 		prop_object_iterator_release(ncf->ncf_table_iter);
   1196 		ncf->ncf_table_iter = NULL;
   1197 		return NULL;
   1198 	}
   1199 	return &ncf->ncf_cur_table;
   1200 }
   1201 
   1202 unsigned
   1203 npf_table_getid(nl_table_t *tl)
   1204 {
   1205 	prop_dictionary_t tldict = tl->ntl_dict;
   1206 	uint64_t id = (uint64_t)-1;
   1207 
   1208 	prop_dictionary_get_uint64(tldict, "id", &id);
   1209 	return (unsigned)id;
   1210 }
   1211 
   1212 const char *
   1213 npf_table_getname(nl_table_t *tl)
   1214 {
   1215 	prop_dictionary_t tldict = tl->ntl_dict;
   1216 	const char *tname = NULL;
   1217 
   1218 	prop_dictionary_get_cstring_nocopy(tldict, "name", &tname);
   1219 	return tname;
   1220 }
   1221 
   1222 int
   1223 npf_table_gettype(nl_table_t *tl)
   1224 {
   1225 	prop_dictionary_t tldict = tl->ntl_dict;
   1226 	int type = 0;
   1227 
   1228 	prop_dictionary_get_int32(tldict, "type", &type);
   1229 	return type;
   1230 }
   1231 
   1232 void
   1233 npf_table_destroy(nl_table_t *tl)
   1234 {
   1235 	prop_object_release(tl->ntl_dict);
   1236 	free(tl);
   1237 }
   1238 
   1239 /*
   1240  * ALG INTERFACE.
   1241  */
   1242 
   1243 int
   1244 _npf_alg_load(nl_config_t *ncf, const char *name)
   1245 {
   1246 	prop_dictionary_t al_dict;
   1247 
   1248 	if (_npf_prop_array_lookup(ncf->ncf_alg_list, "name", name))
   1249 		return EEXIST;
   1250 
   1251 	al_dict = prop_dictionary_create();
   1252 	prop_dictionary_set_cstring(al_dict, "name", name);
   1253 	prop_array_add(ncf->ncf_alg_list, al_dict);
   1254 	prop_object_release(al_dict);
   1255 	return 0;
   1256 }
   1257 
   1258 int
   1259 _npf_alg_unload(nl_config_t *ncf, const char *name)
   1260 {
   1261 	if (!_npf_prop_array_lookup(ncf->ncf_alg_list, "name", name))
   1262 		return ENOENT;
   1263 
   1264 	// Not yet: prop_array_add(ncf->ncf_alg_list, al_dict);
   1265 	return ENOTSUP;
   1266 }
   1267 
   1268 /*
   1269  * MISC.
   1270  */
   1271 
   1272 static prop_dictionary_t
   1273 _npf_debug_initonce(nl_config_t *ncf)
   1274 {
   1275 	if (!ncf->ncf_debug) {
   1276 		prop_array_t iflist = prop_array_create();
   1277 		ncf->ncf_debug = prop_dictionary_create();
   1278 		prop_dictionary_set(ncf->ncf_debug, "interfaces", iflist);
   1279 		prop_object_release(iflist);
   1280 	}
   1281 	return ncf->ncf_debug;
   1282 }
   1283 
   1284 void
   1285 _npf_debug_addif(nl_config_t *ncf, const char *ifname)
   1286 {
   1287 	prop_dictionary_t ifdict, dbg = _npf_debug_initonce(ncf);
   1288 	prop_array_t iflist = prop_dictionary_get(dbg, "interfaces");
   1289 	u_int if_idx = if_nametoindex(ifname);
   1290 
   1291 	if (_npf_prop_array_lookup(iflist, "name", ifname)) {
   1292 		return;
   1293 	}
   1294 	ifdict = prop_dictionary_create();
   1295 	prop_dictionary_set_cstring(ifdict, "name", ifname);
   1296 	prop_dictionary_set_uint32(ifdict, "index", if_idx);
   1297 	prop_array_add(iflist, ifdict);
   1298 	prop_object_release(ifdict);
   1299 }
   1300 
   1301 int
   1302 npf_nat_lookup(int fd, int af, npf_addr_t *addr[2], in_port_t port[2],
   1303     int proto, int dir)
   1304 {
   1305 	prop_dictionary_t conn_dict, conn_res = NULL;
   1306 	int error = EINVAL;
   1307 
   1308 	conn_dict = prop_dictionary_create();
   1309 	if (conn_dict == NULL)
   1310 		return ENOMEM;
   1311 
   1312 	if (!prop_dictionary_set_uint16(conn_dict, "direction", dir))
   1313 		goto out;
   1314 
   1315 	conn_res = prop_dictionary_create();
   1316 	if (conn_res == NULL)
   1317 		goto out;
   1318 
   1319 	if (!_npf_add_addr(conn_res, "saddr", af, addr[0]))
   1320 		goto out;
   1321 	if (!_npf_add_addr(conn_res, "daddr", af, addr[1]))
   1322 		goto out;
   1323 	if (!prop_dictionary_set_uint16(conn_res, "sport", port[0]))
   1324 		goto out;
   1325 	if (!prop_dictionary_set_uint16(conn_res, "dport", port[1]))
   1326 		goto out;
   1327 	if (!prop_dictionary_set_uint16(conn_res, "proto", proto))
   1328 		goto out;
   1329 	if (!prop_dictionary_set(conn_dict, "key", conn_res))
   1330 		goto out;
   1331 
   1332 	prop_object_release(conn_res);
   1333 	conn_res = NULL;
   1334 
   1335 #if !defined(_NPF_STANDALONE)
   1336 	error = prop_dictionary_sendrecv_ioctl(conn_dict, fd,
   1337 	    IOC_NPF_CONN_LOOKUP, &conn_res);
   1338 #else
   1339 	error = ENOTSUP;
   1340 #endif
   1341 	if (error != 0)
   1342 		goto out;
   1343 
   1344 	prop_dictionary_t nat = prop_dictionary_get(conn_res, "nat");
   1345 	if (nat == NULL) {
   1346 		errno = ENOENT;
   1347 		goto out;
   1348 	}
   1349 
   1350 	if (!_npf_get_addr(nat, "oaddr", addr[0])) {
   1351 		error = EINVAL;
   1352 		goto out;
   1353 	}
   1354 
   1355 	prop_dictionary_get_uint16(nat, "oport", &port[0]);
   1356 	prop_dictionary_get_uint16(nat, "tport", &port[1]);
   1357 out:
   1358 	if (conn_res)
   1359 		prop_object_release(conn_res);
   1360 	prop_object_release(conn_dict);
   1361 	return error;
   1362 }
   1363 
   1364 struct npf_endpoint {
   1365 	npf_addr_t addr[2];
   1366 	in_port_t port[2];
   1367 	uint16_t alen;
   1368 	uint16_t proto;
   1369 };
   1370 
   1371 static bool
   1372 npf_endpoint_load(prop_dictionary_t cdict, const char *name,
   1373     struct npf_endpoint *ep)
   1374 {
   1375 	prop_dictionary_t ed = prop_dictionary_get(cdict, name);
   1376 	if (ed == NULL)
   1377 		return false;
   1378 	if (!(ep->alen = _npf_get_addr(ed, "saddr", &ep->addr[0])))
   1379 		return false;
   1380 	if (ep->alen != _npf_get_addr(ed, "daddr", &ep->addr[1]))
   1381 		return false;
   1382 	if (!prop_dictionary_get_uint16(ed, "sport", &ep->port[0]))
   1383 		return false;
   1384 	if (!prop_dictionary_get_uint16(ed, "dport", &ep->port[1]))
   1385 		return false;
   1386 	if (!prop_dictionary_get_uint16(ed, "proto", &ep->proto))
   1387 		return false;
   1388 	return true;
   1389 }
   1390 
   1391 static void
   1392 npf_conn_handle(prop_dictionary_t cdict, npf_conn_func_t fun, void *v)
   1393 {
   1394 	prop_dictionary_t nat;
   1395 	struct npf_endpoint ep;
   1396 	uint16_t tport;
   1397 	const char *ifname;
   1398 
   1399 	if (!prop_dictionary_get_cstring_nocopy(cdict, "ifname", &ifname))
   1400 		goto err;
   1401 
   1402 	if ((nat = prop_dictionary_get(cdict, "nat")) != NULL &&
   1403 	    prop_object_type(nat) == PROP_TYPE_DICTIONARY) {
   1404 		if (!prop_dictionary_get_uint16(nat, "tport", &tport))
   1405 			goto err;
   1406 	} else {
   1407 		tport = 0;
   1408 	}
   1409 	if (!npf_endpoint_load(cdict, "forw-key", &ep))
   1410 		goto err;
   1411 
   1412 	in_port_t p[] = {
   1413 	    ntohs(ep.port[0]),
   1414 	    ntohs(ep.port[1]),
   1415 	    ntohs(tport)
   1416 	};
   1417 	(*fun)((unsigned)ep.alen, ep.addr, p, ifname, v);
   1418 err:
   1419 	return;
   1420 }
   1421 
   1422 int
   1423 npf_conn_list(int fd, npf_conn_func_t fun, void *v)
   1424 {
   1425 	nl_config_t *ncf;
   1426 
   1427 	ncf = npf_config_retrieve(fd);
   1428 	if (ncf == NULL) {
   1429 		return errno;
   1430 	}
   1431 
   1432 	/* Connection list - array */
   1433 	if (prop_object_type(ncf->ncf_conn_list) != PROP_TYPE_ARRAY) {
   1434 		return EINVAL;
   1435 	}
   1436 
   1437 	prop_object_iterator_t it = prop_array_iterator(ncf->ncf_conn_list);
   1438 	prop_dictionary_t condict;
   1439 	while ((condict = prop_object_iterator_next(it)) != NULL) {
   1440 		if (prop_object_type(condict) != PROP_TYPE_DICTIONARY) {
   1441 			return EINVAL;
   1442 		}
   1443 		npf_conn_handle(condict, fun, v);
   1444 	}
   1445 	return 0;
   1446 }
   1447