1 1.1 rmind /*- 2 1.1 rmind * Copyright (c) 2009-2020 The NetBSD Foundation, Inc. 3 1.1 rmind * All rights reserved. 4 1.1 rmind * 5 1.1 rmind * This material is based upon work partially supported by The 6 1.1 rmind * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. 7 1.1 rmind * 8 1.1 rmind * Redistribution and use in source and binary forms, with or without 9 1.1 rmind * modification, are permitted provided that the following conditions 10 1.1 rmind * are met: 11 1.1 rmind * 1. Redistributions of source code must retain the above copyright 12 1.1 rmind * notice, this list of conditions and the following disclaimer. 13 1.1 rmind * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 rmind * notice, this list of conditions and the following disclaimer in the 15 1.1 rmind * documentation and/or other materials provided with the distribution. 16 1.1 rmind * 17 1.1 rmind * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 1.1 rmind * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 1.1 rmind * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 1.1 rmind * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 1.1 rmind * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 1.1 rmind * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 1.1 rmind * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 1.1 rmind * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 1.1 rmind * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 1.1 rmind * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 1.1 rmind * POSSIBILITY OF SUCH DAMAGE. 28 1.1 rmind */ 29 1.1 rmind 30 1.1 rmind #include <sys/cdefs.h> 31 1.1 rmind __RCSID("$NetBSD: npf_cmd.c,v 1.1 2020/05/30 14:16:56 rmind Exp $"); 32 1.1 rmind 33 1.1 rmind #include <stdio.h> 34 1.1 rmind #include <string.h> 35 1.1 rmind #include <stdlib.h> 36 1.1 rmind #include <unistd.h> 37 1.1 rmind #include <errno.h> 38 1.1 rmind #include <err.h> 39 1.1 rmind 40 1.1 rmind #ifdef __NetBSD__ 41 1.1 rmind #include <sha1.h> 42 1.1 rmind #define SHA_DIGEST_LENGTH SHA1_DIGEST_LENGTH 43 1.1 rmind #else 44 1.1 rmind #include <openssl/sha.h> 45 1.1 rmind #endif 46 1.1 rmind 47 1.1 rmind #include "npfctl.h" 48 1.1 rmind 49 1.1 rmind //////////////////////////////////////////////////////////////////////////// 50 1.1 rmind // 51 1.1 rmind // NPFCTL RULE COMMANDS 52 1.1 rmind // 53 1.1 rmind 54 1.1 rmind #ifdef __NetBSD__ 55 1.1 rmind static unsigned char * 56 1.1 rmind SHA1(const unsigned char *d, size_t l, unsigned char *md) 57 1.1 rmind { 58 1.1 rmind SHA1_CTX c; 59 1.1 rmind 60 1.1 rmind SHA1Init(&c); 61 1.1 rmind SHA1Update(&c, d, l); 62 1.1 rmind SHA1Final(md, &c); 63 1.1 rmind return md; 64 1.1 rmind } 65 1.1 rmind #endif 66 1.1 rmind 67 1.1 rmind static void 68 1.1 rmind npfctl_generate_key(nl_rule_t *rl, void *key) 69 1.1 rmind { 70 1.1 rmind void *meta; 71 1.1 rmind size_t len; 72 1.1 rmind 73 1.1 rmind if ((meta = npf_rule_export(rl, &len)) == NULL) { 74 1.1 rmind errx(EXIT_FAILURE, "error generating rule key"); 75 1.1 rmind } 76 1.1 rmind __CTASSERT(NPF_RULE_MAXKEYLEN >= SHA_DIGEST_LENGTH); 77 1.1 rmind memset(key, 0, NPF_RULE_MAXKEYLEN); 78 1.1 rmind SHA1(meta, len, key); 79 1.1 rmind free(meta); 80 1.1 rmind } 81 1.1 rmind 82 1.1 rmind int 83 1.1 rmind npfctl_nat_ruleset_p(const char *name, bool *natset) 84 1.1 rmind { 85 1.1 rmind const size_t preflen = sizeof(NPF_RULESET_MAP_PREF) - 1; 86 1.1 rmind *natset = strncmp(name, NPF_RULESET_MAP_PREF, preflen) == 0; 87 1.1 rmind return (*natset && strlen(name) <= preflen) ? -1 : 0; 88 1.1 rmind } 89 1.1 rmind 90 1.1 rmind static nl_rule_t * 91 1.1 rmind npfctl_parse_rule(int argc, char **argv, parse_entry_t entry) 92 1.1 rmind { 93 1.1 rmind char rule_string[1024]; 94 1.1 rmind nl_rule_t *rl; 95 1.1 rmind 96 1.1 rmind /* Get the rule string and parse it. */ 97 1.1 rmind if (!join(rule_string, sizeof(rule_string), argc, argv, " ")) { 98 1.1 rmind errx(EXIT_FAILURE, "command too long"); 99 1.1 rmind } 100 1.1 rmind npfctl_parse_string(rule_string, entry); 101 1.1 rmind if ((rl = npfctl_rule_ref()) == NULL) { 102 1.1 rmind errx(EXIT_FAILURE, "could not parse the rule"); 103 1.1 rmind } 104 1.1 rmind return rl; 105 1.1 rmind } 106 1.1 rmind 107 1.1 rmind void 108 1.1 rmind npfctl_rule(int fd, int argc, char **argv) 109 1.1 rmind { 110 1.1 rmind static const struct ruleops_s { 111 1.1 rmind const char * cmd; 112 1.1 rmind int action; 113 1.1 rmind bool extra_arg; 114 1.1 rmind } ruleops[] = { 115 1.1 rmind { "add", NPF_CMD_RULE_ADD, true }, 116 1.1 rmind { "rem", NPF_CMD_RULE_REMKEY, true }, 117 1.1 rmind { "del", NPF_CMD_RULE_REMKEY, true }, 118 1.1 rmind { "rem-id", NPF_CMD_RULE_REMOVE, true }, 119 1.1 rmind { "list", NPF_CMD_RULE_LIST, false }, 120 1.1 rmind { "flush", NPF_CMD_RULE_FLUSH, false }, 121 1.1 rmind { NULL, 0, 0 } 122 1.1 rmind }; 123 1.1 rmind uint8_t key[NPF_RULE_MAXKEYLEN]; 124 1.1 rmind const char *ruleset_name = argv[0]; 125 1.1 rmind const char *cmd = argv[1]; 126 1.1 rmind int error, action = 0; 127 1.1 rmind bool extra_arg, natset; 128 1.1 rmind parse_entry_t entry; 129 1.1 rmind uint64_t rule_id; 130 1.1 rmind nl_rule_t *rl; 131 1.1 rmind 132 1.1 rmind for (unsigned n = 0; ruleops[n].cmd != NULL; n++) { 133 1.1 rmind if (strcmp(cmd, ruleops[n].cmd) == 0) { 134 1.1 rmind action = ruleops[n].action; 135 1.1 rmind extra_arg = ruleops[n].extra_arg; 136 1.1 rmind break; 137 1.1 rmind } 138 1.1 rmind } 139 1.1 rmind argc -= 2; 140 1.1 rmind argv += 2; 141 1.1 rmind 142 1.1 rmind if (!action || (extra_arg && argc == 0)) { 143 1.1 rmind usage(); 144 1.1 rmind } 145 1.1 rmind 146 1.1 rmind if (npfctl_nat_ruleset_p(ruleset_name, &natset) != 0) { 147 1.1 rmind errx(EXIT_FAILURE, 148 1.1 rmind "invalid NAT ruleset name (note: the name must be " 149 1.1 rmind "prefixed with `" NPF_RULESET_MAP_PREF "`)"); 150 1.1 rmind } 151 1.1 rmind entry = natset ? NPFCTL_PARSE_MAP : NPFCTL_PARSE_RULE; 152 1.1 rmind 153 1.1 rmind switch (action) { 154 1.1 rmind case NPF_CMD_RULE_ADD: 155 1.1 rmind rl = npfctl_parse_rule(argc, argv, entry); 156 1.1 rmind npfctl_generate_key(rl, key); 157 1.1 rmind npf_rule_setkey(rl, key, sizeof(key)); 158 1.1 rmind error = npf_ruleset_add(fd, ruleset_name, rl, &rule_id); 159 1.1 rmind break; 160 1.1 rmind case NPF_CMD_RULE_REMKEY: 161 1.1 rmind rl = npfctl_parse_rule(argc, argv, entry); 162 1.1 rmind npfctl_generate_key(rl, key); 163 1.1 rmind error = npf_ruleset_remkey(fd, ruleset_name, key, sizeof(key)); 164 1.1 rmind break; 165 1.1 rmind case NPF_CMD_RULE_REMOVE: 166 1.1 rmind rule_id = strtoull(argv[0], NULL, 16); 167 1.1 rmind error = npf_ruleset_remove(fd, ruleset_name, rule_id); 168 1.1 rmind break; 169 1.1 rmind case NPF_CMD_RULE_LIST: 170 1.1 rmind error = npfctl_ruleset_show(fd, ruleset_name); 171 1.1 rmind break; 172 1.1 rmind case NPF_CMD_RULE_FLUSH: 173 1.1 rmind error = npf_ruleset_flush(fd, ruleset_name); 174 1.1 rmind break; 175 1.1 rmind default: 176 1.1 rmind abort(); 177 1.1 rmind } 178 1.1 rmind 179 1.1 rmind switch (error) { 180 1.1 rmind case 0: 181 1.1 rmind /* Success. */ 182 1.1 rmind break; 183 1.1 rmind case ESRCH: 184 1.1 rmind errx(EXIT_FAILURE, "ruleset \"%s\" not found", ruleset_name); 185 1.1 rmind case ENOENT: 186 1.1 rmind errx(EXIT_FAILURE, "rule was not found"); 187 1.1 rmind default: 188 1.1 rmind errx(EXIT_FAILURE, "rule operation: %s", strerror(error)); 189 1.1 rmind } 190 1.1 rmind if (action == NPF_CMD_RULE_ADD) { 191 1.1 rmind printf("OK %" PRIx64 "\n", rule_id); 192 1.1 rmind } 193 1.1 rmind } 194 1.1 rmind 195 1.1 rmind //////////////////////////////////////////////////////////////////////////// 196 1.1 rmind // 197 1.1 rmind // NPFCTL TABLE COMMANDS 198 1.1 rmind // 199 1.1 rmind 200 1.1 rmind static int 201 1.1 rmind npfctl_table_type(const char *typename) 202 1.1 rmind { 203 1.1 rmind static const struct tbltype_s { 204 1.1 rmind const char * name; 205 1.1 rmind unsigned type; 206 1.1 rmind } tbltypes[] = { 207 1.1 rmind { "ipset", NPF_TABLE_IPSET }, 208 1.1 rmind { "lpm", NPF_TABLE_LPM }, 209 1.1 rmind { "const", NPF_TABLE_CONST }, 210 1.1 rmind { NULL, 0 } 211 1.1 rmind }; 212 1.1 rmind 213 1.1 rmind for (unsigned i = 0; tbltypes[i].name != NULL; i++) { 214 1.1 rmind if (strcmp(typename, tbltypes[i].name) == 0) { 215 1.1 rmind return tbltypes[i].type; 216 1.1 rmind } 217 1.1 rmind } 218 1.1 rmind return 0; 219 1.1 rmind } 220 1.1 rmind 221 1.1 rmind void 222 1.1 rmind npfctl_table_replace(int fd, int argc, char **argv) 223 1.1 rmind { 224 1.1 rmind const char *name, *newname, *path, *typename = NULL; 225 1.1 rmind nl_config_t *ncf; 226 1.1 rmind nl_table_t *t; 227 1.1 rmind unsigned type = 0; 228 1.1 rmind int c, tid = -1; 229 1.1 rmind FILE *fp; 230 1.1 rmind 231 1.1 rmind name = newname = argv[0]; 232 1.1 rmind optind = 2; 233 1.1 rmind while ((c = getopt(argc, argv, "n:t:")) != -1) { 234 1.1 rmind switch (c) { 235 1.1 rmind case 't': 236 1.1 rmind typename = optarg; 237 1.1 rmind break; 238 1.1 rmind case 'n': 239 1.1 rmind newname = optarg; 240 1.1 rmind break; 241 1.1 rmind default: 242 1.1 rmind errx(EXIT_FAILURE, 243 1.1 rmind "Usage: %s table \"table-name\" replace " 244 1.1 rmind "[-n \"name\"] [-t <type>] <table-file>\n", 245 1.1 rmind getprogname()); 246 1.1 rmind } 247 1.1 rmind } 248 1.1 rmind argc -= optind; 249 1.1 rmind argv += optind; 250 1.1 rmind 251 1.1 rmind if (typename && (type = npfctl_table_type(typename)) == 0) { 252 1.1 rmind errx(EXIT_FAILURE, "unsupported table type '%s'", typename); 253 1.1 rmind } 254 1.1 rmind 255 1.1 rmind if (argc != 1) { 256 1.1 rmind usage(); 257 1.1 rmind } 258 1.1 rmind 259 1.1 rmind path = argv[0]; 260 1.1 rmind if (strcmp(path, "-") == 0) { 261 1.1 rmind path = "stdin"; 262 1.1 rmind fp = stdin; 263 1.1 rmind } else if ((fp = fopen(path, "r")) == NULL) { 264 1.1 rmind err(EXIT_FAILURE, "open '%s'", path); 265 1.1 rmind } 266 1.1 rmind 267 1.1 rmind /* Get existing config to lookup ID of existing table */ 268 1.1 rmind if ((ncf = npf_config_retrieve(fd)) == NULL) { 269 1.1 rmind err(EXIT_FAILURE, "npf_config_retrieve()"); 270 1.1 rmind } 271 1.1 rmind if ((t = npfctl_table_getbyname(ncf, name)) == NULL) { 272 1.1 rmind errx(EXIT_FAILURE, 273 1.1 rmind "table '%s' not found in the active configuration", name); 274 1.1 rmind } 275 1.1 rmind tid = npf_table_getid(t); 276 1.1 rmind if (!type) { 277 1.1 rmind type = npf_table_gettype(t); 278 1.1 rmind } 279 1.1 rmind npf_config_destroy(ncf); 280 1.1 rmind 281 1.1 rmind if ((t = npfctl_load_table(newname, tid, type, path, fp)) == NULL) { 282 1.1 rmind err(EXIT_FAILURE, "table load failed"); 283 1.1 rmind } 284 1.1 rmind 285 1.1 rmind if (npf_table_replace(fd, t, NULL)) { 286 1.1 rmind err(EXIT_FAILURE, "npf_table_replace(<%s>)", name); 287 1.1 rmind } 288 1.1 rmind } 289 1.1 rmind 290 1.1 rmind void 291 1.1 rmind npfctl_table(int fd, int argc, char **argv) 292 1.1 rmind { 293 1.1 rmind static const struct tblops_s { 294 1.1 rmind const char * cmd; 295 1.1 rmind int action; 296 1.1 rmind } tblops[] = { 297 1.1 rmind { "add", NPF_CMD_TABLE_ADD }, 298 1.1 rmind { "rem", NPF_CMD_TABLE_REMOVE }, 299 1.1 rmind { "del", NPF_CMD_TABLE_REMOVE }, 300 1.1 rmind { "test", NPF_CMD_TABLE_LOOKUP }, 301 1.1 rmind { "list", NPF_CMD_TABLE_LIST }, 302 1.1 rmind { "flush", NPF_CMD_TABLE_FLUSH }, 303 1.1 rmind { NULL, 0 } 304 1.1 rmind }; 305 1.1 rmind npf_ioctl_table_t nct; 306 1.1 rmind fam_addr_mask_t fam; 307 1.1 rmind size_t buflen = 512; 308 1.1 rmind char *cmd, *arg; 309 1.1 rmind int n, alen; 310 1.1 rmind 311 1.1 rmind /* Default action is list. */ 312 1.1 rmind memset(&nct, 0, sizeof(npf_ioctl_table_t)); 313 1.1 rmind nct.nct_name = argv[0]; 314 1.1 rmind cmd = argv[1]; 315 1.1 rmind 316 1.1 rmind for (n = 0; tblops[n].cmd != NULL; n++) { 317 1.1 rmind if (strcmp(cmd, tblops[n].cmd) != 0) { 318 1.1 rmind continue; 319 1.1 rmind } 320 1.1 rmind nct.nct_cmd = tblops[n].action; 321 1.1 rmind break; 322 1.1 rmind } 323 1.1 rmind if (tblops[n].cmd == NULL) { 324 1.1 rmind errx(EXIT_FAILURE, "invalid command '%s'", cmd); 325 1.1 rmind } 326 1.1 rmind 327 1.1 rmind switch (nct.nct_cmd) { 328 1.1 rmind case NPF_CMD_TABLE_LIST: 329 1.1 rmind case NPF_CMD_TABLE_FLUSH: 330 1.1 rmind arg = NULL; 331 1.1 rmind break; 332 1.1 rmind default: 333 1.1 rmind if (argc < 3) { 334 1.1 rmind usage(); 335 1.1 rmind } 336 1.1 rmind arg = argv[2]; 337 1.1 rmind } 338 1.1 rmind 339 1.1 rmind again: 340 1.1 rmind switch (nct.nct_cmd) { 341 1.1 rmind case NPF_CMD_TABLE_LIST: 342 1.1 rmind nct.nct_data.buf.buf = ecalloc(1, buflen); 343 1.1 rmind nct.nct_data.buf.len = buflen; 344 1.1 rmind break; 345 1.1 rmind case NPF_CMD_TABLE_FLUSH: 346 1.1 rmind break; 347 1.1 rmind default: 348 1.1 rmind if (!npfctl_parse_cidr(arg, &fam, &alen)) { 349 1.1 rmind errx(EXIT_FAILURE, "invalid CIDR '%s'", arg); 350 1.1 rmind } 351 1.1 rmind nct.nct_data.ent.alen = alen; 352 1.1 rmind memcpy(&nct.nct_data.ent.addr, &fam.fam_addr, alen); 353 1.1 rmind nct.nct_data.ent.mask = fam.fam_mask; 354 1.1 rmind } 355 1.1 rmind 356 1.1 rmind if (ioctl(fd, IOC_NPF_TABLE, &nct) != -1) { 357 1.1 rmind errno = 0; 358 1.1 rmind } 359 1.1 rmind switch (errno) { 360 1.1 rmind case 0: 361 1.1 rmind break; 362 1.1 rmind case EEXIST: 363 1.1 rmind errx(EXIT_FAILURE, "entry already exists or is conflicting"); 364 1.1 rmind case ENOENT: 365 1.1 rmind errx(EXIT_FAILURE, "not found"); 366 1.1 rmind case EINVAL: 367 1.1 rmind errx(EXIT_FAILURE, "invalid address, mask or table ID"); 368 1.1 rmind case ENOMEM: 369 1.1 rmind if (nct.nct_cmd == NPF_CMD_TABLE_LIST) { 370 1.1 rmind /* XXX */ 371 1.1 rmind free(nct.nct_data.buf.buf); 372 1.1 rmind buflen <<= 1; 373 1.1 rmind goto again; 374 1.1 rmind } 375 1.1 rmind /* FALLTHROUGH */ 376 1.1 rmind default: 377 1.1 rmind err(EXIT_FAILURE, "ioctl(IOC_NPF_TABLE)"); 378 1.1 rmind } 379 1.1 rmind 380 1.1 rmind if (nct.nct_cmd == NPF_CMD_TABLE_LIST) { 381 1.1 rmind npf_ioctl_ent_t *ent = nct.nct_data.buf.buf; 382 1.1 rmind char *buf; 383 1.1 rmind 384 1.1 rmind while (nct.nct_data.buf.len--) { 385 1.1 rmind if (!ent->alen) 386 1.1 rmind break; 387 1.1 rmind buf = npfctl_print_addrmask(ent->alen, "%a", 388 1.1 rmind &ent->addr, ent->mask); 389 1.1 rmind puts(buf); 390 1.1 rmind ent++; 391 1.1 rmind } 392 1.1 rmind free(nct.nct_data.buf.buf); 393 1.1 rmind } else { 394 1.1 rmind printf("%s: %s\n", getprogname(), 395 1.1 rmind nct.nct_cmd == NPF_CMD_TABLE_LOOKUP ? 396 1.1 rmind "match" : "success"); 397 1.1 rmind } 398 1.1 rmind } 399 1.1 rmind 400 1.1 rmind //////////////////////////////////////////////////////////////////////////// 401 1.1 rmind // 402 1.1 rmind // NPFCTL CONNECTION COMMANDS 403 1.1 rmind // 404 1.1 rmind 405 1.1 rmind typedef struct { 406 1.1 rmind FILE * fp; 407 1.1 rmind unsigned alen; 408 1.1 rmind const char * ifname; 409 1.1 rmind bool nat; 410 1.1 rmind bool nowide; 411 1.1 rmind bool name; 412 1.1 rmind 413 1.1 rmind bool v4; 414 1.1 rmind unsigned pwidth; 415 1.1 rmind } npf_conn_filter_t; 416 1.1 rmind 417 1.1 rmind static int 418 1.1 rmind npfctl_conn_print(unsigned alen, const npf_addr_t *a, const in_port_t *p, 419 1.1 rmind const char *ifname, void *arg) 420 1.1 rmind { 421 1.1 rmind const npf_conn_filter_t *fil = arg; 422 1.1 rmind char *addrstr, *src, *dst; 423 1.1 rmind const char *fmt; 424 1.1 rmind FILE *fp = fil->fp; 425 1.1 rmind bool nat_conn; 426 1.1 rmind 427 1.1 rmind /* 428 1.1 rmind * Filter connection entries by IP version, interface and/or 429 1.1 rmind * applicability of NAT. 430 1.1 rmind */ 431 1.1 rmind if (alen != fil->alen) { 432 1.1 rmind return 0; 433 1.1 rmind } 434 1.1 rmind if (fil->ifname && (!ifname || strcmp(ifname, fil->ifname) != 0)) { 435 1.1 rmind return 0; 436 1.1 rmind } 437 1.1 rmind nat_conn = !npfctl_addr_iszero(&a[2]) || p[2] != 0; 438 1.1 rmind if (fil->nat && !nat_conn) { 439 1.1 rmind return 0; 440 1.1 rmind } 441 1.1 rmind 442 1.1 rmind fmt = fil->name ? "%A" : (fil->v4 ? "%a" : "[%a]"); 443 1.1 rmind 444 1.1 rmind addrstr = npfctl_print_addrmask(alen, fmt, &a[0], NPF_NO_NETMASK); 445 1.1 rmind easprintf(&src, "%s:%d", addrstr, p[0]); 446 1.1 rmind free(addrstr); 447 1.1 rmind 448 1.1 rmind addrstr = npfctl_print_addrmask(alen, fmt, &a[1], NPF_NO_NETMASK); 449 1.1 rmind easprintf(&dst, "%s:%d", addrstr, p[1]); 450 1.1 rmind free(addrstr); 451 1.1 rmind 452 1.1 rmind fprintf(fp, "%-*s %-*s ", fil->pwidth, src, fil->pwidth, dst); 453 1.1 rmind free(src); 454 1.1 rmind free(dst); 455 1.1 rmind 456 1.1 rmind fprintf(fp, "%-10s ", ifname ? ifname : "-"); 457 1.1 rmind if (nat_conn) { 458 1.1 rmind addrstr = npfctl_print_addrmask(alen, fmt, &a[2], NPF_NO_NETMASK); 459 1.1 rmind fprintf(fp, "%s", addrstr); 460 1.1 rmind free(addrstr); 461 1.1 rmind if (p[2]) { 462 1.1 rmind fprintf(fp, ":%d", p[2]); 463 1.1 rmind } 464 1.1 rmind } 465 1.1 rmind fputc('\n', fp); 466 1.1 rmind return 1; 467 1.1 rmind } 468 1.1 rmind 469 1.1 rmind static void 470 1.1 rmind npf_conn_list_v(int fd, unsigned alen, npf_conn_filter_t *f) 471 1.1 rmind { 472 1.1 rmind f->alen = alen; 473 1.1 rmind f->v4 = alen == sizeof(struct in_addr); 474 1.1 rmind f->pwidth = f->nowide ? 0 : ((f->v4 ? 15 : 40) + 1 + 5); 475 1.1 rmind if (npf_conn_list(fd, npfctl_conn_print, f) != 0) { 476 1.1 rmind err(EXIT_FAILURE, "npf_conn_list"); 477 1.1 rmind } 478 1.1 rmind } 479 1.1 rmind 480 1.1 rmind int 481 1.1 rmind npfctl_conn_list(int fd, int argc, char **argv) 482 1.1 rmind { 483 1.1 rmind npf_conn_filter_t f; 484 1.1 rmind bool header = true; 485 1.1 rmind unsigned alen = 0; 486 1.1 rmind int c; 487 1.1 rmind 488 1.1 rmind argc--; 489 1.1 rmind argv++; 490 1.1 rmind 491 1.1 rmind memset(&f, 0, sizeof(f)); 492 1.1 rmind f.fp = stdout; 493 1.1 rmind 494 1.1 rmind while ((c = getopt(argc, argv, "46hi:nNW")) != -1) { 495 1.1 rmind switch (c) { 496 1.1 rmind case '4': 497 1.1 rmind alen = sizeof(struct in_addr); 498 1.1 rmind break; 499 1.1 rmind case '6': 500 1.1 rmind alen = sizeof(struct in6_addr); 501 1.1 rmind break; 502 1.1 rmind case 'h': 503 1.1 rmind header = false; 504 1.1 rmind break; 505 1.1 rmind case 'i': 506 1.1 rmind f.ifname = optarg; 507 1.1 rmind break; 508 1.1 rmind case 'n': 509 1.1 rmind f.nat = true; 510 1.1 rmind break; 511 1.1 rmind case 'N': 512 1.1 rmind f.name = true; 513 1.1 rmind break; 514 1.1 rmind case 'W': 515 1.1 rmind f.nowide = true; 516 1.1 rmind break; 517 1.1 rmind default: 518 1.1 rmind errx(EXIT_FAILURE, 519 1.1 rmind "Usage: %s list [-46hnNW] [-i <ifname>]\n", 520 1.1 rmind getprogname()); 521 1.1 rmind } 522 1.1 rmind } 523 1.1 rmind 524 1.1 rmind if (header) { 525 1.1 rmind fprintf(f.fp, "# %-*s %-*s %-*s %s\n", 526 1.1 rmind 21 - 2, "src-addr:port", 527 1.1 rmind 21, "dst-addr:port", 528 1.1 rmind 10, "interface", 529 1.1 rmind "nat-addr:port"); 530 1.1 rmind } 531 1.1 rmind 532 1.1 rmind if (!alen || alen == sizeof(struct in_addr)) { 533 1.1 rmind npf_conn_list_v(fd, sizeof(struct in_addr), &f); 534 1.1 rmind } 535 1.1 rmind if (!alen || alen == sizeof(struct in6_addr)) { 536 1.1 rmind npf_conn_list_v(fd, sizeof(struct in6_addr), &f); 537 1.1 rmind } 538 1.1 rmind 539 1.1 rmind return 0; 540 1.1 rmind } 541