1 /* $OpenBSD: pfctl_radix.c,v 1.27 2005/05/21 21:03:58 henning Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2002 Cedric Berger 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * - Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * - Redistributions in binary form must reproduce the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer in the documentation and/or other materials provided 18 * with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 * 33 */ 34 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include <sys/types.h> 39 #include <sys/ioctl.h> 40 #include <sys/socket.h> 41 42 #include <net/if.h> 43 #include <net/pfvar.h> 44 45 #include <errno.h> 46 #include <string.h> 47 #include <ctype.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <limits.h> 51 #include <err.h> 52 53 #include "pfctl.h" 54 55 #define BUF_SIZE 256 56 57 extern int dev; 58 59 static int pfr_next_token(char buf[BUF_SIZE], FILE *); 60 61 static void 62 pfr_report_error(struct pfr_table *tbl, struct pfioc_table *io, 63 const char *err) 64 { 65 unsigned long maxcount; 66 size_t s; 67 68 s = sizeof(maxcount); 69 if (sysctlbyname("net.pf.request_maxcount", &maxcount, &s, NULL, 70 0) == -1) 71 return; 72 73 if (io->pfrio_size > maxcount || io->pfrio_size2 > maxcount) 74 fprintf(stderr, "cannot %s %s: too many elements.\n" 75 "Consider increasing net.pf.request_maxcount.", 76 err, tbl->pfrt_name); 77 } 78 79 int 80 pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags) 81 { 82 struct pfioc_table io; 83 84 bzero(&io, sizeof io); 85 io.pfrio_flags = flags; 86 if (filter != NULL) 87 io.pfrio_table = *filter; 88 if (ioctl(dev, DIOCRCLRTABLES, &io)) 89 return (-1); 90 if (ndel != NULL) 91 *ndel = io.pfrio_ndel; 92 return (0); 93 } 94 95 int 96 pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) 97 { 98 struct pfioc_table io; 99 100 if (size < 0 || (size && tbl == NULL)) { 101 errno = EINVAL; 102 return (-1); 103 } 104 bzero(&io, sizeof io); 105 io.pfrio_flags = flags; 106 io.pfrio_buffer = tbl; 107 io.pfrio_esize = sizeof(*tbl); 108 io.pfrio_size = size; 109 if (ioctl(dev, DIOCRADDTABLES, &io)) { 110 pfr_report_error(tbl, &io, "add table"); 111 return (-1); 112 } 113 if (nadd != NULL) 114 *nadd = io.pfrio_nadd; 115 return (0); 116 } 117 118 int 119 pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags) 120 { 121 struct pfioc_table io; 122 123 if (size < 0 || (size && tbl == NULL)) { 124 errno = EINVAL; 125 return (-1); 126 } 127 bzero(&io, sizeof io); 128 io.pfrio_flags = flags; 129 io.pfrio_buffer = tbl; 130 io.pfrio_esize = sizeof(*tbl); 131 io.pfrio_size = size; 132 if (ioctl(dev, DIOCRDELTABLES, &io)) { 133 pfr_report_error(tbl, &io, "delete table"); 134 return (-1); 135 } 136 if (ndel != NULL) 137 *ndel = io.pfrio_ndel; 138 return (0); 139 } 140 141 int 142 pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size, 143 int flags) 144 { 145 struct pfioc_table io; 146 147 if (size == NULL || *size < 0 || (*size && tbl == NULL)) { 148 errno = EINVAL; 149 return (-1); 150 } 151 bzero(&io, sizeof io); 152 io.pfrio_flags = flags; 153 if (filter != NULL) 154 io.pfrio_table = *filter; 155 io.pfrio_buffer = tbl; 156 io.pfrio_esize = sizeof(*tbl); 157 io.pfrio_size = *size; 158 if (ioctl(dev, DIOCRGETTABLES, &io)) { 159 pfr_report_error(tbl, &io, "get table"); 160 return (-1); 161 } 162 *size = io.pfrio_size; 163 return (0); 164 } 165 166 int 167 pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, 168 int flags) 169 { 170 struct pfioc_table io; 171 172 if (size == NULL || *size < 0 || (*size && tbl == NULL)) { 173 errno = EINVAL; 174 return (-1); 175 } 176 bzero(&io, sizeof io); 177 io.pfrio_flags = flags; 178 if (filter != NULL) 179 io.pfrio_table = *filter; 180 io.pfrio_buffer = tbl; 181 io.pfrio_esize = sizeof(*tbl); 182 io.pfrio_size = *size; 183 if (ioctl(dev, DIOCRGETTSTATS, &io)) { 184 pfr_report_error(filter, &io, "get tstats for"); 185 return (-1); 186 } 187 *size = io.pfrio_size; 188 return (0); 189 } 190 191 int 192 pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags) 193 { 194 struct pfioc_table io; 195 196 if (tbl == NULL) { 197 errno = EINVAL; 198 return (-1); 199 } 200 bzero(&io, sizeof io); 201 io.pfrio_flags = flags; 202 io.pfrio_table = *tbl; 203 if (ioctl(dev, DIOCRCLRADDRS, &io)) 204 return (-1); 205 if (ndel != NULL) 206 *ndel = io.pfrio_ndel; 207 return (0); 208 } 209 210 int 211 pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 212 int *nadd, int flags) 213 { 214 int ret; 215 216 ret = pfctl_table_add_addrs(dev, tbl, addr, size, nadd, flags); 217 if (ret) { 218 errno = ret; 219 return (-1); 220 } 221 return (0); 222 } 223 224 int 225 pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 226 int *ndel, int flags) 227 { 228 int ret; 229 230 ret = pfctl_table_del_addrs(dev, tbl, addr, size, ndel, flags); 231 if (ret) { 232 errno = ret; 233 return (-1); 234 } 235 return (0); 236 } 237 238 int 239 pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 240 int *size2, int *nadd, int *ndel, int *nchange, int flags) 241 { 242 int ret; 243 244 ret = pfctl_table_set_addrs(dev, tbl, addr, size, size2, nadd, ndel, 245 nchange, flags); 246 if (ret) { 247 errno = ret; 248 return (-1); 249 } 250 return (0); 251 } 252 253 int 254 pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, 255 int flags) 256 { 257 int ret; 258 259 ret = pfctl_table_get_addrs(dev, tbl, addr, size, flags); 260 if (ret) { 261 errno = ret; 262 return (-1); 263 } 264 return (0); 265 } 266 267 int 268 pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, 269 int flags) 270 { 271 struct pfioc_table io; 272 273 if (tbl == NULL || size == NULL || *size < 0 || 274 (*size && addr == NULL)) { 275 errno = EINVAL; 276 return (-1); 277 } 278 bzero(&io, sizeof io); 279 io.pfrio_flags = flags; 280 io.pfrio_table = *tbl; 281 io.pfrio_buffer = addr; 282 io.pfrio_esize = sizeof(*addr); 283 io.pfrio_size = *size; 284 if (ioctl(dev, DIOCRGETASTATS, &io)) { 285 pfr_report_error(tbl, &io, "get astats from"); 286 return (-1); 287 } 288 *size = io.pfrio_size; 289 return (0); 290 } 291 292 int 293 pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) 294 { 295 struct pfioc_table io; 296 297 if (size < 0 || (size && !tbl)) { 298 errno = EINVAL; 299 return (-1); 300 } 301 bzero(&io, sizeof io); 302 io.pfrio_flags = flags; 303 io.pfrio_buffer = tbl; 304 io.pfrio_esize = sizeof(*tbl); 305 io.pfrio_size = size; 306 if (ioctl(dev, DIOCRCLRTSTATS, &io)) { 307 pfr_report_error(tbl, &io, "clear tstats from"); 308 return (-1); 309 } 310 if (nzero) 311 *nzero = io.pfrio_nzero; 312 return (0); 313 } 314 315 int 316 pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 317 int *nmatch, int flags) 318 { 319 struct pfioc_table io; 320 321 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 322 errno = EINVAL; 323 return (-1); 324 } 325 bzero(&io, sizeof io); 326 io.pfrio_flags = flags; 327 io.pfrio_table = *tbl; 328 io.pfrio_buffer = addr; 329 io.pfrio_esize = sizeof(*addr); 330 io.pfrio_size = size; 331 if (ioctl(dev, DIOCRTSTADDRS, &io)) { 332 pfr_report_error(tbl, &io, "test addresses in"); 333 return (-1); 334 } 335 if (nmatch) 336 *nmatch = io.pfrio_nmatch; 337 return (0); 338 } 339 340 int 341 pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, 342 int *nadd, int *naddr, int ticket, int flags) 343 { 344 struct pfioc_table io; 345 346 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 347 errno = EINVAL; 348 return (-1); 349 } 350 bzero(&io, sizeof io); 351 io.pfrio_flags = flags; 352 io.pfrio_table = *tbl; 353 io.pfrio_buffer = addr; 354 io.pfrio_esize = sizeof(*addr); 355 io.pfrio_size = size; 356 io.pfrio_ticket = ticket; 357 if (ioctl(dev, DIOCRINADEFINE, &io)) { 358 pfr_report_error(tbl, &io, "define inactive set table"); 359 return (-1); 360 } 361 if (nadd != NULL) 362 *nadd = io.pfrio_nadd; 363 if (naddr != NULL) 364 *naddr = io.pfrio_naddr; 365 return (0); 366 } 367 368 /* interface management code */ 369 370 int 371 pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size) 372 { 373 struct pfioc_iface io; 374 375 if (size == NULL || *size < 0 || (*size && buf == NULL)) { 376 errno = EINVAL; 377 return (-1); 378 } 379 bzero(&io, sizeof io); 380 if (filter != NULL) 381 if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >= 382 sizeof(io.pfiio_name)) { 383 errno = EINVAL; 384 return (-1); 385 } 386 io.pfiio_buffer = buf; 387 io.pfiio_esize = sizeof(*buf); 388 io.pfiio_size = *size; 389 if (ioctl(dev, DIOCIGETIFACES, &io)) 390 return (-1); 391 *size = io.pfiio_size; 392 return (0); 393 } 394 395 /* buffer management code */ 396 397 const size_t buf_esize[PFRB_MAX] = { 0, 398 sizeof(struct pfr_table), sizeof(struct pfr_tstats), 399 sizeof(struct pfr_addr), sizeof(struct pfr_astats), 400 sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e) 401 }; 402 403 /* 404 * add one element to the buffer 405 */ 406 int 407 pfr_buf_add(struct pfr_buffer *b, const void *e) 408 { 409 size_t bs; 410 411 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX || 412 e == NULL) { 413 errno = EINVAL; 414 return (-1); 415 } 416 bs = buf_esize[b->pfrb_type]; 417 if (b->pfrb_size == b->pfrb_msize) 418 if (pfr_buf_grow(b, 0)) 419 return (-1); 420 memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs); 421 b->pfrb_size++; 422 return (0); 423 } 424 425 /* 426 * return next element of the buffer (or first one if prev is NULL) 427 * see PFRB_FOREACH macro 428 */ 429 void * 430 pfr_buf_next(struct pfr_buffer *b, const void *prev) 431 { 432 size_t bs; 433 434 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) 435 return (NULL); 436 if (b->pfrb_size == 0) 437 return (NULL); 438 if (prev == NULL) 439 return (b->pfrb_caddr); 440 bs = buf_esize[b->pfrb_type]; 441 if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1) 442 return (NULL); 443 return (((caddr_t)prev) + bs); 444 } 445 446 /* 447 * minsize: 448 * 0: make the buffer somewhat bigger 449 * n: make room for "n" entries in the buffer 450 */ 451 int 452 pfr_buf_grow(struct pfr_buffer *b, int minsize) 453 { 454 caddr_t p; 455 size_t bs; 456 457 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) { 458 errno = EINVAL; 459 return (-1); 460 } 461 if (minsize != 0 && minsize <= b->pfrb_msize) 462 return (0); 463 bs = buf_esize[b->pfrb_type]; 464 if (!b->pfrb_msize) { 465 if (minsize < 64) 466 minsize = 64; 467 b->pfrb_caddr = calloc(bs, minsize); 468 if (b->pfrb_caddr == NULL) 469 return (-1); 470 b->pfrb_msize = minsize; 471 } else { 472 if (minsize == 0) 473 minsize = b->pfrb_msize * 2; 474 if (minsize < 0 || minsize >= SIZE_T_MAX / bs) { 475 /* msize overflow */ 476 errno = ENOMEM; 477 return (-1); 478 } 479 p = realloc(b->pfrb_caddr, minsize * bs); 480 if (p == NULL) 481 return (-1); 482 bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs); 483 b->pfrb_caddr = p; 484 b->pfrb_msize = minsize; 485 } 486 return (0); 487 } 488 489 /* 490 * reset buffer and free memory. 491 */ 492 void 493 pfr_buf_clear(struct pfr_buffer *b) 494 { 495 if (b == NULL) 496 return; 497 if (b->pfrb_caddr != NULL) 498 free(b->pfrb_caddr); 499 b->pfrb_caddr = NULL; 500 b->pfrb_size = b->pfrb_msize = 0; 501 } 502 503 int 504 pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork, 505 int (*append_addr)(struct pfr_buffer *, char *, int)) 506 { 507 FILE *fp; 508 char buf[BUF_SIZE]; 509 int rv; 510 511 if (file == NULL) 512 return (0); 513 if (!strcmp(file, "-")) 514 fp = stdin; 515 else { 516 fp = pfctl_fopen(file, "r"); 517 if (fp == NULL) 518 return (-1); 519 } 520 while ((rv = pfr_next_token(buf, fp)) == 1) 521 if (append_addr(b, buf, nonetwork)) { 522 rv = -1; 523 break; 524 } 525 if (fp != stdin) 526 fclose(fp); 527 return (rv); 528 } 529 530 int 531 pfr_next_token(char buf[BUF_SIZE], FILE *fp) 532 { 533 static char next_ch = ' '; 534 int i = 0; 535 536 for (;;) { 537 /* skip spaces */ 538 while (isspace(next_ch) && !feof(fp)) 539 next_ch = fgetc(fp); 540 /* remove from '#' until end of line */ 541 if (next_ch == '#') 542 while (!feof(fp)) { 543 next_ch = fgetc(fp); 544 if (next_ch == '\n') 545 break; 546 } 547 else 548 break; 549 } 550 if (feof(fp)) { 551 next_ch = ' '; 552 return (0); 553 } 554 do { 555 if (i < BUF_SIZE) 556 buf[i++] = next_ch; 557 next_ch = fgetc(fp); 558 } while (!feof(fp) && !isspace(next_ch)); 559 if (i >= BUF_SIZE) { 560 errno = EINVAL; 561 return (-1); 562 } 563 buf[i] = '\0'; 564 return (1); 565 } 566 567 char * 568 pfr_strerror(int errnum) 569 { 570 switch (errnum) { 571 case ESRCH: 572 return "Table does not exist"; 573 case ENOENT: 574 return "Anchor or Ruleset does not exist"; 575 default: 576 return strerror(errnum); 577 } 578 } 579