? lib/libnpf/o ? lib/libnpf/x ? usr.sbin/npf/npftest/libnpftest/npf_stand.h Index: lib/libnpf/npf.c =================================================================== RCS file: /cvsroot/src/lib/libnpf/npf.c,v retrieving revision 1.40 diff -u -u -r1.40 npf.c --- lib/libnpf/npf.c 26 Dec 2016 23:05:05 -0000 1.40 +++ lib/libnpf/npf.c 27 Dec 2016 19:34:47 -0000 @@ -122,7 +122,7 @@ return true; } -static bool +static unsigned _npf_get_addr(prop_dictionary_t dict, const char *name, npf_addr_t *addr) { prop_object_t obj = prop_dictionary_get(dict, name); @@ -136,9 +136,9 @@ case sizeof(struct in_addr): case sizeof(struct in6_addr): memcpy(addr, d, sz); - return true; + return (unsigned)sz; default: - return false; + return 0; } } @@ -1359,3 +1359,108 @@ prop_object_release(conn_dict); return error; } + +struct npf_conn { + uint32_t proto; + uint32_t flags; + const char *ifname; + struct npf_endpoint { + npf_addr_t addr[2]; + in_port_t port[2]; + uint16_t alen; + uint16_t proto; + } ep[2]; + struct npf_nat { + npf_addr_t oaddr; + in_port_t oport; + in_port_t tport; + } nat; +}; + +static bool +npf_endpoint_load(prop_dictionary_t cdict, const char *name, + struct npf_endpoint *ep) +{ + prop_dictionary_t ed = prop_dictionary_get(cdict, name); + if (ed == NULL) + return false; + if (!(ep->alen = _npf_get_addr(ed, "saddr", &ep->addr[0]))) + return false; + if (ep->alen != _npf_get_addr(ed, "daddr", &ep->addr[1])) + return false; + if (!prop_dictionary_get_uint16(ed, "sport", &ep->port[0])) + return false; + if (!prop_dictionary_get_uint16(ed, "dport", &ep->port[1])) + return false; + if (!prop_dictionary_get_uint16(ed, "proto", &ep->proto)) + return false; + return true; +} + +static void +npf_conn_handle(prop_dictionary_t cdict, npf_conn_func_t fun, void *v) +{ + prop_dictionary_t nat; + struct npf_conn c; + + prop_dictionary_get_uint32(cdict, "proto", &c.proto); + prop_dictionary_get_uint32(cdict, "flags", &c.flags); + prop_dictionary_get_cstring_nocopy(cdict, "ifname", &c.ifname); +#ifdef notyet + obj = prop_dictionary_get(cdict, "state"); + if ((d = prop_data_data_nocopy(obj)) == NULL || + prop_data_size(obj) != sizeof(npf_state_t)) { + goto err; + } + memcpy(&con->c_state, d, sizeof(npf_state_t)); +#endif + + if ((nat = prop_dictionary_get(cdict, "nat")) != NULL && + prop_object_type(nat) == PROP_TYPE_DICTIONARY) { + if (!_npf_get_addr(nat, "oaddr", &c.nat.oaddr)) + goto err; + prop_dictionary_get_uint16(nat, "oport", &c.nat.oport); + prop_dictionary_get_uint16(nat, "tport", &c.nat.tport); + } else { + c.nat.tport = c.nat.oport = 0; + } + if (!npf_endpoint_load(cdict, "forw-key", &c.ep[0])) + goto err; + + if (!npf_endpoint_load(cdict, "back-key", &c.ep[1])) + goto err; + in_port_t p[] = { + ntohs(c.ep[0].port[0]), + ntohs(c.ep[0].port[1]), + ntohs(c.nat.tport) + }; + (*fun)((unsigned)c.ep[0].alen, c.ep[0].addr, p, c.ifname, v); +err: + return; +} + +int +npf_conn_list(int fd, npf_conn_func_t fun, void *v) +{ + nl_config_t *ncf; + + ncf = npf_config_retrieve(fd); + if (ncf == NULL) { + return errno; + } + + /* Connection list - array */ + if (prop_object_type(ncf->ncf_conn_list) != PROP_TYPE_ARRAY) { + return EINVAL; + } + + prop_object_iterator_t it = prop_array_iterator(ncf->ncf_conn_list); + prop_dictionary_t condict; + while ((condict = prop_object_iterator_next(it)) != NULL) { + if (prop_object_type(condict) != PROP_TYPE_DICTIONARY) { + return EINVAL; + } + npf_conn_handle(condict, fun, v); + } + return 0; +} Index: lib/libnpf/npf.h =================================================================== RCS file: /cvsroot/src/lib/libnpf/npf.h,v retrieving revision 1.31 diff -u -u -r1.31 npf.h --- lib/libnpf/npf.h 26 Dec 2016 23:05:05 -0000 1.31 +++ lib/libnpf/npf.h 27 Dec 2016 19:34:47 -0000 @@ -150,6 +150,11 @@ int _npf_alg_load(nl_config_t *, const char *); int _npf_alg_unload(nl_config_t *, const char *); +/* utils */ +typedef int (*npf_conn_func_t)(unsigned, const npf_addr_t *, const in_port_t *, + const char *, void *); +int npf_conn_list(int, npf_conn_func_t, void *); + #endif __END_DECLS Index: usr.sbin/npf/npfctl/npf_show.c =================================================================== RCS file: /cvsroot/src/usr.sbin/npf/npfctl/npf_show.c,v retrieving revision 1.20 diff -u -u -r1.20 npf_show.c --- usr.sbin/npf/npfctl/npf_show.c 26 Dec 2016 23:05:05 -0000 1.20 +++ usr.sbin/npf/npfctl/npf_show.c 27 Dec 2016 19:34:47 -0000 @@ -153,7 +153,7 @@ errx(EXIT_FAILURE, "invalid byte-code mark (address)"); } addr = (const npf_addr_t *)words; - return npfctl_print_addrmask(alen, addr, mask); + return npfctl_print_addrmask(alen, "%a", addr, mask); } static char * @@ -437,7 +437,7 @@ /* Get the translation address (and port, if used). */ npf_nat_getmap(nt, &addr, &alen, &port); - seg = npfctl_print_addrmask(alen, &addr, NPF_NO_NETMASK); + seg = npfctl_print_addrmask(alen, "%a", &addr, NPF_NO_NETMASK); if (port) { char *p; easprintf(&p, "%s port %u", seg, ntohs(port)); Index: usr.sbin/npf/npfctl/npfctl.c =================================================================== RCS file: /cvsroot/src/usr.sbin/npf/npfctl/npfctl.c,v retrieving revision 1.49 diff -u -u -r1.49 npfctl.c --- usr.sbin/npf/npfctl/npfctl.c 27 Dec 2016 13:43:38 -0000 1.49 +++ usr.sbin/npf/npfctl/npfctl.c 27 Dec 2016 19:34:47 -0000 @@ -70,6 +70,7 @@ NPFCTL_STATS, NPFCTL_SAVE, NPFCTL_LOAD, + NPFCTL_CONN_LIST, }; static const struct operations_s { @@ -92,6 +93,7 @@ /* Full state save/load */ { "save", NPFCTL_SAVE }, { "load", NPFCTL_LOAD }, + { "list", NPFCTL_CONN_LIST }, /* --- */ { NULL, 0 } }; @@ -147,6 +149,9 @@ fprintf(stderr, "\t%s save | load\n", progname); + fprintf(stderr, + "\t%s list [-46hnNw] [-i ]\n", + progname); exit(EXIT_FAILURE); } @@ -230,9 +235,10 @@ } char * -npfctl_print_addrmask(int alen, const npf_addr_t *addr, npf_netmask_t mask) +npfctl_print_addrmask(int alen, const char *fmt, const npf_addr_t *addr, + npf_netmask_t mask) { - const unsigned buflen = 64; + const unsigned buflen = 256; char *buf = ecalloc(1, buflen); struct sockaddr_storage ss; @@ -241,12 +247,14 @@ switch (alen) { case 4: { struct sockaddr_in *sin = (void *)&ss; + sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; memcpy(&sin->sin_addr, addr, sizeof(sin->sin_addr)); break; } case 16: { struct sockaddr_in6 *sin6 = (void *)&ss; + sin6->sin6_len = sizeof(*sin6); sin6->sin6_family = AF_INET6; memcpy(&sin6->sin6_addr, addr, sizeof(sin6->sin6_addr)); break; @@ -254,7 +262,7 @@ default: assert(false); } - inet_ntop(ss.ss_family, (const void *)&ss, buf, buflen); + sockaddr_snprintf(buf, buflen, fmt, (const void *)&ss); if (mask && mask != NPF_NO_NETMASK) { const unsigned len = strlen(buf); snprintf(&buf[len], buflen - len, "/%u", mask); @@ -359,7 +367,7 @@ while (nct.nct_data.buf.len--) { if (!ent->alen) break; - buf = npfctl_print_addrmask(ent->alen, + buf = npfctl_print_addrmask(ent->alen, "%a", &ent->addr, ent->mask); puts(buf); ent++; @@ -574,6 +582,103 @@ return error; } +struct npf_conn_filter { + uint16_t alen; + const char *ifname; + bool nat; + bool wide; + bool name; + int width; + FILE *fp; +}; + +static int +npfctl_conn_print(unsigned alen, const npf_addr_t *a, const in_port_t *p, + const char *ifname, void *v) +{ + struct npf_conn_filter *fil = v; + FILE *fp = fil->fp; + char *src, *dst; + + if (fil->ifname && strcmp(ifname, fil->ifname) != 0) + return 0; + if (fil->alen && alen != fil->alen) + return 0; + if (fil->nat && !p[2]) + return 0; + + int w = fil->width; + const char *fmt = fil->name ? "%A" : + (alen == sizeof(struct in_addr) ? "%a" : "[%a]"); + src = npfctl_print_addrmask(alen, fmt, &a[0], NPF_NO_NETMASK); + dst = npfctl_print_addrmask(alen, fmt, &a[1], NPF_NO_NETMASK); + if (fil->wide) + fprintf(fp, "%s:%d %s:%d", src, p[0], dst, p[1]); + else + fprintf(fp, "%*.*s:%-5d %*.*s:%-5d", w, w, src, p[0], + w, w, dst, p[1]); + free(src); + free(dst); + if (!p[2]) { + fputc('\n', fp); + return 1; + } + fprintf(fp, " via %s:%d\n", ifname, ntohs(p[2])); + return 1; +} + + +static int +npfctl_conn_list(int fd, int argc, char **argv) +{ + struct npf_conn_filter f; + int c; + int header = true; + memset(&f, 0, sizeof(f)); + + argc--; + argv++; + + while ((c = getopt(argc, argv, "46hi:nNw")) != -1) { + switch (c) { + case '4': + f.alen = sizeof(struct in_addr); + break; + case '6': + f.alen = sizeof(struct in6_addr); + break; + case 'h': + header = false; + case 'i': + f.ifname = optarg; + break; + case 'n': + f.nat = true; + break; + case 'N': + f.name = true; + break; + case 'w': + f.wide = true; + break; + default: + fprintf(stderr, + "Usage: %s list [-46hnNw] [-i ]\n", + getprogname()); + exit(EXIT_FAILURE); + } + } + f.width = f.alen == sizeof(struct in_addr) ? 25 : 41; + int w = f.width + 6; + f.fp = stdout; + if (header) + fprintf(f.fp, "%*.*s %*.*s\n", + w, w, "From address:port ", w, w, "To address:port "); + + npf_conn_list(fd, npfctl_conn_print, &f); + return 0; +} + static void npfctl(int action, int argc, char **argv) { @@ -659,6 +764,10 @@ ret = npfctl_print_stats(fd); fun = "npfctl_print_stats"; break; + case NPFCTL_CONN_LIST: + ret = npfctl_conn_list(fd, argc, argv); + fun = "npfctl_conn_list"; + break; } if (ret) { err(EXIT_FAILURE, "%s", fun); Index: usr.sbin/npf/npfctl/npfctl.h =================================================================== RCS file: /cvsroot/src/usr.sbin/npf/npfctl/npfctl.h,v retrieving revision 1.40 diff -u -u -r1.40 npfctl.h --- usr.sbin/npf/npfctl/npfctl.h 26 Dec 2016 23:05:05 -0000 1.40 +++ usr.sbin/npf/npfctl/npfctl.h 27 Dec 2016 19:34:47 -0000 @@ -111,7 +111,8 @@ void npfctl_parse_string(const char *); void npfctl_print_error(const npf_error_t *); -char * npfctl_print_addrmask(int, const npf_addr_t *, npf_netmask_t); +char * npfctl_print_addrmask(int, const char *, const npf_addr_t *, + npf_netmask_t); void npfctl_note_interface(const char *); unsigned npfctl_table_getid(const char *); int npfctl_protono(const char *);