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