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[], 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 struct pfioc_table io; 215 216 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 217 errno = EINVAL; 218 return (-1); 219 } 220 bzero(&io, sizeof io); 221 io.pfrio_flags = flags; 222 io.pfrio_table = *tbl; 223 io.pfrio_buffer = addr; 224 io.pfrio_esize = sizeof(*addr); 225 io.pfrio_size = size; 226 if (ioctl(dev, DIOCRADDADDRS, &io)) { 227 pfr_report_error(tbl, &io, "add addresses in"); 228 return (-1); 229 } 230 if (nadd != NULL) 231 *nadd = io.pfrio_nadd; 232 return (0); 233 } 234 235 int 236 pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 237 int *ndel, int flags) 238 { 239 struct pfioc_table io; 240 241 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 242 errno = EINVAL; 243 return (-1); 244 } 245 bzero(&io, sizeof io); 246 io.pfrio_flags = flags; 247 io.pfrio_table = *tbl; 248 io.pfrio_buffer = addr; 249 io.pfrio_esize = sizeof(*addr); 250 io.pfrio_size = size; 251 if (ioctl(dev, DIOCRDELADDRS, &io)) { 252 pfr_report_error(tbl, &io, "delete addresses in"); 253 return (-1); 254 } 255 if (ndel != NULL) 256 *ndel = io.pfrio_ndel; 257 return (0); 258 } 259 260 int 261 pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 262 int *size2, int *nadd, int *ndel, int *nchange, int flags) 263 { 264 struct pfioc_table io; 265 266 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 267 errno = EINVAL; 268 return (-1); 269 } 270 bzero(&io, sizeof io); 271 io.pfrio_flags = flags; 272 io.pfrio_table = *tbl; 273 io.pfrio_buffer = addr; 274 io.pfrio_esize = sizeof(*addr); 275 io.pfrio_size = size; 276 io.pfrio_size2 = (size2 != NULL) ? *size2 : 0; 277 if (ioctl(dev, DIOCRSETADDRS, &io)) { 278 pfr_report_error(tbl, &io, "set addresses in"); 279 return (-1); 280 } 281 if (nadd != NULL) 282 *nadd = io.pfrio_nadd; 283 if (ndel != NULL) 284 *ndel = io.pfrio_ndel; 285 if (nchange != NULL) 286 *nchange = io.pfrio_nchange; 287 if (size2 != NULL) 288 *size2 = io.pfrio_size2; 289 return (0); 290 } 291 292 int 293 pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, 294 int flags) 295 { 296 struct pfioc_table io; 297 298 if (tbl == NULL || size == NULL || *size < 0 || 299 (*size && addr == NULL)) { 300 errno = EINVAL; 301 return (-1); 302 } 303 bzero(&io, sizeof io); 304 io.pfrio_flags = flags; 305 io.pfrio_table = *tbl; 306 io.pfrio_buffer = addr; 307 io.pfrio_esize = sizeof(*addr); 308 io.pfrio_size = *size; 309 if (ioctl(dev, DIOCRGETADDRS, &io)) { 310 pfr_report_error(tbl, &io, "get addresses from"); 311 return (-1); 312 } 313 *size = io.pfrio_size; 314 return (0); 315 } 316 317 int 318 pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, 319 int flags) 320 { 321 struct pfioc_table io; 322 323 if (tbl == NULL || size == NULL || *size < 0 || 324 (*size && addr == NULL)) { 325 errno = EINVAL; 326 return (-1); 327 } 328 bzero(&io, sizeof io); 329 io.pfrio_flags = flags; 330 io.pfrio_table = *tbl; 331 io.pfrio_buffer = addr; 332 io.pfrio_esize = sizeof(*addr); 333 io.pfrio_size = *size; 334 if (ioctl(dev, DIOCRGETASTATS, &io)) { 335 pfr_report_error(tbl, &io, "get astats from"); 336 return (-1); 337 } 338 *size = io.pfrio_size; 339 return (0); 340 } 341 342 int 343 pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) 344 { 345 struct pfioc_table io; 346 347 if (size < 0 || (size && !tbl)) { 348 errno = EINVAL; 349 return (-1); 350 } 351 bzero(&io, sizeof io); 352 io.pfrio_flags = flags; 353 io.pfrio_buffer = tbl; 354 io.pfrio_esize = sizeof(*tbl); 355 io.pfrio_size = size; 356 if (ioctl(dev, DIOCRCLRTSTATS, &io)) { 357 pfr_report_error(tbl, &io, "clear tstats from"); 358 return (-1); 359 } 360 if (nzero) 361 *nzero = io.pfrio_nzero; 362 return (0); 363 } 364 365 int 366 pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 367 int *nmatch, int flags) 368 { 369 struct pfioc_table io; 370 371 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 372 errno = EINVAL; 373 return (-1); 374 } 375 bzero(&io, sizeof io); 376 io.pfrio_flags = flags; 377 io.pfrio_table = *tbl; 378 io.pfrio_buffer = addr; 379 io.pfrio_esize = sizeof(*addr); 380 io.pfrio_size = size; 381 if (ioctl(dev, DIOCRTSTADDRS, &io)) { 382 pfr_report_error(tbl, &io, "test addresses in"); 383 return (-1); 384 } 385 if (nmatch) 386 *nmatch = io.pfrio_nmatch; 387 return (0); 388 } 389 390 int 391 pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, 392 int *nadd, int *naddr, int ticket, int flags) 393 { 394 struct pfioc_table io; 395 396 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 397 errno = EINVAL; 398 return (-1); 399 } 400 bzero(&io, sizeof io); 401 io.pfrio_flags = flags; 402 io.pfrio_table = *tbl; 403 io.pfrio_buffer = addr; 404 io.pfrio_esize = sizeof(*addr); 405 io.pfrio_size = size; 406 io.pfrio_ticket = ticket; 407 if (ioctl(dev, DIOCRINADEFINE, &io)) { 408 pfr_report_error(tbl, &io, "define inactive set table"); 409 return (-1); 410 } 411 if (nadd != NULL) 412 *nadd = io.pfrio_nadd; 413 if (naddr != NULL) 414 *naddr = io.pfrio_naddr; 415 return (0); 416 } 417 418 /* interface management code */ 419 420 int 421 pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size) 422 { 423 struct pfioc_iface io; 424 425 if (size == NULL || *size < 0 || (*size && buf == NULL)) { 426 errno = EINVAL; 427 return (-1); 428 } 429 bzero(&io, sizeof io); 430 if (filter != NULL) 431 if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >= 432 sizeof(io.pfiio_name)) { 433 errno = EINVAL; 434 return (-1); 435 } 436 io.pfiio_buffer = buf; 437 io.pfiio_esize = sizeof(*buf); 438 io.pfiio_size = *size; 439 if (ioctl(dev, DIOCIGETIFACES, &io)) 440 return (-1); 441 *size = io.pfiio_size; 442 return (0); 443 } 444 445 /* buffer management code */ 446 447 const size_t buf_esize[PFRB_MAX] = { 0, 448 sizeof(struct pfr_table), sizeof(struct pfr_tstats), 449 sizeof(struct pfr_addr), sizeof(struct pfr_astats), 450 sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e) 451 }; 452 453 /* 454 * add one element to the buffer 455 */ 456 int 457 pfr_buf_add(struct pfr_buffer *b, const void *e) 458 { 459 size_t bs; 460 461 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX || 462 e == NULL) { 463 errno = EINVAL; 464 return (-1); 465 } 466 bs = buf_esize[b->pfrb_type]; 467 if (b->pfrb_size == b->pfrb_msize) 468 if (pfr_buf_grow(b, 0)) 469 return (-1); 470 memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs); 471 b->pfrb_size++; 472 return (0); 473 } 474 475 /* 476 * return next element of the buffer (or first one if prev is NULL) 477 * see PFRB_FOREACH macro 478 */ 479 void * 480 pfr_buf_next(struct pfr_buffer *b, const void *prev) 481 { 482 size_t bs; 483 484 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) 485 return (NULL); 486 if (b->pfrb_size == 0) 487 return (NULL); 488 if (prev == NULL) 489 return (b->pfrb_caddr); 490 bs = buf_esize[b->pfrb_type]; 491 if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1) 492 return (NULL); 493 return (((caddr_t)prev) + bs); 494 } 495 496 /* 497 * minsize: 498 * 0: make the buffer somewhat bigger 499 * n: make room for "n" entries in the buffer 500 */ 501 int 502 pfr_buf_grow(struct pfr_buffer *b, int minsize) 503 { 504 caddr_t p; 505 size_t bs; 506 507 if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) { 508 errno = EINVAL; 509 return (-1); 510 } 511 if (minsize != 0 && minsize <= b->pfrb_msize) 512 return (0); 513 bs = buf_esize[b->pfrb_type]; 514 if (!b->pfrb_msize) { 515 if (minsize < 64) 516 minsize = 64; 517 b->pfrb_caddr = calloc(bs, minsize); 518 if (b->pfrb_caddr == NULL) 519 return (-1); 520 b->pfrb_msize = minsize; 521 } else { 522 if (minsize == 0) 523 minsize = b->pfrb_msize * 2; 524 if (minsize < 0 || minsize >= SIZE_T_MAX / bs) { 525 /* msize overflow */ 526 errno = ENOMEM; 527 return (-1); 528 } 529 p = realloc(b->pfrb_caddr, minsize * bs); 530 if (p == NULL) 531 return (-1); 532 bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs); 533 b->pfrb_caddr = p; 534 b->pfrb_msize = minsize; 535 } 536 return (0); 537 } 538 539 /* 540 * reset buffer and free memory. 541 */ 542 void 543 pfr_buf_clear(struct pfr_buffer *b) 544 { 545 if (b == NULL) 546 return; 547 if (b->pfrb_caddr != NULL) 548 free(b->pfrb_caddr); 549 b->pfrb_caddr = NULL; 550 b->pfrb_size = b->pfrb_msize = 0; 551 } 552 553 int 554 pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork, 555 int (*append_addr)(struct pfr_buffer *, char *, int)) 556 { 557 FILE *fp; 558 char buf[BUF_SIZE]; 559 int rv; 560 561 if (file == NULL) 562 return (0); 563 if (!strcmp(file, "-")) 564 fp = stdin; 565 else { 566 fp = pfctl_fopen(file, "r"); 567 if (fp == NULL) 568 return (-1); 569 } 570 while ((rv = pfr_next_token(buf, fp)) == 1) 571 if (append_addr(b, buf, nonetwork)) { 572 rv = -1; 573 break; 574 } 575 if (fp != stdin) 576 fclose(fp); 577 return (rv); 578 } 579 580 int 581 pfr_next_token(char buf[BUF_SIZE], FILE *fp) 582 { 583 static char next_ch = ' '; 584 int i = 0; 585 586 for (;;) { 587 /* skip spaces */ 588 while (isspace(next_ch) && !feof(fp)) 589 next_ch = fgetc(fp); 590 /* remove from '#' until end of line */ 591 if (next_ch == '#') 592 while (!feof(fp)) { 593 next_ch = fgetc(fp); 594 if (next_ch == '\n') 595 break; 596 } 597 else 598 break; 599 } 600 if (feof(fp)) { 601 next_ch = ' '; 602 return (0); 603 } 604 do { 605 if (i < BUF_SIZE) 606 buf[i++] = next_ch; 607 next_ch = fgetc(fp); 608 } while (!feof(fp) && !isspace(next_ch)); 609 if (i >= BUF_SIZE) { 610 errno = EINVAL; 611 return (-1); 612 } 613 buf[i] = '\0'; 614 return (1); 615 } 616 617 char * 618 pfr_strerror(int errnum) 619 { 620 switch (errnum) { 621 case ESRCH: 622 return "Table does not exist"; 623 case ENOENT: 624 return "Anchor or Ruleset does not exist"; 625 default: 626 return strerror(errnum); 627 } 628 } 629